前言
通过一个星期的踩坑,终于。终于。终于。将项目部署成功!
接下来分享一些实际项目中遇到的坑。也算是自己的工作积累吧。
注意:Linux 中路径是严格区分大小写的哦,多检查一下项目的文件路径
先提前在Linux 服务器上先把net core 的依赖,docker 和 nginx 都装好
项目
工作需求是将一个多站点项目部署到docker
单站点发布倒是简单,多站点这可咋整?DockerFile放在哪儿?应该一个站点一个站点发还是一起发?静态文件和配置文件又该怎么处理?等等。。。。。。。
接下来开始第一步
先测试站点是否能够在本地跑起来(所有站点,如果有站点跑不起来现在本地检查,保证每个站点能够单独自依赖运行)
最重要的一点:项目中绝对不能出现绝对地址,例如 D:/微信文件/WeChat Files/All Users 只能用相对路径 ../WeChat Files/All Users
所有站点都能运行了,在本地运行一下,发现还是不行,因为站点与站点之间存在互相依赖关系,所以打开地址之后发现是404
后面检查发现,项目中的请求都是以 站点/控制器/页面 这种方式请求的,因为站点与站点之间存在互相依赖关系,站点信息已经明确了,所以在请求中多加了一个站点所以请求地址不对了
该怎么解决呢?改项目中的代码的话,工作量会不会太大了,而且你也不知道那些东西改了会不会出一些不可预料的错误
来说说解决办法吧
中间件中将 pattern 将路由处理一下,这样再有请求进来,所有的请求地址将会被路由处理:例如 :/BasicApplication/Retrieval/index 将会变成 /Retrieval/index
/// <summary> /// 添加Endpoint并Area路由支持 /// </summary> public static IEndpointRouteBuilder MapControllersWithAreaRoute(this IEndpointRouteBuilder endpoints, bool area = true) { if (area) { endpoints.MapControllerRoute( name: "area-route", //areaName:"area", pattern: "{site:}/{area:exists}/{controller=Home}/{action=Index}/{id?}" ); endpoints.MapControllerRoute( name: "viewName", pattern: "{site:}/{area:exists}/{controller}/{*viewName}", defaults: new { action = "DisplayAnyView" } ); } endpoints.MapControllerRoute( name: "default", pattern: "{site:}/{controller=Home}/{action=Index}/{id?}" ); endpoints.MapControllerRoute( name: "viewName", pattern: "{site:}/{controller}/{*viewName}", defaults: new { action = "DisplayAnyView" } ); return endpoints; }
本地的地址的问题解决了,接下来再启动就发现问题解决啦
接下来把发布文件拷贝到 linux 服务器上(文件中有站点发布文件,静态文件和配置文件)
拷贝过去之后在用命令运行一下单站点(window上能跑,linux上一般都能跑,注意多检查静态文件的路径)
站点没问题之后就可以将文件打包成镜像了,这里是打包到docker
应该一个站点一个站点发还是一起发?这肯定是要一个站点一个站点的发的。
需要在每个站点下新增DockerFile(我这里使用的是centOS 8 数据库链接上需要处理一下协议问题)为了防止出现这个错误 provider: TCP Provider, error: 35 - An internal exception was caught
在.NET Core/.NET 5的容器镜像中的OpenSSL的最低协议版本要求为TLSv1.2,而我们的MS SQL Server所用的版本较低,不支持TLSv1.2只支持TLSv1。
可参考 https://blog.csdn.net/farway000/article/details/124441124 或者在 dockerfile中 加上 这一句 RUN sed -i 's/TLSv1.2/TLSv1/g' /etc/ssl/openssl.cnf
我先例出一个站点的示例,其他站点类似
dockerfile 示例
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app/Basicapplication EXPOSE 80 COPY . . ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN sed -i 's/TLSv1.2/TLSv1/g' /etc/ssl/openssl.cnf ENV ASPNETCORE_URLS=http://+:80 ENTRYPOINT ["dotnet", "BasicApplication.dll","--server.urls","http://*:80"]
每个站点一个dockerfile ,因为要把每个站点部署在不同的容器中
建议不要将多余文件也build到镜像,包括静态文件,配置文件。(建议建立一个镜像,检查一下是否创建成功,避免重复创建后面花时间一个一个删)
创建镜像:docker build -f /home/zhangweifeng/公共/linux/BasicApplication/Dockerfile -t basic:v1 . (镜像image 不能用大写名称命名否则会报错)
将所有镜像创建好(再次确认你的镜像是能运行的,不然放进容器会报错,而且容器也起不来)
镜像建立好之后,还不能忘了还有静态文件和配置文件需要挂载到容器里。不然容器启动时会提示文件路径找不到。
怎么挂载静态文件呢?可参考 https://www.tnblog.net/aojiancc2/article/details/7723
下边直接上代码:
docker run -v /home/zhangweifeng/公共/linux/WebResource:/app/WebResource/ -v /home/zhangweifeng/公共/linux/ExcelTemplate:/app/ExcelTemplate/ -v /home/zhangweifeng/公共/linux/TempFolder:/app/TempFolder/ -v /home/zhangweifeng/公共/linux/share:/app/share/ -v /home/zhangweifeng/公共/linux/NKConfig.json:/app/NKConfig.json -v /home/zhangweifeng/公共/linux/nlog.config:/app/nlog.config -v /home/zhangweifeng/公共/linux/web.config:/app/web.config -v /home/zhangweifeng/公共/linux/WW_verify_k2C7T5PiccuF4fiZ.txt:/app/WW_verify_k2C7T5PiccuF4fiZ.txt -p 9001:80 basic:v1
-p 9001:80 代表的就是 将容器内80端口 映射到宿主机的9001 端口。访问本机9001端口就等于访问到容器内的80端口
每个容器指定的端口不能重复,这里我有5个站点,配了5个端口分别为 9001,9002,9003,9004,9005,9006(后边需要做nginx代理的)
目录挂载上之后,运行还是行的话,还得检查一下容器内的路径映射的对不对了,容器内以项目文件为准,静态文件该放上级放上级,该放同级放同级。
把每个容器都跑起来
跑起来之后发现,每个项目都是独立的,他们之间的互相引用应该怎么处理呢。
这时候就需要用到 nginx 了。
查看nginx所在目录
which nginx
启动 nginx
转到nginx所在目录 -> ./nginx
修改nginx 配置文件
要编辑nginx文件得用命令,因为它是只读的
新增如下端口配置
输入 i 进入编辑模式
按住 shift + : 退出编辑模式
输入 wq! 保存并退出
每个不同的请求标识转发到不同的端口,这个就需要根据自己的项目配置了。nginx配置比较简单,保存完成之后
重新加载nginx配置文件
nginx -s reload
我这里是用8011 端口代理的,在服务器访问发现没问题,但是我在自己电脑上发现访问不到8011,但是访问 9001 又是可以的
这也是一个小坑,因为服务器没有开放8011 端口,所以需要将8011端口开放,才能在自己电脑上访问到
开放端口命令:/sbin/iptables -I INPUT -p tcp --dport 8011 -j ACCEPT
查看防火墙所有开放的端口
firewall-cmd --zone=public --list-ports
开放端口
firewall-cmd --zone=public --add-port=8092/tcp --permanent
关闭端口
firewall-cmd --zone=public --remove-port=5672/tcp --permanent
配置立即生效
firewall-cmd --reload