捕获在Docker容器内运行的Python脚本输出
这里的目的是使用一个docker容器作为安全的沙箱,来运行不可信的python脚本,并且希望能通过python中的docker-py模块来实现,同时能够捕获这个脚本的输出。
我在docker容器内运行一个名为foo.py的python脚本(这个脚本在我的Dockerfile中被设置为ENTRYPOINT
命令,所以容器一启动就会执行它),但是我无法捕获到这个脚本的输出。当我通过正常的命令行接口运行容器时,
docker run -v /host_dirpath:/cont_dirpath my_image
(host_dirpath
是包含foo.py的目录)我能看到foo.py的预期输出被打印到标准输出上,输出的内容只是一个键值对的字典。然而,我想通过python中的docker-py模块来实现这个功能,但不知为何,脚本的输出没有被logs
方法捕获到。以下是我使用的python代码:
from docker import Client
docker = Client(base_url='unix://var/run/docker.sock',
version='1.10',
timeout=10)
contid = docker.create_container('my_image', volumes={"/cont_dirpath":""})
docker.start(contid, binds={"/host_dirpath": {"bind": "/cont_dirpath"} })
print "Docker logs: " + str(docker.logs(contid))
结果只是显示“Docker logs: ” - 日志中没有任何内容被捕获,无论是标准输出还是标准错误输出(我尝试在foo.py中引发一个异常来测试这个)。
我想要的结果是由foo.py计算出来的,目前只是通过python的print
语句打印到标准输出上。我该如何将这些内容包含在docker容器的日志中,以便我能从python中读取?或者有没有其他方法可以从容器外捕获这个输出?
任何帮助都将非常感谢。提前谢谢!
编辑:
使用docker-py仍然没有成功,但当我使用正常的命令行接口通过subprocess.Popen运行容器时,它工作得很好 - 输出确实被正确地抓取到了标准输出中。
2 个回答
你可能会遇到一个叫做“竞争条件”的问题,因为你启动的容器和你的控制程序是同时运行的。在你获取日志之前,你需要等容器启动并完成。可以在代码中,在docker.start之后加一个docker.wait。
docker.wait(contid)
你的输出看起来是空的,因为还没有任何日志记录下来。
你遇到这种情况是因为Python默认会把输出内容先存起来,不会立刻显示。
举个例子:
vagrant@docker:/vagrant/tmp$ cat foo.py
#!/usr/bin/python
from time import sleep
while True:
print "f00"
sleep(1)
然后从一个作为后台进程运行的容器中查看日志时,什么都看不到:
vagrant@docker:/vagrant/tmp$ docker logs -f $(docker run -d -v $(pwd):/app dockerfile/python python /app/foo.py)
但是如果你在命令行中加上 -u
参数来关闭Python的输出缓冲,所有内容就会显示出来:
vagrant@docker:/vagrant/tmp$ docker logs -f $(docker run -d -v $(pwd):/app dockerfile/python python -u /app/foo.py)
f00
f00
f00
f00
你也可以通过设置 PYTHONUNBUFFERED
这个环境变量来实现同样的效果:
vagrant@docker:/vagrant/tmp$ docker logs -f $(docker run -d -v $(pwd):/app -e PYTHONUNBUFFERED=0 dockerfile/python python /app/foo.py)
f00
f00
f00
f00
需要注意的是,这种情况只影响没有使用 -t
或 --tty
参数的容器。