在工作中,我們通常遇到的問題是,如何控制systemd服務(wù)的啟動順序,同志們第一反應(yīng)就會是使用Before=或者After=去進(jìn)行控制。 問題來了,如果服務(wù)啟動時沒有順序要求,但是關(guān)閉時有順序要求, 該如何操作?
通過查找如下相關(guān)文檔, 我查到了這樣一段話:
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=規(guī)定了進(jìn)程的啟動順序, 那么關(guān)閉時的順序與啟動時的順序?qū)⑹窍喾吹摹?/p>
比如有A、B、C三個服務(wù), 啟動時的順序時A->B->C, 那么服務(wù)的關(guān)閉順序?qū)⑹荂->B->A。 事實是這樣的嗎? 下面通過一個小實驗進(jìn)行驗證。
驗證systemd的關(guān)閉順序
這里我們準(zhǔn)備三個服務(wù),服務(wù)在啟動時候會向文件中寫入相應(yīng)的啟動和關(guān)閉日志,通過日志我們來判斷服務(wù)的啟動和關(guān)閉順序。
首先是test1.sh, 該文件接受start/stop兩個命令行參數(shù), 啟動時寫入日志start1, 關(guān)閉時寫入日志stop1。
#!/bin/bash
case "$1" in
start)
echo "start1" >> /home/test/test.log
;;
stop)
echo "stop1" >> /home/test/test.log
;;
*)
esac
下面是test1服務(wù)的systemd的service文件test1.service,這里我們只需要腳本執(zhí)行一次,因此使用的Type是oneshot類型,并且指定RemainAfterExit=yes,意思是該腳本只會執(zhí)行一次,并且退出后, 不會意味著服務(wù)是inacive狀態(tài), 將會顯示服務(wù)是active(exited)狀態(tài)。
[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類似,只是打印的日志內(nèi)容不同。
#!/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
通過下面的命令將三個服務(wù)分別加入到systemd的目錄中,并且啟動它們并設(shè)為開機啟動。
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文件已經(jīng)打印出了剛剛手動執(zhí)行啟動命令產(chǎn)生的日志
[root@localhost test]# cat test.log
start1
start2
start3
通過上述的步驟,我們構(gòu)建出了三個服務(wù),這三個服務(wù)的啟動順序是test1->test2->test3, 那么根據(jù)我們的推測, 關(guān)閉順序應(yīng)該是test3->test2->test1,是否如此呢?
下面就是到了最終驗證的時刻!
reboot
等待一小會后,我們打印出test.log
[root@localhost test]# cat test.log
start1
start2
start3
stop3
stop2
stop1
start1
start2
start3
可以看到停止時依次打印出了stop3,stop2,stop1。這與我們的猜想以及文檔中的說明是一致的。
結(jié)論
systemd通過After和Before可以指定服務(wù)的啟動順序, 在系統(tǒng)關(guān)閉時,服務(wù)的關(guān)閉順序和啟動順序是相反的, 先啟動的后關(guān)閉,后啟動的先關(guān)閉。