Как сохранить работоспособность контейнера Docker после запуска сервисов?
Я видел кучу учебников, которые, похоже, делают то же самое, что я пытаюсь сделать, но почему-то мои контейнеры Docker выходят. В принципе, я настраиваю веб-сервер и несколько демонов внутри контейнера Docker. Я делаю последние части этого через bash script, называемый run-all.sh
, который я запускаю через CMD в своем файле Docker. run-all.sh
выглядит следующим образом:
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 script, чтобы сохранить его, но как правильно удержать его от выхода?
Ответы
Ответ 1
Это не так, как вы должны проектировать свои контейнеры Docker.
При разработке контейнера Docker вы должны его построить таким образом, чтобы выполнялся только один процесс (т.е. у вас должен быть один контейнер для Nginx, один для супервизора или приложения, в котором он работает); Кроме того, этот процесс должен работать на переднем плане.
Контейнер "выйдет", когда сам процесс завершится (в вашем случае этот процесс - ваш bash script).
Однако, если вам действительно нужно (или хотите) запустить несколько сервисов в контейнере Docker, подумайте, начиная с "Docker Base Image" , который использует runit
как процесс псевдо-init (runit
будет оставаться в сети, пока Nginx и Supervisor работают), который останется на переднем плане, пока ваши другие процессы выполняют свою задачу.
У них есть существенные документы, поэтому вы сможете достичь того, что вы пытаетесь сделать достаточно легко.
Ответ 2
Если вы используете файл Docker, попробуйте:
ENTRYPOINT ["tail", "-f", "/dev/null"]
(Очевидно, что это предназначено только для целей dev, вам не нужно сохранять контейнер в живых, если он не запускает процесс, например nginx...)
Ответ 3
У меня была такая же проблема, и я узнал, что если вы используете свой контейнер с флагом -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
просто позволяет запускать контейнер в фоновом режиме.
Ответ 4
Причина, по которой он выходит, заключается в том, что оболочка script запускается сначала как PID 1, и когда это завершено, PID 1 исчез, а докер работает только в то время, когда PID 1.
Вы можете использовать супервизор для выполнения всего, если он запускается с флагом "-n", который он сказал, чтобы не демонализовать, поэтому он останется первым процессом:
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, и не имеет смысла их разлучать.
Ответ 5
Вы можете запустить обычный cat
без каких-либо аргументов, как упомянуто bro @Sa'ad, чтобы просто поддерживать работу контейнера [фактически ничего не делая, кроме ожидания ввода данных пользователем) (плагин Jenkins 'Docker делает то же самое)
Ответ 6
Убедитесь, что вы добавили daemon off;
к вам nginx.conf или запустили его с помощью CMD ["nginx", "-g", "daemon off;"]
в соответствии с официальным изображением nginx
Затем используйте следующее, чтобы запустить как супервизор как службу, так и nginx в качестве процесса переднего плана, который предотвратит выход из контейнера
service supervisor start && nginx
В некоторых случаях вам нужно будет иметь более одного процесса в вашем контейнере, поэтому принудительное подключение контейнера к одному процессу не будет работать и может создать больше проблем при развертывании.
Итак, вам нужно понять компромиссы и принять ваше решение соответственно.
Ответ 7
Захват PID процесса ngnix в переменной (например, $NGNIX_PID) и в конце файла точки входа
wait $NGNIX_PID
Таким образом, ваш контейнер должен работать до тех пор, пока ngnix не будет жив, когда ngnix остановится, контейнер также остановится
Ответ 8
Мотивация:
Нет ничего плохого в запуске нескольких процессов внутри контейнера Docker. Если вам нравится использовать докер в качестве легкоspring виртуальной машины - пусть будет так. Другие любят делить свои приложения на микро сервисы. Я думаю: ЛАМПА стек в одном контейнере? Просто здорово.
Ответ:
Придерживайтесь хорошего базового изображения, такого как базовое изображение. Там могут быть другие. Прокомментируйте, пожалуйста.
И это еще один призыв к руководителю. Потому что базовый образ phusion предоставляет супервизор помимо некоторых других вещей, таких как cron и locale setup. Вещи, которые вам нравятся, когда вы запускаете такую легкую виртуальную машину. Для чего это стоит и предоставляет ssh-соединения в контейнер.
Сам образ phusion просто запустится и продолжит работать, если вы выполните следующую базовую инструкцию запуска Docker:
[email protected]:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
[email protected]:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
521e8a12f6ff phusion/baseimage "/sbin/my_init" 12 seconds ago Up 11 seconds
Или просто:
Если базовый образ не для вас... Для быстрой работы CMD я бы предположил что-то вроде этого для bash:
CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"
Или это для busybox:
CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"
Это хорошо, потому что он немедленно выйдет на docker stop
. Простой sleep
или cat
займут несколько секунд, прежде чем контейнер выйдет.
Ответ 9
У меня такая же проблема. Вы можете попробовать эту команду: журналы докеров [контейнер]
Он покажет вам, почему контейнер останавливается. В моем случае он показывает: Разрешен отказ
Ответ 10
Как насчет использования формы надзора, если она доступна?
Служба YOUR_SERVICE контролирует
После успешного выполнения надзора он не выйдет, если не убили или специально попросили выйти.
Спасает необходимость создания supervisord.conf