CentOS 7 systemd管理
CentOS系統啓動流程:
POST --> Boot Sequence --> Bootloader --> kernel + initramfs(initrd) --> rootfs --> /sbin/init
innit程序:
CentOS 5:SysV init
CetnOS 6: Upstart
CentOS 7 : Systemd
Systemd新特性:
系統Sys V init和LSB init scripts兼容
系統引導時實現服務並行啓動;採用socket / D-Bus activation等技術啓動服務;爲了減少系統啓動時間,systemd的目標是:儘可能啓動更少的進程;儘可能將更多的進程並行啓動;
按需激活進程;Systemd可以提供按需啓動的能力,只有在某個服務被真正請求的時候才啓動它。當該服務結束,systemd可以關閉它,等待下次需要時再次啓動它。
能夠對系統進行快照和恢復;
啓動掛載點和自動掛載點的管理:
Systemd自助管理系統上的掛載點,以便能夠在系統啓動時自動掛載它們。且兼容/etc/fstab文件;
實現事務依賴關係管理:
systemd 維護一個"事務一致性"的概念,保證所有相關的服務都可以正常啓動而不會出現互相依賴,以至於死鎖的情況。
基於內生依賴關係定義服務控制邏輯;
system利用Linux內核的特性即CGroup來完成進程跟蹤的任務。當停止服務時,通過查詢CGroup,systemd可以確保找到所有的相關進程,從而乾淨地停止服務;
日誌服務:systemd自帶日誌服務journald,該日誌服務的設計初衷是克服現有的syslog服務的缺點。
System的基本概念
單元的概念:
系統初始化需要做的事情非常多。需要啓動後臺服務,比如啓動 SSHD 服務;需要做配置工作,比如掛載文件系統。這個過程中的每一步都被 systemd 抽象爲一個配置單元,即 unit。可以認爲一個服務是一個配置單元;一個掛載點是一個配置單元;一個交換分區的配置是一個配置單元;等等。systemd 將配置單元歸納爲以下一些不同的類型。然而,systemd 正在快速發展,新功能不斷增加。所以配置單元類型可能在不久的將來繼續增加。
service:代表一個後臺服務進程,比如mysqld。這是常用的一類;
socket:此類配置單元封裝系統和互聯網中的一個套接字。當下,systemd支持流式、數據包和連續包的AF_INET、AF_INET6、AF_UNIX socket。每一個套接字配置單元都有一個相應的服務配置單元 。相應的服務在第一個"連接"進入套接字時就會啓動(例如:nscd.socket 在有新連接後便啓動 nscd.service)。
device :此類配置單元封裝一個存在於 Linux 設備樹中的設備。每一個使用 udev 規則標記的設備都將會在 systemd 中作爲一個設備配置單元出現。
mount :此類配置單元封裝文件系統結構層次中的一個掛載點。Systemd 將對這個掛載點進行監控和管理。比如可以在啓動時自動將其掛載;可以在某些條件下自動卸載。Systemd 會將/etc/fstab 中的條目都轉換爲掛載點,並在開機時處理。
automount :此類配置單元封裝系統結構層次中的一個自掛載點。每一個自掛載配置單元對應一個掛載配置單元 ,當該自動掛載點被訪問時,systemd 執行掛載點中定義的掛載行爲。
swap: 和掛載配置單元類似,交換配置單元用來管理交換分區。用戶可以用交換配置單元來定義系統中的交換分區,可以讓這些交換分區在啓動時被激活。
target :此類配置單元爲其他配置單元進行邏輯分組。它們本身實際上並不做什麼,只是引用其他配置單元而已。這樣便可以對配置單元做一個統一的控制。這樣就可以實現大家都已經非常熟悉的運行級別概念。比如想讓系統進入圖形化模式,需要運行許多服務和配置命令,這些操作都由一個個的配置單元表示,將所有這些配置單元組合爲一個目標(target),就表示需要將這些配置單元全部執行一遍以便進入目標所代表的系統運行狀態。 (例如:multi-user.target 相當於在傳統使用 SysV 的系統中運行級別 3)
timer:定時器配置單元用來定時觸發用戶定義的操作,這類配置單元取代了 atd、crond 等傳統的定時服務。
snapshot :與 target 配置單元相似,快照是一組配置單元。它保存了系統當前的運行狀態。
依賴關係:
雖然 systemd 將大量的啓動工作解除了依賴,使得它們可以併發啓動。但還是存在有些任務,它們之間存在天生的依賴,不能用"套接字激活"(socket activation)、D-Bus activation 和 autofs 三大方法來解除依賴(三大方法詳情見後續描述)。比如:掛載必須等待掛載點在文件系統中被創建;掛載也必須等待相應的物理設備就緒。爲了解決這類依賴問題,systemd 的配置單元之間可以彼此定義依賴關係。
Systemd 用配置單元定義文件中的關鍵字來描述配置單元之間的依賴關係。比如:unit A 依賴 unit B,可以在 unit B 的定義中用"require A"來表示。這樣 systemd 就會保證先啓動 A 再啓動 B。
Systemd事務:
Systemd 能保證事務完整性。Systemd 的事務概念和數據庫中的有所不同,主要是爲了保證多個依賴的配置單元之間沒有環形引用。 存在循環依賴,那麼 systemd 將無法啓動任意一個服務。此時systemd 將會嘗試解決這個問題,因爲配置單元之間的依賴關係有兩種:required是強依賴;want 則是弱依賴,systemd 將去掉 wants 關鍵字指定的依賴看看是否能打破循環。如果無法修復,systemd會報錯。
Systemd 能夠自動檢測和修復這類配置錯誤,極大地減輕了管理員的排錯負擔。
Target和運行級別:
systemd 用目標(target)替代了運行級別的概念,提供了更大的靈活性,如您可以繼承一個已有的目標,並添加其它服務,來創建自己的目標。下表列舉了 systemd 下的目標和常見 runlevel 的對應關係:
Systemd 的併發啓動原理
如前所述,在 Systemd 中,所有的服務都併發啓動,比如Avahi、D-Bus、livirtd、X11、HAL 可以同時啓動。乍一看,這似乎有點兒問題,比如 Avahi 需要syslog 的服務,Avahi 和syslog 同時啓動,假設 Avahi 的啓動比較快,所以syslog 還沒有準備好,可是 Avahi 又需要記錄日誌,這豈不是會出現問題?
Systemd 的開發人員仔細研究了服務之間相互依賴的本質問題,發現所謂依賴可以分爲三個具體的類型,而每一個類型實際上都可以通過相應的技術解除依賴關係。
併發啓動原理之一:解決 socket 依賴
絕大多數的服務依賴是套接字依賴。比如服務A 通過一個套接字端口S1 提供自己的服務,其他的服務如果需要服務A,則需要連接S1。因此如果服務A 尚未啓動,S1就不存在,其他的服務就會得到啓動錯誤。所以傳統地,人們需要先啓動服務A,等待它進入就緒狀態,再啓動其他需要它的服務。Systemd認爲,只要我們預先把S1 建立好,那麼其他所有的服務就可以同時啓動而無需等待服務A 來創建S1 了。如果服務A 尚未啓動,那麼其他進程向S1 發送的服務請求實際上會被Linux 操作系統緩存,其他進程會在這個請求的地方等待。一旦服務A 啓動就緒,就可以立即處理緩存的請求,一切都開始正常運行。
那麼服務如何使用由 init 進程創建的套接字呢?
Linux 操作系統有一個特性,當進程調用fork 或者exec 創建子進程之後,所有在父進程中被打開的文件句柄(file descriptor) 都被子進程所繼承。套接字也是一種文件句柄,進程A 可以創建一個套接字,此後當進程A 調用 exec 啓動一個新的子進程時,只要確保該套接字的close_on_exec 標誌位被清空,那麼新的子進程就可以繼承這個套接字。子進程看到的套接字和父進程創建的套接字是同一個系統套接字,就彷彿這個套接字是子進程自己創建的一樣,沒有任何區別。
這個特性以前被一個叫做 inetd 的系統服務所利用。Inetd 進程會負責監控一些常用套接字端口,比如Telnet,當該端口有連接請求時,inetd才啓動 telnetd 進程,並把有連接的套接字傳遞給新的telnetd 進程進行處理。這樣,當系統沒有telnet 客戶端連接時,就不需要啓動telnetd 進程。Inetd可以代理很多的網絡服務,這樣就可以節約很多的系統負載和內存資源,只有當有真正的連接請求時才啓動相應服務,並把套接字傳遞給相應的服務進程。
和 inetd 類似,systemd 是所有其他進程的父進程,它可以先建立所有需要的套接字,然後在調用exec 的時候將該套接字傳遞給新的服務進程,而新進程直接使用該套接字進行服務即可。
併發啓動原理之二:解決 D-Bus 依賴
D-Bus 是 desktop-bus 的簡稱,是一個低延遲、低開銷、高可用性的進程間通信機制。它越來越多地用於應用程序之間通信,也用於應用程序和操作系統內核之間的通信。很多現代的服務進程都使用D-Bus取代套接字作爲進程間通信機制,對外提供服務。比如簡化Linux 網絡配置的NetworkManager 服務就使用D-Bus 和其他的應用程序或者服務進行交互:郵件客戶端軟件evolution 可以通過D-Bus 從NetworkManager 服務獲取網絡狀態的改變,以便做出相應的處理。
D-Bus 支持所謂"busactivation"功能。如果服務A 需要使用服務 B 的 D-Bus 服務,而服務 B 並沒有運行,則 D-Bus 可以在服務 A 請求服務 B 的 D-Bus 時自動啓動服務 B。而服務 A 發出的請求會被 D-Bus 緩存,服務 A 會等待服務 B 啓動就緒。利用這個特性,依賴D-Bus 的服務就可以實現並行啓動。
併發啓動原理之三:解決文件系統依賴
系統啓動過程中,文件系統相關的活動是最耗時的,比如掛載文件系統,對文件系統進行磁盤檢查(fsck),磁盤配額檢查等都是非常耗時的操作。在等待這些工作完成的同時,系統處於空閒狀態。那些想使用文件系統的服務似乎必須等待文件系統初始化完成纔可以啓動。但是systemd 發現這種依賴也是可以避免的。
Systemd 參考了 autofs 的設計思路,使得依賴文件系統的服務和文件系統本身初始化兩者可以併發工作。autofs可以監測到某個文件系統掛載點真正被訪問到的時候才觸發掛載操作,這是通過內核automounter 模塊的支持而實現的。比如一個open()系統調用作用在"/misc/cd/file1"的時候,/misc/cd 尚未執行掛載操作,此時 open()調用被掛起等待,Linux 內核通知 autofs,autofs 執行掛載。這時候,控制權返回給open()系統調用,並正常打開文件。
Systemd 集成了 autofs 的實現,對於系統中的掛載點,比如/home,當系統啓動的時候,systemd 爲其創建一個臨時的自動掛載點。在這個時刻/home真正的掛載設備尚未啓動好,真正的掛載操作還沒有執行,文件系統檢測也還沒有完成。可是那些依賴該目錄的進程已經可以併發啓動,他們的open()操作被內建在systemd 中的autofs 捕獲,將該open()調用掛起(可中斷睡眠狀態)。然後等待真正的掛載操作完成,文件系統檢測也完成後,systemd將該自動掛載點替換爲真正的掛載點,並讓open()調用返回。由此,實現了那些依賴於文件系統的服務和文件系統本身同時併發啓動。
當然對於"/"根目錄的依賴實際上一定還是要串行執行,因爲systemd 自己也存放在/之下,必須等待系統根目錄掛載檢查好。
不過對於類似/home 等掛載點,這種併發可以提高系統的啓動速度,尤其是當/home是遠程的 NFS 節點,或者是加密盤等,需要耗費較長的時間纔可以準備就緒的情況下,因爲併發啓動,這段時間內,系統並不是完全無事可做,而是可以利用這段空餘時間做更多的啓動進程的事情,總的來說就縮短了系統啓動時間。
Systemd 的使用
下面針對技術人員的不同角色來簡單地介紹一下 systemd 的使用。本文只打算給出簡單的描述,讓您對 systemd 的使用有一個大概的理解。具體的細節內容太多,即無法在一篇短文內寫全。還需要讀者自己去進一步查閱 systemd 的文檔。
Unit 文件的編寫
開發人員開發了一個新的服務程序,比如httpd,就需要爲其編寫一個配置單元文件以便該服務可以被systemd 管理,類似UpStart 的工作配置文件。在該文件中定義服務啓動的命令行語法,以及和其他服務的依賴關係等。
此外我們之前已經瞭解到,systemd 的功能繁多,不僅用來管理服務,還可以管理掛載點,定義定時任務等。這些工作都是由編輯相應的配置單元文件完成的。我在這裏給出幾個配置單元文件的例子。
下面是 SSH 服務的配置單元文件,服務配置單元文件以.service爲文件名後綴。
[root@kalaguiyin system]# cat/usr/lib/systemd/system/sshd.service [Unit] Description=OpenSSH server daemon After=network.target sshd-keygen.service Wants=sshd-keygen.service #[unit]部分,描述信息 [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStart=/usr/sbin/sshd -D $OPTIONS ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s #[service]定義,ExecStartPre定義啓動服務之前應該運行的命令; #ExecStart 定義啓動服務的具體命令行語法。 [Install] WantedBy=multi-user.target #[install]部分:WangtedBy表明這個服務是在多用戶模式下所需要的。
那我們就來看下multi-user.target 吧:
[root@kalaguiyin system]# catmulti-user.target [Unit] Description=Multi-User System Documentation=man:systemd.special(7) Requires=basic.target Conflicts=rescue.service rescue.target After=basic.target rescue.servicerescue.target AllowIsolate=yes # Requires 定義表明 multi-user.target 啓動的時候 basic.target 也必須被啓動;另外 basic.target 停止的時# 候,multi-user.target 也必須停止。如果您接着查看 basic.target 文件,會發現它又指定了 sysinit.target 等# 其他的單元必須隨之啓動。同樣 sysinit.target 也會包含其他的單元。採用這樣的層層鏈接的結構,最終所# 有需要支持多用戶模式的組件服務都會被初始化啓動好。 [Install] Alias=default.target # Alias 定義,即定義本單元的別名,這樣在運行 systemctl 的時候就可以使用這個別名來引用本單元。
此外在/etc/systemd/system 目錄下還可以看到諸如*.wants 的目錄,放在該目錄下的配置單元文件等同於在[Unit]小節中的 wants 關鍵字,即本單元啓動時,還需要啓動這些單元。比如您可以簡單地把您自己寫的 foo.service 文件放入 multi-user.target.wants 目錄下,這樣每次都會被默認啓動了。
[root@kalaguiyin system]# pwd /etc/systemd/system [root@kalaguiyin system]# ls basic.target.wants display-manager.service bluetooth.target.wants getty.target.wants dbus-org.bluez.service graphical.target.wants printer.target.wants sockets.target.wants spice-vdagentd.target.wants default.target sysinit.target.wants default.target.wants
再讓我們來看看sys-kernel-debug.mout文件,這個文件定義了一個文件掛載點:
[root@kalaguiyin system]# cat sys-kernel-debug.mount [Unit] Description=Debug File System Documentation=https://www.kernel.org/doc/Documentation/filesystems/debugfs.txt Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems DefaultDependencies=no ConditionPathExists=/sys/kernel/debug Before=sysinit.target [Mount] What=debugfs Where=/sys/kernel/debug Type=debugfs
這個配置單元文件定義了一個掛載點。掛載配置單元文件有一個[Mount]配置小節,裏面配置了 What,Where 和 Type 三個數據項。這都是掛載命令所必須的,例子中的配置等同於下面這個掛載命令:
mount –t debugfs /sys/kernel/debug debugfs
Systemd系統管理:
systemd 的主要命令行工具是 systemctl。
多數管理員應該都已經非常熟悉系統服務和 init 系統的管理,比如 service、chkconfig以及 telinit 命令的使用。systemd 也完成同樣的管理任務,只是命令工具systemctl 的語法有所不同而已。
啓動服務
systemctl start httpd.service 如圖1:
停止服務
systemctl stop httpd.service 如圖2:
重啓服務
systemctl restarthttpd.service 如圖3:
重載服務
systemctl reloadhttpd.service
條件式重啓
systemctl condrestarthttpd.service
狀態查看
systemctl statushttpd.service
列出可以啓動或停止的服務列表。
systemctl list-unit-files –type=service
設置服務爲開機啓動
chkconfig httpd on systemctl enablehttpd.service
取消服務開機啓動;
systemctl disablehttpd.service
檢查一個服務在當前環境下被配置爲啓用還是禁用。
systemctl is-enabledhttpd.service;echo $?
輸出在各個運行級別下服務的啓用和禁用情況
systemctl list-unit-files –type=service
列出某服務在哪些運行級別下啓用和禁用。
ls /etc/lib/systemd/system/*.wants/httpd.service
改變用戶運行級別:
systemctl isolatemulti-user.target
multi-user.target == 第3運行級別
graphical.target == 第5運行級別
runlevel3.target 符號鏈接,指向multi-user.target
runlevel5.target 符號鏈接,指向graphical.target
改變默認運行級別:
[root@kalaguiyinsystem]# systemctl set-default multi-user.target rm'/etc/systemd/system/default.target' ln -s'/usr/lib/systemd/system/multi-user.target''/etc/systemd/system/default.target'
上述操作的實質是刪除/usr/lib/systemd/system/default.target,然後將目標級別的target文件鏈接至/etc/systemd/system/default.target文件;
systemd 已經不僅僅是一個初始化系統了:
systemd 還負責系統其他的管理配置,比如配置網絡,Locale 管理,管理系統內核模塊加載等。
Systemd 出色地替代了sysvinit 的所有功能,但它並未就此自滿。因爲init 進程是系統所有進程的父進程這樣的特殊性,systemd 非常適合提供曾經由其他服務提供的功能,比如定時任務 (以前由 crond 完成) ;會話管理 (以前由 ConsoleKit/PolKit 等管理) 。僅僅從本文皮毛一樣的介紹來看,Systemd已經管得很多了,可它還在不斷髮展。它將逐漸成爲一個多功能的系統環境,能夠處理非常多的系統管理任務,有人甚至將它看作一個操作系統。這非常有助於標準化 Linux 的管理!