0%

Linux Supervisor

背景

​ 最近在搭建混沌工程所需要的专项测试环境,原来一般都是直接通过 nohup + & 的方式,但该方式存在一个问题,如果由于服务器重启或者进程被kill掉了,那这个时候就需要再手动的去启动相应的进程。 这样对于只有一两个进程来说还好,但对于需要维护很多台虚拟机或者很多进程的时候则会比较繁琐。所以便牵扯到守护进程一一Supervisor

什么是守护进程

在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。由于在linux中,每个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭。但是守护进程却能突破这种限制,它脱离于终端并且在后台运行,并且它脱离终端的目的是为了避免进程在运行的过程中的信息在任何终端中显示并且进程也不会被任何终端所产生的终端信息所打断。它从被执行的时候开始运转,直到整个系统关闭才退出。

Supervisor

比较容易弄混淆的几个名词:

  • supervisor:要安装的软件的名称;
  • supervisord:装好 supervisor 软件后,supervisord 用于启动 supervisor 服务;
  • supervisorctl:用于管理 supervisor 配置文件中 programsupervisor 服务本身。

在 Linux 上有很多可以管理进程的工具,使用 Supervisor 来做这个事情。原因有两点:

  • 它是微软官方文档推荐的,降低学习成本。
  • 它并不一定是最好的,但一定是文档最全的。

Docker上安装 supervisor

下面主要介绍下在新的Docker环境上安装supervisor的过程中可能遇到的问题。(也可参考supervisor官网的安装方式)

问题一:新启动的Docker,通过yum安装 supervisor 失败。

1
2
3
4
5
6
7
8
9
[root@fafebfab0828 /]# yum install -y supervisor
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
* base: mirrors.nju.edu.cn
* extras: mirrors.nju.edu.cn
* updates: mirrors.nju.edu.cn
...
No package supervisor available.
Error: Nothing to do

即使通过修改了yum源的配置,仍然存在这个问题。

根本原因:新启动的Docker中,不存在 EPEL(Extra Packages for Enterprise Linux)企业版Linux额外包,PHEL分布非标准包的社区类库。

解决方案

  1. 安装EPEL包推荐

    1
    2
    yum -y install epel-release
    yum install -y supervisor
  2. 通过 Centos pkg 官网 (链接为Centos7,如是其他系统需找到对应链接)找到对应的 supervisor 安装包。

    ⚠️ PS: 其缺点是该安装包如果还依赖其他的包就会挺麻烦,可能还需要按照该方式下载其他的依赖包。

    1
    2
    3
    4
    5
    6
    # 此时安装 supervisor 还是依赖 python-meld3 和 python-setuptools
    [root@28c67f46fd89 home]# rpm -ivh supervisor-3.4.0-1.el7.noarch.rpm
    warning: supervisor-3.4.0-1.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY
    error: Failed dependencies:
    python-meld3 >= 0.6.5 is needed by supervisor-3.4.0-1.el7.noarch
    python-setuptools is needed by supervisor-3.4.0-1.el7.noarch

问题二:开机自启动 supervisor 失败

1
2
3
4
5
# 开机自启动
systemctl enable supervisor
# 启动 supervisord 服务
systemctl start supervisor
Failed to get D-Bus connection: Operation not permitted

原因:Docker运行一个容器起来的时候,只是为你提供特定的文件系统层和进程隔离,它给你一个VM的感觉却并不是VM,所以你可能偶尔会想要像在物理机那样使用systemctl start|status|stop来管理服务进程,就会出现上述错误。

需要启动systemd进程, 所以需要特权。解决办法:

1
2
3
4
5
# 创建容器
docker run -d --name centos7 --privileged=true centos:7 /usr/sbin/init

# 进入容器中
docker exec -it centos7 /bin/bash

使用 supervisor 启动其他进程

下面通过python写了一个简单的demo,通过supervisor来进行自启动以及守护。

  1. 编写需要守护的Demo脚本:test.py,对应的目录为: home/demo/test.py,具体内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import time
    import logging

    def print_demo():
    count = 0
    LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
    logging.basicConfig(filename='/home/demo/my.log', level=logging.DEBUG, format=LOG_FORMAT)
    while True:
    time.sleep(1)
    logging.info("=================start print num: [%s]" % count)
    count += 1
    logging.debug("This is a debug log.")
    logging.critical("This is a critical log.")


    if __name__ == "__main__":
    print_demo()
  2. 配置 supervisord.d 下的启动脚本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@28c67f46fd89 demo]# cat /etc/supervisord.d/demo-python.ini
    [program:demo_python]
    command=python /home/demo/test.py
    autorestart=true
    user=root

    # 该文件更多的配置信息如下:
    [program:x]:配置文件必须包括至少一个program,x是program名称,必须写上,不能为空
    command:包含一个命令,当这个program启动时执行
    directory:执行子进程时supervisord暂时切换到该目录
    user:账户名
    startsecs:进程从STARING状态转换到RUNNING状态program所需要保持运行的时间(单位:秒)
    redirect_stderr:如果是true,则进程的stderr输出被发送回其stdout文件描述符上的supervisord
    stdout_logfile:将进程stdout输出到指定文件
    stdout_logfile_maxbytes:stdout_logfile指定日志文件最大字节数,默认为50MB,可以加KB、MB或GB等单位
    stdout_logfile_backups:要保存的stdout_logfile备份的数量
  3. 校验是否启动成功。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@28c67f46fd89 ~]# supervisorctl status
    demo_python RUNNING pid 12318, uptime 1 day, 22:49:35

    # 或者通过ps和查看日志的内容的办法确认是否正常
    [root@28c67f46fd89 ~]# ps aux|grep test
    hly 552 0.0 0.3 38460 7028 ? S 10:21 0:00 python /home/demo/test.py
    root 570 0.0 0.0 9104 828 pts/3 S+ 10:28 0:00 grep --color=auto test

    # 对应日志内容:
    [root@28c67f46fd89 ~]# cat /home/demo/my.log
    2021-11-22 10:23:20,724 - INFO - =================start print num: [22]
    2021-11-22 10:23:20,724 - DEBUG - This is a debug log.
    2021-11-22 10:23:20,724 - CRITICAL - This is a critical log.

supervisorctl 常用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
systemctl enable supervisor			# 开机自启动
systemctl start supervisor # 启动 supervisord 服务

# 停止所有的项目 【用stop停止掉的进程,用reload或者update都不会自动重启】
supervisorctl stop all
supervisorctl start all # 开始所有的项目
supervisorctl start xxxx(program_name) # 开始单个项目
supervisorctl restart xxxx(program_name) # 重启单个项目
supervisorctl stop xxxx(program_name) # 停止单个项目

# tail <name> stderr 查看制定任务启动失败的日志
supervisorctl tail demo_python stderr

# 查看项目运行状态
supervisorctl status

# reread、update、reload的区别
# update 更新新的配置到supervisord(不会重启原来已运行的程序)
# reload 载入所有配置文件,并按新的配置启动、管理所有进程(会重启原来已运行的程序)
supervisorctl reread # 重新加载配置
supervisorctl update # 更新supervisor配置 (更新后看起来会自动重启所有项目)
supervisorctl reload # 重新启动配置中的所有程序

2021/12/1分割线

最近又遇到一个新的问题:部分Python服务需要进行虚拟环境的加载,但启动脚本中又不能直接使用source命令。具体的解决方案如下:

1
2
3
4
5
6
7
8
9
10
11
# 解决办法
# 1. 编写shell脚本进行启动。具体代码如下:
#!/bin/bash
source /home/demo/ENV/bin/activate
exec python3 /home/demo/test.py

# 2. 编写 cat /etc/supervisord.d/demo-python.ini
[program:demo_python]
command=/bin/bash /home/demo/start_test.sh
autorestart=true
user=root

参考链接

------------- 本 文 结 束 感 谢 您 的 阅 读 -------------