天天看點

關機時,如何控制systemd服務的關閉順序?

作者:我是小x

在工作中,我們通常遇到的問題是,如何控制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可以指定服務的啟動順序, 在系統關閉時,服務的關閉順序和啟動順序是相反的, 先啟動的後關閉,後啟動的先關閉。

繼續閱讀