在工作中,我們通常遇到的問題是,如何控制systemd服務的啟動順序,同志們第一反應就會是使用Before=或者After=去進行控制。 問題來了,如果服務啟動時沒有順序要求,但是關閉時有順序要求, 該如何操作?
通過查找如下相關文檔, 我查到了這樣一段話:
https://www.freedesktop.org/software/systemd/man/systemd.unit.html
When two units with an ordering dependency between them are shut down, the inverse of the start-up order is Applied. I.e. if a unit is configured with After= on another unit, the former is stopped before the latter if both are shut down.
上面這段話的意思是,如果使用After=或者Before=規定了進程的啟動順序, 那么關閉時的順序與啟動時的順序將是相反的。
比如有A、B、C三個服務, 啟動時的順序時A->B->C, 那么服務的關閉順序將是C->B->A。 事實是這樣的嗎? 下面通過一個小實驗進行驗證。
驗證systemd的關閉順序
這里我們準備三個服務,服務在啟動時候會向文件中寫入相應的啟動和關閉日志,通過日志我們來判斷服務的啟動和關閉順序。
首先是test1.sh, 該文件接受start/stop兩個命令行參數, 啟動時寫入日志start1, 關閉時寫入日志stop1。
#!/bin/bash
case "$1" in
start)
echo "start1" >> /home/test/test.log
;;
stop)
echo "stop1" >> /home/test/test.log
;;
*)
esac
下面是test1服務的systemd的service文件test1.service,這里我們只需要腳本執行一次,因此使用的Type是oneshot類型,并且指定RemainAfterExit=yes,意思是該腳本只會執行一次,并且退出后, 不會意味著服務是inacive狀態, 將會顯示服務是active(exited)狀態。
[Unit]
Description=mytest:while date service
After.NETwork.target sshd.service
[Service]
Type=oneshot
ExecStart= /home/test/test1.sh start
ExecStop= /home/test/test1.sh stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
test2.sh與test1.sh類似,只是打印的日志內容不同。
#!/bin/bash
case "$1" in
start)
echo "start2" >> /home/test/test.log
;;
stop)
echo "stop2" >> /home/test/test.log
;;
*)
esac
test2.service同test1.service, 不同的是我在After中增加了test1.service, 這就意味著test2晚于test1啟動。
[Unit]
Description=mytest:while date service
After=network.target sshd.service test1.service
[Service]
Type=oneshot
ExecStart= /home/test/test2.sh start
ExecStop= /home/test/test2.sh stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
test3.sh同test1.sh
#!/bin/bash
case "$1" in
start)
echo "start3" >> /home/test/test.log
;;
stop)
echo "stop3" >> /home/test/test.log
;;
*)
esac
test3.service同test1.service,不同的是我在After中增加了test2.service, 這就意味著test3晚于test2啟動。
[Unit]
Description=mytest:while date service
After=network.target sshd.service test2.service
[Service]
Type=oneshot
ExecStart= /home/test/test3.sh start
ExecStop= /home/test/test3.sh stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
通過下面的命令將三個服務分別加入到systemd的目錄中,并且啟動它們并設為開機啟動。
cp test1.service /usr/lib/systemd/system/
cp test2.service /usr/lib/systemd/system/
cp test3.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable test1
systemctl enable test2
systemctl enable test3
systemctl start test1
systemctl start test2
systemctl start test3
此時,test.log文件已經打印出了剛剛手動執行啟動命令產生的日志
[root@localhost test]# cat test.log
start1
start2
start3
通過上述的步驟,我們構建出了三個服務,這三個服務的啟動順序是test1->test2->test3, 那么根據我們的推測, 關閉順序應該是test3->test2->test1,是否如此呢?
下面就是到了最終驗證的時刻!
reboot
等待一小會后,我們打印出test.log
[root@localhost test]# cat test.log
start1
start2
start3
stop3
stop2
stop1
start1
start2
start3
可以看到停止時依次打印出了stop3,stop2,stop1。這與我們的猜想以及文檔中的說明是一致的。
結論
systemd通過After和Before可以指定服務的啟動順序, 在系統關閉時,服務的關閉順序和啟動順序是相反的, 先啟動的后關閉,后啟動的先關閉。