简体   繁体   English

docker容器内调用命令

[英]Call commands within docker container

I have a docker container where I need to run some commands.我有一个 docker 容器,我需要在其中运行一些命令。 Usually, I do this manually by running the following commands:通常,我通过运行以下命令手动执行此操作:

host> docker exec -it my-container bash
container> eval $(ssh-agent)
container> ssh-add ~/.ssh/my-key
<TYPE PASSPHRASE!!!>
container> pytest

I've tried to call docker exec -it from the subprocess, but I couldn't mimic the same behavior as the manual workflow.我试图从子流程调用docker exec -it ,但我无法模仿与手动工作流相同的行为。 I can't send commands one by one, as the ssh key is loaded only for the current session, if I run it non-interactively I can't use the key.我无法一一发送命令,因为 ssh 密钥仅针对当前 session 加载,如果我以非交互方式运行它,我将无法使用该密钥。

I have two problems - I need to type passphrase via stdin (I don't see a way to provide it together with ssh-add ), and I want to know when pytest will exit and the return code.我有两个问题 - 我需要通过 stdin 输入密码(我没有看到将它与ssh-add一起提供的方法),我想知道pytest何时退出和返回代码。

What is the most seamless way to achieve that?实现这一目标的最无缝方式是什么? I'd prefer to avoid installing additional dependencies, but if it's necessary then I can use something.我宁愿避免安装额外的依赖项,但如果有必要,我可以使用一些东西。

The ssh-agent listens on a Unix socket; ssh-agent 监听 Unix 套接字; its location is in the $SSH_AUTH_SOCK environment variable.它的位置在$SSH_AUTH_SOCK环境变量中。 You can use a Docker bind mount ( docker run -v option) to inject this socket into the container.您可以使用 Docker 绑定安装( docker run -v选项)将此套接字注入容器。 Then when you run ssh-add on the host, provided the socket is accessible and the environment variable is set correctly on the host, the container can access the credentials in the agent.然后,当您在主机上运行ssh-add时,只要套接字可访问并且主机上的环境变量设置正确,容器就可以访问代理中的凭据。

I would not use docker exec here.我不会在这里使用docker exec A container generally runs some single command;一个容器通常运行一些单一的命令; say in your case that your container is running a Flask or Django application.假设您的容器正在运行 Flask 或 Django 应用程序。 You wouldn't normally "go inside" the Django application while it's running to run its unit tests inside the server.当 Django 应用程序正在运行时,您通常不会“进入”该应用程序以在服务器内部运行其单元测试。 A separate container and a separate process makes more sense.一个单独的容器和一个单独的进程更有意义。

The invocation I might use here would look something a little more like:我在这里可能使用的调用看起来更像:

eval $(ssh-agent)                           # if not already done on login
ssh-add                                     # if not already done on login
docker run \
  --rm \                                    # delete temporary test container when done
  -v "$SSH_AUTH_SOCK:/tmp/ssh-auth.sock" \  # mount ssh socket into container
  -e SSH_AUTH_SOCK=/tmp/ssh-auth.sock \     # set socket location to mounted socket
  -u $(id -u) \                             # run as host user (with permissions on the socket)
  your-image \
  pytest                                    # override command to run in container

I would be surprised to see unit tests that actually depended on access to particular ssh credentials;我会惊讶地看到单元测试实际上取决于对特定 ssh 凭据的访问; you also may find it easier to restructure your tests to mock service clients that need these credentials, or to run these tests in a Python virtual environment on the host before you build a Docker image at all.您还可能会发现,在构建 Docker 映像之前,重组测试以模拟需要这些凭据的服务客户端或在主机上的 Python 虚拟环境中运行这些测试会更容易。

I have found expect (or in the case of python, pexpect) to be very helpful in situations where you are stuck with having to supply user input.我发现 expect(或者在 python 的情况下,pexpect)在您不得不提供用户输入的情况下非常有用。 Here's a simple script to execute your example (admittedly, there are additional dependencies):这是一个执行示例的简单脚本(诚然,还有其他依赖项):

#!/usr/bin/env python
import pexpect
from getpass import getpass

prompt = ">"
child = pexpect.spawn ('docker exec -it my-container bash'))  
child.expect (prompt)
child.sendline ('eval $(ssh-agent)')
child.expect (prompt)
child.sendline ('ssh-add ~/.ssh/my-key')
child.expect ('Enter passphrase for /root/.ssh/my-key:')
password = getpass( prompt="Private Key Password:")
child.sendline (password)
child.expect (prompt)
child.sendline ("pytest")

I took the example from https://pexpect.readthedocs.io/en/stable/overview.html and put in your commands.我从https://pexpect.readthedocs.io/en/stable/overview.html中获取示例并输入您的命令。

A note on the prompt.关于提示的注释。 When I tested the code above, my bash shell in my container had a '$' prompt.当我测试上面的代码时,我容器中的 bash shell 有一个 '$' 提示符。 I think that I was lucky that '$' worked for me, since it's basically a valid regex.我认为我很幸运“$”对我有用,因为它基本上是一个有效的正则表达式。 Your mileage may vary with the '>' prompt, but you may also want to pay attention to the information regarding CR/LF on the same page mentioned above.您的里程数可能因“>”提示而异,但您可能还需要注意上述同一页面上有关 CR/LF 的信息。

I assume that when you launched the container, you mounted your ~/.ssh directory.我假设当您启动容器时,您安装了 ~/.ssh 目录。 When I launched my container to verify the code above, I added the mount option: -v ~/.ssh:/root/.ssh当我启动我的容器来验证上面的代码时,我添加了挂载选项: -v ~/.ssh:/root/.ssh

You have to run this command instead to avoid typing the password您必须改为运行此命令以避免输入密码

sshpass -p [PASSWORD] ssh [USER]@172.17.0.2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM