容器进程树

使用 Docker 运行程序时,需要注意进程数是否正确,能否正确处理退出信号。本文记录几个我遇到过的案例。

Zabbix进程树错误

容器化 Zabbix 后运行不到1分钟就退出,日志如下。

     1:20181218:163231.437 One child process died (PID:1768,exitcode/signal:1). Exiting ...
     1:20181218:163233.444 syncing history data...
     1:20181218:163233.450 syncing history data done
     1:20181218:163233.450 syncing trends data...
     1:20181218:163241.877 syncing trends data done
     1:20181218:163241.878 Zabbix Server stopped. Zabbix 3.0.24 (revision 87227).

pstree看到进程树不对:

bash-4.1$ pstree
zabbix_server─┬─cron.sh
              ├─crond───crond───bash───sleep
              ├─2*[sh]
              └─156*[zabbix_server]

cron.sh用于发报警,发完就退出,不应该是zabbix_server的子进程

需要引入init程序,比如dumb-init

RUN chmod +x /init.sh
USER zabbix
ENTRYPOINT ["/usr/bin/dumb-init"]
CMD ["/init.sh"]

init.sh 脚本:

#!/bin/bash
[ ! -d /zabbix/alertscripts ] && mkdir -p /zabbix/alertscripts
[ ! -d /zabbix/externalscripts ] && mkdir -p /zabbix/externalscripts

sudo chown -R zabbix:zabbix /zabbix

sudo crond
exec /usr/sbin/zabbix_server -f -c $APP_CONFIG_PATH/ZABBIX_SERVER_CONF

gbalancer进程树错误

gbalancer-daemon选项无效,用 & 使程序进入后台,但是进程树错误:

dumb-init-+-crond
          |-nginx-+-gbalancer
          |       `-4*[nginx]
          `-php-fpm7---30*[php-fpm7]

使用 daemonize 解决,alpine中需要编译:

apk add gcc musl-dev make
./configure
make

正确的进程树:

dumb-init-+-crond
          |-gbalancer
          |-nginx---4*[nginx]
          `-php-fpm7---30*[php-fpm7]

supervisord处理退出信号

以下日志可以看到supervisord可以正确处理退出信号。

[root@itop php7-nginx]# docker logs php-sup
chown: /home/wwwroot/default/: No such file or directory
/usr/lib/python2.7/site-packages/supervisor/options.py:461: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
  'Supervisord is running as root and it is searching '
2018-12-25 10:30:19,447 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  If you intend to run as root, you can set user=root in the config file to avoid this message.
2018-12-25 10:30:19,458 INFO RPC interface 'supervisor' initialized
2018-12-25 10:30:19,458 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2018-12-25 10:30:19,458 INFO supervisord started with pid 1
2018-12-25 10:30:20,467 INFO spawned: 'nginx' with pid 29
2018-12-25 10:30:20,490 INFO spawned: 'php-fpm' with pid 30
2018-12-25 10:30:21,796 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2018-12-25 10:30:21,796 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2018-12-25 10:31:58,224 WARN received SIGTERM indicating exit request
2018-12-25 10:31:58,224 INFO waiting for nginx, php-fpm to die
2018-12-25 10:31:58,703 INFO stopped: php-fpm (exit status 0)
2018-12-25 10:31:58,744 INFO stopped: nginx (exit status 0)

使用exec

使用脚本启动程序时应该用 exec 替换 Shell 进程,否则 sh 进程将无法处理 SIGTERM 信号,容器内程序不能优雅的退出(最终会被 kill)。表现为执行 docker stop 时要等待一段时间(受 --shutdown-timeout int Set the default shutdown timeout (default 15) 参数影响)。

未使用 exec 时错误的进程树:

ae5c908cc86d:~# pstree 
sh---supervisord-+-nginx---4*[nginx]
                 `-php-fpm7---30*[php-fpm7]

docker stop时的日志,可以看到 supervisord 没有收到 SIGTERM

[root@itop php7-nginx]# docker stop php-sup
php-sup
[root@itop php7-nginx]# docker logs php-sup
chown: /home/wwwroot/default/: No such file or directory
/usr/lib/python2.7/site-packages/supervisor/options.py:461: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
  'Supervisord is running as root and it is searching '
2018-12-25 12:53:11,450 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  If you intend to run as root, you can set user=root in the config file to avoid this message.
2018-12-25 12:53:11,462 INFO RPC interface 'supervisor' initialized
2018-12-25 12:53:11,462 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2018-12-25 12:53:11,462 INFO supervisord started with pid 27
2018-12-25 12:53:12,467 INFO spawned: 'nginx' with pid 29
2018-12-25 12:53:12,520 INFO spawned: 'php-fpm' with pid 30
2018-12-25 12:53:13,770 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2018-12-25 12:53:13,771 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
[root@itop php7-nginx]# 

supervisord vs dumb-init

都能实现功能,但是 dumb-init 更轻量,supervisord 需要安装 Python 环境,镜像会比较大。

参考资料

1. https://www.artindustrial-it.com/2017/09/20/10-best-practices-for-creating-good-docker-images/

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注