[英]Call commands within docker container
我有一个 docker 容器,我需要在其中运行一些命令。 通常,我通过运行以下命令手动执行此操作:
host> docker exec -it my-container bash
container> eval $(ssh-agent)
container> ssh-add ~/.ssh/my-key
<TYPE PASSPHRASE!!!>
container> pytest
我试图从子流程调用docker exec -it
,但我无法模仿与手动工作流相同的行为。 我无法一一发送命令,因为 ssh 密钥仅针对当前 session 加载,如果我以非交互方式运行它,我将无法使用该密钥。
我有两个问题 - 我需要通过 stdin 输入密码(我没有看到将它与ssh-add
一起提供的方法),我想知道pytest
何时退出和返回代码。
实现这一目标的最无缝方式是什么? 我宁愿避免安装额外的依赖项,但如果有必要,我可以使用一些东西。
ssh-agent 监听 Unix 套接字; 它的位置在$SSH_AUTH_SOCK
环境变量中。 您可以使用 Docker 绑定安装( docker run -v
选项)将此套接字注入容器。 然后,当您在主机上运行ssh-add
时,只要套接字可访问并且主机上的环境变量设置正确,容器就可以访问代理中的凭据。
我不会在这里使用docker exec
。 一个容器通常运行一些单一的命令; 假设您的容器正在运行 Flask 或 Django 应用程序。 当 Django 应用程序正在运行时,您通常不会“进入”该应用程序以在服务器内部运行其单元测试。 一个单独的容器和一个单独的进程更有意义。
我在这里可能使用的调用看起来更像:
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
我会惊讶地看到单元测试实际上取决于对特定 ssh 凭据的访问; 您还可能会发现,在构建 Docker 映像之前,重组测试以模拟需要这些凭据的服务客户端或在主机上的 Python 虚拟环境中运行这些测试会更容易。
我发现 expect(或者在 python 的情况下,pexpect)在您不得不提供用户输入的情况下非常有用。 这是一个执行示例的简单脚本(诚然,还有其他依赖项):
#!/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")
我从https://pexpect.readthedocs.io/en/stable/overview.html中获取示例并输入您的命令。
关于提示的注释。 当我测试上面的代码时,我容器中的 bash shell 有一个 '$' 提示符。 我认为我很幸运“$”对我有用,因为它基本上是一个有效的正则表达式。 您的里程数可能因“>”提示而异,但您可能还需要注意上述同一页面上有关 CR/LF 的信息。
我假设当您启动容器时,您安装了 ~/.ssh 目录。 当我启动我的容器来验证上面的代码时,我添加了挂载选项: -v ~/.ssh:/root/.ssh
您必须改为运行此命令以避免输入密码
sshpass -p [PASSWORD] ssh [USER]@172.17.0.2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.