systemd詳解詳解
systemd詳解
CentOS 7 使用systemd替換了SysV。Systemd目的是要取代Unix時代以來一直在使用的init系統(tǒng),兼容SysV和LSB的啟動腳本,而且夠在進(jìn)程啟動過程中更有效地引導(dǎo)加載服務(wù)。
systemd的特性有:
- 支持并行化任務(wù)
- 同時采用socket式與D-Bus總線式激活服務(wù);
- 按需啟動守護(hù)進(jìn)程(daemon);
- 利用 Linux 的 cgroups 監(jiān)視進(jìn)程;
- 支持快照和系統(tǒng)恢復(fù);
- 維護(hù)掛載點(diǎn)和自動掛載點(diǎn);
- 各服務(wù)間基于依賴關(guān)系進(jìn)行精密控制。
systemd基本工具
檢視和控制systemd的主要命令是systemctl。該命令可用于查看系統(tǒng)狀態(tài)和管理系統(tǒng)及服務(wù)。詳見man 1 systemctl。
小貼士:
- 在 systemctl 參數(shù)中添加 -H <用戶名>@<主機(jī)名> 可以實(shí)現(xiàn)對其他機(jī)器的遠(yuǎn)程控制。該過程使用ssh鏈接。
- systemadm是systemd 的官方圖形前端
分析系統(tǒng)狀態(tài)
輸出激活的單元:
- $ systemctl
以下命令等效:
- $ systemctl list-units
輸出運(yùn)行失敗的單元:
- $ systemctl --failed
所有可用的單元文件存放在 /usr/lib/systemd/system/ 和 /etc/systemd/system/ 目錄(后者優(yōu)先級更高)。查看所有已安裝服務(wù):
- $ systemctl list-unit-files
使用單元
一個單元配置文件可以描述如下內(nèi)容之一:系統(tǒng)服務(wù)(.service)、掛載點(diǎn)(.mount)、sockets(.sockets) 、系統(tǒng)設(shè)備(.device)、交換分區(qū)(.swap)、文件路徑(.path)、啟動目標(biāo)(.target)、由 systemd 管理的計時器(.timer)。詳情參閱 man 5 systemd.unit。
使用 systemctl 控制單元時,通常需要使用單元文件的全名,包括擴(kuò)展名(例如 sshd.service)。但是有些單元可以在systemctl中使用簡寫方式。
- 如果無擴(kuò)展名,systemctl 默認(rèn)把擴(kuò)展名當(dāng)作 .service。例如 netcfg 和 netcfg.service 是等價的。
- 掛載點(diǎn)會自動轉(zhuǎn)化為相應(yīng)的 .mount 單元。例如 /home 等價于 home.mount。
- 設(shè)備會自動轉(zhuǎn)化為相應(yīng)的 .device 單元,所以 /dev/sda2 等價于 dev-sda2.device。
注: 有一些單元的名稱包含一個 @ 標(biāo)記, (e.g. name@string.service): 這意味著它是模板單元 name@.service 的一個 實(shí)例。 string 被稱作實(shí)例標(biāo)識符, 在 systemctl 調(diào)用模板單元時,會將其當(dāng)作一個參數(shù)傳給模板單元,模板單元會使用這個傳入的參數(shù)代替模板中的 %I 指示符。 在實(shí)例化之前,systemd 會先檢查 name@string.suffix 文件是否存在(如果存在,應(yīng)該就是直接使用這個文件,而不是模板實(shí)例化了)。大多數(shù)情況下,包換 @ 標(biāo)記都意味著這個文件是模板。如果一個模板單元沒有實(shí)例化就調(diào)用,該調(diào)用會返回失敗,因為模板單元中的 %I 指示符沒有被替換。
立即激活單元:
- # systemctl start <單元>
立即停止單元:
- # systemctl stop <單元>
重啟單元:
- # systemctl restart <單元>
命令單元重新讀取配置:
- # systemctl reload <單元>
輸出單元運(yùn)行狀態(tài):
- $ systemctl status <單元>
檢查單元是否配置為自動啟動:
- $ systemctl is-enabled <單元>
開機(jī)自動激活單元:
- # systemctl enable <單元>
注意: 如果服務(wù)沒有Install段落,一般意味著應(yīng)該通過其它服務(wù)自動調(diào)用它們。如果真的需要手動安裝,可以直接連接服務(wù),如下(將foo替換為真實(shí)的服務(wù)名):
- # ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/
取消開機(jī)自動激活單元:
- # systemctl disable <單元>
顯示單元的手冊頁(必須由單元文件提供):
- # systemctl help <單元>
重新載入 systemd,掃描新的或有變動的單元:
- # systemctl daemon-reload
電源管理
安裝 polkit 后才可使用電源管理。
如果你正登錄在一個本地的systemd-logind用戶會話,且當(dāng)前沒有其它活動的會話,那么以下命令無需root權(quán)限即可執(zhí)行。否則(例如,當(dāng)前有另一個用戶登錄在某個tty),systemd 將會自動請求輸入root密碼。
重啟:
- $ systemctl reboot
退出系統(tǒng)并停止電源:
- $ systemctl poweroff
待機(jī):
- $ systemctl suspend
休眠:
- $ systemctl hibernate
混合休眠模式(同時休眠到硬盤并待機(jī)):
- $ systemctl hybrid-sleep
編寫單元文件
systemd單元文件的語法來源于 XDG桌面入口配置文件.desktop文件,最初的源頭則是Microsoft Windows的.ini文件。單元文件可以從兩個地方加載,優(yōu)先級從低到高分別是:
- /usr/lib/systemd/system/: 軟件包安裝的單元
- /etc/systemd/system/: 系統(tǒng)管理員安裝的單元
注意: 當(dāng)systemd運(yùn)行在用戶模式下時,使用的加載路徑是完全不同的。
單元文件的語法,可以參考系統(tǒng)已經(jīng)安裝的單元,也可以參考man systemd.service中的EXAMPLES章節(jié)。
小貼士: 以 # 開頭的注釋可能也能用在 unit-files 中, 但是只能在新行中使用。 不要在 systemd 的參數(shù)后面使用行末注釋, 否則 unit 將會啟動失敗。
處理依賴關(guān)系
使用systemd時,可通過正確編寫單元配置文件來解決其依賴關(guān)系。典型的情況是,單元A要求單元B在A啟動之前運(yùn)行。在此情況下,向單元A配置文件中的 [Unit] 段添加 Requires=B 和 After=B 即可。若此依賴關(guān)系是可選的,可添加 Wants=B 和 After=B。請注意 Wants= 和 Requires= 并不意味著 After=,即如果 After= 選項沒有制定,這兩個單元將被并行啟動。
依賴關(guān)系通常被用在服務(wù)(service)而不是目標(biāo)(target)上。例如, network.target 一般會被某個配置網(wǎng)絡(luò)接口的服務(wù)引入,所以,將自定義的單元排在該服務(wù)之后即可,因為 network.target 已經(jīng)啟動。
服務(wù)類型
編寫自定義的 service 文件時,可以選擇幾種不同的服務(wù)啟動方式。啟動方式可通過配置文件 [Service] 段中的 Type= 參數(shù)進(jìn)行設(shè)置。
- Type=simple(默認(rèn)值):systemd認(rèn)為該服務(wù)將立即啟動。服務(wù)進(jìn)程不會fork。如果該服務(wù)要啟動其他服務(wù),不要使用此類型啟動,除非該服務(wù)是socket激活型。
- Type=forking:systemd認(rèn)為當(dāng)該服務(wù)進(jìn)程fork,且父進(jìn)程退出后服務(wù)啟動成功。對于常規(guī)的守護(hù)進(jìn)程(daemon),除非你確定此啟動方式無法滿足需求,使用此類型啟動即可。使用此啟動類型應(yīng)同時指定 PIDFile=,以便systemd能夠跟蹤服務(wù)的主進(jìn)程。
- Type=oneshot:這一選項適用于只執(zhí)行一項任務(wù)、隨后立即退出的服務(wù)。可能需要同時設(shè)置 RemainAfterExit=yes 使得 systemd 在服務(wù)進(jìn)程退出之后仍然認(rèn)為服務(wù)處于激活狀態(tài)。
- Type=notify:與 Type=simple 相同,但約定服務(wù)會在就緒后向 systemd 發(fā)送一個信號。這一通知的實(shí)現(xiàn)由 libsystemd-daemon.so 提供。
- Type=dbus:若以此方式啟動,當(dāng)指定的 BusName 出現(xiàn)在DBus系統(tǒng)總線上時,systemd認(rèn)為服務(wù)就緒。
- Type=idle: systemd會等待所有任務(wù)(Jobs)處理完成后,才開始執(zhí)行idle類型的單元。除此之外,其他行為和Type=simple 類似。
type的更多解釋可以參考 systemd.service(5)。
修改現(xiàn)存單元文件
要更改由軟件包提供的單元文件,先創(chuàng)建名為 /etc/systemd/system/<單元名>.d/ 的目錄(如 /etc/systemd/system/httpd.service.d/),然后放入 *.conf 文件,其中可以添加或重置參數(shù)。這里設(shè)置的參數(shù)優(yōu)先級高于原來的單元文件。例如,如果想添加一個額外的依賴,創(chuàng)建這么一個文件即可:
- /etc/systemd/system/<unit>.d/customdependency.conf
- [Unit]
- Requires=<新依賴>
- After=<新依賴>
其它舉例,
- /etc/systemd/system/unit.d/customexec.conf
- [Service]
- ExecStartExecStart=
- ExecStart=new command
想知道為什么修改 ExecStart 前必須將其置空
下面是自動重啟服務(wù)的一個例子:
- /etc/systemd/system/unit.d/restart.conf
- [Service]
- Restart=always
- RestartSec=30
然后運(yùn)行以下命令使更改生效:
- # systemctl daemon-reload
- # systemctl restart <單元>
此外,把舊的單元文件從 /usr/lib/systemd/system/ 復(fù)制到 /etc/systemd/system/,然后進(jìn)行修改,也可以達(dá)到同樣效果。在 /etc/systemd/system/ 目錄中的單元文件的優(yōu)先級總是高于 /usr/lib/systemd/system/ 目錄中的同名單元文件。注意,當(dāng) /usr/lib/ 中的單元文件因軟件包升級變更時,/etc/ 中自定義的單元文件不會同步更新。此外,你還得執(zhí)行 systemctl reenable <unit>,手動重新啟用該單元。因此,建議使用前面一種利用 *.conf 的方法。
小貼士: 用 systemd-delta 命令來查看哪些單元文件被覆蓋、哪些被修改。系統(tǒng)維護(hù)的時候需要及時了解哪些單元已經(jīng)有了更新
單元配置文件的 vim 語法高亮支持
可從官方倉庫安裝 vim-systemd 軟件包,使 unit 配置文件在 Vim 下支持語法高亮。
目標(biāo)(target)
啟 動級別(runlevel)是一個舊的概念。現(xiàn)在,systemd 引入了一個和啟動級別功能相似又不同的概念——目標(biāo)(target)。不像數(shù)字表示的啟動級別,每個目標(biāo)都有名字和獨(dú)特的功能,并且能同時啟用多個。一些 目標(biāo)繼承其他目標(biāo)的服務(wù),并啟動新服務(wù)。systemd 提供了一些模仿 sysvinit 啟動級別的目標(biāo),仍可以使用舊的 telinit 啟動級別 命令切換。
獲取當(dāng)前目標(biāo)
不要使用 runlevel 命令了:
- $ systemctl list-units --type=target
創(chuàng)建新目標(biāo)
在 Fedora 中,啟動級別 0、1、3、5、6 都被賦予特定用途,并且都對應(yīng)一個 systemd 的目標(biāo)。然而,沒有什么很好的移植用戶定義的啟動級別(2、4)的方法。要實(shí)現(xiàn)類似功能,可以以原有的啟動級別為基礎(chǔ),創(chuàng)建一個新的目標(biāo) /etc/systemd/system/<新目標(biāo)>(可以參考 /usr/lib/systemd/system/graphical.target),創(chuàng)建 /etc/systemd/system/<新目標(biāo)>.wants 目錄,向其中加入額外服務(wù)的鏈接(指向 /usr/lib/systemd/system/ 中的單元文件)。
目標(biāo)表
| SysV 啟動級別 | Systemd 目標(biāo) | 注釋 |
|---|---|---|
| 0 | runlevel0.target, poweroff.target | 中斷系統(tǒng)(halt) |
| 1, s, single | runlevel1.target, rescue.target | 單用戶模式 |
| 2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用戶自定義啟動級別,通常識別為級別3。 |
| 3 | runlevel3.target, multi-user.target | 多用戶,無圖形界面。用戶可以通過終端或網(wǎng)絡(luò)登錄。 |
| 5 | runlevel5.target, graphical.target | 多用戶,圖形界面。繼承級別3的服務(wù),并啟動圖形界面服務(wù)。 |
| 6 | runlevel6.target, reboot.target | 重啟 |
| emergency | emergency.target | 急救模式(Emergency shell) |
切換啟動級別/目標(biāo)
systemd 中,啟動級別通過“目標(biāo)單元”訪問。通過如下命令切換:
- # systemctl isolate graphical.target
該命令對下次啟動無影響。等價于telinit 3 或 telinit 5。
修改默認(rèn)啟動級別/目標(biāo)
開機(jī)啟動進(jìn)的目標(biāo)是 default.target,默認(rèn)鏈接到 graphical.target (大致相當(dāng)于原來的啟動級別5)。可以通過內(nèi)核參數(shù)更改默認(rèn)啟動級別:
小貼士: 可以省略擴(kuò)展名 .target。
- systemd.unit=multi-user.target (大致相當(dāng)于級別3)
- systemd.unit=rescue.target (大致相當(dāng)于級別1)
另一個方法是修改 default.target。可以通過 systemctl 修改它:
- # systemctl enable multi-user.target
命令執(zhí)行情況由 systemctl 顯示:鏈接 /etc/systemd/system/default.target 被創(chuàng)建,指向新的默認(rèn)啟動級別。該方法當(dāng)且僅當(dāng)目標(biāo)配置文件中有以下內(nèi)容時有效:
- [Install]
- Alias=default.target
目前,multi-user.target、graphical.target 都包含這段內(nèi)容。
臨時文件
/usr/lib/tmpfiles.d/ 和 /etc/tmpfiles.d/ 中的文件描述了 systemd-tmpfiles 如何創(chuàng)建、清理、刪除臨時文件和目錄,這些文件和目錄通常存放在 /run 和 /tmp 中。配置文件名稱為 /etc/tmpfiles.d/<program>.conf。此處的配置能覆蓋 /usr/lib/tmpfiles.d/ 目錄中的同名配置。
臨時文件通常和服務(wù)文件同時提供,以生成守護(hù)進(jìn)程需要的文件和目錄。例如 Samba 服務(wù)需要目錄 /run/samba 存在并設(shè)置正確的權(quán)限位,就象這樣:
- /usr/lib/tmpfiles.d/samba.conf
- D /run/samba 0755 root root
此外,臨時文件還可以用來在開機(jī)時向特定文件寫入某些內(nèi)容。比如,要禁止系統(tǒng)從USB設(shè)備喚醒,利用舊的 /etc/rc.local 可以用 echo USBE > /proc/acpi/wakeup,而現(xiàn)在可以這么做:
- /etc/tmpfiles.d/disable-usb-wake.conf
- w /proc/acpi/wakeup - - - - USBE
詳情參見 man 5 tmpfiles.d。
注意: 該方法不能向 /sys 中的配置文件添加參數(shù),因為 systemd-tmpfiles-setup 有可能在相關(guān)模塊加載前運(yùn)行。這種情況下,需要首先通過 modinfo <模塊名> 確認(rèn)需要的參數(shù),并在 /etc/modprobe.d 下的一個文件中設(shè)置改參數(shù)。另外,還可以使用 udev 規(guī)則,在設(shè)備就緒時設(shè)置相應(yīng)屬性。
定時器
定時器是以 .timer 為后綴的配置文件,記錄由system的里面由時間觸發(fā)的動作, 定時器可以替代 cron 的大部分功能。
日志
systemd提供了自己日志系統(tǒng)(logging system),稱為 journal. 使用 systemd 日志,無需額外安裝日志服務(wù)(syslog)。讀取日志的命令:
- # journalctl
默認(rèn)情況下(當(dāng) Storage= 在文件 /etc/systemd/journald.conf 中被設(shè)置為 auto),日志記錄將被寫入 /var/log/journal/。該目錄是 systemd 軟件包的一部分。若被刪除,systemd 不會自動創(chuàng)建它,直到下次升級軟件包時重建該目錄。如果該目錄缺失,systemd 會將日志記錄寫入 /run/systemd/journal。這意味著,系統(tǒng)重啟后日志將丟失。
Tip: 如果 /var/log/journal/ 位于 btrfs 文件系統(tǒng),應(yīng)該考慮對這個目錄禁用寫入時復(fù)制
過濾輸出
journalctl可以根據(jù)特定字段過濾輸出,例如:
顯示本次啟動后的所有日志:
- # journalctl -b
不過,一般大家更關(guān)心的不是本次啟動后的日志,而是上次啟動時的(例如,剛剛系統(tǒng)崩潰了)。可以使用 -b 參數(shù):
- journalctl -b -0 顯示本次啟動的信息
- journalctl -b -1 顯示上次啟動的信息
- journalctl -b -2 顯示上上次啟動的信息 journalctl -b -2
- Show all messages from date (and optional time):
- # journalctl --since="2012-10-30 18:17:16"
- Show all messages since 20 minutes ago:
- # journalctl --since "20 min ago"
- 顯示最新信息
- # journalctl -f
- 顯示特定程序的所有消息:
- # journalctl /usr/lib/systemd/systemd
- 顯示特定進(jìn)程的所有消息:
- # journalctl _PID=1
- 顯示指定單元的所有消息:
- # journalctl -u netcfg
- Show kernel ring buffer:
- # journalctl -k
- Show auth.log equivalent by filtering on syslog facility:
- # journalctl -f -l SYSLOG_FACILITY=10
詳情參閱man journalctl、man systemd.journal-fields,以及Lennert的這篇博文
日志大小限制
如果按上面的操作保留日志的話,默認(rèn)日志最大限制為所在文件系統(tǒng)容量的 10%,即:如果 /var/log/journal 儲存在 50GiB 的根分區(qū)中,那么日志最多存儲 5GiB 數(shù)據(jù)。可以修改 /etc/systemd/journald.conf 中的 SystemMaxUse 來指定該最大限制。如限制日志最大 50MiB:
- SystemMaxUse=50M
詳情參見 man journald.conf.
配合syslog使用
systemd提供了 socket /run/systemd/journal/syslog,以兼容傳統(tǒng)日志服務(wù)。所有系統(tǒng)信息都會被傳入。要使傳統(tǒng)日志服務(wù)工作,需要讓服務(wù)鏈接該 socket,而非 /dev/log(官方說明)。Arch 軟件倉庫中的 syslog-ng 已經(jīng)包含了需要的配置。
設(shè)置開機(jī)啟動 syslog-ng:
- # systemctl enable syslog-ng
這里有一份很不錯的 journalctl指南。
Forward journald to /dev/tty12
In /etc/systemd/journald.conf enable the following:
- ForwardToConsole=yes
- TTYPath=/dev/tty12
- MaxLevelConsole=info
重啟journald:
- # systemctl restart systemd-journald
疑難解答
關(guān)機(jī)/重啟十分緩慢
如果關(guān)機(jī)特別慢(甚至跟死機(jī)了一樣),很可能是某個拒不退出的服務(wù)在作怪。systemd 會等待一段時間,然后再嘗試殺死它。請閱讀這篇文章,確認(rèn)你是否是該問題受害者。
短時進(jìn)程無日志記錄
若 journalctl -u foounit.service 沒有顯示某個短時進(jìn)程的任何輸出,那么改用 PID 試試。例如,若 systemd-modules-load.service 執(zhí)行失敗,那么先用 systemctl status systemd-modules-load 查詢其 PID(比如是123),然后檢索該 PID 相關(guān)的日志 journalctl -b _PID=123。運(yùn)行時進(jìn)程的日志元數(shù)據(jù)(諸如 _SYSTEMD_UNIT 和 _COMM)被亂序收集在 /proc 目錄。要修復(fù)該問題,必須修改內(nèi)核,使其通過套接字連接來提供上述數(shù)據(jù),該過程類似于 SCM_CREDENTIALS。
診斷啟動問題
使用如下內(nèi)核參數(shù)引導(dǎo): systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
禁止在程序崩潰時轉(zhuǎn)儲內(nèi)存
要使用老的內(nèi)核轉(zhuǎn)儲,創(chuàng)建下面文件:
- /etc/sysctl.d/49-coredump.conf
- kernel.core_pattern = core
- kernel.core_uses_pid = 0
然后運(yùn)行:
- # /usr/lib/systemd/systemd-sysctl
同樣可能需要執(zhí)行"unlimit"設(shè)置文件大小:
- $ ulimit -c unlimited
systemd詳解
CentOS 7 使用systemd替換了SysV。Systemd目的是要取代Unix時代以來一直在使用的init系統(tǒng),兼容SysV和LSB的啟動腳本,而且夠在進(jìn)程啟動過程中更有效地引導(dǎo)加載服務(wù)。
systemd的特性有:
- 支持并行化任務(wù)
- 同時采用socket式與D-Bus總線式激活服務(wù);
- 按需啟動守護(hù)進(jìn)程(daemon);
- 利用 Linux 的 cgroups 監(jiān)視進(jìn)程;
- 支持快照和系統(tǒng)恢復(fù);
- 維護(hù)掛載點(diǎn)和自動掛載點(diǎn);
- 各服務(wù)間基于依賴關(guān)系進(jìn)行精密控制。
systemd基本工具
檢視和控制systemd的主要命令是systemctl。該命令可用于查看系統(tǒng)狀態(tài)和管理系統(tǒng)及服務(wù)。詳見man 1 systemctl。
小貼士:
- 在 systemctl 參數(shù)中添加 -H <用戶名>@<主機(jī)名> 可以實(shí)現(xiàn)對其他機(jī)器的遠(yuǎn)程控制。該過程使用ssh鏈接。
- systemadm是systemd 的官方圖形前端
分析系統(tǒng)狀態(tài)
輸出激活的單元:
- $ systemctl
以下命令等效:
- $ systemctl list-units
輸出運(yùn)行失敗的單元:
- $ systemctl --failed
所有可用的單元文件存放在 /usr/lib/systemd/system/ 和 /etc/systemd/system/ 目錄(后者優(yōu)先級更高)。查看所有已安裝服務(wù):
- $ systemctl list-unit-files
使用單元
一個單元配置文件可以描述如下內(nèi)容之一:系統(tǒng)服務(wù)(.service)、掛載點(diǎn)(.mount)、sockets(.sockets) 、系統(tǒng)設(shè)備(.device)、交換分區(qū)(.swap)、文件路徑(.path)、啟動目標(biāo)(.target)、由 systemd 管理的計時器(.timer)。詳情參閱 man 5 systemd.unit。
使用 systemctl 控制單元時,通常需要使用單元文件的全名,包括擴(kuò)展名(例如 sshd.service)。但是有些單元可以在systemctl中使用簡寫方式。
- 如果無擴(kuò)展名,systemctl 默認(rèn)把擴(kuò)展名當(dāng)作 .service。例如 netcfg 和 netcfg.service 是等價的。
- 掛載點(diǎn)會自動轉(zhuǎn)化為相應(yīng)的 .mount 單元。例如 /home 等價于 home.mount。
- 設(shè)備會自動轉(zhuǎn)化為相應(yīng)的 .device 單元,所以 /dev/sda2 等價于 dev-sda2.device。
注: 有一些單元的名稱包含一個 @ 標(biāo)記, (e.g. name@string.service): 這意味著它是模板單元 name@.service 的一個 實(shí)例。 string 被稱作實(shí)例標(biāo)識符, 在 systemctl 調(diào)用模板單元時,會將其當(dāng)作一個參數(shù)傳給模板單元,模板單元會使用這個傳入的參數(shù)代替模板中的 %I 指示符。 在實(shí)例化之前,systemd 會先檢查 name@string.suffix 文件是否存在(如果存在,應(yīng)該就是直接使用這個文件,而不是模板實(shí)例化了)。大多數(shù)情況下,包換 @ 標(biāo)記都意味著這個文件是模板。如果一個模板單元沒有實(shí)例化就調(diào)用,該調(diào)用會返回失敗,因為模板單元中的 %I 指示符沒有被替換。
立即激活單元:
- # systemctl start <單元>
立即停止單元:
- # systemctl stop <單元>
重啟單元:
- # systemctl restart <單元>
命令單元重新讀取配置:
- # systemctl reload <單元>
輸出單元運(yùn)行狀態(tài):
- $ systemctl status <單元>
檢查單元是否配置為自動啟動:
- $ systemctl is-enabled <單元>
開機(jī)自動激活單元:
- # systemctl enable <單元>
注意: 如果服務(wù)沒有Install段落,一般意味著應(yīng)該通過其它服務(wù)自動調(diào)用它們。如果真的需要手動安裝,可以直接連接服務(wù),如下(將foo替換為真實(shí)的服務(wù)名):
- # ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/
取消開機(jī)自動激活單元:
- # systemctl disable <單元>
顯示單元的手冊頁(必須由單元文件提供):
- # systemctl help <單元>
重新載入 systemd,掃描新的或有變動的單元:
- # systemctl daemon-reload
電源管理
安裝 polkit 后才可使用電源管理。
如果你正登錄在一個本地的systemd-logind用戶會話,且當(dāng)前沒有其它活動的會話,那么以下命令無需root權(quán)限即可執(zhí)行。否則(例如,當(dāng)前有另一個用戶登錄在某個tty),systemd 將會自動請求輸入root密碼。
重啟:
- $ systemctl reboot
退出系統(tǒng)并停止電源:
- $ systemctl poweroff
待機(jī):
- $ systemctl suspend
休眠:
- $ systemctl hibernate
混合休眠模式(同時休眠到硬盤并待機(jī)):
- $ systemctl hybrid-sleep
編寫單元文件
systemd單元文件的語法來源于 XDG桌面入口配置文件.desktop文件,最初的源頭則是Microsoft Windows的.ini文件。單元文件可以從兩個地方加載,優(yōu)先級從低到高分別是:
- /usr/lib/systemd/system/: 軟件包安裝的單元
- /etc/systemd/system/: 系統(tǒng)管理員安裝的單元
注意: 當(dāng)systemd運(yùn)行在用戶模式下時,使用的加載路徑是完全不同的。
單元文件的語法,可以參考系統(tǒng)已經(jīng)安裝的單元,也可以參考man systemd.service中的EXAMPLES章節(jié)。
小貼士: 以 # 開頭的注釋可能也能用在 unit-files 中, 但是只能在新行中使用。 不要在 systemd 的參數(shù)后面使用行末注釋, 否則 unit 將會啟動失敗。
處理依賴關(guān)系
使用systemd時,可通過正確編寫單元配置文件來解決其依賴關(guān)系。典型的情況是,單元A要求單元B在A啟動之前運(yùn)行。在此情況下,向單元A配置文件中的 [Unit] 段添加 Requires=B 和 After=B 即可。若此依賴關(guān)系是可選的,可添加 Wants=B 和 After=B。請注意 Wants= 和 Requires= 并不意味著 After=,即如果 After= 選項沒有制定,這兩個單元將被并行啟動。
依賴關(guān)系通常被用在服務(wù)(service)而不是目標(biāo)(target)上。例如, network.target 一般會被某個配置網(wǎng)絡(luò)接口的服務(wù)引入,所以,將自定義的單元排在該服務(wù)之后即可,因為 network.target 已經(jīng)啟動。
服務(wù)類型
編寫自定義的 service 文件時,可以選擇幾種不同的服務(wù)啟動方式。啟動方式可通過配置文件 [Service] 段中的 Type= 參數(shù)進(jìn)行設(shè)置。
- Type=simple(默認(rèn)值):systemd認(rèn)為該服務(wù)將立即啟動。服務(wù)進(jìn)程不會fork。如果該服務(wù)要啟動其他服務(wù),不要使用此類型啟動,除非該服務(wù)是socket激活型。
- Type=forking:systemd認(rèn)為當(dāng)該服務(wù)進(jìn)程fork,且父進(jìn)程退出后服務(wù)啟動成功。對于常規(guī)的守護(hù)進(jìn)程(daemon),除非你確定此啟動方式無法滿足需求,使用此類型啟動即可。使用此啟動類型應(yīng)同時指定 PIDFile=,以便systemd能夠跟蹤服務(wù)的主進(jìn)程。
- Type=oneshot:這一選項適用于只執(zhí)行一項任務(wù)、隨后立即退出的服務(wù)。可能需要同時設(shè)置 RemainAfterExit=yes 使得 systemd 在服務(wù)進(jìn)程退出之后仍然認(rèn)為服務(wù)處于激活狀態(tài)。
- Type=notify:與 Type=simple 相同,但約定服務(wù)會在就緒后向 systemd 發(fā)送一個信號。這一通知的實(shí)現(xiàn)由 libsystemd-daemon.so 提供。
- Type=dbus:若以此方式啟動,當(dāng)指定的 BusName 出現(xiàn)在DBus系統(tǒng)總線上時,systemd認(rèn)為服務(wù)就緒。
- Type=idle: systemd會等待所有任務(wù)(Jobs)處理完成后,才開始執(zhí)行idle類型的單元。除此之外,其他行為和Type=simple 類似。
type的更多解釋可以參考 systemd.service(5)。
修改現(xiàn)存單元文件
要更改由軟件包提供的單元文件,先創(chuàng)建名為 /etc/systemd/system/<單元名>.d/ 的目錄(如 /etc/systemd/system/httpd.service.d/),然后放入 *.conf 文件,其中可以添加或重置參數(shù)。這里設(shè)置的參數(shù)優(yōu)先級高于原來的單元文件。例如,如果想添加一個額外的依賴,創(chuàng)建這么一個文件即可:
- /etc/systemd/system/<unit>.d/customdependency.conf
- [Unit]
- Requires=<新依賴>
- After=<新依賴>
其它舉例,
- /etc/systemd/system/unit.d/customexec.conf
- [Service]
- ExecStartExecStart=
- ExecStart=new command
想知道為什么修改 ExecStart 前必須將其置空
下面是自動重啟服務(wù)的一個例子:
- /etc/systemd/system/unit.d/restart.conf
- [Service]
- Restart=always
- RestartSec=30
然后運(yùn)行以下命令使更改生效:
- # systemctl daemon-reload
- # systemctl restart <單元>
此外,把舊的單元文件從 /usr/lib/systemd/system/ 復(fù)制到 /etc/systemd/system/,然后進(jìn)行修改,也可以達(dá)到同樣效果。在 /etc/systemd/system/ 目錄中的單元文件的優(yōu)先級總是高于 /usr/lib/systemd/system/ 目錄中的同名單元文件。注意,當(dāng) /usr/lib/ 中的單元文件因軟件包升級變更時,/etc/ 中自定義的單元文件不會同步更新。此外,你還得執(zhí)行 systemctl reenable <unit>,手動重新啟用該單元。因此,建議使用前面一種利用 *.conf 的方法。
小貼士: 用 systemd-delta 命令來查看哪些單元文件被覆蓋、哪些被修改。系統(tǒng)維護(hù)的時候需要及時了解哪些單元已經(jīng)有了更新
單元配置文件的 vim 語法高亮支持
可從官方倉庫安裝 vim-systemd 軟件包,使 unit 配置文件在 Vim 下支持語法高亮。
目標(biāo)(target)
啟 動級別(runlevel)是一個舊的概念。現(xiàn)在,systemd 引入了一個和啟動級別功能相似又不同的概念——目標(biāo)(target)。不像數(shù)字表示的啟動級別,每個目標(biāo)都有名字和獨(dú)特的功能,并且能同時啟用多個。一些 目標(biāo)繼承其他目標(biāo)的服務(wù),并啟動新服務(wù)。systemd 提供了一些模仿 sysvinit 啟動級別的目標(biāo),仍可以使用舊的 telinit 啟動級別 命令切換。
獲取當(dāng)前目標(biāo)
不要使用 runlevel 命令了:
- $ systemctl list-units --type=target
創(chuàng)建新目標(biāo)
在 Fedora 中,啟動級別 0、1、3、5、6 都被賦予特定用途,并且都對應(yīng)一個 systemd 的目標(biāo)。然而,沒有什么很好的移植用戶定義的啟動級別(2、4)的方法。要實(shí)現(xiàn)類似功能,可以以原有的啟動級別為基礎(chǔ),創(chuàng)建一個新的目標(biāo) /etc/systemd/system/<新目標(biāo)>(可以參考 /usr/lib/systemd/system/graphical.target),創(chuàng)建 /etc/systemd/system/<新目標(biāo)>.wants 目錄,向其中加入額外服務(wù)的鏈接(指向 /usr/lib/systemd/system/ 中的單元文件)。
目標(biāo)表
| SysV 啟動級別 | Systemd 目標(biāo) | 注釋 |
|---|---|---|
| 0 | runlevel0.target, poweroff.target | 中斷系統(tǒng)(halt) |
| 1, s, single | runlevel1.target, rescue.target | 單用戶模式 |
| 2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用戶自定義啟動級別,通常識別為級別3。 |
| 3 | runlevel3.target, multi-user.target | 多用戶,無圖形界面。用戶可以通過終端或網(wǎng)絡(luò)登錄。 |
| 5 | runlevel5.target, graphical.target | 多用戶,圖形界面。繼承級別3的服務(wù),并啟動圖形界面服務(wù)。 |
| 6 | runlevel6.target, reboot.target | 重啟 |
| emergency | emergency.target | 急救模式(Emergency shell) |
切換啟動級別/目標(biāo)
systemd 中,啟動級別通過“目標(biāo)單元”訪問。通過如下命令切換:
- # systemctl isolate graphical.target
該命令對下次啟動無影響。等價于telinit 3 或 telinit 5。
修改默認(rèn)啟動級別/目標(biāo)
開機(jī)啟動進(jìn)的目標(biāo)是 default.target,默認(rèn)鏈接到 graphical.target (大致相當(dāng)于原來的啟動級別5)。可以通過內(nèi)核參數(shù)更改默認(rèn)啟動級別:
小貼士: 可以省略擴(kuò)展名 .target。
- systemd.unit=multi-user.target (大致相當(dāng)于級別3)
- systemd.unit=rescue.target (大致相當(dāng)于級別1)
另一個方法是修改 default.target。可以通過 systemctl 修改它:
- # systemctl enable multi-user.target
命令執(zhí)行情況由 systemctl 顯示:鏈接 /etc/systemd/system/default.target 被創(chuàng)建,指向新的默認(rèn)啟動級別。該方法當(dāng)且僅當(dāng)目標(biāo)配置文件中有以下內(nèi)容時有效:
- [Install]
- Alias=default.target
目前,multi-user.target、graphical.target 都包含這段內(nèi)容。
臨時文件
/usr/lib/tmpfiles.d/ 和 /etc/tmpfiles.d/ 中的文件描述了 systemd-tmpfiles 如何創(chuàng)建、清理、刪除臨時文件和目錄,這些文件和目錄通常存放在 /run 和 /tmp 中。配置文件名稱為 /etc/tmpfiles.d/<program>.conf。此處的配置能覆蓋 /usr/lib/tmpfiles.d/ 目錄中的同名配置。
臨時文件通常和服務(wù)文件同時提供,以生成守護(hù)進(jìn)程需要的文件和目錄。例如 Samba 服務(wù)需要目錄 /run/samba 存在并設(shè)置正確的權(quán)限位,就象這樣:
- /usr/lib/tmpfiles.d/samba.conf
- D /run/samba 0755 root root
此外,臨時文件還可以用來在開機(jī)時向特定文件寫入某些內(nèi)容。比如,要禁止系統(tǒng)從USB設(shè)備喚醒,利用舊的 /etc/rc.local 可以用 echo USBE > /proc/acpi/wakeup,而現(xiàn)在可以這么做:
- /etc/tmpfiles.d/disable-usb-wake.conf
- w /proc/acpi/wakeup - - - - USBE
詳情參見 man 5 tmpfiles.d。
注意: 該方法不能向 /sys 中的配置文件添加參數(shù),因為 systemd-tmpfiles-setup 有可能在相關(guān)模塊加載前運(yùn)行。這種情況下,需要首先通過 modinfo <模塊名> 確認(rèn)需要的參數(shù),并在 /etc/modprobe.d 下的一個文件中設(shè)置改參數(shù)。另外,還可以使用 udev 規(guī)則,在設(shè)備就緒時設(shè)置相應(yīng)屬性。
定時器
定時器是以 .timer 為后綴的配置文件,記錄由system的里面由時間觸發(fā)的動作, 定時器可以替代 cron 的大部分功能。
日志
systemd提供了自己日志系統(tǒng)(logging system),稱為 journal. 使用 systemd 日志,無需額外安裝日志服務(wù)(syslog)。讀取日志的命令:
- # journalctl
默認(rèn)情況下(當(dāng) Storage= 在文件 /etc/systemd/journald.conf 中被設(shè)置為 auto),日志記錄將被寫入 /var/log/journal/。該目錄是 systemd 軟件包的一部分。若被刪除,systemd 不會自動創(chuàng)建它,直到下次升級軟件包時重建該目錄。如果該目錄缺失,systemd 會將日志記錄寫入 /run/systemd/journal。這意味著,系統(tǒng)重啟后日志將丟失。
Tip: 如果 /var/log/journal/ 位于 btrfs 文件系統(tǒng),應(yīng)該考慮對這個目錄禁用寫入時復(fù)制
過濾輸出
journalctl可以根據(jù)特定字段過濾輸出,例如:
顯示本次啟動后的所有日志:
- # journalctl -b
不過,一般大家更關(guān)心的不是本次啟動后的日志,而是上次啟動時的(例如,剛剛系統(tǒng)崩潰了)。可以使用 -b 參數(shù):
- journalctl -b -0 顯示本次啟動的信息
- journalctl -b -1 顯示上次啟動的信息
- journalctl -b -2 顯示上上次啟動的信息 journalctl -b -2
- Show all messages from date (and optional time):
- # journalctl --since="2012-10-30 18:17:16"
- Show all messages since 20 minutes ago:
- # journalctl --since "20 min ago"
- 顯示最新信息
- # journalctl -f
- 顯示特定程序的所有消息:
- # journalctl /usr/lib/systemd/systemd
- 顯示特定進(jìn)程的所有消息:
- # journalctl _PID=1
- 顯示指定單元的所有消息:
- # journalctl -u netcfg
- Show kernel ring buffer:
- # journalctl -k
- Show auth.log equivalent by filtering on syslog facility:
- # journalctl -f -l SYSLOG_FACILITY=10
詳情參閱man journalctl、man systemd.journal-fields,以及Lennert的這篇博文
日志大小限制
如果按上面的操作保留日志的話,默認(rèn)日志最大限制為所在文件系統(tǒng)容量的 10%,即:如果 /var/log/journal 儲存在 50GiB 的根分區(qū)中,那么日志最多存儲 5GiB 數(shù)據(jù)。可以修改 /etc/systemd/journald.conf 中的 SystemMaxUse 來指定該最大限制。如限制日志最大 50MiB:
- SystemMaxUse=50M
詳情參見 man journald.conf.
配合syslog使用
systemd提供了 socket /run/systemd/journal/syslog,以兼容傳統(tǒng)日志服務(wù)。所有系統(tǒng)信息都會被傳入。要使傳統(tǒng)日志服務(wù)工作,需要讓服務(wù)鏈接該 socket,而非 /dev/log(官方說明)。Arch 軟件倉庫中的 syslog-ng 已經(jīng)包含了需要的配置。
設(shè)置開機(jī)啟動 syslog-ng:
- # systemctl enable syslog-ng
這里有一份很不錯的 journalctl指南。
Forward journald to /dev/tty12
In /etc/systemd/journald.conf enable the following:
- ForwardToConsole=yes
- TTYPath=/dev/tty12
- MaxLevelConsole=info
重啟journald:
- # systemctl restart systemd-journald
疑難解答
關(guān)機(jī)/重啟十分緩慢
如果關(guān)機(jī)特別慢(甚至跟死機(jī)了一樣),很可能是某個拒不退出的服務(wù)在作怪。systemd 會等待一段時間,然后再嘗試殺死它。請閱讀這篇文章,確認(rèn)你是否是該問題受害者。
短時進(jìn)程無日志記錄
若 journalctl -u foounit.service 沒有顯示某個短時進(jìn)程的任何輸出,那么改用 PID 試試。例如,若 systemd-modules-load.service 執(zhí)行失敗,那么先用 systemctl status systemd-modules-load 查詢其 PID(比如是123),然后檢索該 PID 相關(guān)的日志 journalctl -b _PID=123。運(yùn)行時進(jìn)程的日志元數(shù)據(jù)(諸如 _SYSTEMD_UNIT 和 _COMM)被亂序收集在 /proc 目錄。要修復(fù)該問題,必須修改內(nèi)核,使其通過套接字連接來提供上述數(shù)據(jù),該過程類似于 SCM_CREDENTIALS。
診斷啟動問題
使用如下內(nèi)核參數(shù)引導(dǎo): systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
禁止在程序崩潰時轉(zhuǎn)儲內(nèi)存
要使用老的內(nèi)核轉(zhuǎn)儲,創(chuàng)建下面文件:
- /etc/sysctl.d/49-coredump.conf
- kernel.core_pattern = core
- kernel.core_uses_pid = 0
然后運(yùn)行:
- # /usr/lib/systemd/systemd-sysctl
同樣可能需要執(zhí)行"unlimit"設(shè)置文件大小:
- $ ulimit -c unlimited

浙公網(wǎng)安備 33010602011771號