daemon
Daemon 守护进程服务
- systemd
- supervisor
- launchd
一、supervisor
是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程
supervisor官网:supervisord.org
安装supervisor
supervisor是用python开发的,支持yum和pip安装
[root@localhost ~]# yum install supervisor
[root@localhost ~]# pip3 install supervisor
配置文件
若没有配置文件,可以生成主配置文件模板
[root@localhost ~]# echo_supervisord_conf > /etc/supervisord.conf
# 参考链接
http://supervisord.org/configuration.html
配置模板
# 参数可以根据需求进行调整
[program:pock]
directory=/home/sugars/pock/backend
command=/home/sugars/pock/pock_venv/bin/python3 /home/sugars/pock/backend/sugars.py
autostart=true
autorestart=true
startsecs=7
user = sugars
stderr_logfile=/var/log/supervisor/pock-err.log
stdout_logfile=/var/log/supervisor/pock.log
redirect_stderr = true
stdout_logfile_maxbytes = 50MB
stdout_logfile_backups = 3
stopasgroup=true
killasgroup=true
配置文件读取目录于顺序
# 配置文件明名为supervisor.comf,如果不使用`-c` 指定文件名,则自动匹配的文件路径为
1) ../etc/supervisord.conf
2) ../supervisord.conf
3) $CWD/supervisord.conf
4) $CWD/etc/supervisord.conf
5) /etc/supervisord.conf
6) /etc/supervisor/supervisord.conf
systemctl start supervisord
supervisor命令说明
supervisorctl status 查看进程运行状态
supervisorctl start g_name 启动进程
supervisorctl stop g_name 关闭进程
supervisorctl restart g_name 重启进程
supervisorctl update 重新载入配置文件(配置文件修改后使用该命令加载新的配置)
supervisorctl shutdown 关闭
supervisord supervisorctl clear g_name 清空进程日志
supervisorctl 进入到交互模式下。使用help查看所有命令。
supervisorctl start/stop/restart + all 表示启动,关闭,重启所有进程
supervisorctl reload //重新启动配置中的所有程序
新添加一个program
后的操作
root@serialt:~# supervisorctl update sugar
停止sugar
服务
root@serialt:~# supervisorctl stop sugar
启动sugar
服务
root@serialt:~# supervisorctl start sugar
重启sugar
服务
root@serialt:~# supervisorctl restart sugar
日志管理
在rhel中,supervisord的日志轮转管理是通过调用logrotate来实现的,其配置文件内容是
[root@serialt ~]# cat /etc/logrotate.d/supervisor
/var/log/supervisor/*.log {
missingok
weekly
notifempty
nocompress
}
会自动轮转/var/log/supervisor/*.log
的文件,若把用supervisor管理的日志也输入到/var/log/supervisor/
里会导致日志文件被轮转成带时间戳的格式
sugar.log
sugar.log-20211019
sugar.log-20211026
sugar.log.1
sugar.log.2
sugar.log.3
两种解决办法:
1)修改supervisord的日志记录文件,同时修改supervisord的logrotate配置文件
2)supervisord管理的进程的日志不输出到/var/log/supervisor
里
日志压缩
supervisord本身日志只能轮转,不能用于压缩,要实现日志压缩论证,需要借用logrotate
[root@tc ~]# cat /etc/logrotate.d/sugar
/var/log/sugar/*.log {
missingok
daily
notifempty
create 0664 nobody root
#dateext
#dateformat .%Y%m%d
rotate 20
compress
delaycompress
copytruncate
size 10K
}
二、systemd
常用命令
systemctl restart foo
systemctl stop foo
systemctl start foo
systemctl status foo
systemctl cat foo
systemctl daemon-reload
配置模板
[Unit]
Description=Gins
After=network-online.target
Documentation=https://serialt.github.io/
Documentation=https://serialt.github.io on-failure always
[Service]
Type=simple
WorkingDirectory=/usr/local/gin
KillSignal=SIGTERM
ExecStart=/usr/local/gins/bin/gins start
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=on-failure
RestartSec=3
TimeoutSec=50
User=gins
Group=gins
[Install]
WantedBy=multi-user.target
systemd 236之后的版本可以直接在systemd的unit文件里面配置StandardOutput
和StandardError
两个参数来将相关运行日志输出到指定的文件中。
[Unit]
Description=Gins
After=network.target
Documentation=https://serialt.github.io/
Documentation=https://serialt.github.io on-failure always
[Service]
Type=simple
WorkingDirectory=/usr/local/gin
KillSignal=SIGTERM
ExecStart=/usr/local/gins/bin/gins start
ExecStop=/bin/kill -SIGTERM $MAINPID
# append类型可以在原有文件末尾继续追加内容,而file类型则是重新打开一个新文件
# 两者的区别类似于 echo >> 和 echo >
StandardOutput=append:/home/coredns/logs/coredns.log
StandardError=append:/home/coredns/logs/coredns_error.log
Restart=on-failure
RestartSec=3
TimeoutSec=50
User=gins
Group=gins
[Install]
WantedBy=multi-user.target
三、launchd服务
https://www.fythonfang.com/blog/2021/4/19/mac-launchd-daemons-and-agents-tutorial
基本概念
launchd
是 MacOS 上用于管理系统级或者用户级后台服务进程的管理工具。也是官方推荐的系统后台进程管理工具,就好像在 Linux 系统里,我们使用 systemd
去管理后台服务进程一样。
launchd
是一个程序,以系统常驻进程的形态运转,是 MacOS 系统启动后的第一个进程,在 Terminal 终端,键入命令 ps aux
可以看到,launchd
的进程ID(PID)是 1
。也即这是系统的第一个进程。
与 launchd
交互的工具,叫 launchctl
。可以认为是它的管理客户端程序。通过该命令,我们可以发送指令给 launchd
完成对系统服务或后台进程的管理。
launchd
的管理对象都是后台进程,这些后台进程使用一种特定格式的配置文件叫 launchd.plist
来描述被管理的对象。这种文件是 XML
格式的,根据不同的运行权限,放在不同的目录里面,请看下面的表格。
目录 | 说明 |
---|---|
~/Library/LaunchAgents |
用户自己提供的用户级 Agent。 |
/Library/LaunchAgents |
管理员提供的用户级 Agent。 |
/Library/LaunchDaemons |
管理员提供的系统级 Daemon。 |
/System/Library/LaunchAgents |
苹果官方提供的用户级 Agent。 |
/System/Library/LaunchDaemons |
苹果官方提供的系统级 Daemon。 |
存放 launchd 配置文件的常用目录
通过 launchd
管理的进程,人为被分为了几个种类:
- 服务(Services)—— 在后台运行,用以支持图形界面应用(GUI App)运行的服务进程,比如响应系统全局快捷键,或者进行网络通信等;
- 守护进程(Daemons)—— 理论上,不属于服务的后台进程,都归为守护进程一类,不过这里特指运行在后台,且不能与用户交互图形界面产生联系的进程;
- 代理(Agents)—— 以用户的名义,在后台运行的进程,可以和用户图形界面产生联系,比如呼起一个软件的界面,不过官方不推荐这么用。
一般文件名都以com.domain.programName.plist
格式命名,不管是 Daemons 还是 Agents 格式都是一样的,只是存放位置不同。看下面一个 hello world 的例子 ~/Library/LaunchAgents/com.example.hello.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.hello</string>
<key>ProgramArguments</key>
<array>
<string>/bin/echo</string>
<string>hello world</string>
</array>
</dict>
</plist>
上面定义了一个最简单的任务只使用了Label
和ProgramAgruments
两个键
Label
这是个必须的键,指定这个任务名ProgramArguments
是带参数的可执行文件上面等同于运行/bin/echo hello world
命令,如果执行的程序不带参数可以使用Program
键,但一个任务中必须包含这两个中的其中一个键
还有一些常用的键名,所有的键可参考man 5 launchd.plist
或者这里
Keys | Description |
---|---|
EnvironmentVariables |
设置运行环境变量 |
StandardOutPath |
标准输出到文件 |
StandardErrorPath |
标准错误到文件 |
RunAtLoad |
是否再加载的时候就运行 |
StartInterval |
设置程序每隔多少秒运行一次 |
KeepAlive |
是否设置程序是一直存活着 如果退出就重启 |
UserName |
设置用户名只在 Daemons 可用 |
WorkingDirectory |
设置工作目录 |
# 检查配置
$ plutil ~/Library/LaunchAgents/com.example.hello.plist
/Users/fython/Library/LaunchAgents/com.example.hello.plist: OK
# 加载配置文件
$ launchctl load ~/Library/LaunchAgents/com.example.hello.plist
# 启动服务
$ launchctl start com.example.hello
$ cat /tmp/hello.log
hello world
$ launchctl list | grep hello
- 0 com.example.hello
$ launchctl remove com.example.hello # remove jobs
一个任务首先需要被加载(load),然后启动(start)正常运行完退出,所以我们查看/tmp
目录下会有日志输出
1)任务一般都要手动启动(start),如果设置了RunAtLoad
或者KeepAlive
则在launchctl load
时就启动
2)使用launchctl list
列出当前加载的任务,第一列代表进程id,因为上面的程序运行一次就退出了所以显示-
,第二列是程序上次运行退出的code,0
代表正常退出,如果是正数代表退出的时候是有错误的,负数代表是接收到信号被终止的
3)launchctl stop <service_name>
可以终止一个在运行中的任务,launchctl unload <path>
指定路径卸载一个任务,launchctl remove <service_name>
通过服务名卸载任务
4)launchctl load <path>
只会加载没有被disable的任务,可以加-w
参数 launchctl load -w <path>
覆盖如果设置了disable的,下次开机启动一定会起来。launchctl unload <path>
只会停止和卸载这个任务,但下次启动还会加载,可以使用-w
参数launchctl unload -w <path>
停止任务,下次启动也不会起来,也就是标记了disable
5)调试一个任务可以配合使用plutil
命令检查语法,设置StandardOutPath
、StandardErrorPath
、Debug
键,也可以看看苹果自带的Console.app
应用中的system.log
基本操作
# 罗列系统当前运行的进程清单
launchctl list
# 查看特定服务的配置信息
launchctl list com.adobe.AdobeCreativeCloud
# 加载特定的服务配置
launchctl load <file_path>
# 卸载特定的服务配置
launchctl unload -w /Library/LaunchAgents/com.adobe.AdobeCreativeCloud.plist
# 特此说明,-w 参数的作用是,如果自动执行了 load 命令尝试去恢复服务注册,则让其无效
plist 文件配置
配置参数
1)配置job名
<key>Label</key>
<string>com.local.cmd</string>
2)cmd启动配置
<key>ProgramArguments</key>
<array>
<string>/usr/bin/rsync</string>
<string>--archive</string>
<string>--compress-level=9</string>
<string>/Volumes/Macintosh HD</string>
<string>/Volumes/Backup</string>
</array>
执行后命令
/usr/bin/rsync --archive --compress-level=9 "/Volumes/Macintosh HD" "/Volumes/Backup"
3)环境变量设置
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/bin:/usr/bin:/usr/local/bin</string>
</dict>
3)设置工作目录
<key>WorkingDirectory</key>
<string>/tmp</string>
4)资源限制
<key>HardResourceLimits</key>
<dict>
<key>FileSize</key>
<integer>1048576</integer>
</dict>
<key>SoftResourceLimits</key>
<dict>
<key>FileSize</key>
<integer>524288</integer>
</dict>
5)其他
RunAtLoad
<key>RunAtLoad</key>
<true/>
每隔多少秒执行
单位 秒
<key>StartInterval</key>
<integer>3600</integer>
定时执行
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
可用参数
Month | Integer | Month of year (1..12, 1 being January) |
---|---|---|
Day | Integer | Day of month (1..31) |
Weekday | Integer | Day of week (0..7, 0 and 7 being Sunday) |
Hour | Integer | Hour of day (0..23) |
Minute | Integer | Minute of hour (0..59) |
示例1:
/Library/LaunchDaemons/com.fython.clash.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.fython.clash</string>
<key>RunAtLoad</key>
<true/>
<key>UserName</key>
<string>root</string>
<key>StandardErrorPath</key>
<string>/Users/fython/bin/clash/stderr.log</string>
<key>StandardOutPath</key>
<string>/Users/fython/bin/clash/stdout.log</string>
<key>WorkingDirectory</key>
<string>/Users/fython/bin/clash</string>
<key>ProgramArguments</key>
<array>
<string>/Users/fython/bin/clash/clash</string>
<string>-f</string>
<string>config.yaml</string>
<string>-d</string>
<string>/Users/fython/bin/clash</string>
</array>
<key>KeepAlive</key>
<true/>
</dict>
</plist>