Supervisor简介

Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。

它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。

也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非rootuser,这个user就可以管理它对应的进程。

事件背景

给公司用 docker 部署新的 dnmp 开发环境,想用 supervisor 实现对 php 进程和 swoole 进程的监控。但是部署了 dnmp 后,发现对于存活的 php 进程无法正确的监控到,始终报 fatal ,致命错误。

image-20210914112634470

错误分析

dnmp 中,由于 supervisor 作为一个独立的容器存在,所以对于监控配置文件 supervisor/conf.d/php-fpm.ini 中运行的 php 命令并无法正常执行(因为只有在php容器中才可执行 php-cli 命令)。

所以,接下来的改写,目的就是吧 supervisor 移植到 php 容器中运行。

参考文献

已修改的配置下载:https://github.com/jefferyjob/dnmp_supervisor

配置修改过程

php的dockerfile改写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
ARG PHP_VERSION
FROM ${PHP_VERSION}

ARG TZ
ARG PHP_EXTENSIONS
ARG CONTAINER_PACKAGE_URL

# 配置清华镜像
RUN if [ $CONTAINER_PACKAGE_URL ] ; then sed -i "s/dl-cdn.alpinelinux.org/${CONTAINER_PACKAGE_URL}/g" /etc/apk/repositories ; fi

# 安装php扩展
COPY ./extensions /tmp/extensions
WORKDIR /tmp/extensions
RUN chmod +x install.sh \
&& sh install.sh \
&& rm -rf /tmp/extensions

# 添加扩展安装执行脚本
ADD ./extensions/install-php-extensions /usr/local/bin/

# 赋予可执行权限
RUN chmod uga+x /usr/local/bin/install-php-extensions

# 安装必要的软件
# supervisor
# bash
# 设置时区
RUN apk update \
&& apk upgrade \
&& apk add supervisor \
&& apk add bash \
&& apk --no-cache add tzdata \
&& cp "/usr/share/zoneinfo/$TZ" /etc/localtime \
&& echo "$TZ" > /etc/timezone \
&& rm -rf /var/cache/apk/*

# Fix: https://github.com/docker-library/php/issues/240
RUN apk add gnu-libiconv libstdc++ --no-cache --repository http://${CONTAINER_PACKAGE_URL}/alpine/edge/community/ --allow-untrusted
ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php


# 安装 composer 并更改它的缓存主页
RUN curl -o /usr/bin/composer https://mirrors.aliyun.com/composer/composer.phar \
&& chmod +x /usr/bin/composer
ENV COMPOSER_HOME=/tmp/composer

# 配置用户组
RUN apk --no-cache add shadow && usermod -u 1000 www-data && groupmod -g 1000 www-data

# 设置工作目录
WORKDIR /var/www

主要修改的内容是:

1
2
3
4
5
6
7
8
RUN apk update \
&& apk upgrade \
&& apk add supervisor \
&& apk add bash \
&& apk --no-cache add tzdata \
&& cp "/usr/share/zoneinfo/$TZ" /etc/localtime \
&& echo "$TZ" > /etc/timezone \
&& rm -rf /var/cache/apk/*

docker-composer中 php 的容器编排修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# php7
php:
build:
context: ./services/php
args:
PHP_VERSION: php:7.4.7-fpm-alpine
CONTAINER_PACKAGE_URL: mirrors.ustc.edu.cn
PHP_EXTENSIONS: pdo_mysql,mysqli,mbstring,gd,curl,opcache,apcu,zip,opcache,redis,swoole
TZ: "Asia/Tokyo"
container_name: php
ports:
- "9001:9001"
expose:
- 9000 # php-fpm
- 9001 # supervisor
- 5200 # swoole laravels
#extra_hosts:
# - "www.site1.com:172.17.0.1"
volumes:
- ..:/var/www/:rw
- ./services/php/php.ini:/usr/local/etc/php/php.ini:ro
- ./services/php/php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf:rw
- ./logs/php:/var/log/php
- ./data/composer:/tmp/composer
# supervisor 文件映射配置
- ./services/supervisor/supervisord.conf:/etc/supervisord.conf:rw
- ./services/supervisor/conf.d:/etc/supervisor/conf.d:rw
- ./logs/supervisor:/var/log/supervisor:rw
restart: always
command:
- /bin/sh
- -c
- |
supervisord -n -c /etc/supervisord.conf
cap_add:
- SYS_PTRACE
environment:
APP_ENV: "developer"
networks:
- default

主要增加了 9001:9001的端口映射,然后在容器内部通过 expose 暴露 9001 的端口。

在 volumes 里面映射了 supervisor 的相关配置文件。

在 command 中加入了supervisor启动脚本:

1
2
3
4
5
command:
- /bin/sh
- -c
- |
supervisord -n -c /etc/supervisord.conf

修改supervisor对于php的监听配置

services/supervisor/conf.d/php-fpm.ini

1
2
3
[program:php]
command=/usr/local/bin/php -S 0.0.0.0:80
directory=/var/www/

然后重新 build 容器,最后 up 启动容器就成功了!

测试结果

image-20210914132415422

总结

当前处理方式的弊端

本篇文章处理的方式是将 supervisor 安装进 php 容器中,然后运行命令 command=/usr/local/bin/php -S 0.0.0.0:80 来监听 php 的相关进程。

所以这样做的弊端就是,如果 php 的容器宕机后,由于 supervisor 存在于php容器中,那么 supervisor 也将无法使用,所以supervisor失去了他监控健康进程的意义。

基于当前的环境要求如何改写

可以将 supervisor 继续作为一个独立的容器运行,然后在配置文件command中,通过 docker exec - it xxx xx 等相关配置,来监听别的容器中的相关进程是否健康。