Skip to main content

第 10 章:認識系統服務 Daemons

systemd 使用的 unit 分類

  • 平行處理所有服務,加速開機流程
  • 一經要求就回應的 on-demand 啟動方式
  • 服務相依性的自我檢查
  • 依 daemon 功能分類
  • 將多個 daemons 集合成為一個群組
  • 向下相容舊有的 init 服務腳本

systemd 的設定檔放置目錄

systemd 將過去所謂的 daemon 執行腳本通通稱為一個服務單位 (unit),而每種服務單位依據功能來區分時,就分類為不同的類型 (type)。 基本的類型有包括系統服務、資料監聽與交換的插槽檔服務 (socket)、儲存系統狀態的快照類型、提供不同類似執行等級分類的操作環境 (target) 等等。 因為設定檔都放置在底下的目錄中

  • /usr/lib/systemd/system/:每個服務最主要的啟動腳本設定,有點類似以前的 /etc/init.d 底下的檔案;
  • /run/systemd/system/:系統執行過程中所產生的服務腳本,這些腳本的優先序要比 /usr/lib/systemd/system/ 高!
  • /etc/systemd/system/:管理員依據主機系統的需求所建立的執行腳本,其實這個目錄有點像以前 /etc/rc.d/rc5.d/Sxx 之類的功能!執行優先序又比 /run/systemd/system/ 高喔!

也就是說,到底系統開機會不會執行某些服務其實是看 /etc/systemd/system/ 底下的設定,所以該目錄底下就是一大堆連結檔。而實際執行的 systemd 啟動腳本設定檔, 其實都是放置在 /usr/lib/systemd/system/ 底下的喔!因此如果你想要修改某個服務啟動的設定,應該要去 /usr/lib/systemd/system/ 底下修改才對! /etc/systemd/system/ 僅是連結到正確的執行腳本設定檔而已。所以想要看執行腳本設定,應該就得要到 /usr/lib/systemd/system/ 底下去查閱才對!

systemd 的 unit 類型分類說明

systemd 的 unit 類型分類說明
ll /usr/lib/systemd/system/ | grep -E '(vsftpd|multi|cron)'

-rw-r--r--. 1 root root 284 7月 30 2014 crond.service
-rw-r--r--. 1 root root 567 3月 6 06:51 multipathd.service
-rw-r--r--. 1 root root 524 3月 6 13:48 multi-user.target
drwxr-xr-x. 2 root root 4096 5月 4 17:52 multi-user.target.wants
lrwxrwxrwx. 1 root root 17 5月 4 17:52 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 5月 4 17:52 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 5月 4 17:52 runlevel4.target -> multi-user.target
-rw-r--r--. 1 root root 171 6月 10 2014 vsftpd.service
-rw-r--r--. 1 root root 184 6月 10 2014 vsftpd@.service
-rw-r--r--. 1 root root 89 6月 10 2014 vsftpd.target

# 比較重要的是上頭提供的那三行特殊字體的部份!
常見的 systemd 的服務類型
副檔名主要服務功能
.service一般服務類型 (service unit):主要是系統服務,包括伺服器本身所需要的本機服務以及網路服務都是!比較經常被使用到的服務大多是這種類型! 所以,這也是最常見的類型了!
.socket內部程序資料交換的插槽服務 (socket unit):主要是 IPC (Inter-process communication) 的傳輸訊息插槽檔 (socket file) 功能。 這種類型的服務通常在監控訊息傳遞的插槽檔,當有透過此插槽檔傳遞訊息來說要連結服務時,就依據當時的狀態將該用戶的要求傳送到對應的 daemon, 若 daemon 尚未啟動,則啟動該 daemon 後再傳送用戶的要求。
使用 socket 類型的服務一般是比較不會被用到的服務,因此在開機時通常會稍微延遲啟動的時間 (因為比較沒有這麼常用嘛!)。一般用於本機服務比較多,例如我們的圖形界面很多的軟體都是透過 socket 來進行本機程序資料交換的行為。 (這與早期的 xinetd 這個 super daemon 有部份的相似喔!)
.target執行環境類型 (target unit):其實是一群 unit 的集合,例如上面表格中談到的 multi-user.target 其實就是一堆服務的集合~也就是說, 選擇執行 multi-user.target 就是執行一堆其他 .service 或/及 .socket 之類的服務就是了!
.mount.automount檔案系統掛載相關的服務 (automount unit / mount unit):例如來自網路的自動掛載、NFS 檔案系統掛載等與檔案系統相關性較高的程序管理。
.path偵測特定檔案或目錄類型 (path unit):某些服務需要偵測某些特定的目錄來提供佇列服務,例如最常見的列印服務,就是透過偵測列印佇列目錄來啟動列印功能! 這時就得要 .path 的服務類型支援了!
.timer循環執行的服務 (timer unit):這個東西有點類似 anacrontab 喔!不過是由 systemd 主動提供的,比 anacrontab 更加有彈性!

透過 systemctl 管理服務

基本上, systemd 這個啟動服務的機制,主要是透過一隻名為 systemctl 的指令來處理的!跟以前 systemV 需要 service / chkconfig / setup / init 等指令來協助不同, systemd 就是僅有 systemctl 這個指令來處理而已呦!

透過 systemctl 管理單一服務 (service unit) 的啟動/開機啟動與觀察狀態

透過 systemctl 管理單一服務
systemctl [command] [unit]

command 主要有:
start :立刻啟動後面接的 unit
stop :立刻關閉後面接的 unit
restart :立刻關閉後啟動後面接的 unit,亦即執行 stop 再 start 的意思
reload :不關閉後面接的 unit 的情況下,重新載入設定檔,讓設定生效
enable :設定下次開機時,後面接的 unit 會被啟動
disable :設定下次開機時,後面接的 unit 不會被啟動
status :目前後面接的這個 unit 的狀態,會列出有沒有正在執行、開機預設執行否、登錄等資訊等!
is-active :目前有沒有正在運作中
is-enabled:開機時有沒有預設要啟用這個 unit範例一:看看目前 atd 這個服務的狀態為何?
systemctl status atd.service
atd.service - Job spooling tools
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled)
Active: active (running) since Mon 2015-08-10 19:17:09 CST; 5h 42min ago
Main PID: 1350 (atd)
CGroup: /system.slice/atd.service
└─1350 /usr/sbin/atd -f

Aug 10 19:17:09 study.centos.vbird systemd[1]: Started Job spooling tools.
# 重點在第二、三行喔~
# Loaded:這行在說明,開機的時候這個 unit 會不會啟動,enabled 為開機啟動,disabled 開機不會啟動
# Active:現在這個 unit 的狀態是正在執行 (running) 或沒有執行 (dead)
# 後面幾行則是說明這個 unit 程序的 PID 狀態以及最後一行顯示這個服務的登錄檔資訊!
# 登錄檔資訊格式為:『時間』 『訊息發送主機』 『哪一個服務的訊息』 『實際訊息內容』
# 所以上面的顯示訊息是:這個 atd 預設開機就啟動,而且現在正在運作的意思!範例二:正常關閉這個 atd 服務
systemctl stop atd.service
systemctl status atd.service
atd.service - Job spooling tools
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled)
Active: inactive (dead) since Tue 2015-08-11 01:04:55 CST; 4s ago
Process: 1350 ExecStart=/usr/sbin/atd -f $OPTS (code=exited, status=0/SUCCESS)
Main PID: 1350 (code=exited, status=0/SUCCESS)

Aug 10 19:17:09 study.centos.vbird systemd[1]: Started Job spooling tools.
Aug 11 01:04:55 study.centos.vbird systemd[1]: Stopping Job spooling tools...
Aug 11 01:04:55 study.centos.vbird systemd[1]: Stopped Job spooling tools.
# 目前這個 unit 下次開機還是會啟動,但是現在是沒在運作的狀態中!同時,
# 最後兩行為新增加的登錄訊息,告訴我們目前的系統狀態喔!

回到 systemctl status atd.service 的第三行,不是有個 Active 的 daemon 現在狀態嗎?除了 running 跟 dead 之外, 有沒有其他的狀態呢?有的~基本上有幾個常見的狀態:

  • active (running):正有一隻或多隻程序正在系統中執行的意思,舉例來說,正在執行中的 vsftpd 就是這種模式。
  • active (exited):僅執行一次就正常結束的服務,目前並沒有任何程序在系統中執行。 舉例來說,開機或者是掛載時才會進行一次的 quotaon 功能,就是這種模式! quotaon 不須一直執行~只須執行一次之後,就交給檔案系統去自行處理囉!通常用 bash shell 寫的小型服務,大多是屬於這種類型 (無須常駐記憶體)。
  • active (waiting):正在執行當中,不過還再等待其他的事件才能繼續處理。舉例來說,列印的佇列相關服務就是這種狀態! 雖然正在啟動中,不過,也需要真的有佇列進來 (列印工作) 這樣他才會繼續喚醒印表機服務來進行下一步列印的功能。
  • inactive:這個服務目前沒有運作的意思。

既然 daemon 目前的狀態就有這麼多種了,那麼 daemon 的預設狀態有沒有可能除了 enable/disable 之外,還有其他的情況呢?當然有!

  • enabled:這個 daemon 將在開機時被執行
  • disabled:這個 daemon 在開機時不會被執行
  • static:這個 daemon 不可以自己啟動 (enable 不可),不過可能會被其他的 enabled 的服務來喚醒 (相依屬性的服務)
  • mask:這個 daemon 無論如何都無法被啟動!因為已經被強制註銷 (非刪除)。可透過 systemctl unmask 方式改回原本狀態

服務啟動/關閉與觀察的練習

問題:找到系統中名為 chronyd 的服務,觀察此服務的狀態,觀察完畢後,將此服務設定為:

  1. 開機不會啟動
  2. 現在狀況是關閉的情況!

回答:

# 1. 觀察一下狀態,確認是否為關閉/未啟動呢?
systemctl status chronyd.service
hronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled)
Active: active (running) since Mon 2015-08-10 19:17:07 CST; 24h ago
.....(底下省略).....

# 2. 由上面知道目前是啟動的,因此立刻將他關閉,同時開機不會啟動才行!
systemctl stop chronyd.service
systemctl disable chronyd.service
rm '/etc/systemd/system/multi-user.target.wants/chronyd.service'
# 看得很清楚~其實就是從 /etc/systemd/system 底下刪除一條連結檔案而已~

systemctl status chronyd.service
chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled)
Active: inactive (dead)
# 如此則將 chronyd 這個服務完整的關閉了!

強迫服務註銷 (mask) 的練習

比較正規的作法是,要關閉 cups.service 時,連同其他兩個會喚醒 service 的 cups.socket 與 cups.path 通通關閉,那就沒事了! 比較不正規的作法是,那就強迫 cups.service 註銷吧!透過 mask 的方式來將這個服務註銷看看!

強迫服務註銷的練習
# 1. 保持剛剛的狀態,關閉 cups.service,啟動 cups.socket,然後註銷 cups.servcie
systemctl stop cups.service
systemctl mask cups.service
ln -s '/dev/null' '/etc/systemd/system/cups.service'
# 喔耶~其實這個 mask 註銷的動作,只是讓啟動的腳本變成空的裝置而已!

systemctl status cups.service
cups.service
Loaded: masked (/dev/null)
Active: inactive (dead) since Tue 2015-08-11 23:14:16 CST; 52s ago

systemctl start cups.service
Failed to issue method call: Unit cups.service is masked. # 再也無法喚醒!

上面的範例你可以仔細推敲一下~原來整個啟動的腳本設定檔被連結到 `/dev/null 這個空裝置~因此,無論如何你是再也無法啟動這個 cups.service 了! 透過這個 mask 功能,你就可以不必管其他相依服務可能會啟動到這個想要關閉的服務了!雖然是非正規,不過很有效! ^_^

那如何取消註銷呢?當然就是 unmask 即可啊!

systemctl unmask cups.service
rm '/etc/systemd/system/cups.service'
systemctl status cups.service
cups.service - CUPS Printing Service
Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
Active: inactive (dead) since Tue 2015-08-11 23:14:16 CST; 4min 35s ago
# 好佳在有恢復正常!

透過 systemctl 觀察系統上所有的服務

上一小節談到的是單一服務的啟動/關閉/觀察,以及相依服務要註銷的功能。那系統上面有多少的服務存在呢?這個時候就得要透過 list-units 及 list-unit-files 來觀察了! 細部的用法如下:

觀察系統上所有的服務
systemctl [command] [--type=TYPE] [--all]command:
list-units :依據 unit 列出目前有啟動的 unit。若加上 --all 才會列出沒啟動的。
list-unit-files :依據 /usr/lib/systemd/system/ 內的檔案,將所有檔案列表說明。
--type=TYPE:就是之前提到的 unit type,主要有 service, socket, target 等範例一:列出系統上面有啟動的 unit
systemctl
UNIT LOAD ACTIVE SUB DESCRIPTION
proc-sys-fs-binfmt_mis... loaded active waiting Arbitrary Executable File Formats File System
sys-devices-pc...:0:1:... loaded active plugged QEMU_HARDDISK
sys-devices-pc...0:1-0... loaded active plugged QEMU_HARDDISK
sys-devices-pc...0:0-1... loaded active plugged QEMU_DVD-ROM
.....(中間省略).....
vsftpd.service loaded active running Vsftpd ftp daemon
.....(中間省略).....
cups.socket loaded failed failed CUPS Printing Service Sockets
.....(中間省略).....
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.

141 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
# 列出的項目中,主要的意義是:
# UNIT :項目的名稱,包括各個 unit 的類別 (看副檔名)
# LOAD :開機時是否會被載入,預設 systemctl 顯示的是有載入的項目而已喔!
# ACTIVE :目前的狀態,須與後續的 SUB 搭配!就是我們用 systemctl status 觀察時,active 的項目!
# DESCRIPTION :詳細描述囉
# cups 比較有趣,因為剛剛被我們玩過,所以 ACTIVE 竟然是 failed 的喔!被玩死了! ^_^
# 另外,systemctl 都不加參數,其實預設就是 list-units 的意思!範例二:列出所有已經安裝的 unit 有哪些?
systemctl list-unit-files
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
dev-mqueue.mount static
proc-fs-nfsd.mount static
.....(中間省略).....
systemd-tmpfiles-clean.timer static

336 unit files listed.

使用 systemctl list-unit-files 會將系統上所有的服務通通列出來~而不像 list-units 僅以 unit 分類作大致的說明。 至於 STATE 狀態就是前兩個小節談到的開機是否會載入的那個狀態項目囉!主要有 enabled、disabled、mask、static 等等。

假設我不想要知道這麼多的 unit 項目,我只想要知道 service 這種類別的 daemon 而已,而且不論是否已經啟動,通通要列出來! 那該如何是好?

systemctl list-units --type=service --all# 只剩下 *.service 的項目才會出現喔!範例一:查詢系統上是否有以 cpu 為名的服務?
systemctl list-units --type=service --all | grep cpu
cpupower.service loaded inactive dead Configure CPU power related settings
# 確實有喔!可以改變 CPU 電源管理機制的服務哩!

透過 systemctl 管理不同的操作環境 (target unit)

透過上個小節我們知道系統上所有的 systemd 的 unit 觀察的方式,那麼可否列出跟操作界面比較有關的 target 項目。

透過 systemctl 管理不同的操作環境
systemctl list-units --type=target --all
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Encrypted Volumes
emergency.target loaded inactive dead Emergency Mode
final.target loaded inactive dead Final Step
getty.target loaded active active Login Prompts
graphical.target loaded active active Graphical Interface
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded inactive dead Network is Online
network.target loaded active active Network
nss-user-lookup.target loaded inactive dead User and Group Name Lookups
paths.target loaded active active Paths
remote-fs-pre.target loaded active active Remote File Systems (Pre)
remote-fs.target loaded active active Remote File Systems
rescue.target loaded inactive dead Rescue Mode
shutdown.target loaded inactive dead Shutdown
slices.target loaded active active Slices
sockets.target loaded active active Sockets
sound.target loaded active active Sound Card
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
syslog.target not-found inactive dead syslog.target
time-sync.target loaded inactive dead System Time Synchronized
timers.target loaded active active Timers
umount.target loaded inactive dead Unmount All Filesystems

LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.

26 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.
  • graphical.target:就是文字加上圖形界面,這個項目已經包含了底下的 multi-user.target 項目!
  • multi-user.target:純文字模式!
  • rescue.target:在無法使用 root 登入的情況下,systemd 在開機時會多加一個額外的暫時系統,與你原本的系統無關。這時你可以取得 root 的權限來維護你的系統。 但是這是額外系統,因此可能需要動到 chroot 的方式來取得你原有的系統喔!再後續的章節我們再來談!
  • emergency.target:緊急處理系統的錯誤,還是需要使用 root 登入的情況,在無法使用 rescue.target 時,可以嘗試使用這種模式!
  • shutdown.target:就是關機的流程。
  • getty.target:可以設定你需要幾個 tty 之類的,如果想要降低 tty 的項目,可以修改這個東西的設定檔!

正常的模式是 multi-user.target 以及 graphical.target 兩個,救援方面的模式主要是 rescue.target 以及更嚴重的 emergency.target。 如果要修改可提供登入的 tty 數量,則修改 getty.target 項目。基本上,我們最常使用的當然就是 multi-user 以及 graphical 囉! 那麼我如何知道目前的模式是哪一種?又得要如何修改呢?底下來玩一玩吧!

修改可提供登入的 tty 數量
systemctl [command] [unit.target]

選項與參數:
command:
get-default :取得目前的 target
set-default :設定後面接的 target 成為預設的操作模式
isolate :切換到後面接的模式範例一:我們的測試機器預設是圖形界面,先觀察是否真為圖形模式,再將預設模式轉為文字界面
systemctl get-default
graphical.target # 果然是圖形界面喔!

systemctl set-default multi-user.target
systemctl get-default
multi-user.target

範例二:在不重新開機的情況下,將目前的操作環境改為純文字模式,關掉圖形界面
systemctl isolate multi-user.target範例三:若需要重新取得圖形界面呢?
systemctl isolate graphical.target

要注意,改變 graphical.target 以及 multi-user.target 是透過 isolate 來處理的!鳥哥剛剛接觸到 systemd 的時候,在 multi-user.target 環境下轉成 graphical.target 時, 可以透過 systemctl start graphical.target 喔!然後鳥哥就以為關閉圖形界面即可回到 multi-user.target 的!但使用 systemctl stop graphical.target 卻完全不理鳥哥~這才發現錯了...在 service 部份用 start、stop、restart 才對,在 target 項目則請使用 isolate (隔離不同的操作模式) 才對!

在正常的切換情況下,使用上述 isolate 的方式即可。不過為了方便起見, systemd 也提供了數個簡單的指令給我們切換操作模式之用喔! 大致上如下所示:

systemctl 切換操作模式
systemctl poweroff 系統關機
systemctl reboot 重新開機
systemctl suspend 進入暫停模式
systemctl hibernate 進入休眠模式
systemctl rescue 強制進入救援模式
systemctl emergency 強制進入緊急救援模式

關機、重新開機、救援與緊急模式這沒啥問題,那麼什麼是暫停與休眠模式呢?

  • suspend:暫停模式會將系統的狀態資料保存到記憶體中,然後關閉掉大部分的系統硬體,當然,並沒有實際關機喔! 當使用者按下喚醒機器的按鈕,系統資料會重記憶體中回復,然後重新驅動被大部分關閉的硬體,就開始正常運作!喚醒的速度較快。
  • hibernate:休眠模式則是將系統狀態保存到硬碟當中,保存完畢後,將電腦關機。當使用者嘗試喚醒系統時,系統會開始正常運作, 然後將保存在硬碟中的系統狀態恢復回來。因為資料是由硬碟讀出,因此喚醒的效能與你的硬碟速度有關。

透過 systemctl 分析各服務之間的相依性

systemctl list-dependencies
systemctl list-dependencies [unit] [--reverse]

選項與參數:
--reverse :反向追蹤誰使用這個 unit 的意思!範例一:列出目前的 target 環境下,用到什麼特別的 unit
systemctl get-default
multi-user.target

systemctl list-dependencies
default.target
├─abrt-ccpp.service
├─abrt-oops.service
├─vsftpd.service
├─basic.target
│ ├─alsa-restore.service
│ ├─alsa-state.service
.....(中間省略).....
│ ├─sockets.target
│ │ ├─avahi-daemon.socket
│ │ ├─dbus.socket
.....(中間省略).....
│ ├─sysinit.target
│ │ ├─dev-hugepages.mount
│ │ ├─dev-mqueue.mount
.....(中間省略).....
│ └─timers.target
│ └─systemd-tmpfiles-clean.timer
├─getty.target
│ └─getty@tty1.service
└─remote-fs.target

因為我們前一小節的練習將預設的操作模式變成 multi-user.target 了,因此這邊使用 list-dependencies 時,所列出的 default.target 其實是 multi-user.target 的內容啦!根據線條連線的流程,我們也能夠知道, multi-user.target 其實還會用到 basic.target + getty.target + remote-fs.target 三大項目, 而 basic.target 又用到了 sockets.target + sysinit.target + timers.target... 等一堆~所以囉,從這邊就能夠清楚的查詢到每種 target 模式底下還有的相依模式。 那麼如果要查出誰會用到 multi-user.target 呢?就這麼作!

systemctl list-dependencies --reverse
systemctl list-dependencies --reverse
default.target
└─graphical.target

reverse 本來就是反向的意思,所以加上這個選項,代表『誰還會用到我的服務』的意思~所以看得出來, multi-user.target 主要是被 graphical.target 所使用喔! 好~那再來,graphical.target 又使用了多少的服務呢?可以這樣看:

systemctl list-dependencies graphical.target
systemctl list-dependencies graphical.target
graphical.target
├─accounts-daemon.service
├─gdm.service
├─network.service
├─rtkit-daemon.service
├─systemd-update-utmp-runlevel.service
└─multi-user.target
├─abrt-ccpp.service
├─abrt-oops.service
.....(底下省略).....

所以可以看得出來,graphical.target 就是在 multi-user.target 底下再加上 accounts-daemon, gdm, network, rtkit-deamon, systemd-update-utmp-runlevel 等服務而已! 這樣會看了嗎?了解 daemon 之間的相關性也是很重要的喔!出問題時,可以找到正確的服務相依流程!

與 systemd 的 daemon 運作過程相關的目錄簡介

我們在前幾小節曾經談過比較重要的 systemd 啟動腳本設定檔在 /usr/lib/systemd/system/, /etc/systemd/system/ 目錄下,那還有哪些目錄跟系統的 daemon 運作有關呢? 基本上是這樣的:

  • /usr/lib/systemd/system/:使用 CentOS 官方提供的軟體安裝後,預設的啟動腳本設定檔都放在這裡,這裡的資料盡量不要修改~ 要修改時,請到 /etc/systemd/system 底下修改較佳!
  • /run/systemd/system/:系統執行過程中所產生的服務腳本,這些腳本的優先序要比 /usr/lib/systemd/system/ 高!
  • /etc/systemd/system/:管理員依據主機系統的需求所建立的執行腳本,其實這個目錄有點像以前 /etc/rc.d/rc5.d/Sxx 之類的功能!執行優先序又比 /run/systemd/system/ 高喔!
  • /etc/sysconfig/*:幾乎所有的服務都會將初始化的一些選項設定寫入到這個目錄下,舉例來說,mandb 所要更新的 man page 索引中,需要加入的參數就寫入到此目錄下的 man-db 當中喔!而網路的設定則寫在 /etc/sysconfig/network-scripts/ 這個目錄內。所以,這個目錄內的檔案也是挺重要的;
  • /var/lib/:一些會產生資料的服務都會將他的資料寫入到 /var/lib/ 目錄中。舉例來說,資料庫管理系統 Mariadb 的資料庫預設就是寫入 /var/lib/mysql/ 這個目錄下啦!
  • /run/:放置了好多 daemon 的暫存檔,包括 lock file 以及 PID file 等等。

我們知道 systemd 裡頭有很多的本機會用到的 socket 服務,裡頭可能會產生很多的 socket file ~那你怎麼知道這些 socket file 放置在哪裡呢? 很簡單!還是透過 systemctl 來管理!

systemctl list-sockets
systemctl list-sockets
LISTEN UNIT ACTIVATES
/dev/initctl systemd-initctl.socket systemd-initctl.service
/dev/log systemd-journald.socket systemd-journald.service
/run/dmeventd-client dm-event.socket dm-event.service
/run/dmeventd-server dm-event.socket dm-event.service
/run/lvm/lvmetad.socket lvm2-lvmetad.socket lvm2-lvmetad.service
/run/systemd/journal/socket systemd-journald.socket systemd-journald.service
/run/systemd/journal/stdout systemd-journald.socket systemd-journald.service
/run/systemd/shutdownd systemd-shutdownd.socket systemd-shutdownd.service
/run/udev/control systemd-udevd-control.socket systemd-udevd.service
/var/run/avahi-daemon/socket avahi-daemon.socket avahi-daemon.service
/var/run/cups/cups.sock cups.socket cups.service
/var/run/dbus/system_bus_socket dbus.socket dbus.service
/var/run/rpcbind.sock rpcbind.socket rpcbind.service
@ISCSIADM_ABSTRACT_NAMESPACE iscsid.socket iscsid.service
@ISCSID_UIP_ABSTRACT_NAMESPACE iscsiuio.socket iscsiuio.service
kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service

16 sockets listed.
Pass --all to see loaded but inactive sockets, too.

這樣很清楚的就能夠知道正在監聽本機服務需求的 socket file 所在的檔名位置囉!

網路服務與埠口對應簡介

嗯!那麼想一想,系統上面有沒有什麼設定可以讓服務與埠號對應在一起呢?那就是 /etc/services 啦!

/etc/services
cat /etc/services....(前面省略)....
ftp 21/tcp
ftp 21/udp fsp fspd
ssh 22/tcp # The Secure Shell (SSH) Protocol
ssh 22/udp # The Secure Shell (SSH) Protocol
....(中間省略)....
http 80/tcp www www-http # WorldWideWeb HTTP
http 80/udp www www-http # HyperText Transfer Protocol
....(底下省略)....# 這個檔案的內容是以底下的方式來編排的:
# <daemon name> <port/封包協定> <該服務的說明>

像上面說的是,第一欄為 daemon 的名稱、第二欄為該 daemon 所使用的埠號與網路資料封包協定, 封包協定主要為可靠連線的 TCP 封包以及較快速但為非連線導向的 UDP 封包。 舉個例子說,那個遠端連線機制使用的是 ssh 這個服務,而這個服務的使用的埠號為 22 !就是這樣啊!

關閉網路服務

netstat -tlunp
netstat -tlunp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
tcp6 0 0 :::555 :::* LISTEN 29113/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1340/sshd
tcp6 0 0 ::1:25 :::* LISTEN 2387/master
udp 0 0 0.0.0.0:5353 0.0.0.0:* 750/avahi-daemon: r
udp 0 0 0.0.0.0:36540 0.0.0.0:* 750/avahi-daemon: r

如上表所示,我們的系統上至少開了 22, 25, 555, 5353, 36540 這幾個埠口~而其中 5353, 36540 是由 avahi-daemon 這個東西所啟動的! 接下來我們使用 systemctl 去觀察一下,到底有沒有 avahi-daemon 為開頭的服務呢?

systemctl list-units --all | grep avahi-daemon
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
avahi-daemon.socket loaded active running Avahi mDNS/DNS-SD Stack Activation Socket

透過追查,知道這個 avahi-daemon 的目的是在區域網路進行類似網芳的搜尋,因此這個服務可以協助你在區網內隨時了解隨插即用的裝置! 包括筆記型電腦等,只要連上你的區網,你就能夠知道誰進來了。問題是,你可能不要這個協定啊!所以,那就關閉他吧!

systemctl stop avahi-daemon.service
systemctl stop avahi-daemon.socket
systemctl disable avahi-daemon.service avahi-daemon.socket
netstat -tlunp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
tcp6 0 0 :::555 :::* LISTEN 29113/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1340/sshd
tcp6 0 0 ::1:25 :::* LISTEN 2387/master

一般來說,你的本機伺服器至少需要 25 號埠口,而 22 號埠口則最好加上防火牆來管理遠端連線登入比較妥當~因此,上面的埠口中, 除了 555 是我們上一章因為測試而產生的之外,這樣的系統能夠被爬牆的機會已經少很多了! ^_^!OK!現在如果你的系統裡面有一堆網路埠口在監聽, 而你根本不知道那是幹麻用的,鳥哥建議你,現在就透過上面的方式,關閉他吧!

systemctl 針對 service 類型的設定檔

以前,我們如果想要建立系統服務,就得要到 /etc/init.d/ 底下去建立相對應的 bash shell script 來處理。那麼現在 systemd 的環境底下, 如果我們想要設定相關的服務啟動環境,那應該如何處理呢?這就是本小節的任務囉!

systemctl 設定檔相關目錄簡介

現在我們知道服務的管理是透過 systemd,而 systemd 的設定檔大部分放置於 /usr/lib/systemd/system/ 目錄內。但是 Red Hat 官方文件指出, 該目錄的檔案主要是原本軟體所提供的設定,建議不要修改!而要修改的位置應該放置於 /etc/systemd/system/ 目錄內。舉例來說,如果你想要額外修改 vsftpd.service 的話, 他們建議要放置到哪些地方呢?

  • /usr/lib/systemd/system/vsftpd.service:官方釋出的預設設定檔;
  • /etc/systemd/system/vsftpd.service.d/custom.conf:在 /etc/systemd/system 底下建立與設定檔相同檔名的目錄,但是要加上 .d 的副檔名。然後在該目錄下建立設定檔即可。另外,設定檔最好附檔名取名為 .conf 較佳! 在這個目錄下的檔案會『累加其他設定』進入 /usr/lib/systemd/system/vsftpd.service 內喔!
  • /etc/systemd/system/vsftpd.service.wants/*:此目錄內的檔案為連結檔,設定相依服務的連結。意思是啟動了 vsftpd.service 之後,最好再加上這目錄底下建議的服務。
  • /etc/systemd/system/vsftpd.service.requires/*:此目錄內的檔案為連結檔,設定相依服務的連結。意思是在啟動 vsftpd.service 之前,需要事先啟動哪些服務的意思。

基本上,在設定檔裡面你都可以自由設定相依服務的檢查,並且設定加入到哪些 target 裡頭去。但是如果是已經存在的設定檔,或者是官方提供的設定檔, Red Hat 是建議你不要修改原設定,而是到上面提到的幾個目錄去進行額外的客製化設定比較好!當然,這見仁見智~如果你硬要修改原始的 /usr/lib/systemd/system 底下的設定檔。

systemctl 設定檔的設定項目簡介

sshd.service
cat /usr/lib/systemd/system/sshd.service
[Unit] # 這個項目與此 unit 的解釋、執行服務相依性有關
Description=OpenSSH server daemon
After=network.target sshd-keygen.service
Wants=sshd-keygen.service

[Service] # 這個項目與實際執行的指令參數有關
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install] # 這個項目說明此 unit 要掛載哪個 target 底下
WantedBy=multi-user.target

分析上面的設定檔,我們大概能夠將整個設定分為三個部份,就是:

  • [Unit]: unit 本身的說明,以及與其他相依 daemon 的設定,包括在什麼服務之後才啟動此 unit 之類的設定值;
  • [Service], [Socket], [Timer], [Mount], [Path]..:不同的 unit type 就得要使用相對應的設定項目。我們拿的是 sshd.service 來當範本,所以這邊就使用 [Service] 來設定。 這個項目內主要在規範服務啟動的腳本、環境設定檔檔名、重新啟動的方式等等。
  • [Install]:這個項目就是將此 unit 安裝到哪個 target 裡面去的意思!

至於設定檔內有些設定規則還是得要說明一下:

  • 設定項目通常是可以重複的,例如我可以重複設定兩個 After 在設定檔中,不過,後面的設定會取代前面的喔!因此,如果你想要將設定值歸零, 可以使用類似『 After= 』的設定,亦即該項目的等號後面什麼都沒有,就將該設定歸零了 (reset)。
  • 如果設定參數需要有『是/否』的項目 (布林值, boolean),你可以使用 1, yes, true, on 代表啟動,用 0, no, false, off 代表關閉!隨你喜好選擇囉!
  • 空白行、開頭為 # 或 ; 的那一行,都代表註解!

每個部份裡面還有很多的設定細項,我們使用一個簡單的表格來說明每個項目好了!

設定參數參數意義說明
Description就是當我們使用 systemctl list-units 時,會輸出給管理員看的簡易說明!當然,使用 systemctl status 輸出的此服務的說明,也是這個項目!
Documentation這個項目在提供管理員能夠進行進一步的文件查詢的功能!提供的文件可以是如下的資料
Documentation=http://www....
Documentation=man:sshd(8)
Documentation=file:/etc/ssh/sshd_config
After說明此 unit 是在哪個 daemon 啟動之後才啟動的意思!基本上僅是說明服務啟動的順序而已,並沒有強制要求裡頭的服務一定要啟動後此 unit 才能啟動。 以 sshd.service 的內容為例,該檔案提到 After 後面有 network.target 以及 sshd-keygen.service,但是若這兩個 unit 沒有啟動而強制啟動 sshd.service 的話, 那麼 sshd.service 應該還是能夠啟動的!這與 Requires 的設定是有差異的喔!
Before與 After 的意義相反,是在什麼服務啟動前最好啟動這個服務的意思。不過這僅是規範服務啟動的順序,並非強制要求的意思。
Requires明確的定義此 unit 需要在哪個 daemon 啟動後才能夠啟動!就是設定相依服務啦!如果在此項設定的前導服務沒有啟動,那麼此 unit 就不會被啟動!
Wants與 Requires 剛好相反,規範的是這個 unit 之後最好還要啟動什麼服務比較好的意思!不過,並沒有明確的規範就是了!主要的目的是希望建立讓使用者比較好操作的環境。 因此,這個 Wants 後面接的服務如果沒有啟動,其實不會影響到這個 unit 本身!
Conflicts代表衝突的服務!亦即這個項目後面接的服務如果有啟動,那麼我們這個 unit 本身就不能啟動!我們 unit 有啟動,則此項目後的服務就不能啟動! 反正就是衝突性的檢查啦!

接下來了解一下在 [Service] 當中有哪些項目可以使用!

設定參數參數意義說明
Type說明這個 daemon 啟動的方式,會影響到 ExecStart 喔!一般來說,有底下幾種類型
simple:預設值,這個 daemon 主要由 ExecStart 接的指令串來啟動,啟動後常駐於記憶體中
forking:由 ExecStart 啟動的程序透過 spawns 延伸出其他子程序來作為此 daemon 的主要服務。原生的父程序在啟動結束後就會終止運作。 傳統的 unit 服務大多屬於這種項目,例如 httpd 這個 WWW 服務,當 httpd 的程序因為運作過久因此即將終結了,則 systemd 會再重新生出另一個子程序持續運作後, 再將父程序刪除。據說這樣的效能比較好
oneshot:與 simple 類似,不過這個程序在工作完畢後就結束了,不會常駐在記憶體中。
dbus:與 simple 類似,但這個 daemon 必須要在取得一個 D-Bus 的名稱後,才會繼續運作!因此設定這個項目時,通常也要設定 BusName= 才行!
idle:與 simple 類似,意思是,要執行這個 daemon 必須要所有的工作都順利執行完畢後才會執行。這類的 daemon 通常是開機到最後才執行即可的服務!比較重要的項目大概是 simple, forking 與 oneshot 了!畢竟很多服務需要子程序 (forking),而有更多的動作只需要在開機的時候執行一次(oneshot),例如檔案系統的檢查與掛載啊等等的。
EnvironmentFile可以指定啟動腳本的環境設定檔!例如 sshd.service 的設定檔寫入到 /etc/sysconfig/sshd 當中!你也可以使用 Environment= 後面接多個不同的 Shell 變數來給予設定!
ExecStart就是實際執行此 daemon 的指令或腳本程式。你也可以使用 ExecStartPre (之前) 以及 ExecStartPost (之後) 兩個設定項目來在實際啟動服務前,進行額外的指令行為。 但是你得要特別注意的是,指令串僅接受『指令 參數 參數...』的格式,不能接受 <, >, >>, `
ExecStop與 systemctl stop 的執行有關,關閉此服務時所進行的指令。
ExecReload與 systemctl reload 有關的指令行為
Restart當設定 Restart=1 時,則當此 daemon 服務終止後,會再次的啟動此服務。舉例來說,如果你在 tty2 使用文字界面登入,操作完畢後登出,基本上,這個時候 tty2 就已經結束服務了。 但是你會看到螢幕又立刻產生一個新的 tty2 的登入畫面等待你的登入!那就是 Restart 的功能!除非使用 systemctl 強制將此服務關閉,否則這個服務會源源不絕的一直重複產生!
RemainAfterExit當設定為 RemainAfterExit=1 時,則當這個 daemon 所屬的所有程序都終止之後,此服務會再嘗試啟動。這對於 Type=oneshot 的服務很有幫助!
TimeoutSec若這個服務在啟動或者是關閉時,因為某些緣故導致無法順利『正常啟動或正常結束』的情況下,則我們要等多久才進入『強制結束』的狀態!
KillMode可以是 process, control-group, none 的其中一種,如果是 process 則 daemon 終止時,只會終止主要的程序 (ExecStart 接的後面那串指令),如果是 control-group 時, 則由此 daemon 所產生的其他 control-group 的程序,也都會被關閉。如果是 none 的話,則沒有程序會被關閉喔!
RestartSec與 Restart 有點相關性,如果這個服務被關閉,然後需要重新啟動時,大概要 sleep 多少時間再重新啟動的意思。預設是 100ms (毫秒)。

最後,再來看看那麼 Install 內還有哪些項目可用?

設定參數參數意義說明
WantedBy這個設定後面接的大部分是 *.target unit !意思是,這個 unit 本身是附掛在哪一個 target unit 底下的!一般來說,大多的服務性質的 unit 都是附掛在 multi-user.target 底下!
Also當目前這個 unit 本身被 enable 時,Also 後面接的 unit 也請 enable 的意思!也就是具有相依性的服務可以寫在這裡呢!
Alias進行一個連結的別名的意思!當 systemctl enable 相關的服務時,則此服務會進行連結檔的建立!以 multi-user.target 為例,這個傢伙是用來作為預設操作環境 default.target 的規劃, 因此當你設定用成 default.target 時,這個 /etc/systemd/system/default.target 就會連結到 /usr/lib/systemd/system/multi-user.target 囉!

多重的重複設定方式:以 getty 為例

/usr/lib/systemd/system/getty@.service
cat /usr/lib/systemd/system/getty@.service
[Unit]
Description=Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
After=systemd-user-sessions.service plymouth-quit-wait.service
After=rc-local.service
Before=getty.target
ConditionPathExists=/dev/tty0

[Service]
ExecStart=-/sbin/agetty --noclear %I $TERM
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes

[Install]
WantedBy=getty.target

比較重要的當然就是 ExecStart 項目囉!那麼我們去 man agetty 時,發現到它的語法應該是『 agetty --noclear tty1 』之類的字樣, 因此,我們如果要啟動六個 tty 的時候,基本上應該要有六個啟動設定檔。亦即是可能會用到 getty1.service, getty2.service...getty6.service 才對! 哇!這樣控管很麻煩啊~所以,才會出現這個 @ 的項目啦!咦!這個 @ 到底怎麼回事呢?我們先來看看 getty@.service 的上游,亦即是 getty.target 這個東西的內容好了!

systemctl show getty.target# 那個 show 的指令可以將 getty.target 的預設設定值也取出來顯示!
Names=getty.target
Wants=getty@tty1.service
WantedBy=multi-user.target
Conflicts=shutdown.target
Before=multi-user.target
After=getty@tty1.service getty@tty2.service getty@tty3.service getty@tty4.service
getty@tty6.service getty@tty5.service
.....(後面省略).....

你會發現,咦!怎麼會多出六個怪異的 service 呢?我們拿 getty@tty1.service 來說明一下好了!當我們執行完 getty.target 之後, 他會持續要求 getty@tty1.service 等六個服務繼續啟動。那我們的 systemd 就會這麼作:

  • 先看 /usr/lib/systemd/system/, /etc/systemd/system/ 有沒有 getty@tty1.service 的設定,若有就執行,若沒有則執行下一步;
  • getty@.service 的設定,若有則將 @ 後面的資料帶入成 %I 的變數,進入 getty@.service 執行!

這也就是說,其實 getty@tty1.service 實際上是不存在的!他主要是透過 getty@.service 來執行~也就是說, `getty@.service 的目的是為了要簡化多個執行的啟動設定, 他的命名方式是這樣的:

原始檔案:執行服務名稱@.service
執行檔案:執行服務名稱@範例名稱.service

因此當有範例名稱帶入時,則會有一個新的服務名稱產生出來!你再回頭看看 getty@.service 的啟動腳本:

ExecStart=-/sbin/agetty --noclear %I $TERM

上表中那個 %I 指的就是『範例名稱』!根據 getty.target 的資訊輸出來看,getty@tty1.service 的 %I 就是 tty1 囉!因此執行腳本就會變成『 /sbin/agetty --noclear tty1 』! 所以我們才有辦法以一個設定檔來啟動多個 tty1 給用戶登入囉!

將 tty 的數量由 6 個降低到 4 個

現在你應該要感到困擾的是,那麼『 6 個 tty 是誰規定的』為什麼不是 5 個還是 7 個?這是因為 systemd 的登入設定檔 /etc/systemd/logind.conf 裡面規範的啦! 假如你想要讓 tty 數量降低到剩下 4 個的話,那麼可以這樣實驗看看:

# 1. 修改預設的 logind.conf 內容,將原本 6 個虛擬終端機改成 4 個
vim /etc/systemd/logind.conf
[Login]
NAutoVTs=4
ReserveVT=0
# 原本是 6 個而且還註解,請取消註解,然後改成 4 吧!# 2. 關閉不小心啟動的 tty5, tty6 並重新啟動 getty.target 囉!
systemctl stop getty@tty5.service
systemctl stop getty@tty6.service
systemctl restart systemd-logind.service

現在你再到桌面環境下,按下 [ctrl]+[alt]+[F1]~[F6] 就會發現,只剩下四個可用的 tty 囉!後面的 tty5, tty6 已經被放棄了!不再被啟動喔! 好!那麼我暫時需要啟動 tty8 時,又該如何處理呢?需要重新建立一個腳本嗎?不需要啦!可以這樣作!

systemctl start getty@tty8.service

無須額外建立其他的啟動服務設定檔喔!

暫時新增 vsftpd 到 2121 埠口

不知道你有沒有發現,其實在 /usr/lib/systemd/system 底下還有個特別的 vsftpd@.service 喔!來看看他的內容:

cat /usr/lib/systemd/system/vsftpd@.service
[Unit]
Description=Vsftpd ftp daemon
After=network.target
PartOf=vsftpd.target

[Service]
Type=forking
ExecStart=/usr/sbin/vsftpd /etc/vsftpd/%i.conf

[Install]
WantedBy=vsftpd.target

根據前面 getty@.service 的說明,我們知道在啟動的腳本設定當中, %i 或 %I 就是代表 @ 後面接的範例檔名的意思! 那我能不能建立 vsftpd3.conf 檔案,然後透過該檔案來啟動新的服務呢?就來玩玩看!

# 1. 根據 vsftpd@.service 的建議,於 /etc/vsftpd/ 底下先建立新的設定檔
cd /etc/vsftpd
[root@study vsftpd]#cp vsftpd.conf vsftpd3.conf
[root@study vsftpd]#vim vsftpd3.conflisten_port=2121

# 2. 暫時啟動這個服務,不要永久啟動他!
[root@study vsftpd]#systemctl start vsftpd@vsftpd3.service
[root@study vsftpd]#systemctl status vsftpd@vsftpd3.service
vsftpd@vsftpd3.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd@.service; disabled)
Active: active (running) since Thu 2015-08-13 01:34:05 CST; 5s ago

[root@study vsftpd]#netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp6 0 0 :::2121 :::* LISTEN 16404/vsftpd
tcp6 0 0 :::555 :::* LISTEN 12672/vsftpd
tcp6 0 0 :::21 :::* LISTEN 12670/vsftpd

服務範例

備份範例
vim /backups/backup.sh

#!/bin/bash

source="/etc /home /root /var/lib /var/spool/{cron,at,mail}"
target="/backups/backup-system-$(date +%Y-%m-%d).tar.gz"
[ ! -d /backups ] && mkdir /backups
tar -zcvf ${target} ${source} &> /backups/backup.log

chmod a+x /backups/backup.sh
ll /backups/backup.sh-rwxr-xr-x. 1 root root 220 Aug 13 01:57 /backups/backup.sh
# 記得要有可執行的權限才可以喔!

接下來,我們要如何設計一隻名為 backup.service 的啟動腳本設定呢?可以這樣做喔!

vim /etc/systemd/system/backup.service[Unit]
Description=backup my server
Requires=atd.service

[Service]
Type=simple
ExecStart=/bin/bash -c " echo /backups/backup.sh | at now"

[Install]
WantedBy=multi-user.target
# 因為 ExecStart 裡面有用到 at 這個指令,因此, atd.service 就是一定要的服務!

systemctl daemon-reload
systemctl start backup.service
systemctl status backup.service
backup.service - backup my server
Loaded: loaded (/etc/systemd/system/backup.service; disabled)
Active: inactive (dead)

Aug 13 07:50:31 study.centos.vbird systemd[1]: Starting backup my server...
Aug 13 07:50:31 study.centos.vbird bash[20490]: job 8 at Thu Aug 13 07:50:00 2015
Aug 13 07:50:31 study.centos.vbird systemd[1]: Started backup my server.
# 為什麼 Active 是 inactive 呢?這是因為我們的服務僅是一個簡單的 script 啊!
# 因此執行完畢就完畢了,不會繼續存在記憶體中喔!

systemctl 針對 timer 的設定檔

有時候,某些服務你想要定期執行,或者是開機後執行,或者是什麼服務啟動多久後執行等等的。在過去,我們大概都是使用 crond 這個服務來定期處理, 不過,既然現在有一直常駐在記憶體當中的 systemd 這個好用的東西,加上這 systemd 有個協力服務,名為 timers.target 的傢伙,這傢伙可以協助定期處理各種任務! 那麼,除了 crond 之外,如何使用 systemd 內建的 time 來處理各種任務呢?這就是本小節的重點囉!

systemd.timer 的優勢

在 archlinux 的官網 wiki 上面有提到,為啥要使用 systemd.timer 呢?

  • 由於所有的 systemd 的服務產生的資訊都會被紀錄 (log),因此比 crond 在 debug 上面要更清楚方便的多;
  • 各項 timer 的工作可以跟 systemd 的服務相結合;
  • 各項 timer 的工作可以跟 control group (cgroup,用來取代 /etc/secure/limit.conf 的功能) 結合,來限制該工作的資源利用

雖然還是有些弱點啦~例如 systemd 的 timer 並沒有 email 通知的功能 (除非自己寫一個),也沒有類似 anacron 的一段時間內的隨機取樣功能 (random_delay), 不過,總體來說,還是挺不錯的!此外,相對於 crond 最小的單位到分, systemd 是可以到秒甚至是毫秒的單位哩!相當有趣!

任務需求

基本上,想要使用 systemd 的 timer 功能,你必須要有幾個要件:

  • 系統的 timer.target 一定要啟動
  • 要有個 sname.service 的服務存在 (sname 是你自己指定的名稱)
  • 要有個 sname.timer 的時間啟動服務存在

滿足上面的需求就 OK 了!有沒有什麼案例可以來實作看看?這樣說好了,我們上個小節不是才自己做了個 backup.service 的服務嗎?那麼能不能將這個 backup.service 用在定期執行上面呢?好啊!那就來測試看看!

sname.timer 的設定值

你可以到 /etc/systemd/system 底下去建立這個 *.timer 檔,那這個檔案的內容要項有哪些東西呢?基本設定主要有底下這些: (man systemd.timer & man systemd.time)

設定參數參數意義說明
OnActiveSec當 timers.target 啟動多久之後才執行這隻 unit
OnBootSec當開機完成後多久之後才執行
OnStartupSec當 systemd 第一次啟動之後過多久才執行
OnUnitActiveSec這個 timer 設定檔所管理的那個 unit 服務在最後一次啟動後,隔多久後再執行一次的意思
OnUnitInactiveSec這個 timer 設定檔所管理的那個 unit 服務在最後一次停止後,隔多久再執行一次的意思。
OnCalendar使用實際時間 (非循環時間) 的方式來啟動服務的意思!至於時間的格式後續再來談。
Unit一般來說不太需要設定,因此如同上面剛剛提到的,基本上我們設定都是 sname.server + sname.timer,那如果你的 sname 並不相同時,那在 .timer 的檔案中, 就得要指定是哪一個 service unit 囉!
Persistent當使用 OnCalendar 的設定時,指定該功能要不要持續進行的意思。通常是設定為 yes ,比較能夠滿足類似 anacron 的功能喔!

基本的項目僅有這些而已,在設定上其實並不困難啦!

使用於 OnCalendar 的時間

如果你想要從 crontab 轉成這個 timer 功能的話,那麼對於時間設定的格式就得要了解了解~基本上的格式如下所示:

語法:英文周名  YYYY-MM-DD  HH:MM:SS
範例:Thu 2015-08-13 13:40:00

上面談的是基本的語法,你也可以直接使用間隔時間來處理!常用的間隔時間單位有:

  • us 或 usec:微秒 (10 秒)
  • ms 或 msec:毫秒 (10 秒)
  • s, sec, second, seconds
  • m, min, minute, minutes
  • h, hr, hour, hours
  • d, day, days
  • w, week, weeks
  • month, months
  • y, year, years

常見的使用範例有:

隔 3 小時:             3h  或 3hr 或 3hours
隔 300 分鐘過 10 秒: 10s 300m
隔 5 天又 100 分鐘: 100m 5day
# 通常英文的寫法,小單位寫前面,大單位寫後面~所以先秒、再分、再小時、再天數等~

此外,你也可以使用英文常用的口語化日期代表,例如 today, tomorrow 等!假設今天是 2015-08-13 13:50:00 的話,那麼:

英文口語實際的時間格式代表
nowThu 2015-08-13 13:50:00
todayThu 2015-08-13 00:00:00
tomorrowThu 2015-08-14 00:00:00
hourly--* *:00:00
daily--* 00:00:00
weeklyMon --* 00:00:00
monthly--01 00:00:00
+3h10mThu 2015-08-13 17:00:00
2015-08-16Sun 2015-08-16 00:00:00

一個循環時間運作的案例

現在假設這樣:

  • 開機後 2 小時開始執行一次這個 backup.service
  • 自從第一次執行後,未來我每兩天要執行一次 backup.service
vim /etc/systemd/system/backup.timer[Unit]
Description=backup my server timer

[Timer]
OnBootSec=2hrs
OnUnitActiveSec=2days

[Install]
WantedBy=multi-user.target
# 只要這樣設定就夠了!儲存離開吧!

systemctl daemon-reload
systemctl enable backup.timer
systemctl restart backup.timer
systemctl list-unit-files | grep backup
backup.service disabled # 這個不需要啟動!只要 enable backup.timer 即可!
backup.timer enabled

systemctl show timers.target
ConditionTimestamp=Thu 2015-08-13 14:31:11 CST # timer 這個 unit 啟動的時間!

systemctl show backup.service
ExecMainExitTimestamp=Thu 2015-08-13 14:50:19 CST # backup.service 上次執行的時間

systemctl show backup.timer
NextElapseUSecMonotonic=2d 19min 11.540653s # 下一次執行距離 timers.target 的時間

如上表所示,我上次執行 backup.service 的時間是在 2015-08-13 14:50 ,由於設定兩個小時執行一次,因此下次應該是 2015-08-15 14:50 執行才對! 由於 timer 是由 timers.target 這個 unit 所管理的,而這個 timers.target 的啟動時間是在 2015-08-13 14:31 , 要注意,最終 backup.timer 所紀錄的下次執行時間,其實是與 timers.target 所紀錄的時間差!因此是『 2015-08-15 14:50 - 2015-08-13 14:31 』才對! 所以時間差就是 2d 19min 囉!

一個固定日期運作的案例

backup.timer
vim /etc/systemd/system/backup2.timer[Unit]
Description=backup my server timer2

[Timer]
OnCalendar=Sun *-*-* 02:00:00
Persistent=true
Unit=backup.service

[Install]
WantedBy=multi-user.target

systemctl daemon-reload
systemctl enable backup2.timer
systemctl start backup2.timer
systemctl show backup2.timer
NextElapseUSecRealtime=45y 7month 1w 6d 10h 30min

預設啟動的 Daemons 服務

服務名稱功能簡介
abrtd(系統)abrtd 服務可以提供使用者一些方式,讓使用者可以針對不同的應用軟體去設計錯誤登錄的機制, 當軟體產生問題時,使用者就可以根據 abrtd 的登錄檔來進行錯誤克服的行為。還有其他的 abrt-xxx.service 均是使用這個服務來加強應用程式 debug 任務的。
accounts-daemon(可關閉)(系統)使用 accountsservice 計畫所提供的一系列 D-Bus 界面來進行使用者帳號資訊的查詢。 基本上是與 useradd, usermod, userdel 等軟體有關。
alsa-X(可關閉)(系統)開頭為 alsa 的服務有不少,這些服務大部分都與音效有關!一般來說, 伺服器且不開圖形界面的話,這些服務可以關閉!
atd(系統)單一的例行性工作排程,抵擋機制的設定檔在 /etc/at.{allow,deny}
auditd(可以讓系統需 SELinux 稽核的訊息寫入 /var/log/audit/audit.log 中。
avahi-daemon(可關閉)(系統)也是一個用戶端的服務,可以透過 Zeroconf 自動的分析與管理網路。 Zeroconf 較常用在筆記型電腦與行動裝置上,所以我們可以先關閉他啦!
brandbotrhel-*(系統)這些服務大多用於開機過程中所需要的各種偵測環境的腳本,同時也提供網路界面的啟動與關閉。 基本上,你不要關閉掉這些服務比較妥當!
chronydntpdntpdate(系統)都是網路校正時間的服務!一般來說,你可能需要的僅有 chronyd 而已!
cpupower(系統)提供 CPU 的運作規範~可以參考 /etc/sysconfig/cpupower 得到更多的資訊! 這傢伙與你的 CPU 使用情況有關喔!
crond(系統)系統設定檔為 /etc/crontab
cups(可關閉)(系統/網路)用來管理印表機的服務,可以提供網路連線的功能,有點類似列印伺服器的功能哩! 你可以在 Linux 本機上面以瀏覽器的 http://localhost:631 來管理印表機喔!由於我們目前沒有印表機,所以可以暫時關閉他。
dbus(系統)使用 D-Bus 的方式在不同的應用程式之間傳送訊息, 使用的方向例如應用程式間的訊息傳遞、每個使用者登入時提供的訊息資料等。
dm-eventmultipathd(系統)監控裝置對應表 (device mapper) 的主要服務,當然不能關掉啊! 否則就無法讓 Linux 使用我們的週邊裝置與儲存裝置了!
dmraid-activationmdmonitor(系統)用來啟動 Software RAID 的重要服務!最好不要關閉啦!雖然你可能沒有 RAID。
dracut-shutdown(系統)用來處理 initramfs 的相關行為,這與開機流程相關性較高~
ebtables(系統/網路)透過類似 iptables 這種防火牆規則的設定方式,設計網路卡作為橋接時的封包分析政策。 其實就是防火牆。不過與底下談到的防火牆應用不太一樣。如果沒有使用虛擬化,或者啟用了 firewalld ,這個服務可以不啟動。
emergencyrescue(系統)進入緊急模式或者是救援模式的服務
firewalld(系統/網路)就是防火牆!以前有 iptables 與 ip6tables 等防火牆機制,新的 firewalld 搭配 firewall-cmd 指令,可以快速的建置好你的防火牆系統喔!因此,從 CentOS 7.1 以後,iptables 服務的啟動腳本已經被忽略了! 請使用 firewalld 來取代 iptables 服務喔!
gdm(系統)GNOME 的登入管理員,就是圖形界面上一個很重要的登入管理服務!
getty@(系統)就是要在本機系統產生幾個文字界面 (tty) 登入的服務囉!
hyperksmlibvirt*vmtoolsd(系統)跟建立虛擬機器有關的許多服務!如果你不玩虛擬機, 那麼這些服務可以先關閉。此外,如果你的 Linux 本來就在虛擬機的環境下,那這些服務對你就沒有用!因為這些服務是讓實體機器來建立虛擬機的!
irqbalance(系統)如果你的系統是多核心的硬體,那麼這個服務要啟動, 因為它可以自動的分配系統中斷 (IRQ) 之類的硬體資源。
iscsi*(系統)可以掛載來自網路磁碟機的服務!這個服務可以在系統內模擬好貴的 SAN 網路磁碟。 如果你確定系統上面沒有掛載這種網路磁碟,也可以將他關閉的。
kdump(可關閉)(系統)在安裝 CentOS 的章節就談過這東西,主要是 Linux 核心如果出錯時,用來紀錄記憶體的東西。 鳥哥覺得不需要啟動他!除非你是核心駭客!
lvm2-*(系統)跟 LVM 相關性較高的許多服務,當然也不能關!不然系統上面的 LVM2 就沒人管了!
microcode(系統)Intel 的 CPU 會提供一個外掛的微指令集提供系統運作, 不過,如果你沒有下載 Intel 相關的指令集檔案,那麼這個服務不需要啟動的,也不會影響系統運作。
ModemManagernetworkNetworkManager*(系統/網路)主要就是數據機、網路設定等服務!進入 CentOS 7 之後,系統似乎不太希望我們使用 network 服務了, 比較建議的是使用 NetworkManager 搭配 nmcli 指令來處理網路設定~所以,反而是 NetworkManager 要開,而 network 不用開哩!
quotaon(系統)啟動 Quota 要用到的服務喔!
rc-local(系統)相容於 /etc/rc.d/rc.local 的呼叫方式!只是,你必須要讓 /etc/rc.d/rc.local 具有 x 的權限後, 這個服務才能真的運作!否則,你寫入 /etc/rc.d/rc.local 的腳本還是不會運作的喔!
rsyslog(系統)這個服務可以記錄系統所產生的各項訊息, 包括 /var/log/messages 內的幾個重要的登錄檔啊。
smartd(系統)這個服務可以自動的偵測硬碟狀態,如果硬碟發生問題的話, 還能夠自動的回報給系統管理員,是個非常有幫助的服務喔!不可關閉他啊!
sysstat(系統)事實上,我們的系統有隻名為 sar 的指令會記載某些時間點下,系統的資源使用情況,包括 CPU/流量/輸入輸出量等, 當 sysstat 服務啟動後,這些紀錄的資料才能夠寫入到紀錄檔 (log) 裡面去!
systemd-*(系統)大概都是屬於系統運作過程所需要的服務,沒必要都不要更動它的預設狀態!
plymount*upower(系統)與圖形界面的使用相關性較高的一些服務!沒啟動圖形界面時,這些服務可以暫時不管他!
服務名稱功能簡介
dovecot(網路)可以設定 POP3/IMAP 等收受信件的服務,如果你的 Linux 主機是 email server 才需要這個服務,否則不需要啟動他啦!
httpd(網路)這個服務可以讓你的 Linux 伺服器成為 www server 喔!
named(網路)這是領域名稱伺服器 (Domain Name System) 的服務, 這個服務非常重要,但是設定非常困難!目前應該不需要這個服務啦!
nfsnfs-server(網路)這就是 Network Filesystem,是 Unix-Like 之間互相作為網路磁碟機的一個功能。
smbnmb(網路)這個服務可以讓 Linux 模擬成為 Windows 上面的網路上的芳鄰。 如果你的 Linux 主機想要做為 Windows 用戶端的網路磁碟機伺服器,這玩意兒得要好好玩一玩。
vsftpd(網路)作為檔案傳輸伺服器 (FTP) 的服務。
sshd(網路)這個是遠端連線伺服器的軟體功能, 這個通訊協定比 telnet 好的地方在於 sshd 在傳送資料時可以進行加密喔!這個服務不要關閉他啦!
rpcbind(網路)達成 RPC 協定的重要服務!包括 NFS, NIS 等等都需要這東西的協助!
postfix(網路)寄件的郵件主機~因為系統還是會產生很多 email 訊息!例如 crond / atd 就會傳送 email 給本機用戶! 所以這個服務千萬不能關!即使你不是 mail server 也是要啟用這服務才行!