centos部署.net core

Centos7部署.net core应用

安装

dotnet产品提要

首先需要注册Microsoft签名密钥并添加Microsoft产品提要,才能安装.net

1
2
rpm --import https://packages.microsoft.com/keys/microsoft.asc
sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl= https://packages.microsoft.com/yumrepos/microsoft-rhel7.3-prod\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/dotnetdev.repo'

默认使用root用户操作

安装.NET SDK

首先更新yum

1
yum update

安装所需组件

1
yum install libunwind libicu

安装.NET SDK

1
yum install dotnet-sdk-2.1.200

完成安装,dotnet --version验证安装

部署应用

将你的.net core应用随意放置在某个目录,进入目录,执行

1
dotnet YourApp.WebApi.dll

即可启动服务,默认启动端口为5000.

nginx代理

安装nginx

安装nginx需要添加EPEL仓库,然后再安装:

1
2
yum install epel-release
yum install nginx
启动nginx

启动:

1
systemctl start nginx
设置nginx开机启动
1
systemctl enable nginx
修改配置

将nginx的默认配置文件中的80端口内容注释掉,文件路径:/etc/nginx/nginx.conf,然后在nginx的配置加载目录下创建你需要代理的端口配置文件yourapp.conf,路径:/etc/nginx/conf.d,文件内容:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

重启nginx即可通过80端口访问部署的.net core服务。

配置守护进程

由于.net core程序在linux上运行,一般都是需要在shell里运行,执行命令:dotnet app.dll,一旦窗口关闭了,程序就被杀了,所以需要配置个守护进程,微软推荐:Supervisor

安装

安装很简单,一条命令:

1
yum install supervisor

配置

修改默认配置文件:supervisord.conf,找到最后:

1
2
[include]
files = supervisord.d/*.ini

修改为:

1
2
[include]
files = supervisord.d/*.conf

进入supervisord.d文件夹,创建APP的配置文件YourAPP.conf

1
2
cd supervisord.d
vim YourAPP.conf

内容为:

1
2
3
4
5
6
7
8
9
10
11
[program:HelloWebApp]
command=dotnet YourAPP.dll #要执行的命令
directory=/usr/local/YourAPP #命令执行的目录
environment=ASPNETCORE__ENVIRONMENT=Production #环境变量
user=root #进程执行的用户身份
stopsignal=INT
autostart=true #是否自动启动
autorestart=true #是否自动重启
startsecs=1 #自动重启间隔
stderr_logfile=/var/log/HelloWebApp.err.log #标准错误日志
stdout_logfile=/var/log/HelloWebApp.out.log #标准输出日志

保存退出

运行supervisord

1
2
supervisord -c /etc/supervisord.conf
ps -ef | grep APPName

常用命令:

1
2
3
4
5
supervisorctl shutdown #关闭所有任务

supervisorctl stop|start program_name

supervisorctl status #查看所有任务状态

加自启动

文件路径:/usr/lib/systemd/system/supervisord.service,安装时候已经存在,如果没有,就自己创建一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=Supervisor daemon

[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf
ExecStop=/usr/bin/supervisorctl shutdown
ExecReload=/usr/bin/supervisorctl reload
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

加载启动项:

1
2
3
systemctl enable supervisord
验证
systemctl is-enabled supervisord

问题记录

由于安装在linux上,不同于windows,出现了一个现象,页面进行请求之后,消息队列中的消息一直无法被消费,查看日志,显示:

1
2
3
The handler does not support custom handling of certificates with this combination of libcurl (7.29.0) and its SSL backend ("NSS/3.28.4").) ---> System.PlatformNotSupportedException: The handler does not support custom handling of certificates with this combination of libcurl (7.29.0) and its SSL backend ("NSS/3.28.4").
at System.Net.Http.CurlHandler.SslProvider.SetSslOptionsForUnsupportedBackend(EasyRequest easy, ClientCertificateProvider certProvider)
at System.Net.Http.CurlHandler.SslProvider.SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption

原因就是linux不支持ssl(貌似是这样),搜了一堆答案,大部分是建议升级curl

解决linux netcore https请求使用自签名证书忽略安全检查方法

开始:
首先安装openssl和gcc

1
yum install openssl-devel gcc

然后是最新版本的curl:

1
2
3
4
5
6
wget https://curl.haxx.se/download/curl-7.59.0.tar.gz
tar -zxf curl-7.59.0.tar.gz
cd curl-7.59.0
./configure --prefix=/usr/local/curl/ --without-nss --with-ssl=/usr/local/ssl/
make
make install

备份原来的curl:

1
mv /usr/bin/curl /usr/bin/curl.bak

新安装的curl创建软链接

1
ln -s /usr/local/curl/bin/curl /usr/bin/curl

查看此时curl版本

1
curl --version

编辑搜索目录:

1
vim /etc/ld.so.conf

增加一行:/usr/local/curl/lib

重启服务,完成!

Supervisor详细配置文件

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
; Sample supervisor config file.
;
; For more information on the config file, please see:
; http://supervisord.org/configuration.html
;
; Notes:
; - Shell expansion ("~" or "$HOME") is not supported. Environment
; variables can be expanded using this syntax: "%(ENV_HOME)s".
; - Quotes around values are not supported, except in the case of
; the environment= options as shown below.
; - Comments must have a leading space: "a=b ;comment" not "a=b;comment".
; - Command will be truncated if it looks like a config file comment, e.g.
; "command=bash -c 'foo ; bar'" will truncate to "command=bash -c 'foo ".

[unix_http_server]
file=/tmp/supervisor.sock ; socket 文件路径
;chmod=0700 ; socket 文件 模式 (默认 0700)
;chown=nobody:nogroup ; socket file uid:gid owner
;username=user ; 使用supervisorctl连接的用户
;password=123 ; 上条用户的密码

;[inet_http_server] ; Web Server和远程的supervisorctl 配置块(默认关闭)
;port=127.0.0.1:9001 ; 监听的地址和端口
;username=user ; 登录时用的用户
;password=123 ; 上条用户的密码

[supervisord]
logfile=/tmp/supervisord.log ; supervisord进程日志路径
logfile_maxbytes=50MB ; supervisord进程日志的大小 当超过50M时,会生成一个新的日志( 0 表示不限制)
logfile_backups=10 ; 日志文件保持的数量,启动supervisor时 会自动创建10个buckup文件,用于log rotate ( 0 表示不限制)
loglevel=info ; 日志级别
pidfile=/tmp/supervisord.pid ; supervisord的pid文件路径。
nodaemon=false ; 如果是true,supervisord进程将在前台运行 默认为false(后台运行)
minfds=1024 ; 这个是最少系统空闲的文件描述符,低于这个值supervisor将不会启动
minprocs=200 ; 最小可用的进程描述符,低于这个值supervisor也将不会正常启动
;umask=022 ; 进程创建文件的掩码 (默认 022)
;user=chrism ; 该参数指定的用户也可以对supervisord进行管理
;identifier=supervisor ; supervisord的标识符
;directory=/tmp ; 当supervisord以守护进程运行的时候,启动supervisord进程之前,会先切换到这个目录
;nocleanup=true ; false的时候 supervisord进程启动的时候 会在把以前子进程产生的日志文件(路径为AUTO的情况下)清除掉(true不清除)
;childlogdir=/tmp ; 当子进程日志路径为AUTO的时候,子进程日志文件的存放路径 (默认 $TMP)
;environment=KEY="value" ; 这个是用来设置环境变量的,supervisord在linux中启动默认继承了linux的 环境变量,在这里可以设置supervisord进程特有的其他环境变量supervisord启动子进程时,子进程会拷贝父进程的内存空间内容。 所以设置的这些环境变量也会被子进程继承 (默认不设置)
;strip_ansi=false ; 这个选项如果设置为true,会清除子进程日志中的所有ANSI(\n,\t) 序列

[rpcinterface:supervisor] ; 这个选项是给XML_RPC用的,果想使用supervisord或者web server 必须要开启
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface


[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; supervisorctl本地连接supervisord,本地UNIX socket
;serverurl=http://127.0.0.1:9001 ; supervisorctl远程连接supervisord的时候,用到的地址和端口
;username=chris ; 连接登录的用户名
;password=123 ; 密码
;prompt=mysupervisor ; 输入用户名密码时候的提示符 默认:mysupervisor
;history_file=~/.sc_history ; 指定历史命令的文件


;[program:theprogramname] ; 案例 [program:给要管理进程起的一个名字]
;command=/bin/cat ; 要执行的进程 可带参数 $1 $2 $3 注意!! 执行的进程不能是守护进程 ! !
;process_name=%(program_name)s ; 进程名 下条numprocs参数为1,就不用管这个参数 默认值%(program_name)s也就是上面的那个program冒号后面的名字
;numprocs=1 ; 启动进程的数目。当不为1时,就是进程池的概念,默认为1
;directory=/tmp ; 进程运行前,会前切换到这个目录
;umask=022 ; 进程掩码 (default None)
;priority=999 ; 子进程启动关闭优先级,优先级低的,最先启动,关闭的时候最后关闭 (default 999)
;autostart=true ; 设置为true 子进程将在supervisord启动后被自动启动
;startsecs=1 ; 设置子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了
;startretries=3 ; 进程启动失败后,最大尝试启动的次数 当超过3次后,supervisor将把此进程的状态置为FAIL
;autorestart=unexpected ; 设置子进程挂掉后自动重启的情况,有三个选项,false,unexpected和true。如果为false的时候,无论什么情况下,都不会被重新启动,如果为unexpected,只有当进程的退出码不在上面的exitcodes里面定义的退出码的时候,>才会被自动重启。当为true的时候,只要子进程挂掉,将会被无条件的重启
;exitcodes=0,2 ; 注意和上面的的autorestart=unexpected对应 exitcodes里面的定义的退出码是expected的。
;stopsignal=QUIT ; 进程停止信号,可以为TERM, HUP, INT, QUIT, KILL, USR1, or USR2等信号 默认为TERM 当用设定的信号去杀掉进程,退出码会被认为是expected
;stopwaitsecs=10 ; 这个是当我们向子进程发送stopsignal信号后,到系统返回信息给supervisord,所等待的最大时间。 超过这个时间,supervisord会向该子进程发送一个强制kill的信号(默认10秒)
;stopasgroup=false ; 这个东西主要用于,supervisord管理的子进程,这个子进程本身还有子进程 那么我们如果仅仅干掉supervisord的子进程的话,子进程的子进程有可能会变成孤儿进程 所以咱们可以设置可个选项,把整个该子进程的整个进程组都干掉 设置为true的话,一般killasgroup也会被设置为true 该选项发送的是stop信号(def false)
;killasgroup=false ; 这个和上面的stopasgroup类似,不过发送的是kill信号(def false)
;user=chrism ; 如果supervisord是root启动,我们在这里设置这个非root用户,可以用来管理该program 默认不设置
;redirect_stderr=true ; 为true,则stderr的日志会被写入stdout日志文件中 (default false)
;stdout_logfile=/a/path ; 子进程的stdout的日志路径,可以指定路径,AUTO,none等三个选项 设置为none的话,将没有日志产生。设置为AUTO的话,将随机找一个地方成日志文件,而且当supervisord重新启动的时候,以前的日志文件会被清空。当 redirect_stderr=true的时候,sterr也会写进这个日志文件
;stdout_logfile_maxbytes=1MB ; 日志文件最大大小,和[supervisord]中定义的一样 (default 50MB)
;stdout_logfile_backups=10 ; 和[supervisord]定义的一样 (0 means none, default 10)
;stdout_capture_maxbytes=1MB ; 这个东西是设定capture管道的大小,当值不为0的时候,子进程可以从stdout发送信息,而supervisor可以根据信息,发送相应的event (default 0)
;stdout_events_enabled=false ; 为ture的时候,当子进程由stdout向文件描述符中写日志的时候,将触发supervisord发送PROCESS_LOG_STDOUT类型的event(default false)
;stderr_logfile=/a/path ; 设置stderr写的日志路径,当redirect_stderr=true。这个就不用设置了,设置了也是白搭。因为它会被写入stdout_logfile的同一个文件中 default AUTO(随便找个地存,supervisord重启被清空)
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A="1",B="2" ; 这个是该子进程的环境变量,和别的子进程是不共享的
;serverurl=AUTO ; override serverurl computation (childutils)


;[eventlistener:theeventlistenername] ;这个东西其实和program的地位是一样的,也是suopervisor启动的子进程,不过它干的活是订阅supervisord发送的event。他的名字就叫listener了。我们可以在listener里面做一系列处理,比如报警....
;command=/bin/eventlistener ; 和上面的program一样,表示listener的可执行文件的路径
;process_name=%(program_name)s ; 这个也一样,进程名,当下面的numprocs为多个的时候,才需要。否则默认就OK了
;numprocs=1 ; 相同的listener启动的个数
;events=EVENT ; event event事件的类型,也就是说,只有写在这个地方的事件类型。才会被发送
;buffer_size=10 ; event队列缓存大小 (default 10)
;directory=/tmp ; 进程执行前,会切换到这个目录下执行 (def no cwd)
;umask=022 ; umask for process (default None)
;priority=-1 ; 启动优先级 (default -1)
;autostart=true ; true supervisord启动一起启动 (default: true)
;startsecs=1 ; 设置子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了 (def. 1)
;startretries=3 ; 失败最大尝试次数 (default 3)
;autorestart=unexpected ; 和program一样 (def: unexpected)
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false ; send stop signal to the UNIX process group (default false)
;killasgroup=false ; SIGKILL the UNIX process group (def false)
;user=chrism ; setuid to this UNIX account to run the program
;redirect_stderr=false ; redirect_stderr=true is not allowed for eventlisteners
;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10 ; # of stdout logfile backups (0 means none, default 10)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A="1",B="2" ; process environment additions
;serverurl=AUTO ; override serverurl computation (childutils)


;[group:thegroupname] ; 这个东西就是给programs分组,划分到组里面的program。我们就不用一个一个去操作了 我们可以对组名进行统一的操作。 注意:program被划分到组里面之后,就相当于原来的配置从supervisor的配置文件里消失了supervisor只会对组进行管理,而不再会对组里面的单个program进行管理了
;programs=progname1,progname2 ; 组成员,用逗号分开
;priority=999 ; 优先级,相对于组和组之间 (default 999)


;[include] ; 跟Nginx虚拟主机一个样
;files = relative/directory/*.ini

参考链接

centos部署.net core

文章目录
  1. 安装
    1. dotnet产品提要
    2. 安装.NET SDK
  2. 部署应用
    1. nginx代理
      1. 安装nginx
      2. 启动nginx
      3. 设置nginx开机启动
      4. 修改配置
  3. 配置守护进程
    1. 安装
    2. 配置
    3. 加自启动
  4. 问题记录
    1. 解决linux netcore https请求使用自签名证书忽略安全检查方法
  5. Supervisor详细配置文件
  6. 参考链接
|