CentOS 7之Systemd詳解之服務單元設置system.service

原文出處:https://blog.csdn.net/yuesichiu/article/details/51485147


英文網址:https://www.freedesktop.org/software/systemd/man/systemd.service.html

名稱

systemd.service - 服務單元配置

概要

service.service

描述

以 .service 結尾的單元文件,用於封裝一個被 systemd 監視與控制的進程。

本手冊只列出專用於此種單元的選項,它們全部位於"[Service]"小節之中(通用於所有單元的選項參見 systemd.unit(5) 手冊)。

其他可用的選項位於 systemd.exec(5) 手冊(定義了命令的執行環境), 以及 systemd.kill(5) 手冊(定義瞭如何結束進程), 以及 systemd.resource-control(5) 手冊(定義了進程的資源控制)。

如果要求啓動或停止的某個單元文件不存在,systemd 將會尋找同名的SysV初始化腳本(去掉 .service 後綴), 並根據那個同名腳本動態的創建一個 service 單元。這主要用於與傳統的SysV兼容(不能保證100%兼容)。 更多與SysV的兼容性可參見 Incompatibilities with SysV 文檔。

自動依賴

  • 設置了 Type=dbus 的服務會自動添加 Requires=dbus.socket 與 After=dbus.socket 依賴

  • 基於套接字激活的服務會自動添加對與其相關的 .socket 單元的 After= 依賴。

除非明確設置了 DefaultDependencies=false,否則 service 單元都自動隱含如下依賴:

  • Requires=sysinit.target After=sysinit.target After=basic.target Conflicts=shutdown.target Before=shutdown.target 這樣可以確保普通的服務單元:(1)、在基礎系統啓動完畢之後纔開始啓動,(2)、在關閉系統之前先被幹淨的停止。 只有那些需要在系統啓動的早期就必須啓動的服務,以及那些必須在關機動作的結尾才能停止的服務才需要設置 DefaultDependencies=false 。 systemd.exec(5) 與 systemd.resource-control(5) 中的某些資源限制選項也會自動隱含的添加一些其他的依賴關係。

  • 從同一個模版實例化出來的所有服務單元(單元名稱中帶有 "@" 字符), 默認全部屬於與模版同名的同一個 slice 單元。 該同名 slice 一般在系統關機時,與所有模版實例一起停止。 如果你不希望像上面這樣,那麼可以在模版單元中明確設置 DefaultDependencies=no , 並且:要麼在該模版文件中明確定義特定的 slice 單元(同樣也要明確設置 DefaultDependencies=no)、 要麼在該模版文件中明確設置 Slice=system.slice (或其他合適的 slice)。

[Service]小節選項

每個服務單元文件都必須包含一個"[Service]"小節。由於此小節中的許多選項也同時適用於其他類型的單元, 所以本手冊僅記錄了專用於服務單元的選項。其他共享的選項參見 systemd.exec(5) 與 systemd.kill(5) 手冊。

Type=

  • 設置進程的啓動類型,必須是下列值之一:simple, forking, oneshot, dbus, notify, idle 之一。

  • 如果設爲"simple"(設置了 ExecStart= 但未設置 BusName= 時的默認值),那麼表示 ExecStart= 所設定的進程就是該服務的主進程。 如果此進程需要爲其他進程提供服務,那麼必須在該進程啓動之前先建立好通信渠道(例如套接字),以加快後繼單元的啓動速度。

  • "dbus"(設置了 ExecStart= 與 BusName= 時的默認值)與"simple"類似,不同之處在於該進程需要在 D-Bus 上獲得一個由 BusName= 指定的名稱。 systemd 將會在啓動後繼單元之前,首先確保該進程已經成功的獲取了指定的 D-Bus 名稱。設置爲此類型相當於隱含的依賴於 dbus.socket 單元。

  • "oneshot"(未設置 ExecStart= 時的默認值)與"simple"類似,不同之處在於該進程必須在 systemd 啓動後繼單元之前退出。 此種類型通常需要設置 RemainAfterExit= 選項。

  • 如果設爲"forking",那麼表示 ExecStart= 所設定的進程將會在啓動過程中使用 fork() 系統調用。這是傳統UNIX守護進程的經典做法。 也就是當所有的通信渠道都已建好、啓動亦已成功之後,父進程將會退出,而子進程將作爲該服務的主進程繼續運行。 對於此種進程,建議同時設置 PIDFile= 選項,以幫助 systemd 準確定位該服務的主進程,進而加快後繼單元的啓動速度。

  • "notify"與"simple"類似,不同之處在於該進程將會在啓動完成之後通過 sd_notify(3) 之類的接口發送一個通知消息。 systemd 將會在啓動後繼單元之前,首先確保該進程已經成功的發送了這個消息。 如果設置爲此類型,那麼 NotifyAccess= 將只能設置爲"all"或者"main"(默認)。 注意,目前 Type=notify 尚不能在 PrivateNetwork=yes 的情況下正常工作。

  • "idle"與"simple"類似,不同之處在於該進程將會被延遲到所有的操作都完成之後再執行。 這樣可以避免控制檯上的狀態信息與 shell 腳本的輸出混雜在一起。

RemainAfterExit=

  • 可設爲"yes"或"no"(默認值),表示當該服務的所有進程全部退出之後,是否依然將此服務視爲活動(active)狀態。

GuessMainPID=

  • 可設爲"yes"(默認值)或"no",表示在無法明確定位該服務的主進程的情況下,systemd 是否應該猜測主進程的PID(可能不正確)。 該選項僅在設置了 Type=forking 但未設置 PIDFile= 的情況下有意義。如果PID猜測錯誤,那麼該服務的失敗檢測與自動重啓功能將失效。

PIDFile=

  • 守護進程的PID文件,必須是絕對路徑。強烈建議在 Type=forking 的情況下明確設置此選項。 systemd 將會在此服務啓動後從此文件中讀取主守護進程的PID 。systemd 不會寫入此文件,但會在此服務停止後刪除它(若存在)。

BusName=

  • 設置與此服務通信所使用的 D-Bus 名稱。在 Type=dbus 的情況下必須明確設置此選項。

BusPolicy=

  • 如果設置了此項,那麼 systemd 將會創建一個自定義的kdbus端點(endpoint),並將其安裝爲該服務默認的總線節點(bus node)。 這個自定義的端點可以擁有它自己的策略規則。端點的名稱就是其所服務的單元的名稱。 端點的節點(node)將被綁定掛載到默認的總線節點的位置,這樣該服務就只能通過它自己的端點訪問總線。 注意,自定義端點的默認策略是'拒絕所有',因此,你必須在 BusPolicy= 中明確的添加必要的允許策略。 這個選項的值由兩部分組成:總線名+訪問級別,中間以空格分隔。 訪問級別必須是 see, talk, own 之一,並且 talk 隱含了 see ,而 own 隱含了 talk 與 see 。 如果對同一個總線名稱多次指定了訪問級別,那麼將以擁有最大權限的那個爲準。 例如: BusPolicy=org.freedesktop.systemd1 talk BusPolicy=org.foo.bar see 該選項僅在內核開啓了kdbus(即將併入官方內核)支持的情況下有意義。

ExecStart=

  • 在啓動該服務時需要執行的命令行(命令+參數)。有關命令行的更多細節可參見後文的"命令行"小節。 僅在設置了 Type=oneshot 的情況下,纔可以設置任意個命令行(包括零個),否則必須且只能設置一個命令行。 多個命令行既可以在同一個 ExecStart= 中設置,也可以通過設置多個 ExecStart= 來達到相同的效果。 如果設爲一個空字符串,那麼先前設置的所有命令行都將被清空。 如果不設置任何 ExecStart= 指令,那麼必須確保設置了 RemainAfterExit=yes 指令。 命令行必須以一個絕對路徑表示的可執行文件開始,並且其後的那些參數將依次作爲"argv[1] argv[2] ..."傳遞給被執行的進程。 如果在絕對路徑前加上可選的"@"前綴,那麼其後的那些參數將依次作爲"argv[0] argv[1] argv[2] ..."傳遞給被執行的進程。 如果在絕對路徑前加上可選的"-"前綴,那麼即使該進程以失敗狀態(例如非零的返回值或者出現異常)退出,也會被視爲成功退出。 可以同時使用"-"與"@"前綴,且順序任意。 如果設置了多個命令行,那麼這些命令行將以其在單元文件中出現的順序依次執行。 如果某個無"-"前綴的命令行執行失敗,那麼剩餘的命令行將不會被執行,同時該單元將變爲失敗(failed)狀態。 當未設置 Type=forking 時,這裏設置的命令行所啓動的進程將被視爲該服務的主守護進程。

ExecStartPre=, ExecStartPost=

  • 設置在執行 ExecStart= 之前/後執行的命令行。語法規則與 ExecStart= 完全相同。 如果設置了多個命令行,那麼這些命令行將以其在單元文件中出現的順序依次執行。 如果某個無"-"前綴的命令行執行失敗,那麼剩餘的命令行將不會被執行,同時該單元將變爲失敗(failed)狀態。 僅在所有無"-"前綴的 ExecStartPre= 命令全部執行成功的前提下,纔會繼續執行 ExecStart= 命令。 ExecStartPost= 命令僅在服務已經被成功啓動之後纔會運行,判斷的標準基於 Type= 選項。 具體說來,對於 Type=simple 或 Type=idle 就是主進程已經成功啓動;對於 Type=oneshot 來說就是主進程已經成功退出; 對於 Type=forking 來說就是初始進程已經成功退出;對於 Type=notify 來說就是已經發送了"READY=1"; 對於 Type=dbus 來說就是已經取得了 BusName= 中設置的總線名稱。 注意,不可將 ExecStartPre= 用於需要長時間執行的進程。 因爲所有由 ExecStartPre= 派生的子進程都會在啓動 ExecStart= 服務進程之前被殺死。

ExecReload=

  • 這是一個可選的指令,用於設置當該服務被要求重新載入配置時所執行的命令行。語法規則與 ExecStart= 完全相同。 另外,還有一個特殊的環境變量 $MAINPID 可以用於表示主進程的PID,例如可以這樣使用: /bin/kill -HUP $MAINPID 注意,像上例那樣,通過向守護進程發送復位信號,強制其重新加載配置文件,並不是一個好習慣。 因爲這是一個異步操作,所以不適用於需要按照特定順序重新加載配置文件的服務。 我們強烈建議將 ExecReload= 設置爲一個能夠確保重新加載配置文件的操作同步完成的命令行。

ExecStop=

  • 這是一個可選的指令,用於設置當該服務被要求停止時所執行的命令行。語法規則與 ExecStart= 完全相同。 執行完此處設置的命令行之後,該服務所有剩餘的進程將會根據 KillMode= 的設置被殺死(參見 systemd.kill(5) 手冊)。 如果未設置此選項,那麼當此服務被停止時,該服務的所有進程都將會根據 KillMode= 的設置被立即全部殺死。 與 ExecReload= 一樣,也有一個特殊的環境變量 $MAINPID 可以用於表示主進程的PID 一般來說,僅僅設置一個結束服務的命令,而不等待其完成,是不夠的。 因爲當此處設置的命令執行完之後,剩餘的進程會被 SIGKILL 信號立即殺死,這可能會導致數據丟失。 因此,這裏設置的命令必須是同步操作,而不能是異步操作。

ExecStopPost=

  • 這是一個可選的指令,用於設置該服務停止之後所執行的命令行。語法規則與 ExecStart= 完全相同。 無論此服務是正常停止,還是異常退出,此處的設置都適用。 RestartSec= 設定在重啓服務(Restart=)前暫停多長時間。默認值是100毫秒(100ms)。 如果未指定時間單位,那麼將視爲以秒爲單位。例如設爲"20"等價於設爲"20s"。

TimeoutStartSec=

  • 設定該服務允許的最大啓動時長。如果守護進程未能在限定的時長內發出"啓動完畢"的信號,那麼該服務將被視爲啓動失敗,並會被關閉。 如果未指定時間單位,那麼將視爲以秒爲單位。例如設爲"20"等價於設爲"20s"。設爲"0"則表示永不超時。 當 Type=oneshot 時,默認值爲"0",否則默認值等於 DefaultTimeoutStartSec= 的值(參見 systemd-system.conf(5) 手冊)。

TimeoutStopSec=

  • 設定該服務允許的最大停止時長。如果該服務未能在限定的時長內成功停止,那麼將會被強制使用 SIGTERM 信號關閉, 如果依然未能在相同的時長內成功停止,那麼將會被強制使用 SIGKILL 信號關閉(參見 systemd.kill(5) 手冊中的 KillMode= 選項)。 如果未指定時間單位,那麼將視爲以秒爲單位。例如設爲"20"等價於設爲"20s"。設爲"0"則表示永不超時。 默認值等於 DefaultTimeoutStartSec= 的值(參見 systemd-system.conf(5) 手冊)。

TimeoutSec=

  • 一個同時設置 TimeoutStartSec= 與 TimeoutStopSec= 的快捷方式。

WatchdogSec=

設置該服務的看門狗(watchdog)的超時時長。看門狗將在服務成功啓動之後被激活。 該服務在運行過程中必須週期性的以"WATCHDOG=1"("keep-alive ping")調用 sd_notify(3) 函數。 如果在兩次調用之間的時間間隔大於這裏設定的值,那麼該服務將被視爲失敗(failed)狀態,並會被強制使用 SIGABRT 信號關閉。 通過將 Restart= 設爲"on-failure"或"always"可以實現在失敗狀態下的自動重啓該服務。 這裏設置的值將會通過 WATCHDOG_USEC 環境變量傳遞給守護進程,這樣就允許那些支持看門狗的服務自動啓用"keep-alive ping"。 如果設置了此選項,那麼必須將 NotifyAccess= 設爲"main"(此種情況下的隱含默認值)或"all"。 如果未指定時間單位,那麼將視爲以秒爲單位。例如設爲"20"等價於設爲"20s"。默認值"0"表示禁用看門狗功能。

Restart=

  • 當服務進程正常退出、異常退出、被殺死、超時的時候,是否重新啓動該服務。 "服務進程"是指 ExecStart=, ExecStartPre=, ExecStartPost=, ExecStop=, ExecStopPost=, ExecReload= 中設置的進程。 當進程是由於 systemd 的正常操作(例如 systemctl stop|restart)而被停止時,該服務不會被重新啓動。 "超時"可以是看門狗的"keep-alive ping"超時,也可以是 systemctl start|reload|stop 操作超時。

  • 該選項可以取下列值之一:no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, always "no"(默認值)表示不會被重啓。"always"表示會被無條件的重啓。 "on-success"表示僅在服務進程正常退出時重啓,所謂"正常退出"是指: 退出碼爲"0",或者進程收到 SIGHUP, SIGINT, SIGTERM, SIGPIPE 信號並且退出碼符合 SuccessExitStatus= 的設置。 "on-failure"表示僅在服務進程異常退出時重啓,所謂"異常退出"是指: 退出碼不爲"0",或者進程被強制殺死(包括"core dump"以及收到 SIGHUP, SIGINT, SIGTERM, SIGPIPE 之外的其他信號), 或者進程由於看門狗或者 systemd 的操作超時而被殺死。 對於 on-failure, on-abnormal, on-abort, on-watchdog 的分別適用於哪種異常退出,見下表:

       

  • 注意如下兩個例外情況: (1) RestartPreventExitStatus= 中列出的退出碼或者信號永遠不會導致該服務被重啓。 (2) RestartForceExitStatus= 中列出的退出碼或者信號將會無條件的導致該服務被重啓。 對於需要長期持續運行的守護進程,推薦設爲"on-failure"以增強可用性。 對於自身可以自主選擇何時退出的服務,推薦設爲"on-abnormal"。

SuccessExitStatus=

  • 額外定義附加的進程"正常退出"狀態。可以設爲一系列以空格分隔的數字退出碼或者信號名稱,例如: SuccessExitStatus=1 2 8 SIGKILL 表示當進程的退出碼是 1, 2, 8 或被 SIGKILL 信號終止時,都可以視爲"正常退出"。 注意,退出碼"0"以及 SIGHUP, SIGINT, SIGTERM, SIGPIPE 信號是標準的"正常退出",不需要在此特別定義。 注意,如果進程擁有自定義的信號處理器,並且在收到信號後通過調用 _exit(2) 退出,那麼有關信號的信息就會丟失。 在這種情況下,進程必須自己完成清理工作並使用相同的信號自殺。參見 Proper handling of SIGINT/SIGQUIT — How to be a proper program 如果多次使用此選項,那麼最終的結果將是多個列表的合集。如果將此項設爲空,那麼先前設置的列表將被清空。

RestartPreventExitStatus=

  • 可以設爲一系列以空格分隔的數字退出碼或者信號名稱,當進程的退出碼或收到的信號與此處的設置匹配時, 該服務將無條件的禁止重新啓動(無視 Restart= 的設置)。例如: RestartPreventExitStatus=1 6 SIGABRT 表示退出碼 1, 2, 8 與 SIGKILL 信號將不會導致該服務被重啓。 默認值爲空,表示完全遵守 Restart= 的設置。

  • 如果多次使用此選項,那麼最終的結果將是多個列表的合集。如果將此項設爲空,那麼先前設置的列表將被清空。 RestartForceExitStatus= 可以設爲一系列以空格分隔的數字退出碼或者信號名稱,當進程的退出碼或收到的信號與此處的設置匹配時, 該服務將無條件的被重新啓動(無視 Restart= 的設置)。 默認值爲空,表示完全遵守 Restart= 的設置。 如果多次使用此選項,那麼最終的結果將是多個列表的合集。如果將此項設爲空,那麼先前設置的列表將被清空。

PermissionsStartOnly=

  • 設爲 true 表示所有與權限相關的執行選項(例如 User= 之類的選項,參見 systemd.exec(5) 手冊)僅對 ExecStart= 中的程序有效, 而對 ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop=, ExecStopPost= 中的程序無效。 默認值 false 表示所有與權限相關的執行選項對所有 Exec*= 系列選項中的程序都有效。

RootDirectoryStartOnly=

  • 設爲 true 表示根目錄(參見 systemd.exec(5) 中的 RootDirectory= 選項)僅對 ExecStart= 中的程序有效, 而對 ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop=, ExecStopPost= 中的程序無效。 默認值 false 表示根目錄對所有 Exec*= 系列選項中的程序都有效。

NonBlocking=

  • 是否爲所有通過socket激活傳遞的文件描述符設置非阻塞標記(O_NONBLOCK)。默認值爲 false 設爲 true 表示所有大於2的文件描述符(也就是 stdin, stdout, stderr 之外的文件描述符)都將被設置爲非阻塞模式。 該選項僅在與 socket 單元(systemd.socket(5))聯用的時候纔有意義。

NotifyAccess=

  • 設置通過sd_notify(3)訪問服務狀態通知socket的訪問模式。 可以設爲:none(默認值), main, all 之一。 "none"表示不更新任何守護進程的狀態,忽略所有的狀態更新消息。 "main"表示僅接受主進程的狀態更新消息。 "all"表示接受該服務cgroup內的所有進程的狀態更新消息。 當設置了 Type=notify 或 WatchdogSec= 的時候,此選項應該被設爲"main"或"all",如果未設置,那麼隱含爲"main"。

Sockets=

  • 設置一個socket單元的名稱,表示該服務在啓動時應當從它繼承socket文件描述符。通常並不需要明確設置此選項, 因爲所有與該服務同名(不算後綴)的socket單元的socket文件描述符,都會被自動的傳遞給派生進程。 注意:(1)同一個socket文件描述符可以被傳遞給多個不同的進程(服務)。 (2)當socket上有流量進入時,被啓動的可能是另一個不同於該服務的其他服務。 換句話說就是:socket單元中的 Service= 所指向的服務單元中的 Sockets= 設置未必要反向指回去。

  • 如果多次使用此選項,那麼最終的結果將是多個socket單元的合集。如果將此項設爲空,那麼先前設置的socket單元的列表將被清空。

StartLimitInterval=, StartLimitBurst=

  • 限制該服務的啓動頻率。默認值是每10秒內不得超過5次(StartLimitInterval=10s StartLimitBurst=5)。

  • StartLimitInterval= 的默認值等於systemd配置文件中 DefaultStartLimitInterval= 的值,"0"表示取消啓動頻率限制。

  • StartLimitBurst= 的默認值等於systemd配置文件中 DefaultStartLimitBurst= 的值。

  • 雖然這兩個選項經常與 Restart= 一起使用,但是它們不只限制 Restart= 羅輯所導致的重啓,而是限制所有類型的啓動(包括手動啓動)。 注意,當 Restart=邏輯所導致的重啓超出了啓動頻率限制之後,Restart= 邏輯將會被禁用(也就是不會在下一個時間段內再次嘗試重啓), 然而,如果該單元隨後又被手動重啓,那麼 Restart= 羅輯將被再次激活。 注意,"systemctl reset-failed ..."命令會清除該服務的重啓次數計數器,這通常用於在手動啓動之前清除啓動限制。

StartLimitAction=

  • 設置到達啓動頻率限制後觸發什麼動作。 可設爲 none(默認值), reboot, reboot-force, reboot-immediate, poweroff, poweroff-force, poweroff-immediate 之一。

  • "none"表示除了禁止再次啓動之外,不觸發任何動作。

  • "reboot"表示觸發常規的系統重啓的動作,相當於執行"systemctl reboot"命令。

  • "reboot-force"表示觸發系統的強制重啓動作(強制殺死所有進程但不會造成文件系統不一致),相當於執行"systemctl reboot -f"命令。

  • "reboot-immediate"表示立即調用內核的reboot(2)函數,可能會造成文件系統的數據丟失。

  • poweroff, poweroff-force, poweroff-immediate 與對應的"reboot*"項含義類似,不同之處僅僅在於是關機而不是重啓。

FailureAction=

  • 設置當該服務進入失敗(failed)狀態時所觸發的動作。取值範圍與默認值都與 StartLimitAction= 完全相同。

RebootArgument=

  • 設置reboot(2)系統調用的可選參數,僅用於 StartLimitAction= 與 FailureAction= 的重啓動作。 其作用與"systemctl reboot [arg]"命令中的可選參數[arg]完全相同。

FileDescriptorStoreMax=

  • 允許在 systemd 中最多爲該服務存儲多少個使用sd_pid_notify_with_fds(3)的"FDSTORE=1"消息的文件描述符,默認值爲"0"(不存儲)。 用於實現重啓該服務而不會丟失其狀態(前提是該服務將各種狀態序列化之後保存在 /run 中,同時將文件描述符交給 systemd 暫存)。 所有被 systemd 暫存的文件描述符都將在該服務重啓之後交還給該服務的主進程。 所有被 systemd 暫存的文件描述符都將在遇到如下兩種情況時被自動關閉: (1)收到 POLLHUP 或 POLLERR 信號;(2)該服務被徹底停止,並且沒有任何剩餘的任務隊列

USBFunctionDescriptors=

  • 設爲一個包含 USB FunctionFS 描述符的文件路徑,以實現 USB gadget 支持。 僅與配置了 ListenUSBFunction= 的 socket 單元一起使用。該文件的內容將被寫入 ep0 文件。 USBFunctionStrings= 設爲一個包含 USB FunctionFS 字符串的文件路徑。 其行爲與上面的 USBFunctionDescriptors= 類似。 參見 systemd.exec(5) 與 systemd.kill(5) 手冊頁,以獲取更多其他選項。

命令行

本小節講解 ExecStart=, ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop=, ExecStopPost= 選項的命令行解析規則。

僅在設置了 Type=oneshot 的前提下,纔可以設置多個命令行,且必須用分號(;)將每個命令行隔開(分號自身用"\;"表示)。

例如: ExecStart=/bin/echo one ; /bin/echo "two two" 每個命令行的內部以空格分隔,每一項的邊界都可以用單引號或者雙引號進行界定。 第一項是要運行的命令,隨後的各項則是命令的參數。 行尾的反斜槓(\)將被視作續行符,這和bash的續行語法類似。例如: ExecStart=/bin/echo / >/dev/null & \; \ /bin/ls 的含義是向 /bin/echo 命令傳遞五個參數:"/", ">/dev/null", "&", ";", "/bin/ls". 命令行的語法刻意保持了與shell的相似性,但並不相同。 特別的,重定向(<, <<, >, >)、管道(|)、後臺運行(&),以及其他下文未明確提及的符號都不被支持。 第一項,要運行的命令,必須使用絕對路徑。可以在其中包含空格,但是不可以包含控制字符。 可以在隨後的各項命令參數中使用 systemd.unit(5) 中描述的"%"系列特殊符號,但不可用於命令自身(第一項)。 此外,還可以使用C語言風格的轉義序列(含義也相同),但只能識別如下符號:\a \b \f \n \r \t \v \\ \" \' \s \xxx \nnn 此外,還支持兩種不同的環境變量替換方式("${FOO}"與"$FOO")。

下面的兩個例子,將能清除的體現兩者的差別:

例(1):

Environment="ONE=one" 'TWO=two two' ExecStart=/bin/echo $ONE $TWO ${TWO}

這將給 /bin/echo 依次傳遞如下四個參數: "one", "two", "two", "two two"

例(2):

Environment=ONE='one' "TWO='two two' too" THREE=

ExecStart=/bin/echo ${ONE} ${TWO} ${THREE}

ExecStart=/bin/echo $ONE $TWO $THREE

這將給第一個 /bin/echo 依次傳遞如下三個參數: "'one'", "'two two' too", "" 同時給第二個 /bin/echo 依次傳遞如下三個參數: "one", "two two", "too" 具體說來就是: "${FOO}"的內容將原封不動的轉化爲一個單獨的命令行參數,無論其中是否包含空格與引號,也無論它是否爲空。 "$FOO"的內容將將原封不動的插入命令行中,但對插入內容的解釋卻遵守一般的命令行解析規則。 此外,如果想要傳遞美元符號($)自身,則必須使用"$$"。而那些無法在替換時確定內容的變量將被當做空字符串。 注意,不可以在第一項(也就是命令的絕對路徑)中使用變量替換。 這裏使用的變量必須首先在 Environment= 或 EnvironmentFile= 中定義。 此外,在systemd.exec(5)手冊的"派生進程中的環境變量"小節中列出的"靜態變量"也可以使用。 例如,$USER 就是一個"靜態變量",但是,$TERM 則不是"靜態變量"。 注意,這裏的命令行並不直接支持shell命令,但是可以通過模仿下面這個變通的方法來實現: ExecStart=/bin/sh -c 'dmesg | tac'

例1. 簡單服務

下面的單元文件創建了一個運行 /usr/sbin/foo-daemon 守護進程的服務。未設置的 Type= 等價於默認的 Type=simple 執行 /usr/sbin/foo-daemon 進程之後,systemd 即認爲該單元已經啓動成功。

[Unit]

Description=Foo

[Service]

ExecStart=/usr/sbin/foo-daemon

[Install]

WantedBy=multi-user.target

注意,/usr/sbin/foo-daemon 必須在啓動後持續運行直到服務被停止。 如果該進程只是爲了派生守護進程,那麼應該使用 Type=forking 因爲沒有設置 ExecStop= ,所以在停止服務時,systemd 將會直接向該服務啓動的所有進程發送 SIGTERM 信號, 若超過指定時間依然存在未被殺死的進程,那麼將會繼續發送 SIGKILL 信號。詳見 systemd.kill(5) 手冊。

默認的 Type=simple 並不包含任何通知機制(例如通知"服務已完成初始化")。要想使用通知機制,應該將 Type= 設爲其他非默認值。 例如:Type=notify 可用於能夠理解 systemd 通知協議的服務; Type=forking 可用於能將自身切換到後臺的服務; Type=dbus 可用於能夠在完成初始化之後獲得一個 D-Bus 名稱的單元

例2. 一次性服務

Type=oneshot 用於那些只需要執行一次性動作而不需要持久運行的單元,例如文件系統檢查或者清理臨時文件。 此類單元,將會在啓動後一直等待指定的動作完成,然後再回到停止狀態。下面是一個執行清理動作的單元:

[Unit]

Description=Cleanup old Foo data

[Service]

Type=oneshot ExecStart=/usr/sbin/foo-cleanup

[Install]

WantedBy=multi-user.target

注意,在 /usr/sbin/foo-cleanup 執行結束前,該服務一直處於'正在啓動中'的狀態,而一旦執行結束, 該服務又立即變爲'停止'狀態,也就是說,對於 Type=oneshot 類型的服務,不存在'活動'狀態。 這意味着,如果再一次啓動該服務,將會再一次執行該服務定義的動作。 注意,在時間順序上晚於該服務的單元,將會一直等到該服務變成'停止'狀態後,纔會開始啓動。

Type=oneshot 是唯一可以設置多個 ExecStart= 的服務類型。多個 ExecStart= 指令將按照它們出現的順序依次執行, 一旦遇到錯誤,就會立即停止,不再繼續執行,同時該服務也將進入'失敗'狀態。

例3. 可停止的一次性服務

有時候,單元需要執行一個程序以完成某個設置(啓動),然後又需要再執行另一個程序以撤消先前的設置(停止), 而在設置持續有效的時段中,該單元應該視爲處於'活動'狀態,但實際上並無任何程序在持續運行。 網絡配置服務就是一個典型的例子。此外,只能啓動一次(不可多次啓動)的一次性服務,也是一個例子。

可以通過設置 RemainAfterExit=yes 來滿足這種需求。 在這種情況下,systemd 將會在啓動成功後將該單元視爲處於'活動'狀態(而不是'停止'狀態)。 RemainAfterExit=yes 雖然可以用於所有 Type= 類型,但是主要用於 Type=oneshot 和 Type=simple 類型。 對於 Type=oneshot 類型,systemd 一直等到服務啓動成功之後,纔會將該服務置於'活動'狀態。 所以,依賴於該服務的其他單元必須等待該服務啓動成功之後,才能啓動。 但是對於 Type=simple 類型,依賴於該服務的其他單元無需等待,將會和該服務同時並行啓動。

下面的類似展示了一個簡單的靜態防火牆服務(simple-firewall.service):

[Unit]

Description=Simple firewall

[Service]

Type=oneshot

RemainAfterExit=yes

ExecStart=/usr/local/sbin/simple-firewall-start

ExecStop=/usr/local/sbin/simple-firewall-stop

[Install]

WantedBy=multi-user.target

因爲服務啓動成功後一直處於'活動'狀態,所以再次執行"systemctl start simple-firewall.service"命令不會有任何效果。

例4. 傳統的服務

多數傳統的守護進程(服務)在啓動時會轉入後臺運行。systemd 通過 Type=forking 來支持這種工作方式。 對於 Type=forking 類型的服務,如果最初啓動的進程尚未退出,那麼該單元將依然處於'正在初始化中'狀態。 當最初的進程成功退出,並且至少有一個進程仍然在運行(並且 RemainAfterExit=no),該服務才被視爲處於'活動'狀態。

對於單進程的傳統服務,當最初的進程成功退出後,將會只剩單獨一個進程仍然在持續運行, systemd 將會把這個唯一剩餘的進程視爲該服務的主進程。 僅在這種情況下,纔將可以在 ExecReload=, ExecStop= ... 之類的選項中使用 $MAINPID 變量。 對於多進程的傳統服務,當最初的進程成功退出後,將會剩餘多個進程在持續運行, 因此,systemd 無法確定哪一個進程纔是該服務的主進程。在這種情況下,不可以使用 $MAINPID 變量。

然而,如果主進程會創建傳統的PID文件,那麼應該將 PIDFile= 設爲此PID文件的絕對路徑, 以幫助 systemd 從該PID文件中讀取主進程的PID,從而幫助確定該服務的主進程。 注意,守護進程必須在完成初始化之前寫入PID文件,否則可能會導致 systemd 讀取失敗(讀取時文件不存在)。

下面是一個單進程傳統服務的示例:

[Unit]

Description=Some simple daemon

[Service]

Type=forking

ExecStart=/usr/sbin/my-simple-daemon -d

[Install]

WantedBy=multi-user.target

參見 systemd.kill(5) 以瞭解如何結束服務進程。

 

例5. D-Bus 服務

對於需要在 D-Bus 系統總線上註冊一個名字的服務,應該使用 Type=dbus 並且設置相應的 BusName= 值。 該服務不可以派生任何子進程。一旦從 D-Bus 系統總線成功獲取所需的名字,該服務即被視爲初始化成功。

下面是一個典型的 D-Bus 服務:

[Unit]

Description=Simple DBus service

[Service]

Type=dbus

BusName=org.example.simple-dbus-service

ExecStart=/usr/sbin/simple-dbus-service

[Install]

WantedBy=multi-user.target

對於用於 D-Bus 激活的服務來說,不可以包含"[Install]"小節, 而是應該在對應的 D-Bus service 文件中設置 SystemdService= 選項, 例如(/usr/share/dbus-1/system-services/org.example.simple-dbus-service.service):

[D-BUS Service]

Name=org.example.simple-dbus-service

Exec=/usr/sbin/simple-dbus-service

User=root

SystemdService=simple-dbus-service.service

參見system-kill手冊以瞭解如何結束服務。

例6. 能夠通知初始化已完成的服務

Type=simple 類型的服務非常容易編寫,但是無法將'初始化已完成'的消息及時通知給 systemd 是一個重大缺陷。 Type=notify 可以彌補該缺陷,它支持將'初始化已完成'的消息及時通知給 systemd。

下面是一個典型的例子:

[Unit]

Description=Simple notifying service

[Service]

Type=notify

ExecStart=/usr/sbin/simple-notifying-service

[Install]

WantedBy=multi-user.target

注意,該守護進程必須支持 systemd 通知協議,否則 systemd 將會認爲該服務一直處於'正在啓動中',並在超時後將其殺死。 關於如何支持該通知協議,參見 sd_notify(3) 手冊頁。 參見 systemd.kill(5) 手冊以瞭解如何結束服務。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章