• Supervisor 后台进程管理


    img

    Author:rab



    前言

    Supervisor 是一个进程控制系统,基于 Python 开发的一个 client/server 服务,它允许其用户监控和控制类 UNIX 操作系统上的许多进程(不支持 Windows 系统)。能将一个普通的命令行进程变为后台 daemon,并监控进程状态,异常退出时能自动重启。

    Supervisor 管理的进程,当一个进程意外被杀死,Supervisort 监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写 shell 脚本来控制。

    官方参考文档

    一、安装

    常用三种安装方法:yum、pip、easy_install。接下来以 CentOS 7.9 为例,分别介绍安装步骤。

    1.1 Yum

    1、安装 Supervisor

    yum install -y epel* && yum install -y supervisor
    
    • 1

    2、启动 Supervisor 并做开机自启动

    systemctl start supervisord.service
    systemctl enable supervisord.service
    
    • 1
    • 2

    3、验证 Supervisor 版本

    [root@supervisor ~]# supervisord -v
    3.4.0
    
    • 1
    • 2

    1.2 Pip

    1、安装 Python3.x

    image-20220807130748498

    没有 3.9 版本的 Python,想要安装更高版本的话,可通过编译安装。

    image-20220807132147612

    但是 Python 3.6 是可以安装的,对于 Surprise 安装该版本即可。

    yum install -y python36
    
    • 1

    image-20220807132450838

    2、安装 Supervisor

    使用 pip 来安装,前提要保证 pip 版本大于 2.6

    pip3.6 install supervisor
    
    • 1

    1.3 easy_install

    easy_install-3.6 supervisor
    
    • 1

    二、配置

    2.1 常用命令

    supervisorctl status                    // 查看所有进程的状态
    supervisorctl status es                 // 查看指定进程的状态
    supervisorctl start|stop|restart all    // 对所有进程操作
    supervisorctl stop es                   // 停止es
    supervisorctl start es                  // 启动es
    supervisorctl restart es                // 重启es
    supervisorctl update                    // 配置文件修改后使用该命令加载新的配置
    supervisorctl reload                    // 重新启动配置中的所有程序
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.2 配置文件

    安装好后在/etc/会生成一个 supervisord.conf 文件及一个 supervisord.d 文件目录。

    supervisord.d 目录用来存放用户自定义的进程配置。

    1、看看 supervisord.conf 配置文件内容

    image-20220807134516088

    ; Sample supervisor config file.
    
    [unix_http_server]
    file=/var/run/supervisor/supervisor.sock   ; (the path to the socket file)
    ;chmod=0700                 ; sockef file mode (default 0700)
    ;chown=nobody:nogroup       ; socket file uid:gid owner
    ;username=user              ; (default is no username (open server))
    ;password=123               ; (default is no password (open server))
    
    ;[inet_http_server]         ; inet (TCP) server disabled by default
    ;port=127.0.0.1:9001        ; (ip_address:port specifier, *:port for all iface)
    ;username=user              ; (default is no username (open server))
    ;password=123               ; (default is no password (open server))
    
    [supervisord]
    logfile=/var/log/supervisor/supervisord.log  ; (main log file;default $CWD/supervisord.log)
    logfile_maxbytes=50MB       ; (max main logfile bytes b4 rotation;default 50MB)
    logfile_backups=10          ; (num of main logfile rotation backups;default 10)
    loglevel=info               ; (log level;default info; others: debug,warn,trace)
    pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
    nodaemon=false              ; (start in foreground if true;default false)
    minfds=1024                 ; (min. avail startup file descriptors;default 1024)
    minprocs=200                ; (min. avail process descriptors;default 200)
    ;umask=022                  ; (process file creation umask;default 022)
    ;user=chrism                 ; (default is current user, required if root)
    ;identifier=supervisor       ; (supervisord identifier, default is 'supervisor')
    ;directory=/tmp              ; (default is not to cd during start)
    ;nocleanup=true              ; (don't clean up tempfiles at start;default false)
    ;childlogdir=/tmp            ; ('AUTO' child log dir, default $TEMP)
    ;environment=KEY=value       ; (key value pairs to add to environment)
    ;strip_ansi=false            ; (strip ansi escape codes in logs; def. false)
    
    ; the below section must remain in the config file for RPC
    ; (supervisorctl/web interface) to work, additional interfaces may be
    ; added by defining them in separate rpcinterface: sections
    [rpcinterface:supervisor]
    supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
    
    [supervisorctl]
    serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL  for a unix socket
    ;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
    ;username=chris              ; should be same as http_username if set
    ;password=123                ; should be same as http_password if set
    ;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
    ;history_file=~/.sc_history  ; use readline history if available
    
    ; The below sample program section shows all possible program subsection values,
    ; create one or more 'real' program: sections to be able to control them under
    ; supervisor.
    
    ;[program:theprogramname]
    ;command=/bin/cat              ; the program (relative uses PATH, can take args)
    ;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
    ;numprocs=1                    ; number of processes copies to start (def 1)
    ;directory=/tmp                ; directory to cwd to before exec (def no cwd)
    ;umask=022                     ; umask for process (default None)
    ;priority=999                  ; the relative start priority (default 999)
    ;autostart=true                ; start at supervisord start (default: true)
    ;autorestart=true              ; retstart at unexpected quit (default: true)
    ;startsecs=10                  ; number of secs prog must stay running (def. 1)
    ;startretries=3                ; max # of serial start failures (default 3)
    ;exitcodes=0,2                 ; 'expected' exit codes for process (default 0,2)
    ;stopsignal=QUIT               ; signal used to kill process (default TERM)
    ;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
    ;user=chrism                   ; setuid to this UNIX account to run the program
    ;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
    ;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
    ;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
    ;stdout_logfile_backups=10     ; # of stdout logfile backups (default 10)
    ;stdout_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
    ;stdout_events_enabled=false   ; emit events on stdout writes (default false)
    ;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
    ;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
    ;stderr_logfile_backups=10     ; # of stderr logfile backups (default 10)
    ;stderr_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
    ;stderr_events_enabled=false   ; emit events on stderr writes (default false)
    ;environment=A=1,B=2           ; process environment additions (def no adds)
    ;serverurl=AUTO                ; override serverurl computation (childutils)
    
    ; The below sample eventlistener section shows all possible
    ; eventlistener subsection values, create one or more 'real'
    ; eventlistener: sections to be able to handle event notifications
    ; sent by supervisor.
    
    ;[eventlistener:theeventlistenername]
    ;command=/bin/eventlistener    ; the program (relative uses PATH, can take args)
    ;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
    ;numprocs=1                    ; number of processes copies to start (def 1)
    ;events=EVENT                  ; event notif. types to subscribe to (req'd)
    ;buffer_size=10                ; event buffer queue size (default 10)
    ;directory=/tmp                ; directory to cwd to before exec (def no cwd)
    ;umask=022                     ; umask for process (default None)
    ;priority=-1                   ; the relative start priority (default -1)
    ;autostart=true                ; start at supervisord start (default: true)
    ;autorestart=unexpected        ; restart at unexpected quit (default: unexpected)
    ;startsecs=10                  ; number of secs prog must stay running (def. 1)
    ;startretries=3                ; max # of serial start failures (default 3)
    ;exitcodes=0,2                 ; 'expected' exit codes for process (default 0,2)
    ;stopsignal=QUIT               ; signal used to kill process (default TERM)
    ;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
    ;user=chrism                   ; setuid to this UNIX account to run the program
    ;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
    ;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
    ;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
    ;stdout_logfile_backups=10     ; # of stdout logfile backups (default 10)
    ;stdout_events_enabled=false   ; emit events on stdout writes (default false)
    ;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
    ;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
    ;stderr_logfile_backups        ; # of stderr logfile backups (default 10)
    ;stderr_events_enabled=false   ; emit events on stderr writes (default false)
    ;environment=A=1,B=2           ; process environment additions
    ;serverurl=AUTO                ; override serverurl computation (childutils)
    
    ; The below sample group section shows all possible group values,
    ; create one or more 'real' group: sections to create "heterogeneous"
    ; process groups.
    
    ;[group:thegroupname]
    ;programs=progname1,progname2  ; each refers to 'x' in [program:x] definitions
    ;priority=999                  ; the relative start priority (default 999)
    
    ; The [include] section can just contain the "files" setting.  This
    ; setting can list multiple files (separated by whitespace or
    ; newlines).  It can also contain wildcards.  The filenames are
    ; interpreted as relative to this file.  Included files *cannot*
    ; include files themselves.
    
    [include]
    files = supervisord.d/*.ini
    
    • 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
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129

    2、说明

    配置文件中看 [include] 部分,在该部分中,我们可以自定义应用程序管理配置,配置文件名以 *.ini 结尾,当然,你也可以根据自己的习惯来文件名,如files = supervisord.d/*.conf

    三、实践

    3.1 ES 服务

    以 ES 为例进行 Supervisor 功能验证。

    3.1.1 服务部署

    1、安装 ES

    执行安装脚本(略)

    image-20220807140726605

    2、验证 ES

    [root@supervisor elasticsearch]# lsof -i:9200 
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    java    1698 yyds  121u  IPv6  23984      0t0  TCP *:wap-wsp (LISTEN)
    
    • 1
    • 2
    • 3

    image-20220807141552973

    3.1.2 Supervisor 管理应用程序

    1、新增 Supervisor 自定义配置

    用于管理 ES 的生命周期

    vim /etc/supervisord.d/es.ini
    
    • 1
    [program:es]
    command=/data/elasticsearch/bin/elasticsearch
    directory=/data/elasticsearch
    user=yyds
    numprocs=1
    priority=1
    autostart=true
    startsecs=30
    satrtretries=3
    autorestart=true
    stopasgroup=true
    killasgroup=true
    redirect_stderr=true
    stdout_logfile_maxbytes=10MB
    stdout_logfile_backups=10
    stdout_logfile=/data/elasticsearch/logs/supervisor.log
    
    # 注意:command 后面是启动命令,不能写成后台方式启动,如:nohup java -jar xxx.jar & 否则无法启动
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、在上面 ES 安装中,已经启动 ES 了,为效果先 kill 掉

    image-20220807143255024

    3、启动服务

    supervisord -c /etc/supervisord.conf
    
    • 1

    4、看看状态

    [root@supervisor ~]# supervisorctl status es
    es                               RUNNING   pid 1269, uptime 0:01:46
    
    • 1
    • 2

    此时,如果你的服务器重启了,supervisor 管理的进程会随服务器的重启而重启,前提是你本身的 supervisord 做了开机自启动。

    3.2 Java 应用程序

    3.2.1 构建 jar 测试包

    image-20220807165005055

    3.2.2 Supervisor 管理应用程序

    1、新增配置文件

    [program:java-test]
    command=java -jar /root/java_code/target/springboot-test-1.0-SNAPSHOT.jar
    directory=/root/java_code/target
    user=root
    numprocs=1
    priority=1
    autostart=true
    startsecs=30
    satrtretries=3
    autorestart=true
    stopasgroup=true
    killasgroup=true
    redirect_stderr=true
    stdout_logfile_maxbytes=10MB
    stdout_logfile_backups=10
    stdout_logfile=/root/java_code/logs/supervisor.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2、重载配置文件

    supervisorctl reload
    
    • 1

    3、验证

    image-20220807170420085

    去浏览器访问:http://192.168.56.120:8080/test/

    image-20220807170523509

    3.3 启用 web 管理

    具备 Python 环境

    1、打开 HTTP web 字段注释

    vim /etc/supervisord.conf
    
    # 定义IP:PORT
    # 定义用户名/密码
    # 重载一下配置
    # 注意端口不要与系统已有端口冲突
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    image-20220807171118227

    2、重载配置

    supervisorctl reload
    
    • 1

    3、web 验证

    • 登录

      image-20220807171534194

    • 看看管理界面

      image-20220807172336066

    • 可进行相关的点击操作

      刷新、停止(所有)、重启(所有)、查看日志、清理日志

      image-20220807174752093

    • 查看日志

      image-20220807172422599

    四、Supervisord 对比 Systemd

    首先,Supervisord 是 Python 写的一个守护进程,在 Linux 中(yum安装的 Supervisord)它本身也是由 Systemd 来管理。

    而且 Systemd 也可以实现后台守护进程,稳定性相对于 Supervisor 要强,但是 Supervisord 具有统一进程管理的优势,同时也具备 Web 终端管理,实现进程的一键式管理。如果重启 Supervisord ,那 Supervisord 管理的整个进程也要被重启,对于 Systemd 来说,一个进程对应一个 Systemd 后台管理,而且是 Linux 原生的后台守护进程。

    以下为 Systemd 后台管理进程的一个案例,其实现效果等同于 Supervisord。

    vim /usr/lib/systemd/system/java-test.service
    
    • 1
    [Unit]
    Description=java-test project service
    Requires=network.target
    
    [Service]
    #User=root
    #Group=root
    Type=simple
    WorkingDirectory=/root/java_code/target
    ExecStart=/usr/bin/java -jar /root/java_code/target/springboot-test-1.0-SNAPSHOT.jar > /dev/null 2>&1
    ExecStop=/bin/kill -s HUP $MAINPID
    
    Restart=always
    RestartSec=30
    StartLimitInterval=30
    
    [Install]
    WantedBy=multi-user.target graphical.target
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    重载 systemd

    systemctl daemon-reload
    
    • 1

    启动 Java 进程

    # 启动
    systemctl start java-test.service
    
    # 开机自启
    systemctl enable java-test.service
    
    • 1
    • 2
    • 3
    • 4
    • 5

    五、FAQ

    5.1 加载 supervisor 配置报错

    1、报错现象

    Error: Another program is already listening on a port that one of our HTTP servers is configured to use.  Shut this program down first before starting supervisord.
    For help, use /usr/bin/supervisord -h
    
    • 1
    • 2

    2、解决方案

    # 找到sock文件并unlink或找到PID并kill掉 pe -ef |grep supervisord
    [root@supervisor logs]# find / -name supervisor.sock
    /run/supervisor/supervisor.sock
    
    # unlink 或 kill
    [root@supervisor logs]# unlink /run/supervisor/supervisor.sock
    
    # 再次加载
    [root@supervisor logs]# supervisord -c /etc/supervisord.conf
    
    # 再或者重启supervisor
    systemctl restart supervisord.service
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    image-20220807144149207

    image-20220807144232368

    5.2 supervisor 启动太快

    1、报错现象

    [root@supervisor ~]# supervisorctl status
    es                               FATAL     Exited too quickly (process log may have details)
    
    • 1
    • 2

    面向百度了一下,说把 startsecs 值设置为 0。

    [program:es]
    command=/data/elasticsearch/bin/elasticsearch
    directory=/data/elasticsearch
    user=yyds
    numprocs=1
    priority=1
    autostart=true
    startsecs=0
    satrtretries=3
    autorestart=true
    stopasgroup=true
    killasgroup=true
    redirect_stderr=true
    stdout_logfile_maxbytes=10MB
    stdout_logfile_backups=10
    stdout_logfile=/data/elasticsearch/logs/supervisor.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    好,重启后,确实变为 RUNNING 了

    [root@supervisor ~]# supervisorctl status
    es                               RUNNING   pid 22768, uptime 0:00:00
    
    • 1
    • 2

    但是,并没什么 R 用,ES 进程并没有起来。

    image-20220807150127308

    在看看 supervisor.log 日志。

    image-20220807145717858

    提示:没有找到 Java 环境。

    2、解决方案

    为什么一开始却是执行成功的呢?而我重启服务器后就说无法找到 JAVA 环境呢?安装日志输出内容,JAVA 路径必须为/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

    # 先来看看我本机的 JDK 路径
    [root@supervisor elasticsearch]# which java
    /opt/jdk/bin/java
    
    # 与日志输出的路径不一致,导致supervisor找不到JDK环境,从而导致ES无法运行,因为ES依赖于JDK
    
    • 1
    • 2
    • 3
    • 4
    • 5

    重新修改一下 JDK 二进制路径

    [root@supervisor elasticsearch]# rm -rf /etc/profile.d/jdk.sh 
    [root@supervisor elasticsearch]# source /etc/profile
    
    • 1
    • 2

    做软链接,再次查看 JDK 路径

    [root@supervisor elasticsearch]# ln -s /opt/jdk/bin/* /usr/bin/
    
    • 1

    image-20220807151301211

    重启后还报错

    image-20220807151923123

    而我本机已经设置了最大文件打开数了啊

    [root@supervisor logs]# ulimit  -H -n
    65536
    
    • 1
    • 2

    在看看 Supervisor 默认的配置文件,因该就是配置文件默认值的问题

    image-20220807160210727

    该值不能超过你操作系统本身的文件大小,于是将该值设置为 65536

    image-20220807160437074

    然后再次重启 Supervisor

    image-20220807160558812

    看看 ES 进程

    image-20220807160646239

    <点击跳转至开头>

  • 相关阅读:
    烟花效果,H5+C3+JS实现
    Shell和Terminal的区别于联系
    硅芯思见:【145】问芯吾跬(IC设计验证常见问题汇总三)
    【蓝桥杯选拔赛真题30】python计算倒数和 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析
    open clip论文阅读摘要
    LeetCode_704_二分查找
    12.6 - 每日一题 - 408
    Excel 数据透视表教程大全之 02 添加字段、设置数据格式应用货币模式、按值进行排序(教程含样本数据)
    mysql8 修改用户密码
    SDN环境搭建(超详细)
  • 原文地址:https://blog.csdn.net/IT_ZRS/article/details/126215750