1. 程式人生 > 實用技巧 >系統服務配置 服務(Service)-詳細版

系統服務配置 服務(Service)-詳細版

轉載: https://blog.51cto.com/littledevil/1912570

System.service:

服務單元,你可以理解為系統服務和原來的init.d下面的服務一樣,只是比它更加豐富。每一個服務都是以.service進行標識的,如下圖:

systemctl list-unit-files --type=service

STATE 說明

disabled 表示開機不啟動
enabled 表示開機啟動
static 對應Unit檔案中沒有定義[install]區域,因此無法設定為開機啟動

我們看看一個服務包含哪些內容:

systemctl cat sshd.service

通過這個圖是不是可以看出一些聯絡呢?和之前說的單元概念中包括的[Unit]段和[Install]段,這裡還多了一個[Service]段,這個段就是用來定義服務的。我們先說一下常用的配置項有哪些:
配置項 說明
Type=
可以包含的值為simple、forking、oneshot、dbus、notify、idel其中之一。

simple:表示ExecStar=程序是該服務的主程序。如果它需要為其他程序提供服務,那麼必須在該服務啟動之前先建立好通訊渠道,比如套接字,以加快後續單元的啟動速度。

forking:表示ExecStar=程序將會在啟動時使用fork()函式,這是傳統Unix系統的做法,也就是這個程序將由systemd程序fork出來,然後當該程序都準備就緒時,systemd程序退出,而fork出來的程序作為服務的主程序繼續執行,對於此型別的程序,建議設定PIDFile=選項,以幫助systemd準確定位該服務的主程序。

oneshot:該程序會在systemd啟動後續單元之前退出,適用於僅需要執行一次的程式。比如清理磁碟,你只需要執行一次,不需要一直在後臺執行這個程式。

dbus:該程序需要在D-Bus上獲得一個由BusName=指定的名稱,systemd將會在啟動後續單元之前,首先確保該程序已經成功的獲取了指定D-Bus名稱。

notify:與simple類似,不同之處在於該程序會在啟動完成之後通過sd_notify之類的介面傳送一個通知訊息。systemd在啟動後續單元之前,必須確保該程序已經成功地傳送了一個訊息。

idel:與simple類似,不同之處在於該程序將會被延遲到所有操作都完成之後在執行。這樣可以避免控制檯上的狀態資訊與shell指令碼的輸出混在在一起。

ReaminAfterExit= 當該服務的所有程序都退出之後,是否依然將此無視為活動的,預設為no。
GuessMainPID= 在沒有設定PIDFile=值的時候,systemd是否要猜測主程序的PID。預設是yes。
PIDFile= 守護程序的PID檔案,必須是絕對路徑,強烈建議在Type=forking的情況下明確設定此選項。這個路徑也不是隨便寫的,而是你的程序實際的PID檔案路徑。這樣systemd才能正確的讀取該檔案,但是它不會寫入,只是會在服務停止後刪除該檔案,如果存在的話。
BusName= 設定與此服務通訊所使用的D-Bus名稱,如果Type=dbus,則必須設定此項。
ExecStart=
設定啟動服務是要執行的命令(命令+引數)。命令列必須是一個絕對路徑表示可執行檔案的位置,後面可以跟多個該命令支援的引數。如果在命令前面加上下面的標誌,將會有不同含義:

@:表示後面的引數一次傳遞給被執行的程式

-:表示即使該程序以失敗狀態退出,也會被視為成功退出

+:表示該程序擁有超級使用者特權

如果設定多個ExecStart=那麼將依次執行,如果某個沒有“-”字首的命令執行失敗,那麼後續的ExecStart=將不會執行,同時該單元變為失敗(failed)狀態。

如果沒有設定Type=forking時,這裡的命令所啟動的程序,將被視為該服務的主守護程序。

ExecStartPre=

ExecStartPost=

在執行ExecStart之前或之後執行的命令。規則與ExecStart=相同。

對於ExecStartPost= 命令僅在服務已經啟動成功之後才會執行,判斷的標準基於 Type= 選項。 具體說來,對於 Type=simple 或 Type=idle 就是主程序已經成功啟動; 對於 Type=oneshot 來說就是主程序已經成功退出; 對於 Type=forking 來說就是初始程序已經成功退出; 對於 Type=notify 來說就是已經發送了 "READY=1" ; 對於 Type=dbus 來說就是已經取得了 BusName= 中設定的匯流排名稱。注意一下2點:

不可將 ExecStartPre= 用於需要長時間執行的程序。 因為所有由 ExecStartPre= 派生的子程序 都會在啟動 ExecStart= 服務程序之前被殺死。

如果在服務啟動完成之前,任意一個 ExecStartPre=, ExecStart=, ExecStartPost= 中無 "-" 字首的命令執行失敗或超時, 那麼,ExecStopPost= 將會被繼續執行,而 ExecStop= 則會被跳過。

ExecReload=
這是一個可選的指令, 用於設定當該服務被要求重新載入配置時所執行的命令列。 語法規則與 ExecStart= 完全相同。

另外,還有一個特殊的環境變數 $MAINPID 可用於表示主程序的PID, 例如可以這樣使用:/bin/kill -HUP $MAINPID

注意,像上例那樣,通過向守護程序傳送復位訊號, 強制其重新載入配置檔案,並不是一個好習慣。 因為這是一個非同步操作, 所以不適用於需要按照特定順序重新載入配置檔案的服務。 我們強烈建議將 ExecReload= 設為一個 能夠確保重新載入配置檔案的操作同步完成的命令列

ExecStop=
這是一個可選的指令, 用於設定當該服務被要求停止時所執行的命令列。 語法規則與 ExecStart= 完全相同。 執行完此處設定的命令列之後, 該服務所有剩餘的程序將會根據 KillMode= 的設定被殺死(參見 systemd.kill(5))。 如果未設定此選項,那麼當此服務被停止時, 該服務的所有程序都將會根據 KillSignal= 的設定被立即全部殺死。 與 ExecReload= 一樣, 也有一個特殊的環境變數 $MAINPID 可用於表示主程序的PID

一般來說, 僅僅設定一個結束服務的命令而不等待其完成, 是不夠的。 因為當此處設定的命令執行完之後, 剩餘的程序會被 SIGKILL 訊號立即殺死, 這可能會導致資料丟失。 因此,這裡設定的命令必須是同步操作, 而不能是非同步操作。

注意,僅在服務確實啟動成功的前提下,才會執行 ExecStop= 中設定的命令。 如果服務從未啟動或啟動失敗(例如,任意一個 ExecStart=, ExecStartPre=, ExecStartPost= 中無 "-" 字首的命令執行失敗或超時), 那麼 ExecStop= 將會被跳過。 如果想要無條件的在服務停止後執行特定的動作,那麼應該使用 ExecStopPost= 選項。

應該將此選項用於那些必須在服務乾淨的退出之前執行的命令。 當此選項設定的命令被執行的時候,應該假定服務正處於完全正常的執行狀態,可以正常的與其通訊。 如果想要無條件的在服務停止後"清理屍體",那麼應該使用 ExecStopPost= 選項。

KillMode=的值有如下幾種:

control-group:表示殺死該單元的cgroup內的所有程序

process:表示僅殺死主程序

mixed:表示先向主程序傳送SIGTERM訊號,然後在向該單元的cgroup內的其他程序傳送SIGKILL訊號。

none:表示僅執行ExecStop=動作,而不殺死任何程序,這會導致程序單元停止了,但是該單元的cgroup還依然存在,直到其餘程序全部死亡。

預設是control-group。

ExecStopPost=
這是一個可選的指令, 用於設定在該服務停止之後所執行的命令列。 語法規則與 ExecStart= 完全相同。 注意,與 ExecStop= 不同,無論服務是否啟動成功, 此選項中設定的命令都會在服務停止後被無條件的執行。

應該將此選項用於設定那些無論服務是否啟動成功都必須在服務停止後無條件執行的清理操作。 此選項設定的命令必須能夠正確處理由於服務啟動失敗而造成的各種殘缺不全以及資料不一致的場景。 由於此選項設定的命令在執行時,整個服務的所有程序都已經全部結束,所以無法與服務進行任何通訊。

RestartSec= 設定在重啟服務(Restart=)前暫停多長時間。 預設值是100毫秒(100ms)。 如果未指定時間單位,那麼將視為以秒為單位。 例如設為"20"等價於設為"20s"
TimeoutStartSec= 設定該服務允許的最大啟動時長。 如果守護程序未能在限定的時長內發出"啟動完畢"的訊號,那麼該服務將被視為啟動失敗,並會被關閉。 如果未指定時間單位,那麼將視為以秒為單位。
TimeoutStopSec= 設定該服務允許的最大停止時長。 如果該服務未能在限定的時長內成功停止, 那麼將會被強制使用 SIGTERM 訊號關閉, 如果依然未能在相同的時長內成功停止, 那麼將會被強制使用 SIGKILL 訊號關閉。如果未指定時間單位,那麼將視為以秒為單位。 例如設為"20"等價於設為"20s"。 設為 "infinity" 則表示永不超時。
RuntimeMaxSec= 允許服務持續執行的最大時長。 如果服務持續執行超過了此處限制的時長,那麼該服務將會被強制終止,同時將該服務變為失敗(failed)狀態。 注意,此選項對 Type=oneshot 型別的服務無效,因為它們會在啟動完成後立即終止。 預設值為 "infinity" (不限時長)。
WatchdogSec= 設定該服務的看門狗(watchdog)的超時時長。 看門狗將在服務成功啟動之後被啟動。 該服務在執行過程中必須週期性的以 "WATCHDOG=1" ("keep-alive ping")呼叫 sd_notify(3) 函式。 如果在兩次呼叫之間的時間間隔大於這裡設定的值, 那麼該服務將被視為失敗(failed)狀態, 並會被強制使用 SIGABRT 訊號關閉。 通過將 Restart= 設為 on-failure, on-watchdog, on-abnormal, always 之一, 可以實現在失敗狀態下的自動重啟該服務。 這裡設定的值將會通過 WATCHDOG_USEC= 環境變數傳遞給守護程序, 這樣就允許那些支援看門狗的服務自動啟用"keep-alive ping"。 如果設定了此選項, 那麼必須將 NotifyAccess= 設為 main(此種情況下的隱含預設值) 或 all 。 如果未指定時間單位,那麼將視為以秒為單位。 例如設為"20"等價於設為"20s"。 預設值"0"表示禁用看門狗功能。 詳見 sd_watchdog_enabled(3) 與 sd_event_set_watchdog(3) 手冊。
Restart=
當服務程序正常退出、異常退出、被殺死、超時的時候,是否重啟系統該服務。程序通過正常操作被停止則不會被執行重啟。可選值為:

no:預設值,表示任何時候都不會被重啟

always:表示會被無條件重啟

no-success:表示僅在服務程序正常退出時重啟

on-failure:表示僅在服務程序異常退出時重啟

所謂正常退出是指,退出碼為“0”,或者到IGHUP, SIGINT, SIGTERM, SIGPIPE 訊號之一,並且退出碼符合 SuccessExitStatus= 的設定。

所謂異常退出時指,退出碼不為“0”,或者被強殺或者因為超時被殺死。

SuccessExitStatus=
額外定義附加的程序"正常退出"狀態。 可以設為一系列以空格分隔的數字退出碼或者訊號名稱
說明:如果在ExecStart=中設定多個命令,那麼每個命令必須用“;”隔開,且只有Type=oneshot時才可用。

另外在[Service]段中還可以使用:

配置項 說明
WorkingDirectory= 設定程序的工作目錄。 既可以設為特殊值 "~" 表示 User= 使用者的家目錄, 也可以設為一個以 RootDirectory= 為基準的絕對路徑。 例如當 RootDirectory=/sysroot 並且 WorkingDirectory=/work/dir 時, 實際的工作目錄將是 /sysroot/work/dir 。 當 systemd 作為系統例項執行時,此選項的預設值是 / ; 當 systemd 作為使用者例項執行時,此選項的預設值是對應使用者的家目錄。 如果給目錄加上 "-" 字首, 那麼表示即使此目錄不存在,也不算致命錯誤。 如果未設定 RootDirectory= 選項, 那麼為 WorkingDirectory= 設定的絕對路徑 將以主機(或容器)的根目錄(也就是執行 systemd 的系統根目錄)為基準。 注意,設定此選項將會導致自動新增額外的依賴關係(見上文)。
RootDirectory= 設定以 chroot(2) 方式執行程序時的根目錄。 必須設為一個以主機(或容器)的根目錄(也就是執行 systemd 的系統根目錄)為基準的絕對路徑。 如果設定了此選項, 必須確保程序及其輔助檔案在 chroot() 監獄中確實可用。 注意,設定此選項將會導致自動新增額外的依賴關係(見上文)。
User=

Group=

設定程序在執行時使用的使用者與組。 既可以設為數字形式的ID也可以設為字串形式的名稱。 如果沒有明確設定 Group= 選項,則使用 User= 所屬的預設組。 此選項不影響帶有 "+" 字首的命令。
Nice= 設定程序的預設謙讓值。 可以設為 -20(最高優先順序) 到 19(最低優先順序) 之間的整數值。
Environment=
設定程序的環境變數, 值是一個空格分隔的 VAR=VALUE 列表。 可以多次使用此選項以增加新的變數或者修改已有的變數 (同一個變數以最後一次的設定為準)。 若設為空, 則表示清空先前所有已設定的變數。 注意: (1)不會在字串內部進行變數展開(也就是"$"沒有特殊含義); (2)如果值中包含空格, 那麼必須在字串兩邊使用雙引號(")界定

Environment="VAR1=word1 word2"。

EnvironmentFile=
與 Environment= 類似, 不同之處在於此選項是從文字檔案中讀取環境變數的設定。 檔案中的空行以及以分號(;)或井號(#)開頭的行會被忽略, 其他行的格式必須符合 VAR=VALUE 的shell變數賦值語法。 行尾的反斜槓()將被視為續行符, 這與shell語法類似。 若想在變數值中包含空格, 則必須在值的兩端加上雙引號(")界定。

檔案必須用絕對路徑表示(可以包含萬用字元)。 但可在路徑前加上"-"字首表示忽略不存在的檔案。 可以多次使用此選項, 以從多個不同的檔案中讀取設定。 若設為空, 則表示清空所有先前已經從檔案中讀取的環境變數。

這裡列出的檔案將在程序啟動前的瞬間被讀取, 因此可以由前一個單元生成配置檔案, 再由後一個單元去讀取它。

從檔案中讀取的環境變數會覆蓋 Environment= 中設定的同名變數。 檔案的讀取順序就是它們出現在單元檔案中的順序, 並且對於同一個變數,以最後讀取的檔案中的設定為準。

我們再回來看之前的sshd的服務定義:

現在你就知道如何定義一個服務了。尤其是編譯安裝軟體的時候,較新版本的軟體可能提供了.service的檔案,如果沒有你就需要自己寫。
常用命令

#啟動一個服務
systemctl start postfix.service
#關閉一個服務
systemctl stop postfix.service
#重啟一個服務
systemctl restart postfix.service
#顯示一個服務的狀態
systemctl status postfix.service
#在開機時啟用一個服務
systemctl enable postfix.service
#在開機時禁用一個服務
systemctl disable postfix.service
#檢視服務是否開機啟動
systemctl is-enabled postfix.service
#檢視已啟動的服務列表
systemctl list-unit-files|grep enabled
#檢視啟動失敗的服務列表
systemctl --failed
#重新載入service檔案
systemctl daemon-reload

待續。。。