若是要在Red Hat Enterprise Linux上将.NET Core进程做为后台进程运行,则能够建立自定义systemd单元。今天我将为.NET Core编写两个自定义系统单元的例子。一个是运行.NET Core控制台应用程序的一种类型,另外一个是运行ASP.NET Core Web应用程序的简单类型。 linux
您能够用dotnet run
在systemd中使用指定项目目录做为工做目录。可是,咱们来构建一个二进制文件并将其用于systemd。用dotnet new 命令建立您的项目后编辑Program.cs以下。nginx
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>目录下的二进制文件
。git
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
|
首先,建立一个运行守护进程和工做目录的用户。web
$ 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!
|
在上述系统单元中,程序在临时文件夹下写入一个文件。你有时想写一个来自其余用户的临时文件是安全的。您能够在[Service]
section中的指定使用PrivateTemp。app
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
目录。dom
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
|
如今咱们来构建一个ASP.NET Core Web应用程序。今天我使用默认的模板项目。svg
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命令运行。ui
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.
|
为这个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,防火墙等等。