2023年6月

.NET Core部署到linux(CentOS)最全解决方案,常规篇一文,我们详细讲解了传统的.NET Core部署到Linux服务器的方法,学到了Linux在虚拟机下的安装、Xshell,Xftp的使用方法、git在linux下的交互使用以及.net core在linux下的发布与运行全过程。本文讲讲解通过使用Supervisor+Nginx的组合来实现.net core的高效部署。

官网:http://supervisord.org,源码位置:https://github.com/Supervisor/supervisor

Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。

它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程。

在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。由于在linux中,每个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭。但是守护进程却能突破这种限制,它脱离于终端并且在后台运行,并且它脱离终端的目的是为了避免进程在运行的过程中的信息在任何终端中显示并且进程也不会被任何终端所产生的终端信息所打断。它从被执行的时候开始运转,直到整个系统关闭才退出。

此处的创建守护进程,是指发布在Linux上 asp.net core 程序的dotnet xxx.dll命令的宿主进程创建一个守护进程。在 Linux 上有很多可以管理进程的工具,我们使用 Supervisor 来做这个事情。

原因有两点:

①、它是微软官方文档推荐的,降低学习成本。
②、它并不一定是最好的,但一定是文档最全的。

  • supervisord

主进程,负责管理进程的server,它会根据配置文件创建指定数量的应用程序的子进程,管理子进程的整个生命周期,对crash的进程重启,对进程变化发送事件通知等。同时内置web server和XML-RPC Interface,轻松实现进程管理。。该服务的配置文件在/etc/supervisor/supervisord.conf。

  • supervisorctl

客户端的命令行工具,提供一个类似shell的操作接口,通过它你可以连接到不同的supervisord进程上来管理它们各自的子程序,命令通过UNIX socket或者TCP来和服务通讯。用户通过命令行发送消息给supervisord,可以查看进程状态,加载配置文件,启停进程,查看进程标准输出和错误输出,远程操作等。服务端也可以要求客户端提供身份验证之后才能进行操作。

  • Web Server

superviosr提供了web server功能,可通过web控制进程(需要设置[inethttpserver]配置项)

  • XML-R- #supervisor

一个Linux/Unix系统上的进程监控工具
一个Python开发的通用的进程管理程序
可以管理和监控Linux上面的进程
能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启
不过同daemontools一样,它不能监控daemon进程

相应安装建议以管理员方式登录系统,非管理员请以sudo命令安装。

Linux sudo命令以系统管理者的身份执行指令,也就是说,经由 sudo 所执行的指令就好像是 root 亲自执行。

1、安装EPEL源的命令如下:

  1. sudo yum -y install epel-release

安装EPEL源

2、执行如下命令安装supervisor:

  1. sudo yum -y install supervisor

安装supervisor

3、设置开机启动:

  1. systemctl enable supervisord

设置开机启动

4、启动supervisord

  1. systemctl start supervisord

5、查看supervisord状态

  1. systemctl status supervisord

查看supervisord状态

通过vi命令或者xftp修改配置文件开启web界面访问,如下图所示,分别取消inet_http_server等四个配置的注释:

  1. vi /etc/supervisord.conf

image-20210114101415192

执行如下命令,重新加载配置文件:

  1. supervisorctl reload

然后在浏览器打开http://你的ip:9001,输入上面我们设置的用户名:user1,密码:123456后,如图所示:

image-20210114101622234

image-20210114101825812

看到上图这个界面,就表示supervisor安装完成了。

切换到/etc/supervisord.d目录,在此目录创建名称为:core50test.ini的ini文件,内容如下:

  1. #表示程序名称,用于在supervisor中显示,无特殊意义。

  2. [program:core50test]

  3. # 输入执行命令,这里表示执行的是dotnet Core50Test.dll

  4. command=/bin/bash -"dotnet Core50Test.dll"

  5. # 应用程序根目录

  6. directory=/root/app_data/core50test/publish

  7. # 是否自动启动,当 supervisor 加载该配置文件的时候立即启动它

  8. autostart=true

  9. # 是否自动重启, 程序异常退出后自动重启

  10. autorestart=true

  11. # 该配置文件输出单个日志文件的大小,默认50M

  12. logfile_maxbytes=50MB

  13. # 日志备份个数

  14. logfile_backups=10

  15. # 记录日志级别

  16. loglevel=info

  17. # 指定标准输出日志文件

  18. stdout_logfile=/root/app_data/data/logs/core50test/core50test.out.log

  19. # 环境变量

  20. environment=ASPNETCORE_ENVIRONMENT=Production

  21. # 启动服务的用户

  22. user=root

  23. # 把stderr重定向到stdout,默认 false

  24. redirect_stderr=true

上述代码包含了注释信息,参考精減版配置如下:

  1. [program:core50test]

  2. command=/bin/bash -"dotnet Core50Test.dll"

  3. directory=/root/app_data/core50test/publish

  4. autostart=true

  5. autorestart=true

  6. logfile_maxbytes=50MB

  7. logfile_backups=10

  8. loglevel=info

  9. stdout_logfile=/root/app_data/data/logs/core50test/core50test.out.log

  10. environment=ASPNETCORE_ENVIRONMENT=Production

  11. user=root

  12. redirect_stderr=true

注意:stdout_logfile指向的文件夹一定要先创建,否则无法启动,上述配置文件中的内容需要根据用户实际情况修改,如我当前登录的用户是:yonghu,你们是其他的就做相应的修改即可。

然后执行如下命令来重新加载配置:

  1. supervisorctl reload

命令执行成功后, 刷新浏览器,可以看到如下界面:

supervisor正在运行的应用

当界面显示running时,则表示我们我们刚刚配置的.net core应用运行起来了。

如下图所示。

image-20210114150451949

我们可以方便的通过supervisor提供的web管理界面对我们的应用进行启动与停止,查看日志等操作,非常的方便,丝般润滑般的爽呀。

Supervisor启动与停止应用

查看日志:

查看日志

  1. ### 查看supervisorctl支持的命令

  2. # supervisorctl help

  3. default commands (type help <topic>):

  4. =====================================

  5. add exit open reload restart start tail

  6. avail fg pid remove shutdown status update

  7. clear maintail quit reread signal stop version

  8.  

  9. ### 查看当前运行的进程列表

  10. # supervisorctl status

Supervisor常用命令

  • update 更新新的配置到supervisord(不会重启原来已运行的程序)

  • reload,载入所有配置文件,并按新的配置启动、管理所有进程(会重启原来已运行的程序)

  • start xxx: 启动某个进程

  • restart xxx: 重启某个进程

  • stop xxx: 停止某一个进程(xxx),xxx为[program:theprogramname]里配置的值

  • stop groupworker: 重启所有属于名为groupworker这个分组的进程(start,restart同理)

  • stop all,停止全部进程,注:start、restart、stop都不会载入最新的配置文

  • reread,当一个服务由自动启动修改为手动启动时执行一下就ok

最常用的几个命令为:

  1. #启动所有

  2. supervisorctl start all

  3.  

  4. # 重启所有

  5. supervisorctl restart all

  6.  

  7. # 停止所有

  8. supervisorctl stop all

  9.  

  10. #PS:要操作某个服务,把all换成服务名即可

  11. #查看服务状态

  12. supervisorctl status

在前面文章中,我们已经可以非常方便的对web应用进行部署与管理了,但还存在一个问题,我们的应用程序默认是绑定的5000端口,如果要指定80端口或者配置域名该怎么处理呢?下面就该nginx登场了。

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

安装方式参考:http://nginx.org/en/linux_packages.html#RHEL-CentOS

安装先决条件:

  1. sudo yum install -y yum-utils

安装yum-utils

设置yum存储库,先创建一下内容的文件:/etc/yum.repos.d/nginx.repo

  1. [nginx-stable]

  2. name=nginx stable repo

  3. baseurl=http://nginx.org/packages/centos/$releasever/$basearch/

  4. gpgcheck=1

  5. enabled=1

  6. gpgkey=https://nginx.org/keys/nginx_signing.key

  7. module_hotfixes=true

  8.  

  9. [nginx-mainline]

  10. name=nginx mainline repo

  11. baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/

  12. gpgcheck=1

  13. enabled=0

  14. gpgkey=https://nginx.org/keys/nginx_signing.key

  15. module_hotfixes=true

image-20210114161247091

默认情况下,使用稳定 nginx 包的存储库。如果要使用主线 nginx 包,请运行以下命令:

  1. yum-config-manager --enable nginx-mainline

运行如下命令安装nginx:

  1. sudo yum install -y nginx

安装nginx

设置开机启动:

  1. systemctl enable nginx

启动nginx:

  1. systemctl start nginx

设置nginx开机启动并启动nginx

此时,就可以在浏览器通过ip访问了:http://你的ip,界面如下:

nginx启动界面

nginx安装完成后,切换到/etc/nginx/conf.d目录,修改default.conf文件内容,如下所示:

  1. server {

  2. listen 80;

  3. server_name localhost;

  4. location / {

  5. proxy_pass http://0.0.0.0:5000;

  6. }

  7. error_page 500 502 503 504 /50x.html;

  8. location = /50x.html {

  9. root /usr/share/nginx/html;

  10. }

  11. }

保存后,执行如下命令,重新加载配置:

  1. nginx -s reload

然后再次访问http://你的ip,一切正常的话应该可以看到如下的界面,表示我们的.NET Core程序已经完美运行在linux系统了。

以nginx方式运行

如果部署后遇到类型下面这样的错误

502网关错误

出现这样的问题,有可能的是因为SeLinux的限制,执行如下命令之后,再刷新页面:

  1. setenforce 0

selinux(security enhanced linux)安全增强型linux系统,它是一个linux内核模块,也是linux的一个安全子系统。

selinux的主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)

如果设置后还是不能解决,可以查看nginx的日志了,默认的日志路径为:/var/log/nginx

通过setenforce 0命令,只是临时实效,重启后会失效。

可以通过修改/etc/selinux/config 文件,将SELINUX=enforcing改为SELINUX=disabled,然后重启,即可永久生效。

image-20210114181544503

通过近两篇文章的介绍,我们需要更新应用,只需要将代码提交到git仓库,然后在服务器中执行git pull和dotnet publish即可。

如果熟悉shell的话,可以通过编写shell命令一键执行应用程序的更新,代码示例:

  1. # !/bin/bash

  2. cd /root/app_data/source/core50test

  3. git pull

  4. dotnet publish -/root/app_data/core50test/publish

  5. supervisorctl restart core50test

将上述的代码保存为sh文件,上传到服务器,并设置权限。如下图所示:

image-20210115155730265

代码提交到git仓库后,执行如下命令:

  1. ./build.sh

执行结果如下图所示:

shell教本部署

更新后重新运行,已经更新。

image-20210115113537048

这儿可能有的小伙伴会遇到一个小小的坑要注意,shell脚本写得没有问题,执行会报类似这样的错误

  1. $'\r':command not found

出现这种问题是因为windows下的文件换行用的是\r\n,而linux系统用的是\n,如果在win下的文档上传到linux,就有可能出现这样的问题,只需用vi打开shell脚本文件,然后使用命令:set ff=unix,保存文件即可。

shell命令 unix格式设置

supervisor一个作为守护线程,用于维护应用程序的生命周期的,nginx则是作为反向代理使用,配置shell可以做到高效部署,非常的方便。

 


本文为大家介绍使用 .NET Core部署到Linux服务器的方法,通过本文你将了解到Linux在虚拟机下的安装、Xshell,Xftp的使用方法、git在linux下的交互使用以及.net core在linux下的发布与运行全过程,本文皆在总结了一些经验与笔记在部署过程中遇到的一些问题,同时分享给大家,供大家参考,欢迎讨论交流。

操作系统可选择你比较熟悉的Linux发行版,如果你是第一次接触Linux,推荐使用CentOs,因为本文的内容都是在CentOs中进行演示的。

至于系统的安装,你可以选择云服务器,或者使用虚拟机安装。虚拟机安装CentOs的方式可以参考:一网打尽,一文讲通虚拟机安装及Linux使用

我们推荐使用XShell作为连接工具,下载地址:https://www.netsarang.com/zh/xshell-download/

Xshell是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。

Xshell可以在Windows界面下用来访问远端不同系统下的服务器,从而比较好的达到远程控制终端的目的。除此之外,其还有丰富的外观配色方案以及样式选择。

安装完成后,打开软件,点击左上角的新建回话按钮,打开新建回话属性,如下图所示:

Xshell新建回话

在【主机】中填写服务器的ip地址,相应的用户与密码设置好,然后点击【连接】按钮。连接成功的界面如下所示:

image-20210113170538768

外部与Linux服务文件交互可以使用Xftp工具上传或git仓库中转等其他方法,本文会演示使用Xftp与git仓库两种方式进行代码文件的中转。Xftp工具,下载地址:https://www.netsarang.com/zh/xftp-download/

Xftp是一个功能强大的SFTP、FTP 文件传输软件。使用了 Xftp 以后,MS Windows 用户能安全地在 UNIX/Linux 和 Windows PC 之间传输文件。

安装完成后,可以通过XShell一键打开Xftp,Xftp打开后,在软件的右侧可以切换要上传文件的目标路径,然后将文件拖到右侧释放后,就会自动上传了。

相对开发来说,使用Git仓库中转的方式是我们推荐的使用方式,在频繁的迭代更新中,先在本地编译发布后,再将文件拷贝到服务器,这个操作流程稍显繁琐。而通过git仓库来中转的方式则相对比较简单,开发者仅需要将开发好的代码推送(push)到git仓库,然后在服务器中执行build,publish等操作,减少了繁琐的拷贝文件的过程,因为build和publish都是在服务器中执行,可以通过编写shell部署脚本的方式,最终实现一键快速部署。

要使用git需要在服务器安装git客户端,并配置ssh公钥(配置公钥的目的是拉取私有的仓库,公开的仓库无需配置公钥)。

下面讲解具体的操作步骤:

首先安装git客户端,执行如下命令:

  1. yum -y install git

在安装过程如果出现错误:Couldn’t resolve host

Could not resolve host

一般是因为DNS服务器没有配置正确,解决办法:
1、打开文件/etc/resolv.conf在其中添加:

resolv.conf

2、退出保存后重启网络:

service network restart

git安装后,通过如下命令生成sshkey:

  1. # 这里的xx@xxx.com只是生成的sshkey的名称,并不约束货要求具体命名为某个邮箱。

  2. ssh-keygen -t rsa -"xx@xxx.com"

按照提示,按三次回车,即可生成sshkey,如下图所示:
生成sshkey

通过如下命令可查看公钥:

  1. cat ~/.ssh/id_rsa.pub

复制生成后的sshkey,配置到代码仓库的公钥中。

查看公钥

公钥已经生成,如何在代码托管平台进行配置呢?

接下来我们将学习如何在gitee代码托管平台下配置公钥(github类似)。

进入私有仓库的【管理】页面,找到【公钥管理】,点击【添加公钥】,将刚刚生成的公钥复制过去,如下图所示:

添加公钥

出现类似于Hi xxx的字样,则表示git公钥配置成功了。

  1. ssh -T git@gitee.com

次使用需要确认并添加主机到本机SSH可信列表,如下图所示:

添加主机到本机SSH可信列表

输入yes后,出现类似于Hi xxx的字样,则表示git公钥配置成功了。

在前面我们已经做好了部署前的准备工作,安装了xshell、xftp、git、对仓库配置了公钥等。

接下来我们将在linux服务器上安装.net core sdk。

.NET运行时是.NET程序运行的先决条件,而SDK并不是必须的,但如果通过git方式进行文件中转的话,就需要到在服务器端进行编译,所以SDK也需要安装。(注:docker部署方式无需在服务器安装SDK和运行时,在后面的文章中我们介绍

下面一起看看在CentOs中如何安装SDK和运行时(其他环境可参考官方文档:https://docs.microsoft.com/zh-cn/dotnet/core/install/linux)。

在安装 .NET 之前,我们需要将 Microsoft 包签名密钥添加到受信任密钥列表,并添加 Microsoft 包存储库。如果之前安装过.NET Core3.1 ,那么这个步骤可以省略

运行如下命令,将 Microsoft 包签名密钥添加到受信任密钥列表,并添加 Microsoft 包存储库。

  1. sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm

将 Microsoft 包签名密钥添加到受信任密钥列表

通过如下命令安装SDK:

  1. sudo yum install -y dotnet-sdk-5.0

安装dotnetsdk50

.NET Core SDK 使你可以通过 .NET Core来 开发我们的应用。

安装完成后,可以验证安装。

dotnet --info

验证net core安装

通过如下命令安装netcore运行时:

  1. sudo yum install -y aspnetcore-runtime-5.0

注:上述命令中的最后的5.0表示的是版本号,如果安装其他版本如:3.1,修改对应的版本号即可。参考资料:https://dotnet.microsoft.com/download/dotnet-core

如果已经安装了安装 .NET Core SDK,则无需安装相应的运行时,在上面我们已经安装了sdk,再安装运行时会提示已经安装,如下图所示。

aspnetcore-runtime

在前面的准备工作中我们介绍了两种将文件发布到服务器的方式,分别为:xftp与git,下面我们分别演示这两种方式的方法与步骤。

首先,准备好要发布的程序,
下图是我创建的一个.NET5.0的示例代码:

image-20210113161511112

image-20210113161527341

可以通过打开vs的程序包管理器控制台,执行如下命令进行发布:

  1. dotnet publish -./publish

也可以右键项目发布,发布到文件夹中,如下图所示。

image-20210113162327320

在这儿需要注意的是框架依赖部署模式,因为之前我们已经安装了.NET Core环境,这里就不使用独立部署模式了,默认也就是“框架依赖”。

image-20210113175714504

框架依赖部署:

依赖框架的部署 (FDD) 依赖目标系统上存在共享系统级版本的 .NET Core。 由于已存在 .NET Core,因此应用在 .NET Core 安装程序间也是可移植的。 应用仅包含其自己的代码和任何位于 .NET Core 库外的第三方依赖项。 FDD 包含可通过在命令行中使用 dotnet 实用程序启动的 .dll 文件。 例如,dotnet app.dll 就可以运行一个名为 app 的应用程序。
对于 FDD,仅部署应用程序和第三方依赖项。 不需要部署 .NET Core,因为应用将使用目标系统上存在的 .NET Core 版本。 这是定目标到 .NET Core 的 .NET Core 和 ASP.NET Core 应用程序的默认部署模型

优点:
①、不需要提前定义 .NET Core 应用将在其上运行的目标操作系统。 因为无论什么操作系统,.NET Core 的可执行文件和库都是用通用的 PE 文件格式,因此,无论什么基础操作系统,.NET Core 都可执行应用。
②、部署包很小。 只需部署应用及其依赖项,而无需部署 .NET Core 本身。
③、许多应用都可使用相同的 .NET Core 安装,从而降低了主机系统上磁盘空间和内存使用量。

缺点:
①、仅当主机系统上已安装你设为目标的 .NET Core 版本或更高版本时,应用才能运行。
②、如果不了解将来版本,.NET Core 运行时和库可能发生更改。 在极少数情况下,这可能会更改应用的行为。

独立部署:

独立部署 (SCD) 不依赖目标系统上存在的共享组件。 所有组件(包括 .NET Core 库和 .NET Core 运行时)都包含在应用程序中,并且独立于其他 .NET Core 应用程序。 SCD 包括一个可执行文件(如 Windows 平台上名为 app 的应用程序的 app.exe),它是特定于平台的 .NET Core 主机的重命名版本,还包括一个 .dll 文件(如 app.dll),而它是实际的应用程序。
对于独立部署,可以部署应用和所需的第三方依赖项以及生成应用所使用的 .NET Core 版本。 创建 SCD 不包括各种平台上的 .NET Core 本机依赖项,因此运行应用前这些依赖项必须已存在

优点:
①、可以对与应用一起部署的 .NET Core 版本具有单独的控制权
②、目标系统可以运行你的 .NET Core 应用,因为你提供的是应用将在其上运行的 .NET Core 版本

缺点:
①、由于 .NET Core 包含在部署包中,因此必须提前选择为其生成部署包的目标平台
②、部署包相对较大,因为需要将 .NET Core 和应用及其第三方依赖项包括在内。
③、向系统部署大量独立的 .NET Core 应用可能会使用大量磁盘空间,因为每个应用都会复制 .NET Core 文件

image-20210116111525878

在上图可以看到,发布之后的文件的路径为:bin/Release/net5.0/publish/

image-20210113162422379

打开Xftp,将publish文件夹拖到Xftp右侧窗口,即可完成上传。

image-20210113162958593

切换到发布的目录,启动运行,如下图所示,成功运行。

image-20210113165147617

也可以指定端口

  1. #启动站点,自定义端口号,运行环境

  2. dotnet Core50Test.dll --urls="http://*:8081;http://*:8082" --environment=Development

这里urls配置,如果需要局域网或者外网访问,不能填成urls=”http://localhost:8081;http://localhost:8082

首先,将代码推送到git仓库中,复制SSH地址。如下图所示:

image-20210113163255139

然后在服务器中,执行克隆命令:

  1. mkdir core50test

  2. cd core50test

  3. git clone git@gitee.com:******/core50test.git

执行结果如下图所示:

git克隆

此时项目代码已经下载到服务器中,切换工作目录到解决方案所在的目录。

  1. cd core50test

然后执行dotnet publish命令对程序进行编译发布。

  1. dotnet publish -/yonghu/web/publish

执行完毕后,编译发布后的文件将被保存在/yonghu/web/publish目录中。

image-20210113164049764

将工作目录切换到/yonghu/web/publish,执行如下命令:

  1. dotnet core50test.dll

执行结果如下图:

image-20210113164425166

到这里为止,咱们的程序已经在linux服务器运行起来了。

image-20210113164755688

通过上在的介绍,相信很多小伙伴已经对.netcore项目到linux的发布有了深刻的认识了,但这些操作还是略显繁琐,启动、停止、摘取等都是单独的去处理,下次文章我们将介绍通过配置使用Supervisor+Nginx,以及shell脚本来实现.net core的高效部署。

 


.NET Core部署到linux(CentOS)最全解决方案,高阶篇(Docker+Nginx 或 Jexus)

在前两篇:

.NET Core部署到linux(CentOS)最全解决方案,常规篇

.NET Core部署到linux(CentOS)最全解决方案,进阶篇(Supervisor+Nginx)

我们对.netcore部署到linux有了一个充分的了解,已经可以满足应用要求了,这篇文章我们继续深入带你了解使用Doker+jexus或Nginx来部署.net core应用。

Jexus是一款Linux平台上的高性能WEB服务器和负载均衡网关服务器,以支持ASP.NET、ASP.NET CORE、PHP为特色,同时具备反向代理、入侵检测等重要功能。可以这样说,Jexus是.NET、.NET CORE跨平台的最优秀的宿主服务器,如果我们认为它是Linux平台的IIS,这并不为过,因为,Jexus不但非常快,而且拥有IIS和其它Web服务器所不具备的高度的安全性。同时,Jexus Web Server 是完全由中国人自主开发的的国产软件,真正做到了“安全、可靠、可控”, 具备我国党政机关和重要企事业单位信息化建设所需要的关键品质。

jexus官网:https://www.jexus.org/

jexus的安装非常简单,执行如下命令:

  1. curl https://jexus.org/release/x64/install.sh|sudo sh

Jexus的安装

注:运行安装命令,需要操作者有root权限。

安装完成后,切换到/usr/jexus目录,修改/usr/jexus/siteconf目录下的default,内容如下所示:

Python技术站热门推荐:

PDF电子发票识别软件,一键识别电子发票并导入到Excel中!

10大顶级数据挖掘软件!

人工智能的十大作用!


注:因为在前面的章节用了nginx,使用了80端口,因此这儿我使用8099端口。

  1. port=8099 #端口

  2. hosts=* #域名

  3. AppHost={cmd=dotnet Core50Test.dll; root=/root/app_data/core50test/publish; port=5000}

Jexus的配置

接下来,我们重启jexus,执行如下命令:

  1. /usr/jexus/jws restart

重启jexus

提示Ok后,我们的应用就表示启动起来了。

可以通过执行如下命令,看下执行的结果:

  1. ps -aux

ps

可以看到我们的应用已经启动起来了,到浏览器使用8099端口浏览看下效果。

浏览应用

关于jexus更详细的使用说明,请参考官方文档。

Jexus包括如下操作命令(首先 cd /usr/jexus):
启动:sudo ./jws start
停止:sudo ./jws stop
重启:sudo ./jws restart

在前面的文章介绍中,不管是supervisor+nginx还是jexus,都需要在服务器安装 .NET Core的SDK或者运行时,假如咱们多个应用程序,各应用程序所用.net core版本不一样,上面的做法就需要咱们分别安装对应的SDK或者运行时,对于维护还是比较麻烦的。Docker的出现,可以完美解决上述问题。

Docker

  • docker是一个开源的软件部署解决方案;

  • docker也是轻量级的应用容器框架;

  • docker可以打包、发布、运行任何的应用。

Docker有如下优点:

1、快速,一致地交付您的应用程序

Docker 允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。

容器非常适合持续集成和持续交付(CI / CD)工作流程,请考虑以下示例方案:

  • 您的开发人员在本地编写代码,并使用 Docker 容器与同事共享他们的工作。

  • 他们使用 Docker 将其应用程序推送到测试环境中,并执行自动或手动测试。

  • 当开发人员发现错误时,他们可以在开发环境中对其进行修复,然后将其重新部署到测试环境中,以进行测试和验证。

  • 测试完成后,将修补程序推送给生产环境,就像将更新的镜像推送到生产环境一样简单。

2、响应式部署和扩展

Docker 是基于容器的平台,允许高度可移植的工作负载。Docker 容器可以在开发人员的本机上,数据中心的物理或虚拟机上,云服务上或混合环境中运行。

Docker 的可移植性和轻量级的特性,还可以使您轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。

3、在同一硬件上运行更多工作负载

Docker 轻巧快速。它为基于虚拟机管理程序的虚拟机提供了可行、经济、高效的替代方案,因此您可以利用更多的计算能力来实现业务目标。Docker 非常适合于高密度环境以及中小型部署,而您可以用更少的资源做更多的事情。

执行如下命令:

  1. sudo yum install docker

PS:

遇报错 Another app is currentlty holding the yum lock ,waiting for it to exit..

解决方法: rm –r /var/run/yum.pid 这个命令 解锁即可

docker安装1

docker安装2

安装完成后,执行如下命令设置docker开机启动:

  1. systemctl enable docker

执行如下命令启动docker:

  1. systemctl start docker

查看docker启动状态:

查看docker启动状态

ps:安装过程有问题的话,可能直接运行如命令安装。

yum install docker-ce-cli

查看docker版本命令:

查看docker版本

安装docker之后,我们需要在代码里增加dockerfile文件。

通过Visual Studio可以帮我们自动生成,在解决方案中,右击项目名称,依次选择【添加】->【Docker支持】,如下图所示:

net core docker支持

生成的dockerfile文件如下所示:

  1. #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

  2.  

  3. FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base

  4. WORKDIR /app

  5. EXPOSE 80

  6.  

  7. FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build

  8. WORKDIR /src

  9. COPY ["Core50Test.csproj", ""]

  10. RUN dotnet restore "./Core50Test.csproj"

  11. COPY . .

  12. WORKDIR "/src/."

  13. RUN dotnet build "Core50Test.csproj" -Release -/app/build

  14.  

  15. FROM build AS publish

  16. RUN dotnet publish "Core50Test.csproj" -Release -/app/publish

  17.  

  18. FROM base AS final

  19. WORKDIR /app

  20. COPY --from=publish /app/publish .

  21. ENTRYPOINT ["dotnet", "Core50Test.dll"]

将代码推送到git仓库,然后再linux服务器中拉取最新代码。

切换到/root/app_data/source/core50test目录,执行如下命令,拉取最新代码:

  1. git pull

拉取代码

然后执行如下命令,将代码打包为镜像:

  1. docker build -Dockerfile -t core50test .

首次打包镜像涉及到拉取.NET Core的官方镜像,拉取速度可能较慢,请耐心等待。

打包镜像

image-20210118173932286

打包完成后,执行如下命令,可查看当前服务器已存在的镜像:

  1. docker images

查看当前服务器已存在的镜像

镜像打包完成后,我们就可以执行docker run命令启用我们的应用了:

  1. docker run -81:80 -dit --restart=always --name core50test core50test

执行结果如下:

docker run命令启用我们的应用

通过浏览器访问:http://ip:81。如无意外,我们可以看到应用已经成功运行。

应用成功运行

docker run :创建一个新的容器并运行一个命令

  1. docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

OPTIONS说明:

  • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

  • -d: 后台运行容器,并返回容器ID;

  • -i: 以交互模式运行容器,通常与 -t 同时使用;

  • -P: 随机端口映射,容器内部端口随机映射到主机的端口

  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

  • —name=”nginx-lb”: 为容器指定一个名称;

  • —dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;

  • —dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;

  • -h “mars”: 指定容器的hostname;

  • -e username=”ritchie”: 设置环境变量;

  • —env-file=[]: 从指定文件读入环境变量;

  • —cpuset=”0-2” or —cpuset=”0,1,2”: 绑定容器到指定CPU运行;

  • -m :设置容器使用内存最大值;

  • —net=”bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;

  • —link=[]: 添加链接到另一个容器;

  • —expose=[]: 开放一个端口或一组端口;

  • —volume , -v: 绑定一个卷

可以通过编写shell脚本,实现一键更新应用。在/root目录中,创建dockerbuild.sh文件,文件内容如下:

  1. # !/bin/bash

  2.  

  3. cd /root/app_data/source/core50test

  4. git pull

  5. imtag=$(uuidgen |sed 's/-//g')

  6. docker build -Dockerfile -t core50test:${imtag} .

  7. docker stop core50test

  8. docker rm core50test

  9. docker run -dit --restart=always --name core50test -81:80 core50test:${imtag}

docker一键更新应用shell脚本

给dockerbuild.sh文件设置执行权限,命令如下:

  1. chmod 777 dockerbuild.sh

当有新代码推送到git仓库时,进入服务器,执行dockerbuild.sh即可快速更新应用程序。

./dockerbuild.sh

执行dockerbuild.sh快速更新应用程序

image-20210118175843088

至此,.net core使用docker方式部署介绍完成。

Docker常用命令,总的来说分为以下几种:

  • Docker环境信息 — docker [info|version]

  • 容器生命周期管理 — docker [create|exec|run|start|stop|restart|kill|rm|pause|unpause]

  • 容器操作运维 — docker [ps|inspect|top|attach|wait|export|port|rename|stat]

  • 容器rootfs命令 — docker [commit|cp|diff]

  • 镜像仓库 — docker [login|pull|push|search]

  • 本地镜像管理 — docker [build|images|rmi|tag|save|import|load]

  • 容器资源管理 — docker [volume|network]

  • 系统日志信息 — docker [events|history|logs]

从docker命令使用出发,梳理出如下命令结构图:

docker常用命令

要查看更详细的命令,可以查看官网或者命令帮助

  1. docker --help

通过前面三篇文章的介绍,我们已经对.net core多方案部署到linux下有了非常全面的认识,小型团队已经足够使用。留心的同学会注意到,虽然目前的方案可以实现一键部署更新,但是还是需要登陆到linux服务器去执行相应的命令。

显示,这不是最优的方案,那么还有没有更好的方案呢?比如:当我们提交给git仓库后,自动出发部署命令是不是就更方便了呢?

答案是肯定的,我们可以借助jenkins来实现。如有兴趣,可以自行研究,或者敬请期待后面的讲解。以及在大型项目中基于k8s实现的devops。其实k8s实现devops的原理以上面的介绍差不多,基于就是借助gitlab的runner或者jenkins,监听git仓库的状态,当发现指定的分支发生变化后,打包镜像,然后通过替换k8s的deployment的镜像来实现自动更新。同时,k8s实现了弹性伸缩、滚动更新等功能。

 


前言

最近在做uniapp的项目,也遇到了各种各样的渲染的问题,很多小伙伴会一头雾水,为什么渲染会这么卡顿慢?为什么明明数据量一致却远没有原生来得痛快流畅?当然有算法本身或者实现业务的问题,也有方案框架本身的问题,这里将会就跨平台方案维度进行解析。

Uniapp、RN、Flutter区别以及背景

uniapp背景

先说语言技术栈,uniapp是vue技术栈,一开始只有vue2,虽然后面支持vue3了,但是貌似框架底层的支持缺陷还是很多的,比如有些我们默认的一些vue全家桶库的支持并不好(vueX等)。

其实对于玩过微信小程序和京东Taro的人会发现,uniapp的官方文档风格其实和小程序是没有差异的,甚至于说连文件目录结构都和小程序没有差异,但底层API和组件的提供上却是小程序的子集关系(小程序支持的,uniappp不支持),而且如果你的需求只是开发小程序,vue语法和小程序语法几乎没有决定性区别的情况下是还不如用原生小程序开发,支持的API更多,书写反而更加简单。

当然再说背景,uniapp和Hbuilder有十分十分十分十分十分十分强烈(这个一定要强调)的工程绑定关系,uniapp官方几乎对于技术的依赖真的只能靠团队零散几个大神支撑,感觉大量的成本和时间在推广运营这一侧(比如各个群里貌似水军的狂热分子),uniapp的开发很多功能打包调试的过程都只能依赖Hbuilder,有点为了推广Hbuilder而忽略技术沉淀本身的感觉,当然这几年也针对uniapp进行了升级,通过一系列配置,多少也能支持cli命令打包和使用vscode进行开发了。

uniapp的优点

跨平台开发是为了解决js工程师打破原生安卓或者IOS开发者之间的开发壁垒,所以一般情况下,如果是为了快速低成本的招前端员工来进行没有复杂交互场景和大数据渲染的情况,uniapp绝对是当前跨平台方案中最快的。

另一方面就是如果你有一个项目需要同时进行小程序和移动app的迭代需求,公司人员少,uniapp也是个好选择,但问题在于对于复杂节点渲染的场景,其实技术支持力度还不如京东的Taro,技术团队也没有京东来的迅速(例如fragment渲染),即便当前已经支持了Vue3,但是由于市面uniappUI库以及官方插件都是针对vue2的开发,一旦项目升级到3,但是却不能向下兼容那些三方库了,而且3的语法层级也多很多多余封装。

然后对于一些less、scss之类的样式写法倒是非常舒服支持力度也可以。最主要的是uniapp是双引擎渲染,同时支持webView和weex渲染。

uniapp的缺点

其实在讲优点的时候顺带提到了缺点,这也是没办法的,因为为了让开发人员傻瓜化而让开发的上限降低也是没有办法的,双引擎的开发表面上是学习成本降低了,但是渲染效率也会随之下降很多很多倍,当下市场上并没有uniapp比较具有代表性的或者具有现象级别的产品,大部分都是中小企业的快速产物,换句话就是uniapp并不适合做产品,如果想要保证成果物的细粒度化操作和优化,uniapp就会是一个噩梦。

而且最要命的是uniapp的js和原生的通信问题,当前这个框架采用vue,采用云打包的方式生成apk发布使用,这个框架我并不看好,开发者可以打开布局边界查看下布局,其中完全使用网页的形式呈现给用户,基本跟android不怎么挂钩,即便挂钩,官方也已经作出了api供用户使用。虽然说完全使用网页的形式制作,但性能方面……哈哈,因为官方做出了很多网页的优化,具体性能劣势于flutter,reactNative。

react-native背景

语法是react,而且目前也支持函数组件开发了(hooks),说实话不论是语法简洁性和学习成本同过去的RN真的是质的飞跃,但js和native的通信机制开销依然很大……

团队背景是facebook团队,技术的支持专业度相比uniapp还是比较高的,和google的flutter也是旗鼓相当,并没有额外的IDE的营销成本,对于不同的IDE爱好者都很友好。

其实和uniapp比较像,因为尤雨溪的原因,所以uniapp用vue,因为facebook的原因,所以是react。只是这个团队比起营销还是会更注重技术(国内外行情毕竟不一样,要活下来吧)

react-native的优点

复杂场景的渲染颗粒度要高一点,自由度更高,同比渲染效率会比uniapp高(我想这就是react和vue框架上的差异导致的吧),相比较而言不会限制IDE,纯开发角度而言,在工程角度上RN可以做到的事情更多,很多复杂业务场景的实现上可以更加灵活。

打包效率没得说,毕竟人家可以细粒度化操作,虽然uniapp也能强行做,但相对心力损耗就大得多了。

然后市场上也有很多成熟的产品:

react-native的缺点

之前也说到过,uniapp支持小程序、app、H5,人家老外没有小程序这玩意儿,所以根本不打算去做这种事,就跨平台多端内容性肯定是没有uniapp多的,目前人家还是专注于web、安卓、ios方面的支持,另一点是样式书写的问题,虽然你可以强行在工程上采用scss、less的写法,但有一些写法是不支持的(例如sticky等),只能切换实现思路,样式的书写属于写了一个style对象,然后内联进去(就跟安卓原生的本质没有区别),但也正因为这种约束,部分样式的效率还是比uniapp高的。

但是也因为不约束你的IDE,所以前期的工程准备成本相对会高一些,再加上中国有一堵伟大的墙,安装某些工程内容的时候还是很心累的(一般出现在ios开发中)。

通信侧也会出现 JS 到 Native 之间通信开销,导致交互的流畅性受损,当然uniapp也一样。这也是为什么不论是RN,还是uniapp,大家都会吐槽交互流畅性的本质问题。

flutter的背景

语言是Dart语法,很多前端小伙伴一下子就懵逼了,背景是Google,世界顶尖科技巨头,至于为什么选择Dart的原因,人家技术官很不好意思地解释了一下:“因为当时Dart就在我们旁边,所以能够得到对应的技术反馈……”,好家伙,有的东西真的不是说为了考虑所有的方便才去开发,而是当时的资源,才有了现在的技术选择……

flutter的优点

中国市场上的hybrid混合开发基本上都会涉及到一个概念,就是JSBridge。

无论是uniapp、还是rn,工程开发的时候虽然是js,但最终还是会打包成一个原生包,也就是native,程序会通过jsbridge搭建起一个js与native之间的桥梁,js做什么操作,返回反馈给native对应的命令,当然这也解释为什么明明在浏览器端有些js语法支持,到了RN和uniapp中就不行的原因,因为不存在对应的native和js的命令映射关系呀!所以有的公司会专门请一个工程师去解决native和jsbridge的问题(例如阿里的1688就是基于weex的hybird开发)。

然后像是RN和uniapp(其实我感觉uniapp的UI是优先适配小程序组件库的……),为了能够让UI有效渲染,还是拿的原生最简单的一些View组件进行封装,然后像是一些比较复杂的UI组件还是需要工程师自己一层套一层实现,自然而然这个渲染压力就会上来,毕竟不是原生,再加上通信开销,卡就会变的很正常,所以一些大厂也会专门找人做这种底层组件保证效率。

这里就完全体现了flutter的伟大之处,这里引用别人的几句话

Flutter 是 Google 开源的 UI 工具包,帮助开发者通过一套代码库高效构建多平台精美应用,支持移动、Web、桌面和嵌入式平台,Flutter是完全免费、开源的。它也是构建未来的 Google Fuchsia 应用的主要方式。
flutter根据google推出的flutter SDK进行编写,完全颠覆了android的开发理念,须知道,android flutter都是google的, android开发使用的android SDK,flutter却不然,自制了一套自己的SDK,直接使用GPU渲染机制,在用户手机上 非常直接的 canvas draw view,其手段非常牛逼。
reactNative 的bridge(桥接)技术也是很厉害的!他通过了android 与 js之间构成了bridge,中间经过了编译,最终进行了android控件转换,这点有些像javac编译class那一块了,最终绘制在用户手机上的是原生控件。其中性能问题并不算太大,因为得到的是原生页面,所以比较受欢迎。相对比下来 rn中间那层转换编译 对于 flutter来说是没有的,相对来说flutter是最直接的,但这里我也要指出,对于目前用户手机性能来说,现在android已经到11了,中间那部分转换损耗的性能,用户基本是感知不到的。

而且也存在成熟产品:


如此一来,flutter的优势也真的很强了!

flutter的缺点

一句话,语法!成也语法败语法,先不说当下Dart语言的开发群体有多少,招工好不好招,有那时间学习flutter,我还不如直接学习android,而且复杂交互里一层套一层的写法真当是把人恶心坏了,这边举个例子:

HTML写法

<div class="greybox">  
  <div class=redbox>  
    smaple text  
  </div>  
</div>  
 
.greybox {  
  display: flex;  
  align-items: center;  
  justify-content: center;  
  background-color: #e0e0e0; /* grey 300 */  
  width: 320px;  
  height: 240px;  
  font: 18px  
}  
.redbox {  
  background-color: #ef5350; /* red 400 */  
  padding: 16px;  
  color: #ffffff  
}

Flutter写法

var container = new Container( // grey box  
  child: new Center(  
    child: new Container( // red box  
      child: new Text(  
        "smaple text",  
        style: new TextStyle(  
          color: Colors.white,  
          fontSize: 18.0,  
        ),  
      ),  
      decoration: new BoxDecoration(  
        color: Colors.red[400],  
      ),  
      padding: new EdgeInsets.all(16.0),  
    ),  
  ),  
  width: 320.0,  
  height: 240.0,  
  color: Colors.grey[300],  
);

看官明白了吧?这么开发工程,这学习成本和开发当真是还不如原生开发吧?

而且不支持热更新真的难受,就算使用了三方也会造成性能损耗……

-----------------

这里修改一下,flutter支持热更新啦!!感觉热更新还不错!(记录于2022年9月27日)

三者总对比

移动端生态而言

原生 > RN > Uniapp >Flutter

学习成本

原生 > Flutter > RN > Uniapp(但其实随着hooks的入场,RN的学习成本和Uniapp差距不大了)

渲染效率

原生 > Flutter > RN > Uniapp