Systemd入門教程

CentOS 7使用Systemd替換了SysV。Systemd目的是要取代Unix時代以來一直在使用的init系統,兼容SysV和LSB的啓動腳本,而且夠在進程啓動過程中更有效地引導加載服務。

Systemd的特性

支持並行化任務
同時採用socket式與D-Bus總線式激活服務
按需啓動守護進程(daemon)
利用Linux的cgroups監視進程
支持快照和系統恢復
維護掛載點和自動掛載點
各服務間基於依賴關係進行精密控制





什麼是init系統

在Linux中,init就是initialization(初始化)的縮寫。init是一個daemon(後臺)進程, 它是Linux系統開機啓動(內核加載完畢)後運行的第一個進程,進程號(pid)爲1。直到系統關機它才終止運行,也就是說它也是Linux系統關機前運行的最後一個進程。

Linux系統中所有其他進程都是直接或間接由init進程啓動的, 因此init進程是其他所有進程的父進程或祖先進程。 因此它可以做許多其他進程不能做的事情,接管其他進程不負責的功能。

正是由於其特殊性, 萬一init因爲某種原因不能啓動,那麼Linux系統就再也無法啓動其他進程, 系統就會處於Kernel Panic狀態。

什麼是Systemd

Systemd是System Management Daemon的簡寫(在UNIX系統中,後臺進程都按照慣例以d結尾,因此當你看到一個進程的名字以d結尾,那它極有可能是一個後臺進程), 它是Linux系統中啓動的第一個進程,也就上面所說的init daemon進程。

Systemd的優點是功能強大,使用方便,缺點是體系龐大,非常複雜。事實上,現在還有很多人反對使用Systemd,理由就是它過於複雜,與操作系統的其他部分強耦合,違反keep simple, keep stupid的Unix哲學。

Systemd架構圖



Systemd基本工具


Systemd並不是一個命令,而是一組命令,涉及到系統管理的方方面面。

systemd-analyze

systemd-analyze命令用於查看啓動耗時。

開機啓動過程

Systemd最基本的任務是管理開機啓動過程,並提供開機啓動的一些信息。

想得到開機啓動時間,運行下面命令

$ systemd-analyze

想得到開機時每一個任務啓動的時間,運行下面命令

$ systemd-analyze blame

想得到更多的啓動信息,systemd-analyze 這個命令也可以通過以下命令生成一個描述各個啓動任務信息的svg格式圖片

$ systemd-analyze plot > plot.svg

顯示瀑布狀的啓動過程流

$ systemd-analyze critical-chain

顯示指定服務的啓動流

$ systemd-analyze critical-chain atd.service

systemctl

檢視和控制Systemd的主要命令是systemctl。該命令可用於查看系統狀態和管理系統及服務。詳見man 1 systemctl

在systemctl參數中添加-H <用戶名>@<主機名>可以實現對其他機器的遠程控制。該過程使用ssh鏈接。systemadm是Systemd的官方圖形前端。

# 啓動進入救援狀態(單用戶狀態) $ systemctl rescue # CPU停止工作 $ systemctl halt # 重啓系統 $ systemctl reboot # 關閉系統,切斷電源 $ systemctl poweroff # 暫停系統 $ systemctl suspend # 讓系統進入冬眠狀態 $ systemctl hibernate # 讓系統進入交互式休眠狀態 $ systemctl hybrid-sleep # 讓系統進入進入緊急模式 $ systemctl emergency # 通過ssh遠程控制主機 $ systemctl --host user_name@host_name command $ systemctl -H user_name@host_name command

journalctl

Systemd統一管理所有Unit的啓動日誌。帶來的好處就是,可以只用journalctl一個命令,查看所有日誌(內核日誌和應用日誌)。日誌的配置文件是/etc/systemd/journald.conf

journalctl功能強大,用法非常多。

# 查看所有日誌(默認情況下 ,只保存本次啓動的日誌) $ journalctl # 查看內核日誌(不顯示應用日誌) $ journalctl -k # 查看系統本次啓動的日誌 $ journalctl -b $ journalctl -b -0 # 查看上一次啓動的日誌(需更改設置) $ journalctl -b -1 $ journalctl -b caf0524a1d394ce0bdbcff75b94444fe # 查看指定時間的日誌 $ journalctl --since="2012-10-30 18:17:16" $ journalctl --since "20 min ago" $ journalctl --since yesterday $ journalctl --since "2015-01-10" --until "2015-01-11 03:00" $ journalctl --since 09:00 --until "1 hour ago" $ journalctl --since=today $ journalctl --since "2015-06-01 01:00:00" $ journalctl --since "2015-06-01" --until "2015-06-13 15:00" $ journalctl --since 09:00 --until "1 hour ago" # 顯示尾部的最新10行日誌 $ journalctl -n # 顯示尾部指定行數的日誌 $ journalctl -n 20 # 實時滾動顯示最新日誌 $ journalctl -f # 查看指定服務的日誌 $ journalctl /usr/lib/systemd/systemd # 查看指定進程的日誌 $ journalctl _PID=1 # 查看某個路徑的腳本的日誌 $ journalctl /usr/bin/bash # 查看指定用戶的日誌 $ journalctl _UID=33 $ journalctl _UID=33 --since today # 查看指定用組的日誌 $ journalctl _GID=33 # 查看指定字段的數據 $ journalctl -F _GID # 查看某個Unit的日誌 $ journalctl -u nginx.service $ journalctl -u nginx.service --since today $ journalctl -u nginx.service -u postgresql.service --since today # 實時滾動顯示某個 Unit 的最新日誌 $ journalctl -u nginx.service -f # 合併顯示多個 Unit 的日誌 $ journalctl -u nginx.service -u php-fpm.service --since today # 查看指定優先級(及其以上級別)的日誌,共有8級 # 0: emerg # 1: alert # 2: crit # 3: err # 4: warning # 5: notice # 6: info # 7: debug $ journalctl -p err -b # 日誌默認分頁輸出,--no-pager 改爲正常的標準輸出 $ journalctl --no-pager # 以 JSON 格式(單行)輸出 $ journalctl -b -u nginx.service -o json # 以 JSON 格式(多行)輸出,可讀性更好 format:       * cat       * export       * json       * json-pretty       * json-sse       * short       * short-iso       * short-monotonic       * short-precise       * verbose $ journalctl -b -u nginx.service  -o json-pretty # 顯示日誌佔據的硬盤空間 $ journalctl --disk-usage # 指定日誌文件佔據的最大空間 $ journalctl --vacuum-size=1G # 指定日誌文件保存多久 $ journalctl --vacuum-time=1years # 查看某個應用的日誌 $ journalctl /sbin/crond $ journalctl `which crond` # 以UTC時間格式顯示日誌 $ journalctl --utc # 簡潔顯示有關啓動的日誌 $ journalctl --list-boots # 顯示有關內核啓動的日誌 $ journalctl -k

hostnamectl

hostnamectl命令用於查看當前主機的信息。

# 顯示當前主機的信息 $ hostnamectl # 設置主機名。 $ hostnamectl set-hostname <hostname>

localectl

localectl命令用於查看本地化設置。

# 查看本地化設置 $ localectl $ localectl status $ localectl list-locales $ localectl list-keymaps # 設置本地化參數。 $ localectl set-locale.utf8 $ localectl set-keymap en_GB $ localectl set-x11-keymap en_GB

timedatectl

timedatectl命令用於查看當前時區設置。

# 查看當前時區設置 $ timedatectl # 顯示所有可用的時區 $ timedatectl list-timezones                                                                                    # 顯示系統的當前時間和日期 $ timedatectl status # 設置當前時區 $ timedatectl set-timezone America/New_York $ timedatectl set-timezone UTC $ timedatectl set-time YYYY-MM-DD $ timedatectl set-time HH:MM:SS $ timedatectl set-time 'YYYY-MM-DD HH:MM:SS' $ timedatectl set-local-rtc boolean   # yes/no $ timedatectl set-ntp boolean # 設置硬件時鐘以協調世界時UTC $ timedatectl | grep local #首先確定你的硬件時鐘是否設置爲本地時區 $ timedatectl set-local-rtc 1 #將你的硬件時鐘設置爲本地時區 $ timedatectl set-local-rtc 0 #將你的硬件時鐘設置爲協調世界時 # 將Linux系統時鐘同步到遠程NTP服務器 $ timedatectl set-ntp true #自動時間同步到遠程NTP服務器 $ timedatectl set-ntp false #禁用NTP時間同步 注意:你必須在系統上安裝NTP以實現與NTP服務器的自動時間同步。

loginctl

loginctl命令用於查看當前登錄的用戶。

# 列出當前session $ loginctl list-sessions # 列出當前登錄用戶 $ loginctl list-users # 列出顯示指定用戶的信息 $ loginctl show-user tom

bootctl

與系統加載相關命令

$ bootctl status $ bootctl update $ bootctl install $ bootctl remove

其它命令

$ busctl $ machinectl $ networkctl $ systemd-cgtop $ systemd-cgls

Systemd Unit

系統啓動過程中,Systemd用Unit來組織那些各種不同的任務, 例如生成網絡端口、配置硬件設備、加載存儲設備、開啓後臺服務進程、等等

Systemd要求每一個任務對應一個Unit, 而每一個Unit都需要一個包含必要信息的配置文件,而這些配置文件的語法很簡單,這也是Systemd的要實現的目的之一。

Systemd可以管理所有系統資源。不同的資源統稱爲Unit(單位)。

Unit一共分成12種

Service unit:系統服務
Target unit:多個Unit構成的一個組
Device Unit:硬件設備
Mount Unit:文件系統的掛載點
Automount Unit:自動掛載點
Path Unit:文件或路徑
Scope Unit:不是由Systemd啓動的外部進程
Slice Unit:進程組
Snapshot Unit:Systemd快照,可以切回某個快照
Socket Unit:進程間通信的socket
Swap Unit:swap文件
Timer Unit:定時器










Systemd通過配置文件的後綴名來判斷unit的類型,比如一個service類型的unit的配置文件名通常類似於name.service, 一個mount類型的unit的配置文件名通常類似於name.mount。

# 設置開機自啓動某服務 $ systemctl enable name.service# 停止開機自啓動某服務 $ systemctl disable name.service# 屏蔽(讓它不能啓動)或顯示一個或多個服務 $ systemctl mask name.service# 取消屏蔽(讓它不能啓動)或顯示一個或多個服務 $ systemctl unmask name.service# 查看Unit配置文件的內容 $ systemctl cat name.service# 編輯Unit配置文件的內容 $ systemctl edit name.service# 顯示Unit配置文件的內容 $ systemctl show name.service $ systemctl show name.service -p property # 查看當前系統的所有Unit $ systemctl list-units # 列出所有Unit,包括沒有找到配置文件的或者啓動失敗的 $ systemctl list-units --all # 列出所有沒有運行的Unit $ systemctl list-units --all --state=inactive $ systemctl list-units --type service --all --state=inactive # 列出所有加載失敗的Unit $ systemctl list-units --failed # 列出所有正在運行的、類型爲service的Unit $ systemctl list-units --type=service # 列出所有服務 $ systemctl list-unit-files

Unit的狀態

systemctl status命令用於查看系統狀態和單個Unit的狀態。

# 顯示系統狀態 $ systemctl status # 顯示單個Unit的狀態 $ sysystemctl status bluetooth.service # 顯示遠程主機的某個Unit的狀態 $ systemctl -H [email protected] status httpd.service 除了status命令,systemctl還提供了三個查詢狀態的簡單方法,主要供腳本內部的判斷語句使用。 # 顯示某個Unit是否正在運行 $ systemctl is-active application.service # 顯示某個Unit是否處於啓動失敗狀態 $ systemctl is-failed application.service # 顯示某個Unit服務是否建立了啓動鏈接 $ systemctl is-enabled application.service

Unit管理

對於用戶來說,最常用的是下面這些命令,用於啓動和停止Unit(主要是 service)。

# 立即啓動一個服務 $ systemctl start name.service # 立即停止一個服務 $ systemctl stop name.service # 重啓一個服務 $ systemctl restart name.service #重新啓動一個或多個已經激活的服務 $ systemctl try-restart name.service # 殺死一個服務的所有子進程 $ systemctl kill name.service # 重新加載一個服務的配置文件 $ systemctl reload name.service # 重載所有修改過的配置文件 $ systemctl daemon-reload # 顯示某個Unit的所有底層參數 $ systemctl show httpd.service # 顯示某個Unit的指定屬性的值 $ systemctl show -p CPUShares httpd.service # 設置某個Unit的指定屬性 $ systemctl set-property httpd.service CPUShares=500

Unit依賴關係

Unit之間存在依賴關係:A依賴於B,就意味着Systemd在啓動A的時候,同時會去啓動B。

列出一個Unit的所有依賴。

$ systemctl list-dependencies nginx.service

上面命令的輸出結果之中,有些依賴是Target類型,默認不會展開顯示。如果要展開Target,就需要使用--all參數。

$ systemctl list-dependencies --all nginx.service

Unit的配置文件

Systemd會自動生成一些unit,而這些unit並不會存在配置文件,但是它們可以通過systemctl來訪問。

每一個Unit都有一個配置文件,告訴Systemd怎麼啓動這Unit。Systemd默認從目錄/etc/systemd/system/讀取配置文件。但是裏面存放的大部分文件都是符號鏈接,指向目錄/usr/lib/systemd/system/,真正的配置文件存放在那個目錄。

systemctl enable命令用於在上面兩個目錄之間,建立符號鏈接關係。

$ systemctl enable [email protected]

等同於

$ ln -s '/usr/lib/systemd/system/[email protected]' '/etc/systemd/system/multi-user.target.wants/[email protected]'

如果配置文件裏面設置了開機啓動,systemctl enable命令相當於激活開機啓動。

與之對應的,systemctl disable命令用於在兩個目錄之間,撤銷符號鏈接關係,相當於撤銷開機啓動。

$ systemctl disable [email protected]

配置文件的後綴名,就是該Unit的種類,比如sshd.socket。如果省略,Systemd 默認後綴名爲.service,所以sshd會被理解成sshd.service。

注: 如果同一個配置文件名都處於這兩個文件夾中, systemd會忽略/usr/lib/systemd/system/中的同名配置文件。

配置文件的狀態

systemctl list-unit-files命令用於列出所有配置文件。

# 列出所有配置文件 $ systemctl list-unit-files # 列出指定類型的配置文件 $ systemctl list-unit-files --type=service

這個命令會輸出一個列表。

$ systemctl list-unit-files UNIT FILE              STATE chronyd.service        enabled [email protected]         static [email protected]     disabled

這個列表顯示每個配置文件的狀態,一共有四種。

enabled:已建立啓動鏈接
disabled:沒建立啓動鏈接
static:該配置文件沒有[Install]部分(無法執行),只能作爲其他配置文件的依賴
masked:該配置文件被禁止建立啓動鏈接


注意,從配置文件的狀態無法看出,該Unit是否正在運行。這必須執行前面提到的systemctl status命令。

$ systemctl status bluetooth.service

一旦修改配置文件,就要讓SystemD重新加載配置文件,然後重新啓動,否則修改不會生效。

$ systemctl daemon-reload $ systemctl restart httpd.service
配置文件的格式

配置文件就是普通的文本文件,可以用文本編輯器打開。

systemctl cat命令可以查看配置文件的內容。

$ systemctl cat atd.service [Unit] Description=ATD daemon [Service] Type=forking ExecStart=/usr/bin/atd [Install] WantedBy=multi-user.target

從上面的輸出可以看到,配置文件分成幾個區塊。每個區塊的第一行,是用方括號表示的區別名,比如[Unit]。注意,配置文件的區塊名和字段名,都是大小寫敏感的。

每個區塊內部是一些等號連接的鍵值對。

[Section] Directive1=value Directive2=value . . .

注意:鍵值對的等號兩側不能有空格。

配置文件的區塊

[Unit]區塊通常是配置文件的第一個區塊,用來定義Unit的元數據,以及配置與其他Unit的關係。它的主要字段如下

Description:簡短描述
Documentation:文檔地址
Requires:當前 Unit 依賴的其他 Unit,如果它們沒有運行,當前 Unit 會啓動失敗
Wants:與當前 Unit 配合的其他 Unit,如果它們沒有運行,當前 Unit 不會啓動失敗
BindsTo:與Requires類似,它指定的 Unit 如果退出,會導致當前 Unit 停止運行
Before:如果該字段指定的 Unit 也要啓動,那麼必須在當前 Unit 之後啓動
After:如果該字段指定的 Unit 也要啓動,那麼必須在當前 Unit 之前啓動
Conflicts:這裏指定的 Unit 不能與當前 Unit 同時運行
Condition…:當前 Unit 運行必須滿足的條件,否則不會運行
Assert…:當前 Unit 運行必須滿足的條件,否則會報啓動失敗








[Install]通常是配置文件的最後一個區塊,用來定義如何啓動,以及是否開機啓動。它的主要字段如下

WantedBy:它的值是一個或多個 Target,當前 Unit 激活時(enable)符號鏈接會放入/etc/systemd/system目錄下面以 Target 名 + .wants後綴構成的子目錄中
RequiredBy:它的值是一個或多個 Target,當前 Unit 激活時,符號鏈接會放入/etc/systemd/system目錄下面以 Target 名 + .required後綴構成的子目錄中
Alias:當前 Unit 可用於啓動的別名
Also:當前 Unit 激活(enable)時,會被同時激活的其他 Unit


[Service]區塊用來 Service 的配置,只有Service類型的Unit纔有這個區塊。它的主要字段如下

Type:定義啓動時的進程行爲。它有以下幾種值。
Type=simple:默認值,執行ExecStart指定的命令,啓動主進程
Type=forking:以 fork 方式從父進程創建子進程,創建後父進程會立即退出
Type=oneshot:一次性進程,Systemd 會等當前服務退出,再繼續往下執行
Type=dbus:當前服務通過D-Bus啓動
Type=notify:當前服務啓動完畢,會通知Systemd,再繼續往下執行
Type=idle:若有其他任務執行完畢,當前服務纔會運行
ExecStart:啓動當前服務的命令
ExecStartPre:啓動當前服務之前執行的命令
ExecStartPost:啓動當前服務之後執行的命令
ExecReload:重啓當前服務時執行的命令
ExecStop:停止當前服務時執行的命令
ExecStopPost:停止當其服務之後執行的命令
RestartSec:自動重啓當前服務間隔的秒數
Restart:定義何種情況 Systemd 會自動重啓當前服務,可能的值包括always(總是重啓)、on-success、on-failure、on-abnormal、on-abort、on-watchdog
TimeoutSec:定義 Systemd 停止當前服務之前等待的秒數
Environment:指定環境變量















Systemd Target

啓動計算機的時候,需要啓動大量的Unit。如果每一次啓動,都要一一寫明本次啓動需要哪些Unit,顯然非常不方便。Systemd的解決方案就是Target。

簡單說,Target就是一個Unit組,包含許多相關的Unit 。啓動某個Target的時候,Systemd就會啓動裏面所有的Unit。從這個意義上說,Target這個概念類似於[狀態點],啓動某個Target就好比啓動到某種狀態。

傳統的init啓動模式裏面,有RunLevel的概念,跟Target的作用很類似。不同的是RunLevel是互斥的,不可能多個RunLevel同時啓動,但是多個Target可以同時啓動。

它與init進程的主要差別如下

  • 默認的RunLevel(在/etc/inittab文件設置)現在被默認的 Target 取代,位置是/etc/systemd/system/default.target,通常符號鏈接到graphical.target(圖形界面)或者multi-user.target(多用戶命令行)。

  • 啓動腳本的位置,以前是/etc/init.d目錄,符號鏈接到不同的 RunLevel 目錄 (比如/etc/rc3.d、/etc/rc5.d等),現在則存放在/lib/systemd/system和/etc/systemd/system目錄。

  • 配置文件的位置,以前init進程的配置文件是/etc/inittab,各種服務的配置文件存放在/etc/sysconfig目錄。現在的配置文件主要存放在/lib/systemd目錄,在/etc/systemd目錄裏面的修改可以覆蓋原始設置。

Target與傳統RunLevel的對應關係如下

Traditional runlevel      New target name     Symbolically linked to... Runlevel 0           |    runlevel0.target -> poweroff.target Runlevel 1           |    runlevel1.target -> rescue.target Runlevel 2           |    runlevel2.target -> multi-user.target Runlevel 3           |    runlevel3.target -> multi-user.target Runlevel 4           |    runlevel4.target -> multi-user.target Runlevel 5           |    runlevel5.target -> graphical.target Runlevel 6           |    runlevel6.target -> reboot.target
# 查看當前系統的所有Target $ systemctl list-unit-files --type=target # 查看一個Target包含的所有Unit $ systemctl list-dependencies multi-user.target # 查看啓動時的默認Target $ systemctl get-default # 設置啓動時的默認Target $ systemctl set-default multi-user.target # 切換Target時,默認不關閉前一個Target啓動的進程, # systemctl isolate 命令改變這種行爲, # 關閉前一個Target裏面所有不屬於後一個Target的進程 $ systemctl isolate multi-user.target


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章