1. 程式人生 > >Linux Systemd 詳細介紹: Unit、Unit File、Systemctl、Target

Linux Systemd 詳細介紹: Unit、Unit File、Systemctl、Target

## Systemd ### 簡介 CentOS 7 使用 Systemd 替換了SysV Ubuntu 從 15.04 開始使用 Systemd Systemd 是 Linux 系統工具,用來啟動守護程序,已成為大多數發行版的標準配置 #### 特點 優點: 1. 按需啟動程序,減少系統資源消耗 2. 並行啟動程序,提高系統啟動速度 在 SysV-init 時代,將每個服務專案編號,依次執行啟動指令碼。Ubuntu 的 Upstart 解決了沒有直接依賴的啟動之間的並行啟動。而 Systemd 通過 Socket 快取、DBus 快取和建立臨時掛載點等方法進一步解決了啟動程序之間的依賴,做到了**所有系統服務併發啟動**。對於使用者自定義的服務,Systemd 允許配置其啟動依賴專案,從而確保服務按必要的順序執行。 > SystemV Upstart 參考上一篇博文:[Linux 初始化系統 SystemV Upstart](https://www.cnblogs.com/usmile/p/13065566.html) 3. 使用 CGroup 監視和管理程序的生命週期 CGroup 提供了類似檔案系統的介面,當程序建立子程序時,子程序會繼承父程序的 CGroup。因此無論服務如何啟動新的子程序,所有的這些相關程序都會屬於同一個 CGroup 在 Systemd 之前的主流應用管理服務都是使用 程序樹 來跟蹤應用的繼承關係的,而程序的父子關係很容易通過 兩次 fork 的方法脫離。 而 Systemd 則提供通過 CGroup 跟蹤程序關係,引補了這個缺漏。通過 CGroup 不僅能夠實現服務之間訪問隔離,限制特定應用程式對系統資源的訪問配額,還能更精確地管理服務的生命週期 4. 統一管理服務日誌 5. 支援快照和系統恢復 缺點: 1. 過於複雜,與作業系統的其他部分強耦合,違反"keep simple, keep stupid"的[Unix 哲學](http://www.ruanyifeng.com/blog/2009/06/unix_philosophy.html) #### 架構圖 ![](https://img2020.cnblogs.com/blog/1418536/202006/1418536-20200608160218449-876445211.png) ### Unit(單元|服務) Systemd 可以管理所有系統資源: 1. 將系統資源劃分為12類 2. 將每個系統資源稱為一個 Unit。Unit 是 Systemd 管理系統資源的基本單位 3. 使用一個 Unit File 作為 Unit 的單元檔案,Systemd 通過單元檔案控制 Unit 的啟動 > 例如,MySQL服務被 Systemd 視為一個 Unit,使用一個 mysql.service 作為啟動配置檔案 ### Unit File(單元檔案|配置檔案) 單元檔案中包含該單元的描述、屬性、啟動命令等 #### 型別 Systemd 將系統資源劃分為12類,對應12種類型的單元檔案 | 系統資源型別 | 單元副檔名 | 單元檔案描述 | | ------------ | -------------- | ------------------------------------------------------------ | | Service | .service | 封裝**守護程序**的啟動、停止、重啟和過載操作,是最常見的一種 Unit 檔案 | | Target | .target | 定義 target 資訊及依賴關係,一般僅包含 Unit 段 | | Device | .device | 對於 `/dev` 目錄下的硬體裝置,主要用於定義裝置之間的依賴關係 | | Mount | .mount | 定義檔案系統的掛載點,可以替代過去的 `/etc/fstab` 配置檔案 | | Automount | .automount | 用於控制自動掛載檔案系統,相當於 SysV-init 的 autofs 服務 | | Path | .path | 用於監控指定目錄或檔案的變化,並觸發其它 Unit 執行 | | Scope | .scope | 這種 Unit 檔案不是使用者建立的,而是 Systemd 執行時產生的,描述一些系統服務的分組資訊 | | Slice | .slice | 用於表示一個 CGroup 的樹 | | Snapshot | .snapshot | 用於表示一個由 systemctl snapshot 命令建立的 Systemd Units 執行狀態快照,可以切回某個快照 | | Socket | .socket | 監控來自於系統或網路的資料訊息 | | Swap | .swap | 定義一個使用者做虛擬記憶體的交換分割槽 | | Timer | .timer | 用於配置在特定時間觸發的任務,替代了 Crontab 的功能 | > 對於操作單元檔案的命令,如果預設副檔名,則預設`.service`副檔名 > > 而操作 target 的命令,例如 isolate,則預設`.target`副檔名 #### 語法 單元檔案的語法來源於 XDG桌面入口配置檔案`.desktop`檔案 Unit 檔案可以分為三個配置區段: - Unit 段:所有 Unit 檔案通用,用來定義 Unit 的元資料,以及配置與其他 Unit 的關係 - Install 段:所有 Unit 檔案通用,用來定義如何啟動,以及是否開機啟動 - Service 段:服務(Service)型別的 Unit 檔案(字尾為 .service)特有的,用於定義服務的具體管理和執行動作 > 單元檔案中的區段名和欄位名大小寫敏感 > > 每個區段內都是一些等號連線的鍵值對(鍵值對的等號兩側不能有空格) ###### Unit 段 主要欄位如下: - `Description`:當前服務的簡單描述 - `Documentation`:文件地址,可以是一個或多個文件的 URL 路徑 【依賴關係】 - `Requires`:與其它 Unit 的強依賴關係,如果其中任意一個 Unit 啟動失敗或異常退出,當前 Unit 也會被退出 - `Wants`:與其它 Unit 的弱依賴關係,如果其中任意一個 Unit 啟動失敗或異常退出,不影響當前 Unit 繼續執行 > 只涉及依賴關係,預設情況下 兩個 Unit 同時啟動 【啟動順序】 - `After`:該欄位指定的 Unit 全部啟動完成以後,才會啟動當前 Unit - `Before`:該欄位指定的 Unit 必須在當前 Unit 啟動完成之後再啟動 > 只涉及啟動順序,不影響啟動結果和執行情況 - `Binds To`:與 Requires 相似,該欄位指定的 Unit 如果退出,會導致當前 Unit 停止執行 - `Part Of`:一個 Bind To 作用的子集,僅在列出的 Unit 失敗或重啟時,終止或重啟當前 Unit,而不會隨列出Unit 的啟動而啟動 > http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.unit.5.html ###### Install 段 主要欄位如下: - `WantedBy`:它的值是一個或多個 target,執行enable命令時,符號連結會放入`/etc/systemd/system`目錄下以 target 名 + `.wants`字尾構成的子目錄中 - `RequiredBy`:它的值是一個或多個 target,執行enable命令時,符號連結會放入`/etc/systemd/system`目錄下以 target 名 + `.required`字尾構成的子目錄中 - `Alias`:當前 Unit 可用於啟動的別名 - `Also`:當前 Unit 被 enable/disable 時,會被同時操作的其他 Unit > http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.unit.5.html ###### Service 段 主要欄位如下: 【啟動型別】 - `Type`:定義啟動時的程序行為。它有以下幾種值。 - `Type=simple`:預設值,`ExecStart`欄位啟動的程序為主程序 - 服務程序不會 fork,如果該服務要啟動其他服務,不要使用此型別啟動,除非該服務是 socket 啟用型 - `Type=forking`:`ExecStart`欄位將以`fork()`方式從父程序建立子程序啟動,建立後父程序會立即退出,子程序成為主程序。 - 通常需要指定`PIDFile`欄位,以便 Systemd 能夠跟蹤服務的主程序 - 對於常規的守護程序(daemon),除非你確定此啟動方式無法滿足需求,使用此型別啟動即可 - `Type=oneshot`:只執行一次,Systemd 會等當前服務退出,再繼續往下執行 - 適用於只執行一項任務、隨後立即退出的服務 - 通常需要指定`RemainAfterExit=yes`欄位,使得 Systemd 在服務程序退出之後仍然認為服務處於啟用狀態 - `Type=dbus`:當前服務通過 D-Bus 訊號啟動。當指定的 BusName 出現在 DBus 系統總線上時,Systemd認為服務就緒 - `Type=notify`:當前服務啟動完畢會發出通知訊號,通知 Systemd,然後 Systemd 再啟動其他服務 - `Type=idle`:Systemd 會等到其他任務都執行完,才會啟動該服務。 - 一種使用場合是:讓該服務的輸出,不與其他服務的輸出相混合 【啟動行為】 - `ExecStart`:啟動當前服務的命令 > ```bash > ExecStart=/bin/echo execstart1 > ExecStart= > ExecStart=/bin/echo execstart2 > ``` > > 順序執行設定的命令,把欄位置空,表示清除之前的值 - `ExecStartPre`:啟動當前服務之前執行的命令 - `ExecStartPost`:啟動當前服務之後執行的命令 - `ExecReload`:重啟當前服務時執行的命令 - `ExecStop`:停止當前服務時執行的命令 - `ExecStopPost`:停止當前服務之後執行的命令 - `RemainAfterExit`:當前服務的所有程序都退出的時候,Systemd 仍認為該服務是啟用狀態 - 這個配置主要是提供給一些並非常駐記憶體,而是啟動註冊後立即退出,然後等待訊息按需啟動的特殊型別服務使用的 - `TimeoutSec`:定義 Systemd 停止當前服務之前等待的秒數 > 注:所有的啟動設定之前,都可以加上一個連詞號(`-`),表示"抑制錯誤",即發生錯誤的時候,不影響其他命令的執行。比如,`EnvironmentFile=-/etc/sysconfig/sshd`(注意等號後面的那個連詞號),就表示即使`/etc/sysconfig/sshd`檔案不存在,也不會丟擲錯誤。 【重啟行為】 - `RestartSec`:Systemd 重啟當前服務間隔的秒數 - `KillMode`:定義 Systemd 如何停止服務,可能的值包括: - control-group(預設值):當前控制組裡面的所有子程序,都會被殺掉 - process:只殺主程序(sshd 服務,推薦值) - mixed:主程序將收到 SIGTERM 訊號,子程序收到 SIGKILL 訊號 - none:沒有程序會被殺掉,只是執行服務的 stop 命令。 - `Restart`:定義何種情況 Systemd 會自動重啟當前服務,可能的值包括: - no(預設值):退出後不會重啟 - on-success:只有正常退出時(退出狀態碼為0),才會重啟 - on-failure:非正常退出時(退出狀態碼非0),包括被訊號終止和超時,才會重啟(守護程序,推薦值) - on-abnormal:只有被訊號終止和超時,才會重啟(對於允許發生錯誤退出的服務,推薦值) - on-abort:只有在收到沒有捕捉到的訊號終止時,才會重啟 - on-watchdog:超時退出,才會重啟 - always:不管是什麼退出原因,總是重啟 【上下文】 - `PIDFile`:指向當前服務 PID file 的絕對路徑。 - `User`:指定執行服務的使用者 - `Group`:指定執行服務的使用者組 - `EnvironmentFile`:指定當前服務的環境引數檔案。該檔案內部的`key=value`鍵值對,可以用`$key`的形式,在當前配置檔案中獲取 > 啟動`sshd`,執行的命令是`/usr/sbin/sshd -D $OPTIONS`,其中的變數`$OPTIONS`就來自`EnvironmentFile`欄位指定的環境引數檔案。 > http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.service.5.html #### 佔位符 在 Unit 檔案中,有時會需要使用到一些與執行環境有關的資訊,例如節點 ID、執行服務的使用者等。這些資訊可以使用佔位符來表示,然後在實際執行中動態地替換為實際的值。 > 詳細瞭解見 https://cloud.tencent.com/developer/article/1516125 #### 模板 在現實中,往往有一些應用需要被複制多份執行,就會用到模板檔案 模板檔案的寫法與普通單元檔案基本相同,只是模板檔名是以 @ 符號結尾。例如:[email protected] 通過模板檔案啟動服務例項時,需要在其檔名的 @ 字元後面附加一個用於區分服務例項的引數字串,通常這個引數是用於監控的埠號或控制檯 TTY 編譯號 ``` systemctl start [email protected] ``` Systemd 在執行服務時,首先尋找跟單元名完全匹配的單元檔案,如果沒有找到,才會嘗試選擇匹配模板 例如上面的命令,System 首先會在約定的目錄下尋找名為 [email protected] 的單元檔案,如果沒有找到,而檔名中包含 @ 字元,它就會嘗試去掉字尾引數匹配模板檔案。對於 [email protected],Systemd 會找到 [email protected] 模板檔案,並通過這個模板檔案將服務例項化。 > 詳細瞭解見 https://cloud.tencent.com/developer/article/1516125 #### 狀態 `systemctl list-unit-files` 將會列出檔案的 state,包括 static, enabled, disabled, masked, indirect - masked service軟連結到`/dev/null` 該單元檔案被禁止建立啟動連結 - static 該單元檔案沒有`[Install]`部分(無法執行),只能作為其他配置檔案的依賴 - enabled 已建立啟動連結 - disabled 沒建立啟動連結 > https://askubuntu.com/a/731674 #### 示例 1. 關掉觸控板配置檔案 ```bash Unit] Description=Switch-off Touchpad [Service] Type=oneshot ExecStart=/usr/bin/touchpad-off start ExecStop=/usr/bin/touchpad-off stop RemainAfterExit=yes [Install] WantedBy=multi-user.target ``` - oneshot 表明這個服務只要執行一次就夠了,不需要長期執行 - `RemainAfterExit`欄位設為`yes`,表示程序退出以後,服務仍然保持執行。這樣的話,一旦使用`systemctl stop`命令停止服務,`ExecStop`指定的命令就會執行,從而重新開啟觸控板 ### Systemd 內建命令 ###### `systemd-analyze` Analyze and debug system manager, If no command is passed, **Systemd-analyze time** is implied > https://www.freedesktop.org/software/systemd/man/systemd-analyze.html ###### `systemd-analyze time` 檢視初始化耗時 ###### ` systemd-analyze blame` 列印所有執行單元,按它們初始化的時間排序。此資訊可用於優化啟動時間。注意,輸出可能具有誤導性,因為一個服務的初始化可能非常緩慢,因為它等待另一個服務的初始化完成 `systemd-run` 將一個指定的服務變成後臺服務 > 未測試 > > 參考 https://www.freedesktop.org/software/systemd/man/systemd-run.html ### systemctl 系統服務管理命令 `systemctl`是 Systemd 的主命令,用於管理系統 #### 與 service 命令的區別 1. systemctl 融合了 service 和 chkconfig 的功能 2. 在 Ubuntu18.04 中沒有自帶 chkconfig 命令;service 命令實際上重定向到 systemctl 命令 | 動作 | SysV Init 指令 | Systemd 指令 | | -------------------- | ------------------------------- | ----------------------------------------- | | 啟動某服務 | service httpd start | systemctl start httpd | | 停止某服務 | service httpd stop | systemctl stop httpd | | 重啟某服務 | service httpd restart | systemctl restart httpd | | 檢查服務狀態 | service httpd status | systemctl status httpd | | 刪除某服務 | chkconfig --del httpd | 停掉應用,刪除其配置檔案 | | 使服務開機自啟動 | chkconfig --level 5 httpd on | systemctl enable httpd | | 使服務開機不自啟動 | chkconfig --level 5 httpd off | systemctl disable httpd | | 查詢服務是否開機自啟 | chkconfig --list \| grep httpd | systemctl is-enabled httpd | | 加入自定義服務 | chkconfig --add test | systemctl load test | | 顯示所有已啟動的服務 | chkconfig --list | systemctl list-unit-files \| grep enabled | #### 引數 ###### `--all` 顯示載入到記憶體的所有單元 ###### `--type` `-t` `--type=` 顯示指定型別(12種類型)的單元 ###### `--state` `--state=` 顯示指定狀態的單元或單元檔案 > - 單元狀態 > > 輸入 `systemctl list-units --state` 按 `Tab`鍵,顯示所有可用的值 > > - 單元檔案狀態 > > 另外還可以用 enabled static disabled 等`systemctl list-unit-files` 顯示的狀態 ###### `--failed` `--state=failed` 顯示載入失敗的單元 ``` systemctl --failed ``` ###### `--version` 列印 Systemd 版本 ```bash lfp@legion:/lib/systemd/system$ systemctl --version Systemd 237 +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid ``` #### 單元命令 > 我的理解 > > - systemd 對單元的管理,不涉及單元檔案自身屬性和內容 > ###### `list-units` 相當於`systemctl` 列出當前已載入的單元(記憶體) 預設情況下僅顯示處於啟用狀態(正在執行)的單元 > UNIT 單元名 > > LOAD 載入狀態 > > ACTIVE SUB 執行狀態(大狀態 子狀態) > > DESCRIPTION 描述 ###### `start` 啟動單元 ``` systemctl start mysql.service ``` ###### `stop` 停止單元 ``` systemctl stop mysql.service ``` ###### `kill` 殺掉單元程序 ``` systemctl kill mysql.service ``` ###### `reload` 不終止單元,重新載入 針對該單元的 執行配置檔案,而不是 針對 systemd的 該單元的啟動配置檔案 > 例如啟動 MySQL 服務,reload 可以在不停止服務的情況下過載 MySQL 的配置檔案 `my.cnf` ###### `restart` 重啟單元 該單元在重啟之前擁有的資源不會被完全清空,比如檔案描述符儲存設施 ``` systemctl reload mysql.service ``` ###### `status` `status [unit | PID]` 顯示單元或程序所屬單元的執行資訊 ``` systemctl status mysql.service ``` > `Loaded`行:配置檔案的位置,是否設為開機啟動 > > `Active`行:表示正在執行 > > `Main PID`行:主程序ID > > `CGroup`塊:應用的所有子程序 > > 日誌塊:應用的日誌 ###### `is-active` 判斷指定的單元是否處於啟用狀態 ```bash # 預設會列印當前單元的狀態,可以通過 --quiet 引數取消列印 lfp@legion:~$ systemctl is-active mysql active ``` ###### `is-failed` 判斷指定的單元是否處於啟動失敗狀態 ```bash lfp@legion:~$ systemctl is-failed mysql active ``` ###### `list-dependencies` 檢視單元之間的依賴關係 ``` systemctl list-dependencies graphical.target systemctl list-dependencies mysql.service ``` ###### `show` `show --property= Unit` <==> `show -p Unit` 顯示單元所有底層引數 ```bash lfp@legion:~$ systemctl show -p MainPID mysql MainPID=1061 ``` ###### `set-property` 在單元啟動的時候設定執行時的某個屬性,立即生效,並儲存在磁碟中作為啟動配置 如果添加了`--runtime`則重啟後失效 並非所有的屬性都可以設定,只是 [systemd.resource-control](http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.resource-control.5.html) 包含的屬性 ###### `isolate` 切換到某個 target(系統狀態),立即停止該 target 未包含的單元程序。也可以理解為切換 runlevel 如果沒有指定副檔名,則預設`.target` 只有當.target單元檔案中的`AllowIsolate=yes`時,才能使用 isolate 切換;也可以用`IgnoreOnIsolate=yes`欄位來拒絕使用 isolate 切換 ```bash systemctl isolate multi-user.target ``` ###### `cat` 顯示單元配置檔案的備份檔案,包括插入式配置`drop-ins`,可以完整的看到單元服務的配置。注意這裡列印的依據是磁碟的上內容,如果使用者修改了配置檔案(磁碟已修改)但是未執行`daemon-reload`命令(記憶體中未更新),那麼該命令顯示的配置和實際執行情況有出入 ```bash lfp@legion:~$ systemctl cat mysql.service # /lib/systemd/system/mysql.service # MySQL Systemd service file [Unit] Description=MySQL Community Server ... [Install] WantedBy=multi-user.target [Service] Type=forking ... # 這段就顯示的是 插入式配置 drop-in 的內容 # /etc/systemd/system/mysql.service.d/mysql.conf # MySQL Systemd service file [Unit] # Description=MySQL Community Server conf [Service] # ExecStartPost=/home/lfp/bin/espeak.sh ``` #### 單元檔案命令 > 我的理解 > > - systemd 對單元檔案自身屬性和內容的管理 ###### `list-unit-files` 列出所有已安裝的單元檔案和它們的啟用狀態 > 和`list-units`的區別是 > > - list-units 僅顯示當前已載入到記憶體中的單元 > - list-unit-files 會讀取單元檔案內容,列出所有單元,包括存在於硬碟未載入進記憶體的單元 > > 實際測試結果: > > systemctl list-unit-files 顯示“348 Unit files listed” > > systemctl list-units --all 顯示“405 loaded units listed” > > systemctl list-units 顯示 “232 loaded units listed” ###### `enable` 使某個單元開機自啟動 這會根據**單元檔案內容**中的`[Install]`指定的 target 組,建立一個軟連結 > ```bash > lfp@legion:/etc/systemd/system$ vim ***L.service > # 檔案內容 [Install] 段 > ...... > [Install] > WantedBy=multi-user.target > ...... > > lfp@legion:/etc/systemd/system$ systemctl is-enabled ***L.service > disabled > lfp@legion:/etc/systemd/system$ systemctl enable ***L.service > # 根據 [Install] 段指定的組,新增軟連結 > Created symlink /etc/systemd/system/multi-user.target.wants/***L.service → /etc/systemd/system/***L.service. > lfp@legion:/etc/systemd/system$ systemctl is-enabled ***L.service > enabled > ``` ###### `disable` 取消某個單元開機自啟動設定,刪除軟連結 這會刪除**所有**指向該單元檔案的軟連結,不僅僅是 enable 操作建立的 ###### `reenable` disable 和 enable 的結合,根據單元檔案內容中的 [Install] 段,重置軟連結 ###### `is-enabled` 檢查某個單元是否是開機自啟動的(建立的啟動連結) ```bash lfp@legion:~$ systemctl is-enabled mysql enabled ``` ###### `get-default` 獲取預設啟動 target,default-target 是指向該 target 的軟連結 ###### `set-default` 設定預設啟動 target,同時修改 default-target 指向設定的 target ``` systemctl set-default multi-user.target ``` #### 生命週期管理命令 ###### `daemon-reload` 重新**載入**所有的單元檔案和依賴關係 對單元檔案有修改的時候,需要執行該命令重新載入檔案內容 #### 系統管理命令 ###### `reboot` ``` systemctl reboot ``` 重啟系統(非同步操作) > it will return after the reboot operation is enqueued, without waiting for it to complete ###### `poweroff` 關閉系統,切斷電源(非同步操作) ###### `halt` 僅CPU停止工作,其他硬體仍處於開機狀態(非同步操作) ###### `suspend` 暫停系統(非同步操作) 將觸發執行`suspend.target` ###### `hibernate` 讓系統進入冬眠狀態(非同步操作) 將觸發執行`hibernate.target` ### 目錄、檔案 `/run/systemd/system/` 單元(服務)執行時生成的配置檔案所在目錄 `/etc/systemd/system/` 系統或使用者自定義的配置檔案,**初始化過程中**`Systemd`只執行`/etc/systemd/system`目錄裡面的配置檔案 `/lib/systemd/system/ ` 軟體安裝時新增的配置檔案,類似於` /etc/init.d/` 對於支援 Systemd 的程式,安裝的時候,會自動的在 `/lib/systemd/system` 目錄新增一個配置檔案 > 其他目錄都是軟連結 `/etc/systemd/system/default.target` Systemd 執行的第一個單元檔案,符號連結到預設啟動 target 對應的 `.target` 單元檔案 #### 優先順序 SysV 的啟動指令碼放在`/etc/init.d`目錄下 Systemd 的單元檔案放在`/etc/systemd/system` 和 `/lib/systemd/system`目錄下 當一個程式在3個目錄下都存在啟動方式時,優先順序是`/etc/systemd/system --> /lib/systemd/system --> /etc/init.d` ```bash lfp@legion:/etc/init.d$ ll -rwxr-xr-x 1 root root 5650 5月 19 22:09 mysql* lfp@legion:/etc/systemd/system$ ll -rw-r--r-- 1 root root 511 5月 20 01:42 mysql.service lfp@legion:/lib/systemd/system$ ll -rw-r--r-- 1 root root 499 5月 20 01:20 mysql.service ``` - `/etc/systemd/system` 裡面的同名service會覆蓋`/lib/systemd/system` 裡面的 > 注意檢視檔案資訊,該同名檔案不能是指向 /lib/systemd/system 的軟連結 > > 軟連結不會覆蓋而會同步 - 如果某個程式不存在Systemd 單元檔案,那麼會執行`/etc/init.d`裡面的啟動指令碼 > 根據啟動過程, `/etc/systemd/system/multi-user.target.wants/` 目錄下是很多指向` /lib/systemd/system/`目錄的**軟連結**,所以兩個目錄下的單元檔案會互相同步。 > > 如果`/etc/systemd/system/` 和 `/etc/systemd/system/multi-user.target.wants/` 同時存在單元檔案,測試發現,不管是手動啟動還是開機自啟動,使用的都是 `/etc/systemd/system/` 目錄下的service單元檔案 ##### 測試 ###### 執行`/etc/init.d`目錄下的指令碼 mysql 修改 `mysql.service` 為`mysql.service.bak` 然後通過`service mysql restart`啟動`/etc/init.d/mysql`指令碼 下面是啟動後的一些資訊 ![](https://img2020.cnblogs.com/blog/1418536/202006/1418536-20200608160344455-1619243714.png) > 注:在恢復`mysql.service`之前,需要先通過`service mysql stop` 利用`/etc/init.d/mysql`指令碼中的`stop`結束上面的程序,否則一旦恢復,`service mysql stop` 執行的操作就不是 `/etc/init.d/mysql`指令碼中的`stop`,無法結束上面的程序,出現命令無法正常執行的情況 結束上面的程序,恢復`mysql.service`,重新啟動 ![](https://img2020.cnblogs.com/blog/1418536/202006/1418536-20200608160406468-319771464.png) ###### `/etc/systemd/system` 覆蓋測試 未修改前,檢視MySQL的狀態 ```bash lfp@legion:~$ service mysql status ● mysql.service - MySQL Community Server # 可以發現這裡的 mysql.service 是在 /lib/systemd/system 下面 Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: en Active: active (running) since Sat 2020-04-25 18:34:30 CST; 5h 33min ago Main PID: 988 (mysqld) Tasks: 28 (limit: 4915) CGroup: /system.slice/mysql.service └─988 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid 4月 25 18:34:30 legion Systemd[1]: Starting MySQL Community Server... 4月 25 18:34:30 legion Systemd[1]: Started MySQL Community Server. ``` 將 /lib/systemd/system 下面的檔案複製到 ` /etc/systemd/system/` 下面 ```bash sudo cp /lib/systemd/system/mysql.service /etc/systemd/system/ ``` 修改 mysql.service ``` sudo vim /etc/systemd/system/mysql.service ``` ​ ![](https://img2020.cnblogs.com/blog/1418536/202006/1418536-20200608160451165-1855890790.png) 重啟 mysql.service ,系統提示需要重新載入 ```bash lfp@legion:~$ systemctl restart mysql.service Warning: The Unit file, source configuration file or drop-ins of mysql.service changed on disk. Run 'systemctl daemon-reload' to reload units. lfp@legion:~$ systemctl daemon-reload # 重新載入 lfp@legion:~$ systemctl restart mysql.service # 重啟 lfp@legion:~$ systemctl status mysql.service ● mysql.service - MySQL Community Server hahahaha # 發現這裡是修改之後的,覆蓋了 /lib/systemd/lib 中的 # 這裡也可以看到載入路徑 Loaded: loaded (/etc/systemd/system/mysql.service; enabled; vendor preset: en Active: active (running) since Sun 【2020-04-26】 00:47:02 CST; 5s ago Process: 21590 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/m Process: 21581 ExecStartPre=/usr/share/mysql/mysql-Systemd-start pre (code=exi Main PID: 21592 (mysqld) Tasks: 27 (limit: 4915) CGroup: /system.slice/mysql.service └─21592 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pi 4月 26 00:47:02 legion Systemd[1]: Starting MySQL Community Server hahahaha... 4月 26 00:47:02 legion Systemd[1 ``` ### Target 兩個含義 1. 系統的某個狀態稱為一個 target(類似於"狀態點") 2. 達到某個系統狀態,所需的一個或多個資源(Unit)稱為一個 target(一個 Unit 組) > 1. target是一個抽象的系統資源,不像MySQL有實體 > > 2. 如果一個target只包含一個Unit,那麼該 target,沒有對應的目錄,指的就是這個 Unit > > 例如 `hibernate.target `只包含 `systemd-hibernate.service`一個Unit > > 如果一個target包含多個Unit,那麼該target,有對應的 xxx.target.wants 目錄,指的是目錄裡面所有的Unit > > 例如 `multi-user.target` 包含位於`/etc/systemd/system/multi-user.target.wants`目錄下的多個 Unit target也是一個 Target 型別的系統資源,有對應的單元檔案 xxx.target Systemd 使用 target 來劃分和管理資源(Unit),啟動(啟用)某個 xxx.target 單元檔案,通過執行該 target 包含的 Unit,使系統達到某種狀態 > 對於狀態點的理解: > > 例如,執行`systemd suspend`命令讓系統暫停,會觸發啟動`suspend.target`,然後執行裡面的`systemd-suspend.service` Unit,使系統達到一個暫停的狀態 傳統的`init`啟動模式裡面,有 RunLevel 的概念,跟 Target 的作用很類似。不同的是,RunLevel 是互斥的,不可能多個 RunLevel 同時啟動,但是多個 Target 可以同時啟動 #### 啟動 target runlevel是 SysV init 初始化系統中的概念,在Systemd初始化系統中使用的是 Target,他們之間的對映關係是 | Runlevel | Target | 說明 | | -------- | ----------------- | ---------------------------------- | | 0 | poweroff.target | 關閉系統 | | 1 | rescue.target | 維護模式 | | 2,3,4 | multi-user.target | 多使用者,無圖形系統(命令列介面) | | 5 | graphical.target | 多使用者,圖形化系統(圖形使用者介面) | | 6 | reboot.target | 重啟系統 | #### 啟動過程 ![](https://img2020.cnblogs.com/blog/1418536/202006/1418536-20200608160526927-216960400.png) 1. 讀入 `/boot` 目錄下的核心檔案 2. 核心檔案載入完之後,開始執行第一個程式`/sbin/init` 初始化程序,由 Systemd 初始化系統引導,完成相關的初始化工作 3. Systemd 執行`default.target` ,獲知設定的啟動 target > 實際上 `default.target` 是指向設定的啟動 target 的軟連結 > ![](https://img2020.cnblogs.com/blog/1418536/202006/1418536-20200608160632771-62990504.png) 4. Systemd 執行啟動 target 對應的單元檔案。根據單元檔案中定義的[依賴關係](https://www.freedesktop.org/software/systemd/man/bootup.html#System%20Manager%20Bootup),傳遞控制權,依次執行其他 target 單元檔案,同時啟動每個 target 包含的單元 > 對於圖形化介面,預設 target 是 graphical,Systemd 執行位於`/lib/systemd/system/` 目錄下的 graphical.target 單元檔案,根據 target 單元檔案中定義的依賴關係,依次啟動其他 target 單元檔案以及各個 target 包含的位於`/etc/systemd/system/`目錄下的單元 > > 例如: graphical.target 的依賴關係是 > > ```bash > [Unit] > Description=Graphical Interface > Documentation=man:systemd.special(7) > Requires=multi-user.target # > Wants=display-manager.service # > Conflicts=rescue.service rescue.target > After=multi-user.target rescue.service rescue.target display-manager.service # > AllowIsolate=yes > ``` > > 因此,依次啟動 multi-user.target --> basic.target --> sysinit.target --> local-fs.target -->local-fs-pre.target --> ... > > 同時啟動每個 target 包含的位於`/etc/systemd/system/`目錄下的Unit > > **SysV對應的 rc5.d --> /etc/init.d 目錄下的指定的指令碼就不會在開機的時候執行了** #### 檢視預設 target `systemctl get-default` ```bash lfp@legion:~$ runlevel N 5 lfp@legion:~$ systemctl get-default graphical.target ``` #### 修改預設 target `systemctl set-default [xxx.target]` ```bash # Ubuntu18.04 # 圖形使用者介面 切換 命令列介面 sudo systemctl set-default multi-user.target # 命令列介面 切換 圖形使用者介面 systemctl set-default graphical.target reboot # 命令列介面 想進入 圖形使用者介面(僅進入一次,重啟系統後仍然會進入命令列模式) sudo systemctl start lightdm ``` > https://ask.csdn.net/questions/695344 > > https://askubuntu.com/a/788465 ### 其他操作 #### 修改配置檔案 1. 直接修改`/lib/systemd/system`目錄下的單元檔案 > 如果軟體包更新,修改會被丟棄 2. 將`/lib/systemd/system`中的單元檔案複製到`/etc/systemd/system/` > 如果軟體包更新,不會同步更新 3. 在`/etc/systemd/system/` 中新增配置(推薦) ###### 新增配置 步驟: 1. 在`/etc/systemd/system/` 目錄下新建`<單元名>.d`目錄 2. 在`<單元名>.d`目錄下,新建`<單元名>.conf`檔案 3. 在`<單元名>.conf`檔案中修改配置 測試: 1. 建立目錄及檔案 ```bash # /mysql.service.d lfp@legion:/etc/systemd/system/mysql.service.d$ ls mysql.conf ``` 2. 修改配置 ```bash # MySQL Systemd service config file # 不需要所有的組,僅新增需要修改的組及選項 [Unit] Description=MySQL Community Server config test [Service] ExecStartPost=/home/lfp/bin/espeak.sh ``` 3. 重啟測試 ```bash lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl daemon-reload lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl restart mysql.service lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl status mysql.service lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl status mysql.service # 描述已經被修改 ● mysql.service - MySQL Community Server config test Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled) # 加入了配置檔案 Drop-In: /etc/systemd/system/mysql.service.d └─mysql.conf Active: active (running) since Thu 2020-05-21 20:18:02 CST; 12min ago # 新增的動作執行成功 Process: 4703 ExecStartPost=/home/lfp/bin/espeak.sh (code=exited, status=0/SUCCESS) Process: 4672 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid (code=exited, status=0/SUCCESS) Process: 4663 ExecStartPre=/usr/share/mysql/mysql-Systemd-start pre (code=exited, status=0/SUCCESS) Main PID: 4674 (mysqld) Tasks: 27 (limit: 4915) CGroup: /system.slice/mysql.service └─4674 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid 5月 21 20:18:02 legion espeak.sh[4703]: ALSA lib pcm_route.c:867:(find_matching_chmap) Found no matching channel map ``` #### 新增開機啟動服務 1. 新增啟動配置檔案 2. 通過 `rc.local`檔案 `/lib/systemd/rc.local.service` ```bash # 如果存在,就自動新增到 multi-user.target # This Unit gets pulled automatically into multi-user.target by # Systemd-rc-local-generator if /etc/rc.local is executable. [Unit] Description=/etc/rc.local Compatibility Documentation=man:systemd-rc-local-generator(8) ConditionFileIsExecutable=/etc/rc.local After=network.target [Service] Type=forking ExecStart=/etc/rc.local start TimeoutSec=0 RemainAfterExit=yes GuessMainPID=no ``` 建立 rc.local 檔案,賦予可執行許可權,即可新增啟動命令 ```bash sudo touch /etc/rc.local chmod 755 /etc/rc.local lfp@legion:/etc$ vim rc.local #!/bin/sh -e echo "test rc.local" > /usr/local/rclocal.log echo "rc.local `date +%Y-%m-%d-%H:%M:%S`" >/home/lfp/log/rclocal.log exit 0 ``` ### system 工具集 #### hostnamectl 主機名管理命令 ###### hostnamectl ###### `hostnamectl status` Show current system hostname and related information ```bash lfp@legion:/lib/systemd/system$ hostnamectl status Static hostname: legion Icon name: computer-laptop Chassis: laptop Machine ID: b28xxxxxxxx2ecafa29e Boot ID: 21xxxxxxxxxxxx1d3a47504d Operating System: Ubuntu 18.04.4 LTS Kernel: Linux 5.3.0-51-generic Architecture: x86-64 ``` #### journalctl 日誌管理命令 Systemd 統一管理所有 Unit 的**啟動日誌**。帶來的好處就是,可以只用`journalctl`一個命令,檢視所有日誌(核心日誌和應用日誌)。 配置檔案 `/etc/systemd/journald.conf` 日誌儲存目錄 `/var/log/journal/` 預設日誌最大限制為所在檔案系統容量的 10%,可通過` /etc/systemd/journald.conf` 中的 SystemMaxUse 欄位來指定 > 該目錄是 systemd 軟體包的一部分。若被刪除,systemd 不會自動建立它,直到下次升級軟體包時重建該目錄。如果該目錄缺失,systemd 會將日誌記錄寫入 /run/systemd/journal。這意味著,系統重啟後日志將丟失。 ###### `journalctl -u [服務名]` 檢視指定單元的日誌 ###### `journalctl -b` - journalctl -b -0 顯示本次啟動的資訊 - journalctl -b -1 顯示上次啟動的資訊 - journalctl -b -2 顯示上上次啟動的資訊 ### 參考 http://manpages.ubuntu.com/manpages/bionic/en/man1/systemctl.1.html http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.unit.5.html https://www.cnblogs.com/yingsong/p/6012180.html https://www.cnblogs.com/sparkdev/p/8472711.html http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html https://linoxide.com/linux-how-to/systemd-boot-process/ https://cloud.tencent.com/developer/article/1516125 https://www.cnblogs.com/sparkdev/p/8472711.html https://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html