Linux 服務管理之 syste
簡介
systemd 是一種用於 Linux 操作系統的初始化系統和服務管理器,由 Lennart Poettering 主導開發並在 LGPL 2.1 及其後續版本許可證下開源發佈。自 2010 年代中期以來,systemd 已經廣泛被多數主流 Linux 發行版採用,如 Ubuntu、Fedora、openSUSE、Debian 和 CentOS/RHEL 7 及以後版本,作爲默認的初始化系統取代了傳統的 System V init 和 Upstart 等系統。
主要功能和特點
-
並行啓動服務:systemd 引入了服務間的依賴關係管理,允許並行啓動多個不相互依賴的服務,顯著縮短了系統啓動時間。
-
Unit 文件:每個系統資源(如服務、掛載點、設備、sockets、計時器等)都被定義爲一個 “單元”(Unit),並由一個相應的配置文件(Unit file)來描述。這些文件通常位於 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目錄下,擁有 .service、.socket、.target 等後綴。
-
依賴關係管理:systemd 允許精確地定義服務之間的依賴關係,確保服務按照正確的順序啓動或停止。
-
系統目標(Targets):類似於 System V init 的運行級別,但更加靈活,代表一組服務的集合,定義了系統的某種運行狀態(如 multi-user.target 對應傳統的運行級別 3)。
-
journal 日誌:systemd 提供了一個名爲 journal 的日誌系統,用於收集和查看系統日誌,支持快速過濾和查詢。
-
Socket 激活:服務可以根據實際需求(如客戶端連接)動態激活,而不是一直運行等待請求,提高了資源利用率。
-
環境變量與資源限制:Unit 文件中可以設定服務的環境變量、資源使用限制(如內存、CPU 時間)等。
-
用戶服務:除了系統級別的服務外,systemd 還支持用戶級別的服務,通過 user@.service 類型的單元。
-
網絡命名和管理:systemd 提供了一個叫做 networkd 的組件,用於網絡接口的配置和管理。
-
系統狀態與管理工具:systemctl 命令是與 systemd 交互的主要工具,用於啓動、停止、重啓服務,查看服務狀態,管理系統目標等。
原理概述
1.Systemd 初始化過程:
-
當 Linux 系統啓動時,內核會加載並執行第一個用戶空間程序,即 systemd。它作爲 PID 1 運行,是所有其他進程的父進程。
-
systemd 首先讀取配置文件(通常是 /etc/systemd/system 和 /usr/lib/systemd/system 中的 .service 文件),解析系統服務的依賴關係,並基於此構建一個啓動圖。
-
它按照依賴順序並行或順序地啓動服務,這大大提高了系統的啓動速度。
2.Service Unit 文件:
-
每個服務由一個單元文件(Unit File)定義,通常位於 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目錄下,以 .service 擴展名結尾。
-
這些文件包含了服務的各種屬性,如執行命令、依賴關係、重啓行爲、環境變量等。
3.systemctl 命令功能:
-
systemctl 允許用戶與 systemd 交互,對服務進行管理,包括但不限於啓動、停止、重啓、查看狀態、設置開機啓動等操作。
-
它通過與 systemd 的 D-Bus 接口通信來發送指令,實現對服務單元的控制。
4.systemctl 命令處理流程:
-
當用戶執行 systemctl start example.service 時,systemctl 會通過 D-Bus 向 systemd 發送一個請求,要求啓動名爲 example.service 的服務。
-
systemd 根據服務的配置文件和當前系統狀態來決定如何處理這一請求,比如檢查服務的依賴是否已經就緒,然後執行相應的啓動腳本。
-
如果啓用了日誌記錄,systemd 會通過 journalctl 記錄服務的啓動過程和輸出,便於後續的故障排查。
5. 啓用與禁用服務:
-
使用 systemctl enable example.service 命令,實際上是在系統默認的啓動目標(如 multi-user.target)的配置鏈接到服務單元文件。這意味着系統啓動時,該服務會被自動啓動。
-
相反,systemctl disable example.service 則移除這些鏈接,服務不再自動啓動,但仍然可以通過 systemctl start 手動啓動。
6.Cgroups 和命名空間:
- systemd 使用控制組(Control Groups, cgroups)來跟蹤和限制服務資源使用,以及命名空間(Namespaces)來隔離服務的視圖,如文件系統、網絡棧等,增強了系統的安全性和資源管理能力。
通過上述機制,systemctl 和 systemd 一起提供了強大且靈活的系統服務管理功能,提升了系統的響應速度和管理效率。
設計單元 unit
systemd 設計的單元(Units)是用於描述系統資源和服務的配置文件,它們代表了 systemd 可以管理的各種不同類型的對象。這些單元類型允許 systemd 根據配置來啓動、停止、重啓或管理相應的系統組件。以下是 systemd 支持的主要單元類型分類:
-
服務單元 (.service):這是最常用的單元類型,用於定義系統服務,如守護進程(daemon)及其相關進程。服務單元控制着服務的啓動、停止、重載等操作。
-
套接字單元 (.socket):用於管理系統中的本地 IPC(進程間通信)或網絡套接字,支持基於套接字激活服務,即當套接字上有連接請求時自動啓動相應服務。
-
目標單元 (.target):作爲一組單元的集合,用於定義系統狀態或運行級別,如多用戶目標(multi-user.target)或圖形界面目標(graphical.target)。切換目標實際上就是啓動或停止與該目標相關聯的一組服務。
-
設備單元 (.device):代表系統中的硬件設備,可以用於基於設備的激活,即當設備接入或移除時執行特定操作。
-
掛載單元 (.mount):控制文件系統的掛載點,定義如何以及何時掛載或卸載文件系統。
-
路徑單元 (.path):監控文件或目錄的存在、不存在、修改等變化,並基於這些變化觸發動作。
-
計時器單元 (.timer):用於定義定時任務,可以在特定的時間間隔執行其他單元。
-
交換單元 (.swap):管理交換分區或文件,控制交換空間的啓用和禁用。
-
自動掛載點單元 (.automount):用於自動掛載文件系統,當訪問到掛載點時才實際掛載,不訪問時自動卸載,節省資源。
-
Snapshot 單元 (.snapshot):用於保存和恢復系統狀態快照,是系統狀態的即時備份,可用於快速回滾。
-
Slice 單元 (.slice):用於組織和管理 cgroup 層級,控制資源分配,特別是對於一組相關的進程。
這些單元通過它們的配置文件來定義,並且 systemd 通過解析這些文件來確定如何處理不同的系統組件和服務。每個單元類型都服務於特定的系統管理目的,共同構建了一個強大且靈活的初始化系統和服務管理框架。
服務單元 service
一個典型的. service 服務單元文件示例是管理 SSH 服務的配置文件。SSH 服務允許用戶通過加密的網絡連接遠程登錄系統。下面是一個簡化版的 ssh.service 服務單元文件示例,通常位於 / usr/lib/systemd/system/ssh.service 或 / etc/systemd/system/ssh.service:
[Unit]
Description=OpenSSH server daemon
After=network.target auditd.service
[Service]
Type=notify
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
這個文件分爲三個部分:
1.[Unit] 部分:描述了單元的元數據和依賴關係。
-
Description=:簡述服務的功能。
-
After=:定義此服務應該在哪些服務啓動後才啓動,這裏指定了網絡必須先啓動,以及 auditd 服務(如果啓用)。
2.[Service] 部分:定義了服務的具體行爲。
-
Type=:定義服務的類型,notify 表示服務會在啓動後通知 systemd 其啓動狀態。
-
ExecStart=:指定啓動服務的命令行。
-
ExecReload=:指定重新加載服務配置的命令。
-
KillMode=:指定 systemd 如何終止服務的進程。
-
Restart=:定義服務失敗後是否以及如何重啓,這裏是 on-failure 表示僅在失敗時重啓。
-
RestartSec=:重啓前等待的秒數。
3.[Install] 部分:定義瞭如何將服務安裝到系統中,即決定服務應該在哪種系統目標(target)下啓用。
- WantedBy=:聲明此服務希望被包含在 multi-user.target 中,這意味着 SSH 服務在多用戶、無圖形界面的系統狀態中自動啓動。
通過這個服務單元文件,systemd 知道如何控制 SSH 服務的啓動、停止、重啓以及如何響應服務的失敗情況,從而實現了對 SSH 服務的精細管理。
套接字單元. socket
一個套接字單元(.socket)的用例是用於配置監聽特定網絡端口或 Unix 域套接字的服務,以便當有連接請求到達時自動激活相應的服務單元。這有助於減少資源消耗,因爲服務只有在真正需要時才啓動。下面是一個簡單的 HTTP 服務(例如使用 nginx 作爲 Web 服務器)的套接字單元示例,文件可能位於 / etc/systemd/system/nginx.socket:
[Unit]
Description=nginx Web Server Socket
[Socket]
ListenStream=80
Accept=yes
[Install]
WantedBy=sockets.target
這個. socket 單元的各部分解釋如下:
1.[Unit] 部分:描述了單元的基本信息。
- Description=:說明這個套接字單元的功能,這裏是爲 nginx Web 服務器配置監聽套接字。
2.[Socket] 部分:定義了套接字的具體配置。
-
ListenStream=:指定監聽的 TCP 端口,在這個例子中是 80 端口,用於 HTTP 服務。
-
Accept=yes:指示 systemd 接受傳入的連接,並根據關聯的服務單元自動啓動服務。
3.[Install] 部分:定義瞭如何將套接字單元安裝到系統中。
- WantedBy=sockets.target:表明這個套接字單元應該在 sockets.target 下啓用,這是 systemd 默認啓動的一部分,意味着系統啓動時就會開始監聽這個端口。
配合這個. socket 單元,還需要一個對應的服務單元(通常是. service),例如 nginx.service,來定義當套接字接收連接時應執行的服務啓動命令。在服務單元中,通常會使用 Socket = 指令來引用相應的套接字單元,以確保服務只在有實際連接請求時被激活。這樣,當有 HTTP 請求到達 80 端口時,systemd 會自動啓動或喚醒 nginx.service 來處理請求,提高了資源的使用效率。
目標單元. target
一個目標單元(.target)的例子是 multi-user.target,它是 systemd 中一個非常基礎且常用的目標,代表了多用戶、非圖形界面的系統運行狀態。這個目標意味着系統已經完成了初始化並準備好了 shell 接入和其他多用戶服務,但沒有啓動圖形桌面環境。許多服務器系統默認啓動到這個目標。
multi-user.target 並不需要一個顯式的單元文件來定義,因爲它是 systemd 內部預設的目標之一,但理解其概念和用途是非常重要的。下面簡要概述其行爲,雖然實際中你可能不會直接編輯一個 multi-user.target 的配置文件,但可以通過查看其依賴關係來理解它所包含的服務:
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=sysinit.target basic.target
AllowIsolate=yes
這段描述是示意性的,說明了 multi-user.target 的一些關鍵屬性:
-
Description:簡短描述目標,這裏是 “多用戶系統”。
-
Requires:列出該目標依賴的基本目標,如 basic.target,表示在達到 multi-user.target 之前,basic.target 必須已經啓動完成。
-
Conflicts:定義了與該目標衝突的服務或目標,如救援模式的服務和目標。
-
After:指明該目標應當在哪些目標之後啓動,確保了系統的有序啓動。
-
AllowIsolate:允許使用 systemctl isolate multi-user.target 命令直接切換到此目標。
當系統啓動並指定了 multi-user.target 作爲默認目標時,systemd 會啓動所有依賴於 multi-user.target 的服務單元,如 SSH 服務、數據庫服務、Web 服務器等,但不包括 X Window 系統或 GNOME、KDE 等桌面環境服務。這對於大多數服務器場景是理想的,因爲它減少了不必要的圖形界面資源消耗。
設備單元. device
設備單元(.device)是 systemd 用於管理系統中的硬件設備的配置單元。這些單元自動由 udev 規則創建,並且可以用來基於設備的狀態變化(如插入或移除)執行動作。下面是一個簡單的設備單元示例,假設我們要爲一個特定的 USB 存儲設備定義一些自動化行爲,這個設備單元可能被命名爲 / etc/systemd/system/usb_storage_device.device:
[Unit]
Description=USB Storage Device
Wants=usb_storage.mount
[Device]
KernelMatchSubsystem=block
KernelMatchAttributes=idVendor=1234,idProduct=5678
[Install]
WantedBy=dev-block-sda.device
在這個例子中,設備單元定義了以下內容:
1.[Unit] 部分:
-
Description=:描述了設備單元的功能,這裏是識別一個 USB 存儲設備。
-
Wants=:聲明當此設備被激活時,也應啓動或激活 usb_storage.mount 單元,即自動掛載該設備。
2.[Device] 部分:
-
KernelMatchSubsystem=:匹配內核設備子系統,這裏是 block,意味着塊設備,涵蓋了硬盤、USB 存儲等。
-
KernelMatchAttributes=:使用 udev 屬性來精確匹配設備,如供應商 ID(idVendor) 和產品 ID(idProduct),這裏假定爲虛構的值,實際使用時需要根據具體設備查詢並替換。
3.[Install] 部分:
- WantedBy=:指定這個設備單元應該在哪個設備單元激活時啓動。在這個例子中,它與特定的設備文件(如 sda)相關聯,意味着當該設備被系統識別時,這個設備單元將被激活。
通過這樣的設備單元配置,當系統檢測到符合特定條件的 USB 存儲設備插入時,systemd 可以自動掛載它,或者執行其他定義好的操作,提供了對硬件事件響應的自動化機制。
掛載單元 mount
掛載單元(.mount)用於定義文件系統的掛載點及其掛載參數。這些單元允許 systemd 在系統啓動時自動掛載文件系統,並能夠管理這些掛載點的生命週期。下面是一個掛載單元的例子,用於自動掛載一個名爲 data-disk 的硬盤分區到 / mnt/data 目錄:
[Unit]
Description=Mount for Data Disk
Before=local-fs.target
[Mount]
What=/dev/disk/by-label/data-disk
Where=/mnt/data
Type=ext4
Options=noatime,nodiratime
[Install]
WantedBy=multi-user.target
這個. mount 單元的各個部分說明如下:
1.[Unit] 部分:
-
Description=:描述掛載單元的功能,這裏是用於數據磁盤的掛載點。
-
Before=:定義此掛載操作應在 local-fs.target 之前完成,確保文件系統掛載的正確順序。
2.[Mount] 部分:
-
What=:指定要掛載的設備或設備標識符。這裏使用了 / dev/disk/by-label/data-disk,意味着是通過磁盤標籤來標識設備,這種方式比直接使用設備節點更健壯,不易受設備名變動影響。
-
Where=:指定掛載點目錄,這裏是 / mnt/data。
-
Type=:指定文件系統的類型,這裏是 ext4。
-
Options=:掛載選項,noatime 和 nodiratime 告訴系統不要更新文件或目錄的最後訪問時間戳,可以減少 I/O 操作,提高性能。
3.[Install] 部分:
- WantedBy=:聲明這個掛載單元應該在 multi-user.target 目標下啓動,意味着在多用戶、非圖形界面的系統狀態下自動掛載這個文件系統。
通過這個掛載單元配置,每當系統進入 multi-user.target 狀態時,systemd 會自動掛載標籤爲 data-disk 的硬盤分區到 / mnt/data 目錄,且遵循指定的掛載選項。
路徑單元 path
路徑單元(.path)用於監控文件或目錄是否存在、是否發生變化,然後基於這些變化來觸發其他單元的操作。下面是一個路徑單元的例子,用於監控日誌目錄 / var/log/app_logs 下是否有新創建的日誌文件,並在檢測到新文件時重新加載 app_logger.service 服務,以確保日誌服務能處理新的日誌條目:
[Unit]
Description=Watch for new log files in /var/log/app_logs
[Path]
PathModified=/var/log/app_logs/*.log
[Install]
WantedBy=multi-user.target
這個. path 單元的各部分含義如下:
1.[Unit] 部分:
- Description=:簡述路徑單元的作用,這裏是監控特定目錄下的日誌文件變化。
2.[Path] 部分:
- PathModified=:指定要監控的路徑及其模式。這裏使用通配符 *.log 來監控 / var/log/app_logs 目錄下所有. log 文件的修改。當這些日誌文件被創建或修改時,systemd 會觸發關聯的動作。
3.[Install] 部分:
- WantedBy=:聲明此路徑單元應該在 multi-user.target 下啓動,意味着在多用戶、無圖形界面的系統狀態下啓用此監控。
爲了完整實現上述功能,還需要一個服務單元(.service)與之關聯,比如 app_logger.service,並且在該服務單元中使用適當的配置來響應路徑單元觸發的事件。例如,服務單元中可能會包含 ExecReload 指令來定義當路徑單元觸發時執行的重載命令。這樣,一旦 / var/log/app_logs 目錄中有新的日誌文件生成或修改,systemd 就會自動重新加載 app_logger.service,確保日誌處理邏輯能夠及時處理新日誌。
計時器單元 timer
計時器單元(.timer)在 Systemd 中用於安排服務單元或其他單元按指定的時間計劃執行。下面是一個. timer 單元的例子,該例設置了一個每天凌晨 3 點執行一次清理緩存任務的服務。
首先,需要有一個服務單元(如 cache-cleanup.service),定義實際執行的任務:
[Unit]
Description=Cleanup Cache Files
[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup_cache.sh
在這個例子中,cleanup_cache.sh 是一個腳本,負責執行實際的緩存清理操作。
接下來是對應的計時器單元(cache-cleanup.timer),用於定時觸發上述服務:
[Unit]
Description=Daily Cache Cleanup Timer
[Timer]
OnCalendar=*-*-* 03:00:00 # 每天凌晨3點執行
Persistent=true # 如果錯過執行時間,在下次機會立即執行
AccuracySec=1min # 執行時間的精度,這裏設置爲1分鐘
[Install]
WantedBy=timers.target
[Timer] 部分的設置解釋如下:
-
OnCalendar=--* 03:00:00:定義了執行時間,這裏設置爲每天的 03:00:00(即凌晨 3 點整)。
-
Persistent=true:如果因爲系統關閉或計時器未激活而錯過了執行時間,那麼在系統下次啓動或計時器被激活時立即執行。
-
AccuracySec=1min:指定了執行時間的容忍度,即計時器觸發的實際時間可能與設定時間最多相差的時間,這裏是 1 分鐘。
最後,通過 [Install] 部分的 WantedBy=timers.target,確保此計時器在系統啓動時被啓用。
要使這個計時器生效,你需要通過 Systemd 的命令行工具進行啓用和啓動操作:
sudo systemctl enable cache-cleanup.timer
sudo systemctl start cache-cleanup.timer
這樣設置後,每天凌晨 3 點,cleanup_cache.service 就會自動執行,完成緩存清理任務。
slice 單元
Slice 單元(.slice)在 Systemd 中用於組織和管理一組相關進程的資源分配,特別是通過 Linux 控制組(cgroups)來實現對 CPU、內存等資源的限制。下面是一個 Slice 單元的例子,展示瞭如何創建一個名爲 user-1000.slice 的 Slice,用於管理屬於用戶 UID 1000 的進程,並設置一些資源限制:
示例:用戶 Slice 單元 (user-1000.slice)
[Unit]
Description=Slice for User with ID 1000
[Slice]
MemoryMax=500M # 限制該Slice內所有進程的總內存使用量不超過500MB
CPUQuota=20% # 限制該Slice內所有進程的CPU使用率不超過20%
在這個例子中,.slice 單元定義了幾個關鍵的資源限制:
-
MemoryMax=500M:設置了該 Slice 內所有進程可使用的最大內存總量爲 500MB。
-
CPUQuota=20%:限制了該 Slice 內所有進程可使用的 CPU 時間比例,不超過單個 CPU 核心 20% 的計算能力。
創建這樣一個 Slice 單元后,可以通過將用戶會話或者特定服務綁定到這個 Slice 中,來實現對這些進程資源使用的集體管理。例如,你可以通過修改用戶的登錄服務(假設爲 user@.service 模板實例)來指定 Slice:
# 在相應的用戶服務單元(如默認的getty服務)中
[Unit]
...
PartOf=user-1000.slice
[Service]
...
或者,如果要手動將一個已運行的進程移動到該 Slice,可以使用 systemctl set-property 命令調整其控制組歸屬:
sudo systemctl set-property --user my_service.service Slice=user-1000.slice
配置文件
systemd 的配置文件主要是單元(Unit)文件,這些文件定義了系統如何管理不同的實體,如服務、掛載點、設備、sockets、計時器等。以下是幾個主要的目錄及其用途:
1./etc/systemd/system/:此目錄存放系統管理員自定義或修改的單元文件,以及通過軟鏈接指向 / lib/systemd/system / 或其他地方的默認單元文件。管理員在這裏放置的文件優先級最高,可以覆蓋默認設置。開機啓動服務的配置通常通過在此目錄創建軟鏈接到實際的單元文件實現。
2./usr/lib/systemd/system/:這個目錄包含所有預裝服務的默認單元文件。這些是由軟件包安裝時提供的,代表了服務的標準配置。它們的優先級低於 / etc/systemd/system / 目錄中的文件。
3.run/systemd/system/:此目錄用於存放系統運行過程中動態生成的服務腳本或臨時修改的單元文件,這些變化不會永久保存。這個目錄的優先級高於上述兩個目錄,意味着這裏的配置會覆蓋任何靜態配置。
4。/usr/local/lib/systemd/system/:某些本地編譯安裝的軟件可能會將服務單元文件放在這裏,優先級介於 / usr/lib/systemd/system / 和 / etc/systemd/system / 之間。
理解這些目錄的關鍵在於它們的優先級和用途:
-
lib/systemd/system/ 和 /usr/local/lib/systemd/system/ 存放的是系統或本地安裝的服務的標準配置。
-
/etc/systemd/system/ 用於系統管理員進行定製化配置,可以覆蓋默認設置。
-
/run/systemd/system/ 則用於臨時性的、即時生效的配置更改,適合在不希望永久改變配置時使用。
通過這些目錄的組織,systemd 允許系統管理員靈活地調整服務管理配置,同時保持了配置文件的清晰結構和可維護性。
常用命令
systemctl 是 Systemd 系統和服務管理器的主要命令行接口,它提供了一個統一的方式來管理 Linux 系統中的各種服務、系統狀態、以及相關的系統組件。
- 服務管理:
-
啓動服務:使用 systemctl start <服務名> 命令啓動指定的服務。
-
停止服務:使用 systemctl stop <服務名> 停止指定的服務。
-
重啓服務:使用 systemctl restart <服務名> 重啓服務。
-
查看狀態:通過 systemctl status <服務名> 查看服務當前狀態。
- 開機啓動管理:
-
啓用服務:systemctl enable <服務名> 設置服務爲開機啓動。
-
禁用服務:systemctl disable <服務名> 取消服務的開機啓動設置。
- 系統狀態查詢:
-
列出所有單元:systemctl list-units 顯示當前活躍的單元(服務、掛載點、sockets 等)。
-
查看單元文件狀態:systemctl list-unit-files 顯示所有單元文件的狀態(是否啓用)。
- 時間安排與定時任務:
- 計時器單元:通過 .timer 單元定義定時任務,如 systemctl start mytimer.timer。
- 資源管理:
-
Slice 單元:通過 .slice 單元組織和管理資源分配給一組進程。
-
資源限制:可以在 Slice 或服務單元中設置 CPU、內存等資源限制。
- 系統控制:
-
關機、重啓:systemctl poweroff 關閉系統,systemctl reboot 重啓系統。
-
目標管理:切換系統運行級別,如 systemctl isolate multi-user.target 進入多用戶命令行模式。
- 日誌查看:
- 服務日誌:使用 journalctl -u <服務名> 查看服務的日誌輸出。
- 配置重載:
- 重載配置:systemctl daemon-reload 重新加載 systemd 的配置文件,確保改動生效。
小結
systemd 作爲一個全面的系統和服務管理框架,通過其高度集成的設計和豐富的功能集,爲 Linux 系統帶來了更快的啓動速度、更高的服務管理效率和更細緻的系統控制能力。儘管它的引入曾引發過爭議,但隨着其在各大發行版中的廣泛應用,systemd 已成爲現代 Linux 系統服務管理的重要組成部分。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/FFVuD09kQcRBub5CWi0pEw