转载请注明原作者(think8848)和出处(http://think8848.cnblogs.com)
写在前面的话
不知不觉在cnblogs上注册已经10多年了,看我的园龄就直接暴露了我实际年龄,很多时候看到时间概念时,我总觉得一阵惭愧...自12年开始,我都不知道在忙什么,反正是挺忙的,忙到经常下班就天黑了,以至于偶尔看到傍晚的天空时居然会产生一种莫名的感动。也是从12年开始就很少上cnblogs了,到后来居然莫名奇妙的连用户名和密码都被改了,费了老大劲才又找到,可惜还是改不回我以前那6位的密码了。最近因工作的关系,对这些年一直在做的项目进行了一些反思,发觉一个事实:一个技术性公司或者一名技术人员,轻视技术的话就很容易变成无源之水、无本之木了,因此,是时候好好的学习了,种一颗树最好的时间是十年前,其次就是现在。
写本文的初衷是在CentOS生产环境中部署ASP.NET Core应用程序,为了避免以后又忘记各种步骤,所以还是做点笔记比较好。在此我不打算谈个人对.NET Core技术前景的理解,不管其他人会不会选这个路线,反正我计划是走这个技术路线了。也不打算说明ASP.NET Core项目结构,甚至对于本文涉及的步骤也不解释为什么要这么做(本文涉及的内容比较多,如果全都去说明,篇幅将非常之大,所以我会在相关章节放参考资料链接,希望对您有所帮助)如果您想详细了解本文中每个步骤的含义,请参阅这里,本文将主要介绍在CentOS7.2的最小安装环境里,部署ASP.NET Core应用程序的方法。为了达到照着这篇文章能真正将Web网站真正部署成功的目的,每一个环节我都反复做了验证,如果您照着这个步骤做但却被卡在某步,额..我除了建议您检查操作步骤外,只能希望您面向运气的编程经验能足够丰富。通常而言,这种部署工作,环境的影响非常大,一定要多试、多想、多折腾,没有别的好办法,很多时候别人在远程是帮你解决不了问题的,Good luck!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~我是分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一、 CentOS环境准备(yum源)
本文使用的CentOS版本
CentOS7.2下载地址:http://iso.mirrors.ustc.edu.cn/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1511.iso
CentOS7.2最小安装虚拟机文件(本文实验环境,278M)下载地址: http://pan.baidu.com/s/1pLxWuvT 提取码:sqxn,root密码111111
虚拟机安装包:https://download3.vmware.com/software/wkst/file/VMware-workstation-full-12.1.1-3770994.exe
虚拟机你懂的:5A02H-AU243-TZJ49-GTC7K-3C61N
1. 安装wget
sudo yum install wget -y
2. 备份默认yum源
sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
3. 下载阿里云yum源
sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
4. 清除并重建yum缓存
sudo yum clean all sudo yum makecache
5. 安装EPEL源
sudo yum install epel-release -y
二、安装.NET Core SDK
1. 安装.NET Core SDK
sudo yum install libunwind -y sudo yum install libicu -y curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=809131 sudo mkdir -p /opt/dotnet sudo tar zxf dotnet.tar.gz -C /opt/dotnet sudo ln -s /opt/dotnet/dotnet /usr/local/bin
使用 dotnet --info 查看.NET Core安装信息
2. 创建Hello World
cd ~
mkdir projects cd projects
mkdir hwapp cd hwapp
dotnet new
dotnet restore
dotnet run
(友情提醒1,不要使用 sudo mkdir hwapp 这种方法创建文件夹,不然...
友情提醒2,如果出现“libunwind.so.8: cannot open shared object file: No such file or directory”错误,请尝试使用 sudo yum install icu -y 修复,很奇怪的是我在实体机安装的版本里遇到这个问题了,但是在虚拟机中没有遇到这个问题,解决问题的办法来自这里,感谢ModestMT.Zou兄)
三、安装Nginx或Apache
3.1 安装Nginx
sudo yum install nginx -y
3.1.1 将Nginx设置为开机启动
sudo systemctl enable nginx.service
3.1.2 启动Nginx
service nginx start
3.1.3 查看Nginx是否安装成功并已经启动
a. 查看进程
ps -ef | grep nginx
b. 查看http head
curl --head localhost
3.1.4 设置反向代理
先将nginx配置文件/etc/nginx/nginx.conf中的默认代理的location节注释掉,免得维护起来不方便(当然如果不嫌那些无关配置看着碍眼,也可以直接在这里配置)
然后在/etc/nginx/default.d目录下新建配置文件
cd /etc/nginx/default.d sudo vi aspnetcoreapp.conf
文件内容如下(也可以不用建这个配置文件,直接在/etc/nginx/nginx.conf的location节点中输入这些proxy***内容即可)
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;
}
3.1.5 重启nginx
service nginx restart
3.2 安装Apache
sudo yum install httpd -y
3.2.1 设置Apache开机启动
sudo systemctl enable httpd.service
3.2.2 然后启动Apache服务
service httpd start
3.2.3 查看Apache是否安装并启动成功的方法参见上面3.1.3内容
3.2.4 设置反向代理,在/etc/httpd/conf.d目录下创建reverse_proxy.conf文件
cd /etc/httpd/conf.d sudo vi reverse_proxy.conf
文件内容如下:
<VirtualHost *: 80>
ServerAdmin think8848.cnblogs.com
ServerName think8848
ProxyRequests Off
<Proxy *>
Order Deny,Allow
Allow from all
</Proxy>
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
</VirtualHost>
(友情提示:在上面这个配置里面,ServerAdmin和ServerName中间不要包含空格,另外,Order Deny,Allow中的逗号两边也不要带空格,不要问我为什么,等我哭会儿再告诉你)
3.2.5 重启Apache
service httpd restart
四、设置防火墙例外
4.1 备份防火墙配置文件
sudo cp /etc/firewalld/zones/public.xml /etc/firewalld/zones/public.xml.bak
4.2 编辑防火墙配置文件,开放80端口
sudo vi /etc/firewalld/zones/public.xml
<rule family="ipv4">
<port protocal="tcp" port="80"/>
<accept />
</rule>
4.3 重启防火墙
service firewalld restart
4.4 在浏览器中输入虚拟机ip,看看http服务是否可用,不出意外应该能看到这个页面了
(友情提示 ,如果您不知道虚拟机ip是多少,可以使用ifconfig,如果您发现ifconfig居然是无效命令,那么可能需要先安装一下net-tools包,如下: sudo yum install net-tools -y )
a. Nginx
b. Apache
五、新建ASP.NET Core项目
建一个Asp.Net Core项目 ,使用dotnet命令参数请参阅这里
cd ~/projects mkdir aspnetcoreapp cd aspnetcoreapp dotnet new -t web dotnet restore dotnet run
应该可以看到ASP.NET Core项目已经可以运行了
但此时使用在其他终端上尝试访问http://CentOS地址,是打不开网站的,主要是因为SELinux限制了访问,你可以先将SELinux临时关闭,看看能不能访问
sudo setenforce 0
可以使用命令查看SELinux是否生效,permissive说明已经关闭了
sestatus
此时访问http://CentOS地址,应该就能看见这个界面了
六、新建SELinux策略
现在我们为SELinux创建策略,使其允许Nginx访问
6.1 创建SELinux策略,首先安装semanage命令包
sudo yum install policycoreutils-python -y
(友情提示,如果在执行 sudo cat ... audit2allow -M httpd_allow 命令过程中发生 could not write output file: [Errno 13] Permission denied: 'httpd_allow.te' )错误,则进入到用户根目录 cd ~ 重试,点击这里查看SELinux和audit2allow相关内容)
6.2 创建并应用SELinux策略
6.2.1 创建Nginx策略
cd ~ sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M nginx_allow sudo semodule -i nginx_allow.pp
6.2.2 创建Apache策略
cd ~
sudo cat /var/log/audit/audit.log | grep httpd | grep denied | audit2allow -M httpd_allow sudo semodule -i httpd_allow.pp
七、安装Supervisor
sudo yum install python-setuptools -y sudo easy_install supervisor
7.1 生成配置文件
如果用root用户,则直接使用下列语句
echo_supervisord_conf > /etc/supervisord.conf
如果非root用户,则使用下列命令
cd ~ echo_supervisord_conf > supervisord.conf sudo mv supervisord.conf /etc
修改/etc/supervisord.conf配置文件,将最后两行修改为:
然后再创建一个supervisor的配置目录
sudo mkdir supervisor.d
在这个目录里面新建一个文件aspnetcoreapp.conf,内空如下
[program:aspnetcoreapp]
command=dotnet aspnetcoreapp.dll
directory=/var/websites/aspnetcoreapp
autostart=true
autorestart=true
stderr_logfile=/var/log/aspnetcoreapp.d/error.log
stdout_logfile=/var/log/aspnetcoreapp.d/output.log
environment=ASPNETCORE_ENVIRONMENT=Production
user=root
stopsignal=INT
顺便再创建一下日志文件夹
sudo mkdir /var/log/aspnetcoreapp.d
设置supervisor开机启动
sudo wget -O /usr/lib/systemd/system/supervisord.service https://raw.githubusercontent.com/Supervisor/initscripts/master/centos-systemd-etcs systemctl enable supervisord.service
(友情提示,如果supervisor有问题搞不定,请参考这里,有关supervisor开机启动脚本,请参考这里)
八、发布ASP.NET Core网站
8.1 发布ASP.NET Core网站前,一些依赖的包要安装一下
sudo yum install npm -y sudo npm install -g bower sudo npm install -g gulp
8.2 发布网站
cd ~/projects/aspnetcoreapp dotnet publish -o ~/publish
将网站移动到/var/websites目录中
sudo mkdir /var/websites
sudo mv ~/publish /var/websites/aspnetcoreapp
8.3 启动网站
systemctl start supervisord
稍等片刻,应该就可以打开网站了。使用 reboot 命令重启电脑看看网站能不能访问。
(友情提示:如果第一次在使用dotnet publish命令发布网站过程中网络或是其他原因中断了发布,那么就有可能在以后发布时报“Error: Cannot find module '***'”错误,在这种情况下尝试删除项目根目录下的node_modules文件夹,应该就可以解决问题了)
九、使用systemd实现ASP.NET Core开机自动启动
有关systemd的详细资料,请参阅这里和这里,在使用systemd实现.NET Core程序开机启动前,请先关闭Supervisor服务,方法如下:
sudo systemctl disable supervisord.service
9.1 创建aspnetcoreapp.service文件
cd /usr/lib/systemd/system sudo vi aspnetcoreapp.service
9.2 输入配置文件内容
[Unit]
Description=ASP.NET Core systemd demo Wants=network.target
After=network.target [Service]
ExecStart=/usr/local/bin/dotnet /var/websites/aspnetcoreapp/aspnetcoreapp.dll [Install]
WantedBy=multi-user.target
9.3 设置开机启动
sudo systemctl enable aspnetcoreapp.service
通常使用dotnet命令运行一个*.dll时,基本上都是在dll所在目录中进行,如果不在dll所在目录,想要运行dll行不行呢?答案是可以的,如: dotnet ~/project/hwapp/bin/hwapp.dll ,这完全没有问题,然而,ASP.NET Core项目直接这么运行则会有问题,如下图所示:
请注意Content root path的值,这对于一个web应用而言,意味着wwwroot等之类的目录全都找不到了,使用curl验证一下,果然发生500错误了
那要怎么解决这个问题呢?so easy,只需要将Program.cs中改一下就可以了
首先引入 using System.Reflection; 命名空间,然后将 .UseContentRoot(Directory.GetCurrentDirecotry()) 行注释掉,在下面加上 .UseContentRoot(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)) ,这行代码对于.NETer不用多解释吧,如下图所示
接下来发布Web网站,然后替换/var/websites下原来的网站,接下来重启电脑
重启后进程里面有aspnetcoreapp.dll,说明网站启动成功了
十、使用Monit监控ASP.NET Core网站服务
到现在貌似一切都看起来还不错,但是还有一个问题,如果使用systemd启动网站,而网站应用挂了,如何能自动恢复服务呢?,这里再引入一个监控工具Monit,关于Monit的更多信息请参阅这里
10.1 安装monit
sudo yum install monit -y
10.2 创建网站监控配置文件
sudo vi /etc/monit.d/aspnetcoreapp.conf
配置内容如下:
check host aspnetcoreapp with address localhost
start program "/usr/bin/systemctl start aspnetcoreapp.service"
stop program "/usr/bin/systemctl stop aspnetcoreapp.service" if failed host localhost port 5000 protocol http then restart
if 3 restarts within 3 cycles then timeout
可以使用 sudo monit -t 来测试配置文件是否合法
10.3 配置Monit开机启动
sudo systemctl enable monit.service
重启电脑,应该就能看到启动效果了
10.4 为了展示Monit的监控效果,我们杀死ASP.NET Core网站进程,方法如下:
sudo pkill -9 -f 'aspnetcoreapp.dll'
多刷新几次进程,就会发现过了一小会,网站又被启动了
最后一个问题,那干脆不要使用systemd,直接用monit来自动启动ASP.NET Core网站行不行呢?额...这个问题不好说,我尝试了一下将aspnetcoreapp.conf修改成如下:
check host aspnetcoreapp with address localhost
start program "/usr/local/bin/dotnet /var/websites/aspnetcoreapp/aspnetcoreapp.dll"
stop program "pkill -9 -f 'aspnetcoreapp.dll'" if failed host localhost port 5000 protocol http then restart
if 3 restarts within 3 cycles then timeout
也可以启动Web网站,但是过不了多久就会重启,但是重启时网站也跟着重启,这就尴尬了...这个原因我猜想应该是在monit中启动的dotnet命令,在它的一次check周期结束后monit的check进程就关闭了,而使用这个进程打开的dotnet程序也跟着关了,不知道monit是否有systemd的类似foking的设置,有知道的兄弟吱一声吧。
最最后,才开始接触.NET Core,通过这两天一个简单的学习,个人感觉Nginx+Supervisor的方式效果更好点,ASP.NET Core官方也使用此组合。