systemd詳解詳解

systemd詳解

CentOS 7 使用systemd替換了SysV。Systemd目的是要取代Unix時代以來一直在使用的init系統,兼容SysV和LSB的啓動腳本,並且夠在進程啓動過程當中更有效地引導加載服務。php

systemd的特性有:html

  • 支持並行化任務
  • 同時採用socket式與D-Bus總線式激活服務;
  • 按需啓動守護進程(daemon);
  • 利用 Linux 的 cgroups 監視進程;
  • 支持快照和系統恢復;
  • 維護掛載點和自動掛載點;
  • 各服務間基於依賴關係進行精密控制。

systemd基本工具

檢視和控制systemd的主要命令是systemctl。該命令可用於查看系統狀態和管理系統及服務。詳見man 1 systemctl。前端

小貼士:linux

  • 在 systemctl 參數中添加 -H <用戶名>@<主機名> 能夠實現對其餘機器的遠程控制。該過程使用ssh連接。
  • systemadm是systemd 的官方圖形前端

分析系統狀態

輸出激活的單元:web

  1. $ systemctl

如下命令等效:shell

  1. $ systemctl list-units

輸出運行失敗的單元:vim

  1. $ systemctl --failed

全部可用的單元文件存放在 /usr/lib/systemd/system/ 和 /etc/systemd/system/ 目錄(後者優先級更高)。查看全部已安裝服務:網絡

  1. $ systemctl list-unit-files

使用單元

一個單元配置文件能夠描述以下內容之一:系統服務(.service)、掛載點(.mount)、sockets(.sockets) 、系統設備(.device)、交換分區(.swap)、文件路徑(.path)、啓動目標(.target)、由 systemd 管理的計時器(.timer)。詳情參閱 man 5 systemd.unit。ssh

使用 systemctl 控制單元時,一般須要使用單元文件的全名,包括擴展名(例如 sshd.service)。可是有些單元能夠在systemctl中使用簡寫方式。socket

  • 若是無擴展名,systemctl 默認把擴展名看成 .service。例如 netcfg 和 netcfg.service 是等價的。
  • 掛載點會自動轉化爲相應的 .mount 單元。例如 /home 等價於 home.mount。
  • 設備會自動轉化爲相應的 .device 單元,因此 /dev/sda2 等價於 dev-sda2.device。

注: 有一些單元的名稱包含一個 @ 標記, (e.g. name@string.service): 這意味着它是模板單元 name@.service 的一個 實例。 string 被稱做實例標識符, 在 systemctl 調用模板單元時,會將其看成一個參數傳給模板單元,模板單元會使用這個傳入的參數代替模板中的 %I 指示符。 在實例化以前,systemd 會先檢查 name@string.suffix 文件是否存在(若是存在,應該就是直接使用這個文件,而不是模板實例化了)。大多數狀況下,包換 @ 標記都意味着這個文件是模板。若是一個模板單元沒有實例化就調用,該調用會返回失敗,由於模板單元中的 %I 指示符沒有被替換。

當即激活單元:

  1. # systemctl start <單元>

當即中止單元:

  1. # systemctl stop <單元>

重啓單元:

  1. # systemctl restart <單元>

命令單元從新讀取配置:

  1. # systemctl reload <單元>

輸出單元運行狀態:

  1. $ systemctl status <單元>

檢查單元是否配置爲自動啓動:

  1. $ systemctl is-enabled <單元>

開機自動激活單元:

  1. # systemctl enable <單元>

注意: 若是服務沒有Install段落,通常意味着應該經過其它服務自動調用它們。若是真的須要手動安裝,能夠直接鏈接服務,以下(將foo替換爲真實的服務名):

  1. # ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/

取消開機自動激活單元:

  1. # systemctl disable <單元>

顯示單元的手冊頁(必須由單元文件提供):

  1. # systemctl help <單元>

從新載入 systemd,掃描新的或有變更的單元:

  1. # systemctl daemon-reload

電源管理

安裝 polkit 後纔可以使用電源管理。

若是你正登陸在一個本地的systemd-logind用戶會話,且當前沒有其它活動的會話,那麼如下命令無需root權限便可執行。不然(例如,當前有另外一個用戶登陸在某個tty),systemd 將會自動請求輸入root密碼。

重啓:

  1. $ systemctl reboot

退出系統並中止電源:

  1. $ systemctl poweroff

待機:

  1. $ systemctl suspend

休眠:

  1. $ systemctl hibernate

混合休眠模式(同時休眠到硬盤並待機):

  1. $ systemctl hybrid-sleep

編寫單元文件

systemd單元文件的語法來源於 XDG桌面入口配置文件.desktop文件,最初的源頭則是Microsoft Windows的.ini文件。單元文件能夠從兩個地方加載,優先級從低到高分別是:

  • /usr/lib/systemd/system/: 軟件包安裝的單元
  • /etc/systemd/system/: 系統管理員安裝的單元

注意: 當systemd運行在用戶模式下時,使用的加載路徑是徹底不一樣的。

單元文件的語法,能夠參考系統已經安裝的單元,也能夠參考man systemd.service中的EXAMPLES章節

小貼士: 以 # 開頭的註釋可能也能用在 unit-files 中, 可是隻能在新行中使用。 不要在 systemd 的參數後面使用行末註釋, 不然 unit 將會啓動失敗。

處理依賴關係

使用systemd時,可經過正確編寫單元配置文件來解決其依賴關係。典型的狀況是,單元A要求單元B在A啓動以前運行。在此狀況下,向單元A配置文件中的 [Unit] 段添加 Requires=B 和 After=B 便可。若此依賴關係是可選的,可添加 Wants=B 和 After=B。請注意 Wants= 和 Requires= 並不意味着 After=,即若是 After= 選項沒有制定,這兩個單元將被並行啓動。

依賴關係一般被用在服務(service)而不是目標(target)上。例如, network.target 通常會被某個配置網絡接口的服務引入,因此,將自定義的單元排在該服務以後便可,由於 network.target 已經啓動。

服務類型

編寫自定義的 service 文件時,能夠選擇幾種不一樣的服務啓動方式。啓動方式可經過配置文件 [Service] 段中的 Type= 參數進行設置。

  • Type=simple(默認值):systemd認爲該服務將當即啓動。服務進程不會fork。若是該服務要啓動其餘服務,不要使用此類型啓動,除非該服務是socket激活型。
  • Type=forking:systemd認爲當該服務進程fork,且父進程退出後服務啓動成功。對於常規的守護進程(daemon),除非你肯定此啓動方式沒法知足需求,使用此類型啓動便可。使用此啓動類型應同時指定 PIDFile=,以便systemd可以跟蹤服務的主進程。
  • Type=oneshot:這一選項適用於只執行一項任務、隨後當即退出的服務。可能須要同時設置 RemainAfterExit=yes 使得 systemd 在服務進程退出以後仍然認爲服務處於激活狀態。
  • Type=notify:與 Type=simple 相同,但約定服務會在就緒後向 systemd 發送一個信號。這一通知的實現由 libsystemd-daemon.so 提供。
  • Type=dbus:若以此方式啓動,當指定的 BusName 出如今DBus系統總線上時,systemd認爲服務就緒。
  • Type=idle: systemd會等待全部任務(Jobs)處理完成後,纔開始執行idle類型的單元。除此以外,其餘行爲和Type=simple 相似。

type的更多解釋能夠參考 systemd.service(5)

修改現存單元文件

要更改由軟件包提供的單元文件,先建立名爲 /etc/systemd/system/<單元名>.d/ 的目錄(如 /etc/systemd/system/httpd.service.d/),而後放入 *.conf 文件,其中能夠添加或重置參數。這裏設置的參數優先級高於原來的單元文件。例如,若是想添加一個額外的依賴,建立這麼一個文件便可:

  1. /etc/systemd/system/<unit>.d/customdependency.conf
  2. [Unit]
  3. Requires=<新依賴>
  4. After=<新依賴>

其它舉例,

  1. /etc/systemd/system/unit.d/customexec.conf
  2. [Service]
  3. ExecStartExecStart=
  4. ExecStart=new command

想知道爲何修改 ExecStart 前必須將其置空

下面是自動重啓服務的一個例子:

  1. /etc/systemd/system/unit.d/restart.conf
  2. [Service]
  3. Restart=always
  4. RestartSec=30

而後運行如下命令使更改生效:

  1. # systemctl daemon-reload
  2. # systemctl restart <單元>

此外,把舊的單元文件從 /usr/lib/systemd/system/ 複製到 /etc/systemd/system/,而後進行修改,也能夠達到一樣效果。在 /etc/systemd/system/ 目錄中的單元文件的優先級老是高於 /usr/lib/systemd/system/ 目錄中的同名單元文件。注意,當 /usr/lib/ 中的單元文件因軟件包升級變動時,/etc/ 中自定義的單元文件不會同步更新。此外,你還得執行 systemctl reenable <unit>,手動從新啓用該單元。所以,建議使用前面一種利用 *.conf 的方法。

小貼士: 用 systemd-delta 命令來查看哪些單元文件被覆蓋、哪些被修改。系統維護的時候須要及時瞭解哪些單元已經有了更新

單元配置文件的 vim 語法高亮支持

可從官方倉庫安裝 vim-systemd 軟件包,使 unit 配置文件在 Vim 下支持語法高亮。

目標(target)

啓 動級別(runlevel)是一箇舊的概念。如今,systemd 引入了一個和啓動級別功能類似又不一樣的概念——目標(target)。不像數字表示的啓動級別,每一個目標都有名字和獨特的功能,而且能同時啓用多個。一些 目標繼承其餘目標的服務,並啓動新服務。systemd 提供了一些模仿 sysvinit 啓動級別的目標,仍可使用舊的 telinit 啓動級別 命令切換。
獲取當前目標

不要使用 runlevel 命令了:

  1. $ systemctl list-units --type=target

建立新目標

在 Fedora 中,啓動級別 0、一、三、五、6 都被賦予特定用途,而且都對應一個 systemd 的目標。然而,沒有什麼很好的移植用戶定義的啓動級別(二、4)的方法。要實現相似功能,能夠以原有的啓動級別爲基礎,建立一個新的目標 /etc/systemd/system/<新目標>(能夠參考 /usr/lib/systemd/system/graphical.target),建立 /etc/systemd/system/<新目標>.wants 目錄,向其中加入額外服務的連接(指向 /usr/lib/systemd/system/ 中的單元文件)。

目標表

SysV 啓動級別 Systemd 目標 註釋
0 runlevel0.target, poweroff.target 中斷系統(halt)
1, s, single runlevel1.target, rescue.target 單用戶模式
2, 4 runlevel2.target, runlevel4.target, multi-user.target 用戶自定義啓動級別,一般識別爲級別3。
3 runlevel3.target, multi-user.target 多用戶,無圖形界面。用戶能夠經過終端或網絡登陸。
5 runlevel5.target, graphical.target 多用戶,圖形界面。繼承級別3的服務,並啓動圖形界面服務。
6 runlevel6.target, reboot.target 重啓
emergency emergency.target 急救模式(Emergency shell)

切換啓動級別/目標

systemd 中,啓動級別經過「目標單元」訪問。經過以下命令切換:

  1. # systemctl isolate graphical.target

該命令對下次啓動無影響。等價於telinit 3 或 telinit 5。

修改默認啓動級別/目標

開機啓動進的目標是 default.target,默認連接到 graphical.target (大體至關於原來的啓動級別5)。能夠經過內核參數更改默認啓動級別:

小貼士: 能夠省略擴展名 .target。

  •  systemd.unit=multi-user.target (大體至關於級別3)
  •  systemd.unit=rescue.target (大體至關於級別1)

另外一個方法是修改 default.target。能夠經過 systemctl 修改它:

  1. # systemctl enable multi-user.target

命令執行狀況由 systemctl 顯示:連接 /etc/systemd/system/default.target 被建立,指向新的默認啓動級別。該方法當且僅當目標配置文件中有如下內容時有效:

  1. [Install]
  2. Alias=default.target

目前,multi-user.target、graphical.target 都包含這段內容。

臨時文件

/usr/lib/tmpfiles.d/ 和 /etc/tmpfiles.d/ 中的文件描述了 systemd-tmpfiles 如何建立、清理、刪除臨時文件和目錄,這些文件和目錄一般存放在 /run 和 /tmp 中。配置文件名稱爲 /etc/tmpfiles.d/<program>.conf。此處的配置能覆蓋 /usr/lib/tmpfiles.d/ 目錄中的同名配置。

臨時文件一般和服務文件同時提供,以生成守護進程須要的文件和目錄。例如 Samba 服務須要目錄 /run/samba 存在並設置正確的權限位,就象這樣:

  1. /usr/lib/tmpfiles.d/samba.conf
  2. D /run/samba 0755 root root

此外,臨時文件還能夠用來在開機時向特定文件寫入某些內容。好比,要禁止系統從USB設備喚醒,利用舊的 /etc/rc.local 能夠用 echo USBE > /proc/acpi/wakeup,而如今能夠這麼作:

  1. /etc/tmpfiles.d/disable-usb-wake.conf
  2. w /proc/acpi/wakeup - - - - USBE

詳情參見 man 5 tmpfiles.d。

注意: 該方法不能向 /sys 中的配置文件添加參數,由於 systemd-tmpfiles-setup 有可能在相關模塊加載前運行。這種狀況下,須要首先經過 modinfo <模塊名> 確認須要的參數,並在 /etc/modprobe.d 下的一個文件中設置改參數。另外,還可使用 udev 規則,在設備就緒時設置相應屬性。

定時器

定時器是以 .timer 爲後綴的配置文件,記錄由system的裏面由時間觸發的動做, 定時器能夠替代 cron 的大部分功能。

日誌

systemd提供了本身日誌系統(logging system),稱爲 journal. 使用 systemd 日誌,無需額外安裝日誌服務(syslog)。讀取日誌的命令:

  1. # journalctl

默認狀況下(當 Storage= 在文件 /etc/systemd/journald.conf 中被設置爲 auto),日誌記錄將被寫入 /var/log/journal/。該目錄是 systemd 軟件包的一部分。若被刪除,systemd 不會自動建立它,直到下次升級軟件包時重建該目錄。若是該目錄缺失,systemd 會將日誌記錄寫入 /run/systemd/journal。這意味着,系統重啓後日志將丟失。

Tip: 若是 /var/log/journal/ 位於 btrfs 文件系統,應該考慮對這個目錄禁用寫入時複製

過濾輸出

journalctl能夠根據特定字段過濾輸出,例如:

顯示本次啓動後的全部日誌:

  1. # journalctl -b

不過,通常你們更關心的不是本次啓動後的日誌,而是上次啓動時的(例如,剛剛系統崩潰了)。可使用 -b 參數:

  • journalctl -b -0 顯示本次啓動的信息
  • journalctl -b -1 顯示上次啓動的信息
  • journalctl -b -2 顯示上上次啓動的信息 journalctl -b -2
  • Show all messages from date (and optional time):
  1. # journalctl --since="2012-10-30 18:17:16"
  • Show all messages since 20 minutes ago:
  1. # journalctl --since "20 min ago"
  • 顯示最新信息
  1. # journalctl -f
  • 顯示特定程序的全部消息:
  1. # journalctl /usr/lib/systemd/systemd
  • 顯示特定進程的全部消息:
  1. # journalctl _PID=1
  • 顯示指定單元的全部消息:
  1. # journalctl -u netcfg
  • Show kernel ring buffer:
  1. # journalctl -k
  • Show auth.log equivalent by filtering on syslog facility:
  1. # journalctl -f -l SYSLOG_FACILITY=10

詳情參閱man journalctl、man systemd.journal-fields,以及Lennert的這篇博文

日誌大小限制

若是按上面的操做保留日誌的話,默認日誌最大限制爲所在文件系統容量的 10%,即:若是 /var/log/journal 儲存在 50GiB 的根分區中,那麼日誌最多存儲 5GiB 數據。能夠修改 /etc/systemd/journald.conf 中的 SystemMaxUse 來指定該最大限制。如限制日誌最大 50MiB:

  1. SystemMaxUse=50M

詳情參見 man journald.conf.

配合syslog使用

systemd提供了 socket /run/systemd/journal/syslog,以兼容傳統日誌服務。全部系統信息都會被傳入。要使傳統日誌服務工做,須要讓服務連接該 socket,而非 /dev/log(官方說明)。Arch 軟件倉庫中的 syslog-ng 已經包含了須要的配置。

設置開機啓動 syslog-ng:

  1. # systemctl enable syslog-ng

這裏有一份很不錯的 journalctl指南。

Forward journald to /dev/tty12

In /etc/systemd/journald.conf enable the following:

  1. ForwardToConsole=yes
  2. TTYPath=/dev/tty12
  3. MaxLevelConsole=info

重啓journald:

  1. # systemctl restart systemd-journald

疑難解答

關機/重啓十分緩慢

若是關機特別慢(甚至跟死機了同樣),極可能是某個拒不退出的服務在做怪。systemd 會等待一段時間,而後再嘗試殺死它。請閱讀這篇文章,確認你是不是該問題受害者。

短時進程無日誌記錄

若 journalctl -u foounit.service 沒有顯示某個短時進程的任何輸出,那麼改用 PID 試試。例如,若 systemd-modules-load.service 執行失敗,那麼先用 systemctl status systemd-modules-load 查詢其 PID(好比是123),而後檢索該 PID 相關的日誌 journalctl -b _PID=123。運行時進程的日誌元數據(諸如 _SYSTEMD_UNIT 和 _COMM)被亂序收集在 /proc 目錄。要修復該問題,必須修改內核,使其經過套接字鏈接來提供上述數據,該過程相似於 SCM_CREDENTIALS。

診斷啓動問題

使用以下內核參數引導: systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M

禁止在程序崩潰時轉儲內存

要使用老的內核轉儲,建立下面文件:

  1. /etc/sysctl.d/49-coredump.conf
  2. kernel.core_pattern = core
  3. kernel.core_uses_pid = 0

而後運行:

  1. # /usr/lib/systemd/systemd-sysctl

一樣可能須要執行"unlimit"設置文件大小:

  1. $ ulimit -c unlimited
Sun Jul 20 23:00:16 CST 2014

systemd詳解

CentOS 7 使用systemd替換了SysV。Systemd目的是要取代Unix時代以來一直在使用的init系統,兼容SysV和LSB的啓動腳本,並且夠在進程啓動過程當中更有效地引導加載服務。

systemd的特性有:

  • 支持並行化任務
  • 同時採用socket式與D-Bus總線式激活服務;
  • 按需啓動守護進程(daemon);
  • 利用 Linux 的 cgroups 監視進程;
  • 支持快照和系統恢復;
  • 維護掛載點和自動掛載點;
  • 各服務間基於依賴關係進行精密控制。

systemd基本工具

檢視和控制systemd的主要命令是systemctl。該命令可用於查看系統狀態和管理系統及服務。詳見man 1 systemctl

小貼士:

  • 在 systemctl 參數中添加 -H <用戶名>@<主機名> 能夠實現對其餘機器的遠程控制。該過程使用ssh連接。
  • systemadm是systemd 的官方圖形前端

分析系統狀態

輸出激活的單元:

  1. $ systemctl

如下命令等效:

  1. $ systemctl list-units

輸出運行失敗的單元:

  1. $ systemctl --failed

全部可用的單元文件存放在 /usr/lib/systemd/system/ 和 /etc/systemd/system/ 目錄(後者優先級更高)。查看全部已安裝服務:

  1. $ systemctl list-unit-files

使用單元

一個單元配置文件能夠描述以下內容之一:系統服務(.service)、掛載點(.mount)、sockets(.sockets) 、系統設備(.device)、交換分區(.swap)、文件路徑(.path)、啓動目標(.target)、由 systemd 管理的計時器(.timer)。詳情參閱 man 5 systemd.unit。

使用 systemctl 控制單元時,一般須要使用單元文件的全名,包括擴展名(例如 sshd.service)。可是有些單元能夠在systemctl中使用簡寫方式。

  • 若是無擴展名,systemctl 默認把擴展名看成 .service。例如 netcfg 和 netcfg.service 是等價的。
  • 掛載點會自動轉化爲相應的 .mount 單元。例如 /home 等價於 home.mount。
  • 設備會自動轉化爲相應的 .device 單元,因此 /dev/sda2 等價於 dev-sda2.device。

注: 有一些單元的名稱包含一個 @ 標記, (e.g. name@string.service): 這意味着它是模板單元 name@.service 的一個 實例。 string 被稱做實例標識符, 在 systemctl 調用模板單元時,會將其看成一個參數傳給模板單元,模板單元會使用這個傳入的參數代替模板中的 %I 指示符。 在實例化以前,systemd 會先檢查 name@string.suffix 文件是否存在(若是存在,應該就是直接使用這個文件,而不是模板實例化了)。大多數狀況下,包換 @ 標記都意味着這個文件是模板。若是一個模板單元沒有實例化就調用,該調用會返回失敗,由於模板單元中的 %I 指示符沒有被替換。

當即激活單元:

  1. # systemctl start <單元>

當即中止單元:

  1. # systemctl stop <單元>

重啓單元:

  1. # systemctl restart <單元>

命令單元從新讀取配置:

  1. # systemctl reload <單元>

輸出單元運行狀態:

  1. $ systemctl status <單元>

檢查單元是否配置爲自動啓動:

  1. $ systemctl is-enabled <單元>

開機自動激活單元:

  1. # systemctl enable <單元>

注意: 若是服務沒有Install段落,通常意味着應該經過其它服務自動調用它們。若是真的須要手動安裝,能夠直接鏈接服務,以下(將foo替換爲真實的服務名):

  1. # ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/

取消開機自動激活單元:

  1. # systemctl disable <單元>

顯示單元的手冊頁(必須由單元文件提供):

  1. # systemctl help <單元>

從新載入 systemd,掃描新的或有變更的單元:

  1. # systemctl daemon-reload

電源管理

安裝 polkit 後纔可以使用電源管理。

若是你正登陸在一個本地的systemd-logind用戶會話,且當前沒有其它活動的會話,那麼如下命令無需root權限便可執行。不然(例如,當前有另外一個用戶登陸在某個tty),systemd 將會自動請求輸入root密碼。

重啓:

  1. $ systemctl reboot

退出系統並中止電源:

  1. $ systemctl poweroff

待機:

  1. $ systemctl suspend

休眠:

  1. $ systemctl hibernate

混合休眠模式(同時休眠到硬盤並待機):

  1. $ systemctl hybrid-sleep

編寫單元文件

systemd單元文件的語法來源於 XDG桌面入口配置文件.desktop文件,最初的源頭則是Microsoft Windows的.ini文件。單元文件能夠從兩個地方加載,優先級從低到高分別是:

  • /usr/lib/systemd/system/: 軟件包安裝的單元
  • /etc/systemd/system/: 系統管理員安裝的單元

注意: 當systemd運行在用戶模式下時,使用的加載路徑是徹底不一樣的。

單元文件的語法,能夠參考系統已經安裝的單元,也能夠參考man systemd.service中的EXAMPLES章節

小貼士: 以 # 開頭的註釋可能也能用在 unit-files 中, 可是隻能在新行中使用。 不要在 systemd 的參數後面使用行末註釋, 不然 unit 將會啓動失敗。

處理依賴關係

使用systemd時,可經過正確編寫單元配置文件來解決其依賴關係。典型的狀況是,單元A要求單元B在A啓動以前運行。在此狀況下,向單元A配置文件中的 [Unit] 段添加 Requires=B 和 After=B 便可。若此依賴關係是可選的,可添加 Wants=B 和 After=B。請注意 Wants= 和 Requires= 並不意味着 After=,即若是 After= 選項沒有制定,這兩個單元將被並行啓動。

依賴關係一般被用在服務(service)而不是目標(target)上。例如, network.target 通常會被某個配置網絡接口的服務引入,因此,將自定義的單元排在該服務以後便可,由於 network.target 已經啓動。

服務類型

編寫自定義的 service 文件時,能夠選擇幾種不一樣的服務啓動方式。啓動方式可經過配置文件 [Service] 段中的 Type= 參數進行設置。

  • Type=simple(默認值):systemd認爲該服務將當即啓動。服務進程不會fork。若是該服務要啓動其餘服務,不要使用此類型啓動,除非該服務是socket激活型。
  • Type=forking:systemd認爲當該服務進程fork,且父進程退出後服務啓動成功。對於常規的守護進程(daemon),除非你肯定此啓動方式沒法知足需求,使用此類型啓動便可。使用此啓動類型應同時指定 PIDFile=,以便systemd可以跟蹤服務的主進程。
  • Type=oneshot:這一選項適用於只執行一項任務、隨後當即退出的服務。可能須要同時設置 RemainAfterExit=yes 使得 systemd 在服務進程退出以後仍然認爲服務處於激活狀態。
  • Type=notify:與 Type=simple 相同,但約定服務會在就緒後向 systemd 發送一個信號。這一通知的實現由 libsystemd-daemon.so 提供。
  • Type=dbus:若以此方式啓動,當指定的 BusName 出如今DBus系統總線上時,systemd認爲服務就緒。
  • Type=idle: systemd會等待全部任務(Jobs)處理完成後,纔開始執行idle類型的單元。除此以外,其餘行爲和Type=simple 相似。

type的更多解釋能夠參考 systemd.service(5)

修改現存單元文件

要更改由軟件包提供的單元文件,先建立名爲 /etc/systemd/system/<單元名>.d/ 的目錄(如 /etc/systemd/system/httpd.service.d/),而後放入 *.conf 文件,其中能夠添加或重置參數。這裏設置的參數優先級高於原來的單元文件。例如,若是想添加一個額外的依賴,建立這麼一個文件便可:

  1. /etc/systemd/system/<unit>.d/customdependency.conf
  2. [Unit]
  3. Requires=<新依賴>
  4. After=<新依賴>

其它舉例,

  1. /etc/systemd/system/unit.d/customexec.conf
  2. [Service]
  3. ExecStartExecStart=
  4. ExecStart=new command

想知道爲何修改 ExecStart 前必須將其置空

下面是自動重啓服務的一個例子:

  1. /etc/systemd/system/unit.d/restart.conf
  2. [Service]
  3. Restart=always
  4. RestartSec=30

而後運行如下命令使更改生效:

  1. # systemctl daemon-reload
  2. # systemctl restart <單元>

此外,把舊的單元文件從 /usr/lib/systemd/system/ 複製到 /etc/systemd/system/,而後進行修改,也能夠達到一樣效果。在 /etc/systemd/system/ 目錄中的單元文件的優先級老是高於 /usr/lib/systemd/system/ 目錄中的同名單元文件。注意,當 /usr/lib/ 中的單元文件因軟件包升級變動時,/etc/ 中自定義的單元文件不會同步更新。此外,你還得執行 systemctl reenable <unit>,手動從新啓用該單元。所以,建議使用前面一種利用 *.conf 的方法。

小貼士: 用 systemd-delta 命令來查看哪些單元文件被覆蓋、哪些被修改。系統維護的時候須要及時瞭解哪些單元已經有了更新

單元配置文件的 vim 語法高亮支持

可從官方倉庫安裝 vim-systemd 軟件包,使 unit 配置文件在 Vim 下支持語法高亮。

目標(target)

啓 動級別(runlevel)是一箇舊的概念。如今,systemd 引入了一個和啓動級別功能類似又不一樣的概念——目標(target)。不像數字表示的啓動級別,每一個目標都有名字和獨特的功能,而且能同時啓用多個。一些 目標繼承其餘目標的服務,並啓動新服務。systemd 提供了一些模仿 sysvinit 啓動級別的目標,仍可使用舊的 telinit 啓動級別 命令切換。
獲取當前目標

不要使用 runlevel 命令了:

  1. $ systemctl list-units --type=target

建立新目標

在 Fedora 中,啓動級別 0、一、三、五、6 都被賦予特定用途,而且都對應一個 systemd 的目標。然而,沒有什麼很好的移植用戶定義的啓動級別(二、4)的方法。要實現相似功能,能夠以原有的啓動級別爲基礎,建立一個新的目標 /etc/systemd/system/<新目標>(能夠參考 /usr/lib/systemd/system/graphical.target),建立 /etc/systemd/system/<新目標>.wants 目錄,向其中加入額外服務的連接(指向 /usr/lib/systemd/system/ 中的單元文件)。

目標表

SysV 啓動級別 Systemd 目標 註釋
0 runlevel0.target, poweroff.target 中斷系統(halt)
1, s, single runlevel1.target, rescue.target 單用戶模式
2, 4 runlevel2.target, runlevel4.target, multi-user.target 用戶自定義啓動級別,一般識別爲級別3。
3 runlevel3.target, multi-user.target 多用戶,無圖形界面。用戶能夠經過終端或網絡登陸。
5 runlevel5.target, graphical.target 多用戶,圖形界面。繼承級別3的服務,並啓動圖形界面服務。
6 runlevel6.target, reboot.target 重啓
emergency emergency.target 急救模式(Emergency shell)

切換啓動級別/目標

systemd 中,啓動級別經過「目標單元」訪問。經過以下命令切換:

  1. # systemctl isolate graphical.target

該命令對下次啓動無影響。等價於telinit 3 或 telinit 5。

修改默認啓動級別/目標

開機啓動進的目標是 default.target,默認連接到 graphical.target (大體至關於原來的啓動級別5)。能夠經過內核參數更改默認啓動級別:

小貼士: 能夠省略擴展名 .target。

  •  systemd.unit=multi-user.target (大體至關於級別3)
  •  systemd.unit=rescue.target (大體至關於級別1)

另外一個方法是修改 default.target。能夠經過 systemctl 修改它:

  1. # systemctl enable multi-user.target

命令執行狀況由 systemctl 顯示:連接 /etc/systemd/system/default.target 被建立,指向新的默認啓動級別。該方法當且僅當目標配置文件中有如下內容時有效:

  1. [Install]
  2. Alias=default.target

目前,multi-user.target、graphical.target 都包含這段內容。

臨時文件

/usr/lib/tmpfiles.d/ 和 /etc/tmpfiles.d/ 中的文件描述了 systemd-tmpfiles 如何建立、清理、刪除臨時文件和目錄,這些文件和目錄一般存放在 /run 和 /tmp 中。配置文件名稱爲 /etc/tmpfiles.d/<program>.conf。此處的配置能覆蓋 /usr/lib/tmpfiles.d/ 目錄中的同名配置。

臨時文件一般和服務文件同時提供,以生成守護進程須要的文件和目錄。例如 Samba 服務須要目錄 /run/samba 存在並設置正確的權限位,就象這樣:

  1. /usr/lib/tmpfiles.d/samba.conf
  2. D /run/samba 0755 root root

此外,臨時文件還能夠用來在開機時向特定文件寫入某些內容。好比,要禁止系統從USB設備喚醒,利用舊的 /etc/rc.local 能夠用 echo USBE > /proc/acpi/wakeup,而如今能夠這麼作:

  1. /etc/tmpfiles.d/disable-usb-wake.conf
  2. w /proc/acpi/wakeup - - - - USBE

詳情參見 man 5 tmpfiles.d。

注意: 該方法不能向 /sys 中的配置文件添加參數,由於 systemd-tmpfiles-setup 有可能在相關模塊加載前運行。這種狀況下,須要首先經過 modinfo <模塊名> 確認須要的參數,並在 /etc/modprobe.d 下的一個文件中設置改參數。另外,還可使用 udev 規則,在設備就緒時設置相應屬性。

定時器

定時器是以 .timer 爲後綴的配置文件,記錄由system的裏面由時間觸發的動做, 定時器能夠替代 cron 的大部分功能。

日誌

systemd提供了本身日誌系統(logging system),稱爲 journal. 使用 systemd 日誌,無需額外安裝日誌服務(syslog)。讀取日誌的命令:

  1. # journalctl

默認狀況下(當 Storage= 在文件 /etc/systemd/journald.conf 中被設置爲 auto),日誌記錄將被寫入 /var/log/journal/。該目錄是 systemd 軟件包的一部分。若被刪除,systemd 不會自動建立它,直到下次升級軟件包時重建該目錄。若是該目錄缺失,systemd 會將日誌記錄寫入 /run/systemd/journal。這意味着,系統重啓後日志將丟失。

Tip: 若是 /var/log/journal/ 位於 btrfs 文件系統,應該考慮對這個目錄禁用寫入時複製

過濾輸出

journalctl能夠根據特定字段過濾輸出,例如:

顯示本次啓動後的全部日誌:

  1. # journalctl -b

不過,通常你們更關心的不是本次啓動後的日誌,而是上次啓動時的(例如,剛剛系統崩潰了)。可使用 -b 參數:

  • journalctl -b -0 顯示本次啓動的信息
  • journalctl -b -1 顯示上次啓動的信息
  • journalctl -b -2 顯示上上次啓動的信息 journalctl -b -2
  • Show all messages from date (and optional time):
  1. # journalctl --since="2012-10-30 18:17:16"
  • Show all messages since 20 minutes ago:
  1. # journalctl --since "20 min ago"
  • 顯示最新信息
  1. # journalctl -f
  • 顯示特定程序的全部消息:
  1. # journalctl /usr/lib/systemd/systemd
  • 顯示特定進程的全部消息:
  1. # journalctl _PID=1
  • 顯示指定單元的全部消息:
  1. # journalctl -u netcfg
  • Show kernel ring buffer:
  1. # journalctl -k
  • Show auth.log equivalent by filtering on syslog facility:
  1. # journalctl -f -l SYSLOG_FACILITY=10

詳情參閱man journalctl、man systemd.journal-fields,以及Lennert的這篇博文

日誌大小限制

若是按上面的操做保留日誌的話,默認日誌最大限制爲所在文件系統容量的 10%,即:若是 /var/log/journal 儲存在 50GiB 的根分區中,那麼日誌最多存儲 5GiB 數據。能夠修改 /etc/systemd/journald.conf 中的 SystemMaxUse 來指定該最大限制。如限制日誌最大 50MiB:

  1. SystemMaxUse=50M

詳情參見 man journald.conf.

配合syslog使用

systemd提供了 socket /run/systemd/journal/syslog,以兼容傳統日誌服務。全部系統信息都會被傳入。要使傳統日誌服務工做,須要讓服務連接該 socket,而非 /dev/log(官方說明)。Arch 軟件倉庫中的 syslog-ng 已經包含了須要的配置。

設置開機啓動 syslog-ng:

  1. # systemctl enable syslog-ng

這裏有一份很不錯的 journalctl指南。

Forward journald to /dev/tty12

In /etc/systemd/journald.conf enable the following:

  1. ForwardToConsole=yes
  2. TTYPath=/dev/tty12
  3. MaxLevelConsole=info

重啓journald:

  1. # systemctl restart systemd-journald

疑難解答

關機/重啓十分緩慢

若是關機特別慢(甚至跟死機了同樣),極可能是某個拒不退出的服務在做怪。systemd 會等待一段時間,而後再嘗試殺死它。請閱讀這篇文章,確認你是不是該問題受害者。

短時進程無日誌記錄

若 journalctl -u foounit.service 沒有顯示某個短時進程的任何輸出,那麼改用 PID 試試。例如,若 systemd-modules-load.service 執行失敗,那麼先用 systemctl status systemd-modules-load 查詢其 PID(好比是123),而後檢索該 PID 相關的日誌 journalctl -b _PID=123。運行時進程的日誌元數據(諸如 _SYSTEMD_UNIT 和 _COMM)被亂序收集在 /proc 目錄。要修復該問題,必須修改內核,使其經過套接字鏈接來提供上述數據,該過程相似於 SCM_CREDENTIALS。

診斷啓動問題

使用以下內核參數引導: systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M

禁止在程序崩潰時轉儲內存

要使用老的內核轉儲,建立下面文件:

  1. /etc/sysctl.d/49-coredump.conf
  2. kernel.core_pattern = core
  3. kernel.core_uses_pid = 0

而後運行:

  1. # /usr/lib/systemd/systemd-sysctl

一樣可能須要執行"unlimit"設置文件大小:

  1. $ ulimit -c unlimited
Sun Jul 20 23:00:16 CST 2014
相關文章
相關標籤/搜索