文章目录
- 概念
- supervisor简介
- supervisor特性
- 主要组件
- debian仓库里的版本
- 核心组件——supervisord
- 核心组件——supervisorctl
- 配置详解
- systemctl系统服务
- supervisord服务端
- supervisorctl客户端
- 子进程配置
- 案例
- 测试项目
- 安装supervisor
- 修改配置
- 守护一个shell
- 查看子进程动态
- SONiC实战
- 设置交换机IP
- 等待确认pmon启动
- 修改supervisor配置
- 修改热管理代码
- 配置子进程日志输出
- 附录
- 修改运行中的docker容器
- 参考资料
概念
supervisor简介
supervisor是一个守护套件,用于守护没有独立进程的工具,比如python、bash等等。它可以像系统服务一样守护多个进程,配置依赖关系、shell优先级、环境变量、开机自启、禁止或允许shell启动、print转发logger等等,功能丰富而强大。fancontrol、thermalctld、psud、syseepromd、xcvrd等等都用此套件来保证脚本程序持续运行和异常恢复。
在debian系统中,此守护套件被systemd守护,依赖supervisor维护的shell如此被多层守护,重重守护,保障用户的shell长久运行。它与launchd、daemontools和runit等程序有一些相同的目标。与其中一些程序不同,它并不意味着作为init的“1号进程”来运行。相反,它旨在用于控制与项目或客户相关的流程,并旨在像启动时的任何其他程序一样启动。
supervisor特性
-
方便:传统方式,开发者需要为每个进程实例编写rc.d脚本。这很不方便。rc.d脚本包含进程初始化、自动启动、管理等公共管理表格,它们的编写和维护可能很困难。此外,rc.d脚本无法自动重新启动崩溃的进程,许多程序在崩溃时也无法正常重新启动。Supervisord将流程作为其子流程启动,并且可以配置为在崩溃时自动重新启动它们。它还可以自动配置为在自己的调用中启动进程。
-
精准:在UNIX上,通常很难获得进程的准确上下文状态。Pid文件经常不可靠。supervisord将进程作为子进程启动,因此它总是知道其子进程的真实上行/下行状态,并且可以方便地查询这些数据。
-
可委托:需要控制流程状态的用户通常只需要这样做。他们不希望或不需要对运行进程的机器进行全面的shell访问。侦听“低”TCP端口的进程通常需要作为根用户启动和重新启动(UNIX的一个错误功能)。通常情况下,允许“正常”人员停止或重新启动这样的进程是完全可以的,但为他们提供shell访问权限通常是不切实际的,并且为他们提供root访问权限或sudo访问权限通常也是不可能的。也很难(正确地)向他们解释为什么存在这个问题。如果supervisord以root用户身份启动,则可以允许“普通”用户控制此类过程,而无需向他们解释问题的复杂性。Supervisorctl允许对机器进行非常有限的访问,本质上允许用户通过从简单的shell或web UI发出“停止”、“启动”和“重新启动”命令来查看流程状态并控制Supervisorord控制的子流程。
-
进程分组:进程通常需要分组启动和停止,有时甚至需要按“优先级顺序”启动和停止。通常很难向人们解释如何做到这一点。Supervisor允许您为进程分配优先级,并允许用户通过supervisorctl客户端发出命令,如“start all”和“restart all”,后者按预先分配的优先级顺序启动进程。此外,进程可以分为“进程组”,一组逻辑相关的进程可以作为一个单元停止和启动。
主要组件
debian仓库里的版本
supervisor是一个C/S模型的软件。supervisord是S端,supervisorctl是C端。查询版本,运行apt policy supervisor
显示:
supervisor:Installed: (none)Candidate: 4.2.1-1ubuntu1Version table:4.2.1-1ubuntu1 500500 http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
检查依赖,运行apt depends supervisor
显示:
supervisorbashPreDepends: init-system-helpers (>= 1.54~)Depends: lsb-baseDepends: python3-pkg-resourcesDepends: <python3:any>python3Suggests: supervisor-doc
核心组件——supervisord
supervisor的服务器部分被命名为supervisord。 它负责在自己的调用下启动子程序,响应客户的命令,重新启动崩溃或退出的子进程,记录子进程的stdout和stderr输出,并生成和处理与子进程生命周期内各点相对应的 “事件”。 这通常位于/etc/supervisord.conf中。 这个配置文件是一个 "Windows-INI "风格的配置文件。 保持这个文件的安全是很重要的,因为它可能包含未加密的用户名和密码。
运行 Supervisor 时会启动一个进程 supervisord,它负责启动所管理的进程,并将所管理的进程作为自己的子进程来启动,而且可以在所管理的进程出现崩溃时自动重启,其可执行文件位于:/usr/local/bin/supervisord,主要由python3实现。
核心组件——supervisorctl
Supervisor的命令行客户端被称为supervisorctl。 它为supervisord所提供的功能提供了一个类似shell的接口。 通过supervisorctl,用户可以连接到不同的supervisord进程,获得由supervisord控制的子进程的状态,停止和启动子进程,并获得supervisord的运行进程列表。 服务器可以断言客户端的用户在允许他执行命令之前应该出示认证凭证。 客户端进程通常使用与服务器相同的配置文件,但任何带有[supervisorctl]
部分的配置文件都可以使用。
这是命令行管理工具,同时支持交互模式,可以用来执行 stop、start、restart 等命令,来对这些子进程进行管理,类似systemctl。supervisor是所有进程的父进程,管理着启动的子进程,supervisor以子进程的PID来管理子进程,当子进程异常退出时supervisor可以收到相应的信号量。有些比较重要的功能设计还有欠缺,比如不停服务更新配置文件systemctl reload nginx
,nginx会在不停止服务的情况下装载/etc/nginx.conf
并更新,supervisor就没有类似的协议与受控进程间通讯。
配置详解
systemctl系统服务
supervisor自身依靠systemctl托管,其配置文件位于/lib/systemd/system/supervisor.service
,典型的配置文件内容如下所示:
[Unit]
Description=Supervisor process control system for UNIX
Documentation=http://supervisord.org
After=network.target[Service]
ExecStart=/usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown
ExecReload=/usr/bin/supervisorctl -c /etc/supervisor/supervisord.conf $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=50s[Install]
WantedBy=multi-user.target
supervisord服务端
supervisord是服务端,也是核心服务,它具体实现了对子进程的守护,根据守护进程的配置记录子进程的日志等等,它的配置文件位于:/etc/supervisor/supervisor.conf
,详细说明如下:
; supervisor config file[unix_http_server] ; Web管理配置
file=/var/run/supervisor.sock ; socket文件路径
;chmod=0700 ; socket 文件的权限,也是默认值
;chown=nobody:nogroup ; socket 所属用户及组
;username=user ; 用户名
;password=123 ; 密码;[inet_http_server] ; 是否启用web管理端,默认关闭,如果启用则可以通过web端口管理服务配置、在线查看子进程的日志。还需docker容器开放此端口。
;port=127.0.0.1:9001 ; 监听的IP及端口
;username=user ; 用户名
;password=123 ; 密码[supervisord] ;supervisord 全局配置
logfile=/var/log/supervisor/supervisord.log ; supervisor 日志路径,默认值是$CWD/supervisord.log
logfile_maxbytes=50MB ; 单个日志文件最大数
logfile_backups=10 ; 保留多少个日志文件(默认10个)
loglevel=info ; 日志等级,默认为info; 还可以设置debug、warn、trace
pidfile=/var/run/supervisord.pid ; pid 文件路径
nodaemon=false ; 启动是否丢到前台,设置为false ,表示以daemon 的方式启动
minfds=1024 ; 最小文件打开数,对应系统limit.conf 中的nofile ,默认最小为1024,最大为4096
minprocs=200 ; 最小的进程打开数,对应系统的limit.conf 中的nproc,默认为200
childlogdir=/var/log/supervisor ; 受托管的子进程的日志文件路径
;umask=022 ; (进程创建文件使用的权限的掩码)
;user=chrism ; 启动supervisord服务的用户,默认为root,设置为其它普通用户可提升系统安全性
;identifier=supervisor ; 服务标识,默认值为'supervisor'
;directory=/tmp ; 后台服务的工作目录
;nocleanup=true ; 启动时不要清理临时文件,默认为false,即启动时清理临时文件
;childlogdir=/tmp ; 子进程日志目录,默认值是$TEMP。此配置为空则子进程的日志丢失
;environment=KEY=value ; 子进程环境变量键值对,还可在子进程配置中分别配置。
;strip_ansi=false ; 转义字符在日志中是否用转义字符串表示。默认值为false,即不转义,日志消息若有换行,则日志文件体现出换行。如果希望每条消息仅占用一行或者日志文件是一张表格,则应设置为true。; 以下部分必须保留在配置文件中,RPC(supervisorctl/web接口)才能工作,可以通过在单独的rpcinterface:部分中定义额外的接口来添加
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface; [include]部分只能包含“文件”设置。此设置可以列出多个文件(用空格或换行符分隔)。它还可以包含通配符。
; 文件名被解释为相对于此文件。包含的文件*不能包含文件本身。
[include]
files = /etc/supervisor/conf.d/*.conf;[group:thegroupname] ; 服务组管理,可以将多个服务名写到这里管理(组名自定义)
;programs=progname1,progname2 ; 上面include配置好的服务名,比如hello-cat1等等
;priority=999 ; 相对启动优先级,默认值是999,数值越大,级别越低。
supervisorctl客户端
一个最简单的配置文件,适用于CS两端在同一个系统的情况,无须登录密码直接操作。
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; supervisord服务端socket文件路径
;serverurl=http://127.0.0.1:9001 ; 用于访问局域网其它supervisord服务端,实现CS分离
;username=chris ; 登录账号
;password=123 ; 登录密码
;prompt=mysupervisor ; 命令行提示符,也叫前导符
;history_file=~/.sc_history ; 读取历史文件,如果存在,可批量执行操作。
supervisor安装成功后系统环境中存在supervisorctl工具,常用命令如下所示:
子进程配置
根据supervisord的include配置节,所有位于/etc/supervisor/conf.d/
的以.conf为后缀的文本文件都能被supervisord识别。子进程配置详解如下所示:
[program:theprogramname] ; 定义一个守护进程 ,比如下面的elasticsearch
command=/bin/cat ; 启动程序使用的命令,可以是绝对路径或者相对路径
;process_name=%(program_name)s ; 一个python字符串表达式,用来表示supervisor进程启动的这个的名称,默认值是%(program_name)s
;numprocs=1 ; Supervisor启动这个程序的多个实例,如果numprocs>1,则process_name的表达式必须包含%(process_num)s,默认是1
directory=/tmp ; supervisord在生成子进程的时候会切换到该目录
;umask=022 ; umask for process (default None)
;priority=999 ; 权重,可以控制程序启动和关闭时的顺序,权重越低:越早启动,越晚关闭。默认值是999
autostart=true ; 如果设置为true,当supervisord启动的时候,进程会自动启动
autorestart=true ; 设置为随 supervisord 重启而重启,值可以是false、true、unexpected。false:进程不会自动重启
;startsecs=10 ; 程序启动后等待多长时间后才认为程序启动成功,默认是10秒
;startretries=3 ; supervisord尝试启动一个程序时尝试的次数。默认是3
;exitcodes=0,2 ; 一个预期的退出返回码,默认是0,2。
;stopsignal=QUIT ; 当收到stop请求的时候,发送信号给程序,默认是TERM信号,也可以是 HUP, INT, QUIT, KILL, USR1, or USR2
;stopwaitsecs=10 ; 在操作系统给supervisord发送SIGCHILD信号时等待的时间
;user=chrism ; 如果supervisord以root运行,则会使用这个设置用户启动子程序
;redirect_stderr=true ; 如果设置为true,进程则会把标准错误输出到supervisord后台的标准输出文件描述符
stdout_logfile=/a/path ; 把进程的标准输出写入文件中,如果stdout_logfile没有设置或者设置为AUTO,则supervisor会自动选择一个文件位置
stdout_logfile_maxbytes=1MB ; 标准输出log文件达到多少后自动进行轮转,单位是KB、MB、GB。如果设置为0则表示不限制日志文件大小
stdout_logfile_backups=10 ; 标准输出日志轮转备份的数量,默认是10,如果设置为0,则不备份
;stdout_capture_maxbytes=1MB ; 当进程处于stderr capture mode模式的时候,写入FIFO队列的最大bytes值,单位可以是KB、MB、GB
;stdout_events_enabled=false ; 如果设置为true,当进程在写它的stderr
;stderr_logfile=/a/path ; 把进程的错误日志输出一个文件中,除非redirect_stderr参数被设置为true
;stderr_logfile_maxbytes=1MB ; 错误log文件达到多少后自动进行轮转,单位是KB、MB、GB。如果设置为0则表示不限制日志文件大小
;stderr_logfile_backups=10 ; 错误日志轮转备份的数量,默认是10,如果设置为0,则不备份
;stderr_capture_maxbytes=1MB ; 当进程处于stderr capture mode模式的时候,写入FIFO队列的最大bytes值,单位可以是KB、MB、GB
;stderr_events_enabled=false ; 如果设置为true,当进程在写它的stderr到文件描述符的时候,PROCESS_LOG_STDERR事件会被触发
environment=A=1,B=2 ; 一个k/v对的list列表
;serverurl=AUTO ; 是否允许子进程和内部的HTTP服务通讯,如果设置为AUTO,supervisor会自动的构造一个url
案例
上述所有配置并非都对sonic项目有用。接下来根据最迫切的调试需求演示怎么方便地查看print输出。
测试项目
安装supervisor
此示例在WSL上运行:sudo apt install supervisor
,如下图所示:
修改配置
编辑/etc/supervisor/supervisord.conf
:
查看网页如下图所示:
守护一个shell
-
在home目录下新建一个名为
hello-supervisor.sh
的文件,代码如下:# !/bin/bashecho timer running while true doecho hello at $(date +%F%T)sleep 1 done
-
新增hello1的工作目录:
mkdir -p /var/supervisor/hello1
-
新增守护配置,运行
vim /etc/supervisor/conf.d/hello1.conf
查看子进程动态
两种方式,一种是运行命令:tail -f /var/supervisor/hello1/out.log
,如下图所示:
另一种方式是在网页上查看:
网页能启动能停止但不能配置,日志界面不自动滚屏,需手动操作。如有需要,可打开浏览器调试界面,在控制台输入以下代码:
setInterval(function() {window.scrollTo(0, document.body.scrollHeight);
}, 1000);
滚动条每隔1秒向下滚动1次:
SONiC实战
以pmon容器为例。其它容器操作方法一样。
设置交换机IP
交换机MGMT网口在开机启动时为动态IP,为简化网络访问,在登录成功、切换root账号后输入:ifconfig eth0 192.168.0.3
等待确认pmon启动
-
运行:
journalctl -fu pmon
,等待日志出现如下图所示:
-
运行
docker ps
,记住ID
修改supervisor配置
-
打开supervisor的web服务,编辑
/etc/supervisor/supervisord.conf
,找到[unix_http_server]
,追加代码[inet_http_server] port=:9010 username=pmon password=pmon
如下图所示:
-
退出并重启pmon容器,运行:
systemctl restart pmon
,在浏览器中打开:http://192.168.0.3:9010
,效果如下图所示:
修改热管理代码
为查看日志输出效果修改/usr/local/bin/thermalctld
。当前热管理在正常工作时不输出日志,使测试看不到效果。
-
以60为关键字进行搜索,全部改成10,如下图所示:
-
查找关键字:
def run
,分别追加代码print('executed som policies.')
和print('wait {} seconds'.format(self.wait_time))
,如下图所示:
配置子进程日志输出
以thermalctld为例,
-
新建thermalctld工作目录,运行:
mkdir -p /var/log/supervisor/thermalctld/
-
编辑
/etc/supervisor/conf.d/supervisord.conf
,如下图所示:
-
退出容器,重启pmon,运行:
systemctl restart pmon
附录
修改运行中的docker容器
首先须知,docker镜像不等于docker容器,它们是两个东西。docker镜像可随时随意修改,但docker容器不可以。docker容器来自于在docker镜像的基础来运行的docker run
命令。修改运行中的docker容器的需求来自于它人创建的docker镜像过于封闭,比如开放SSH登录端口等等。下面以修改pmon容器为例说明如何修改运行中的docker容器。 这里需要采用非常规方法在容器启动后修改端口映射设置。容器的端口映射在系统镜像构建的时候已设置,且已设置开启机自动启动。
-
根据上面的ID,进入目录:
cd /var/lib/docker/containers/3a101c79de35bed8ae3f930685f25790ebd3bdc13b148d788ee2d558a4b5caca
-
复制hostconfig.json内容到json格式化工具
-
修改之后复制回去保存,以同样的方法修改
config.v2.json
。 -
运行
docker restart pmon
。docker自动重新压缩配置文件。
参考资料
- linux command:
man supervisor
- http://supervisord.org/
- https://github.com/Supervisor/supervisor/issues/1406
作者: | 曹威 |
链接: | https://blog.csdn.net/caoshiying/article/details/130028462 |
时间: | 2021-04-04 |
版本: | 1.0 |