.NET Worker Service 部署到 Linux 作為 Systemd Service 執行
上一篇文章我們瞭解瞭如何將.NET Worker Service 作為 Windows 服務執行,今天我接著介紹一下如何將 Worker Service 部署到 Linux 上,並作為 Systemd Service 執行。
我在本文中要覆蓋的內容包含:
- 作為 Linux 控制檯程式執行
- 作為 Systemd Service 執行
- 開機自動啟動、檢視日誌資訊
建立專案併發布
下載 Worker Service 原始碼
我將基於上一篇文章中的 Worker Service 原始碼來修改,如果您安裝有 git,可以用下面的命令獲取它:
git clone [email protected]:ITTranslate/WorkerServiceAsWindowsService.git
然後,使用 Visual Studio Code 開啟此專案,構建一下,以確保一切正常:
dotnet build
刪除用不到的依賴項
刪除上一篇文章中用於 Windows Services 的依賴程式包:
dotnet remove package Microsoft.Extensions.Hosting.WindowsServices
然後,刪除 Program.cs 中的 .UseWindowsService()
方法呼叫。
修改配置檔案
開啟配置檔案 appsettings.json,將日誌檔案儲存路徑中的 \
改為 /
,其他不用做任何更改。
{ "Name": "RollingFile", "Args": { "pathFormat": "Logs/{Hour}.log", "outputTemplate": "{Timestamp:o} [{Level:u3}] ({MachineName}/{ProcessId}/{ProcessName}/{ThreadId}) {Message}{NewLine}{Exception}" } }, { "Name": "SQLite", "Args": { "sqliteDbPath": "Logs/log.db", "tableName": "Logs", "maxDatabaseSize": 1, "rollOver": true } }
這是因為 Windows 中使用反斜槓 \
來表示目錄,而 Linux 中使用正斜槓 /
來表示目錄。
假如不修改儲存路徑,您將會看到日誌被儲存成如下的尷尬檔名:
'Logs\2021061715.log'
'Logs\log.db'
釋出程式
執行 dotnet publish
命令將應用程式及其依賴項釋出到資料夾。
dotnet publish -c Release -r linux-x64 -o c:\test\workerpub\linux
這裡我使用
-r linux-x64
引數,指定釋出獨立部署於 Linux 系統的應用程式。
命令執行完成後,您會在 C:\test\workerpub\linux
作為 Linux 控制檯程式執行
將資料夾 C:\test\workerpub\linux 下的檔案壓縮為 linux.zip。
開啟 Xshell 工具,連線到一臺 Linux 測試機(我的測試機作業系統為 CentOS 7.3),在測試機上新建 /srv/Worker 目錄:
mkdir /srv/Worker
使用 rz
命令將 linux.zip 複製到測試機,
然後在測試機上解壓 linux.zip 到 /srv/Worker 目錄:
unzip linux.zip -d /srv/Worker
為我們的應用程式分配可執行許可權,並執行:
# 分配可執行許可權
chmod +x /srv/Worker/MyService
# 執行
/srv/Worker/MyService
按下 Ctrl+C
關閉應用,等待關閉前必須完成的任務正常結束後,應用退出。輸入 ls /srv/Worker
命令回車,您會看到在該目錄下多了一個 Logs 目錄,日誌檔案輸出正常。
作為 Systemd Service 執行
新增 Systemd Service 依賴
為了讓我們的 Worker 監聽來自 Systemd 的啟動和停止訊號,我們需要新增 Microsoft.Extensions.Hosting.Systemd NuGet 包:
dotnet add package Microsoft.Extensions.Hosting.Systemd
然後,我們需要修改 Program.cs 中的 CreateHostBuilder
方法,新增 UseSystemd
方法呼叫,將宿主(Host)生命週期設定為 Microsoft.Extensions.Hosting.Systemd.SystemdLifetime,以便應用程式可以接收啟動和停止訊號,並配置控制檯輸出記錄為 systemd 格式。
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSystemd() // Sets the host lifetime to Microsoft.Extensions.Hosting.Systemd.SystemdLifetime...
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
})
.UseSerilog(); //將 Serilog 設定為日誌提供程式
重新執行以下命令將程式釋出到資料夾:
dotnet publish -c Release -r linux-x64 -o c:\test\workerpub\linux
然後重複前面的步驟,在 Xshell 中使用 rz
命令將應用程式複製到測試機,併為 /srv/Worker/MyService 檔案分配可執行許可權。
配置檔案
接下來我們需要建立配置檔案,將服務的有關資訊告知 systemd,以便它知道如何執行此服務。為此,我們需要建立一個 .service
檔案,我們將在註冊和執行此服務的 Linux 機器上使用該檔案。
在我們的專案中建立一個名為 MyService.service
的服務單元配置檔案,內容如下:
[Unit]
Description=Long running service/daemon created from .NET worker template
[Service]
# The systemd service file must be configured with Type=notify to enable notifications.
Type=notify
# will set the Current Working Directory (CWD). Worker service will have issues without this setting
WorkingDirectory=/srv/Worker
# systemd will run this executable to start the service
ExecStart=/srv/Worker/MyService
# to query logs using journalctl, set a logical name here
SyslogIdentifier=MyService
# Use your username to keep things simple.
# If you pick a different user, make sure dotnet and all permissions are set correctly to run the app
# To update permissions, use 'chown yourusername -R /srv/Worker' to take ownership of the folder and files,
# Use 'chmod +x /srv/Worker/MyService' to allow execution of the executable file
User=yourusername
# This environment variable is necessary when dotnet isn't loaded for the specified user.
# To figure out this value, run 'env | grep DOTNET_ROOT' when dotnet has been loaded into your shell.
Environment=DOTNET_ROOT=/usr/share/dotnet/dotnet
# This gives time to MyService to shutdown gracefully.
TimeoutStopSec=300
[Install]
WantedBy=multi-user.target
使用時應將 User=yourusername 項中的
yourusername
改為具體的 linux 系統的登入名。
Systemd 期望所有的配置檔案放置在 /etc/systemd/system/ 目錄下,我們開啟此目錄,並使用 rz
命令將服務配置檔案複製到 /etc/systemd/system/MyService.service,
cd /etc/systemd/system/
rz
然後執行以下命令讓 systemd 重新載入配置檔案:
systemctl daemon-reload
管理服務
之後,可以執行以下命令來檢查 systemd 是否識別了我們的服務:
systemctl status MyService
結果顯示如下:
這表明我們註冊的新服務被禁用了,可以通過執行以下命令來啟動它:
systemctl start MyService
重新執行 systemctl status MyService
命令檢視服務狀態,顯示如下:
停止服務可以執行以下命令:
systemctl stop MyService
如果您希望該服務在開機時自動啟動,那麼可以執行以下命令:
systemctl enable MyService
禁用開機自動啟動,可以執行以下命令:
systemctl disable MyService
檢視服務是否開機自動啟動,可以執行以下命令:
systemctl is-enabled MyService
Systemd 服務日誌
命令 journalctl
可以用來檢視 systemd 收集的日誌。systemd-journald 服務負責 systemd 的日誌收集,它從核心、systemd 服務和其他源檢索資訊。日誌的集中收集,有利於對其進行檢索查詢。journal 中的日誌記錄是結構化和有索引的,因此 journalctl
能夠以各種有用的格式來展現日誌資訊。
我們可以使用 journalctl
命令來驗證應用程式是否成功執行,因為該命令可以跟蹤顯示應用程式的輸出資訊:
journalctl -u MyService -f
按 Ctrl-C
退出命令。
當我們在程式中呼叫 UseSystemd
方法時,會將 Extensions.LogLevel
對映到 Syslog 日誌級別:
LogLevel | Syslog level | systemd name |
---|---|---|
Trace/Debug | 7 | debug |
Information | 6 | info |
Warning | 4 | warning |
Error | 3 | err |
Critical | 2 | crit |
所以,我們可以使用 journalctl
命令的優先順序標記(priority-flag)-p
來根據日誌級別過濾應用程式的輸出資訊:
journalctl -p 4 -u MyService -f
總結
在本文中,我通過一個例項詳細介紹瞭如何將 .NET Worker Service 部署到 Linux 系統作為 Systemd Service 執行,並說明了如何使用 systemctl
命令來管理服務,如何使用 journalctl
命令檢視 Systemd 服務日誌。
當我們向 HostBuilder 添加了 .UseSystemd()
方法呼叫後,編譯出的程式,既可以作為 Linux 控制檯應用執行,也可以作為 Systemd Service 執行。
您可以從 GitHub 下載本文中的原始碼。
參考:
- https://swimburger.net/blog/dotnet/how-to-run-a-dotnet-core-console-app-as-a-service-using-systemd-on-linux
- https://devblogs.microsoft.com/dotnet/net-core-and-systemd/
- https://docs.microsoft.com/zh-cn/dotnet/core/tools/dotnet-publish
- https://www.freedesktop.org/wiki/Software/systemd/
- https://systemd.io/
- https://www.linode.com/docs/guides/how-to-use-journalctl/
- https://github.com/ITTranslate/WorkerServiceAsWindowsService 前篇文章原始碼
- https://github.com/ITTranslate/WorkerServiceAsSystemdService 本文原始碼
相關閱讀:
- .NET Worker Service 入門介紹
- .NET Worker Service 如何優雅退出
- .NET Worker Service 新增 Serilog 日誌記錄
- .NET Worker Service 作為 Windows 服務執行及優雅退出改進
- .NET Worker Service 部署到 Linux 作為 Systemd Service 執行
作者 : 技術譯民
出品 : 技術譯站