分析Dockbix的Dockerfile--通用的多程序镜像的设计思路


一般来说一个软件的镜像的最后由ENTRYPOINTCMD来构成,有的镜像可能没有ENTRYPOINT,
ENTRYPOINTCMD的主要区别在于即使你在运行镜像时指定了“命令”
(e.g. docker run nginx echo "test"echo "test"部分就是“命令”),ENTRYPOINT
指定的命令(e.g. ENTRYPOINT entrypoint.sh)也不会被忽略。
总的来说,可以把以下几条规则当做创作Dockerfile的thumb rules:

  • RUN: 用来安装软件或添加依赖,因为RUN会创建一层layer

  • ENTRYPOINT: 用来指定该镜像为可执行程序,并且指定一个一个脚本用来初始化基础环境(
    e.g. 创建镜像运行时所使用的用户、加载程序的依赖、初始化环境变量等。)。

  • CMD: 用来运行软件。

  • ENTRYPOINTCMD结合使用:

    ENTRYPOINT entrypoint.sh中初始化环境,最后执行exec "$@",以此来继续执行
    CMD中的内容。

    参考:bitnami/nginx’s Dockerfile

Dockbix的Dockerfile的结构

大致上来说,和我们构建一个物理Zabbix服务器的结构是一样的。
都是先装OS,再安装Zabbix软件,以及准备一系列我们需要用来达到“自省”的脚本和工具软件。
以下是dockbix的Dockerfile,这个镜像构建出来的可以算是一个“一体化”软件。包括了Zabbix Server、
Zabbix Web Interface、Nginx作为web服务器。

dockbix’s Dockerfile

用图片来表示这个Dockerfile做了什么:

Dockerfile

从Dockbix镜像学习到实用的工具

Dockbix镜像运行起来之后,其程序树是这样的:

[root@8a11e51b8ddb /]# ps axjf
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
     0    615    615    615 pts/0      2343 Ss       0   0:00 /bin/bash
   615   2343   2343    615 pts/0      2343 R+       0   0:00  \_ ps axjf
     0      1      1      1 ?            -1 Ss       0   0:01 /usr/bin/python /usr/bin/supervisord -n -c /etc/supervisord.conf
     1    379    379      1 ?            -1 S        0   0:00 nginx: master process /usr/sbin/nginx
   379    389    379      1 ?            -1 S       80   0:00  \_ nginx: worker process
   379    390    379      1 ?            -1 S       80   0:00  \_ nginx: worker process
     1    380    380      1 ?            -1 S        0   0:01 php-fpm: master process (/etc/php-fpm.conf)
     1    381    381      1 ?            -1 S        0   0:00 /bin/sh /config/ds.sh /tmp/zabbix_server.pid sudo -u zabbix /usr/local/sbin/zabbix_server --foreground -c /usr/local/etc/zab
   381    383    381      1 ?            -1 S        0   0:00  \_ sudo -u zabbix /usr/local/sbin/zabbix_server --foreground -c /usr/local/etc/zabbix_server.conf
   383    392    381      1 ?            -1 S     1000   0:00      \_ /usr/local/sbin/zabbix_server --foreground -c /usr/local/etc/zabbix_server.conf
   392    399    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: configuration syncer [synced configuration in 0.016130 sec, idle 60 sec]
   392    400    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: alerter #1 started
   392    401    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: alerter #2 started
   392    402    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: alerter #3 started
   392    403    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: housekeeper [deleted 50373 hist/trends, 0 items/triggers, 85 events, 0 sessions,
   392    404    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: timer #1 [updated 0 hosts, suppressed 0 events in 0.000859 sec, idle 59 sec]
   392    405    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: http poller #1 [got 0 values in 0.000503 sec, idle 5 sec]
   392    406    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: discoverer #1 [processed 0 rules in 0.000670 sec, idle 60 sec]
   392    407    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: history syncer #1 [processed 0 values, 1 triggers in 0.000493 sec, idle 1 sec]
   392    408    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: history syncer #2 [processed 0 values, 0 triggers in 0.000010 sec, idle 1 sec]
   392    409    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: history syncer #3 [processed 1 values, 0 triggers in 0.001232 sec, idle 1 sec]
   392    410    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: history syncer #4 [processed 0 values, 0 triggers in 0.000015 sec, idle 1 sec]
   392    411    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: escalator #1 [processed 0 escalations in 0.000964 sec, idle 3 sec]
   392    412    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: proxy poller #1 [exchanged data with 0 proxies in 0.000045 sec, idle 5 sec]
   392    413    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: self-monitoring [processed data in 0.000026 sec, idle 1 sec]
   392    414    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: task manager [processed 0 task(s) in 0.000324 sec, idle 5 sec]
   392    415    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: poller #1 [got 0 values in 0.000013 sec, idle 1 sec]
   392    416    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: poller #2 [got 0 values in 0.000007 sec, idle 1 sec]
   392    417    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: poller #3 [got 0 values in 0.000007 sec, idle 1 sec]
   392    418    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: poller #4 [got 0 values in 0.000009 sec, idle 1 sec]
   392    419    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: poller #5 [got 1 values in 0.000538 sec, idle 1 sec]
   392    420    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: unreachable poller #1 [got 0 values in 0.000095 sec, idle 1 sec]
   392    421    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: trapper #1 [processed data in 0.000000 sec, waiting for connection]
   392    422    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: trapper #2 [processed data in 0.000000 sec, waiting for connection]
   392    423    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: trapper #3 [processed data in 0.000000 sec, waiting for connection]
   392    424    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: trapper #4 [processed data in 0.001913 sec, waiting for connection]
   392    425    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: trapper #5 [processed data in 0.011211 sec, waiting for connection]
   392    426    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: icmp pinger #1 [got 0 values in 0.000022 sec, idle 5 sec]
   392    427    381      1 ?            -1 S     1000   0:01          \_ /usr/local/sbin/zabbix_server: alert manager #1 [sent 0, failed 0 alerts, idle 5.010558 sec during 5.010662 sec]
   392    428    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: preprocessing manager #1 [queued 0, processed 4 values, idle 5.002023 sec during
   392    429    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: preprocessing worker #1 started
   392    430    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: preprocessing worker #2 started
   392    431    381      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_server: preprocessing worker #3 started
     1    382    382      1 ?            -1 S        0   0:00 /usr/bin/bash -c while true; do sleep 3600; /usr/bin/bash /config/init/12-xxl-ping.sh; done
   382   1761    382      1 ?            -1 S        0   0:00  \_ sleep 3600
     1    384    384      1 ?            -1 S        0   0:00 bash -c while inotifywait -q -r -e create,delete,modify,move,attrib --exclude "/\." /etc/nginx/ /data/conf/nginx/; do nginx
   384    388    384      1 ?            -1 S        0   0:00  \_ inotifywait -q -r -e create,delete,modify,move,attrib --exclude /\. /etc/nginx/ /data/conf/nginx/
     1    385    385      1 ?            -1 S        0   0:00 /bin/sh /config/ds.sh /tmp/zabbix_agentd.pid sudo -u zabbix /usr/local/sbin/zabbix_agentd --foreground -c /usr/local/etc/zab
   385    387    385      1 ?            -1 S        0   0:00  \_ sudo -u zabbix /usr/local/sbin/zabbix_agentd --foreground -c /usr/local/etc/zabbix_agentd.conf
   387    391    385      1 ?            -1 S     1000   0:00      \_ /usr/local/sbin/zabbix_agentd --foreground -c /usr/local/etc/zabbix_agentd.conf
   391    393    385      1 ?            -1 S     1000   0:02          \_ /usr/local/sbin/zabbix_agentd: collector [idle 1 sec]
   391    394    385      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_agentd: listener #1 [waiting for connection]
   391    396    385      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_agentd: listener #2 [waiting for connection]
   391    397    385      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_agentd: listener #3 [waiting for connection]
   391    398    385      1 ?            -1 S     1000   0:00          \_ /usr/local/sbin/zabbix_agentd: active checks #1 [idle 1 sec]



利用supervisor和inotify-util来做程序的自省和动态重载配置文件

Supervisor是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,supervisor监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

Dockbix中也实用supervisor来做Nginx和php-fpm的自动重启以及配置文件动态更新。

Dockbix镜像最终启动过程是大概如下:

  1. Dockbix的入口为config/bootstrap.sh,由Dockerfile最后的CMD定义。

  2. 执行config/bootstrap.sh过程中调用/config/init/bootstrap.sh,由传入的环境变量(环境变量在docker run --env=...来指定),来决定过滤掉哪些配置文件,也就是是否启动某些软件(功能)。

    比如如果不启动Nginx(i.e. Zabbix Web Interface),就传入ZW_enabled=false

    Dockbix Web Interface’s enabling logic

  3. 过滤不需要要启动的软件后启动,也就是删除掉不需要启动的软件的supervisor配置文件。

    supervisor的配置文件内容:

    [include]
    files = /etc/supervisor.d/*.conf

    supervisor.d/nginx.conf的内容:

    [program:nginx]
    command = /usr/sbin/nginx
    autorestart = true
    stderr_logfile = NONE
    stdout_logfile = NONE
    
    # Watch for changes in Nginx conf directories and restart Nginx when a config change occured
    [program:nginx-reload]
    command=bash -c 'while inotifywait -q -r -e create,delete,modify,move,attrib --exclude "/\." /etc/nginx/ /data/conf/nginx/; do nginx -t && nginx -s reload; done'

    这里可以看到,[program:nginx-reload]中定义了检查nginx的配置文件状态是否发生改变,如果发生改变,就调用nginx -s reload

  4. 最后继续执行config/bootstrap.sh,调用supervisor,来启动这个镜像需要执行的程序。

题外话

虽然使用supervisor可以解决Docker容器同时运行多个业务程序,就算业务程序挂了也无感知的问题,
能不能完美地做到单个容器中监控多个程序是否运行,应该也要看supervisor的配置文件中命令是否合理。


文章作者: 少年G
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 少年G !
评论
 上一篇
CentOS7 Install Docker and Docker Compose CentOS7 Install Docker and Docker Compose
Install Docker by yum with official repository and download the docker-compose executable as per the Linux distribution.
2019-09-17
下一篇 
使用Docker部署Zabbix监控系统来监控主机状态 使用Docker部署Zabbix监控系统来监控主机状态
使用 [monitoring/zabbix-docker-monitoring](https://github.com/monitoringartist/zabbix-docker-monitoring) 的镜像来部署 Zabbix,Zabbix 的 `server`、`proxy`、`agent` 包括 `server` 的 `Mariadb`,全部都是容器化部署。感兴趣的可以阅读 GitHub 原文以了解更多。
2019-09-11
  目录