构建 dotnet&vue 应用镜像->推送到 Nexus 仓库->部署为 k8s 服务实践 ...

打印 上一主题 下一主题

主题 823|帖子 823|积分 2469

前言

前面分享了 k8s 的部署安装,本篇来点实操,将会把一个 .net core + vue 的项目(zhontai),打包构建成 docker 镜像,推送到 nexus 镜像仓库,并部署到 k8s 中
准备

要实现项目的部署,除了准备要部署的环境(k8s),还需要准备项目所用到的各中间件,本文旨在分享部署的一个整体流程,对项目中所使用到的各中间件(mysql,redis 等)的安装使用可自行在本DevOps 系列文章中找到


  • 一个 .net core+vue 的项目

  • Nexus 的安装部署,文章介绍

    • 做为镜像仓库使用,将项目打包镜像及项目镜像推送到仓库,k8s 也从此仓库拉取镜像
    • 版本为 v3.61 ,安装地址为 192.168.0.214:8081,并使用局域网域名解析,
    • 在目标机器先登录能够拉取推送镜像,参考
    • 拉取镜像地址:https://nexus.devops.test.com
    • 推送镜像地址:https://push.nexus.devops.test.com


  • Docker 的安装部署,文章介绍

    • 使用 doker 拉取 sdk、nodejs 镜像进行打包,构建 k8s 所需要的项目镜像
    • 版本:v24.0.6


  • K8S 的安装与部署,文章介绍

    • 部署项目服务
    • 使用 ingress 解析域名到服务

  • 部署前后端项目到 K8S,本文介绍
使用 Docker 打包应用镜像

不管什么语言,基本都可以使用这个打包流程,将官方镜像打包推送到私有镜像仓库个人认为是必要的,不然如果一旦远端的镜像失效,又需要重新拉取镜像时就会很尬尴。

  • 准备打包所需镜像

    • 获取基础打包镜像(dotnet 获取 sdk 镜像,vue 获取 node 镜像)
    • 基于基础镜像,安装所需软件,设置默认配置,复制默认文件,封装项目的打包镜像
    • 挂载项目到 sdk 镜像进行打包,打包后获取构建完成的产物

  • 准备运行所需的基础镜像

    • 获取运行时镜像(.net core 获取 runtime 镜像,vue 获取 nginx 镜像)
    • 基于运行时镜像,将打包构建完从的产物添加到镜像,构建项目镜像
    • 推送项目镜像到仓库

.Net Core 7.0 项目镜像

构建所需一个 sdk 镜像用于打包编译项目,一个 runtime 镜像运行 .net core 项目,版本选择对应的 7.0 即可
构建 dotnet sdk 7.0 打包镜像


  • 拉取 dotnet sdk 镜像: docker pull  mcr.microsoft.com/dotnet/sdk:7.0

    • 目前可以直接拉取,若无法拉取则配置国内镜像源
    • 临时运行容器进行测试: docker run -it --rm  mcr.microsoft.com/dotnet/sdk:7.0,可以将需要的东西进行安装测试再编写 dockerfile


  • 使用 Dockerfile 构建打包镜像 dotnet-sdk-7.0

    • 为了便于后期维护,使用 Dockerfile 来构建
    • 目录文件:dotnet-sdk-7.0/Dockerfile
    • 基于 sdk 安装 dotnet-monitor v7.3.2, 文档 这里只做演示,暂时没用上,后续使用多阶段构建的时候可以将其复制到运行时镜像中
      1. # 基础sdk镜像 v7.0   
      2. FROM mcr.microsoft.com/dotnet/sdk:7.0
      3. # 将tools目录加入环境变量
      4. ENV PATH="$PATH:/root/.dotnet/tools"
      5. # 安装 dotnet-monitor
      6. RUN dotnet tool install -g dotnet-monitor --version 7.3.2
      复制代码
    • 执行构建:docker build -t dotnet-sdk-7.0 -f ./Dockerfile .


  • 推送镜像到 Nexus 仓库

    • 镜像登录认证:docker login  push.nexus.devops.test.com  -u pusher -p devops666
    • 打标签: docker tag dotnet-sdk-7.0  push.nexus.devops.test.com/projectbuild/dotnet-sdk-7.0
    • 推送镜像: docker push  push.nexus.devops.test.com/projectbuild/dotnet-sdk-7.0
    • 记得清理本地缓存镜像: docker rmi  dotnet-sdk-7.0  && docker rmi  push.nexus.devops.test.com/projectbuild/dotnet-sdk-7.0


  • 使用镜像

    • 后续使用 dotnet sdk 7.0 就可以直接使用 nexus.devops.test.com/projectbuild/dotnet-sdk-7.0 即可
    • 直接拉取: docker pull  nexus.devops.test.com/projectbuild/dotnet-sdk-7.0


构建 dotnet runtime 7.0 运行时镜像


  • 拉取 dotnet runtime 镜像: docker pull  mcr.microsoft.com/dotnet/runtime:7.0

    • 临时运行容器进行测试: docker run -it --rm  mcr.microsoft.com/dotnet/runtime:7.0

  • 使用 Dockerfile 构建运行时镜像

    • 为了便于后期维护,使用 Dockerfile 来构建
    • 目录文件:dotnet-runtime-7.0/Dockerfile
    • 若非需要,可以不安装软件,安装软件后镜像会多个 100M
      1. # 基础runtime镜像 v7.0   
      2. FROM mcr.microsoft.com/dotnet/aspnet:7.0
      3. # 写入阿里云镜像源
      4. RUN echo " \
      5. deb http://mirrors.aliyun.com/debian/ bullseye main contrib non-free\n \
      6. deb-src http://mirrors.aliyun.com/debian/ bullseye main contrib non-free\n \
      7. \n \
      8. deb http://mirrors.aliyun.com/debian-security bullseye-security main contrib non-free\n \
      9. deb-src http://mirrors.aliyun.com/debian-security bullseye-security main contrib non-free\n \
      10. \n \
      11. deb http://mirrors.aliyun.com/debian/ bullseye-updates main contrib non-free\n \
      12. deb-src http://mirrors.aliyun.com/debian/ bullseye-updates main contrib non-free\n \
      13. \n \
      14. deb http://mirrors.aliyun.com/debian/ bullseye-backports main contrib non-free\n \
      15. deb-src http://mirrors.aliyun.com/debian/ bullseye-backports main contrib non-free\n \
      16. " | tee /etc/apt/sources.list
      17. # 安装 curl&&vim
      18. RUN apt-get update -y && apt-get install -y curl && apt-get install -y vim
      复制代码
    • 执行构建:docker build -t dotnet-runtime-7.0 -f ./Dockerfile .


  • 推送镜像到 Nexus 仓库

    • 镜像登录认证:docker login  push.nexus.devops.test.com  -u pusher -p devops666
    • 打标签:docker tag dotnet-runtime -7.0 push.nexus.devops.test.com/projectbuild/dotnet-runtime-7.0
    • 推送镜像: docker push  push.nexus.devops.test.com/projectbuild/dotnet-runtime-7.0
    • 记得清理本地缓存镜像: docker rmi  dotnet-runtime-7.0  && docker rmi  push.nexus.devops.test.com/projectbuild/dotnet-runtime-7.0



  • 使用镜像

    • 后续使用 dotnet runtime 7.0 就可以直接使用 nexus.devops.test.com/projectbuild/dotnet-runtime-7.0 即可
    • 直接拉取: docker pull  nexus.devops.test.com/projectbuild/dotnet-runtime-7.0

构建 zhontai 后端项目的应用镜像

制作完镜像,下面将使用 sdk 镜像打包项目生成部署文件,再使用 runtime 镜像部署运行。

  • 下载/克隆项目 admin.core 到服务器,进入项目目录开始执行

      1. # 克隆项目
      2. git clone https://github.com/zhontai/Admin.Core.git -b v3.7.0
      3. # 进入项目 cd Admin.Core
      4. cd Admin.Core
      复制代码
    • src 为.net core 项目代码

  • 使用 sdk 镜像进行打包,生成部署文件到 publish_output

    • docker run -i --rm 创建一个临时容器,容器退出后自动删除容器
    • -v ./build:/build 挂载 MSBuild 属性文件目录(./src/Directory.Build.props 中使用)
    • -v ./src:/src 挂载源码到容器中
    • -v ./publish_output:/publish_output挂载构建物输出目录
    • --name build_zhontai_api 指定运行的容器名称
    • nexus.devops.test.com/projectbuild/dotnet-sdk-7.0 sdk 镜像
    • /bin/bash -c "xxx"以交互模式运行容器,运行时执行命令
    • 若有自定义 nuget 仓库的包还需挂载 /root/.nuget 目录,或直接制作在镜像中
    • 记得挂载 build 目录,否则会提示:Invalid framework identifier
      1. docker run -i --rm \
      2. -v ./build:/build \
      3. -v ./src:/src \
      4. -v ./publish_output:/publish_output \
      5. --name build_zhontai_api \
      6. nexus.devops.test.com/projectbuild/dotnet-sdk-7.0 \
      7. /bin/bash -c 'dotnet publish /src/hosts/ZhonTai.Host -c Release -o /publish_output --runtime linux-x64 --framework net7.0'
      复制代码
    • 执行成功后程序包就生成到 publish_output 中了


  • 使用 runtime 镜像制作应用镜像

    • 将上一步的构建物 Admin.Core/publish_output 添加到运行时镜像中
    • 使用 echo 创建一个 Dockerfile
      1. #创建Dockerfile
      2. echo 'FROM nexus.devops.test.com/projectbuild/dotnet-runtime-7.0 AS runtime
      3. WORKDIR /app
      4. COPY ./publish_output /app
      5. ENV ASPNETCORE_URLS=http://+:8000
      6. ENTRYPOINT ["dotnet", "ZhonTai.Host.dll"]' > Dockerfile
      复制代码
    • 执行构建:docker build -t zhontai_api .

    • 运行测试,成功


  • 推送镜像到仓库

      1. #打标签
      2. docker tag zhontai_api push.nexus.devops.test.com/projectapp/zhontai_api
      3. #推送
      4. docker push push.nexus.devops.test.com/projectapp/zhontai_api
      复制代码
    • 推送成功,这里手动只构建的 latest 版本,若使用自动化构建,还需构建对应版本的镜像,以支持快速回滚


Vue 3 项目打包

构建所需一个 node 镜像用于 vue 项目打包,nginx 用于部署前台项目
构建 nodejs 18.17.1 打包镜像


  • 拉取 nodejs 镜像:docker pull node:18.17.1
  • 将 node 镜像 vue-node-18 打上标签推送到仓库

      1. #拉取仓库
      2. docker pull node:18.17.1
      3. # 打标签
      4. docker tag node:18.17.1 push.nexus.devops.test.com/projectbuild/vue-node-18.17
      5. #推送
      6. docker push push.nexus.devops.test.com/projectbuild/vue-node-18.17
      复制代码
    • 测试使用: docker run -it --rm  nexus.devops.test.com/projectbuild/vue-node-18.17 /bin/bash -c "node -v"



构建 nginx 1.24 运行时镜像


  • 拉取 nginx 镜像:docker pull nginx:1.24
  • 将 nginx 镜像 vue-nginx-1.24 打上标签推送到仓库

      1. #拉取仓库
      2. docker pull nginx:1.24
      3. # 打标签
      4. docker tag nginx:1.24 push.nexus.devops.test.com/projectbuild/vue-nginx-1.24
      5. #推送
      6. docker push push.nexus.devops.test.com/projectbuild/vue-nginx-1.24
      复制代码
    • 测试使用: docker run -it --rm  nexus.devops.test.com/projectbuild/vue-nginx-1.24 /bin/bash进入容器后启用 nginx,并使用 curl http://localhost 测试 nginx 可用



构建 zhontai 前端项目的应用镜像


  • 下载/克隆项目 admin.ui.plus 到文件夹

      1. # 克隆项目
      2. git clone https://github.com/zhontai/admin.ui.plus.git -b v2.2.0
      3. # 进入项目cd admin.ui.plus
      4. cd admin.ui.plus
      5. # 修改接口地址
      6. # 编辑.env.production 中的 VITE_API_URL 配置为接口地址
      复制代码

  • 使用 node 镜像进行打包,生成文件到 dist

      1. docker run -i --rm \
      2. -v ./:/app \
      3. --name build_zhontai_webui \
      4. nexus.devops.test.com/projectbuild/vue-node-18.17 \
      5. /bin/bash -c 'cd /app
      6. npm config set registry https://registry.npmmirror.com
      7. npm install
      8. npm run build'
      复制代码
    • 执行成功,构建输出到 dist 中


  • 使用 nginx 镜像制作应用镜像

      1. # 创建nginx.conf
      2. echo '
      3. server {
      4.     listen       80;
      5.     server_name  localhost;
      6.     charset utf-8;
      7.     location / {
      8.         root   /usr/share/nginx/html;
      9.         try_files $uri $uri/ /index.html;
      10.         index  index.html index.htm;
      11.     }
      12.     #error_page  404              /404.html;
      13.     error_page   500 502 503 504  /50x.html;
      14.     location = /50x.html {
      15.         root   html;
      16.     }
      17. }
      18. '> vue-nginx.conf
      19. #创建Dockerfile
      20. echo '
      21. FROM nexus.devops.test.com/projectbuild/vue-nginx-1.24
      22. EXPOSE 80
      23. COPY ./dist /usr/share/nginx/html
      24. COPY ./vue-nginx.conf /etc/nginx/conf.d/default.conf' > Dockerfile
      复制代码
    • 执行构建:docker build -t zhontai_webui .
    • 测试访问成功


  • 推送镜像到仓库
  1. #打标签
  2. docker tag zhontai_webui push.nexus.devops.test.com/projectapp/zhontai_webui
  3. #推送
  4. docker push push.nexus.devops.test.com/projectapp/zhontai_webui
复制代码
将 Docker 应用镜像部署到 K8S

应用镜像打包成功,现在需要将两个应用精选镜像部署到 k8s 中
应用镜像的拉取凭证设置

因为 nexus 部署在局域网,并且配置的域名是局域网域名,所以面临着如何在 k8s 中访问 https://nexus.devops.test.com 获取镜像的问题,目前我的解决方法时每个节点机器都配置好对应 dns
要想访问到 nexus 仓库,需要满足两个条件,一个是访问到仓库,一个是仓库的认证

  • 给 k8s 所有节点添加 dns 设置nameserver 192.168.123.214


    • 使用 docker login  nexus.devops.test.com  -u puller -p devops666 在宿主机中登录仓库确保可以在节点拉取镜像

  • 创建 nexus 登录凭证

      1. kubectl create secret \
      2. docker-registry \
      3. nexus-login-registry \
      4. --docker-server=nexus.devops.test.com \
      5. --docker-username=puller \
      6. --docker-password=devops666 \
      7. -n default
      复制代码


使用 Deployment 部署应用

配置仅供参考,关于数据库,配置文件,日志,上传文件等未处理

  • 创建后端部署配置:zhontai_api.yaml

      1. ---
      2. ## 配置服务
      3. kind: Service
      4. apiVersion: v1
      5. metadata:
      6.   name: app-zhontai-api
      7.   namespace: default
      8.   labels:
      9.     app: app-zhontai-api
      10. spec:
      11.   selector:
      12.     app: app-zhontai-api
      13.   type: ClusterIP
      14.   ports:
      15.     - name: p80
      16.       port: 80
      17.       targetPort: 8000
      18. ---
      19. kind: Deployment # 指定创建资源的角色/类型
      20. apiVersion: apps/v1 # 指定api版本,此值必须在kubectl api-versions中
      21. metadata: # 资源的元数据/属性
      22.   name: app-zhontai-api # 资源的名字,在同一个namespace中必须唯一
      23.   namespace: default # 部署在哪个namespace中
      24.   labels: # 设定资源的标签
      25.     app: app-zhontai-api
      26. spec: # 资源规范字段  
      27.   selector:
      28.     matchLabels:
      29.       app: app-zhontai-api
      30.   replicas: 2 # 声明副本数目
      31.   revisionHistoryLimit: 2 # 保留历史版本
      32.   strategy: # 策略
      33.     rollingUpdate: # 滚动更新
      34.       maxSurge: 1 # 最大额外可以存在的副本数,可以为百分比,也可以为整数
      35.       maxUnavailable: 1 # 示在更新过程中能够进入不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
      36.     type: RollingUpdate # 滚动更新策略
      37.   template: # 模版
      38.     metadata: # 资源的元数据/属性
      39.       labels: # 设定资源的标签
      40.         app: app-zhontai-api
      41.     spec: # 资源规范字段
      42.       containers:
      43.         - image: nexus.devops.test.com/projectapp/zhontai_api:latest # 容器使用的镜像地址
      44.           name: app-zhontai-api # 容器的名字
      45.           # 每次Pod启动拉取镜像策略,三个选择 Always、Never、IfNotPresent
      46.           # Always,每次都检查;Never,每次都不检查(不管本地是否有);IfNotPresent,如果本地有就不检查,如果没有就拉取
      47.           imagePullPolicy: Always
      48.           resources: # 资源管理
      49.             # limits: # 最大使用
      50.             #   cpu: 300m # CPU,1核心 = 1000m
      51.             #   memory: 500Mi # 内存,1G = 1024Mi
      52.             # requests: # 容器运行时,最低资源需求,也就是说最少需要多少资源容器才能正常运行
      53.             #   cpu: 100m
      54.             #   memory: 100Mi
      55.           livenessProbe: # pod 内部健康检查的设置
      56.             httpGet: # 通过httpget检查健康,返回200-399之间,则认为容器正常
      57.               path: /admin/health # URI地址
      58.               port: 8000 # 端口
      59.               scheme: HTTP # 协议
      60.             initialDelaySeconds: 10 # 表明第一次检测在容器启动后多长时间后开始
      61.             timeoutSeconds: 5 # 检测的超时时间
      62.             periodSeconds: 30 # 检查间隔时间
      63.             successThreshold: 1 # 成功门槛
      64.             failureThreshold: 5 # 失败门槛,连接失败5次,pod杀掉,重启一个新的pod
      65.           ports:
      66.             - name: http # 名称
      67.               containerPort: 80 # 容器开发对外的端口
      68.               protocol: TCP # 协议
      69.           env:
      70.             # 时区
      71.             - name: TZ
      72.               value: Asia/Shanghai
      73.             # app name
      74.             - name: APP_NAME
      75.               value: app.zhontai.api
      76.           # 挂载
      77.           volumeMounts:
      78.             - name: app-logs
      79.               mountPath: /logs #容器中的路径
      80.       # 卷轴
      81.       volumes:
      82.         - name: app-logs
      83.           hostPath:
      84.             path: /app/logs #将日志存放在宿主机的路径,需要在宿主机创建目录
      85.             type: Directory
      86.       #重启策略
      87.       restartPolicy: Always   
      88.       imagePullSecrets: # 镜像仓库拉取密钥
      89.         - name: nexus-login-registry
      复制代码

  • 执行部署:kubectl apply -f zhontai_api.yaml
  • 创建前端部署配置:zhontai_webui.yaml

      1. ---
      2. ## 配置服务
      3. kind: Service
      4. apiVersion: v1
      5. metadata:
      6.   name: app-zhontai-webui
      7.   namespace: default
      8.   labels:
      9.     app: app-zhontai-webui
      10. spec:
      11.   selector:
      12.     app: app-zhontai-webui
      13.   type: ClusterIP
      14.   ports:
      15.     - name: p80
      16.       port: 80
      17.       targetPort: 80
      18. ---
      19. kind: Deployment # 指定创建资源的角色/类型
      20. apiVersion: apps/v1 # 指定api版本,此值必须在kubectl api-versions中
      21. metadata: # 资源的元数据/属性
      22.   name: app-zhontai-webui # 资源的名字,在同一个namespace中必须唯一
      23.   namespace: default # 部署在哪个namespace中
      24.   labels: # 设定资源的标签
      25.     app: app-zhontai-webui
      26. spec: # 资源规范字段  
      27.   selector:
      28.     matchLabels:
      29.       app: app-zhontai-webui
      30.   replicas: 2 # 声明副本数目
      31.   revisionHistoryLimit: 2 # 保留历史版本
      32.   strategy: # 策略
      33.     rollingUpdate: # 滚动更新
      34.       maxSurge: 1 # 最大额外可以存在的副本数,可以为百分比,也可以为整数
      35.       maxUnavailable: 1 # 示在更新过程中能够进入不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
      36.     type: RollingUpdate # 滚动更新策略
      37.   template: # 模版
      38.     metadata: # 资源的元数据/属性
      39.       labels: # 设定资源的标签
      40.         app: app-zhontai-webui
      41.     spec: # 资源规范字段
      42.       containers:
      43.         - image: nexus.devops.test.com/projectapp/zhontai_webui:latest # 容器使用的镜像地址
      44.           name: app-zhontai-webui # 容器的名字
      45.           # 每次Pod启动拉取镜像策略,三个选择 Always、Never、IfNotPresent
      46.           # Always,每次都检查;Never,每次都不检查(不管本地是否有);IfNotPresent,如果本地有就不检查,如果没有就拉取
      47.           imagePullPolicy: Always
      48.           resources: # 资源管理
      49.             # limits: # 最大使用
      50.             #   cpu: 300m # CPU,1核心 = 1000m
      51.             #   memory: 500Mi # 内存,1G = 1024Mi
      52.             # requests: # 容器运行时,最低资源需求,也就是说最少需要多少资源容器才能正常运行
      53.             #   cpu: 100m
      54.             #   memory: 100Mi
      55.           livenessProbe: # pod 内部健康检查的设置
      56.             httpGet: # 通过httpget检查健康,返回200-399之间,则认为容器正常
      57.               path: / # URI地址
      58.               port: 80 # 端口
      59.               scheme: HTTP # 协议
      60.             initialDelaySeconds: 10 # 表明第一次检测在容器启动后多长时间后开始
      61.             timeoutSeconds: 5 # 检测的超时时间
      62.             periodSeconds: 30 # 检查间隔时间
      63.             successThreshold: 1 # 成功门槛
      64.             failureThreshold: 5 # 失败门槛,连接失败5次,pod杀掉,重启一个新的pod
      65.           ports:
      66.             - name: http # 名称
      67.               containerPort: 80 # 容器开发对外的端口
      68.               protocol: TCP # 协议
      69.           env:
      70.             # 时区
      71.             - name: TZ
      72.               value: Asia/Shanghai
      73.             # app name
      74.             - name: APP_NAME
      75.               value: app.zhontai.webui
      76.       #重启策略
      77.       restartPolicy: Always   
      78.       imagePullSecrets: # 镜像仓库拉取密钥
      79.         - name: nexus-login-registry
      复制代码

  • 执行部署:kubectl apply -f zhontai_webui.yaml

配置 Ingress 使用域名访问


  • 部署成功后添加对应 ingress 配置,即可使用域名访问

前端项目需要修改为对应的接口地址

确保绑定的域名正常解析到 k8s 节点,即可使用域名访问了,我这里使用的 DnsServer 泛解析,故可以直接访问,



至此,一步步将一个单体项目部署到了 k8s 中,仅供参考,实际如果时微服务,还设计到一些通用和环境的配置,后面再慢慢分享。
根据上面的步骤,后面分享将其整理成脚本,以便后续可以直接使用。
相关文档

后语

本文始于2023末,结束于2024始。
2023的最后两个月,是这几年以来,学习,产出最高的的两个月。
始于国庆,不止步于元旦。
新年快乐!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美丽的神话

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表