作者 | Paul Brown
譯者 | Andy Song (pinewall) ? ? ? 共計翻譯:16 篇 貢獻時間:67 天
在上一篇文章[1]中,我們展示瞭如何建立一個 systemd 服務並使普通使用者可以啟動和終止遊戲伺服器。但到目前為止,使用這個服務並不比直接執行伺服器高明多少。讓我們更進一步,讓其可以向玩家發郵件,包括在伺服器可用時通知玩家,在伺服器關閉前警告玩家:
# minetest.service
[Unit]
Description= Minetest server
Documentation= https://wiki.minetest.net/Main_Page
[Service]
Type= simple
ExecStart= /usr/games/minetest --server
ExecStartPost= /home/<username>/bin/mtsendmail.sh "Ready to rumble?" "Minetest Starting up"
TimeoutStopSec= 180
ExecStop= /home/<username>/bin/mtsendmail.sh "Off to bed. Nightie night!" "
Minetest Stopping in 2 minutes"
ExecStop= /bin/sleep 120
ExecStop= /bin/kill -2 $MAINPID
這裡涉及幾個新的指令。首先是 ExecStartPost
指令,該指令可以在主行程啟動後馬上執行任何你指定的操作。在本例中,你執行了一個自定義指令碼 mtsendmail
(內容如下),該指令碼以郵件形式通知你的朋友伺服器已經啟動。
#!/bin/bash
# mtsendmail
echo $1 | mutt -F /home/<username>/.muttrc -s "$2" my_minetest@mailing_list.com
我們使用 Mutt[2] 這個命令後郵件客戶端傳送訊息。雖然從實際效果來看,上述指令碼僅有 1 行,但 systemd 單元的引數中不能包含管道及重定向操作,故我們需要將其封裝到指令碼中。
順便提一下,還有一個 ExecStartPre
指令,用於在服務主行程執行之前進行指定操作。
接下來我們看到,關閉伺服器涉及了好幾條指令。TimeoutStopSec
指令用於設定 systemd 友好關閉服務的最大等候時間,預設值大約是 90 秒。超過這個最大等候時間,systemd 會強制關閉服務並報錯。考慮到你希望在徹底關閉伺服器前給使用者預留幾分鐘的時間,你需要將超時時間提高至 3 分鐘,這樣 systemd 就不會誤認為服務關閉時出現問題。
接下來是關閉服務的具體指令部分。雖然沒有 ExecStopPre
這樣的指令,但你可以透過多次使用 ExecStop
指令實現關閉伺服器前執行操作的標的。多個 ExecStop
指令按從上到下的順序依次執行,這樣你就可以在伺服器真正關閉前向用戶傳送訊息。
透過這個特性,你首先應該向你的朋友發郵件,警告其伺服器即將關閉,然後等待兩分鐘,最後關閉伺服器。可以使用 Ctrl + c
關閉 Minetest 伺服器,該操作會被轉換為一個中斷訊號(SIGINT
);當你執行 kill -2 $MAINPID
時就會傳送該中斷訊號,其中 $MAINPID
是 systemd 變數,用於記錄你服務中主行程的 PID 資訊。
看上去好多了!如果你此時啟動服務:
systemctl --user start minetest
服務會啟動 Minetest 伺服器並向你的使用者傳送郵件。關閉服務的情形基本類似,只不過會額外留給使用者 2 分鐘時間退出登入。
開機自啟動
下一步我們讓你的服務在主機啟動後立即可用,在主機關閉時自動關閉。
我們需要將你的服務檔案移動到系統服務目錄,即 /etc/systemd/system/
:
sudo mv /home/<username>/.config/systemd/user/minetest.service /etc/systemd/system/
如果你希望此時啟動該服務,你需要擁有超級使用者許可權:
sudo systemctl start minetest
另外,可以使用如下命令檢查服務狀態:
sudo systemctl status minetest
你會發現服務很糟糕地處於失敗狀態,這是因為 systemd 不能透過背景關係資訊、特徵、配置檔案得知具體使用哪個使用者執行該服務。在單元檔案中增加 User
指令可以解決這個問題。
# minetest.service
[Unit]
Description= Minetest server
Documentation= https://wiki.minetest.net/Main_Page
[Service]
Type= simple
User= <username>
ExecStart= /usr/games/minetest --server
ExecStartPost= /home/<username>/bin/mtsendmail.sh "Ready to rumble?"
"Minetest Starting up"
TimeoutStopSec= 180
ExecStop= /home/<username>/bin/mtsendmail.sh "Off to bed. Nightie night!"
"Minetest Stopping in 2 minutes"
ExecStop= /bin/sleep 120
ExecStop= /bin/kill -2 $MAINPID
systemd 從 User
指令中得知應使用哪個使用者的環境變數來正確執行該服務。你可以使用 root 使用者,但這可能產生安全風險;使用你的個人使用者會好一些,但不少管理員的做法是為服務單獨建立一個使用者,這樣可以有效地將服務與其它使用者和系統元件相互隔離。
下一步我們讓你的服務在系統啟動時自動啟動,系統關閉時自動關閉。要達到這個目的,你需要 啟用 你的服務;但在這之前,你還需要告知 systemd 從哪裡 安裝 它。
對於 systemd 而言,安裝 意味著告知 systemd 在系統啟動的具體哪個步驟啟用你的服務。以通用 Unix 列印系統(cups.service
)為例,它的啟動在網路框架啟動之後、其它列印服務啟動之前。又如,minetest.server
需要使用使用者郵件(及其它元件),需要等待網路和普通使用者對應的服務就緒後才可啟動。
你只需要在單元檔案中新增一個新段和新指令:
...
[Install]
WantedBy= multi-user.target
你可以將其理解為“等待多使用者系統的全部內容就緒”。systemd 中的“標的”類似於舊系統中的執行級別,可以用於將主機轉移到一個或另一個狀態,也可以像本例中這樣讓你的服務等待指定狀態出現後執行。
你的最終 minetest.service
檔案如下:
# minetest.service
[Unit]
Description= Minetest server
Documentation= https://wiki.minetest.net/Main_Page
[Service]
Type= simple
User= <username>
ExecStart= /usr/games/minetest --server
ExecStartPost= /home/<username>/bin/mtsendmail.sh "Ready to rumble?"
"Minetest Starting up"
TimeoutStopSec= 180
ExecStop= /home/<username>/bin/mtsendmail.sh "Off to bed. Nightie night!"
"Minetest Stopping in 2 minutes"
ExecStop= /bin/sleep 120
ExecStop= /bin/kill -2 $MAINPID
[Install]
WantedBy= multi-user.target
在嘗試新的服務之前,你還需要對郵件指令碼做一些調整:
#!/bin/bash
# mtsendmail
sleep 20
echo $1 | mutt -F /home/<username>/.muttrc -s "$2" my_minetest@mailing_list.com
sleep 10
這是因為系統需要一定的時間啟動郵件系統(這裡等待 20 秒),也需要一定時間完成郵件傳送(這裡等待 10 秒)。註意指令碼中的等待時間數值適用於我的系統,你可能需要針對你的系統調整數值。
大功告成啦。執行如下操作:
sudo systemctl enable minetest
你的 Minetest 服務將在系統啟動時自動啟動,在系統關閉時友好關閉並通知你的使用者。
總結
事實上 Debian、 Ubuntu 和一些族類的發行版提供了 minetest-server
這個特別的軟體包,可以提供一部分上述功能,(但不包括郵件通知功能)。即使如此,你還是可以建立你獨有的自定義服務;事實上,你目前建立的服務比 Debian 預設提供的服務更加通用,可以提供更多功能。
更進一步的說,我們這裡描述的流程可以讓你將大多數簡單伺服器轉換為服務,型別可以是遊戲、網站應用或其它應用。同時,這也是你名副其實地踏入 systemd 大師殿堂的第一步。
via: https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping
作者:Paul Brown[4] 選題:lujun9972 譯者:pinewall 校對:wxy
本文由 LCTT 原創編譯,Linux中國 榮譽推出