章節概覽#
當 kernel 啟動 init(第一個 user-space process)後,系統才真正開始建構完整的運作環境。User space 的啟動順序大致如下:
- init 啟動
- 基礎低階服務(如 udevd、syslogd)
- 網路設定
- 中高階服務(cron、列印等)
- 登入提示、GUI、高階應用程式(如 web server)
User space 比 kernel 更加模組化且容易自訂,理解和修改 user-space 啟動不需要低階程式設計知識。
6.1 init 簡介#
init 是一個普通的 user-space 程式,位於 /sbin,主要功能是啟動和停止系統上的關鍵服務 process。
目前所有主流 Linux 發行版的標準 init 實作都是 systemd。歷史上還有其他版本:
- System V init(Sys V,傳統的順序式 init):RHEL 7.0 之前、Debian 8 之前使用
- Upstart:Ubuntu 15.04 之前使用
- runit:輕量系統上較常見
System V init 的限制#
傳統 System V init 依序執行一系列 script,每個 script 啟動一個服務。這種方式有幾個問題:
- 效能問題:開機序列的各部分無法同時執行
- 服務管理困難:需要手動追蹤 daemon 的 PID
- 啟動 script 充滿樣板程式碼(boilerplate code)
- 缺乏 on-demand 服務的概念,大多數服務都在開機時啟動
6.2 辨識你的 init#
判斷系統使用哪種 init 的方法:
- 若系統有
/usr/lib/systemd和/etc/systemd目錄 → systemd - 若有
/etc/init目錄且含多個.conf檔案 → 可能是 Upstart - 若有
/etc/inittab檔案 → 可能是 System V init
6.3 systemd#
systemd 是目前最主流的 init 實作。除了處理開機流程,它還整合了許多傳統 Unix 服務的功能(如 cron、inetd)。systemd 的核心優勢在於進階的服務管理能力:能追蹤啟動後的 daemon、將多個 process 分組管理。
systemd 是目標導向(goal-oriented)的:你定義一個目標,稱為 unit,systemd 會自動解析其相依性並啟動所需的一切。
6.3.1 Unit 與 Unit 類型#
每種功能稱為一個 unit type,每個具體功能稱為一個 unit。最重要的 unit type:
- Service units:控制系統上的 daemon
- Target units:將其他 unit 分組管理
- Socket units:代表網路連線請求的監聽位置
- Mount units:代表檔案系統的掛載
完整的 unit type 列表可在
systemd(1)manual page 中找到。
6.3.2 開機與 Unit 相依性圖#
開機時,systemd 啟動一個預設的 unit,通常是 default.target,它匯集了一組 service 和 mount unit 作為相依性。這些相依性構成一個圖(graph),而非簡單的樹狀結構,因為後期的 unit 可能依賴多個前期 unit。
可以使用 systemd-analyze dot 指令產生相依性圖。

Figure 6-1: Unit dependency graph
在大多數系統上,
default.target是指向另一個高階 target unit(如啟動 GUI 的 target)的符號連結。
6.3.3 systemd 設定#
systemd 的設定檔分散在多個目錄:
- System unit directory(全域設定):
/lib/systemd/system或/usr/lib/systemd/system - System configuration directory(本地設定):
/etc/systemd/system
避免修改 system unit directory,因為發行版會維護它。本地修改應放在
/etc/systemd/system。
查看設定搜尋路徑:
systemctl -p UnitPath show查看系統 unit 和設定目錄:
pkg-config systemd --variable=systemdsystemunitdir
pkg-config systemd --variable=systemdsystemconfdirUnit 檔案格式#
Unit 檔案格式源自 XDG Desktop Entry 規範,使用方括號的 section 名稱,以及 key=value 的設定方式。例如 dbus-daemon.service:
[Unit]
Description=D-Bus System Message Bus
Documentation=man:dbus-daemon(1)
Requires=dbus.socket
RefuseManualStart=yes
[Service]
ExecStart=/usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ExecReload=/usr/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfigVariables 與 Specifiers#
- Variables:以
$開頭,如$OPTIONS、$MAINPID。可來自EnvironmentFile設定或 systemd 內部追蹤 - Specifiers:以
%開頭,如%n(unit 名稱)、%H(hostname)。可用@符號建立 unit 的多個實例(instance),例如getty@tty1、getty@tty2
6.3.4 systemd 操作#
透過 systemctl 指令與 systemd 互動:
# 列出所有啟用的 unit
systemctl list-units
# 查看特定 unit 的狀態
systemctl status sshd.service
# 查看 unit 的日誌
journalctl --unit=unit_name啟動、停止與重新載入#
systemctl start unit
systemctl stop unit
systemctl restart unit
systemctl reload unit # 僅重新載入該 unit 的設定
systemctl daemon-reload # 重新載入所有 unit 設定查看目前的 jobs(unit 狀態變更請求):
systemctl list-jobs新增與移除 Unit#
新增 unit 的步驟:
- 在
/etc/systemd/system建立 unit 檔案 - 若有
[Install]section,需先 enable:systemctl enable unit - 啟動 unit:
systemctl start unit
移除 unit 的步驟:
- 停止 unit:
systemctl stop unit - 若有
[Install]section:systemctl disable unit - 刪除 unit 檔案
enable 一個 unit 並不會啟動它,它只是建立相依性的符號連結。
6.3.5 systemd Process 追蹤與同步#
systemd 使用 cgroups(Linux kernel 功能)來追蹤每個服務的所有 process,無論服務如何 fork 或 daemonize。
透過 unit 檔案中的 Type 選項指定啟動行為:
- Type=simple:process 不 fork,直接作為主服務 process
- Type=forking:服務會 fork,原始 process 結束後視為就緒
- Type=notify:服務就緒時透過特殊函式呼叫通知 systemd
- Type=dbus:服務就緒時在 D-Bus 上註冊
- Type=oneshot:process 執行完畢後就結束,不留常駐 process
- Type=idle:類似 simple,但等所有活躍 jobs 完成後才啟動
6.3.6 systemd 相依性#
systemd 提供多種相依性類型以兼顧彈性與容錯:
| 關鍵字 | 說明 |
|---|---|
| Requires | 嚴格相依。相依的 unit 失敗時,本 unit 也會被停用 |
| Wants | 僅用於啟動。相依的 unit 失敗不影響本 unit |
| Requisite | 相依的 unit 必須已經處於啟用狀態 |
| Conflicts | 負向相依。啟動本 unit 時會停用衝突的 unit |
systemd.service(5)manual page 建議盡量使用 Wants 來指定相依性,因為它不會將失敗傳播到其他 unit,使系統更加穩健。
查看 unit 的相依性:
systemctl show -p type unit排序(Ordering)#
Requires 和 Wants 本身不指定啟動順序,相依的 unit 會同時啟動以加速開機。若需要指定順序:
- Before:本 unit 在指定 unit 之前啟動
- After:本 unit 在指定 unit 之後啟動
預設與隱含相依性#
systemd 會自動為 Wants 相依性加上 After 修飾符,這稱為 default dependency。可在 unit 設定中加入 DefaultDependencies=no 來停用。
條件式相依性(Conditional Dependencies)#
可使用條件參數來根據系統狀態決定是否啟動 unit:
ConditionPathExists=p:路徑 p 存在時才啟動ConditionPathIsDirectory=p:p 是目錄時才啟動ConditionFileNotEmpty=p:p 是非空檔案時才啟動
[Install] Section 與 Enable#
[Install] section 允許在相依性的 unit 中反向定義相依關係:
- WantedBy:enable 時在目標 unit 的
.wants目錄建立符號連結 - RequiredBy:enable 時在目標 unit 的
.requires目錄建立符號連結
# enable 會建立符號連結
systemctl enable test1.target
# disable 會移除符號連結
systemctl disable test1.target6.3.7 systemd On-Demand 與資源平行化啟動#
systemd 的重要功能之一是延遲啟動(on-demand startup):
- 建立一個 service unit(Unit A)和一個 resource unit(Unit R,如 socket unit)
- 啟動 Unit R 後,systemd 監控該資源
- 當有存取資源的請求時,systemd 緩衝輸入並啟動 Unit A
- Unit A 就緒後接管資源,正常運作
Socket Unit 與 Service 範例#
以 echo service 為例,建立 echo.socket:
[Unit]
Description=echo socket
[Socket]
ListenStream=22222
Accept=true對應的 echo@.service(透過命名慣例自動關聯):
[Unit]
Description=echo service
[Service]
ExecStart=/bin/cat
StandardInput=socket以 Auxiliary Unit 優化開機#
Resource unit(如 socket unit)也可用於開機優化:systemd 先啟動 resource unit 來提供介面,讓依賴該資源的 unit 能立即開始啟動,不必等待實際服務就緒。這使得原本必須循序啟動的服務可以平行化。

Figure 6-2: Sequential boot timeline with a resource dependency

Figure 6-3: systemd boot timeline with a resource unit
6.3.8 systemd 輔助元件#
systemd 包含多個輔助系統服務,執行檔都以 systemd- 為前綴:
- udevd(
systemd-udevd):裝置管理 - journald:日誌服務,處理多種日誌機制(包含傳統 syslog)
- resolved:DNS 名稱解析快取
6.4 System V Runlevels#
在傳統 System V init 中,系統的運作狀態稱為 runlevel,以 0 到 6 的數字表示:
- Runlevel 0:關機(halt)
- Runlevel 1:單人模式(single-user mode)
- Runlevel 2-4:文字主控台
- Runlevel 5:GUI 登入
- Runlevel 6:重新開機(reboot)
查看目前 runlevel:
who -rRunlevel 的概念正在逐漸淘汰。即使 systemd 支援 runlevel,它更偏好使用 target unit 作為系統的最終狀態。Runlevel 主要為了相容 System V init script 而存在。
6.5 System V init#
System V init 的核心思想是透過精心建構的啟動順序支援不同 runlevel 之間的切換。
6.5.1 啟動指令序列#
System V init 的設定檔為 /etc/inittab,其中每行格式為四個欄位(以冒號分隔):
- 唯一識別碼
- 適用的 runlevel
- init 應採取的動作(如
initdefault、wait、respawn、ctrlaltdel、sysinit) - 要執行的指令(可選)
inittab 中的關鍵行會觸發 rc 指令,例如:
l5:5:wait:/etc/rc.d/rc 5rc 5 會依序執行 /etc/rc5.d 目錄中以 S 開頭的 script(帶 start 參數),數字決定執行順序(00-99)。
6.5.2 System V init Link Farm#
rc*.d 目錄中的檔案其實是指向 /etc/init.d 目錄中 script 的符號連結,這種結構稱為 link farm。所有 runlevel 共用同一組啟動 script,只是透過不同的符號連結來控制哪些服務要啟動。
- 以 S 開頭:啟動模式(start)
- 以 K 開頭:停止模式(kill/stop)
修改開機順序#
最常見的做法是在 link 名稱前加底線來停用服務:
mv S99httpd _S99httpd6.5.3 run-parts#
run-parts 是 System V init 用來執行 init.d script 的工具,它會依可預測的順序執行指定目錄中的所有可執行程式。不同發行版的 run-parts 功能各有差異。
6.5.4 System V init 控制#
使用 telinit 指令控制 System V init:
telinit 3 # 切換到 runlevel 3
telinit q # 重新讀取 inittab
telinit s # 切換到單人模式切換 runlevel 時,init 會嘗試終止不在新 runlevel
inittab設定中的 process,操作時需謹慎。
6.5.5 systemd 的 System V 相容模式#
systemd 能追蹤 System V init script 啟動的服務:
- 啟動
runlevel<N>.target - 辨識
/etc/rc<N>.d中的符號連結對應的/etc/init.dscript - 將 script 與 service unit 關聯(如
/etc/init.d/foo對應foo.service) - 啟動 service unit 並執行 script
這讓你可以用 systemctl 來管理這些舊式服務,但 init script 仍然是循序執行的。
6.6 關閉系統#
使用 shutdown 指令來關機或重新開機:
shutdown -h now # 立即關機(halt)
shutdown -r now # 立即重新開機(reboot)
shutdown -r +10 # 10 分鐘後重新開機關機流程:
- init 要求所有 process 正常結束
- 若 process 未回應,先送 TERM signal
- 仍未回應則送 KILL signal
- 鎖定系統檔案
- 卸載 root 以外的所有檔案系統
- 將 root 檔案系統重新掛載為唯讀
- 以
sync寫出所有緩衝資料 - 透過
reboot(2)system call 通知 kernel 重新開機或停止
關機過程中應避免重設或直接斷電。若必須緊急關機,可使用
shutdown -f(force)選項。
6.7 Initial RAM Filesystem#
initramfs(initial RAM filesystem)是在正常 user mode 啟動之前的一個小型 user-space 環境。它存在的原因:
- Linux kernel 不直接與 PC BIOS/EFI 溝通來讀取磁碟
- Kernel 需要儲存裝置的驅動程式才能掛載 root filesystem
- 許多儲存控制器驅動以 loadable modules 形式提供
- 若沒有檔案系統,就無法載入模組檔案
運作流程#
- Boot loader 將 initramfs archive 載入記憶體
- Kernel 將其解壓到臨時 RAM filesystem,掛載在
/ - 執行 initramfs 上的 init
- initramfs 中的工具載入必要的驅動模組
- 掛載真正的 root filesystem
- 啟動真正的 init
如果你的 kernel 已包含掛載 root filesystem 所需的所有驅動,可以在 boot loader 設定中省略 initramfs,稍微縮短開機時間。
檢查 initramfs 內容的工具:
- mkinitramfs 建立的 archive 可用 unmkinitramfs 解包
- 較舊的系統可能使用壓縮的 cpio archive
initramfs 末尾有一個重要的 pivot 過程,負責移除臨時檔案系統的內容並永久切換到真正的 root。
initramfs 指的是使用 cpio archive 的實作。較舊的版本稱為 initrd(initial RAM disk),使用磁碟映像檔。雖然 initrd 已不再使用,但這個術語仍常被用來指 cpio-based 的 initial RAM filesystem。
6.8 Emergency Booting 與 Single-User Mode#
當系統出問題時,有兩個主要的救援選項:
Live Image#
使用發行版的 live image 或專用的救援映像檔(如 SystemRescueCD)開機。常見的修復任務:
- 系統當機後檢查檔案系統
- 重設遺忘的密碼
- 修復關鍵設定檔(如
/etc/fstab、/etc/passwd) - 從備份還原
Single-User Mode#
系統快速開機到 root shell,跳過完整的服務啟動流程:
- System V init 中對應 runlevel 1
- systemd 中對應 rescue.target
- 在 boot loader 加上
-s參數進入
Single-user mode 的功能有限:網路幾乎不可用、沒有 GUI、終端機可能無法正常運作。因此 live image 通常是更好的選擇。
6.9 展望#
本章涵蓋了 kernel 到 user-space 啟動的完整流程,以及 systemd 如何管理服務。接下來將深入探討 user space 的兩個面向:系統設定檔(所有 Linux 程式都會用到的)以及 systemd 啟動的核心服務。