Закрытие контейнеров Docker через супервизора
Я не могу закрыть контейнеры Docker, которые были запущены супервизором через supervisorctl stop all
. Даже через supervisorctl status
показано, что контейнеры опущены, docker ps
и ps
указывают, что они на самом деле все еще запущены.
Консультирование надзорной документации по действию для supervisorctl stop <name>
показывает, что SIGTERM
отправляется процессам, за которыми следует SIGKILL
, если все еще выполняется после некоторого льготного периода. Я попытался сделать это вручную и обнаружил, что
-
SIGTERM
, отправленный в процесс docker run
, ничего не делает
-
SIGKILL
действительно убивает процесс, но фактически не обновляет докер. docker ps
показывает, что этот контейнер все еще запущен
- Супервизор
SIGKILL
не закрывает контейнер
Возникает вопрос: как правильно закрыть контейнер Docker супервизором?
Вот результат моих экспериментов, имитирующих супервизора:
Исходная позиция: foo-1
и bar-1
работают (я оставил контейнеры GCE в, если они имеют значение). ps aux
и docker ps
находятся в синхронизации.
[email protected]:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ba70bf8937f me/app:foo "/bin/sh -c 'supervi 5 minutes ago Up 5 minutes foo-1
e1a684bcfceb me/app:bar "/bin/sh -c 'supervi 5 minutes ago Up 5 minutes bar-1
fce5db0517df google/cadvisor:0.8.0 "/usr/bin/cadvisor" 35 minutes ago Up 35 minutes bbbb
db677eed47ef kubernetes/pause:go "/pause" 35 minutes ago Up 35 minutes 0.0.0.0:4194->8080/tcp aaaa
[email protected]:~$ ps aux | grep "docker run"
root 23358 0.0 0.1 124092 11856 pts/0 Sl 02:05 0:00 docker run --rm --name foo-1 ... -i me/app:foo
root 23365 0.0 0.1 124092 11928 pts/0 Sl 02:05 0:00 docker run --rm --name bar-1 ... -i me/app:bar
Имитировать supervisorctl stop foo-1
, отправив SIGTERM
в процесс. Результат: процесс все еще активен.
[email protected]:~$ sudo kill -SIGTERM 23358
... <waiting> ...
[email protected]:~$ ps aux | grep "docker run"
root 23358 0.0 0.1 124092 11856 pts/0 Sl 02:05 0:00 docker run --rm --name foo-1 ... -i me/app:foo
root 23365 0.0 0.1 124092 11928 pts/0 Sl 02:05 0:00 docker run --rm --name bar-1 ... -i me/app:bar
[email protected]venv:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ba70bf8937f me/app:foo "/bin/sh -c 'supervi 6 minutes ago Up 6 minutes foo-1
e1a684bcfceb me/app:bar "/bin/sh -c 'supervi 6 minutes ago Up 6 minutes bar-1
fce5db0517df google/cadvisor:0.8.0 "/usr/bin/cadvisor" 36 minutes ago Up 36 minutes bbbb
db677eed47ef kubernetes/pause:go "/pause" 36 minutes ago Up 36 minutes 0.0.0.0:4194->8080/tcp aaaa
Следующее, что сделал бы супервайзер, это выдать SIGKILL
. Результат: Процесс убит (ps aux
), но все еще отображается как выполняемый процесс докера (docker ps
).
[email protected]:~$ sudo kill -SIGKILL 23358
[email protected]:~$ ps aux | grep "docker run"
root 23365 0.0 0.1 124092 11928 pts/0 Sl 02:05 0:00 docker run --rm --name bar-1 ... -i me/app:bar
[email protected]:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ba70bf8937f me/app:foo "/bin/sh -c 'supervi 19 minutes ago Up 19 minutes foo-1
e1a684bcfceb me/app:bar "/bin/sh -c 'supervi 19 minutes ago Up 19 minutes bar-1
fce5db0517df google/cadvisor:0.8.0 "/usr/bin/cadvisor" 49 minutes ago Up 49 minutes bbbb
db677eed47ef kubernetes/pause:go "/pause" 49 minutes ago Up 49 minutes 0.0.0.0:4194->8080/tcp aaaa
Супервизор был отключен во время описанного выше эксперимента (чтобы избежать вмешательства его автозапуска). Результат для явной отправки SIGKILL
в процесс не мог быть достигнут супервизором; процесс все еще был жив (даже несмотря на то, что диспетчер регистрирует состояние иначе).
Однако docker stop <container_id>
остановил контейнер.
Обновление
Внутри контейнеров Docker также выполняется процесс supervisord
, который управляет определенными процессами. Возможно, проблема в том, что сигналы не распространяются и, следовательно, не будут закрыты...
Обновление 2
Я сузил проблему. Мне удалось запустить процесс контейнеров из Dockerfile
, а не запускать supervisord
, и это имеет значение. Я могу контролировать этот контейнер через супервизор (тот, который находится за пределами контейнеров докеров, который управляет контейнерами).
Обновление 3
Настройка stopasgroup=true
как предложено здесь ничего не меняет.
Обновление 4
Мне удалось решить одну из проблем: supervisorctl
не смог завершить процесс. Проблема заключалась в том, что я запускал контейнеры докеров в файле конфигурации супервизора с помощью command=sudo docker run...
, который создал процесс sudo docker run...
и docker run...
. supervisorctl stop...
только что завершил процесс sudo docker run...
, пока фактический процесс докера все еще работал. Когда я опускаю команду sudo
, запускается только 1 процесс на программу супервизора и supervisorctl stop
завершает процесс.
Остается одна проблема, которая заключается в том, что docker ps
показывает, что контейнер все еще работает, а ps aux
- нет. Как ни странно, контейнеры по-прежнему активны, так как они реагируют на запросы. Быстрый просмотр списка процессов подтверждает, что все процессы, порожденные контейнером докера, все еще активны, но процесс docker run...
отсутствует в списке процессов.
Обновление 5
Отправка SIGTERM
, SIGHUP
или SIGQUIT
в процесс docker run
, похоже, ничего не делает для процесса. Только SIGKILL
правильно завершает процесс докера. Супервизор обновляется должным образом, но docker ps
все еще показывает, что процесс докера запущен.
Ответы
Ответ 1
Я думаю, что нашел проблему. Я этого не понимал, но существует несколько способов запуска программы при запуске контейнера докеров.
По-видимому CMD myexec param1 param2
запускает оболочку, которая, в свою очередь, запускает myexec
(фактически эти два процесса видны в контейнере с /bin/sh -c myexec...
в PID 1. Лучше всего запустить программу напрямую (в моем случае supervisord).
С другой стороны, CMD ["/usr/bin/python", "/usr/local/bin/supervisord", "-c", "/root/supervisord.conf", "--nodaemon"]
работал нормально. Теперь я могу запустить и остановить контейнер докера через супервизора.
Вот соответствующий раздел в документах docker:
Инструкция CMD имеет три формы:
CMD ["executable","param1","param2"]
(форма exec, это предпочтительная форма)
CMD ["param1","param2"]
(как параметры по умолчанию для ENTRYPOINT)
CMD command param1 param2
(форма оболочки)
Обновление
Пример файла супервизора (внутри контейнера Docker):
[program:app]
command=python run_web_server.py
stdout_logfile=/var/log/app/app.log
directory=/opt/app
autostart=true
autorestart=false
stopsignal=INT
redirect_stderr=true
startretries=0
stopasgroup=true
killasgroup=true
[unix_http_server]
file=/var/run/supervisor.sock
chmod=0700
[supervisord]
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
childlogdir=/var/log/supervisor
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock
Шаблон mako для создания файла диспетчера Docker (снаружи):
[program:container]
command=docker run --rm --name ${name} \
% if container_links is not UNDEFINED:
% for host in container_hosts:
--add-host ${host['name']}:${host['ip']} \
% endfor
% endif
% if container_links is not UNDEFINED:
% for link in container_links:
--link ${link}:${link} \
% endfor
% endif
% if port_mappings is not UNDEFINED:
% for ext in port_mappings:
-p ${ext}:${port_mappings[ext]} \
% endfor
% endif
-e "INSTANCE_NAME=${name}" \
-e "TZ=${timezone}" \
% if environ is not UNDEFINED:
% for k in environ:
-e "${k}=${environ[k]}" \
% endfor
% endif
-v ${deployment_dir}/tmp:${deployment_dir}/app/tmp \
... more -v
-i foo/app-${version}:${type}
stdout_logfile=${deployment_dir}/log/${name}.log
redirect_stderr=true
autostart=false
autorestart=false
% if priority is not UNDEFINED:
priority=${priority}
% endif
startretries=0
# stopasgroup=true
# killasgroup=true