Product SiteDocumentation Site

章 9. Unix 服務

9.1. 系統啟動
9.1.1. systemd 啟動系統
9.1.2. System V 初始系統
9.2. 遠端登入
9.2.1. 安全遠程登入:SSH
9.2.2. 使用遠端圖形桌面
9.3. 管理權限
9.4. 管理介面
9.4.1. 管理網頁介面:webmin
9.4.2. 組態套件:debconf
9.5. syslog 系統事件
9.5.1. 原則與機制
9.5.2. 組態檔案
9.6. The inetd 超級伺服器
9.7. 以 cronatd 使用排定的工作
9.7.1. crontab 檔案的格式
9.7.2. 使用 at 命令
9.8. 排定非同步工作:anacron
9.9. 配額
9.10. 備份
9.10.1. 使用 rsync 備份
9.10.2. 供備份恢復系統
9.11. 熱插拔:hotplug
9.11.1. 介绍
9.11.2. 命名問題
9.11.3. udev 的運作
9.11.4. 具體的例子
9.12. 電源管理:進階組態與電源介面 (ACPI)
此章包括若干 Unix 系统共通的服務。管理員應熟悉他們。

9.1. 系統啟動

啟動電腦時,螢幕捲動的訊息表示正在自動處理起始化和組態的工作。需要改變此階段的作業時,就必須好好的理解他們。這正是本章的目的所在。
首先,BIOS 控制電腦,偵測磁碟機,載入 Master Boot Record,再執行啟動程式。然後,找到磁碟內的核心程式,載入並執行它。先初始化該核心,搜尋並載入包括根檔案系統的分割區,並執行第一個程式 — init。通常,此 “根分割區” 以及 init 命令祗在在 RAM 的虛擬檔案系統內 (所以被稱為,“initramfs”,舊稱 “initrd” 就是 “初始化 RAM 磁碟” 的意思)。通常經由硬式磁碟機或網路,讓啟動程式把此檔案系統載入記憶體。它包括核心所需的最少量 “真正” 的根檔案系統:足以驅動系統無法啟動的硬式磁碟機或其他裝置、或者初始化腳本與模組以建構 RAID 陣列,開啟加密分割區、啟動 LVM 等。一但掛上根分割區, initramfs 就把控制權交給真正的啟動程式,機器回到標準的啟動程序。
執行 systemd 的 Linux 機器的啟動程序

圖形 9.1. 執行 systemd 的 Linux 機器的啟動程序

9.1.1. systemd 啟動系統

此 “真正啟動” 是由 systemd 提供的,在本節說明該啟動系統。
Systemd 執行多個程序,設定系統:鍵盤、驅動程式、檔案系統、網路、服務等。同時全面檢視系統,以及必要的配件。每個配件都視為一個 “單元檔案” (有時為多個);通用的語法源自於常用的 “*.ini files“ 語法,包括配對的 key = value 列在 [section] 標頭內。單元檔案儲存在 /lib/systemd/system//etc/systemd/system/ 內;以多種風貌呈現,目前專注在 “服務” 與 “目標”。
systemd “服務檔案” 描述被 systemd 管理的程序。包括與舊型的 init-scripts 相同的資料,但以宣告 (同時較為簡潔) 的方式表述。Systemd 處理大量重複的工作 (啟動與終止程序、檢查其狀態、日註記錄、去除特權等),以及祗供特定程序使用的服務檔案。例如,以下是 SSH 用到的服務檔:
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=sshd.service
如上文所示,程式碼極少,祗有宣告。Systemd 管理顯示進度報表、追蹤程序、以及必要的重啟。
systemd 的 “目標檔案” 描述系統的現狀,包括可操作的服務。不妨視為相當於舊型的執行階段作業。其中一個目標是 local-fs.target;進入之後,系統的其他部份假設所有的在地檔案系統均己掛載並可近用。其他的目標包括 network-online.targetsound.target。目標的相依性可以列在目標檔案內 (於 Requires= 列) 或使用符號連結至在 /lib/systemd/system/targetname.target.wants/ 資料夾內的服務檔案。例如,/etc/systemd/system/printer.target.wants/ 包括一個連結至 /lib/systemd/system/cups.service;systemd 將確保 CUPS 已執行至 printer.target
單元檔案是宣告性的而不是腳本或程式,不能直接執行,祗能被 systemd 解譯;因些有些工具允許管理者與 systemd 互動且控制系統的狀態與其元件。
第一種這類工具是 systemctl。未使用參數執行時,它列出 systemd 已知的所有單元檔 (除了已經停用的),及其現況。systemctl status 則以更佳的角度檢視服務,以及相關的程序。若提供服務的名稱 (如 systemctl status ntp.service),則送回更多詳細的資料,以及與該服務有關的最後幾個日誌檔 (還有更多的)。
執行 systemctl start servicename.service 就能以人工方式啟動服務。同樣的,執行 systemctl stop servicename.service 就能停止已完成的服務;其他的次命令包括 reloadrestart
systemctl enable servicename.service (或 disable) 控制啟動服務 (即開機後自動啟動)。is-enabled 可以檢查服務的狀態。
systemd 重要的功能之一是包括登入的組件 journald。做為補充 syslogd 之類傳統登入系統的組件,但加入額外的功能包括在服務與其產生訊息間的正式連結,以及補捉由初始過程產生的錯誤訊息。在 journalctl 命令的協助下,稍後可顯示該等訊息。不需任何參數,它溢出系統啟動後發生的所有日誌訊息;不過很少用到它。多數時間,把它做為服務的辨識器:
# journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 10:08:49 CEST, end at Tue 2015-03-31 17:06:02 CEST. --
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Received SIGHUP; restarting.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:32 mirtuel sshd[1151]: Accepted password for roland from 192.168.1.129 port 53394 ssh2
Mar 31 10:09:32 mirtuel sshd[1151]: pam_unix(sshd:session): session opened for user roland by (uid=0)
另個有用的命令列旗標是 -f,用於指示 journalctl 繼續顯示溢出的新增訊息 (大部份是在 tail -f file 之內)。
若服務狀況不如預共,第一個步驟是以 systemctl status 檢查該服務是否真的已啟動;若沒有,則第一個命令給的訊息就不足以診斷問題之所在,檢查 journald 產生的日誌檔。例如,假設 SSH 伺服器未啟動時:
# systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
   Active: failed (Result: start-limit) since Tue 2015-03-31 17:30:36 CEST; 1s ago
  Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
  Process: 1188 ExecStart=/usr/sbin/sshd -D $SSHD_OPTS (code=exited, status=255)
 Main PID: 1188 (code=exited, status=255)

Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
# journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 17:29:27 CEST, end at Tue 2015-03-31 17:30:36 CEST. --
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Received SIGHUP; restarting.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:30:10 mirtuel sshd[1147]: Accepted password for roland from 192.168.1.129 port 38742 ssh2
Mar 31 17:30:10 mirtuel sshd[1147]: pam_unix(sshd:session): session opened for user roland by (uid=0)
Mar 31 17:30:35 mirtuel sshd[1180]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1182]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1184]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1186]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1188]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
# vi /etc/ssh/sshd_config
# systemctl start ssh.service
# systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
   Active: active (running) since Tue 2015-03-31 17:31:09 CEST; 2s ago
  Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
 Main PID: 1222 (sshd)
   CGroup: /system.slice/ssh.service
           └─1222 /usr/sbin/sshd -D
# 
檢查服務的狀態 (失敗) 後,再檢查日誌檔;它們會指出組態的錯誤。編輯組態檔並修正錯誤後,重啟服務,確認執行中。

9.1.2. System V 初始系統

System V 初始系統 (簡稱初始) 執行若干程序,根據 /etc/inittab 檔案的指令做事。第一個執行的程式 (對映於 sysinit 步驟) 是 /etc/init.d/rcS,一個執行在 /etc/rcS.d/ 資料夾內所有程式的腳本。
在這些裡面,可找到負責的程式:
  • 組態終端機的鍵盤;
  • 載入驅動程式:大部份的核心模組在偵測到硬體後由核心本身載入;其他的驅動程式在對應模組列在 /etc/modules 時,才自動載入;
  • 檢查檔案系織的完整性;
  • 掛載在地分區;
  • 組態網路;
  • 掛載網路檔案系統 (NFS)。
到了這個地步,init 接手並啟動執行階段預設的程式 (通常是執行階段 2)。它執行 /etc/init.d/rc 2,一個啟動列在 /etc/rc2.d/ 之內的所有服務並命名為 “S” 字母開頭。接著的兩位數,曾經做為服務啟動的順序,不過現在的預設啟動系統使用 insserv,根據腳本的相依性自動決定其先後順序。每個啟動腳本宣告的情況必須符合啟動或停止服務 (例如,必須在另個服務之前或之後啟動);init 再依此情況啟動它們。不再考慮靜態的腳本編號 (但仍需按相依性使用 “S” 及兩個數字與實際的腳本名稱)。通常,基本的服務 (諸如以 rsyslog 登入,或以 portmap 指定埠口) 先列出來,然後才是標準服務與圖形介面 (gdm3)。
這種以相依性為基礎的啟動系統可以自動重新編號,避免人工作業的繁瑣,且限縮可能的人為錯誤,因為其排序係依照參數而訂。另個優點是可以同時啟動多個互相獨立的服務,藉以加速啟動程序。
init 區隔多個執行階層,所以可以用 telinit new-level 命令切換。立即,init 在新的執行階層再次執行 /etc/init.d/rc。這個腳本可執行缺失的服務並停止不再用到的服務。為了做到這個程度,它參照 /etc/rcX.d 的內容 (X 代表新的執行階層)。以 “S” (表示開始 “Start”) 開始的腳本是將啟動的服務;以 “K” (表示砍掉 “Kill”) 開始的腳本是將停止的服務。腳本不會啟動已經在前個執行階層執行的服務。
預設,Debian 的 System V init 使用四個不同的執行階層:
  • 0 層,祗是暫時的,電腦進入關機程序。所以,祗包括若干 “K” 腳本。
  • 1 層,也稱為單一使用者模式,對應於系統的降級模式;祗包括基本服務,並試圖維護與一般使用者非必要的運作。
  • 2 層是標準運作,包括網路服務、圖形介面、使用者登入等。
  • 6 層類似 0 層,除了在重開機之前先執行關機。
其他的階層,尤其是 3 至 5 階。它們預設的組態等同於階層 2,但是管理者可以修改它們 (在對應的 /etc/rcX.d 資料夾新增或刪除腳本) 以適應特定的需求。
以 System V init 執行 Linux 的啟動程序

圖形 9.2. 以 System V init 執行 Linux 的啟動程序

/etc/rcX.d 資料夾內的腳本祗是符號連結 — 安裝套件時由 update-rc.d 程式產生 — 指向儲存在 /etc/init.d/ l裡的實際腳本。管理者可以使用調整後的參數重新執行 update-rc.d 以微調運行層級的服務。The update-rc.d(1) 手冊詳細地描述其語法。請注意移除所有的符號連結 (使用 remove 參數) 不是停用該服務的好方法。應該是,在特定的執行層級組態其為不啟動 (在前個執行層級已有的服務應保留對應的呼叫停止它)。因為 update-rc.d 介面有點麻煩,建議使用較為友善的 rcconf (從 rcconf 套件取用) 介面。
最後,init 啟動虛擬終端機 (getty) 的控制程式。顯示提示符號,等待使用者名稱,然後執行 login user 啟始一個程序。