1. 程式人生 > 其它 >Systemd引數指南

Systemd引數指南

systemd 介紹

systemd是目前Linux系統上主要的系統守護程序管理工具,由於init一方面對於程序的管理是序列化的,容易出現阻塞情況,另一方面init也僅僅是執行啟動指令碼,並不能對服務本身進行更多的管理。所以從CentOS 7開始也由systemd取代了init作為預設的系統程序管理工具。
systemd所管理的所有系統資源都稱作Unit,通過systemd命令集可以方便的對這些Unit進行管理。比如systemctl、hostnamectl、timedatectl、localctl等命令,這些命令雖然改寫了init時代使用者的命令使用習慣(不再使用chkconfig、service等命令),但確實也提供了很大的便捷性。

systemd 特點

  • 最新系統都採用systemd管理(RedHat7,CentOS7,Ubuntu15…)
  • CentOS7 支援開機並行啟動服務,顯著提高開機啟動效率
  • CentOS7關機只關閉正在執行的服務,而CentOS6,全部都關閉一次。
  • CentOS7服務的啟動與停止不再使用指令碼進行管理,也就是/etc/init.d下不在有指令碼。
  • CentOS7使用systemd解決原有模式缺陷,比如原有service不會關閉程式產生的子程序。

systemd 語法

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
systemctl [command]      [unit](配置的應用名稱)
command可選項· start:啟動指定的unit          systemctl start nginx· stop:關閉指定的unit           systemctl stop nginx· restart:重啟指定unit          systemctl restart nginx· reload:過載指定unit           systemctl reload nginx· enable:系統開機時自動啟動指定unit,前提是配置檔案中有相關配置 systemctl enable nginx· disable:開機時不自動執行指定unit   systemctl disable nginx· status:檢視指定unit當前執行狀態 systemctl status nginx

systemd 配置檔案說明

  • 每一個 Unit 都需要有一個配置檔案用於告知 systemd 對於服務的管理方式
  • 配置檔案存放於 /usr/lib/systemd/system/,設定開機啟動後會在 /etc/systemd/system 目錄建立軟連結檔案
  • 每個Unit的配置檔案配置預設字尾名為.service
  • 在 /usr/lib/systemd/system/ 目錄中分為 system 和 user 兩個目錄,一般將開機不登陸就能執行的程式存在系統服務裡,也就是 /usr/lib/systemd/system
  • 配置檔案使用方括號分成了多個部分,並且區分大小寫

unit(單元)的配置檔案

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

[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 。

服務型別 unit 的詳細配置

配置檔案分為三個部分,每個部分中都可以提供詳細的配置資訊。為了精確的控制服務的執行方式,我們需要了解這些詳細的配置選項,並最終讓服務以我們期望的方式執行。

[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 啟動了,則指定的服務就不能啟動。

[Service] 部分
Type
說明這個服務的啟動方式,會影響到 ExecStart,主要有下面幾種型別:
simple:預設值,這個服務主要由 ExecStart 設定的程式來啟動,啟動後常駐於記憶體中。
forking:由 ExecStart 指定的啟動的程式通過 spawns 產生子程序提供服務,然後父程序退出。
oneshot:與 simple 類似,不過這個程式在工作完畢後就結束了,不會常駐在記憶體中。
dbus:與 simple 類似,但這個服務必須要在取得一個 D-Bus 的名稱後,才會繼續執行!因此設定這個專案時,通常也要設定 BusName= 才行。
idle:與 simple 類似,意思是,要執行這個服務必須要所有的工作都順利執行完畢後才會執行。這類的服務通常是開機到最後才執行即可的服務。
notify:與 simple 類似,但這個服務必須要收到一個 sd_notify() 函式傳送的訊息後,才會繼續執行。

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

ExecStartPreExecStartPost 分別在服務啟動前後,執行額外的命令。

ExecStop 用來實現 systemctl stop 命令,關閉服務。
ExecReload 用來實現 systemctl reload 命令,重新載入服務的配置資訊。

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 會每隔 15 分鐘執行一次 nickbak.service 服務。

 

systemd 相關檔案

實戰一

原始碼編譯安裝nginx 實現systemd管理控制
安裝nginx編譯環境
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
yum  -y install gcc gcc-c++    openssl-devel pcre-devel gd-devel  iproute net-tools telnet wget curlwget http://nginx.org/download/nginx-1.15.5.tar.gztar zxf nginx-1.15.5.tar.gz &&cd nginx-1.15.5./configure --prefix=/usr/local/nginx \    --with-http_ssl_module \    --with-http_stub_status_module make -j 4 && make install

通用方式啟動nginx

  •  
  •  
  •  
/usr/local/nginx/sbin/nginx  #啟動/usr/local/nginx/sbin/nginx  -s reload  #重啟/usr/local/nginx/sbin/nginx -s   quit   #關閉nginx

systemd 管理控制啟動模式

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
vim      /usr/lib/systemd/system/nginx.service
[Unit]Description=nginxAfter=network.target
[Service]Type=forkingExecStart=/usr/local/nginx/sbin/nginxExecReload=/usr/local/nginx/sbin/nginx -s reloadExecStop=/usr/local/nginx/sbin/nginx -s quitPrivateTmp=true
[Install]WantedBy=multi-user.target

引數詳解

  •  
  •  
  •  
systemctl restart nginxsystemctl enable  nginxsystemctl stop  nginx

實戰二

二進位制安裝tomcat 實現systemd管理控制

安裝java環境,我已經將安裝包打包到我得伺服器上,也可以去官網下載

  •  
  •  
wget  120.78.77.38/file/jdk-8u231-linux-x64.rpmwget  120.78.77.38/file/apache-tomcat-9.0.27.tar.gz
  •  
rpm -ivh  jdk-8u231-linux-x64.rpm    #rpm直接安裝jdk

配置環境變數

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
vim    /etc/profile
export JAVA_HOME=/usr/java/jdk1.8.0_231-amd64export JRE_HOME=${JAVA_HOME}/jre  export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib  export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/binexport  PATH=${JAVA_HOME}/bin:$PATH source   /etc/profilejava -version   #檢測環境

安裝tomcat

  •  
  •  
  •  
  •  
  •  
tar  -xf  apache-tomcat-9.0.27  mv  apache-tomcat-9.0.27  /usr/local/tomcat啟動tomcatsh    /usr/local/tomcat/bin/startup.sh   #啟動sh   /usr/local/tomcat/bin/shutdown.sh #關閉

systemd管理控制啟動

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
vim      /usr/lib/systemd/system/tomcat.service
[Unit]Description=tomcat serverWants=network-online.targetAfter=network.target
[Service]Type=forkingEnvironment="JAVA_HOME=/usr/java/jdk1.8.0_231-amd64"Environment="PATH=$JAVA_HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin"Environment="CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar"ExecStart=/usr/local/tomcat/bin/startup.shExecStop=/usr/local/tomcat/bin/shutdown.shRestart=on-failure
[Install]WantedBy=multi-user.targetsystemctl restart tomcat  #啟動systemctl enable tomcat   #配置自啟systemctl stop  tomcat   #停止服務systemctl status  tomcat  #檢測狀態
以上兩個實戰nginx和tomcat程式中自帶了啟動停止指令碼,如果啟動得程式沒有自帶指令碼則需要自己編寫一個類似得啟動停止指令碼

實戰三

部署jar程式 實現systemd管理控制
實際得專案中會有一些jar程式需要啟動 如果手動啟動則需要輸入一大串命令 停止則需要殺掉程序來停止,很麻煩
舉一個實際啟動得例子切換到jar目錄下
  •  
java -jar decode.jar -Dconfig=/usr/local/abc/application.properties

編寫一個啟動指令碼

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
vim  demo.sh
#!/bin/bash#
source /etc/profilejarName="abc-web.jar"workDir="/usr/local/abc"
start(){    cd ${workDir} && java -jar ${jarName} --spring.profiles.active=prod --server.port=9630 >uams.log 2>&1 &}
stop(){    ps -ef | grep -qP "(?<=-jar)\s+${jarName}" && kill $(ps -ef | grep -P "(?<=-jar)\s+${jarName}" | awk '{print $2}')}
case $1 in    start)        start        ;;    stop)        stop        ;;    restart)        stop        start        ;;esac
編寫 systemd 配置檔案
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
vim  /usr/lib/systemd/system/abc.service
[Unit]Description=uams serverWants=network-online.targetAfter=network.target
[Service]Type=forkingWorkingDirectory=/usr/local/abc/ExecStart=/bin/bash uams.sh startExecStop=/bin/bash uams.sh stopExecReload=/bin/bash uams.sh restartRestart=on-failure
[Install]WantedBy=multi-user.target

啟動abc服務

  •  
  •  
  •  
  •  
systemctl restart abc  #啟動systemctl enable abc   #配置自啟systemctl stop  abc   #停止服務systemctl status  abc  #檢測狀態