天天看點

用C#編寫Linux守護程序

用C#編寫Linux守護程式
用C#編寫Linux守護程式

 如果要在Red Hat Enterprise Linux上将.NET Core程序作為背景程序運作,則可以建立自定義systemd單元。今天我将為.NET Core編寫兩個自定義系統單元的例子。一個是運作.NET Core控制台應用程式的一種類型,另一個是運作ASP.NET Core Web應用程式的簡單類型。 

控制台應用程式

建立一個應用程式

您可以用

dotnet run

在systemd中使用指定項目目錄作為工作目錄。但是,我們來建構一個二進制檔案并将其用于systemd。用dotnet new 指令建立您的項目後編輯Program.cs如下。

1 using System;
 2 using System.IO;
 3  
 4 namespace ConsoleApplication
 5 {
 6     public class Program
 7     {
 8         public static void Main(string[] args)
 9         {
10             var path = Path.GetTempFileName();
11             File.WriteAllText(path, "Hello Temp File!");
12             Console.WriteLine($"Wrote temp file: {path}");
13         }
14     }
15 }      

然後用

dotnet publish

指令釋出項目。你會看到

bin/<Configuration>/<Framework>目錄下的二進制檔案

1

2

3

4

5

$ dotnet publish -c Release

Publishing ConsoleApp for .NETCoreApp,Version=v1.1

Project ConsoleApp (.NETCoreApp,Version=v1.1) was previously compiled. Skipping compilation.

publish: Published to /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/ConsoleApp/bin/Release/netcoreapp1.1/publish

Published 1/1 projects successfully

建立一個自定義的systemd

首先,建立一個運作守護程序和工作目錄的使用者。

$ sudo useradd -s /sbin/nologin dotnetuser
$ sudo mkdir /var/SystemdExample
$ sudo cp /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/ConsoleApp/bin/Release/netcoreapp1.1/publish/* /var/SystemdExample
$ sudo chown -R dotnetuser:dotnetuser /var/SystemdExample      

然後在

/etc/systemd/system/

目錄下建立一個自定義的systemd單元檔案。檔案名應該是

<unit-name>.<unit-type>

。我建立的目錄和檔案名為:

/etc/systemd/system/netcore-console-example.service

6

7

8

9

10

11

12

13

14

[Unit]

Description=Example for .NET Core ConsoleApp with systemd

DefaultDependencies=no

[Service]

Type=oneshot

RemainAfterExit=no

ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll

WorkingDirectory=/var/SystemdExample

User=dotnetuser

Group=dotnetuser

[install]

您應該在ExecStart中指定dotnet的完整路徑。以上是紅帽提供的.NET Core 1.1的情況。然後你可以用

systemctl

指令執行守護程序。您可以使用

systemctl status

指令或

journalctl

指令檢視控制台輸出。

15

16

17

18

$ sudo systemctl start netcore-console-example.service

$ sudo systemctl status netcore-console-example.service

● netcore-console-example.service - Example for .NET Core ConsoleApp with systemd

Loaded: loaded (/etc/systemd/system/netcore-console-example.service; enabled; vendor preset: disabled)

Active: inactive (dead) since Fri 2017-02-24 00:29:16 JST; 13s ago

Process: 18075 ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll (code=exited, status=0/SUCCESS)

Main PID: 18075 (code=exited, status=0/SUCCESS)

Feb 24 00:29:16 localhost.localdomain systemd[1]: Starting Example for .NET Core ConsoleApp with systemd...

Feb 24 00:29:16 localhost.localdomain dotnet[18075]: Wrote temp file: /tmp/tmph1ok6H.tmp

Feb 24 00:29:16 localhost.localdomain systemd[1]: Started Example for .NET Core ConsoleApp with systemd.

$ journalctl -u netcore-console-example.service -e

Feb 24 00:29:16 localhost.localdomain systemd[1]: Starting Example for .NET Core ConsoleApp with systemd...

Feb 24 00:29:16 localhost.localdomain dotnet[18075]: Wrote temp file: /tmp/tmph1ok6H.tmp

Feb 24 00:29:16 localhost.localdomain systemd[1]: Started Example for .NET Core ConsoleApp with systemd.

$ sudo cat /tmp/tmph1ok6H.tmp

Hello Temp File!

使用PrivateTemp

在上述系統單元中,程式在臨時檔案夾下寫入一個檔案。你有時想寫一個來自其他使用者的臨時檔案是安全的。您可以在

[Service]

section中的指定使用PrivateTemp。

[Service]

Type=oneshot

RemainAfterExit=no

ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll

WorkingDirectory=/var/SystemdExample

User=dotnetuser

Group=dotnetuser

PrivateTemp=true

重新加載單元檔案後,程式可以像前一樣通路

/tmp

目錄,但這不是實際的

/tmp

目錄。

$ sudo systemctl daemon-reload

$ sudo systemctl start netcore-console-example.service

$ sudo systemctl status netcore-console-example.service

● netcore-console-example.service - Example for .NET Core ConsoleApp with systemd

Loaded: loaded (/etc/systemd/system/netcore-console-example.service; enabled; vendor preset: disabled)

Active: inactive (dead) since Fri 2017-02-24 00:35:46 JST; 12s ago

Process: 18415 ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll (code=exited, status=0/SUCCESS)

Main PID: 18415 (code=exited, status=0/SUCCESS)

Feb 24 00:35:46 localhost.localdomain systemd[1]: Starting Example for .NET Core ConsoleApp with systemd...

Feb 24 00:35:46 localhost.localdomain dotnet[18415]: Wrote temp file: /tmp/tmpJLWAGC.tmp

Feb 24 00:35:46 localhost.localdomain systemd[1]: Started Example for .NET Core ConsoleApp with systemd.

$ ls /tmp/tmpJLWAGC.tmp

ls: cannot access /tmp/tmpJLWAGC.tmp: No such file or directory

Web應用程式

現在我們來建構一個ASP.NET Core Web應用程式。今天我使用預設的模闆項目。

$ dotnet new -t web

Created new C# project in /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp.

$ dotnet restore

** snipped**

log  : Restore completed in 9721ms.

$ dotnet publish -c Release

Publishing WebApp for .NETCoreApp,Version=v1.1

** snipped **

publish: Published to /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp/bin/Release/netcoreapp1.1/publish

Published 1/1 projects successfully

現在可以用dotnet指令運作。

$ dotnet bin/Release/netcoreapp1.1/publish/WebApp.dll

info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]

User profile is available. Using '/home/tatanaka/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.

Hosting environment: Production

Content root path: /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp

Now listening on: http://localhost:5000

Application started. Press Ctrl+C to shut down.

為這個Web應用程式也指定dotnetuser名稱。

$ sudo mkdir /var/SystemdExample

$ sudo cp -R bin/Release/netcoreapp1.1/publish/* /var/SystemdWebExample

$ sudo chown -R dotnetuser:dotnetuser /var/SystemdWebExample

然後建立一個自定義的systemd單元檔案

/etc/systemd/system/netcore-web-example.service

19

20

[Unit]

Description=Example for .NET Core WebApp with systemd

DefaultDependencies=no

Wants=network.target # network is required

After=network.target

[Service]

ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet WebApp.dll

WorkingDirectory=/var/SystemdWebExample

Restart=always

RestartSec=10   # Restart service after 10 seconds if dotnet service crashes

SyslogIdentifier=dotnet-example

User=dotnetuser

Group=dotnetuser

PrivateTmp=true

Environment=ASPNETCORE_ENVIRONMENT=Production # specify environment variable for environment

Environment=ASPNETCORE_URLS=http://*:8080 # specify environement variable for listening port

[Install]

WantedBy = multi-user.target

最後,您可以将ASP.NET Core應用程式作為Linux守護程式運作。請注意,此應用程式偵聽端口8080代替了ASP.NET Core 預設的 5000,因為我在

ASPNETCORE_URLS

單元檔案中指定了環境變量  。

21

22

23

24

25

26

27

28

29

30

31

32

$ systemctl start netcore-web-example.service

[tatanaka@localhost WebApp]$ systemc^C

[tatanaka@localhost WebApp]$ sudo systemctl status netcore-web-example.service

[sudo] password for tatanaka:

● netcore-web-example.service - Example for .NET Core WebApp with systemd

Loaded: loaded (/etc/systemd/system/netcore-web-example.service; disabled; vendor preset: disabled)

Active: active (running) since Sat 2017-02-25 01:02:12 JST; 11s ago

Main PID: 7041 (dotnet)

CGroup: /system.slice/netcore-web-example.service

└─7041 /opt/rh/rh-dotnetcore11/root/usr/bin/dotnet WebApp.dll

Feb 25 01:02:12 localhost.localdomain systemd[1]: Started Example for .NET Core WebApp with systemd.

Feb 25 01:02:12 localhost.localdomain systemd[1]: Starting Example for .NET Core WebApp with systemd...

Feb 25 01:02:12 localhost.localdomain dotnet-example[7041]: info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]

Feb 25 01:02:12 localhost.localdomain dotnet-example[7041]: User profile is available. Using '/home/dotnetuser/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.

Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Hosting environment: Production

Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Content root path: /var/SystemdWebExample

Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Now listening on: http://*:8080

Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Application started. Press Ctrl+C to shut down.

$ journalctl -u netcore-web-example -xf

-- Logs begin at Mon 2017-02-20 11:58:31 JST. --

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Sending file. Request path: '/images/banner4.svg'. Physical path: '/var/SystemdWebExample/wwwroot/images/banner4.svg'

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Request finished in 0.1973ms 200 image/svg+xml

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Request starting HTTP/1.1 GET http://localhost:8080/favicon.ico

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Sending file. Request path: '/favicon.ico'. Physical path: '/var/SystemdWebExample/wwwroot/favicon.ico'

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Request finished in 0.5824ms 200 image/x-icon

然而這對于ASP.NET Core的生産使用來說是不夠的。你可能需要設定一個反向代理伺服器,比如Jexus,nginx,防火牆等等。

 Writing a Linux daemon in C#

用C#編寫Linux守護程式

作者:Chaunce

來源:http://www.cnblogs.com/xiaoliangge/

GitHub:https://github.com/liuyl1992

個人位址:http://blog.chaunce.top

公衆号請搜:架構師進階俱樂部 SmartLife_com

用C#編寫Linux守護程式

聲明:原創部落格請在轉載時保留原文連結或者在文章開頭加上本人部落格位址,如發現錯誤,歡迎批評指正。凡是轉載于本人的文章,不能設定打賞功能等盈利行為