Centos7 Systemd 使用詳解

[toc]php

1、Systemd 是什麼?

systemd 是一個屬於用戶空間的系統服務管理程序,在紅帽 RHEL7 上採用,替代了原來 RHEL6 上的 systemVinit。 其做用是,在內核啓動完成後,初始化用戶空間的進程,進程號爲 1 、管理操做系統的運行級別,系統的服務啓動和關閉,系統的掛載點。html

systemd 的特性:

  • 支持服務並行啓動,實現快速開機
  • 按需啓動守護進程
  • 支持快照和系統恢復
  • 各服務間依賴關係管理
  • 同時採用socket式與D-Bus總線式激活服務
  • 維護掛載點和自動掛載點
  • 能夠經過 Linux 的 cgroups 監控運行的進程

2、Systemd 管理系統的運行級別

查看當前默認的啓動級別
systemctl get-default
切換到多用戶級別
systemctl isolate multi-user.target
或
systemctl isolate runlevel3.target
設置系統默認啓動的運行級別
systemctl set-default multi-user.target
運行級別對應表
systemd target 解釋
runlevel0.target, poweroff.target 關閉系統 —> 0
runlevel1.target, rescue.target 單用戶模式 —> 1
runlevel2.target, runlevel4.target, multi-user.target 用戶定義/域特定運行級別。默認等同於 3 —> 2,4
runlevel3.target, multi-user.target 最經常使用模式,非圖形化多用戶 —> 3
runlevel5.target, graphical.target 多用戶圖形化 —> 5
runlevel6.target, reboot.target 重啓 —> 6
systemd 運行級別配置目錄
/etc/systemd/system/

3、Systemd 管理系統服務

認識 Systemd 下的 unit 文件

在 Systemd 下 unit 文件用於配置對資源的控制,每種資源對應不一樣的 unit 文件類型,好比後臺服務(service)、套接字(socket)、設備(device)、掛載點(mount) 等。 全部 unit 文件都包含兩個通用段 [Unit] 、[Install] 和一個資源類型段,如 [Service] 就表示後臺服務。java

unit 類型以下:

  • service :守護進程的啓動、中止、重啓和重載是此類 unit 中最爲明顯的幾個類型。nginx

  • socket :此類 unit 封裝系統和互聯網中的一個socket。當下,systemd支持流式, 數據報和連續包的AF_INET,AF_INET6,AF_UNIXsocket 。也支持傳統的 FIFOs 傳輸模式。每個 socket unit 都有一個相應的服務 unit 。相應的服務在第一個「鏈接」進入 socket 或 FIFO 時就會啓動(例如:nscd.socket 在有新鏈接後便啓動 nscd.service)。shell

  • device :此類 unit 封裝一個存在於 Linux設備樹中的設備。每個使用 udev 規則標記的設備都將會在 systemd 中做爲一個設備 unit 出現。udev 的屬性設置能夠做爲配置設備 unit 依賴關係的配置源。centos

  • mount:此類 unit 封裝系統結構層次中的一個掛載點。api

  • automount :此類 unit 封裝系統結構層次中的一個自掛載點。每個自掛載 unit 對應一個已掛載的掛載 unit (須要在自掛載目錄能夠存取的狀況下儘早掛載)。安全

  • target :此類 unit 爲其餘 unit 進行邏輯分組。它們自己實際上並不作什麼,只是引用其餘 unit 而已。這樣即可以對 unit 作一個統一的控制。(例如:multi-user.target 至關於在傳統使用 SysV 的系統中運行級別5);bluetooth.target 只有在藍牙適配器可用的狀況下才調用與藍牙相關的服務,如:bluetooth 守護進程、obex 守護進程等)bash

  • snapshot :與 targetunit 類似,快照自己不作什麼,惟一的目的就是引用其餘 unit 。

編寫後臺服務的 unit 文件

對應到 centos6 其實就是 /etc/init.d/ 下面的服務腳本,只是到了 systemd 裏面叫作 service unit 文件,命名必須以 .service 結尾。網絡

  • service unit(服務腳本) 文件在系統中的存放路徑

    /usr/lib/systemd/system
  • 先來看一個簡單的示例
[Unit]
Description=nginx
After=network.target

[Service]
Type=forking
PIDFile=/alidata/server/nginx/logs/nginx.pid
ExecStart=/alidata/server/nginx/sbin/nginx -c /alidata/server/nginx/conf/nginx.conf
ExecReload=/alidata/server/nginx/sbin/nginx -s reload
ExecStop=/alidata/server/nginx/sbin/nginx -s stop
PrivateTmp=true

[Install]
WantedBy=multi-user.target

整個文件分爲三個部分,[Unit]、[Service]、[Install]

[Unit] :記錄文件的通用信息,如描述,開機啓動順序

[Service] :記錄 unit 文件類型,服務控制的相關指令

[Install] :安裝信息

Unit 經常使用配置指令

  • Description:對本service的描述。

  • Before, After:定義啓動順序,Before=xxx.service,表明本服務在xxx.service啓動以前啓動。After=xxx.service,表明本服務在xxx以後啓動。

  • Requires: 這個單元啓動了,那麼它「須要」的單元也會被啓動; 它「須要」的單元被中止了,它本身也活不了。可是請注意,這個設定並不能控制某單元與它「須要」的單元的啓動順序(啓動順序是另外控制的),即 Systemd 不是先啓動 Requires 再啓動本單元,而是在本單元被激活時,並行啓動二者。因而會產生爭分奪秒的問題,若是 Requires 先啓動成功,那麼皆大歡喜; 若是 Requires 啓動得慢,那本單元就會失敗(Systemd 沒有自動重試)。因此爲了系統的健壯性,不建議使用這個標記,而建議使用 Wants 標記。可使用多個 Requires。

  • Wants:推薦使用。本單元啓動了,它「想要」的單元也會被啓動。可是啓動不成功,對本單元沒有影響。

  • Conflicts:一個單元的啓動會中止與它「衝突」的單元,反之亦然。

Service 經常使用配置指令

  • Type:service的種類,包含下列幾種類型:

    • simple 默認,這是最簡單的服務類型。意思就是說啓動的程序就是主體程序,這個程序要是退出那麼一切都退出。
    • forking 表示 ExecStart= 進程將會在啓動過程當中使用 fork() 系統調用,啓動成功之後,父進程將會退出,而子進程將做爲該服務的主進程繼續運行。 在啓動守護進程時使用這個類型。
    • oneshot 用於一次性執行服務,好比清理臨時文件,該類型能夠設置多個 ExecStart= 指令,它們按照出現的順序依次執行。一旦遇到錯誤,就會當即中止,再也不繼續執行,同時服務也將進入 failed 狀態。 在指定的 ExecStart= 指令執行結束前,該服務一直處於 「啓動中」(activating) 狀態,而一旦執行結束,該服務又當即變爲中止(inactive)狀態。也就是說該服務不存在 活動(active) 狀態。 這意味着若是再一次啓動服務,將會再一次執行服務定義的動做,前後順序會晚於該服務單元,將會一直等到該服務變成"中止"(inactive)狀態後,纔開始啓動。 該類型常和 RemainAfterExit 指令同時使用。
  • RemainAfterExit :當該服務的全部進程所有退出以後, 是否依然將此服務視爲活動(active)狀態。 默認值爲 no

  • PIDFile :指定守護進程的 PID 文件,強烈建議在 Type=forking 的狀況下明確設置此選項。由於有些服務啓動以後會派生多個進程,systemd 將會不知道哪個纔是該服務的主進程,指定 PID 文件有助於 Systemd 準確的找到服務的主進程。 systemd 不會寫入此文件, 但會在此服務中止後刪除它。 該指令要放在 ExecStart 上面。

  • ExecStart :啓動服務時須要執行的命令,能夠用 $變量名 引用 Environment 設置的進程環境變量 和 操做系統的環境變量 如 $USER

  • ExecStop :可選指令,用於設置服務被要求中止前所執行的指令,此處指令執行完後,該服務剩餘的進程都會被 kill 掉。 若是該指令沒填寫,在中止服務時會直接 kill 該服務下的全部進程。

  • ExecStartPre :設置在 ExecStart 指令執行以前執行的命令

  • ExecStartPost :設置在 ExecStart 指令執行成功以後執行的命令

  • ExecStopPost :設置該服務中止以後執行的命令

  • Environment :設置進程的環境變量, 值是一個空格分隔的 VAR=VALUE 列表。 能夠屢次使用此選項以增長新的變量或者修改已有的變量 (同一個變量以最後一次的設置爲準)。 若設爲空, 則表示清空先前全部已設置的變量。 注意: (1)不會在字符串內部進行變量展開(也就是"$"沒有特殊含義); (2)若是值中包含空格或者等號, 那麼必須在字符串兩邊使用雙引號(")界定。 例如: Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" 設置了 "VAR1", "VAR2", "VAR3" 三個變量,其值分別爲 "word1 word2", "word3", "$word 5 6"

  • EnvironmentFile :與 Environment= 相似, 不一樣之處在於此選項是從文本文件中讀取環境變量的設置。 文件中的空行以及以分號(;)或井號(#)開頭的行會被忽略, 其餘行的格式必須符合 VAR=VALUE 的shell變量賦值語法。 行尾的反斜槓()將被視爲續行符, 這與shell語法相似。 若想在變量值中包含空格, 則必須在值的兩端加上雙引號(")界定。文件必須用絕對路徑表示(能夠包含通配符)。 但可在路徑前加上"-"前綴表示忽略不存在的文件。 能夠屢次使用此選項, 以從多個不一樣的文件中讀取設置。 若設爲空, 則表示清空全部先前已經從文件中讀取的環境變量。

Install 經常使用配置指令

  • Alias : 啓用時使用的別名,能夠設爲一個空格分隔的別名列表。 每一個別名的後綴(也就是單元類型)都必須與該單元自身的後綴相同。systemctl enable 命令將會爲每一個別名建立一個指向該單元文件的軟鏈接。 注意,由於 mount, slice, swap, automount 單元不支持別名,因此不要在這些類型的單元中使用此選項。

  • WantedBy,RequiredBy : 接受一個空格分隔的單元列表, 表示在使用 systemctl enable 啓用此單元時, 將會在每一個列表單元的 .wants/ 或 .requires/ 目錄中建立一個指向該單元文件的軟鏈接。 這至關於爲每一個列表中的單元文件添加了 Wants=此單元 或 Requires=此單元 選項。 這樣當列表中的任意一個單元啓動時,該單元都會被啓動。

應用示例

一、建立一個簡單服務

[Unit]
Description=簡單的Foo服務

[Service]
ExecStart=/usr/sbin/foo-daemon

[Install]
WantedBy=multi-user.target

該單元文件建立了一個運行 /usr/sbin/foo-daemon 守護進程的服務,未設置 Type= 等價於 Type=simple 默認設置。 注意,本例中的 /usr/sbin/foo-daemon 必須在啓動後持續運行到服務被中止。 若是該進程只是爲了派生守護進程,那麼應該使用 Type=forking

二、一次性服務

[Unit]
Description=清理老舊的 Foo 數據

[Service]
Type=oneshot
ExecStart=/usr/sbin/foo-cleanup

[Install]
WantedBy=multi-user.target

Type=oneshot 用於只須要執行一次,不須要持久運行的單元,例如文件系統檢查或者清理磁盤文件。此單元會啓動後一直等待指定的動做完成, 而後再回到中止狀態。 在 /usr/sbin/foo-cleanup 執行結束前, 該服務一直處於"啓動中"(activating)狀態,而一旦執行結束,該服務又當即變爲"中止"(inactive)狀態。 也就是說,對於 Type=oneshot 類型的服務,不存在"活動"(active)狀態。 這意味着,若是再一次啓動該服務,將會再一次執行該服務定義的動做。 注意,在前後順序上晚於該服務的單元, 將會一直等到該服務變成"中止"(inactive)狀態後, 纔會開始啓動。

Type=oneshot 是惟一能夠設置多個 ExecStart= 指令的服務類型。 多個 ExecStart= 指令將按照它們出現的順序依次執行, 一旦遇到錯誤,就會當即中止,再也不繼續執行, 同時該服務也將進入"失敗"(failed)狀態。

三、可中止的一次性服務

[Unit]
Description=簡單的靜態防火牆

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/simple-firewall-start
ExecStop=/usr/local/sbin/simple-firewall-stop

[Install]
WantedBy=multi-user.target

有時候,單元須要執行一個程序以完成某個設置(啓動), 而後又須要再執行另外一個程序以撤消先前的執行(中止)。 而第一次執行以後,該單元應該處於 活動(active) 狀態,但實際上並沒有任何進程在運行。網絡配置服務就是一個典型的例子,只須要執行一次的服務。

能夠經過設置 RemainAfterExit=yes 來知足這種需求。 在這種狀況下,systemd 將會在啓動成功後將該單元視爲處於"活動"(active)狀態(而不是"中止"(inactive)狀態)。 RemainAfterExit=yes 雖然能夠用於全部 Type= 類型, 可是在實踐中主要用於 Type=oneshot 和 Type=simple 類型。 對於 Type=oneshot 類型, systemd 一直等到服務啓動成功以後,纔會將該服務置於"活動"(active)狀態。 因此,依賴於該服務的其餘單元必須等待該服務啓動成功以後,才能啓動。 可是對於 Type=simple 類型, 依賴於該服務的其餘單元無需等待,將會和該服務同時並行啓動。

四、編寫守護進程單元 nginx.service

[Unit]
Description=nginx
After=network.target

[Service]
Type=forking
PIDFile=/alidata/server/nginx/logs/nginx.pid
ExecStart=/alidata/server/nginx/sbin/nginx -c /alidata/server/nginx/conf/nginx.conf
ExecReload=/alidata/server/nginx/sbin/nginx -s reload
ExecStop=/alidata/server/nginx/sbin/nginx -s stop
PrivateTmp=true

[Install]
WantedBy=multi-user.target

PrivateTmp 設爲 yes 表示在進程的文件系統名字空間中掛載私有的 /tmp 與 /var/tmp 目錄, 也就是不與名字空間外的其餘進程共享臨時目錄。 這樣作會增長進程的臨時文件安全性,但同時也讓進程之間沒法經過 /tmp 或 /var/tmp 目錄進行通訊。 同時,當服務中止以後,全部先前在臨時目錄中建立的文件都將被刪除。

五、編寫守護進程單元 php7-fpm.service

[Unit]
Description=PHP7.0.8 start file

[Service]
Type=forking
PIDFile=/alidata/server/php7.0.8/var/run/php-fpm.pid
ExecStart=/alidata/server/php7.0.8/sbin/php-fpm --daemonize --fpm-config /alidata/server/php7.0.8/etc/php-fpm.conf --pid /alidata/server/php7.0.8/var/run/php-fpm.pid
ExecStartPost=/usr/bin/chown www.www /alidata/server/php7.0.8/var/run/php7-fpm.sock
StandardOutput=syslog
StandardError=inherit

[Install]
WantedBy=multi-user.target
  • StandardOutput

設置進程的標準輸出(STDOUT)。 可設爲 inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+console, socket, fd 之一。 syslog 表示 syslog 日誌服務。 注意,此時全部日誌都會隱含的複製一份到 journal 中。

  • StandardError

設置進程的標準錯誤(STDERR)。 取值範圍及含義與 StandardOutput= 相同。 但有以下例外:(1) inherit 表示使用 StandardOutput= 的值。 (2) fd 的文件描述符名稱的默認值爲 "stderr" 此值默認爲 inherit

六、編寫守護進程單元 filebeat.service

[Unit]
Description=Filebeat sends log files to Logstash or directly to Elasticsearch.
Documentation=https://www.elastic.co/products/beats/filebeat
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/share/filebeat/bin/filebeat -c /etc/filebeat/filebeat.yml -path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/filebeat -path.logs /var/log/filebeat -E serverip=$serverip
Restart=always

[Install]
WantedBy=multi-user.target

注意,在 Centos7 使用 Systemd 啓動 filebeat 時是不會傳遞系統環境變量的。 filebeat 若是在配置文件中引用了系統的環境變量,那麼會致使服務啓動失敗。 報錯大概是找不到那個引用了系統變量自定義的那個字段。 有兩個解決方法:

一、在 unit 文件中使用 Environment 相關參數,定義要使用的環境變量,在 ExecStart 啓動命令時引用。 -E serverip=$serverip

二、在 /etc/profile.d/ 目錄下建立定義系統環境變量的文件,裏面的內容相似
export serverip=ifconfig eth0 | grep 'inet' | awk '{print $2}' | cut -d':' -f2 ,而後在啓動命令時直接用 $變量名 引用系統環境變量。

七、編寫守護進程單元 Logstash

# /usr/lib/systemd/system/logstash.service
# 自定義環境變量的寫法

[Unit]
Description=Logstash start program

[Service]
Type=simple
Environment=LOGDIR=/alidata/log/logstash CONF=/alidata/logstash-6.5.2/ngx_app_api_log_analyze.conf DATA=/alidata/logstash-6.5.2/data
ExecStartPre=/usr/bin/rm -rf $DATA
ExecStartPre=/usr/bin/rm -rf $LOGDIR
ExecStart=/alidata/logstash-6.5.2/bin/logstash -f $CONF -l $LOGDIR

[Install]
WantedBy=multi-user.target
原生RPM包內置寫法
# /etc/systemd/system/logstash.service

[Unit]
Description=logstash

[Service]
Type=simple
User=logstash
Group=logstash
# Load env vars from /etc/default/ and /etc/sysconfig/ if they exist.
# Prefixing the path with '-' makes it try to load, but if the file doesn't
# exist, it continues onward.
EnvironmentFile=-/etc/default/logstash
EnvironmentFile=-/etc/sysconfig/logstash
ExecStart=/usr/share/logstash/bin/logstash "--path.settings" "/etc/logstash"
Restart=always
WorkingDirectory=/
Nice=19
LimitNOFILE=16384

[Install]
WantedBy=multi-user.target
變量定義文件,EnvironmentFile
# /etc/default/logstash

LS_HOME="/usr/share/logstash"
LS_SETTINGS_DIR="/etc/logstash"
LS_PIDFILE="/var/run/logstash.pid"
LS_USER="logstash"
LS_GROUP="logstash"
LS_GC_LOG_FILE="/var/log/logstash/gc.log"
LS_OPEN_FILES="16384"
LS_NICE="19"
SERVICE_NAME="logstash"
SERVICE_DESCRIPTION="logstash"
JAVA_HOME="/usr/java/jdk1.8.0_162"

systemctl 服務管理命令

'''查看系統全部已安裝的服務項'''
systemctl list-unit-files --type=service

'''查看系統全部運行的服務項'''
systemctl list-units --type=service

'''查看系統全部開機自啓動的服務項'''
systemctl list-unit-files --type=service |  grep enabled

'''查看出錯的服務'''
systemctl list-units --type=service --state=failed

'''啓動服務'''
systemctl start nginx.service

'''中止服務'''
systemctl stop nginx.service

'''重載服務的配置文件'''
systemctl reload nginx.service

'''查看服務的狀態'''
systemctl status nginx.service

'''設置服務開機啓動'''
systemctl enable nginx.service

'''禁用服務的開機啓動'''
systemctl disable nginx.service

'''禁止服務的啓動,用於防止服務被其餘服務間接啓動,也沒法經過 start 或 restart 命令來啓動'''
systemctl mask nginx.service

'''取消對服務的啓動禁止'''
systemctl unmask nginx.service

'''從新讀取全部服務項,修改或添加服務單元文件以後須要執行'''
systemctl daemon-reload

'''查看系統啓動耗時'''
systemd-analyze

'''查看各項服務啓動耗時'''
systemd-analyze blame | grep .service

參考文檔:http://www.jinbuguo.com/systemd/systemd.index.html

相關文章
相關標籤/搜索