如果要在Red Hat Enterprise Linux上将.NET Core进程作为后台进程运行,则可以创建自定义systemd单元。今天我将为.NET Core编写两个自定义系统单元的例子。一个是运行.NET Core控制台应用程序的一种类型,另一个是运行ASP.NET Core Web应用程序的简单类型。

控制台应用程序

建立一个应用程序

您可以用dotnet run在systemd中使用指定项目目录作为工作目录。但是,我们来构建一个二进制文件并将其用于systemd。用dotnet new 命令创建您的项目后编辑Program.cs如下。

 using System;
using System.IO; namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
var path = Path.GetTempFileName();
File.WriteAllText(path, "Hello Temp File!");
Console.WriteLine($"Wrote temp file: {path}");
}
}
}

然后用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#

用C#编写Linux守护进程的更多相关文章

  1. C#与Linux守护进程

    用C#编写Linux守护进程   如果要在Red Hat Enterprise Linux上将.NET Core进程作为后台进程运行,则可以创建自定义systemd单元.今天我将为.NET Core编 ...

  2. Linux守护进程编写指南

    Linux守护进程编写指南 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进 程.Linux的大多数服务器 ...

  3. Linux守护进程的编程实现

    Linux 守护进程的编程方法 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程.Linux的大多数s ...

  4. 笔记整理--Linux守护进程

    Linux多进程开发(三)进程创建之守护进程的学习 - _Liang_Happy_Life__Dream - 51CTO技术博客 - Google Chrome (2013/10/11 16:48:2 ...

  5. CentOS 7.4 初次手记:第一章 Linux守护进程(daemon)

    第一节 init & sysvinit 6 I sysvinit 运行顺序... 6 II Sysvinit和系统关闭... 7 III Sysvinit 的小结... 7 IV 运行级别.. ...

  6. 【转】学习Linux守护进程详细笔记

    [原文]https://www.toutiao.com/i6566814959966093837/ Linux守护进程 一. 守护进程概述 守护进程,也就是通常所说的Daemon进程,是Linux中的 ...

  7. [Linux] 守护进程和守护线程

    对于JAVA而言,一般一个应用程序只有一个进程——JVM.除非在代码里面另外派生或者开启了新进程. 而线程,当然是由进程开启的.当开启该线程的进程离开时,线程也就不复存在了. 所以,对于JAVA而言, ...

  8. .NET跨平台实践:用C#开发Linux守护进程

    Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作. 一句话,为L ...

  9. .NET跨平台实践:用C#开发Linux守护进程(转)

    Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作. 一句话,为L ...

随机推荐

  1. MicroPython之TPYBoard v102开发板控制OLED显示中文

    转载请以链接形式注明文章来源,公众号:MicroPython玩家汇 0x00前言 之前看到一篇文章是关于TPYBoardv102控制OLED屏显示的,看到之后就想尝试一下使用OLED屏来显示中文.最近 ...

  2. QCanvasItem介绍-QT3

    QCanvasItem类提供一个在QCanvas上的抽象图形对象. 各种QCanvasItem子类提供立即可用的行为.这个类是一个纯粹的抽象超类,它提供了在所有具体的canvas项目类中共享的行为.Q ...

  3. android散点技术

    1.怎么实现android虚拟按键(回退和回到主界面) android 中如何模拟back键 2.怎么用局域网的方式(wifi或是网线)来调试android机 参考资料: http://www.ith ...

  4. python检测404页面

    某些网站为了实现友好的用户交互,提供了一种自定义的错误页面,而不是显示一个大大的404 ,比如CSDN上的404提示页面如下: 这样虽然提高了用户体验,但是在编写对应POC进行检测的时候如果只根据返回 ...

  5. web前端经典面试题大全及答案

    阅读目录 JavaScript部分 JQurey部分 HTML/CSS部分 正则表达式 开发及性能优化部分 本篇收录了一些面试中经常会遇到的经典面试题以及自己面试过程中遇到的一些问题,并且都给出了我在 ...

  6. 看JQ时代过来的前端,如何转换思路用Vue打造选项卡组件

    前言 在Vue还未流行的时候,我们都是用JQuery来封装一个选项卡插件,如今Vue当道,让我们一起来看看从JQ时代过来的前端是如何转换思路,用数据驱动DOM的思想打造一个Vue选项卡组件. 接下来, ...

  7. CSS 设置table下tbody滚动条

    table tbody { display:block; height:195px; overflow-y:scroll; } table thead, tbody tr { display:tabl ...

  8. 如何在java注解中加入原生html标签内容

    你是否也遇到过类似的事情.想在java注解加入类似于下面这种注释: 结果出来却变成了这样 ,标签被解析了, 这怎么办呢 : 且看分解 我们在注解中直接放入下边这样的代码: <Response&g ...

  9. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (5) EF CRUD

    Github源码地址:https://github.com/solenovex/Building-asp.net-core-2-web-api-starter-template-from-scratc ...

  10. Hadoop日志以及日志的格式和命名组成

    一.日志的格式 有两种日志,分别以log和out结尾 1)以log结尾的日志: 通过log4j日志记录格式进行记录的日志,采用的日常滚动文件后缀策略来命名日志文件,内容比较全. 2)以out结尾的日志 ...