• 用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

    1
    2
    3
    4
    5
    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命令查看控制台输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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

    1
    2
    3
    4
    5
    6
    7
    8
    [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目录。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ 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应用程序。今天我使用默认的模板项目。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ 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命令运行。

    1
    2
    3
    4
    5
    6
    7
    $ 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.

    创建一个自定义的systemd

    为这个Web应用程序也指定dotnetuser名称。

    1
    2
    3
    $ 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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单元文件中指定了环境变量  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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#

  • 相关阅读:
    Day10
    Day9
    Day8
    Day7
    Day 6
    Day5
    第一周计划
    事件总线模式辨析
    解释器模式辨析
    解释器模式深度探究
  • 原文地址:https://www.cnblogs.com/xiaoliangge/p/8379992.html
Copyright © 2020-2023  润新知