systemd 編寫服務管理腳本

咱們運行 linux 服務器的主要目的是經過運行程序提供服務,好比 mysql、web server等。所以管理 linux 服務器主要工做就是配置並管理上面運行的各類服務程序。在 linux 系統中服務程序的管理主要由 init 系統負責。如同筆者在《初識 systemd》一文中的介紹,linux 的 init 系統已經從最初的 sysvinit 進化到了現在的 systemd。本文主要介紹在 systemd 環境中如何編寫運行服務的配置文件。html

unit(單元)的配置文件

Unit 是 systemd 進行任務管理的基本單位,咱們在前文中已經介紹過,service 類型的 unit 表明一個後臺服務進程。接下來咱們就詳細的介紹如何配置 service 類型的 unit。下面咱們先來看一個簡單的服務配置:mysql

[Unit]
Description=Prometheus Server
Documentation=https://prometheus.io/docs/introduction/overview/
After=network.target

[Service]
User=prometheus
Restart=on-failure
WorkingDirectory=/usr/local/share/prometheus/
ExecStart=/usr/local/share/prometheus/prometheus \
          -config.file=/usr/local/share/prometheus/prometheus.yml

[Install]
WantedBy=multi-user.target

這是筆者主機上 prometheus 服務的配置文件。把上面的內容保存到文件 /lib/systemd/system/prometheus.service 中,而後就可使用 systemctl 命令管理 prometheus 服務了。注意,服務類型的配置文件名稱必須以 .service 結尾。
查看上面配置信息的詳細內容,咱們會發現整個配置的內容分爲三個部分:
[Unit] unit 自己的說明,以及與其它有依賴關係的服務的設置,包括在什麼服務以後才啓動此 unit 之類的設置。
[Service] 不一樣的 unit 類型就得要使用相對應的設置項目,好比 timer 類型的 unit 應該是 [Timer],socket 類型的 unit 應該是 [Socket]。服務類型的 unit 就是 [Service],這個項目內主要在規範服務啓動的腳本、環境配置文件文件名、從新啓動的方式等等。
[Install] 這個部分主要設置把該 unit 安裝到哪一個 target 。linux

服務類型 unit 的詳細配置

配置文件分爲三個部分,每一個部分中均可以提供詳細的配置信息。爲了精確的控制服務的運行方式,咱們須要瞭解這些詳細的配置選項,並最終讓服務以咱們指望的方式運行。web

[Unit] 部分
Description    關於該 unit 的簡易說明。
Documentation    文檔相關的內容,如 Documentation=https://prometheus.io/docs/introduction/overview/
                               Documentation=man:sshd(8)
                               Documentation=file:/etc/ssh/sshd_config
After    說明本 unit 是在哪一個服務啓動以後才啓動的意思。僅是說明服務啓動的順序而已,並無強制要求 。
Before    與 After 的意義相反,在指定的服務啓動前最好啓動本個服務的意思。僅是說明服務啓動的順序而已,並沒有強制要求 。
Requires    本 unit 須要在哪一個服務啓動後纔可以啓動!就是設置服務間的依賴性。若是在此項設置的前導服務沒有啓動成功,那麼本 unit 就不會被啓動!
Wants    與 Requires 恰好相反,規範的是這個 unit 以後還要啓動什麼服務,若是這 Wants 後面接的服務若是沒有啓動成功,其實不會影響到這個 unit 自己!
Conflicts    這個項目後面接的服務若是有啓動,那麼本 unit 就不能啓動!若是本 unit 啓動了,則指定的服務就不能啓動。redis

[Service] 部分
Type
說明這個服務的啓動方式,會影響到 ExecStart,主要有下面幾種類型:
simple:默認值,這個服務主要由 ExecStart 設置的程序來啓動,啓動後常駐於內存中。
forking:由 ExecStart 指定的啓動的程序經過 spawns 產生子進程提供服務,而後父進程退出。
oneshot:與 simple 相似,不過這個程序在工做完畢後就結束了,不會常駐在內存中。
dbus:與 simple 相似,但這個服務必需要在取得一個 D-Bus 的名稱後,纔會繼續運行!所以設置這個項目時,一般也要設置 BusName= 才行。
idle:與 simple 相似,意思是,要執行這個服務必需要全部的工做都順利執行完畢後纔會執行。這類的服務一般是開機到最後才執行便可的服務。
notify:與 simple 相似,但這個服務必需要收到一個 sd_notify() 函數發送的消息後,纔會繼續運行。sql

ExecStart
就是實際執行此服務的程序。接受 "命令 參數 參數..." 的格式,不能接受 <, >, >>, |, & 等特殊字符,不少的 bash 語法也不支持。因此,要使用這些特殊的字符時,最好直接寫入到腳本里面去!ubuntu

ExecStartPreExecStartPost 分別在服務啓動先後,執行額外的命令。vim

ExecStop 用來實現 systemctl stop 命令,關閉服務。
ExecReload 用來實現 systemctl reload 命令,從新加載服務的配置信息。bash

Restart 當設置爲 Restart=1 時,若是服務終止,就會自動重啓此服務。
RestartSec 與 Restart 配合使用,在服務終止多長時間以後才從新啓動它。默認是 100ms。服務器

KillMode
能夠是 process, control-group, none 中的一種,若是是 process 則服務終止時,只會終止主要的程序(ExecStart接的後面那串指令),若是是 control-group 時,則由此 daemon 所產生的其餘 control-group 的程序,也都會被關閉。若是是 none 的話,則沒有程序會被關閉。

TimeoutSec
若這個服務在啓動或者是關閉時,由於某些緣故致使沒法順利 "正常啓動或正常結束" 的狀況下,則咱們要等多久才進入 "強制結束" 的狀態!

RemainAfterExit
當設置爲 RemainAfterExit=1 時,則當這個服務所屬的全部程序都終止以後,此服務會再嘗試啓動。這對於 Type=oneshot 的服務頗有幫助!

環境變量的設置對不少程序來講都是十分重要的,下面的配置則能夠以不一樣的方式爲服務程序設置環境變量:
Environment 用來設置環境變量,可使用屢次:

[Service]
# Client Env Vars
Environment=ETCD_CA_FILE=/path/to/CA.pem
Environment=ETCD_CERT_FILE=/path/to/server.crt

EnvironmentFile 經過文件的方式設置環境變量,能夠把下面的內容保存到文件 testenv 中:

AAA_IPV4_ANCHOR_0=X.X.X.X
BBB_IPV4_PRIVATE_0=X.X.X.X
CCC_HOSTNAME=test.example.com

而後這樣設置:

[Service]
EnvironmentFile=/testenv

接下來就能夠在 ExecStart 配置中使用在文件中設置的環境變量,如:

ExecStart=/xxx --abc=xx${AAA_IPV4_ANCHOR_0}yy

[Install] 部分
WantedBy    這個設置後面接的大部分是 *.target unit。意思是,這個 unit 自己是附掛在哪一個 target unit 下面。
Also    當目前這個 unit 被 enable 時,Also 後面接的 unit 也要 enable 的意思。
Alias    當 systemctl enable 相關的服務時,則此服務會進行連接文件的建立!

Timer 類型 unit 的詳細配置

Timer 類型的 unit 主要用來執行定時任務,並有可能取代 cron 服務。因爲 timer 類型的 unit 常常與服務類型的 unit 一塊兒使用,因此本文也附帶介紹一下 timer unit 的配置。與服務類型的 unit 不一樣,timer unit 配置文件中的主要部分是 [Timer],下面是其主要的配置項:
OnActiveSec    當 timers.target 啓動後多久才執行這個 unit。
OnBootSec    當開機後多久才執行這個 unit。
OnStartupSec    當 systemd 第一次啓動後多久才執行這個 unit。
OnUnitActiveSec    這個 timer 配置文件所管理的那個 unit 服務在最後一次啓動後,隔多久後再執行一次。
OnUnitInactiveSec    這個 timer 配置文件所管理的那個 unit 服務在最後一次中止後,隔多久後再執行一次。
Unit    通常不須要設置,基本上咱們設置都是 服務名稱.server + 服務名稱.timer。若是你的服務名稱和 timer 名稱不相同,就須要在 .timer 文件中經過 Unit 項指定服務的名稱。
OnCalendar    使用實際時間(非循環時間)的方式來啓動服務。
Persistent    當使用 OnCalendar 的設置時,指定該功能要不要持續執行。

經過上面的介紹,相信你們對 systemd 服務類型和 timer 類型的 unit 配置已經有了基本的理解,下面讓就讓咱們配置兩個實際的例子。

配置 redis 服務

在 ubuntu 上咱們通常會手動編譯並安裝 redis。在安裝完成後須要把 redis 配置爲 systemd 管理的服務,下面介紹具體的配置過程。
添加 redis 配置文件
首先手動建立 /etc/redis 目錄並添加配置文件:

$ sudo mkdir /etc/redis

並把代碼目錄中的配置文件 redis.conf 拷貝到 /etc/redis 目錄中:

$ sudo cp /tmp/redis-4.0.0/redis.conf /etc/redis/

而後修改配置文件 /etc/redis/redis.conf 中的 supervised 爲 systemd:
supervised systemd

接着繼續在配置文件 /etc/redis/redis.conf 中配置工做目錄,把 dir ./ 修改成:
dir /var/lib/redis

配置由 systemd 管理 redis 服務
建立 /etc/systemd/system/redis.service 文件

$ sudo vim /etc/systemd/system/redis.service

編輯其內容以下:

[Unit]
Description=Redis In-Memory Data Store
After=network.target

[Service]
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always

[Install]
WantedBy=multi-user.target

啓動服務並配置爲開機啓動:

$ sudo systemctl start redis
$ sudo systemctl enable redis
$ sudo systemctl status redis

經過腳本定時備份文件

備份文件的 bash 腳本:

#!/bin/bash
mydate()
{
        date "+%Y%m%d%H%M%S"
}
backupdate=$(mydate)
tar -zcf /tmp/backup.${backupdate}.tar.gz /home/nick/learn

把上面的代碼保存到文件 /usr/local/bin/backupdir.sh,並添加可執行權限:

$ sudo chmod +x /usr/local/bin/backupdir.sh

而後建立 service unit 配置文件:

[Unit]
Description=nick backup learn dir service

[Service]
User=nick
Group=nick
Type=simple
ExecStart=/usr/local/bin/backupdir.sh

[Install]
WantedBy=multi-user.target

把上面的 unit 配置保存到文件 /etc/systemd/system/nickbak.service。
而後執行下面的命令測試服務的執行狀況:

$ sudo systemctl daemon-reload
$ sudo systemctl start nickbak.service

這樣的備份任務只會在執行 sudo systemctl start nickbak.service 時執行一次。下面咱們經過 timer unit 把它配置爲定時執行。
建立 timer unit 配置文件:

[Unit]
Description=nick backup learn dir timer

[Timer]
OnCalendar=*:0/15
Persistent=true
Unit=nickbak.service

[Install]
WantedBy=multi-user.target

把上面的 unit 配置保存到文件 /etc/systemd/system/nickbak.timer。配置中 OnCalendar=*:0/15 表示每 15 分鐘執行一次 nickbak.service 服務。

執行下面的命令把 nickbak.timer 設置爲開機啓動,並啓動 nickbak.timer:

$ sudo systemctl daemon-reload
$ sudo systemctl enable nickbak.timer
$ sudo systemctl start nickbak.timer

如今來看看 nickbak.timer 的狀態:

$ sudo systemctl status nickbak.timer

從如今開始 nickbak.timer 會每隔 15 分鐘執行一次 nickbak.service 服務。

總結

systemd 提供了服務管理(實際上是 unit 管理)的方方面面,咱們須要作的就是寫好服務 unit 的配置文件,而後利用 systemd 來管理咱們的服務。這是一個看似簡單實則繁瑣的任務(不少的配置項其實須要咱們在實踐中不斷的調整並優化)。但願本文對你們來講是個簡單的入門。

參考:
鳥哥的私房菜

相關文章
相關標籤/搜索