返回部落格

如何設定 Linux 服務在重新開機或系統崩潰後自動啟動:第二部分(理論說明)

如何設定 Linux 服務在重新開機或系統崩潰後自動啟動:第二部分(理論說明)

在這份由兩部分組成的教學之第二部分中,關於設定 Linux 服務在重新啟動或系統崩潰後自動啟動的教學中,我們將詳細討論 init 系統。您可以參考 本系列的第一部分:如何設定 Linux 服務在重新啟動或系統崩潰後自動啟動:此處的實際範例.

本教學將偏重於理論。因此,您應該將其作為參考,以更深入地了解 init 系統在 Linux 中的運作方式。在本教學的第一部分中,我們分享了一些 init 系統在啟動時會讀取的程式碼片段和啟動指令碼。我們還使用了 MySQL 作為範例,學習如何啟用和停用 Linux 服務以在崩潰或重新啟動後自動啟動。正如您在這份由兩部分組成的教學的第一部分中所學到的,在不同的 Linux 發行版中使用了三種 init 系統:System V、Upstart 和 Systemd。您可以參考 本教學的第一部分,以了解設定為使用特定 init 系統的發行版和版本.

在本教學中,我們將解釋我們在教學第一部分中使用的程式碼。我們將詳細說明 init 系統使用的指令和設定檔。讓我們開始吧!

先決條件

在這份由兩部分組成的教學的第一部分結論中,我們提到您應該保持這三台測試伺服器運行。如果您已經刪除了它們,您可以返回並重新建立它們。這將有助於您跟隨本教學。您應該擁有的三台測試伺服器是:

  • Ubuntu 9.04 及更早版本,或 Debian 6 x64(我們將用它來演示 System V init 系統)
  • Ubuntu 14.04 x64(我們將用它來演示 Upstart)。這是一份 關於如何輕鬆設定您的 Ubuntu 伺服器的教學.
  • CentOS 7 x64(我們將用它來演示 Systemd)。

在您將用於執行指令的每台伺服器上,您應該要有一個具有 sudo 權限的使用者。這份 關於設定 Linux sudoers 檔案的教學可以引導您.

注意:教學中的指令會干擾系統服務。因此,您不應該在實際運作的生產伺服器上套用它們。

執行等級

一個 執行等級 是一個操作等級,描述了 Linux 系統相對於可用服務的目前狀態。這個概念源於 System V init。當 Linux 系統啟動時,它會初始化核心,進入一個執行等級,並執行與該執行等級關聯的啟動指令碼。您在啟動時只能執行一個執行等級。

執行等級的其他範例包括關機狀態、重新啟動模式、單一使用者模式等。每個等級決定在該狀態下要執行哪些服務。某些服務可以在多個等級上執行,而其他服務則不行。

共有七個執行等級:從 0 到 6。以下是這七個執行等級的定義:

  • 執行等級 0:系統關機
  • 執行等級 1:單一使用者和救援模式
  • 執行等級 2、3、4:啟用網路的多使用者和文字模式
  • 執行等級 5:多使用者、啟用網路和圖形模式
  • 執行等級 6:系統重新啟動

執行等級不一定按順序執行。執行等級 2、3 和 4 因您運行的 Linux 發行版而異。您可以在某些發行版中實作執行等級 4,而在其他發行版中則不行。當您啟用服務以自動啟動時(如第一部分所述),您實際上已將其新增至某個執行等級。在 System V 中,作業系統以特定的執行等級啟動,並且在啟動期間,它會嘗試啟動與該執行等級關聯的所有服務。執行等級在 Systemd 中是目標(targets),我們將在 Systemd 章節中討論。

Init 和 PID 1

init 系統是 Linux 系統啟動且核心載入到記憶體時執行的第一個處理程序。它執行各種任務,包括確定使用者處理程序或系統服務將如何載入、以何種順序載入,以及是否應該自動啟動。在每個 Linux 發行版中,每個處理程序都由處理程序識別碼 (PID) 識別,而 init 的 PID 為 1。它是系統啟動時陸續啟動的所有其他處理程序的父處理程序。

init 的歷史

在最近的 Linux 發行版中發現的 init 系統是對原始系統的改進。最早期的 Linux 發行版版本使用 System V init,這在 Unix 系統 中也有類似的使用。隨著 Linux 的演進,Upstart init 守護行程被實作出來——它是由 Ubuntu 建立的。現在(在撰寫本教學的 2021 年),我們有了 Systemd init 守護行程——它最早是由 Fedora 實作的。隨著 Linux 系統持續演進,可能會出現更新的 init 系統。在本教學中,我們將討論這三個系統:System V、Upstart 和 Systemd。

最近的 Linux 版本預設配備 Systemd init 系統。然而,為了向後相容性,它們保留了其他較舊的 init 系統。您可以在其他 Linux 變體中使用 System V 的不同實作。例如,UNIX 的變體 FreeBSD 使用 BSD init。較舊版本的 Debian 使用 SysVinit。兩者都源自 System V。

每個版本的 init 守護行程管理服務的方式都不同。每個版本中加入的改進都旨在建立一個強大的服務管理工具,以處理 Linux 系統所需的一切,包括服務、裝置、連接埠和其他資源。當時需要一個強大的系統,能夠並行載入資源,並能從系統當機中優雅地復原。

System V Init 順序

System V 利用 inittab 檔案來儲存初始化指令。Upstart 保留了 inittab 檔案以實現向後相容。以下是 System V 的啟動流程:

  • init 系統來自二進位檔案 /sbin/init.
  • 一旦 init 系統載入到記憶體中,它會讀取其第一個檔案,位於 /etc/inittab.
  • 此檔案中的其中一個項目決定了機器應該啟動進入的執行等級(runlevel)。例如,如果將執行等級的值指定為 5,Linux 將在啟用網路的情況下以多使用者、圖形模式啟動(這在專為桌面使用設計的發行版中很常見)。此處指定的執行等級稱為預設執行等級,因為它將始終被使用。
  • 然後,init 系統會進一步查看 /etc/inittab 檔案,並讀取該執行等級需要執行的 init 指令碼。

透過尋找在特定執行等級下要執行的指令碼,init 系統將找到它需要啟動的服務。這些 init 指令碼通常是您為個別服務設定啟動行為的地方,就像我們在本教學第一部分中設定 MySQL 服務的方式一樣。

System V Init 指令碼結構

在本節中,我們將詳細介紹 init 指令碼。System V 設定檔或 init 指令碼是控制服務的工具。Init 指令碼初始化服務,因此得名 init 指令碼。

每個服務都有自己的 init 指令碼。例如,MySQL init 指令碼控制 MySQL 伺服器。應用程式廠商為其特定應用程式提供 init 指令碼,而原生 Linux 服務則隨作業系統安裝一起提供。當您建立自訂應用程式時,您也可以為其建立自己的自訂 init 指令碼。

要啟動像 MySQL 伺服器這樣的服務,首先會將其二進位程式載入到記憶體中。根據其設定,該程式可能會繼續在背景執行以持續接受用戶端連線。該服務的 init 指令碼負責啟動、停止或重新載入二進位應用程式。System V 中的 init 指令碼是 shell 指令碼。它們的另一個名稱是 rc (run command) 指令碼。

System V 目錄結構

init 指令碼的父目錄是 /etc 目錄。而 /etc/init.d 目錄是 init shell 指令碼的實際目錄。這些指令碼會以符號連結(symlink)的方式連結到 rc 目錄。

/etc 目錄下有幾個 rc 目錄,每個目錄的名稱中都有一個數字。這些數字代表不同的執行等級。如果您列出該目錄的內容,您會看到類似以下的名稱:/etc/rc0.d, /etc/rc1.d, /etc/rc2.d 等。

如果您檢視每個 rc 目錄的內容,您會看到以 KS 在它們的檔案名稱中,後面跟著兩個數字。這些檔案包含指向實際程式之實際 init shell 腳本的符號連結。字母 KS 是縮寫:K 代表 Kill 或 Stop,而 S 代表 Start。檔案名稱中的兩個數字代表執行順序。如果您看到一個名為 K05script_name 的檔案,它會在名為 K09script_name.

啟動

隨著啟動順序的進行,讓我們來看看 init 腳本是如何被呼叫的。

S 和 K 腳本並非由 init 系統直接呼叫。相反地,它們是由另一個腳本呼叫的:即 /etc/init.d/rc 腳本。 /etc/inittab 檔案會指示 init 守護行程系統預設應該在什麼執行等級下啟動。根據指定的執行等級,/etc/inittab 檔案中的某一行會呼叫 /etc/init.d/rc 腳本,並將預設執行等級作為參數傳遞。使用此參數,該腳本將呼叫對應 /etc/rcN.d 目錄,其中 N 表示執行等級。例如,如果伺服器以執行等級 5 啟動,則會呼叫對應 /etc/rc5.d 目錄。

rc 目錄內,所有 K 腳本都會依數字順序執行,並帶有參數 stop,而所有 S 腳本也以類似方式執行,並帶有 start 參數。/etc/rcN.d 符號連結將分別以 stopstart 參數呼叫。

簡單來說,每當 Linux 系統進入或切換到某個執行等級時,就會執行某些腳本來停止某些服務,同時執行其他腳本來啟動其他服務。這個程序可確保在給定的 Linux 狀態下,任何不應該執行的行程都會被停止,而任何應該執行的行程都會自動啟動。

System V 自動啟動

當您啟用某個服務在開機時自動啟動時,您就是在直接修改 init 的行為。例如,如果您將某個服務設定為在執行等級 2 自動啟動,則 init 程序會在 /etc/rc2.d 目錄中建立適當的符號連結。為了幫助您理解,我們將用一個範例來進行說明。

System V 範例

為了給您一個實際的範例,我們將使用第 1 部分中的 MySQL 服務設定。因此,請使用 ssh(如果您使用的是 Windows,則使用 putty)以您的 sudo/root 使用者登入 Debian 6 VPS,並繼續執行以下步驟。

步驟 1:開啟並檢查 inittab 檔案

首先,在終端機輸入以下指令以檢視 inittab 檔案的內容:

檔案內容應該類似如下:

數字 2 表示系統啟動時的執行等級。在這種情況下,執行等級 2 是預設值,因此此 Debian 系統將在執行等級 2 中以多使用者、文字模式啟動。您可以執行以下指令來確認:

它將顯示類似以下的輸出:

步驟 2:檢查 rc 目錄

接下來,要列出 rc 目錄,請執行以下指令:

這是輸出的螢幕截圖:

root screenshot

正如我們之前在 inittab 檔案中看到的,系統設定為在 執行等級 2 中開機,因此 /etc/rc2.d 下的腳本將在系統啟動時執行。您可以使用以下指令列出此目錄的內容:

從輸出中可以看出,這些檔案只是指向 /etc/init.d 下實際腳本檔案的符號連結。以下是輸出的片段:

service crash 1

此目錄中沒有 K 腳本,只有 S (start) 腳本。這些腳本將啟動此處連結的服務,例如 rsync。您還可以注意到列出的 mysql 服務,我們將在下一個子主題中討論它。

步驟 3:檢查 Init 腳本

當安裝與 System V 相容的服務時,它會在 /etc/init.d 目錄下建立一個 shell 腳本。您可以輸入以下命令來檢查 MySQL shell 腳本是否可用:

它會顯示以下輸出:

screenshot output

該檔案相當大。您可以輸入以下命令來查看其內容:

步驟 4:使用 chkconfig 或 sysv-rc-conf

Chkconfig 是您可以在基於 RHEL 的發行版(例如 )中使用的命令,CentOS 用來啟用或停用與 System V 相容的服務。您也可以使用它來列出已安裝的服務及其各自的執行等級(runlevel)。以下是該命令(適用於 CentOS):

在 Debian 發行版中,原生並不存在此類公用程式。Debian 系統中的 update-rc.d 僅從執行等級中安裝和移除服務。您可以使用一個自訂工具將 chkconfig 功能引入 Debian 系統。輸入以下命令來安裝它:

安裝完成後,您可以執行以下命令來查看各種服務的執行等級行為:

此命令的輸出格式化為一個表格,左側顯示服務名稱,以及該服務在何種執行等級下執行:

service crash 2

X 表示該服務將在該執行等級下執行。此工具允許您使用方向鍵和空白鍵來啟用或停用特定執行等級的服務。要退出該工具,請按 Q。

步驟 5:測試系統開機時的 MySQL 啟動行為

從上方的螢幕截圖中,您可以看到 mysql 服務在執行等級 2,3,4,5 上已啟用。您可以使用以下命令停用 MySQL:

輸出如下所示。請注意,該服務已在所有執行等級中停止:

service crash 3

執行以下命令以查看該目錄的內容:

請參閱下方輸出中的 mysql 行:

輸出顯示符號連結(symlink)已變更為 K,代表 Kill(停止)。因此,在執行等級 2 下,MySQL 預設不會自動啟動。每當您在 System V 中啟用或停用服務時,就會發生這種情況。只要服務的預設執行等級目錄下存在 S(啟動)腳本,init 守護行程(daemon)就會在系統開機時啟動該服務。

要再次啟用該服務,請輸入以下命令:

步驟 6:測試系統當機後的 MySQL 啟動行為

在本節中,我們將討論 System V 如何處理服務當機。您可以使用這些知識來設定自訂服務在當機後的行為。

在本教學的第一部分中,我們修改了 /etc/inittab 檔案,以使 MySQL 在當機後能自動啟動。我們新增了以下行來啟用此行為:

我們可以透過一些測試來檢查此行為。首先,輸入以下命令重新啟動您的 VPS:

重新啟動後,檢查 mysql_safe 和 mysqld 正在以哪些程序 ID(PID)執行,輸入以下命令以獲取程序 ID:

我們得到的輸出為:

請注意進程 ID。在我們的案例中,它是 1836 和 186338。現在,透過輸入以下命令並使用 -9 參數終止進程來模擬當機。請記得替換為您的進程 ID:

幾分鐘後,執行以下命令來檢查 MySQL 的狀態:

輸出結果顯示 MySQL 正在運行,這意味著它在模擬當機後已重新啟動。如果您再次執行 ps -ef | grep mysql 命令,您會發現 mysqld_safemysqld 進程都在運行,儘管它們擁有新的 ID。

您可以嘗試多次終止這些進程,它們會在幾分鐘後重新啟動。這種行為是透過我們在 /etc/inittab 檔案中新增的那一行來實現的。這就是在 System V 中設定服務在當機後自動重啟的方法。若要再次查看語法,請參閱本教學的第一部分。

某些自訂服務可能存在錯誤,在多次重試後仍無法重新啟動。init 守護進程會嘗試重新啟動服務,但如果它在兩分鐘內失敗超過十次,Linux 系統將會停用該服務最多 5 分鐘。這有助於保持系統穩定,並確保系統資源不會浪費在不斷當機的服務上。建議您檢查系統日誌,以找出自訂應用程式中需要修復的問題。

Upstart 簡介

長期以來,System V init 系統對 Linux 發行版至關重要。然而,科技是不斷進步的。得益於開源社群的支持,Linux 生態系統蓬勃發展。System V 以序列化方式載入工作和服務,這帶來了複雜性且耗費時間。此外,現代可插拔儲存媒體的引入(而 System V 設計之初並未考慮到這一點),也推動了對不同 init 系統的需求。

Ubuntu 的開發人員開始著手開發另一個初始化系統。這個 init 系統旨在加快作業系統的載入速度、確保當機服務的正常清理、保持系統服務之間的依賴關係可預測,並兼顧可插拔儲存媒體。Upstart 守護進程因而誕生。

與 System V init 相比,Upstart init 具有以下幾項優勢:

  • Upstart 不會像 System V 那樣序列化地載入服務,從而縮短了系統的開機時間。
  • 它的設計能更好地處理當機的服務,提供正常的清理和服務重新啟動。
  • Upstart 使用靈活的事件系統,以自訂服務在各種狀態下的處理方式。
  • 此 init 避免了像 System V 那樣用於載入和管理服務的複雜 shell 腳本。Upstart 使用簡單、易於理解和修改的設定檔。
  • Upstart 在設計時就考慮到了向下相容性。/etc/init.d/rc 腳本仍會執行以管理原生的 System V 服務。
  • 它避免了保留指向同一個腳本的冗餘符號連結。

Upstart 事件

Upstart 是基於事件的,允許將多個事件與同一個服務關聯。這種基於事件的架構確保了靈活的服務管理。每個事件都可以呼叫針對該事件的特定 shell 腳本。

Upstart 事件包括:

  • Starting
  • Started
  • Stopping
  • Stopped

在事件之間,服務可以處於各種狀態,包括但不限於:

  • Waiting
  • Pre-start
  • Starting
  • Post-start
  • Running
  • Pre-stop
  • Stopping
  • Post-stop

Upstart init 可以設定為針對這些狀態中的每一種採取行動,因此其設計非常靈活。

Upstart Init 啟動順序

Upstart init 在啟動時會執行 /etc/init.d/rc 腳本,就像 System V 一樣。此腳本會正常執行任何 System V init 腳本,以確保向下相容性。

Upstart 設定檔位於 /etc/init 目錄中,因此它預設會在該處尋找,並執行該目錄下設定檔中的 shell 命令。

Upstart 設定檔

與 System V 中使用的 bash 腳本不同,Upstart init 使用服務設定檔來控制服務。這些服務設定檔的命名標準為 service_name.conf.

這些檔案包含純文字內容,並分為多個稱為 stanza(段落)的區段。每個 stanza 描述服務的不同狀態及其行為。不同的 stanza 控制服務的不同事件。例如:waiting、pre-start、start、pre-stop、stopping 等。

一個 stanza 包含 shell 指令,這使得為每個服務的每個事件啟動多個動作成為可能。此外,每個服務設定檔都指定了以下兩件事:

  • 服務應該在哪些執行等級(runlevel)啟動和停止。
  • 如果服務崩潰,是否應該重新生成(respawn)。

Upstart 目錄結構

Upstart 服務設定檔位於 /etc/init 目錄下。請勿將其與 /etc/init.d.

Upstart 範例

在此範例中,我們將了解 Upstart 如何在系統開機期間以及發生崩潰時處理服務。我們將更詳細地解釋本教學第一部分中所示的實際範例。

步驟 1:登入 Ubuntu 14.0.4 伺服器

首先,為了測試 Upstart,我們將使用第二台 VPS,即執行 Ubuntu 14.0.4 的那台。這是因為該 Linux 發行版原生實作了 Upstart。如果您使用的是 Windows,請使用 ssh 或 putty。您必須使用具有 root 或 sudo 權限的使用者登入。我有一個名為 hackins 的使用者,以下是我的登入方式:

請替換為您的 root/sudo 使用者和伺服器的公用 IP 位址。然後,按下 Enter 鍵,並提供密碼或密碼短語。

步驟 2:檢查 init 和 rc 目錄

Upstart 設定檔儲存在 /etc/init 目錄中。這是您在建立新服務設定檔時將使用的目錄。

若要列出 /etc/init 目錄中的設定檔名稱,請執行以下指令:

正如您從上述指令的輸出中看到的,許多服務都在 Upstart 下執行。按 Q 鍵退出 less。

如果您執行以下指令來列出 rc 目錄中 System V 的服務設定檔,您只會看到幾個:

步驟 3:檢查 Upstart 檔案

在本教學的第一部分中,我們使用了一個 mysql.conf 檔案來學習伺服器設定。為了增加我們的知識,讓我們使用不同的設定。 cron 設定檔是一個不錯的選擇。輸入以下指令以開啟該檔案:

您應該會得到類似於下方螢幕截圖的輸出:

screenshot 4

該腳本非常簡單。請注意以下重要欄位:start on, stop on, fork,以及 respawn。讓我們來定義這些指令的作用:

  • start on 指示 Ubuntu 在系統進入執行等級 2,3,4 或 5 時啟動 cron 守護行程(daemon)。它不會在未在此處指定的其他執行等級上執行,即 0,1 或 6。
  • stop on 指示 Ubuntu 停止執行中的守護行程。然而,在這種情況下,有一個驚嘆號(!),這是一個否定符號。該腳本不應在驚嘆號後面的執行等級停止:2,3,4,5。
  • fork 指令指示 Upstart 將行程與主控台分離,並使其在背景中繼續執行。
  • respawn 指令指示系統在 cron 因任何原因崩潰時自動將其重新啟動。

按下 Ctrl X 鍵退出編輯器,無需輸入任何內容。

其他 Upstart 設定檔也遵循相同的結構,包含用於 start、stop 和 respawn 的 stanza。某些設定檔可能具有額外的指令碼區塊,用於 pre-start、pre-stop、post-start 等。這些程式碼區塊告訴系統當行程處於任何定義的狀態時要執行什麼。

步驟 4:測試系統開機後 MySQL 服務的啟動行為

MySQL 預設設定為系統啟動後自動執行。我們將嘗試停用它並觀察其行為。在 Upstart 中,可以透過建立一個名為 service_name.override 的檔案,位於 /etc/init/ 目錄下來停用服務。該檔案的內容只有一個單字:manual.

讓我們看看如何使用此命令來停用 MySQL 服務。輸入以下命令以使用 nano 編輯器開啟該檔案:

在開啟的檔案中加入以下行:

按下 Ctrl + O 儲存變更,然後按 Enter。按下 Ctrl + X 退出編輯器。執行以下命令重新啟動伺服器:

等待幾分鐘,然後重新登入。重新登入後,輸入以下命令測試 MySQL 服務的狀態:

輸出將顯示該服務未在執行:

這表示 MySQL 在系統啟動後沒有自動啟動。接下來,開啟 MySQL 設定檔並檢查 start 指令是否已變更:

輸出將顯示沒有任何變更:

這意味著如果您的服務沒有自動啟動,而您只檢查該服務的設定檔(service_name.conf),您可能找不到錯誤。您還應該檢查目錄中是否存在 service_name.override 檔案。

輸入以下命令刪除 override 檔案並重新啟用 MySQL 服務。然後,重新啟動伺服器:

伺服器啟動後,再次測試 MySQL 服務的狀態:

它應該會顯示 MySQL 服務已自動啟動。

步驟 5:測試系統崩潰後 MySQL 服務的啟動行為

預設情況下,如果 MySQL 服務崩潰,它會自動重新啟動。要停止此行為,我們將編輯 mysql.conf 檔案。輸入以下命令以使用 nano 編輯器開啟該檔案:

尋找 respawn 指令行,並使用以下方式將其註解掉:#:

執行以下命令以重新啟動服務:

我們使用上述命令來停止和啟動服務,因為在這裡使用 initctl restartinitctl reload 將無法運作。當您執行啟動 MySQL 服務的命令時,輸出將顯示 MySQL 的 PID,例如:

我們的 PID 是 1439。接下來,記下您執行命令時獲得的 PID,我們將在下一步中使用它。要模擬崩潰,請使用以下命令終止 MySQL 程序,請記住按照上述說明替換您的 PID:

要檢查 MySQL 是否在崩潰後重新啟動,請等待幾分鐘,然後輸入以下命令:

輸出將顯示 MySQL 已停止:

嘗試多檢查幾次狀態,看看是否有任何變化。您會注意到 MySQL 保持停止狀態。這是因為服務設定檔中沒有 respawn 指令(即我們註解掉的指令)。請參閱本教學的第一部分,以了解有關 respawn 指令的更多說明。

為什麼我們要向您展示如何在系統啟動或崩潰後停用服務的自動重啟?這主要用於疑難排解。例如,如果您的服務啟動後不斷崩潰,您可能希望停用它以便進行疑難排解,並保持系統穩定。如果您剛好升級到原生隨附 systemd 的新 Linux 發行版,您也可以阻止某些舊的服務設定自動重啟,這將在下一節中討論。

Systemd 簡介

Systemd 是最新的 init 系統,存在於最現代的 Linux 發行版中。它包含許多構成現代 Linux 系統的組件。

Systemd 不僅管理服務,還管理整個 Linux 系統。在本節中,我們將重點介紹 systemd 如何在系統啟動或崩潰後控制服務的行為。

Systemd 向後相容 System V init 指令碼和指令。因此,如果您有任何設定了 System V 的服務,它們也將在 Systemd 下運作。大多數 Upstart 和 System V 管理指令都已修改以與 Systemd 搭配使用。Systemd 在啟動時會將自己重新命名為 init。一個 /sbin/init 檔案存在,並符號連結到 /bin/systemd.

Systemd 設定檔:單元檔案

Systemd 設定由單元檔案組成。每個單元檔案代表一個系統資源。雖然其他兩個 init 系統(即 System V 和 Upstart)負責管理 Linux 系統的服務,但 Systemd 不僅管理服務精靈(daemons),還管理其他類型的系統資源,例如裝置作業系統路徑、通訊端(sockets)、掛載點等。單元檔案儲存了有關該資源的資訊。

每個單元檔案都代表一個特定的系統資源,命名格式為 service_name.unit_type。這意味著您會找到像 home.mount、dbus.service、sshd.socket 等檔案。單元檔案是簡單的文字檔案,具有易於理解和修改的宣告式語法。

目錄結構

原生單元檔案的主要位置是 /lib/systemd/system/ 目錄。您建立的單元檔案或系統管理員自訂建立的單元檔案,以及其他修改過的原生單元檔案,都儲存在 /etc/systemd/system 目錄中。

如果同名的單元檔案同時存在於 /lib/systemd/system//etc/systemd/system 目錄中,systemd 將使用 /etc 目錄下的檔案。

當您啟用服務以在開機時或任何其他目標/執行等級(target/runlevel)啟動時,系統會在 /etc/systemd/system 的適當目錄下為該服務單元檔案建立符號連結。在 /etc/systemd/system 目錄中的單元檔案只是指向 /lib/systemd/system 目錄中同名檔案的符號連結。

Systemd 初始化順序:目標單元

目標單元(Target units)是特殊類型的單元檔案,通常以 .target 為字尾。目標單元與其他類型的單元檔案不同,因為它們不代表某個特定的資源。相反地,它們代表系統在給定時間的整體狀態。

為了實現這一點,目標單元會對屬於特定狀態的多個單元檔案進行分組並啟動。雖然 Systemd 目標(targets)和 System V 執行等級(runlevels)可以進行粗略的比較,但它們並不相同。目標單元檔案具有名稱而不是數字。例如,您會看到像 multi-user.target 而不是 runlevel 3,或者 reboot.target 而不是 runlevel 6。Linux 系統可能會以 multi-user.target 啟動。在這種情況下,它基本上是將伺服器帶入執行等級 2、3 或 4,這會在啟用網路功能的多使用者文字模式下啟動系統。

其區別在於它如何將伺服器帶入該等級。System V 是依序啟動服務。另一方面,當系統啟動時,systemd 會檢查其他服務或資源是否存在,並決定它們的載入順序。

systemd target 單位與 System V 執行等級(runlevel)的另一個不同之處在於,使用 System V 的 Linux 發行版只會存在於一個執行等級中。如果您修改了執行等級,它只會切換並存在於該新的執行等級中。另一方面,target 單位檔案可以是包含性的。此外,啟用某個 target 單位可確保其他 target 單位也作為其一部分被載入。例如,如果您啟動具有圖形使用者介面的 Linux 系統,它將會啟用 graphical.target。這反過來又會自動確保 multi-user.target 也被載入並啟用。

以下是比較執行等級與 target 的表格。

執行等級 (System V) Target 單位 (systemd)
runlevel 0 poweroff.target
runlevel 1 rescue.target
runlevel 2,3,4 multi-user.target
runlevel 5 graphical.target
runlevel 6 reboot.target

Systemd default.target

在 systemd 中,default.target 相當於 System V 中的預設執行等級。我們看到 System V 中的預設執行等級是在 inittab 檔案中定義的。而在 systemd 中,我們有 default.target 檔案。預設的 target 檔案儲存在 /etc/systemd/system 目錄中。它會符號連結(symlink)到 /lib/systemd/system 下的其中一個 target 單位檔案。變更預設 target 僅意味著重新建立符號連結並修改系統的執行等級。

在 System V 中,inittab 指定了 Linux 尋找 init 指令碼的目錄。如前所述,這可以是任何 rc 目錄。另一方面,systemd 預設 target 決定了在開機時要載入的資源單位。所有定義的單位都會被載入。然而,並非所有單位都是並行載入的,也不是所有單位都是依序載入的。資源單位的載入取決於它所 想要需要.

Systemd 依賴關係:Wants 與 Requires

在本節中,我們將討論 Systemd 如何處理依賴關係。我們看到,使用 Upstart 時,在使用設定檔的情況下可以並行載入服務。我們還討論了 System V 如何使用執行等級來決定自動啟動哪個服務,或者等待另一個服務或資源啟動。同樣地,Systemd 服務可以設定為在一個或多個 target 中載入,或者等待另一個服務或資源啟動。

在 Systemd 中,一個 需要 另一個單位的單位檔案,在所需要的單位載入並啟用之前不會啟動。如果所需要的單位在第一個單位處於啟用狀態時載入失敗,則第一個單位將會停止。

這種行為確保了系統的穩定性。一個 需要 特定資源(例如連接埠)可用且啟用的服務,因此可以被設定為等待該資源可用(即連接埠已開啟)。

相反地,一個 想要 另一個單位的單位則沒有這種限制。如果被想要的單位在呼叫單位仍處於啟用狀態時停止,它也不會停止。例如,圖形 target(graphical-target)模式下的一些非必要服務。

Systemd 範例

讓我們看看如何設定 systemd 下服務的行為。

步驟 1:登入您的 VPS 執行個體

我們將使用 MySQL 作為實際服務,並使用 CentOS 7 作為伺服器。若要實際操作這些步驟並理解這些概念,請登入您的 CentOS 7 VPS 或 在 CloudSigma 上建立一個。執行 CentOS 7、Debian 7 或 8,或 Ubuntu 15 或更新版本的 VPS 適合本節,因為它們都隨附 systemd。使用 ssh 指令登入,如果您使用的是 Windows,請使用 PuTTY:

步驟 2:檢查 default.target 檔案與依賴關係

Systemd 的啟動順序遵循一條很長的依賴鏈,我們將在本節中詳細討論。

  • default.target

default.target 檔案控制在正常開機期間啟動的服務。您可以使用以下指令列出預設的 target 單位檔案:

輸出結果類似於下方的螢幕截圖:

screenshot

螢幕截圖顯示預設 target 符號連結到以下目錄中的 multi-user.target 檔案:/lib/systemd/system/ 目錄。這意味著,在預設情況下,系統將在 multi-user.target 下啟動,相當於 runlevel 3.

  • multi-user.target.wants

要查看 multi-user.target 檔案所需的所有服務,請輸入以下命令:

輸出包含很多行,以下是片段:

如輸出所示,它們是指向實際單元檔案的符號連結,位於 /lib/systemd/system/ 目錄中。我們已反白顯示 mysqld.service ,以向您指出它也是 multi-user.target 的一部分。如果您想確認某個服務是否已設定為啟動,可以修改該檔案的命令。例如,我們可以使用以下命令過濾輸出以尋找 mysql 或 cron 守護行程:

輸出將顯示:

要過濾 cron 守護行程的結果,請輸入以下命令:

輸出將顯示:

除了 multi-user.target 之外,還存在其他不同類型的目標,即 system-update.targetbasic.target.

輸入以下命令以查看 multi-user 目標所依賴的目標:

輸出顯示:

這意味著,basic-target 必須先載入,系統才能在 multi-user.target 模式下啟動。

  • basic-target

輸入以下命令以查看 basic.target 還需要哪些其他目標:

輸出將顯示:

  • sysinit.target

您可以執行以下命令來查看是否有任何需要的 target 適用於 sysinit.target。該命令的語法是相同的。您可以繼續修改它,以逐步查看另一個 target unit 需要哪些 target unit。以下是該命令:

輸出將顯示沒有任何需要的 unit 適用於 sysinit.target。我們可以檢查是否有其他服務和 target 被 wantedsysinit.target,使用以下命令:

輸出顯示了一長串被 sysinit.target 想要的服務和 target。您可以在下方看到部分輸出:

在使用 system4 進行系統初始化的過程中,系統不會僅停留在一個 target。相反地,當它從一個 target 移動到另一個 target 時,會以依賴的方式載入服務。

步驟 3:檢查 Unit 檔案

讓我們來看看 unit 檔案的樣子。我們在本教學的第一部分中使用了 MySQL 服務 unit 檔案,我們將再次使用它。不過,我們也可以看看另一個服務 unit 檔案——sshd unit 檔案。輸入以下命令以開啟 sshd 設定檔:

以下是顯示檔案中各行的螢幕截圖:

unit screesnhot

如您所見,檔案中概述的程式碼區塊使其易於理解並在必要時進行修改。以下是一些需要理解的重要指令:

  • AfterAfter 子句告訴系統僅在指定的 target 和服務載入後才載入該服務。在這種情況下,SSHD 服務將在 network target 和 keygen 服務載入後載入。
  • WantsWants 子句顯示哪些 target 想要此服務。在這種情況下, ssh-keygen.service 想要 sshd.service。然而,如果 sshd 失敗或崩潰,它不會關閉 ssh-keygen.service.

按 Ctrl + X 關閉編輯器。

步驟 4:在系統開機時測試 MySQL 服務啟動行為

在本節中,我們將向您展示如何變更和測試 MySQL 服務在系統開機時的行為。在上一節中,我們看到 mysqld.servicemulti-user.target 想要。因此,它將在開機時自動啟動。

您可以透過執行以下命令來停用該服務:

執行該命令顯示已從 /etc/systemd/system/multi-user.target.wants/ 目錄中移除 mysql 符號連結。為了測試這一點,請執行以下命令以測試 MySQL 是否仍被 multi-user.target:

該命令未返回任何內容。如果您嘗試重啟伺服器並檢查 MySQL 狀態,它將不會運行,這意味著它在開機時沒有自動啟動。

現在使用以下命令重新啟用該服務:

輸出將顯示一個符號連結。如果您重啟伺服器,MySQL 應該會自動啟動。啟用 Systemd 服務會在預設 target 的 wants 目錄中建立一個符號連結。停用 Systemd 服務則會從 wants 目錄中移除該符號連結。

步驟 5:測試服務崩潰後 MySQL 服務的啟動行為

預設情況下,MySQL 服務在崩潰時會自動啟動。我們可以在 MySQL 的 Systemd 設定檔中停用此行為。首先,讓我們看看該檔案。輸入以下命令以開啟檔案:

下方的螢幕截圖顯示了輸出:

screen shot 5

Restart 指令的值設定為 on-failure。這意味著 MySQL 服務將在非正常結束代碼、逾時或非正常訊號後重新啟動。以下表格顯示了來自 說明手冊頁.

重新啟動設定/結束原因 no always on-success on-failure on-abnormal on-abort on-watchdog
正常結束代碼或訊號 X X
非正常結束代碼 X X
非正常訊號 X X X X
逾時 X X X
看門狗 X X X X

Systemd 單元檔案中兩個重要的指令是 RestartRestartSec。它們控制服務的崩潰行為。Restart 指定服務何時應重新啟動,而 RestartSec 指定崩潰後重新啟動前應等待多長時間。要停用重新啟動行為,請在行首添加 # 來註解掉 Restart 指令,如下所示:

現在,重新載入系統精靈 (daemon),然後使用以下命令重新載入 mysqld 服務:

接下來,執行以下命令以尋找 MySQL 服務的主 PID (Main PID):

screenshot 7

我們測試的主 PID 是 23809。請記下您的 PID 以在下一個命令中使用。使用 kill -9 命令,透過終止該程序來模擬崩潰。另外,請記住將其替換為您在測試中獲得的程序編號:

如果您執行檢查 MySQL 狀態的命令,您會發現它並未處於活動狀態,且未能重新啟動:

screesnshot 8

只要 mysqld.service 設定檔中的 Restart 指令保持被註解狀態,它就會一直處於失敗狀態。這模擬了服務停止且無法恢復的崩潰情況。

要重新啟用該服務,您可以編輯 mysqld.service 設定檔,取消註解 Restart 指令,然後儲存並關閉。就像您之前所做的那樣,重新載入精靈並重新啟動服務。這會將服務恢復到其初始設定,現在它可以在崩潰後自動啟動。最後,這就是將服務設定為在崩潰後自動啟動的全部內容。如果您想將服務設定為在崩潰後自動啟動,您只需在服務單元檔案的 Restart 指令(如果您願意,也可以添加 RestartSec 指令),放在 [Service] 區段下方。

結論

在本教學中,我們討論了 Linux 如何在啟動期間或崩潰後處理服務。為了理解 Linux 系統初始化程序,我們討論了 Linux 使用的三種 init 系統:System V、Upstart 和 Systemd。我們討論了它們的演變,以及每個 init 程序如何與系統重啟或崩潰後自動啟動服務相關聯。

由於 init 守護程序和 Linux 發行版都在隨時間不斷演進,請記得檢查您正在運行的 Linux 發行版版本,以便了解您的系統原生支援哪一種 init 守護程序。

Linux 原生應用程式和大多數第三方應用程式在系統開機或當機後已經會自動啟動,因此您不需要進行任何操作。當您在設定自己自訂服務的啟動和重啟行為,或者在對不斷當機的服務進行疑難排解時,本教學中的知識至關重要。

祝您使用愉快!

author

Manpreet Singh

作者 · CloudSigma

Preslav Dobrev 是 CloudSigma 的創意設計師,專注於透過傳統與創新行銷渠道建立一致的企業形象。他擅長將藝術願景與策略行銷相融合,創造具有影響力的品牌敘事。

留言

目前尚無留言。成為第一個留言的人吧。