.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 git@github.com: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 系統的可執行程序及其所有依賴項。

作為 Linux 控制台程序運行

將文件夾 C:\test\workerpub\linux 下的文件壓縮為 linux.zip

打開 Xshell 工具,連接到一台 Linux 測試機(我的測試機操作系統為 CentOS 7.3),在測試機上新建 /srv/Worker 目錄:

mkdir /srv/Worker

使用 rz 命令將 linux.zip 復制到測試機,

copy files to linux

然后在測試機上解壓 linux.zip/srv/Worker 目錄:

unzip linux.zip -d /srv/Worker

為我們的應用程序分配可執行權限,並運行:

# 分配可執行權限
chmod +x /srv/Worker/MyService
# 運行
/srv/Worker/MyService

run as console on linux

按下 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 status MyService

這表明我們注冊的新服務被禁用了,可以通過運行以下命令來啟動它:

systemctl start MyService

重新運行 systemctl status MyService 命令查看服務狀態,顯示如下:

systemctl status MyService 2

停止服務可以運行以下命令:

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 下載本文中的源碼

參考:


相關閱讀:

作者 : 技術譯民
出品 : 技術譯站


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM