分類: Linux

Linux 建立自訂 Systemd 服務教學與範例

本篇介紹如何在 Linux 系統中自行建立一個網路伺服器,並設定讓 Systemd 自動啟動與管理伺服器的運作。

建立 Echo 伺服器

首先以 Python 撰寫一個簡單的 echo 伺服器,將其儲存在 /opt/echo_server.py

#!/usr/bin/env python3
import socket

# 建立 socket
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定所有網路介面的 9000 連接埠
serv.bind(('0.0.0.0', 9000))

# 開始接受 client 連線
serv.listen()

while True:

    # 接受 client 連線
    conn, addr = serv.accept()
    print('Client from', addr)

    while True:

        # 接收資料
        data = conn.recv(1024)

        # 若無資料則離開
        if not data: break

        # 傳送資料
        conn.send(data)

    conn.close()
    print('Client disconnected')

這段 Python 程式碼在執行之後,會傾聽所有網路介面的 9000 連接埠,建立連線之後將所有收到的資料送回 client 端。

建立好 /opt/echo_server.py 之後,順便開啟執行權限:

# 開啟執行權限
chmod +x /opt/echo_server.py

我們可以先手動測試一下,啟動 echo 伺服器:

# 啟動 echo 伺服器(server 端)
/opt/echo_server.py

接著開啟另外一個終端機,使用 nc 指令連線至 9000 連接埠

# 連線至 localhost 的 9000 連接埠(client 端)
nc localhost 9000

連上之後,隨意輸入一些文字,送出之後應該就會看到伺服器回應相同的文字,而在伺服器端應該也會顯示一些關於 client 的資訊,這樣就代表 echo 伺服器可以正常運作了。

建立 Systemd 服務單位設定檔

建立一個新的 Systemd 服務單位設定檔,儲存於 /etc/systemd/system/echo_server.service

[Unit]
Description=Echo Server

[Service]
Type=simple
ExecStart=/opt/echo_server.py
Restart=always

[Install]
WantedBy=multi-user.target

權限要設定為 644

sudo chmod 644 /etc/systemd/system/echo_server.service

如果在開發過程中,有修改過 Systemd 的服務單位設定檔,記得重新載入 daemon 讓新設定生效:

# 重新載入 Systemd 設定檔
sudo systemctl daemon-reload

接著就可以使用 systemctl 指令啟動自訂的 echo 伺服器:

# 啟動自訂的 echo 伺服器
sudo systemctl start echo_server

查看 echo 伺服器的狀態:

# 查看 echo 伺服器狀態
systemctl status echo_server
● echo_server.service - Echo Server
   Loaded: loaded (/etc/systemd/system/echo_server.service; disabled; vendor pre
   Active: active (running) since Thu 2019-09-19 06:59:46 UTC; 1min 46s ago
 Main PID: 20142 (python3)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/echo_server.service
           └─20142 python3 /opt/echo_server.py

Sep 19 06:59:46 test-vm systemd[1]: Started Echo Server.

這樣就成功啟動了自己開發的 echo 伺服器了,此時我們可以直接使用上面的 nc 指令測試一下伺服器是否正常運作。

如果要停止 echo 伺服器,可執行:

# 停止 echo 伺服器
sudo systemctl stop echo_server

如果想要讓 echo 伺服器可以在開機時自動啟動,可執行:

# 設定開機自動啟動 echo 伺服器
sudo systemctl enable echo_server
Created symlink /etc/systemd/system/multi-user.target.wants/echo_server.service → /etc/systemd/system/echo_server.service.

若要取消開機自動啟動 echo 伺服器,則可執行:

# 取消開機自動啟動 echo 伺服器
sudo systemctl disable echo_server
Removed /etc/systemd/system/multi-user.target.wants/echo_server.service.

關於 systemctl 指令的詳細用法,請參考 Linux systemd 系統服務管理基礎教學文章

Systemd 服務單位設定檔的完整文件可以從線上手冊查詢:

# 查詢 Systemd 服務單位設定檔說明文件
man systemd.unit
man systemd.service
man systemd.exec

另外亦可從 /lib/systemd/system/(Ubuntu)或 /usr/lib/systemd/system/(CentOS)目錄中找到大量的實際範例。

Systemd 服務單位設定檔範本

以下是一個比較詳細的 Systemd 服務單位設定檔範本,在撰寫自訂服務的設定檔時,可以先複製這份設定再接著修改:

[Unit]
# 服務名稱
Description=Your Server

# 服務相關文件
# Documentation=https://example.com
# Documentation=man:nginx(8)

# 設定服務啟動的先後相依姓,例如在網路啟動之後:
# After=network.target

[Service]
# 行程類型
Type=simple

# 啟動服務指令
ExecStart=/opt/your_command

# 服務行程 PID(通常配合 forking 的服務使用)
# PIDFile=/run/your_server.pid

# 啟動服務前,執行的指令
# ExecStartPre=/opt/your_command

# 啟動服務後,執行的指令
# ExecStartPost=/opt/your_command

# 停止服務指令
# ExecStop=/opt/your_command

# 停止服務後,執行的指令
# ExecStopPost=/opt/your_command

# 重新載入服務指令
# ExecReload=/opt/your_command

# 服務終止時自動重新啟動
Restart=always

# 重新啟動時間格時間(預設為 100ms)
# RestartSec=3s

# 啟動服務逾時秒數
# TimeoutStartSec=3s

# 停止服務逾時秒數
# TimeoutStopSec=3s

# 執行時的工作目錄
# WorkingDirectory=/opt/your_folder

# 執行服務的使用者(名稱或 ID 皆可)
# User=myuser

# 執行服務的群組(名稱或 ID 皆可)
# User=mygroup

# 環境變數設定
# Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"

# 服務輸出訊息導向設定
# StandardOutput=syslog

# 服務錯誤訊息導向設定
# StandardError=syslog

# 設定服務在 Syslog 中的名稱
# SyslogIdentifier=your-server

[Install]
WantedBy=multi-user.target

參考資料:PubNubBenjamin MorelLinodeLinuxConfig.orgTecAdmin.net

G. T. Wang

個人使用 Linux 經驗長達十餘年,樂於分享各種自由軟體技術與實作文章。

Recent Posts

光陽 KYMCO GP 125 機車接電發動、更換電瓶記錄

本篇記錄我的光陽 KYMCO ...

2 年 ago

[開箱] YubiKey 5C NFC 實體金鑰

本篇是 YubiKey 5C ...

2 年 ago

[DIY] 自製竹火把

本篇記錄我拿竹子加上過期的苦茶...

3 年 ago