2014-09-10 9 views
71

Я видел кучу учебников, которые, похоже, делают то же самое, что я пытаюсь сделать, но почему-то мои контейнеры Docker выходят. В принципе, я настраиваю веб-сервер и несколько демонов внутри контейнера Docker. Я делаю последние части этого через сценарий bash под названием run-all.sh, который я запускаю через CMD в своем файле Docker. run-all.sh выглядит следующим образом:Как сохранить контейнер Docker после запуска?

service supervisor start 
service nginx start 

И я начинаю его внутри моего Dockerfile следующим образом:

CMD ["sh", "/root/credentialize_and_run.sh"] 

я могу увидеть, что услуги все начинают правильно, когда я запускаю вещи вручную (т.е. получение на изображение с -i -t/bin/bash), и все выглядит так, как будто он работает правильно, когда я запускаю изображение, но он завершается, как только он заканчивает запуск моих процессов. Я хотел бы, чтобы процессы выполнялись бесконечно, и, насколько я понимаю, контейнер должен продолжать работать, чтобы это произошло. Тем не менее, когда я бегу docker ps -a, я вижу:

➜ docker_test docker ps -a 
CONTAINER ID  IMAGE       COMMAND    CREATED    STATUS      PORTS    NAMES 
c7706edc4189  some_name/some_repo:blah "sh /root/run-all.sh 8 minutes ago  Exited (0) 8 minutes ago      grave_jones 

Что дает? Почему он выходит? Я знаю, что я мог бы просто поставить цикл while в конце моего сценария bash, чтобы поддерживать его, но каков правильный способ удержать его от выхода?

+1

Вы подвергаете порты услуг внешним (опция -p для запуска докеров)? (конечно, это не помешает им выйти) – ribamar

ответ

27

На самом деле это не так, как вы должны проектировать свои контейнеры Docker.

При проектировании контейнера Docker, вы должны построить его таким образом, что есть только один процесс работает (т.е. вы должны иметь один контейнер для Nginx, и один для supervisord или приложений он работает); Кроме того, этот процесс должен работать на переднем плане.

Контейнер «выйдет», когда сам процесс завершится (в вашем случае этот процесс является вашим сценарием bash).


Однако, если вы действительно нужно (или хотят), чтобы запустить несколько службы в контейнере Докер, рассмотрим, начиная с "Docker Base Image", который использует runit как процесс псевдо-инициализации (runit будет оставаться в сети в то время как Nginx и Supervisor run), который останется на переднем плане, пока ваши другие процессы выполняют свою задачу.

У них есть существенные документы, поэтому вы сможете достичь того, что вы пытаетесь сделать достаточно легко.

+0

Можете ли вы объяснить, почему у меня должна быть только одна работа? Я мог бы добавить nginx к диспетчеру, если это необходимо, но не знаю, почему это необходимо. – Eli

+2

@Eli Короткий ответ: так работает Докер. Докер будет запускать только один процесс (и его детей) на контейнер. Рекомендуется, чтобы этот процесс был фактическим процессом приложения (так что, если он выйдет, Docker знает), но вы действительно можете использовать супервизор как этот процесс. Обратите внимание, что вам нужно настроить супервизор для запуска на переднем плане (т. Е. Не daemonize), который выполняется с помощью опции «--nodaemon». –

+0

Я не могу найти документацию для поощрения запускать только одну службу в любом месте, и это кажется странным. Что делать, если вы хотите сначала загрузить учетные данные или запустить некоторые сценарии запуска, которые должны выполняться во время выполнения? Можете ли вы предоставить ссылку на свою заявку? – Eli

9

Убедитесь, что вы добавляете daemon off; вам nginx.conf или запустить его с CMD ["nginx", "-g", "daemon off;"] согласно официального Nginx изображения

Затем используйте следующий запустить и супервизор как обслуживание и Nginx как процесс переднего плана, который предотвратит контейнер от выхода

service supervisor start && nginx

в некоторых случаях вам нужно будет иметь более чем один процесс в контейнере, так заставляя контейнер иметь ровно один процесс не будет работать и может создать больше проблем в развертывании.

Таким образом, вам необходимо понять компромиссы и принять ваше решение соответствующим образом.

33

Причина, по которой он выходит, заключается в том, что сценарий оболочки запускается сначала как PID 1, и когда это будет завершено, PID 1 исчезнет, ​​а докер будет работать только в то время как PID 1.

Вы можете использовать супервизор, чтобы сделать все, если работать с «-пом» флагом он сказал не демон, так что он будет оставаться в качестве первого процесса:

CMD ["/usr/bin/supervisord", "-n"] 

И вашего supervisord.conf:

[supervisord] 
nodaemon=true 

[program:startup] 
priority=1 
command=/root/credentialize_and_run.sh 
stdout_logfile=/var/log/supervisor/%(program_name)s.log 
stderr_logfile=/var/log/supervisor/%(program_name)s.log 
autorestart=false 
startsecs=0 

[program:nginx] 
priority=10 
command=nginx -g "daemon off;" 
stdout_logfile=/var/log/supervisor/nginx.log 
stderr_logfile=/var/log/supervisor/nginx.log 
autorestart=true 

Тогда у вас может быть столько других процессов, сколько вы хотите, и супервизор будет обрабатывать их перезапуск при необходимости.

Таким образом, вы можете использовать супервизор в случаях, когда вам понадобятся nginx и php5-fpm, и не имеет смысла их разлучать.

0

У меня такая же problem.You может попробовать эту команду: Докер журналы [контейнер]

Он покажет вам, почему контейнер stop.In моего случая показывает: Отказано в

42

У меня была такая же проблема, и я узнал, что если вы используете свой контейнер с флагом -t и -d, он продолжает работать.

docker run -td <image> 

Вот что делают флаги (согласно docker run --help):

-d, --detach=false   Run container in background and print container ID 
-t, --tty=false   Allocate a pseudo-TTY 

Наиболее важным из них является -t флаг. -d просто позволяет вам запускать контейнер в фоновом режиме.

+1

Я не могу воспроизвести это. Не могли бы вы привести пример? Есть ли что-то конкретное (например: CMD) о файле Dockerfile, который нам нужен, чтобы это работало? –

+1

Это не сработало для меня. Я использовал команду 'docker logs ', чтобы убедиться, что это ошибка, из-за которой мой контейнер-докер заканчивается. Статус выхода - '0', а последний вывод - это то, что работает мой' lighttpd 'erver: '[ok] Запуск веб-сервера: lighttpd. ' – ob1

+0

Я еще не работал с Docker. Таким образом, возможно, что интерфейс командной строки изменился и эта команда больше не работает. –

24

просто использовать tail -F -n0 /etc/hosts или что-то

он будет держать ваш контейнер работает до тех пор, пока вы не остановить его

+0

в дополнение к моему ответу: но поймите, что docker-compose (not daemonized) используется, чтобы показать вам рабочий процесс вашего контейнера, поэтому было бы удобно уловить файлы журналов ваших запущенных сервисов. cheers –

+1

Это взлом, но он работает –

17

Если вы используете Dockerfile, попробуйте:

ENTRYPOINT ["tail", "-f", "/dev/null"]

(Очевидно, что это предназначено только для целей dev, вам не нужно сохранять контейнер в живых, если только он не выполняет процесс, например nginx ...)

1

Захват PID процесса ngnix в переменной (например, $ NGNIX_PID) и в конце файла Entrypoint сделать

wait $NGNIX_PID 

Таким образом, ваш контейнер должен работать до тех пор ngnix пока жив, когда ngnix останавливается, контейнер также останавливается

Смежные вопросы