Linux 建立 Systemd 服務示範、介紹

systemd 是 linux 中常見的服務管理工具,讓我們可以很方便的建立和管理服務,能夠讓服務自動啟動、重啟、定時執行等。

最簡單 service 檔案

我們會建立副檔名為 .service 的檔案來定義服務,副檔名沒有一定需要 .service ,但是不同的副檔名通常對應不同功能的服務,這裡直接使用 .service 做示範。

在 /etc/systemd/system 資料夾中建立一個 my-test.service 檔案:
    
[Service]
ExecStart=/bin/bash /home/ruyut/run.sh
Restart=on-failure
RestartSec=30
    

上面設定檔的意思是執行 /home/ruyut/run.sh 指令,如果執行失敗後間隔 30 秒再次執行。

接下來要給予檔案權限,使檔案可以執行:
    
sudo chmod +x /etc/systemd/system/my-test.service
    

啟動服務:
    
sudo systemctl start my-test.service
    

註: 服務執行後會失敗,因為在這裡我們並沒有建立 /home/ruyut/run.sh 檔案,服務會因為找不到要執行的指令檔而發生錯誤,但是間隔 30 秒後就會自動再次執行。

等待幾分鐘後使用下面的指令查看執行日誌:
    
journalctl -u my-test.service
    

可以發現確實執行後失敗,並且 30 秒後會自動再次執行
    
journalctl -u my-test.service
May 14 15:27:42 ruyut systemd[1]: Started my-test.service.
May 14 15:27:42 ruyut bash[52621]: /bin/bash: /home/ruyut/run.sh: No such file or directory
May 14 15:27:42 ruyut systemd[1]: my-test.service: Main process exited, code=exited, status=127/n/a
May 14 15:27:42 ruyut systemd[1]: my-test.service: Failed with result 'exit-code'.
May 14 15:28:12 ruyut systemd[1]: my-test.service: Scheduled restart job, restart counter is at 1.
May 14 15:28:12 ruyut systemd[1]: Stopped my-test.service.
May 14 15:28:12 ruyut systemd[1]: Started my-test.service.
May 14 15:28:12 ruyut bash[53418]: /bin/bash: /home/ruyut/run.sh: No such file or directory
May 14 15:28:12 ruyut systemd[1]: my-test.service: Main process exited, code=exited, status=127/n/a
May 14 15:28:12 ruyut systemd[1]: my-test.service: Failed with result 'exit-code'.
May 14 15:28:43 ruyut systemd[1]: my-test.service: Scheduled restart job, restart counter is at 2.
May 14 15:28:43 ruyut systemd[1]: Stopped my-test.service.
May 14 15:28:43 ruyut systemd[1]: Started my-test.service.
May 14 15:28:43 ruyut bash[54214]: /bin/bash: /home/ruyut/run.sh: No such file or directory
May 14 15:28:43 ruyut systemd[1]: my-test.service: Main process exited, code=exited, status=127/n/a
May 14 15:28:43 ruyut systemd[1]: my-test.service: Failed with result 'exit-code'.
    

假設我們依照服務設定檔中的路徑在 /home/ruyut 建立了 run.sh 檔案:
    
#!/bin/bash

echo "$(date)"
    

等待一分鐘後再次查看 log 就會發現成功執行,並且不會再自動執行了。
    
journalctl -u my-test.service
May 14 15:38:17 ruyut systemd[1]: Started my-test.service.
May 14 15:38:17 ruyut bash[69255]: /bin/bash: /home/ruyut/run.sh: No such file or directory
May 14 15:38:17 ruyut systemd[1]: my-test.service: Main process exited, code=exited, status=127/n/a
May 14 15:38:17 ruyut systemd[1]: my-test.service: Failed with result 'exit-code'.
May 14 15:38:47 ruyut systemd[1]: my-test.service: Scheduled restart job, restart counter is at 22.
May 14 15:38:47 ruyut systemd[1]: Stopped my-test.service.
May 14 15:38:47 ruyut systemd[1]: Started my-test.service.
May 14 15:38:47 ruyut bash[70087]: Tue May 14 03:38:47 PM UTC 2024
May 14 15:38:47 ruyut systemd[1]: my-test.service: Deactivated successfully.
    

自動執行服務

上面我們建立的服務需要手動啟動,如果想要開機自動執行的話會出現下列錯誤:
    
sudo systemctl enable my-test.service
The unit files have no installation config (WantedBy=, RequiredBy=, Also=,
Alias= settings in the [Install] section, and DefaultInstance= for template
units). This means they are not meant to be enabled using systemctl.

Possible reasons for having this kind of units are:
• A unit may be statically enabled by being symlinked from another unit's
  .wants/ or .requires/ directory.
• A unit's purpose may be to act as a helper for some other unit which has
  a requirement dependency on it.
• A unit may be started when needed via activation (socket, path, timer,
  D-Bus, udev, scripted systemctl call, ...).
• In case of template units, the unit is meant to be enabled with some
  instance name specified.
    

代表我們的設定檔內容不足,還缺少 Install 區塊:
    
[Service]
ExecStart=/bin/bash /home/ruyut/run.sh
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
    

等等,WantedBy 設定值的 multi-user.target 參數是什麼意思?還有哪些可以用的參數?
筆者研究了一番後將常用設定值整理如下:
  • basic.target: 代表 Linux 已啟動,基礎服務可以使用的狀態
  • multi-user.target: 代表 Linux 已啟動,啟動狀態已經達到可以讓多個使用者使用
  • graphical.target: 代表 Linux 已啟動,啟動狀態已經達到可以使用圖形化使用者介面(註:在沒有安裝圖形化介面的 Linux 中使用這個會在 log 中附加一條警告,因為沒有圖形化介面可以使用)
  • network.target: 代表網路功能已啟動
  • network-online.target: 代表網路功能啟動成功
設定開機自動啟動服務:
    
sudo systemctl enable my-test.service
    

其他常用指令

使用跟隨模式持續顯示服務的日誌:
    
journalctl -u my-test.service -f
    

重新讀取服務設定檔:
    
sudo systemctl daemon-reload 
    

檢查服務狀態:
    
sudo systemctl status my-test.service
    

關閉服務:
    
sudo systemctl stop my-test.service
    

取消開機自動啟動服務:
    
sudo systemctl disable my-test.service
    

其他設定值範例

    
[Unit] 
Description=這是示範用的 service 檔案


[Service]
ExecStart=/bin/bash /home/ruyut/run.sh
Restart=always
RestartSec=10

[Install]
WantedBy=network-online.target
    



參考資料:
RedHat - Chapter 10. Managing Services with systemd

留言

張貼留言

如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com