• 关于.net6项目发布到docker(nginx)踩到的一些坑


    开发环境:桌面云系统(无法使用docker desktop),win10系统

    后端开发工具:vs2022   数据库:mysql     缓存:redis    队列和事件处理:rabbitmq   

    前端开发工具:visual studio code    框架:vue

    发布步骤

    一、发布接口端.NET6 项目

      1.  由于不能运行docker desktop,所以发布的时候只能发布到文件夹,然后手动发布到docker,发布界面如下,注意下图红框选中处,这就是我踩的第一个坑,发布时我想着是发布到liunx系统,所以选择的是liunx-64,发布后才发现运行不了,报错内容为:

    System.InvalidOperationException: Unable to resolve service for type '***.***.***' while attempting to activate '***.***.***'
    错误意思就是加载dll文件失败,后面将目标运行时改为 可移植 然后重新发布,更新后,重新运行dcoker(docker restart 容器Id),问题解决

      2. dockerfile文件编写,dockerfile文件可以由系统自动生成,但是手动发布需要修改系统生成的dockerfile文件,因为手动发布已经生成了dll文件,不需要调用build命令再次生成

       下面是系统生成的dockerfile,包括了复制项目文件到对应文件夹和build生成dll文件

    #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
    
    FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    
    FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
    WORKDIR /src
    COPY ["WebApi/Web/Web.csproj", "WebApi/Web/"]
    COPY ["WebApi/AdminApi/AdminApi.csproj", "WebApi/AdminApi/"]
    
    RUN dotnet restore "WebApi/Web/Web.csproj"
    COPY . .
    WORKDIR "/src/WebApi/Web"
    RUN dotnet build "Web.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "Web.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "Web.dll"]

      下面是我修改后的dockerfile文件,内容简洁很多,只保留了程序入口以及运行端口指定

    #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
    
    FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    
    COPY fonts/ /usr/share/fonts/
    
    ENTRYPOINT ["dotnet", "Web.dll"]

      3. 将文件上传至centos系统,可用的工具有很多,我这边使用的工具是FinalShell,该工具支持界面操作,比其它工具操作要简单一些,比如修改配置文件可以在本地打开,然后直接修改保存,不需要在命令行里面云操作,同时也可以直接拖动文件到指定目录

      4. 创建镜像文件,文件上传后,进行文件所在目录,cd  文件目录 。然后使用命令 docker build -t 镜像名称:版本号   创建镜像文件

      5. 启动运行容器 docker run --name=容器名称 -p 8001:80 -d 镜像名称:版本号   其中8001是系统的端口号,80是容器的端口号,如果要打开就是系统的 IP:8001

      6. 如果容器启动成功,可以使用docker ps查看运行中的容器,这时使用 服务器IP:端口号 及可访问系统,系统部署完成

      7. 踩到的坑

        坑一:上面已经说了,发布时选择目标运行时的问题,我这里改成可移植即可运行

        坑二:swagger运行不了,linux系统目录的问题导致swagger运行不了,根据错误信息查了一下是因为路径的问题,加载xml文件失败,导致swagger运行失败,liunx系统里面的路径要注意两点,1) 目录的分隔符与windows不一致,建议拼接路径是使用Path.DirectorySeparatorChar来获取分隔符,这样就不需要判断运行环境了,我这里swagger运行不了就是因为使用windows里面的目录分隔符。 2)获取当前目录,建议使用Directory.GetCurrentDirectory(),不要使用AppContext.BaseDirectory,这个方法在开发环境中获取到的是.dll文件所有目录

        坑三:ZKWeb.System.Drawing组件的使用,在liunx里面使用该 组件需要另外安装该组件,关键是我安装了也解决不了问题,解决方案见另外一篇博文https://www.cnblogs.com/ithome8/p/16423027.html,这里不再说明。

        坑四:rabbitmq的使用,当然这个和发布没有多大关系,是因为发布的站点和本地站点 使用同一个rabbitmq服务器时会报错,冲突了,访问同一队列,不使用同一个服务器就OK了。

    二、发布前端VUE项目

      1. 进入CMD模式,并且进入项目的根目录 ,使用npm run build进行项目打包,也可以使用VSCode,在终端下面输入npm run build来进行打包,命令执行后文件会打包到vue.config.js文件中配置的outputdir指定的目录下面。

      2. 编写nginx config配置文件,内容如下,在项目发布的目录下面创建nginx目录,将该文件保存到该 目录并且命名为default.conf

    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost ***.***.***.***;
    
    
        # 测试vue history 模式下发布问题
        # 方式一 一般选用方式二就可以
        location / {
           root   /usr/share/nginx/html;
           index  index.html index.htm;
           client_max_body_size 200m;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
               break;
           }
            error_page  404     /404.html;        
            # To allow POST on static pages
            error_page  405     =200 $uri;
        }
        # 此外,如果VUE应用没有发布在域名的目录根下,比如[http://xxx.com/wx/]
        # 那么除了上述配置:
        #location /wx{
            # root   /data/nginx/html; # 在linux下部署一般都是将路径配置完全
            #root   html;
            #index  index.html index.htm;
            #error_page 404 /wx/index.html;
            #if (!-e $request_filename) {
                #rewrite ^/(.*) /wx/index.html last;
                #break;
            #}
        #}
    
        # 方式二
        #location / {
             #try_files $uri $uri/ /index.html;
        #}
            # 配置反响代理接口的反响代理,这里是反向代理的接口配置,不然会访问不了接口
        location ~ /admin/  {
            proxy_set_header Host $http_host;                 
            proxy_set_header X-Real-Ip $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            #//利用正则进行匹配#去掉api前缀,$1是正则中的第一串,这样后端的接口也不需要带api了
            rewrite  ^/(.*)$ /$1 break;  
            #**//api前面的部分将被替换成localserver的地址**
            proxy_pass http://172.16.19.155:8030;   
        }
              # 配置反响代理接口的反响代理
        location ~ /WebApi/  {
            proxy_set_header Host $http_host;                 
            proxy_set_header X-Real-Ip $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            #//利用正则进行匹配#去掉api前缀,$1是正则中的第一串,这样后端的接口也不需要带api了
            rewrite  ^/(.*)$ /$1 break;  
            #**//api前面的部分将被替换成localserver的地址**
            proxy_pass http://172.16.19.155:8030;   
        }  
        #access_log  /var/log/nginx/host.access.log  main;
    
    }

      3. 编写dockerfile文件,内容如下 ,也可以直接将文件上传到指定目录,后面的COPY命令就可以不用了

    # 设置基础镜像
    FROM nginx
    # 将dist文件中的内容复制到 ./html/ 这个目录下面
    COPY dist/  ./html/
    # 用本地的 default.conf 配置来替换nginx镜像里的默认配置
    COPY nginx/default.conf ./conf.d/default.conf

      4. 创建镜像文件,文件上传后,进行文件所在目录,cd  文件目录 。然后使用命令 docker build -t 镜像名称:版本号   创建镜像文件

      5. 启动运行容器 docker run --name=容器名称 -p 8002:80 -d 镜像名称:版本号   其中8001是系统的端口号,80是容器的端口号,如果要打开就是系统的 IP:8002

      6. 至此VUE项目发布就完成了,下面说一下踩的坑

        坑一:发布后打开网站是一片空白,只有两个JS报错,通过查询知道了是什么原因,是配置文件vue.config.js里面没有指定publicPath,导致vue找不到目录,加上即可,代码如下

    const urlConfig = require('./src/config/url') // 引入服务器路径配置
    
    const path = require('path')
    const resolve = (dir) => path.join(__dirname, dir)
    module.exports = {
      // 部署应用包时的基本 URL
      publicPath: process.env.NODE_ENV === 'production' ? '/admin' : '/',
      // 当运行 vue-cli-service build 时生成的生产环境构建文件的目录
      outputDir: '../../publish/dist',
      // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
      assetsDir: 'static',
      publicPath: './',

        坑二:接口调用报跨域错误,获取不到数据,在本地开发正常,是因为开发环境是使用的proxy做了代理转发,所以可以正常访问,下面这段代码会进行转发,所以在开发环境可以正常访问不会跨域    

      devServer: {
        open: false,
        host: '0.0.0.0',
        port: 8031,
        https: false,
        hotOnly: false,
        proxy: {
          '/admin': {
            target: urlConfig.proxyURL,
            ws: false,
            secure: false,
            changeOrigin: true
          }
        },
        before: () => {
    
        }
      }

        解决方案,代码里面接口的访问地址仍然使用项目的访问地址,在nginx里面做配置,进行反向代理,跳转到接口的地址,配置代码如下 

       # 配置反响代理接口的反响代理,这里是反向代理的接口配置,不然会访问不了接口
        location ~ /admin/  {
            proxy_set_header Host $http_host;                 
            proxy_set_header X-Real-Ip $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            #//利用正则进行匹配#去掉api前缀,$1是正则中的第一串,这样后端的接口也不需要带api了
            rewrite  ^/(.*)$ /$1 break;  
            #**//api前面的部分将被替换成localserver的地址**
            proxy_pass http://***.***.***.***:8001;   
        }

    在此记录一下,以免后面还遇到这些问题。。。

  • 相关阅读:
    Codeforces 570E
    Codeforces 570D
    Codeforces 1136E
    Codeforces 570
    小白学习sprint boot容易遇到了一些问题
    力扣 234. 回文链表
    力扣198. 打家劫舍
    力扣543. 二叉树的直径
    力扣141.环形链表
    剑指offer1.跳台阶 & 力扣70.爬楼梯
  • 原文地址:https://www.cnblogs.com/ithome8/p/16424143.html
Copyright © 2020-2023  润新知