Linux 初始化之 Systemd機制


systemd是Linux下的一種init軟件,由Lennart Poettering帶頭開發,其開發目標是提供更優秀的框架以表示系統服務間的依賴關系,並依此實現系統初始化時服務的並行啟動,同時達到降低Shell的系統開銷的效果,最終代替現在常用的System V與BSD風格init程序。傳統sysvinit使用inittab來決定運行哪些shell腳本,大量使用shell腳本被認為是效率低下無法並行的原因。systemd使用了Linux專屬技術,不再顧及POSIX兼容.

設計理念

與多數發行版使用的System V風格init相比,systemd采用了以下新技術:

采用Socket激活式與D-Bus激活式服務,以提高相互依賴的各服務的並行運行性能;

用cgroups代替PID來追蹤進程,以此即使是兩次fork之后生成的守護進程也不會脫離systemd的控制。

從設計構思上說,由於systemd使用了cgroup與fanotify等組件以實現其特性,所以只適用於Linux。有鑒於此,考慮到kFreeBSD分支的軟件源無法納入systemd,為與其他分支保持一致,Debian開發者盡力避免納入systemd。

應用范圍

systemd已納入眾多Linux發行版的軟件源中,以下簡表:

默認init程序為systemd的發行版

Fedora 15及后續版本

Mageia 2[10]

Mandriva 2011[11]

openSUSE 12.1及后續版本[12]

Arch Linux在2012年10月13日將systemd-sysvcompat納入base軟件組,自此Arch Linux默認安裝完即以systemd為init程序[13],同時也提供了與Arch自帶啟動腳本兼容用的systemd啟動腳本包以方便用戶,使用戶能“開箱即用”[14]

Chakra GNU/Linux,在2012.10的光盤鏡像文件發布后默認使用systemd。[15]

可以使用systemd的發行版

Debian GNU/Linux,於“testing”分支源中提供[16],並在2014年的技術委員會的init系統投票中決定在Debian 8 “Jessie”中將以Linux為核心的版本轉換到systemd[17] 。

Gentoo,同Openrc一起被Gentoo官方支持[18][19][20]

除此以外,systemd已由Lennart Poettering提請納入GNOME 3.2的外部依賴關系列表[21],而這意味着所有使用GNOME的發行版都應該使用systemd,最低限度來說也必須將其作為配置選項之一。

一些其他的發行版也把它包含進來,作為 upstart 和 sysvinit 的替代品。

 

systemd 特點

systemd 開啟和監督整個系統是基於 unit 的概念。unit 是由一個與配置文件對應的名字和類型組成的(例如:avahi.service unit 有一個具有相同名字的配置文件,是守護進程 Avahi 的一個封裝單元)unit 有以下幾種類型:

service :守護進程的啟動、停止、重啟和重載是此類 unit 中最為明顯的幾個類型。

socket :此類 unit 封裝系統和互聯網中的一個 socket 。當下,systemd 支持流式、數據報和連續包的 AF_INET、AF_INET6、AF_UNIX socket 。也支持傳統的 FIFOs 傳輸模式。每一個 socket unit 都有一個相應的服務 unit 。相應的服務在第一個“連接”進入 socket 或 FIFO 時就會啟動(例如:nscd.socket 在有新連接后便啟動 nscd.service)。

device :此類 unit 封裝一個存在於 Linux 設備樹中的設備。每一個使用 udev 規則標記的設備都將會在 systemd 中作為一個設備 unit 出現。udev 的屬性設置可以作為配置設備 unit 依賴關系的配置源。

mount :此類 unit 封裝系統結構層次中的一個掛載點。

automount :此類 unit 封裝系統結構層次中的一個自掛載點。每一個自掛載 unit 對應一個已掛載的掛載 unit (需要在自掛載目錄可以存取的情況下盡早掛載)。

target :此類 unit 為其他 unit 進行邏輯分組。它們本身實際上並不做什么,只是引用其他 unit 而已。這樣便可以對 unit 做一個統一的控制。(例如:multi-user.target 相當於在傳統使用 SysV 的系統中運行級別5);bluetooth.target 只有在藍牙適配器可用的情況下才調用與藍牙相關的服務,如:bluetooth 守護進程、obex 守護進程等)

snapshot :與 target unit 相似,快照本身不做什么,唯一的目的就是引用其他 unit 。

systemd 的工具

  • systemctl :用作內省和控制 systemd 系統和服務管理器的狀態。
  • systemd-cgls:以樹形遞歸顯示選中的 Linux 控制組結構層次。
  • systemadm:一個 systemd 系統和服務管理器的圖形化前端。是 systemd-gtk 軟件包的一部分。這還只是前期版本,尚需完善。除非你是一個開發者,否則請不要使用它。

 

systemd 包含了自己的配置和診斷工具,在使用它處理系統啟動問題時用到的技巧不同於 sysvinit。由於它與 upstart 和 sysvinit 的兼容特性,我們在使用這兩個初始化工具的發行版里面熟悉的命令與技巧也適用於 systemd。

 systemctl 命令

檢視和控制systemd的主要命令是systemctl。該命令可用於查看系統狀態和管理系統及服務。詳見man 1 systemctl。該工具在改變配置文件或重新啟動后台程序時需要 root 權限,但即使是非 root 用戶也能下達一些診斷的命令。如果你在啟動該命令時不加任何參數,你會看到一個系統啟動時執行任務的“單位(unit)”列表,包括掛載及檢測磁盤、啟動后台服務及配置硬件。

1)輸出激活的單元

$ systemctl

以下命令等效:

$ systemctl list-units

輸出運行失敗的單元:

$ systemctl --failed

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

$ systemctl list-unit-files

2)使用單元

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

使用 systemctl 控制單元時,通常需要使用單元文件的全名,包括擴展名(例如 sshd.service)。但是有些單元可以在systemctl中使用簡寫方式。

  • 如果無擴展名,systemctl 默認把擴展名當作 .service。例如 netcfg 和 netcfg.service 是等價的。
  • 掛載點會自動轉化為相應的 .mount 單元。例如 /home 等價於 home.mount。
  • 設備會自動轉化為相應的 .device 單元,所以 /dev/sda2 等價於 dev-sda2.device。

立即激活單元:

# systemctl start <單元>

立即停止單元:

# systemctl stop <單元>

重啟單元:

# systemctl restart <單元>

命令單元重新讀取配置:

# systemctl reload <單元>

輸出單元運行狀態:

$ systemctl status <單元>

檢查單元是否配置為自動啟動:

$ systemctl is-enabled <單元>

開機自動激活單元:

# systemctl enable <單元>

注意: 如果服務沒有Install段落,一般意味着應該通過其它服務自動調用它們。如果真的需要手動安裝,可以直接連接服務,如下(將foo替換為真實的服務名):

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

取消開機自動激活單元:

# systemctl disable <單元>

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

# systemctl help <單元>

重新載入 systemd,掃描新的或有變動的單元:

# systemctl daemon-reload

3服務

服務(service)單位是最重要的一類單位之一,因為它們管理着后台服務,而在使用 sysvinit 的發行版里面則一般使用初始化腳本來啟動這些服務。掛載(mount)與自動掛載(automount)單位用來掛載文件系統。

套接字(socket)單位用來創建套接字,並在訪問套接字后,立即利用依賴關系間接地啟動另一單位。你可以使用參數讓 systemctl 只列出某個類型的單位,如所有的服務單位:systemctl --type=service

systemd 自動將其輸出結果遞交給 less 顯示;你不僅可以使用箭頭鍵來上下滾動,也可以向右滾動,因為有時更多的信息會偶爾“藏”到那里。

列表中的第一欄是單位的名字,

第二欄則表示該單位的定義是否已由 systemd 正確加載。

第三欄則告訴我們該單位是否正在運行。如果你使用了 -a 參數,那么該程序將僅顯示非正在運行的單位,即已安裝但並未在啟動時使用的單位,同時也包含引導系統未能正常加載的單位文件(原因很可能為該單位文件出現錯誤)。

第四欄則給出了當前狀態:“exited”表示該進程已經無任何錯誤地完成,這種情況適用於一諸如進程在啟動后並不在后台繼續運行的情況,例如,在系統啟動時由於考慮到兼容性因素執行在 sysvinit 里面常用的 /etc/rc.d/rc.local 文件的服務單位。“Running”表示正在后台運行的服務,如 cron、dbus、sshd 和 udev。

第五欄是對該單位的描述。標有“LSB”或“SYSV”的單位已由 systemd 自動創建以管理傳統啟動腳本。

不能啟動或啟動后崩潰的服務在第四欄中用紅色標為“failed”(如果終端可以顯示彩色)。你可以如下命令來察看該服務是何時崩潰的以及在服務程序結束后提供了什么錯誤代碼:

systemctl status ntpd.service

對於一個新安裝的 Linux Deepin 12.06,systemctl 會列出約50個服務型單位,包含文本終端的登陸進程(agetty)。因為 systemd 不同於 sysvinit, 它會像管理普通的后台服務一樣以服務單位的形式對這些進程進行管理。

 

4)單位文件與目標(target)

 

一單位的處理

創建單位用的系統配置文件位於 /lib/systemd/system/,但 /etc/systemd/system 目錄下的同名文件會優先於前者。

單位文件的定義通常比傳統的 sysvinit 腳本要短得多。例如,用於通過 NTP 來同步網絡時間的服務只有短短幾行:

[Unit]

Description=Network Time Service

 

[Service]

ExecStart=/usr/bin/ntpd -n -u ntp:ntp -g

 

[Install]

WantedBy=multi-user.target

1)      所有的單位文件都包含由[Unit]開頭的一節,其中包含一般設置與簡

2)      [Service]一節含有針對該服務要進行的任務的指定設置——對於 NTP 來說,僅需要啟動該服務的命令行。如果需要用一個指定的命令來終止程序,你可以用 ExecStop= 來進行設置。這一步對於 NTP 守護進程是不需要的,因為根據 Unix 傳統,它可以用一個簡單的“SIGTERM”信號來結束。如果沒有指定其他命令,這個命令會告訴 systemd 結束任務。

3)      [Install]一節包含了 systemd 在(反)安裝時要解釋的說明;這里的 NTP 一例中,其內容意為在“多用戶”目標激活時應當同步時間。

二目標

“目標”單位的概念與 sysvinit 的運行級別相似;實際上,為考慮兼容性,systemd 甚至能夠識別與目標對應的運行級別名稱。所以,你可以在引導裝載程序中的 kernel 一行中加入 single 這個參數;systemd 就會激活 rescue.target,提供一個相當於單用戶模式的最小化界面。

在 systemd 中,多用戶模式(即不使用圖形化登陸界面就完全啟動系統的模式)由 multi-user.target 表示,可以通過下面這個鏈接來將其設為默認啟動目標:

ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target

如果此后你確實需要默認啟動圖形化登陸界面,可用同樣的方式來將 graphical.target 設為默認目標。這等同於傳統初始化工具的運行級別 5。你也可以在引導裝載程序中為 kernel 指定想要啟動的目標單位:

systemd.unit=multi-user.target

 

 如果想要在操作過程中激活一個不同的目標單位,你可以使用 systemctl 的isolate 命令(需要 root 權限):

systemctl isolate rescue.target

切換為 rescue 目標對於管理任務來說很有用,systemd 這時會停止所有的用戶登陸與后台服務,只有系統服務在運行,如監視邏輯卷的服務(lvm2-monitor)。有時,甚至這些服務也需要停止並重新安裝,這時你可以使用 emergency.target 來進入緊急模式(emergency mode),這時只有命令提示符的進程以及內核線程在運行。

 

 systemctl命令取代了rc.d命令

開機模塊加載

/etc/modules-load.d/.conf,相當於原rc.conf中的MODULES變量

# Load virtio-net.ko at boot virtio-net

virtio-net

模塊黑名單仍在/etc/modprobe.d/下,如blacklist.conf:

blacklist badmod.ko

Locale

/etc/locale.conf,相當於原rc.conf中的LOCALE

LANG=en_US.UTF-8 LC_COLLATE=C

LC_COLLATE=C

日志服務

systemd自帶日志服務,參考systemd Journal

sudo journalctl

可以刪除syslog-ng了

主機名

/etc/hostname,相當於原來rc.conf中的HOSTNAME變量

myhostname

網絡

sudo systemctl enable NetworkManager.service

不象rc.conf有專門的配置簡單網絡的地方,還是用NetworkManager、wicd之類的工具吧

如果你堅持使用簡單靜態配置,可以參考[SOLVED] static ethernet setup under systemd?

運行級別

systemdtarget替代了runlevel的概念,提供了更大的靈活性,如你可以繼承一個已有的target,並添加其它服務,來創建自己的target

sudo systemctl list-units --type=target #查詢當前target

sudo systemctl isolate graphical.target #改變當前target,重啟無效

sudo systemctl enable multi-user.target #改變啟動時默認target

sudo systemctl enable kdm.service #graphical是默認target,指定使用的display manager

優化

systemd有自己的”e4rat”

sudo systemctl enable systemd-readahead-collect.service sudo systemctl enable systemd-readahead-replay.service

/etc/fstab,修改/home分區options,檢查/home分區時並行啟動其它服務

defaults,noauto,x-systemd.automount

其他

sudo systemctl reboot #systemctl還有系統關機、重啟、掛起等功能 sudo systemctl suspend

 

 

自己編寫 .service 文件

systemd 的單元文件是受 XDG Desktop Entry .desktop 文件啟發而產生,而最初起源是 Windows 下的 .ini 文件。

示例參見:Systemd/Services

處理依賴關系

使用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= 參數進行設置。具體的參數說明請參閱 man systemd.service 。

  • 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認為服務就緒。

修改現存單元文件

要更改由軟件包提供的單元文件,先創建名為 /etc/systemd/system/<單元名>.d/ 的目錄(如 /etc/systemd/system/httpd.service.d/),然后放入 *.conf 文件,其中可以添加或重置參數。這里設置的參數優先級高於原來的單元文件。例如,如果想添加一個額外的依賴,創建這么一個文件即可:

/etc/systemd/system/<unit>.d/customdependency.conf

[Unit]

Requires=<新依賴>

After=<新依賴>

然后運行以下命令使更改生效:

# systemctl daemon-reload

# 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 命令來查看哪些單元文件被覆蓋、哪些被修改。

 

eg:slock

Locks the system with the help of slock. Very handy when closing the laptop lid for example.

/etc/systemd/system/screenlock.service

[Unit]

Description=Lock X session using slock

Before=sleep.target

 

[Service]

User=<username>

Environment=DISPLAY=:0

ExecStart=/usr/bin/slock

 

[Install]

WantedBy=sleep.target

 

如何定制或增加一個自定義 unit 文件?

unit 文件在 /etc/systemd/system 下的優先級要高於 /lib/systemd/system 下的。按照個人的需求從后者移動到前者並進行自定義修改。

如果一行以 .include 開始,后接文件名,那么該文件在此時被解析為特殊文件。請確保包含的文件在指令前有適當的章節頭信息。

如果可能的話,你應當使用 .include 聲明 unit 文件而不是在 /lib/systemd/system 下復制整個 unit 文件到 /etc/systemd/system 目錄下。這樣你才可以在將來升級軟件包時正確地升級未改變的指令。

在使用 .include 和指令時需要小心,因為它可以有多次定義(像 EnvironmentFile= 一樣)。由於我們只能添加新指令而不能刪除已定義的指令,此時,我們就必須從 /lib/systemd/system復制整個文件到 /etc/systemd/system 中去。

假設我們有一個 lighttpd 服務,我們現在想降低它的 niceness 值。我們需要做的就只是添加 Nice=-5 到 lighttpd.service 文件中。我們可以通過復制整個文件/lib/systemd/system/lighttpd.service 到 /etc/systemd/system/lighttpd.service 或者在 /etc/systemd/system/lighttpd.service 中創建如下文件做到

.include /lib/systemd/system/lighttpd.service

[Service]

Nice=-5

不要忘記在編輯一個 unit 文件后使用 systemdctl daemon-reload 重載 systemd 守護進程。

檢測到 Linux 所使用的虛擬化平台類型。

方法一:dmidecode

要檢測 Linux 底層的虛擬化類型首選的就是 dmidecode 命令,它最初設計來顯示系統 BIOS 和硬件組件的相關信息。使用如下命令便可以檢測相關虛擬化信息:

sudo dmidecode -s system-manufacturer

檢測Linux虛擬化平台類型的幾種方式

系統極客網站運行在 Microsoft Azure 平台上,所以檢測出來是微軟的 Hyper-V。如果你的系統運行在物理服務器上,輸入的將是硬件制造商的實際名稱(如 Dell Inc.)。如果你的 Linux 是運行在虛擬化平台中,則會顯示所使用的虛擬化技術相關名稱,如 「Microsoft Corporation」「QEMU」「Xen」「VirtualBox」「VMware, Inc」等等。

注意:該方法不適用於基於容器的虛擬化技術。

方法二:systemd

對於使用 systemd 的 Linux 系統,可以使用 systemd-detect-virt 命令來進行檢測,該命令目前可以同時檢測到基於 hypervisor 的虛擬化技術(例如 KVM、QEMU、VMware、Xen、Oracle VM、VirtualBox、UML)和基於容器的虛擬化技術(例如 LXC、Docker、OpenVZ)。

systemd-detect-virt

注意:在物理服務器上使用該命令會輸出「none」。

檢測Linux虛擬化平台類型的幾種方式

方法三:virt-what

我們介紹的最后一種檢測 Linux 所使用虛擬化類型的方法是 virt-what 命令,virt-what 實際上是一個 Shell 腳本。它通過各種啟發式方法來識別虛擬化環境類型,可以檢測出 QEMU/KVM、VMware、Hyper-V、VirtualBox、OpenVZ/Virtuozzo、Xen、LXC、IBM PowerVM 以及 Parallels 等平台類型。

在使用之前,大家需要先通過 apt-get 或 yum 安裝 virt-what,再執行如下命令進行檢測:

sudo virt-what

檢測Linux虛擬化平台類型的幾種方式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM