# Systemd - d for daemon - systemd也是一種**init系統**,所謂的init系統就是kernel啟動以後,會執行的**pid 1號程式** - OS啟動後需要啟動很多服務,最後才能進入可提供服務的狀態 * 如何知道有哪些服務?How to List/Enable/Disable/Start/Stop/Restart/Reload * 我們想確認一個服務是否正常查詢服務的log * 假設我自己想架一個簡單的網站,如何寫一個服務設定檔,在開機時自動啟動。假設啟動HTTP伺服器需要等網路連上線,我該怎麼寫相依性 * 如何使用systemctl 關機/重新開機 * systemd裡面那麼多的Target有什麼用?他們跟以前的runlevel有什麼關係,什麼是runlevel systemd還包含了一些服務,比較會用到的像是 - systemd-networkd (他和NetworkManager和netplan的關係是什麼) - systemd-resolved - systemd-timesyncd - systemd-hostnamed - systemd-journald ![](https://www.ruanyifeng.com/blogimg/asset/2016/bg2016030703.png) systemd也提供了對cgroup接口的封裝。cgroup是kernel提供用於控制資源和程式隔離的功能,透過cgroup才真正實現了容器化。無論是docker/containerd追溯到最後都是cgroup。你可以使用systemd-cgls或systemd-cgtop來觀察由systemd管理的容器 ## Systemd Linux 系統開機流程的最後(kernel 載入後),會啟動 Systemd,並由它啟動系統上的其他必要的 process,例如: - 開機後必須執行的程式(初始化系統資源、裝置)、系統必要的背景程式以及使用者安裝的 - 會持續執行的應用程式 (Server 端的軟體或是背景服務) Systemd 在開機流程結束後,會持續在背景執行,並監控、管理所有由它管理的系統資源,使用者也可以透過 Systemd 的 `systemctl` 指令操作、控制這些系統資源 - **優點** - 提供統一的管理介面和日誌系統 - **會管理相依性**,會依照正確順序啟動服務 - E.g., HTTP Server 要在 Network 之後啟動 - 可以**並行(concurrency)啟動多個服務**,當服務間沒有相依性,則可以同時啟動,加快啟動速度 - 使用 [cgroup](https://access.redhat.com/documentation/zh-tw/red_hat_enterprise_linux/6/html/resource_management_guide/ch01) 管理 process,可以控制所有分支出來的 process - 整合常用的服務和功能,使用者不需要自己安裝和設定,例如時間同步、日誌系統 (logger)、服務分析工具... - **缺點** - Systemd 相當龐大且複雜 - 高度依賴 Linux 上的某些功能,無法移植到其他平台 - cgroup - dBus - ... ### Unit - Systemd 管理的資源或服務稱為 unit - 每一個 unit 都有一個對應的 **unit file** 作為設定檔 - Systemd 會根據 unit file 的內容啟動每個 unit Unit 分為多個類型 (括號中的是對應的 unit file 副檔名) - **Service Units** (.service): 系統上持續運行的服務或應用程式 - SSH Server: `sshd.service` - Apache Server: `httpd.service` - **Socket Units** (.socket): 管理系統上的 socket,用於 process 之間的通信 - 本身不會啟動服務,而是監聽特定的 port,並轉發給對應的 service unit - **Target Units** (.target): 定義一組相關聯的 unit,並且可以一次啟動/停止這組 units - 將某些 unit 組合成一個群組,以便於管理 - 用來當作 synchronization point - **Path Units** (.path): 監控檔案、目錄的變化,並觸發其他的 unit - **Timer Units** (.timer): 定時執行的任務或服務 - **Device Units** (.device): 監控、管理硬體裝置 (*/dev* 底下的裝置) - **Mount Units** (.mount): 定義和管理掛載點, - **Automount Units** (.automount): 管理自動掛載的文件系統,只有在必要時才會掛載系統,減少資源使用 - **Swap Units** (.swap): 管理 swap 磁區 - **Slice Units** (.slice): 管理系統的資源 - **Scope Units** (.scope): 由 Systemd 自動產生的檔案 - **Snapshot Units** (.snapshot): 儲存 Systemd 本身的快照,讓 Systemd 可以隨時復原回某狀態 :::warning 在不同發行版上,支援的類型可能不同,執行 ``` systemctl -t help ``` 查看系統上支援的 unit 類型 ::: ### Unit File - Unit File 就是 unit 的設定檔 - 每個 unit file 對應一個由 Systemd 管理的 unit,其中包含一個 unit 的所有設定和資訊 - Unit file 的副檔名表示該 unit 的類型 - Unit file 通常放在兩個目錄中 - */usr/lib/systemd/system* - 通常是安裝 package 時,自動建置的 unit file - Package 在安裝時會把預設的 unit file 複製到該目錄中 - */etc/systemd/system* - 自訂服務的 unit file - 通常是一些由使用者手動建立 unit file ## systemctl 管理系統 - 重啟系統 (reboot) ``` systemctl reboot ``` - 關閉電源 (poweroff) ``` systemctl poweroff ``` - 會正確的執行關機流程 - 通常關機時用 `poweroff`,而不用 `halt` - 停止系統 (halt) ``` systemctl halt ``` - 通常來說,`halt` 的行為會和 `poweroff` 一樣 - 但實際的行為取決於系統的設定 - 進入睡眠模式 ``` systemctl suspend ``` - 目前系統的狀態會記錄在 RAM 中,並進入較低的功耗 (不會斷電) - 按下電源鍵,或是觸動鍵盤、滑鼠喚醒系統 - 喚醒速度快 - 但睡眠期間如果斷電或記憶體發生錯誤,無法恢復紀錄的系統狀態 (必須重新開機) - 進入休眠模式 ``` systemctl hibernate ``` - 目前系統的狀態會記錄在硬碟中,並且系統會斷電 - 按下電源鍵喚醒系統 - 喚醒速度慢 - 進入混和休眠模式 ``` systemctl hybrid-sleep ``` - 系統狀態會同時紀錄在硬碟和記憶體中,並進入低功耗模式 - 按下電源鍵,或是觸動鍵盤、滑鼠喚醒系統 - 一般情況喚醒速度快 - 如果發生過斷電或記憶體錯誤,仍可以從硬碟恢復系統狀態 - 進入救援模式 (單使用者模式) ``` systemctl rescue ``` ## systemctl 管理 Unit ### 列出所有 Unit - 列出已啟動的 Unit ```bash systemctl list-units # 或是 systemctl ``` - 列出所有 Unit ``` systemctl list-units --all ``` - 列出特定狀態的 Unit ``` systemctl list-units --all --state=<unit state> ``` - 可用的 `state`: active, inactive, activating, deactivating, failed - 列出某特定類型的所有 unit ``` systemctl list-units --type=<unit type> ``` - `<unit type>` 就是前面提到的 service、socket、target ... 輸出是以下格式 ``` UNIT LOAD ACTIVE SUB DESCRIPTION proc-sys-fs-binfmt_misc.automount loaded active running Arbitrary Executable File Formats File System Automount Point sys-devices-platform-serial8250-tty-ttyS0.device loaded active plugged /sys/devices/platform/serial8250/tty/ttyS0 sys-devices-platform-serial8250-tty-ttyS1.device loaded active plugged /sys/devices/platform/serial8250/tty/ttyS1 docker.service loaded active running Docker Application Container Engine finalrd.service loaded active exited Create final runtime dir for shutdown pivot root ⋮ ``` - **UNIT** - Unit 的名稱 - **LOAD** - 設定檔是否已載入 - **ACTIVE** - 啟動狀態 - **SUB** - 詳細的執行狀態,各個服務有自訂的數值 - **DESCRIPTION** - 服務的描述 ### 管理服務 管理服務的指令通常是以下格式 ``` systemctl <operation> <service name>.service ``` - 其中 `.service` 可以省略 #### 管理服務運行 - 啟動服務 ``` systemctl start <service> ``` - 停止服務 ``` systemctl stop <service> ``` - 重新啟動服務 ``` systemctl restart <service> ``` - 重新載入服務 ``` systemctl reload <service> ``` #### 管理開機設定 - 設定服務在開機時自動啟動 ``` systemctl enable <service> ``` - 取消服務在開機時啟動 ``` systemctl disable <service> ``` #### 查看服務狀態 - 查看服務的狀態 ``` systemctl status <service> ``` - 查看服務是否運作中、已啟動或是啟動失敗 ``` systemctl is-active <service> systemctl is-enabled <service> systemctl is-failed <service> ``` ## Systemd 內建的背景服務 - 屬於 Systemd 的一部分,並且以 **systemd unit** 的形式存在 - 可以用 `systemctl` 指令執行基本的管理 - 查看執行狀態、關閉、啟動、重啟 ... - 這些服務也都有自己對應的指令,讓使用者可以存取這些服務 ### systemd-networkd - 用於**控制網路介面和網路設定**的背景服務 - DHCP、靜態 IP 設定 - 虛擬網路設定 - 網卡設定 - 查看運行狀態 ```bash systemctl status systemd-networkd ``` - `networkctl` 是 systemd-networkd 的指令,用來執行網路相關的操作 ```bash # 查看 networkctl 的完整使用方式 networkctl --help # 啟用網卡 (等同 ifconfig <interface> up) networkctl up <interface> # 關閉網卡 (等同 ifconfig <interface> down) networkctl down <interface> # 向 DHCP server 取得新的 IP networkctl renew <interface> # 查看目前網路狀態 networkctl status ``` - systemd-networkd 的設定檔放在目錄 */etc/systemd/network* 底下 - 此目錄底下**可以有多個設定檔**,systemd-networkd 啟動時會**載入所有檔案** - 載入時會依照**檔名的字母順序排序** - 後載入的設定會**覆蓋之前的設定** - 設定檔的名稱可以自訂,但副檔名有三種 - `.link`: 網卡設定 - `.netdev`: 虛擬網卡設定 - `.network`: 網路連線設定 - [設定檔語法文件](https://systemd.network/systemd.network.html) - DPCH 設定範例 (.network) ``` [Match] Name=eth0 [Network] DHCP=yes ``` - `eth0` 是介面卡的名稱,設定時記得替換成要使用的介面 - 靜態 IP 設定範例 (.network) ``` [Match] Name=eth0 [Network] Address=192.168.10.50/24 Gateway=192.168.10.1 DNS=8.8.8.8 ``` - 重啟服務,載入新的設定 ```bash systemctl restart systemd-networkd # 或是 networkctl reload ``` :::success **netplan 和 systemd-networkd** - netplan 是**較高階的網路管理工具** - 用來產生對應目前系統的網路設定檔 - 使用 YAML 格式的設定檔案 - 支援 systemd-networkd、network manager 和 ifupdown - 當使用 netplan 設定網路時 - netplan 會自動把 YAML 格式的設定檔,轉換成對應底層的設定檔 - 會自動判斷使用的是 network manager、networkd 或是 ifupdown ::: :::info **Network Manager 和 systemd-networkd** - 兩者都是常見的網路管理工具,直接控制系統的網路介面 - 都可以 Systemd unit 的形式存在 - Network Manager - 支援圖形介面,常用在 desktop 環境 - 整合較多高階的功能 - WIFI、VPN ... - systemd-networkd - Systemd 環境中的網路管理工具,是 Systemd 的一部分 - 較輕量,常用在伺服器或是嵌入式環境 ::: ### systemd-resolved - 用來管理域名解析設定的服務 - 取代傳統 Linux 上的 NSS (name service switch) - DNS 相關的設定檔 - */etc/hosts* - 設定 hostname 和 IP 的對應關係 - 優先級較高 - 格式為 `<IP Address> <hostname>` ``` 127.0.0.1 localhost 127.0.1.1 ubuntu ``` - */etc/resolv.conf* - DNS server 的設定檔 - 在 */etc/hosts* 中找不到對應的 IP 時,會透過這些 DNS Server 查詢 - */etc/systemd/resolved.conf* - systemd-resolved 的設定檔 - systemd-resolved 的操作指令是 `resolvectl` ```bash # 查看完整使用方式 resolvectl --help # 查看目前 DNS 設定 resolvectl status # 查詢對應的 IP resolvectl query <domain name> # 反向查詢對應的 domain name resolvectl query <IP Address> # 清除快取 resolvectl flush-caches ``` ### systemd-timesyncd - 用來進行網路時間同步的服務 - timesyncd 的指令是 `timedatectl` ```bash # 顯示完整使用方式 timedatectl --help # 顯示目前時間資訊 timedatectl timedatectl status # 顯示完整資訊 timedatectl timesync-status # 設定系統時間 timedatectl set-time <TIME> # 設定系統時區 timedatectl set-timezone <ZONE> ``` ### systemd-hostnamed - 用來管理和存取 hostname、以及其他機器相關的 meta data 的服務 - 只在需要的時候被啟動 - hostnamed 的指令是 `hostnamectl` ```bash # 查看完整使用方式 hostnamectl --help # 顯示系統的相關資訊 hostnamectl hostnamectl status # 顯示 host name hostnamectl hostname # 設定 hostname hostnamectl hostname <NAME> hostnamectl set-hostname <NAME> ``` :::warning ***/etc/hosts* 不會被自動修改** - */etc/hosts* 中應該會有 hostname 對應 loopback IP 的設定 - 使用 `hostnamectl` 設定 hostname 時,*/etc/hosts* 的設定不會跟著修改,需要手動修改 ::: ### systemd-journald - Systemd 環境中的日誌服務,會記錄系統上的所有 log - 包含來自早期開機階段、kernel、系統背景程式的標準I/O、以及 syslog 的所有紀錄 - journald 的日誌檔案以壓縮過的 binary 格式儲存,只能用它的指令查看 - 預設設定下,紀錄只會保留一個月 - journald 的指令是 `journalctl` ```bash # 查看所有紀錄 journalctl ``` - `-f`: 只顯示最近的紀錄 - `-r`: 倒序顯示紀錄 (新的優先) - `-k`: 只顯示 kernel 的紀錄 - 透過 PID 可以查詢特定服務的 log - 先用 `systemctl status <UNIT>` 查詢 unit 的 PID - 用 `journalctl _PID=<PID>` 查詢