在Docker容器中运行Python脚本并捕获输出

35
这里的目的是使用Docker容器作为安全沙箱来运行不受信任的Python脚本,但要从Python内部使用docker-py模块实现,并能够捕获该脚本的输出。 我正在Docker容器中运行一个名为foo.py的Python脚本(它被设置为Dockerfile中的ENTRYPOINT命令,因此一旦运行容器就会执行它),但无法捕获该脚本的输出。 当我通过普通的CLI运行容器时...
docker run -v /host_dirpath:/cont_dirpath my_image

(host_dirpath 是包含 foo.py 文件的目录) 我在控制台上看到了 foo.py 期望输出的内容,这只是一个键值对字典。然而,我尝试使用 docker-py 模块从 python 中执行此操作,但某种方式脚本输出未被 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:" - 日志中没有捕获任何内容,包括stdout和stderr(我尝试在foo.py内引发异常以测试此功能)。

我需要的结果是由foo.py计算出来的,并且目前仅使用python print语句打印到stdout。我该如何将其包含在docker容器日志中,以便我可以从python中读取它?或者从容器外部以其他方式捕获此输出?

非常感谢您的帮助。提前致谢!

编辑:

使用docker-py仍然没有成功,但是使用普通CLI运行容器时,通过subprocess.Popen确实可以正确地抓取输出到stdout。


我来到这里是为了查看输出:docker logs -f [container id] 对于我来说非常好,可以检查在容器中运行的Flask应用程序。 - james-see
2个回答

24
您遇到这种情况是因为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参数运行的容器。


非常感谢!我被一个永远运行的Python脚本卡了一个小时,一直在寻找输出。 - Dmytro Sadovnychyi
3
使用-u运行Python并没有改变任何东西。只有PYTHONUNBUFFERED=0对我起作用。 - Victor
5
建议将PYTHONUNBUFFERED设置为1或TRUE以进行清理。在此上下文中,任何值都被视为true,因此0也可以使用。但是,由于0通常表示false,因此更容易引起混淆。 - David Goldfarb

3

您可能会遇到竞态条件,因为启动的容器与您的控制程序并行运行。在获取日志之前,您需要等待容器启动和完成。在 docker.start 之后立即在您的代码中添加 docker.wait。

docker.wait(contid)

你的输出看起来是空的,因为还没有记录任何内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接