【systemd】systemd.service

systemd即為system daemon,是linux下的一種init軟件,由Lennart Poettering帶頭開發,并在LGPL 2.1及其后續版本許可證下開源發布,開發目標是提供更優秀的框架以表示系統服務間的依賴關系,并依此實現系統初始化時服務的并行啟動,同時達到降低Shell的系統開銷的效果,最終代替現在常用的System V與BSD風格init程序。

?與多數發行版使用的System V風格init相比,systemd采用了以下新技術:

?(1) 采用Socket激活式與總線激活式服務,以提高相互依賴的各服務的并行運行性能;

?(2) 用Cgroups代替PID來追蹤進程,以此即使是兩次fork之后生成的守護進程也不會脫離systemd的控制



例 1. 簡單服務

下面的單元文件創建了一個運行 /usr/sbin/foo-daemon 守護進程的服務。 未設置 Type= 等價于 Type=simple 默認設置。 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=清理老舊的 Foo 數據

[Service]

Type=oneshot

ExecStart=/usr/sbin/foo-cleanup

[Install]

WantedBy=multi-user.target

##################################

注意,在 /usr/sbin/foo-cleanup 執行結束前, 該服務一直處于"啟動中"(activating)狀態,而一旦執行結束,該服務又立即變為"停止"(inactive)狀態。 也就是說,對于 Type=oneshot 類型的服務,不存在"活動"(active)狀態。 這意味著,如果再一次啟動該服務,將會再一次執行該服務定義的動作。 注意,在先后順序上晚于該服務的單元, 將會一直等到該服務變成"停止"(inactive)狀態后, 才會開始啟動。

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

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

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

可以通過設置 RemainAfterExit=yes 來滿足這種需求。 在這種情況下,systemd 將會在啟動成功后將該單元視為處于"活動"(active)狀態(而不是"停止"(inactive)狀態)。 RemainAfterExit=yes 雖然可以用于所有 Type= 類型, 但是在實踐中主要用于 Type=oneshot 和 Type=simple 類型。 對于 Type=oneshot 類型, systemd 一直等到服務啟動成功之后,才會將該服務置于"活動"(active)狀態。 所以,依賴于該服務的其他單元必須等待該服務啟動成功之后,才能啟動。 但是對于 Type=simple 類型, 依賴于該服務的其他單元無需等待,將會和該服務同時并行啟動。 下面的類似展示了一個簡單的靜態防火墻服務:

####################################

[Unit]

Description=簡單的靜態防火墻

[Service]

Type=oneshot

RemainAfterExit=yes

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

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

[Install]

WantedBy=multi-user.target

####################################

因為服務啟動成功后一直處于"活動"(active)狀態, 所以再次執行 systemctl start 命令不會有任何效果。

例 4. 傳統的服務

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

對于單進程的傳統服務,當最初的進程成功退出后, 將會只剩單獨一個進程仍然在持續運行, systemd 將會把這個唯一剩余的進程視為該服務的主進程。 僅在這種情況下,才將可以在 ExecReload=, ExecStop= … 之類的選項中使用 $MAINPID 變量。

對于多進程的傳統服務,當最初的進程成功退出后,將會剩余多個進程在持續運行, 因此,systemd 無法確定哪一個進程才是該服務的主進程。 在這種情況下,不可以使用 $MAINPID 變量。 然而,如果主進程會創建傳統的PID文件, 那么應該將 PIDFile= 設為此PID文件的絕對路徑, 以幫助 systemd 從該PID文件中讀取主進程的PID,從而幫助確定該服務的主進程。 注意,守護進程必須在完成初始化之前寫入PID文件, 否則可能會導致 systemd 讀取失敗(讀取時文件不存在)。

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

#################################

[Unit]

Description=一個單進程傳統服務

[Service]

Type=forking

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

[Install]

WantedBy=multi-user.target

##################################?

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

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


##########################################################

[Unit]

Description=The NGINX HTTP and reverse proxy server

After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]

Type=forking

PIDFile=/run/nginx.pid

ExecStartPre=/usr/sbin/nginx -t

ExecStart=/usr/sbin/nginx

ExecReload=/usr/sbin/nginx -s reload

ExecStop=/bin/kill -s QUIT $MAINPID

PrivateTmp=true

[Install]

WantedBy=multi-user.target

###########################################################?

例 5. DBus 服務

對于需要在 D-Bus 系統總線上注冊一個名字的服務, 應該使用 Type=dbus 并且設置相應的 BusName= 值。?

該服務不可以派生任何子進程。 一旦從 D-Bus 系統總線成功獲取所需的名字,該服務即被視為初始化成功。?

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

#################################

[Unit]

Description=一個簡單的 DBus 服務

[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

###################################


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

例 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 將會認為該服務一直處于"啟動中"(activating)狀態,并在超時后將其殺死。 關于如何支持該通知協議,參見 sd_notify(3) 手冊。

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


參考

systemd詳解

https://blog.linuxeye.cn/400.html

Systemd 入門教程:命令篇

http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html

Systemd 入門教程:實戰篇

http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html

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

http://blog.csdn.net/yuesichiu/article/details/51485147

https://www.freedesktop.org/software/systemd/man/systemd.service.html

CentOS 7之Systemd詳解之單元配置systemd.unit

http://blog.csdn.net/yuesichiu/article/details/51331136

CentOS 7系統詳細開機啟動流程和關機流程

http://blog.csdn.net/yuesichiu/article/details/51350654

NGINX systemd service file

https://www.nginx.com/resources/wiki/start/topics/examples/systemd

http://images.linoxide.com/systemd-vs-sysVinit-cheatsheet.pdf

Centos7 創建服務

http://blog.csdn.net/zhangxtn/article/details/50462008

編寫systemd service文件

https://zh.opensuse.org/openSUSE:How_to_write_a_systemd_service

認識系統服務

http://linux.vbird.org/linux_basic/0560daemons.php

systemd System and Service Manager

https://www.freedesktop.org/wiki/Software/systemd/

https://wiki.archlinux.org/index.php/systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type=?

systemd.service 中文手冊

http://www.jinbuguo.com/systemd/systemd.service.html

systemd 使用簡介

https://jin-yang.github.io/post/linux-systemd.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容