Centos7特性——systemd
Centos7特性——systemd
理解Linux啟動過程
在我們打開Linux電腦的電源后第一個啟動的進程就是init。分配給init進程的PID是1。它是系統其他所有進程的父進程。當一臺Linux電腦啟動后,處理器會先在系統存儲中查找BIOS,之后BIOS會檢測系統資源然后找到第一個引導設備,通常為硬盤,然后會查找硬盤的主引導記錄(MBR),然后加載到內存中并把控制權交給它,以后的啟動過程就由MBR控制。
主引導記錄會初始化引導程序(Linux上有兩個著名的引導程序,GRUB和LILO,80%的Linux系統在用GRUB引導程序),這個時候GRUB或LILO會加載內核模塊。內核會馬上查找/sbin下的“init”程序并執行它。從這里開始init成為了Linux系統的父進程。init讀取的第一個文件是/etc/inittab,通過它init會確定我們Linux操作系統的運行級別。它會從文件/etc/fstab里查找分區表信息然后做相應的掛載。然后init會啟動/etc/init.d里指定的默認啟動級別的所有服務/腳本。所有服務在這里通過init一個一個被初始化。在這個過程里,init每次只啟動一個服務,所有服務/守護進程都在后臺執行并由init來管理。
關機過程差不多是相反的過程,首先init停止所有服務,最后階段會卸載文件系統。
以上提到的啟動過程有一些不足的地方。而用一種更好的方式來替代傳統init的需求已經存在很長時間了。也產生了許多替代方案。其中比較著名的有Upstart,Epoch,Muda和Systemd。而Systemd獲得最多關注并被認為是目前最佳的方案。
理解Systemd
開發Systemd的主要目的就是減少系統引導時間和計算開銷。Systemd(系統管理守護進程),最開始以GNU GPL協議授權開發,現在已轉為使用GNU LGPL協議,它是如今討論最熱烈的引導和服務管理程序。如果你的Linux系統配置為使用Systemd引導程序,它取替傳統的SysV init,啟動過程將交給systemd處理。Systemd的一個核心功能是它同時支持SysV init的后開機啟動腳本。
Systemd引入了并行啟動的概念,它會為每個需要啟動的守護進程建立一個套接字,這些套接字對于使用它們的進程來說是抽象的,這樣它們可以允許不同守護進程之間進行交互。Systemd會創建新進程并為每個進程分配一個控制組(cgroup)。處于不同控制組的進程之間可以通過內核來互相通信。systemd處理開機啟動進程的方式非常漂亮,和傳統基于init的系統比起來優化了太多。讓我們看下Systemd的一些核心功能。
·????????和init比起來引導過程簡化了很多
·????????Systemd支持并發引導過程從而可以更快啟動
·????????通過控制組來追蹤進程,而不是PID
·????????優化了處理引導過程和服務之間依賴的方式
·????????支持系統快照和恢復
·????????監控已啟動的服務;也支持重啟已崩潰服務
·????????包含了systemd-login模塊用于控制用戶登錄
·????????支持加載和卸載組件
·????????低內存使用痕跡以及任務調度能力
·????????記錄事件的Journald模塊和記錄系統日志的syslogd模塊
Systemd同時也清晰地處理了系統關機過程。它在/usr/lib/systemd/目錄下有三個腳本,分別叫systemd-halt.service,systemd-poweroff.service,systemd-reboot.service。這幾個腳本會在用戶選擇關機,重啟或待機時執行。在接收到關機事件時,systemd首先卸載所有文件系統并停止所有內存交換設備,斷開存儲設備,之后停止所有剩下的進程。
systemd基本工具
監視和控制systemd的主要命令是systemctl。該命令可用于查看系統狀態和管理系統及服務。詳見man1 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
使用單元unit
一個單元配置文件可以描述如下內容之一:系統服務(.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 文件,其中可以添加或重置參數。這里設置的參數優先級高于原來的單元文件。例如,如果想添加一個額外的依賴,創建這么一個文件即可:
/etc/systemd/system/<unit>.d/customdependency.conf
[Unit]
Requires=<新依賴>
After=<新依賴>
其它舉例,
/etc/systemd/system/unit.d/customexec.conf
?
[Service]
ExecStartExecStart=
ExecStart=new?command
想知道為什么修改 ExecStart 前必須將其置空
下面是自動重啟服務的一個例子:
/etc/systemd/system/unit.d/restart.conf
?
[Service]
Restart=always
RestartSec=30
然后運行以下命令使更改生效:
#?systemctl?daemon-reload
#?systemctl?restart?<單元>
此外,把舊的單元文件從 /usr/lib/systemd/system/ 復制到/etc/systemd/system/,然后進行修改,也可以達到同樣效果。在/etc/systemd/system/ 目錄中的單元文件的優先級總是高于/usr/lib/systemd/system/ 目錄中的同名單元文件。注意,當 /usr/lib/ 中的單元文件因軟件包升級變更時,/etc/ 中自定義的單元文件不會同步更新。此外,你還得執行 systemctlreenable <unit>,手動重新啟用該單元。因此,建議使用前面一種利用 *.conf 的方法。
小貼士: 用 systemd-delta 命令來查看哪些單元文件被覆蓋、哪些被修改。系統維護的時候需要及時了解哪些單元已經有了更新
單元配置文件的 vim 語法高亮支持
可從官方倉庫安裝 vim-systemd 軟件包,使 unit 配置文件在 Vim 下支持語法高亮。
目標(target)
啟 動級別(runlevel)是一個舊的概念。現在,systemd 引入了一個和啟動級別功能相似又不同的概念——目標(target)。不像數字表示的啟動級別,每個目標都有名字和獨特的功能,并且能同時啟用多個。一些 目標繼承其他目標的服務,并啟動新服務。systemd 提供了一些模仿 sysvinit 啟動級別的目標,仍可以使用舊的 telinit 啟動級別 命令切換。
獲取當前目標
不要使用 runlevel 命令了:
$?systemctl?list-units?--type=target
創建新目標
在 Fedora 中,啟動級別 0、1、3、5、6 都被賦予特定用途,并且都對應一個 systemd 的目標。然而,沒有什么很好的移植用戶定義的啟動級別(2、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 中,啟動級別通過“目標單元”訪問。通過如下命令切換:
#?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 修改它:
#?systemctl?enable?multi-user.target
命令執行情況由 systemctl 顯示:鏈接/etc/systemd/system/default.target 被創建,指向新的默認啟動級別。該方法當且僅當目標配置文件中有以下內容時有效:
[Install]
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 存在并設置正確的權限位,就象這樣:
/usr/lib/tmpfiles.d/samba.conf
D?/run/samba?0755?root?root
此外,臨時文件還可以用來在開機時向特定文件寫入某些內容。比如,要禁止系統從USB設備喚醒,利用舊的 /etc/rc.local 可以用 echo USBE > /proc/acpi/wakeup,而現在可以這么做:
/etc/tmpfiles.d/disable-usb-wake.conf
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)。讀取日志的命令:
#?journalctl
默認情況下(當 Storage= 在文件 /etc/systemd/journald.conf 中被設置為 auto),日志記錄將被寫入 /var/log/journal/。該目錄是 systemd 軟件包的一部分。若被刪除,systemd 不會自動創建它,直到下次升級軟件包時重建該目錄。如果該目錄缺失,systemd 會將日志記錄寫入 /run/systemd/journal。這意味著,系統重啟后日志將丟失。
Tip: 如果 /var/log/journal/ 位于btrfs 文件系統,應該考慮對這個目錄禁用寫入時復制
過濾輸出
journalctl可以根據特定字段過濾輸出,例如:
顯示本次啟動后的所有日志:
#?journalctl?-b
不過,一般大家更關心的不是本次啟動后的日志,而是上次啟動時的(例如,剛剛系統崩潰了)。可以使用 -b 參數:
journalctl -b -0 顯示本次啟動的信息
journalctl -b -1 顯示上次啟動的信息
journalctl -b -2 顯示上上次啟動的信息 journalctl -b -2
Show all messages from date (and optional time):
#?journalctl?--since="2012-10-3018:17:16"
Show all messages since 20 minutes ago:
#?journalctl?--since?"20?min?ago"
顯示最新信息
#?journalctl?-f
顯示特定程序的所有消息:
#?journalctl?/usr/lib/systemd/systemd
顯示特定進程的所有消息:
#?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的這篇博文
日志大小限制
如果按上面的操作保留日志的話,默認日志最大限制為所在文件系統容量的 10%,即:如果 /var/log/journal 儲存在 50GiB 的根分區中,那么日志最多存儲 5GiB 數據。可以修改 /etc/systemd/journald.conf 中的 SystemMaxUse 來指定該最大限制。如限制日志最大 50MiB:
SystemMaxUse=50M
詳情參見 man journald.conf.
配合syslog使用
systemd提供了 socket /run/systemd/journal/syslog,以兼容傳統日志服務。所有系統信息都會被傳入。要使傳統日志服務工作,需要讓服務鏈接該 socket,而非 /dev/log(官方說明)。Arch 軟件倉庫中的 syslog-ng 已經包含了需要的配置。
設置開機啟動 syslog-ng:
#?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.????? ?
3.????? kernel.core_pattern?=?core
4.????? kernel.core_uses_pid?=?0
然后運行:
1.????? #?/usr/lib/systemd/systemd-sysctl
同樣可能需要執行"unlimit"設置文件大小:
1.????? $?ulimit?-c?unlimited
?
轉載于:https://blog.51cto.com/13155479/1968197
總結
以上是生活随笔為你收集整理的Centos7特性——systemd的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS 5.X 开机启动流程
- 下一篇: 2463: [中山市选2009]谁能赢呢