Захват вывода скрипта Python, запускаемого внутри контейнера Docker

Цель здесь состоит в том, чтобы использовать контейнер Docker в качестве безопасной изолированной программной среды для запуска ненадежных сценариев Python, но делать это изнутри Python с помощью модуля docker-py и иметь возможность захватывать выходные данные этого сценария.

Я запускаю скрипт python foo.py внутри контейнера докера (он установлен как ENTRYPOINT в моем Dockerfile, поэтому она выполняется сразу после запуска контейнера), и я не могу зафиксировать вывод этого скрипта. Когда я запускаю контейнер через обычный интерфейс командной строки, используя

docker run -v /host_dirpath:/cont_dirpath my_image

(host_dirpath это каталог, содержащий foo.py) Я получаю ожидаемый вывод foo.py, распечатанный в stdout, который является просто словарем пар ключ-значение. Тем не менее, я пытаюсь сделать это из 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: " - в логах ничего не записывается, ни stdout, ни stderr (я попытался вызвать исключение внутри foo.py, чтобы проверить это).

Результаты, которые я получаю, рассчитываются с помощью foo.py и в настоящее время просто выводятся на стандартный вывод с питоном. print заявление. Как я могу включить это в журналы Docker-контейнеров, чтобы я мог читать это из Python? Или захватить этот вывод каким-то другим способом извне контейнера?

Любая помощь будет принята с благодарностью. Заранее спасибо!

РЕДАКТИРОВАТЬ:

Все еще не повезло с docker-py, но он работает хорошо при запуске контейнера с обычным CLI с использованием subprocess.Popen - вывод действительно правильно захватывается stdout при этом.

2 ответа

Вы испытываете это поведение, потому что 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)

но если вы отключите буферизованный вывод Python с помощью -u параметр командной строки, все отображается:

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 параметр.

Вы можете испытать состояние гонки, поскольку запущенный контейнер работает параллельно с вашей управляющей программой. Вам нужно подождать, пока ваш контейнер запустится и закончится, прежде чем захватывать логи. Добавьте docker.wait к вашему коду сразу после docker.start.

docker.wait(contid)

Ваш вывод кажется пустым, потому что ничего еще не было зарегистрировано.

Другие вопросы по тегам