用腾讯宝塔Linux服务器,部署.Net.Core项目(Net6+MSSQL2019)
环境准备 下面我们使用VM虚拟机.我这里安装的Linux系统是centos7 软件提供: VM:VMware 中国 - 交付面向企业的数字化基础 | CN centos7Minimal :Download如果不会下载可以到我的百度网盘下载:由于避免某某东东不直接提供下载 请右上角加群索要直接打开VM 选择 文件打开 centos7镜像文件(我是使用的我网盘制作的镜像) 然后在配置内存
本文的服务器:腾讯宝塔Linux (CentOS 7.8 64bit)
安装最新 .NET6 环境
1. sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
2.sudo yum install dotnet-sdk-6.0
3. sudo yum install aspnetcore-runtime-6.0
安装 SQL Server 2019
1. 下载 Microsoft SQL Server 2019 Red Hat 存储库配置文件:
sudo curl -o /etc/yum.repos.d/mssql-server.repo https://packages.microsoft.com/config/rhel/7/mssql-server-2019.repo
(注意这个版本是适应CentOS 7.8的)
2. 运行以下命令以安装 SQL Server:
sudo yum install -y mssql-server
3包安装完成后,运行 mssql-conf setup,按照提示设置 SA 密码并选择版本。
sudo /opt/mssql/bin/mssql-conf setup
4完成配置后,验证服务是否正在运行:
systemctl status mssql-server
5若要允许远程连接,请在 RHEL 的防火墙上打开 SQL Server 端口。 默认的 SQL Server 端口为 TCP 1433。 如果为防火墙使用的是 FirewallD,则可以使用以下命令:
sudo firewall-cmd --zone=public --add-port=1433/tcp --permanent
sudo firewall-cmd --reload
6如果需要更改对外端口
# 修改Sqlserver默认端口为5500
/opt/mssql/bin/mssql-conf set network.tcpport 5500
修改后,记得再
sudo firewall-cmd --zone=public --add-port=5500/tcp --permanent
sudo firewall-cmd --reload
7启用SQL Server代理
sudo /opt/mssql/bin/mssql-conf set sqlagent.enabled true #需要重启服务生效 sudo systemctl restart mssql-server
8自动备份和删除作业
备份脚本:
declare @path nvarchar(256)
set @path = '/www/data/backup/bdata_' + replace(replace(convert(nvarchar(32),getdate(),126),'.','_'),':','_') + '.bak'
backup database [JPtabData] to disk = @path
删除过期备份
--删除创建时间为@CreateDate,类型为BAK的文件
--与BAK的文件名没有关系
declare @CreateDate datetime
select @CreateDate=getdate()-7
EXECUTE master.dbo.xp_delete_file 0,N'/www/data/backup/',N'BAK',@CreateDate
部署 ASP.NET Core 应用程序
下面就尝试把我用 ASP.NET Core Web API 开发的一个接口网站部署到我们已经安装 .NET SDK 的 CentOS 系统(下文简称服务器)中。
程序发布过程省略(跟以前一样选择Release版本发布文件系统),把编译后的程序发布到了本地 桌面\publish 文件夹
然后借助 FTP 工具 XFTP 把程序文件传输到服务器/home/wwwroot文件夹。
上传完毕后,需要先通过cd
命令进入网站根目录/home/wwwroot
,再输入如下命令启动网站程序:
dotnet WebApplication1.dll
如果在任意非站点根目录,通过下面这种方式直接运行,程序会抛异常,不知是程序原因还是其他原因。
dotnet /home/wwwroot/WebApplication1.dll
如果你可以看到如下界面则表示程序启动成功。
Nginx配置反向代理
Nginx是一个高性能的Web服务器软件。这是一个比 Apache HTTP Server 更加灵活和轻量级的程序。
我们的网站程序启动的端口是5000
,可以借助 Nginx 把程序5000
端口映射到80
端口。
Nginx官方文档 & Nginx开发从入门到精通 - Tengine
安装 Nginx(如果不是宝塔板的,请自安装一个)
1 在Nginx面板添加网站
2。在该站点设置最后加上这行
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
(记住是在最后一个大括号内加,这个是获取客户端IP用的)
3。设置反向代理
Supervisor 配置守护进程
Supervisor 是用 Python 开发的 Linux/Unix 系统下的一个进程管理工具。它可以使进程脱离终端,变为后台守护进程(daemon)。实时监控进程状态,异常退出时能自动重启。
Supervisor 不支持任何版本的 Window 系统;仅支持在 Python2.4 或更高版本,但不能在任何版本的 Python 3 下工作。
其主要组成部分:
supervisord:Supervisor 的守护进程服务,用于接收进程管理命令;
supervisorctl:Supervisor 命令行工具,用于和守护进程通信,发送管理进程的指令;
Web Server:Web 端进程管理工具,提供与 supervisorctl 类似功能,管理进程;
XML-RPC Interface:提供 XML-RPC 接口,请参阅 XML-RPC API文档。
安装 Supervisor
联网状态下,官方推荐首选安装方法是使用easy_install,它是setuptools(Python 包管理工具)的一个功能。所以先执行如下命令安装 setuptools:
yum install python-setuptools
请更换root
用户,执行如下命令安装 Supervisor:
easy_install supervisor
配置 Supervisor
运行supervisord服务的时候,需要指定 Supervisor 配置文件,如果没有显示指定,默认会从以下目录中加载:
$CWD/supervisord.conf #$CWD表示运行 supervisord 程序的目录 $CWD/etc/supervisord.conf /etc/supervisord.conf /etc/supervisor/supervisord.conf (since Supervisor 3.3.0) ../etc/supervisord.conf (Relative to the executable) ../supervisord.conf (Relative to the executable)
所以,先通过如下命令创建目录,以便让 Supervisor 成功加载默认配置:
mkdir /etc/supervisor
加载目录有了,然后通过echo_supervisord_conf
程序(用来生成初始配置文件)来初始化一个配置文件:
echo_supervisord_conf > /etc/supervisor/supervisord.conf
尾部找到如下文本片段:
;[include] ;files = relative/directory/*.ini
改为:
[include]
files = conf.d/*.conf
即,把注释去除、设置/etc/supervisor/conf.d
为 Supervisor 进程配置文件加载目录。
这样,Supervisor 会自动加载该目录下.conf
后缀的文件作为共同服务配置。Supervisor 管理的每个进程单独写一个配置文件放在该目录下,supervisord.conf
配置文件中保留公共配置。
创建进程配置加载目录:
mkdir /etc/supervisor/conf.d
创建文件
touch netcore.conf
接下来就需要为我们已经部署的 ASP .NET Core 程序的宿主进程创建一个进程配置文件netcore.conf
,保存并上传到/etc/supervisor/conf.d
目录。
配置文件netcore.conf
内容如下:
[program:WebApplication1] ;自定义进程名称 command=dotnet WebApplication1.dll ;程序启动命令 directory=/home/wwwroot ;命令执行的目录 autostart=true ;在Supervisord启动时,程序是否启动 autorestart=true ;程序退出后自动重启 startretries=5 ;启动失败自动重试次数,默认是3 startsecs=1 ;自动重启间隔 user=root ;设置启动进程的用户,默认是root priority=999 ;进程启动优先级,默认999,值小的优先启动 stderr_logfile=/var/log/WebApplication1.err.log ;标准错误日志 stdout_logfile=/var/log/WebApplication1.out.log ;标准输出日志 environment=ASPNETCORE_ENVIRONMENT=Production ;进程环境变量 stopsignal=INT ;请求停止时用来杀死程序的信号
启动 Supervisor 服务,命令如下:
supervisord -c /etc/supervisor/supervisord.conf
这时,在会发现我们部署的网站程序不在 shell 中通过dotnet xxx.dll
启动,同样可以访问。
设置 Supervisor 开机启动
首先为 Supervisor 新建一个启动服务脚本supervisord.service
,然后保存并上传至服务器/usr/lib/systemd/system/
目录。
脚本内容如下:(原出处有两个错误,特记录下来 红色的路径要根据你自己的路径更改)
#supervisord service for systemd (CentOS 7.0+) # by ET-CS (https://github.com/ET-CS) [Unit] Description=Supervisor daemon [Service] Type=forking ExecStart=/usr/bin/supervisord -c /etc/supervisor/supervisord.conf ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown ExecReload=/usr/bin/supervisorctl $OPTIONS reload KillMode=process Restart=on-failure RestartSec=42s [Install] WantedBy=multi-user.target
设置开启启动:
systemctl enable supervisor
验证是否成功:
systemctl is-enabled supervisor
如果输出enabled
则表示设置成功,也可重启服务器验证。
其它 Linux 发行版开机启动脚本 User-contributed OS init scripts for Supervisor
Supervisorctl 管理进程
Supervisor 服务启动后,受其管理的进程会在后台运行。可以通过supervisorctl
客户端管理进程。
输入如下命令进入supervisorctl
交互终端,按Ctrl
+C
键退出:
supervisorctl
输入help
查询帮助:
supervisor> help default commands (type help <topic>): ===================================== add exit open reload restart start tail avail fg pid remove shutdown status update clear maintail quit reread signal stop version
输入help ****
查询详细命令,比如输入help stop
:
supervisor> help stop stop <name> Stop a process stop <gname>:* Stop all processes in a group stop <name> <name> Stop multiple processes or groups stop all Stop all processes
如何启动、停止、重启进程等命令,我这里就不在记录,大家自行查找吧。
除此之外,Supervisor 还提供了 Web 管理界面用来管理进程,如何配置启动请参考官方文档。
至此,我们已经完成了 ASP.NET Core 应用程序在 CentOS7 服务器上的部署。
问题#
问题1#
错误 NU1605: 检测到包降级: XXXXXXXXXXXXX 从 4.3.0 降级到 XXXXXXXXXXXXX。直接从项目引用包以选择不同版本
这个问题一开始我按照官方文档修改了,实际还是不可以。所以我选择了可移植发布的。而我在写这篇文章的时候又可以了。
问题2#
验证码我使用了
System.Drawing
,不过在Linux下的话,这个是无法显示的。解决办法
System.Drawing.Common
组件提供对GDI+图形功能的访问。它是依赖于GDI+的,那么在Linux上它如何使用GDI+,因为Linux上是没有GDI+的。Mono 团队使用C语言实现了GDI+接口,提供对非Windows系统的GDI+接口访问能力(个人认为是模拟GDI+,与系统图像接口对接),这个就是libgdiplus
。进而可以推测System.Drawing.Common
这个组件实现时,对于非Windows系统肯定依赖了ligdiplus
这个组件。如果我们当前系统不存在这个组件,那么自然会报错,找不到它,安装它即可解决。Ubuntu一键命令
Copy
sudo curl https://raw.githubusercontent.com/stulzq/awesome-dotnetcore-image/master/install/ubuntu.sh|sh
问题3#
指定端口启动
修改
Program.cs
增加代码
Copy
.ConfigureAppConfiguration(builder => { //dotnet test.dll --urls "http://*:5000;https://*:5001" builder.AddCommandLine(args);//设置添加命令行 })
完整代码
Copy
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) //将默认ServiceProviderFactory指定为AutofacServiceProviderFactory https://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html#asp-net-core-3-0-and-generic-hosting .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureAppConfiguration(builder => { //dotnet test.dll --urls "http://*:5200;https://*:5100" builder.AddCommandLine(args);//设置添加命令行 }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
问题4#
验证码生成代码
验证码生成代码应该是蛮多的,我把我的分享下
Copy
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; namespace XXX.Util { public static class ValidateCodeHelper { /// <summary> /// 验证码的最大长度 /// </summary> public static int MaxLength => 10; /// <summary> /// 验证码的最小长度 /// </summary> public static int MinLength => 1; /// <summary> /// 生成验证码 /// </summary> /// <param name="length">指定验证码的长度</param> /// <returns></returns> public static string CreateValidateCode(int length) { int[] randMembers = new int[length]; int[] validateNums = new int[length]; string validateNumberStr = ""; //生成起始序列值 int seekSeek = unchecked((int)DateTime.Now.Ticks); Random seekRand = new Random(seekSeek); int beginSeek = (int)seekRand.Next(0, Int32.MaxValue - length * 10000); int[] seeks = new int[length]; for (int i = 0; i < length; i++) { beginSeek += 10000; seeks[i] = beginSeek; } //生成随机数字 for (int i = 0; i < length; i++) { Random rand = new Random(seeks[i]); int pownum = 1 * (int)Math.Pow(10, length); randMembers[i] = rand.Next(pownum, Int32.MaxValue); } //抽取随机数字 for (int i = 0; i < length; i++) { string numStr = randMembers[i].ToString(); int numLength = numStr.Length; Random rand = new Random(); int numPosition = rand.Next(0, numLength - 1); validateNums[i] = Int32.Parse(numStr.Substring(numPosition, 1)); } //生成验证码 for (int i = 0; i < length; i++) { validateNumberStr += validateNums[i].ToString(); } return validateNumberStr; } /// <summary> /// 得到验证码图片的长度 /// </summary> /// <param name="validateNumLength">验证码的长度</param> /// <returns></returns> public static int GetImageWidth(int validateNumLength) { return (int)(validateNumLength * 12.0); } /// <summary> /// 得到验证码的高度 /// </summary> /// <returns></returns> public static double GetImageHeight() { return 22.5; } //C# MVC 升级版 /// <summary> /// 创建验证码的图片 /// </summary> /// <param name="validateCode">验证码</param> public static byte[] CreateValidateGraphic(string validateCode) { Bitmap image = new Bitmap((int)Math.Ceiling(validateCode.Length * 12.0), 22); Graphics g = Graphics.FromImage(image); try { //生成随机生成器 Random random = new Random(); //清空图片背景色 g.Clear(Color.White); //画图片的干扰线 for (int i = 0; i < 25; i++) { int x1 = random.Next(image.Width); int x2 = random.Next(image.Width); int y1 = random.Next(image.Height); int y2 = random.Next(image.Height); g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2); } Font font = new Font("Arial", 12, (FontStyle.Bold | FontStyle.Italic)); LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true); g.DrawString(validateCode, font, brush, 3, 2); //画图片的前景干扰点 for (int i = 0; i < 100; i++) { int x = random.Next(image.Width); int y = random.Next(image.Height); image.SetPixel(x, y, Color.FromArgb(random.Next())); } //画图片的边框线 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1); //保存图片数据 MemoryStream stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //输出图片流 return stream.ToArray(); } finally { g.Dispose(); image.Dispose(); } } } }
总结#
更多推荐
所有评论(0)