前言
Systemd 是一系列工具的集合,其作用也遠遠不僅是啟動操作系統,它還接管了后台服務、結束、狀態查詢,以及日志歸檔、設備管理、電源管理、定時任務等許多職責,並支持通過特定事件(如插入特定 USB 設備)和特定端口數據觸發的 On-demand(按需)任務。
存放位置
系統服務,開機不需要登錄就能運行的程序(可以用於開機自啟)
/usr/lib/systemd/system
用戶服務,需要登錄后才能運行程序
/usr/lib/systemd/user
命名
一般xxx.service
Quick Start
nginx.service
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecStop=/usr/local/nginx/sbin/nginx -s stop -c /usr/local/nginx/conf/nginx.conf
ExecReload= /usr/local/nginx/sbin/nginx -s reload -c /usr/local/nginx/conf/nginx.conf
PrivateTmp=ture
[Install]
WantedBy=multi-user.target
code-server.service
[Unit]
Description=code-server background running.
After=network.target
[Service]
Type=simple
Environment="PASSWORD=XXX"
EnvironmentFile=-/etc/code-server/code-server
PIDFile=/run/code-server.pid
ExecStart=/usr/bin/code-server --config /etc/code-server/code-server.config.yaml
KillSignal=control-group
ExecStop=/bin/kill -SIGTERM $MAINPID
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target
參數詳解
[Unit]
Description:簡短描述
Documentation:文檔地址
Requires:當前 Unit 依賴的其他 Unit,如果它們沒有運行,當前 Unit 會啟動失敗
Wants:與當前 Unit 配合的其他 Unit,如果它們沒有運行,當前 Unit 不會啟動失敗
BindsTo:與Requires類似,它指定的 Unit 如果退出,會導致當前 Unit 停止運行
Before:如果該字段指定的 Unit 也要啟動,那么必須在當前 Unit 之后啟動
After:如果該字段指定的 Unit 也要啟動,那么必須在當前 Unit 之前啟動
Conflicts:這里指定的 Unit 不能與當前 Unit 同時運行
Condition...:當前 Unit 運行必須滿足的條件,否則不會運行
Assert...:當前 Unit 運行必須滿足的條件,否則會報啟動失敗
+-------------------+ +---------------------+
|After->Condition...| -> |Requires -> Assert...| ->
+-------------------+ +---------------------+
+-----+ +-------+ +------+
-> |Wants| -> |BindsTo| -> |Before| -> ...
+-----+ +-------+ +------+
[Service]
Type:定義啟動時的進程行為。它有以下幾種值。
Type=simple:(默認值)啟動一個子進程運行命令,用於不會退出的程序
Type=forking:fork一個字進程,等待命令完成后退出,多用於后台進程
Type=oneshot:systemctl 等待命令完成再往下執行,像在控制台執行一個命令一樣
Type=dbus:當前服務通過D-Bus啟動
Type=notify:當前服務啟動完畢,會通知Systemd,再繼續往下執行
Type=idle:若有其他任務執行完畢,當前服務才會運行
PIDFile:存放PID的絕對路徑
ExecStart:啟動當前服務的命令
ExecStartPre:啟動當前服務之前執行的命令
ExecStartPost:啟動當前服務之后執行的命令
ExecReload:重啟當前服務時執行的命令
ExecStop:停止當前服務時執行的命令
ExecStopPost:停止當其服務之后執行的命令
RestartSec:自動重啟當前服務間隔的秒數
Restart:定義何種情況 Systemd 會自動重啟當前服務
no(默認值): # 退出后無操作
on-success: # 只有正常退出時(退出狀態碼為0),才會重啟
on-failure: # 非正常退出時,重啟,包括被信號終止和超時等
on-abnormal: # 只有被信號終止或超時,才會重啟
on-abort: # 只有在收到沒有捕捉到的信號終止時,才會重啟
on-watchdog: # 超時退出時,才會重啟
always: # 不管什么退出原因,都會重啟(除了systemctl stop)
# 對於守護進程,推薦用on-failure
KillMode的類型:
control-group(默認):# 當前控制組里的所有子進程,都會被殺掉
process: # 只殺主進程
mixed: # 主進程將收到SIGTERM信號,子進程收到SIGKILL信號
none: # 沒有進程會被殺掉,只是執行服務的stop命令
PrivateTmp=true # 表示給服務分配獨立的臨時空間
TimeoutSec:停止命令執行前等待秒數。
TimeoutStartSec:啟動命令執行后等待秒數,超時停止。(0 關閉超時檢測)
TimeoutStopSec:停止命令執行后等待秒數,超時使用 SIGKILL 停止服務。
Environment:為服務指定環境變量。
EnvironmentFile:環境變量文件,一行一個不要有空格。
Nice:進程優先級(默認為0)其中 -20 為最高優先級,19 為最低優先級。
WorkingDirectory:指定服務的工作目錄,目錄不純在命令不能運行
RootDirectory:指定服務進程的根目錄(/ 目錄)。如果配置了這個參數,服務將無法訪問指定目錄以外的任何文件
User:指定運行服務的用戶
Group:指定運行服務的用戶組
MountFlags:服務的 Mount Namespace 配置,會影響進程上下文中掛載點的信息。
shared:服務與主機共用一個 Mount Namespace,相互影響
slave:服務使用獨立的 Mount Namespace,它會繼承主機掛載點,操作只有在自己的 Namespace 內生效。
private:服務使用獨立的 Mount Namespace,它在啟動時沒有任何任何掛載點,服務對掛載點的操作也不會反映到主機上。
LimitCPU:LimitSTACK:\
LimitNOFILE:LimitNPROC: 限制特定服務的系統資源量,請看參考
+-----------+ +----+
|User->Group| -> |Nice| ->
+-----------+ +----+
+---------------------------------+ +---------------+ +-------+
-> |RootDirectory -> WorkingDirectory| -> |EnvironmentFile| -> |PIDFile|
+---------------------------------+ +---------------+ +-------+
+----+ +-------------------------------------------------------------+
-> |Type| -> |ExecStartPre -> ExecStart -> ExecStartPost -> TimeoutStartSec| ->
+----+ +-------------------------------------------------------------+
+-------+ +------------------------+
-> |Restart| -> |ExecReload -> RestartSec| ->
+-------+ +------------------------+
+--------+ +--------------------------------------------------------+
-> |KillMode| -> |TimeoutSec -> ExecStop -> ExecStopPost -> TimeoutStopSec| -> ...
+--------+ +--------------------------------------------------------+
[Install]
WantedBy:Unit 激活時(enable)xxx.service符號鏈接會放入/etc/systemd/system/xxx.target.wants/目錄下面
multi-user.target: # 表示多用戶命令行狀態,這個設置很重要
graphical.target: # 表示圖形用戶狀體,它依賴於multi-user.target
RequiredBy:Unit 激活時(enable)xxx.service符號鏈接會放入/etc/systemd/system/xxx.target.required/目錄下面
Alias:當前 Unit 可用於啟動的別名
Also:當前 Unit 激活(enable)時,會被同時激活的其他 Unit
Unit 文件占位符和模板
占位符
在 Unit 文件中,有時會需要使用到一些與運行環境有關的信息,例如節點 ID、運行服務的用戶等。這些信息可以使用占位符來表示,然后在實際運行被動態地替換實際的值。
%n:完整的 Unit 文件名字,包括 .service 后綴名
%p:Unit 模板文件名中 @ 符號之前的部分,不包括 @ 符號
%i:Unit 模板文件名中 @ 符號之后的部分,不包括 @ 符號和.service 后綴名
%t:存放系統運行文件的目錄,通常是 “run”
%u:運行服務的用戶,如果 Unit 文件中沒有指定,則默認為 root
%U:運行服務的用戶 ID
%h:運行服務的用戶 Home 目錄,即 %{HOME} 環境變量的值
%s:運行服務的用戶默認 Shell 類型,即 %{SHELL} 環境變量的值
%m:實際運行節點的 Machine ID,對於運行位置每個的服務比較有用
%b:Boot ID,這是一個隨機數,每個節點各不相同,並且每次節點重啟時都會改變
%H:實際運行節點的主機名
%v:內核版本,即 “uname -r” 命令輸出的內容
%%:在 Unit 模板文件中表示一個普通的百分號
模板
Unit 模板文件的寫法與普通的服務 Unit 文件基本相同,不過 Unit 模板的文件名是以 @ 符號結尾的。通過模板啟動服務實例時,需要在其文件名的 @ 字符后面附加一個參數字符串。
# apache@.service 模板
[Unit]
Description=My Advanced Service Template
After=etcd.service docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill apache%i
ExecStartPre=-/usr/bin/docker rm apache%i
ExecStartPre=/usr/bin/docker pull coreos/apache
ExecStart=/usr/bin/docker run --name apache%i -p %i:80 coreos/apache /usr/sbin/apache2ctl -D FOREGROUND
ExecStartPost=/usr/bin/etcdctl set /domains/example.com/%H:%i running
ExecStop=/usr/bin/docker stop apache1
ExecStopPost=/usr/bin/docker rm apache1
ExecStopPost=/usr/bin/etcdctl rm /domains/example.com/%H:%i
[Install]
WantedBy=multi-user.target
啟動服務
在服務啟動時需要在 @ 后面放置一個用於區分服務實例的附加字符參數,通常這個參數用於監控的端口號或控制台 TTY 編譯號。
Systemd 在運行服務時,總是會先嘗試找到一個完整匹配的 Unit 文件,如果沒有找到,才會嘗試選擇匹配模板。例如上面的命令,System 首先會在約定的目錄下尋找名為 apache@8080.service 的文件,如果沒有找到,而文件名中包含 @ 字符,它就會嘗試去掉后綴參數匹配模板文件。對於 apache@8080.service,systemd 會找到 apache@.service 模板文件,並通過這個模板文件將服務實例化。
systemctl start apache@8080.service