Linux中Systemd的Unit文件詳細介紹

Systemd的Unit文件

在 Systemd 的生態圈中(除了 CoreOS 外,目前的主流 Linux 系統,如 Arch、SUSE、Fedora、RedHat/CentOS 也都已經使用了 Systemd,此外 Ubuntu 也將最快於15.04版本啓用 Systemd 作爲默認的系統管理工具),Unit 文件統一了過去各種不同的系統資源配置格式,例如服務的啓/停、定時任務、設備自動掛載、網絡配置、設備配置、虛擬內存配置等。而 Systemd 通過不同的通過文件的後綴名來區分這些配置文件,之前我們寫的 .service 文件便是其中的一種。

每一個服務以.service結尾,一般會分爲3部分:[Unit]、[Service]和[Install],我寫的這個服務用於開機運行Node.js項目,簡化內容如下:

#[Unit]部分主要是對這個服務的說明,內容包括Description和After,Description
#用於描述服務,After用於描述服務啓動依賴
[Unit]
Description=xiyoulibapi
After=network.target remote-fs.target nss-lookup.target
#[Service]部分是服務的關鍵,是服務的一些具體運行參數的設置,這裏Type=forking
#是後臺運行的形式,PIDFile爲存放PID的文件路徑,ExecStart爲服務的具體運行命令,
#ExecReload爲重啓命令,ExecStop爲停止命令,PrivateTmp=True表示給服務分配獨
#立的臨時空間,注意:[Service]部分的啓動、重啓、停止命令全部要求使用絕對路徑,使
#用相對路徑則會報錯!
[Service]
Type=forking
PIDFile=/node.js/pid
ExecStart=/usr/local/bin/forever start /node.js/xiyoulib/bin/www
ExecReload=/usr/local/bin/forever restart /node.js/xiyoulib/bin/www
ExecStop=/usr/local/bin/forever stop /node.js/xiyoulib/bin/www
PrivateTmp=true
#[Install]部分是服務安裝的相關設置,可設置爲多用戶的
[Install]
WantedBy=multi-user.target

服務腳本按照上面編寫完成後,以754的權限保存在/usr/lib/systemd/system目錄下,這時就可以利用systemctl進行配置了

下面是 Systemd 所支持的12種 Unit 文件類型。

後綴名

作用

.automount

用於控制自動掛載文件系統。自動掛載即當某一目錄被訪問時系統自動掛載該目錄,這類 unit 取代了傳統 Linux 系統的 autofs 相應功能

.device

對應 /dev 目錄下設備,主要用於定義設備之間的依賴關係

.mount

定義系統結構層次中的一個掛載點,可以替代過去的 /etc/fstab 配置文件

.path

用於監控指定目錄變化,並觸發其他 unit 運行

.scope

這類 unit 文件不是用戶創建的,而是 Systemd 運行時自己產生的,描述一些系統服務的分組信息

.service

封裝守護進程的啓動、停止、重啓和重載操作,是最常見的一種 unit 類型

.slice

用於描述 cgroup 的一些信息,極少使用到,一般用戶就忽略它吧

.snapshot

這種 unit 其實是 systemctl snapshot 命令創建的一個描述 Systemd unit 運行狀態的快照

.socket

監控系統或互聯網中的 socket 消息,用於實現基於網絡數據自動觸發服務啓動

.swap

定義一個用於做虛擬內存的交換分區

.target

用於對 unit 進行邏輯分組,引導其他 unit 的執行。它替代了 SysV 中運行級別的作用,並提供更靈活的基於特定設備事件的啓動方式。例如 multi-user.target 相當於過去的運行級別5,而 bluetooth.target 在有藍牙設備接入時就會被觸發

.timer

封裝由system的裏面由時間觸發的動作, 替代了 crontab 的功能

這些琳琅滿目的種類,幾乎囊括了系統管理的大部分的日常工作內容,一致的配置格式和操作方法使得即便普通的 Linux 系統使用者和軟件開發者也能夠很快的上手修改系統的配置,媽媽再也不用擔心我們把系統弄掛了。其實這些配置文件類型中,真正經常需要修改的並不多,並且這篇文章只打算對其中最常用的,也是之前一直在寫的 .service 類型展開說明。主要出於篇幅考慮,不過,既然格式都統一了,只要將一種配置類型用熟了,其他的配置學習來還不是分分鐘的事啦 😄
需要再次強調的是,Unit 文件按照 Systemd 約定,應該被放置在指定的3個系統目錄之一。這3個目錄是有優先級的,依照下面表格,越靠上的優先級越高,因此在幾個目錄中有同名文件的時候,只有優先級最高的目錄裏的那個會被使用。

路徑

說明

/etc/systemd/system

系統或用戶提供的配置文件

/run/systemd/system

軟件運行時生成的配置文件

/usr/lib/systemd/system

系統或第三方軟件安裝時添加的配置文件

由於這裏的最後一個目錄在 CoreOS 中是屬於系統的只讀分區,因此在 CoreOS 中,第三方軟件如果安裝時可能需要特別處理,將配置的 Unit 文件放到 /run/systemd/system目錄中。索性 CoreOS 本來也不推薦直接在系統上安裝軟件,人家特意把系統分區做成只讀這個意思就已經很明確了。一些確實需要安裝在 CoreOS 上的軟件比如 Deis,它的 .service 服務配置都是放到 /run/systemd/system目錄裏面的。
Service文件
開門見山,直接來看兩個實際的服務配置文件吧。

第一個配置是 CoreOS 系統中 Docker 服務的 Unit 文件,路徑是 /usr/lib/systemd/system/docker.service,可以看到其中的內容相當精簡易讀。

[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=docker.socket early-docker.target network.target
Requires=docker.socket early-docker.target
[Service]
Environment=TMPDIR=/var/tmp
Environment=DOCKER_OPTS=’–insecure-registry=“0.0.0.0/0”’
EnvironmentFile=-/run/docker_opts.env
LimitNOFILE=1048576
LimitNPROC=1048576
ExecStart=/usr/lib/coreos/dockerd --daemon --host=fd:// $DOCKER_OPTS
[Install]
WantedBy=multi-user.target
第二個配置的寫法風格與前一個有所差異,但同樣的內容清晰,條理明確。這個配置來自 CoreOS 的一篇文檔,作用是啓動一個 Apache 服務容器然後將服務的運行信息註冊到 Etcd 中。

(注意,這篇文檔原文中的示例中似乎有一個錯誤,在啓動 docker 時,ExecStart 中的命令參數 -p 80:80 應當爲 -p 8081:80,下面代碼已修正)

[Unit]
Description=My Advanced Service
After=etcd.service
After=docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill apache1
ExecStartPre=-/usr/bin/docker rm apache1
ExecStartPre=/usr/bin/docker pull coreos/apache
ExecStart=/usr/bin/docker run --name apache1 -p 8081:80 coreos/apache /usr/sbin/apache2ctl -D FOREGROUND
ExecStartPost=/usr/bin/etcdctl set /domains/example.com/10.10.10.123:8081 running
ExecStop=/usr/bin/docker stop apache1
ExecStopPost=/usr/bin/etcdctl rm /domains/example.com/10.10.10.123:8081
[Install]
WantedBy=multi-user.target
仔細觀察着兩個服務配置,其中有一些很明顯的共同點。我們接下來就以這兩個 Unit 文件爲例,一步步的分析一下 Systemd 服務配置的寫法。

Service 的 Unit 文件可以分爲3個配置區段,其中 Unit 和 Install 段是所有 Unit 文件通用的,用於配置服務(或其他系統資源)的描述、依賴和隨系統啓動方式。而 Service 段則是服務類型的 Unit 文件(後綴.service)特有的,用於定義服務的具體管理和操作方法。其他的每種配置文件也都會有一個特有的配置段,這就是幾種不同 Unit 配置文件最明顯的區別。

來看看每個配置段常用的參數有哪些。

一、Unit 段
Description
一段描述這個 Unit 文件的文字,通常只是簡短的一句話。

Documentation
指定服務的文檔,可以是一個或多個文檔的URL路徑。

Requires
依賴的其他 Unit 列表,列在其中的 Unit 模塊會在這個服務啓動的同時被啓動,並且如果其中有任意一個服務啓動失敗,這個服務也會被終止。

Wants
與 Requires 相似,但只是在被配置的這個 Unit 啓動時,觸發啓動列出的每個 Unit 模塊,而不去考慮這些模塊啓動是否成功。

After
與 Requires 相似,但會在後面列出的所有模塊全部啓動完成以後,纔會啓動當前的服務。

Before
與 After 相反,在啓動指定的任一個模塊之前,都會首先確保當前服務已經運行。

BindsTo
與 Requires 相似,但是一種更強的關聯。啓動這個服務時會同時啓動列出的所有模塊,當有模塊啓動失敗時終止當前服務。反之,只要列出的模塊全部啓動以後,也會自動啓動當前服務。並且這些模塊中有任意一個出現意外結束或重啓,這個服務會跟着終止或重啓。

PartOf
這是一個 BindTo 作用的子集,僅在列出的任何模塊失敗或重啓時,終止或重啓當前服務,而不會隨列出模塊的啓動而啓動。

OnFailure
當這個模塊啓動失敗時,就自動啓動列出的每個模塊。

Conflicts
與這個模塊有衝突的模塊,如果列出模塊中有已經在運行的,這個服務就不能啓動,反之亦然。

上面這些配置中,除了 Description 外,都能夠被添加多次。比如前面第一個例子中的After參數在一行中使用空格分隔指定所有值,也可以像第二個例子中那樣使用多個After參數,在每行參數中指定一個值。

二、Install 段
這個段中的配置與 Unit 有幾分相似,但是這部分配置需要通過 systemctl enable 命令來激活,並且可以通過 systemctl disable 命令禁用。另外這部分配置的目標模塊通常是特定啓動級別的 .target 文件,用來使得服務在系統啓動時自動運行。

WantedBy
和前面的 Wants 作用相似,只是後面列出的不是服務所依賴的模塊,而是依賴當前服務的模塊。

RequiredBy
和前面的 Requires 作用相似,同樣後面列出的不是服務所依賴的模塊,而是依賴當前服務的模塊。

Also
當這個服務被 enable/disable 時,將自動 enable/disable 後面列出的每個模塊。

上面的兩個例子中使用的都是 “WantedBy=multi-user.target” 表明當系統以多用戶方式(默認的運行級別)啓動時,這個服務需要被自動運行。當然還需要 systemctl enable 激活這個服務以後自動運行纔會生效。關於 Linux 系統啓動時的運行級別,可以參看這篇文章。

三、Service 段
這個段是 .service 文件獨有的,也是對於服務配置最重要的部分。這部分的配置選項非常多,主要分爲服務生命週期控制和服務上下文配置兩個方面,下面是比較常用到的一些參數。

服務生命週期控制相關的參數:

Type
服務的類型,常用的有 simple(默認類型) 和 forking。默認的 simple 類型可以適應於絕大多數的場景,因此一般可以忽略這個參數的配置。而如果服務程序啓動後會通過 fork 系統調用創建子進程,然後關閉應用程序本身進程的情況,則應該將 Type 的值設置爲 forking,否則 systemd 將不會跟蹤子進程的行爲,而認爲服務已經退出。

RemainAfterExit
值爲 true 或 false(也可以寫 yes 或 no),默認爲 false。當配置值爲 true 時,systemd 只會負責啓動服務進程,之後即便服務進程退出了,systemd 仍然會認爲這個服務是在運行中的。這個配置主要是提供給一些並非常駐內存,而是啓動註冊後立即退出然後等待消息按需啓動的特殊類型服務使用

ExecStart
這個參數是幾乎每個 .service 文件都會有的,指定服務啓動的主要命令,在每個配置文件中只能使用一次。

ExecStartPre
指定在啓動執行 ExecStart 的命令前的準備工作,可以有多個,如前面第二個例子中所示,所有命令會按照文件中書寫的順序依次被執行。

ExecStartPost
指定在啓動執行 ExecStart 的命令後的收尾工作,也可以有多個。

TimeoutStartSec
啓動服務時的等待的秒數,如果超過這個時間服務任然沒有執行完所有的啓動命令,則 systemd 會認爲服務自動失敗。這一配置對於使用 Docker 容器託管的應用十分重要,由於 Docker 第一次運行時可以能會需要從網絡下載服務的鏡像文件,因此造成比較嚴重的延時,容易被 systemd 誤判爲啓動失敗而殺死。通常對於這種服務,需要將 TimeoutStartSec 的值指定爲 0,從而關閉超時檢測,如前面的第二個例子。

ExecStop
停止服務所需要執行的主要命令。

ExecStopPost
指定在 ExecStop 命令執行後的收尾工作,也可以有多個。

TimeoutStopSec
停止服務時的等待的秒數,如果超過這個時間服務仍然沒有停止,systemd 會使用 SIGKILL 信號強行殺死服務的進程。

Restart
這個值用於指定在什麼情況下需要重啓服務進程。常用的值有 no,on-success,on-failure,on-abnormal,on-abort 和 always。默認值爲 no,即不會自動重啓服務。這些不同的值分別表示了在哪些情況下,服務會被重新啓動,參見下表。

服務退出原因

no

always

on-failure

on-abnormal

on-abort

no-success

正常退出

異常退出

啓動/停止超時

被異常KILL

RestartSec
如果服務需要被重啓,這個參數的值爲服務被重啓前的等待秒數。

ExecReload
重新加載服務所需執行的主要命令。

服務上下文配置相關的參數:

Environment
爲服務添加環境變量,如前面的第一個例子中所示。

EnvironmentFile
指定加載一個包含服務所需的環境變量列表的文件,文件中的每一行都是一個環境變量的定義。

Nice
服務的進程優先級,值越小優先級越高,默認爲0。-20爲最高優先級,19爲最低優先級。

WorkingDirectory
指定服務的工作目錄。

RootDirectory
指定服務進程的根目錄( / 目錄),如果配置了這個參數後,服務將無法訪問指定目錄以外的任何文件。

User
指定運行服務的用戶,會影響服務對本地文件系統的訪問權限。

Group
指定運行服務的用戶組,會影響服務對本地文件系統的訪問權限。

LimitCPU / LimitSTACK / LimitNOFILE / LimitNPROC 等
限制特定服務可用的系統資源量,例如 CPU,程序堆棧,文件句柄數量,子進程數量… 不再展開說明了,值的含義可參考 Linux 文檔資源配額部分中 RLIMIT_ 開頭的那些參數們。

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