Подтвердить что ты не робот

Закрытие контейнеров 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 все еще показывает, что процесс докера запущен.

4b9b3361

Ответ 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