熱門分類
載入中…
目錄0%

🐧 Linux systemd 深入解析與啟動流程管理

    🐧 Linux systemd 深入解析與啟動流程管理

    在現代 Linux 發行版中,systemd 幾乎是預設的初始化系統(init),負責 開機流程服務管理日誌定時任務資源控制 等工作。本文從 啟動鏈單元(unit)設計排錯安全強化最佳實務,帶你完整掌握。

    📑 目錄

    一、開機啟動鏈(Boot Chain)

    1. Firmware/UEFI → Bootloader(GRUB):載入核心與 initramfs。
    2. kernel:掛載 root、啟動 PID 1(systemd)。
    3. systemd:解析預設 target(多使用 default.target 指向 graphical.targetmulti-user.target)。
    4. 依賴解析:依單元(unit)間的 Requires/WantsBefore/AfterConflicts 執行。
    # 查看目前預設 target 與切換
    systemctl get-default
    sudo systemctl set-default multi-user.target
    sudo systemctl isolate rescue.target    # 立即切到維護模式

    二、Unit 基礎:類型、目標與依賴

    常見單元類型:

    • service:常駐或一次性服務。
    • socket:socket-activated 服務(按需啟動)。
    • timer:取代或補強 cron 的排程。
    • target:一組單元的集合(階段或狀態)。
    • path:檔案/目錄變動觸發。
    • mount/automountdevice:掛載或裝置事件。
    # 查依賴與執行關係
    systemctl list-dependencies multi-user.target
    systemctl cat sshd.service
    systemctl status NetworkManager.service

    三、Service 設計:Type、Restart、Environment

    Type 影響 systemd 判定「服務已就緒」的方式:

    • simple(預設):主行程不 daemonize。
    • forking:行程 fork() 後在背景常駐(傳統 daemon)。
    • notify:程式透過 sd_notify 告知「就緒」。
    • oneshot:一次性任務,常搭配 RemainAfterExit=yes
    範例:穩定自動重啟的常駐服務
    [Unit]
    Description=My Web App
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    User=www-data
    WorkingDirectory=/opt/myapp
    ExecStart=/usr/bin/python3 /opt/myapp/app.py
    Restart=on-failure
    RestartSec=3
    Environment="ENV=prod" "PORT=8080"
    # 安全建議(見下節 Hardening)
    NoNewPrivileges=true
    PrivateTmp=true
    ProtectSystem=full
    ProtectHome=true
    
    [Install]
    WantedBy=multi-user.target

    四、覆寫與 Drop-in:不動原檔也能客製

    不要直接改套件提供的 /usr/lib/systemd/system/*.service。改用覆寫:

    sudo systemctl edit myapp.service   # 會在 /etc/systemd/system/myapp.service.d/ 建置 drop-in
    # 編寫內容(只放差異):
    [Service]
    Environment="DEBUG=false"
    Restart=always

    套用並查看:

    sudo systemctl daemon-reload
    sudo systemctl restart myapp.service
    systemctl cat myapp.service

    五、Timer vs cron:事件式排程的優勢

    • 與 service 綁定:排程觸發對應 service,管理一致。
    • 支援搖晃時間(RandomizedDelay):避免尖峰。
    • 缺漏補跑(Persistent):機器關機期間的任務會補執行。
    範例:每天 02:15 執行備份,若錯過則開機補跑
    # /etc/systemd/system/backup.service
    [Unit]
    Description=Nightly Backup
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/backup.sh
    
    # /etc/systemd/system/backup.timer
    [Unit]
    Description=Run backup daily
    
    [Timer]
    OnCalendar=*-*-* 02:15:00
    Persistent=true
    RandomizedDelaySec=120
    
    [Install]
    WantedBy=timers.target
    
    # 啟用
    sudo systemctl enable --now backup.timer
    systemctl list-timers --all

    六、Socket/Path/Device 啟動:按需載入

    socket 啟動讓服務在連線發生時再啟用,降低常駐資源。

    # 觀察 socket 與對應 service
    systemctl list-sockets
    systemctl status ssh.socket

    七、日誌與開機分析:journalctl 與 systemd-analyze

    # 只看本次開機、重要等級以上
    journalctl -b -p warning
    
    # 追服務日誌(即時)
    journalctl -u myapp.service -f
    
    # 啟動耗時總覽與關鍵鏈
    systemd-analyze
    systemd-analyze blame
    systemd-analyze critical-chain
    
    # 產生 SVG(於桌面開啟檢視)
    systemd-analyze plot > boot.svg

    八、資源控制與沙箱:cgroups 與 Hardening

    • CPU/記憶體限制CPUQuota=50%MemoryMax=1G
    • 沙箱化選項NoNewPrivileges=truePrivateTmp=trueProtectSystem=fullProtectHome=trueCapabilityBoundingSet=
    • 臨時服務systemd-run --scope / --unit 快速掛限制跑任務。
    # 以 50% CPU、1G 記憶體限制執行任務
    sudo systemd-run --unit=limit-job --scope -p CPUQuota=50% -p MemoryMax=1G /usr/bin/some-task

    九、常見錯誤與排查清單

    • 服務啟動卡住:檢查 After=network-online.target 是否缺 Wants=network-online.target;確認 systemd-networkd-wait-online 或 NetworkManager 連線等待設定。
    • 權限問題:服務 User= 指定用戶之檔案/目錄權限(參考 chmod/chown 基礎)。
    • 路徑未就緒:使用 path unit 或在 ExecStartPre 加入檢查/建立。
    • Daemonize 與 Type 不符:傳統 daemon 設 Type=forking,否則 systemd 誤判狀態。
    • 錯誤復發:設定 Restart=on-failureRestartSec=,並加強日誌分析(journalctl -xeu)。

    十、實用 Recipes(可直接套用)

    🧩 1) 服務需等「網路可用」再啟動
    [Unit]
    After=network-online.target
    Wants=network-online.target
    🧩 2) oneshot 初始化 + 常駐服務串聯
    # init.service 做準備;myapp.service 真正啟動
    [Unit]
    Description=Initialize directories
    Before=myapp.service
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/init_dirs.sh
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
    🧩 3) 自動重啟並限制重試頻率
    [Service]
    Restart=on-failure
    RestartSec=3
    StartLimitIntervalSec=60
    StartLimitBurst=5
    🧩 4) 硬化一個網頁服務(最小特權)
    [Service]
    User=www-data
    NoNewPrivileges=true
    PrivateTmp=true
    ProtectSystem=full
    ProtectHome=true
    CapabilityBoundingSet=
    AmbientCapabilities=
    ReadWritePaths=/var/lib/myapp

    最後更新:2025-10-23 · 作者:WWFandy

    🔗 分享這篇 LINE Facebook X

    沒有留言:

    字級