通過(guò) systemctl 設(shè)置自定義 Service
前言
如果要在Linux 上設(shè)置一個(gè)開(kāi)機(jī)自啟,出現(xiàn)問(wèn)題自動(dòng)重啟,并且有良好日志的程序,比較流行的方法有 supervisord、systemd,除此之外,還有 upstart、runit 等類似的工具。
但是自從 systemd 被 ubuntu、centos 等主流 Linux 發(fā)行版應(yīng)用以來(lái),systemd 漸漸成為主流方案。
配置說(shuō)明
要自定義一個(gè)服務(wù),需要在 /usr/lib/systemd/system/ 下添加一個(gè)配置文件:<software-name>.service
如果
/usr/lib/systemd/system/不存在,可考慮使用/lib/systemd/system/或/etc/systemd/system/
ExecXXX中的命令,均可以正常使用轉(zhuǎn)義字符以及環(huán)境變量插值語(yǔ)法,比如用\結(jié)尾表示換行,用 $Xxx 獲取環(huán)境變量。
配置文件的內(nèi)容說(shuō)明:
[Unit]: 服務(wù)的啟動(dòng)順序與依賴關(guān)系
Description: 當(dāng)前服務(wù)的簡(jiǎn)單描述
After: 當(dāng)前服務(wù)(<software-name>.service)需要在這些服務(wù)啟動(dòng)后,才啟動(dòng)
Before: 和 After 相反,當(dāng)前服務(wù)需要在這些服務(wù)啟動(dòng)前,先啟動(dòng)
Wants:表示當(dāng)前服務(wù)"弱依賴"于這些服務(wù)。即當(dāng)前服務(wù)依賴于它們,但是沒(méi)有它們,當(dāng)前服務(wù)也能正常運(yùn)行。
Requires: 表示"強(qiáng)依賴"關(guān)系,即如果該服務(wù)啟動(dòng)失敗或異常退出,那么當(dāng)前服務(wù)也必須退出。
[Service] 服務(wù)運(yùn)行參數(shù)的設(shè)置
Type=forking 后臺(tái)運(yùn)行的形式
PIDFile=/software-name/pid pid文件路徑
EnvironmentFile=/xxx/prod.env 通過(guò)文件設(shè)定環(huán)境變量,注意這東西不支持環(huán)境變量的插值語(yǔ)法 ${xxx}
WorkingDirectory=/xxx/xxx 工作目錄
ExecStartPre 為啟動(dòng)做準(zhǔn)備的命令
ExecStart 服務(wù)的具體運(yùn)行命令(對(duì)非 workingdirectory 的文件,必須用絕對(duì)路徑!
ExecReload 重載命令,如果程序支持 HUP 信號(hào)的話,通常將此項(xiàng)設(shè)為 `/bin/kill -HUP $MAINPID`
ExecStop 停止命令
ExecStartPre:?jiǎn)?dòng)服務(wù)之前執(zhí)行的命令
ExecStartPost:?jiǎn)?dòng)服務(wù)之后執(zhí)行的命令
ExecStopPost:停止服務(wù)之后執(zhí)行的命令
RuntimeDirectory=xxxx
RuntimeDirectoryMode=0775
PrivateTmp=True 表示給服務(wù)分配獨(dú)立的臨時(shí)空間
RestartSec 自動(dòng)重啟當(dāng)前服務(wù)間隔的秒數(shù)
Restart 定義何種情況 Systemd 會(huì)自動(dòng)重啟當(dāng)前服務(wù),可能的值包括always(總是重啟)、on-success、on-failure 等
# 程序的 user 和 group
User=ryan
Group=ryan
注意:?jiǎn)?dòng)、重載、停止命令全部要求使用絕對(duì)路徑
[Install] 定義如何安裝這個(gè)配置文件,即怎樣做到開(kāi)機(jī)啟動(dòng)。
# Target的含義是服務(wù)組,表示一組服務(wù)。
WantedBy=multi-user.target
注意,service 文件不支持行內(nèi)注釋!??!注釋必須單獨(dú)一行
Type 說(shuō)明
Type 感覺(jué)是整個(gè)配置文件里面最不好理解的一個(gè)配置項(xiàng),它的實(shí)際作用就是:告訴 systemd 你的 Service 是如何啟動(dòng)的
-
Type=simple(默認(rèn)值):ExecStart命令會(huì)立即啟動(dòng)你的服務(wù),并且持續(xù)運(yùn)行,不會(huì)退出。 -
Type=forking:ExecStart命令會(huì) fork 出你的服務(wù)主進(jìn)程,然后正常退出。使用此 Type 時(shí)應(yīng)同時(shí)指定PIDFile=,systemd 使用它跟蹤服務(wù)的主進(jìn)程。 -
Type=oneshot:ExecStart命令??赡苄枰瑫r(shí)設(shè)置RemainAfterExit=yes使得systemd在服務(wù)進(jìn)程退出之后仍然認(rèn)為服務(wù)處于激活狀態(tài) -
Type=notify:與Type=simple相同,但約定服務(wù)會(huì)在就緒后向 systemd 發(fā)送一個(gè)信號(hào),以表明自己已經(jīng)啟動(dòng)成功。- 細(xì)節(jié):systemd 會(huì)創(chuàng)建一個(gè) unix socket,并將地址通過(guò) $NOTIFY_SOCKET 環(huán)境變量提供給服務(wù),同時(shí)監(jiān)聽(tīng)該 socket 上的信號(hào)。服務(wù)可以使用 systemd 提供的 C 函數(shù)
sd_notify()或者命令行工具systemd-notify發(fā)送信號(hào)給 systemd. - 因?yàn)槎嗔藗€(gè) notify 信號(hào),所以這一 Type 要比 simple 更精確一點(diǎn)。但是需要服務(wù)的配合,
- 細(xì)節(jié):systemd 會(huì)創(chuàng)建一個(gè) unix socket,并將地址通過(guò) $NOTIFY_SOCKET 環(huán)境變量提供給服務(wù),同時(shí)監(jiān)聽(tīng)該 socket 上的信號(hào)。服務(wù)可以使用 systemd 提供的 C 函數(shù)
-
Type=dbus:若以此方式啟動(dòng),當(dāng)指定的 BusName 出現(xiàn)在 DBus 系統(tǒng)總線上時(shí),systemd 認(rèn)為服務(wù)就緒。 -
Type=idle:沒(méi)搞明白,不過(guò)通常也用不到。
更詳細(xì)的見(jiàn) Systemd 入門教程:命令篇 - 阮一峰。
配置舉例
比如 shadsocks Server Service,的配置文件 ss-server.service 的內(nèi)容為:
[Unit]
Description=shadsocks server
After=network.target auditd.service
[Service]
Type=forking
ExecStart=/usr/local/bin/ssserver -c /etc/shadsocks.json --user shadsocks --pid-file /var/run/shadsocks.pid -d start
ExecStop=/usr/local/bin/ssserver -c /etc/shadsocks.json --user shadsocks --pid-file /var/run/shadsocks.pid -d stop
PIDFile=/var/run/shadsocks.pid
Restart=always
RestartSec=4
[Install]
WantedBy=multi-user.target
而 enginx 的配置文件 nginx.service 的內(nèi)容是:
[Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
為了使用環(huán)境變量插值,而使用 sh 啟動(dòng)的 etcd 服務(wù),它的 etcd.service 配置如下:
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target
[Service]
Type=simple
# EnvironmentFile 不支持使用 ${xxx} 變量插值,這里不適合使用
# EnvironmentFile=/data/etcd.env
# -a 表示傳遞環(huán)境變量
ExecStart=/bin/bash -ac '. /data/etcd.env; /data/bin/etcd'
Restart=always
RestartSec=5s
LimitNOFILE=40000
[Install]
WantedBy=multi-user.target
如果你不需要在 /data/etcd.env 中使用環(huán)境變量的插值語(yǔ)法,那可以這樣寫:
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target
[Service]
Type=notify
EnvironmentFile=/data/etcd.env
# ExecXXX 的命令中是可以使用 ${Xxx} 插值語(yǔ)法的
ExecStart=/data/bin/etcd \
--initial-advertise-peer-urls http://${THIS_IP}:2380 \
--listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 \
--listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster "${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380"
Restart=always
RestartSec=5s
LimitNOFILE=40000
[Install]
WantedBy=multi-user.target
服務(wù)的啟動(dòng)、關(guān)閉
systemctl enable ss-server.service # 啟用服務(wù),即開(kāi)機(jī)自動(dòng)啟動(dòng)
systemctl disable ss-server.service # 取消服務(wù),取消開(kāi)機(jī)啟動(dòng)
systemctl start ss-server.service # 啟動(dòng)服務(wù)
systemctl stop ss-server.service # 停止服務(wù)
systemctl restart ss-server.service # 重啟服務(wù)(stop + start)
systemctl reload ss-server.service # 服務(wù)不 stop,直接加載配置更新等(對(duì)應(yīng) ExecReload)
# 檢查狀態(tài)
systemctl status ss-server.service -l
systemctl list-units --type=service # 查看所有服務(wù)

浙公網(wǎng)安備 33010602011771號(hào)