K8s 集群部署微服务 - DevOps(二) - 指南

K8s 集群部署微服务 - DevOps(二)


K8s 集群环境搭建 - yaml 版本(一)
K8s 集群部署中间件 - yaml 版本(二)
K8s 集群部署微服务 - yaml 版本(三)
K8s 集群部署微服务 - DevOps(一)
K8s 集群部署微服务 - DevOps(二)


一、安装 DevOps

  • 根据官方文档,需要创建新的企业空间,默认的企业空间不支持 DevOps。

    在这里插入图片描述

  • 创建之后添加我们的集群进该企业空间:

    在这里插入图片描述

  • 在扩展程中心安装 DevOps,点击安装即可。

    • 安装的过程中需要绑定 pvc 和 pv,所需要我们的k8s有默认的 stroageClass。

    • 安装的过程中需要拉取 jenkins 镜像,由于拉取比较慢,可能回到导致 UI 界面提示安装失败了,但其实还在拉取的过程中,需要拉取成功后,进行卸载 DevOps,在重新安装 DevOps。

    • 如果出现错误: Internal error occurred: failed calling webhook “reverseproxies.extensions.kubesphere.io”,执行如下命令即可:

      kubectl delete validatingwebhookconfiguration extensions.kubesphere.io
    • 其他问题可尝试在 kubeSphere 开发者社区看下

  • 安装成功后:在这里插入图片描述

  • 进去我们自定义的企业空间发现有 DevOps 功能了,到这就安装完成了。

    在这里插入图片描述

二、编写后端流水线

  • 在部署服务之前,需要新建企业空间,不能在默认的企业空间进行部署,因为默认的企业空间是不能使用 DevOps 流水线的,想要 DevOps,必须要在新建的企业空间上进行。在 KubeSphere中,企业空间比命名空间更高层次的隔离单位。隔离关系如下:

    ├── 企业空间A(workspace-a)
    │   ├── 项目1(namespace-a1)
    │   │   ├── MySQL服务
    │   │   └── 其他资源
    │   └── 项目2(namespace-a2)
    └── 企业空间B(workspace-b)  #  新创建的企业空间
        ├── 项目1(namespace-b1) # 这里看不到企业空间A的MySQL
        └── 项目2(namespace-b2)在这里插入代码片
  • 在新建的企业空间中,kubeSphere 上是看不到其他企业空间的任何服务的。但是一些系统服务,是所有命名空间可以共享的,在新建的企业空间无法修改,也无法看到这些服务,如需修改,需要再默认企业空间中进行修改配置。比如上篇文章中配置的服务:ks-apiserver 和 ks-controller-manager。

  • 在新建的企业空间中,创建流水线:DevOps -> 流水线 -> 点击创建:

    在这里插入图片描述

  • 创建流水线之后,需要进行编辑,我这里的流水线分为以下几步:

    • 从 gitee 拉取代码;
    • 将拉取的代码进行项目编译;
    • 编译好之后构建镜像;
    • 推送进行到已经部署好的 harbor;
    • 使用镜像部署服务;
  • 当然你还可以添加额外的步骤,比如单元测试、质量检测等。

1. 拉取代码

  • 我用的 gitee 作为代码仓库。首先开通我们的项目支持 svn 拉取代码,因为我们创建的流水线,默认就是使用的 svn 拉取代码,用 https 会报错。
    在这里插入图片描述

  • 在 kubeSphere 中创建 gitee 的凭证:用户名密码。用于从 gitee 拉取代码的凭证。

    在这里插入图片描述

  • 创建代码仓库,添加代码地址,记得填写 svn 的地址,还要关联上我们上面创建的凭证。

    在这里插入图片描述

  • 接下来编辑我们流水线的第一步:拉取代码

    • 代理选择:none
    • 任务第一步,关联上我们上面创建的代码仓库拉取代码。
    • 任务第二步:添加 shell 脚本,在拉取代码结束后打印出 “拉取代码成功”。
    • 任务第三步:添加了第二个 shell 脚本,打印我们拉取的项目的信息。

在这里插入图片描述

  • 编辑好第一步之后,先点击运行,测试下第一步是否有问题:

    在这里插入图片描述

  • 成功运行了第一步,效果如下:

    在这里插入图片描述

  • 日志如下:
    在这里插入图片描述

2. 项目编译

  • 项目进行编译的时候,maven 会下载项目依赖。但在 kubeSphere 中,默认是没有配置镜像地址的,所以需要配置依赖地址。

  • 在 【集群管理】中,选择我们需要修改的集群,在菜单 【配置】- 【配置字典】- 命名空间【kubesphere-devops-worker】,找到服务名:ks-devops-agent,修改改配置,添加镜像地址:
    在这里插入图片描述

  • 项目编译是在容器中进行的,我的 kubeSphere 版本 v4.2.0-community,提供的容器有 base 和 jnlp,其中 base 就是提供了 java 环境的容器。但是使用的是 jdk-21,而我需要部署的项目使用的 jdk 1.8。所以需要添加新的容器。

  • 【集群】- 选择我们的集群 - 【配置】 - 【配置字段】 - 命名空间【kubesphere-devops-system】- 配置名【jenkins-casc-config】:

    在这里插入图片描述

  • 在 jenkins_user.yaml: templates 下添加我们需要的容器:base-jdk8

    - name: "base-jdk8"
    image: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/kubesphere/builder-maven:v4.1.4-podman"
    command: "cat"
    args: ""
    ttyEnabled: true
    privileged: false
    resourceRequestCpu: "100m"
    resourceLimitCpu: "4000m"
    resourceRequestMemory: "100Mi"
    resourceLimitMemory: "8192Mi"

    在这里插入图片描述

  • 该容器来自渡渡鸟的容器镜像站,如果需要其他版本的 jdk,也可搜索满足需求的容器。当然也可以自己制作容器,放入私有的镜像仓库中。

  • 需要注意的是,我们需要知道我们使用的镜像的maven环境变量,知道maven的setting文件在容器的位置。然后将该文件挂载到上面我们配置的 ks-devops-agent 上,从而让 ks-devops-agent 的 mirrors 仓库生效。需要再 jenkins_user.yaml 下配置挂载:

    - name: "base-jdk8"
    resources:
    requests:
    ephemeral-storage: "1Gi"
    limits:
    ephemeral-storage: "10Gi"
    volumeMounts:
    - name: config-volume
    mountPath: /apache-maven-3.5.3/conf/settings.xml
    subPath: settings.xml

    在这里插入图片描述

  • 如下是容器 base-jdk8 的maven环境变量,对应上面的配置:

    在这里插入图片描述

  • 编辑流水线:指定容器名为:base-jdk8,并添加命令:mvn clean package

    在这里插入图片描述

  • 运行测试成功:

    在这里插入图片描述

3. 构建镜像

  • 在项目中编写 Dockerfile 文件,并推送到仓库中,流水线需要用该 Dockerfile 进行构建镜像。项目结构如下:与 src 齐平

    在这里插入图片描述

  • dockerfile 内容如下:

    # 基础镜像:和你的 JDK 版本匹配(JDK 88-jre-slim,轻量且安全)
    FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/openjdk:8-jre-slim
    # 避免中文乱码
    ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
    # 创建非 root 用户(安全最佳实践,避免容器用 root 运行)
    RUN groupadd --system --gid 1001 appgroup && \
    useradd --system --uid 1001 --gid 1001 appuser
    # 工作目录(容器内目录,统一路径)
    WORKDIR /opt/mortal/app
    # 复制授权服务的 Jar 包到容器(注意:Jar 包名称要和 target/ 下的一致!)
    # 如果你想简化 Jar 包名称,可在复制时重命名为 app.jar(推荐,避免版本号变更导致 Dockerfile 修改)
    # [当前系统相对路径] [容器内绝对路径]
    COPY mortal-gateway/target/mortal-gateway-1.0-SNAPSHOT.jar /opt/mortal/app/mortal-gateway.jar
    # 给非 root 用户授权(避免启动时权限不足)
    RUN chown -R appuser:appgroup /opt/mortal/app
    # 切换到非 root 用户运行
    USER 1001
    # 暴露服务端口(和授权服务的 server.port 一致,比如 2001)
    EXPOSE 1888
    # 启动命令(exec 格式,支持优雅停机)
    ENTRYPOINT ["java", "-jar", "mortal-gateway.jar"]
    • 需要注意我们选择的 jdk 版本必须和 运行容器的主机架构一直才行,不然会报错。
    • mortal-gateway/target/mortal-gateway-1.0-SNAPSHOT.jar:该路径需要根据你编译后的 jar 位置来决定的。
  • 将 Dockerfile 文件推送到远程仓库,在我们运行流水线的第一步会将他拉去下来。

    在这里插入图片描述

  • 接下来就是使用 docker build 进行打包了。但是前提是需要观察我们使用的 base-jdk8 镜像中是否安装了docker-cli,是否启动了 docker 守护进程,如果没有启动docker 守护进程,是无法使用docker build 的。通过观察发现,使用了 podman 代替了 docker:

    在这里插入图片描述

  • podman 对比 docker:

    • 无守护进程:Podman 不需要运行 root 权限的守护进程。
    • rootless 容器:可以在普通用户权限下运行容器,更安全。
    • 没有特权提升:减少了安全风险。
  • 所以我们需要使用 podman build 代替 docker build。使用 podman 还需要解决下权限问题,不然会报错如下:
    在这里插入图片描述

  • 在 jenkins_user.yaml 添加如下三处配置:

    envVars:
    - envVar:
    key: "USER"
    value: "root"
    - envVar:
    key: "HOME"
    value: "/root"
    ---
    securityContext:
    runAsUser: 0
    runAsGroup: 0
    allowPrivilegeEscalation: true
    ---
    securityContext:
    fsGroup: 0
  • 效果如下:

    在这里插入图片描述
    在这里插入图片描述

  • 配置修改后大概两分钟后生效,接下来编写构建镜像流水线:

    podman build -f mortal-gateway/Dockerfile -t mortal.harbor.com/mortal-system/mortal-gateway:1.0-SNAPSHOT .

    在这里插入图片描述

  • 测试运行成功:

    在这里插入图片描述

  • 其他的服务也是按照上面的步骤来:在流水线中点击【添加并行阶段】即可:并行可以加快构建速度

    在这里插入图片描述

  • 添加其他服务:

在这里插入图片描述

  • 测试成功:

在这里插入图片描述

  • 其他优化:

    • 用于 Dockerfile 中的 jdk镜像,上传至私有库 harbor中,这样可以加快拉取速度。该方式之前叙说过多次,便不再赘述。
    • 每次任务的构建都是通过 Agent ,每次构建创建的 pod 都是临时的,构建完成后就被销毁,下次构建又是全新的 Pod,所以本地永远没有缓存。导致每次构建又要重新拉取 jdk 镜像。
  • 查看日志如下,每次都是 copying,没有使用到缓存,服务多的情况下,每个服务都需要 copying,非常慢和浪费资源:

    在这里插入图片描述

  • 修改 jenkins-casc-config ,添加镜像路径的挂载:

    - hostPathVolume:
    hostPath: "/var/data/jenkins_podman_cache"
    mountPath: "/var/lib/containers"

    在这里插入图片描述

  • 其中 hostPath 是宿主机的路径,montPah 是 容器 base-jdk8 的容器路径。

    • hostPath:该路径宿主机如果没有的话,需要提前创建好:

      sudo mkdir -p /var/data/jenkins_podman_cache
      sudo chmod 777 /var/data/jenkins_podman_cache
    • montPah:该值需要确定我们使用的容器中,镜像的路径地址,比如我用的base-jdk8 信息如下:

      在这里插入图片描述

  • 配置好之后再次启动流水线测试效果如下:发现成功使用了缓存,构建速度行得到了大大的提升。从 17.35min 提升到了 58.43 s,速度提升巨大。

    在这里插入图片描述

4. 推送镜像

  • 推送镜像需要如下4步:

    • 指定容器,依旧是我们前面使用的 base-jdk8。

    • 添加 harbor 凭证:harbor 的用户名和密码。

    • 使用 harbor 凭证进行登录。podman login --tls-verify=false -u $HARBOR_USER -p $HARBOR_PASSWD mortal.harbor.com

    • 推送镜像:podman push --tls-verify=false mortal.harbor.com/mortal-system/mortal-authority:1.0-SNAPSHOT

      在这里插入图片描述

  • 如上边成功推送了一个服务的镜像,其他服务的进行,点击【添加并行阶段】,和上述进行一样的设置,修改下镜像名称即可。

5. 部署服务

  • 部署服务分为以下几步:

    • 创建流水线访问 k8s 集群的凭证。
    • 添加该凭证。
    • 执行部署服务的脚本。
  • 创建凭证:选择类型为 kubeconfig,会自动带出内容,点击确定创建。

    在这里插入图片描述

  • 在流水线里添加步骤,然后添加我们刚刚创建的凭证,变量起名为:KUBECONFIG_CONTENT,该变量下一步执行脚本需要用到。

    在这里插入图片描述

  • 执行服务。

    mkdir -p ~/.kube
    echo "$KUBECONFIG_CONTENT" > ~/.kube/config
    envsubst < mortal-gateway/deploy/deploy.yaml | kubectl apply -f -
    • KUBECONFIG_CONTENT 为上面添加凭证的变量名。
    • mortal-gateway/deploy/deploy.yaml:为我们服务的 deploy.yaml 的位置。如果不清楚,可以先打印 ls 看下目录结构。
  • 我们的服务:deploy 位置

    在这里插入图片描述

  • deploy.yaml 内容如下,集合了 deployment,service,pvc,ingress 等

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: gateway-service  # 部署名称
    namespace: mortal-system  # 建议创建专属命名空间,也可改为你的现有命名空间
    labels:
    app: gateway-service
    spec:
    replicas: 1  # 副本数,可根据需求调整
    selector:
    matchLabels:
    app: gateway-service
    template:
    metadata:
    labels:
    app: gateway-service
    spec:
    containers:
    - name: gateway-service
    # 镜像地址(harbor中的目标镜像)
    image: mortal.harbor.com/mortal-system/mortal-gateway:1.0-SNAPSHOT
    imagePullPolicy: Always  # 镜像拉取策略:本地无则拉取
    # 容器端口(对应微服务的启动端口,如80809999等,需与服务配置一致)
    ports:
    - containerPort: 1888
    # 环境变量配置(连接nacos、mysql,根据你的实际配置修改值)
    env:
    # 1. 微服务名称(对应 Nacos DataID 前缀)
    - name: SPRING_APPLICATION_NAME
    value: "mortal-gateway-service"
    # 2. 激活 prod 环境
    - name: SPRING_PROFILES_ACTIVE
    value: "prod"  # 激活prod环境配置
    # 3. Nacos 配置中心地址 + 命名空间
    - name: SPRING_CLOUD_NACOS_CONFIG_SERVER-ADDR
    value: "nacos-headless:8848"
    - name: SPRING_CLOUD_NACOS_CONFIG_NAMESPACE
    value: "db0788b5-43d5-4f7c-abf4-a9aa8308d272"
    # 4. Nacos 注册中心地址 + 命名空间(和配置中心一致)
    - name: SPRING_CLOUD_NACOS_DISCOVERY_SERVER-ADDR
    value: "nacos-headless:8848"
    - name: SPRING_DATASOURCE_URL
    value: "jdbc:mysql://mysql-headless:3306/mortal?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"  # mysql地址(k8s中mysql的service名称)
    - name: SPRING_DATASOURCE_USERNAME
    value: "root"  # mysql用户名
    - name: SPRING_DATASOURCE_PASSWORD
    value: "root"  # mysql密码
    # 资源限制(根据集群资源调整)
    resources:
    limits:
    cpu: "1"
    memory: "1Gi"
    requests:
    cpu: "500m"
    memory: "512Mi"
    # 健康检查(可选,建议配置)
    livenessProbe:
    httpGet:
    path: /actuator/health
    port: 1888
    initialDelaySeconds: 60  # 启动后延迟60秒检查
    periodSeconds: 10  # 每10秒检查一次
    readinessProbe:
    httpGet:
    path: /actuator/health
    port: 1888
    initialDelaySeconds: 30
    periodSeconds: 5
    # 挂载动态PVC(与volumeClaimTemplates名称对应)
    volumeMounts:
    - name: gateway-log-volume  # 必须与volumeClaimTemplates.name一致
    mountPath: /app/logs  # 容器内持久化目录
    volumes:  # 新增volumes字段引用PVC
    - name: gateway-log-volume
    persistentVolumeClaim:
    claimName: gateway-log-pvc  # 对应上面创建的PVC名称
    ---
    # Service配置(暴露微服务,供内部集群访问)
    apiVersion: v1
    kind: Service
    metadata:
    name: gateway-service
    namespace: mortal-system
    spec:
    selector:
    app: gateway-service
    type: ClusterIP  # 集群内部访问,如需外部访问可改为NodePortLoadBalancer
    ports:
    - port: 1888  # Service端口
    targetPort: 1888  # 容器端口(与Deployment中containerPort一致)
    ---
    # gateway-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: gateway-log-pvc
    namespace: mortal-system
    spec:
    accessModes: [ "ReadWriteMany" ]
    storageClassName: "nfs-sc"
    resources:
    requests:
    storage: 2Gi
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: gateway-ingress
    namespace: mortal-system
    annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    # 1. 禁用 HTTPS 重定向(核心)
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    # 2. 禁用强制 SSL 重定向(覆盖全局)
    nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
    # 3. 禁用永久重定向(针对 308 状态码)
    nginx.ingress.kubernetes.io/permanent-redirect-code: "307"
    # 4. 明确指定后端服务用 HTTP 协议(避免默认 HTTPS 转发)
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
    # 5. 其他原有注解保留
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
    spec:
    ingressClassName: nginx
    rules:
    # 无域名规则(直接用 IP 访问)
    - http:
    paths:
    - path: /mortal-gateway/(.*)
    pathType: ImplementationSpecific
    backend:
    service:
    name: gateway-service
    port:
    number: 1888
    # 域名规则(可选,保留)
    - host: gateway.mortal.com
    http:
    paths:
    - path: /mortal-gateway/(.*)
    pathType: ImplementationSpecific
    backend:
    service:
    name: gateway-service
    port:
    number: 1888
  • 其中环境变量配置 env对应如下:

    在这里插入图片描述

    server:
    port: 8888
    servlet:
    context-path: /mortal-gateway
    spring:
    application:
    name: mortal-gateway-service
    cloud:
    nacos:
    discovery:
    enabled: true #如果不想使用 Nacos 进行服务注册与发现,设置为false即可
    server-addr: 14.103.138.45:30848
    namespace: aa104d54-9e4b-470b-9662-31ab4aedefb4
    username: ${NACOS_USERNAME:nacos}
    password: ${NACOS_PASSWORD:nacos}
    metadata:
    management:
    context-path: ${server.servlet.context-path}/actuator
    gateway:
    # 网关全局跨域配置
    globalcors:
    cors-configurations:
    '[/**]':
    allowedOrigins: "*"
    allowedMethods: "*"
    allowedHeaders: "*"
    allowCredentials: true
    # 解决options请求被拦截的问题
    add-to-simple-url-handler-mapping: true
    # 这个地方独立配置,是网关的数据,代码 GatewayConfig.java 中读取被监听
    nacos:
    gateway:
    route:
    config:
    data-id: mortal-gateway-router
    group: prod
    # Spring Boot Actuator 健康检查配置(核心,对应K8s的liveness/readiness探针)
    management:
    endpoints:
    web:
    exposure:
    include: health  # 暴露health端点(如需更多如info、metrics可追加,用逗号分隔)
    base-path: /actuator  # Actuator基础路径,对应K8s探针路径的/actuator
    endpoint:
    health:
    enabled: true  # 启用健康检查端点
    show-details: always  # 显示健康检查详情(生产环境可改为when_authorized)
    health:
    livenessState:
    enabled: true  # 适配K8s存活探针(Spring Boot 2.3+推荐)
    readinessState:
    enabled: true  # 适配K8s就绪探针(Spring Boot 2.3+推荐)
  • 其他微服务添加并行阶段,重复按上述操作即可。

三、编写前端流水线

  • 有了前面部署 后端流水线的经验,部署前端流水线就快了很多了。首先创建 流水线,选择 node.js 模板。

1. 拉取代码

  • 添加 前段代码仓库地址,并添加仓库凭证,如下:

    在这里插入图片描述

2. 项目编译

  • 这次我们使用 kubeSphere 自带的容器 base,来进行后续操作。

  • 选择容器为 base,执行命令:npm install 进行编译。

    在这里插入图片描述

3. 构建镜像

  • 和前面 base-jdk8 一样需要修改 jenkins_user.yaml 的 base 容器的配置:防止权限问题。

    privileged: true
    envVars:
    - envVar:
    key: "USER"
    value: "root"
    - envVar:
    key: "HOME"
    value: "/root"

    在这里插入图片描述

  • 像之前我们用 yaml 文件,用命令行发布前端项目一样,我们需要文件有:

    • Dockerfile
    • nginx.conf
    • .dockerignore
    • 以及要部署的 deployment,service,ingress 整合到 deploy.yaml 中,结构如下:
      在这里插入图片描述
  • 各个文件代码如下:

    • Dockerfile:其中 node 和 nginx 镜像我是改为了私有镜像库中拉取,加快了构建速度。

      # ==================== 阶段1:构建 Vue 项目(Node 环境)====================
      FROM mortal.harbor.com/mortal-system/node:18-alpine AS builder
      # 设置工作目录(root 用户创建,有权限)
      WORKDIR /app
      # 1. 复制依赖文件(root 用户,无权限问题)
      COPY package.json package-lock.json ./
      # 2. 安装依赖(--unsafe-perm 尝试赋予权限,基础保障)
      RUN npm ci --unsafe-perm
      # 3. 复制项目所有核心文件(root 用户,无权限问题)
      COPY ../mortal-front/ ./
      # 4. 关键修复:手动给 node_modules/.bin 下所有命令赋予执行权限
      # 直接暴力解决 vue-tsc、vite 等命令的 Permission denied 问题
      RUN chmod +x -R node_modules/.bin/
      # 5. 构建 Vue 项目(此时命令已有权限,可正常执行)
      RUN npm run build
      # ==================== 阶段2:部署静态资源(Nginx 环境)====================
      FROM mortal.harbor.com/mortal-system/nginx:alpine
      # 复制 dist 产物到 Nginx 静态目录(已验证正确)
      COPY --from=builder /app/dist /usr/share/nginx/html
      # 启用自定义 Nginx 配置(关键!解决路由 404)
      COPY nginx.conf /etc/nginx/conf.d/default.conf
      # 暴露端口(可选,仅声明)
      EXPOSE 80
      # 启动 Nginx
      CMD ["nginx", "-g", "daemon off;"]
    • nginx.conf

      server {
      listen 80;
      server_name localhost;
      root /usr/share/nginx/html;
      index index.html;
      # 核心:所有路由请求转发到 index.html,支持 Vue Router History 模式
      location / {
      try_files $uri $uri/ /index.html;
      add_header Cache-Control "no-cache";
      }
      # 静态资源缓存(可选,优化性能)
      location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|svgz|woff|woff2|ttf|otf)$ {
      expires 7d;
      add_header Cache-Control "public, max-age=604800";
      }
      }
    • .dockerignore

      # 依赖目录
      node_modules
      .npm
      .yarn
      # 构建产物(本地构建的,Docker 内会重新构建)
      dist
      dist-ssr
      # 日志和缓存
      logs
      *.log
      .vite
      .eslintcache
      .prettiercache
      # 本地配置
      .env.local
      .env.development.local
      .env.production.local
      .git
      .gitignore
      README.md
    • deploy.yaml

      # frontend-prod-deploy.yaml
      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: mortal-frontend
      namespace: mortal-system
      spec:
      replicas: 1  # 生产环境建议 2-3 个副本,保证高可用
      selector:
      matchLabels:
      app: mortal-frontend
      template:
      metadata:
      labels:
      app: mortal-frontend
      spec:
      # 私有 Harbor 需配置镜像拉取密钥(和之前一致)
      imagePullSecrets:
      - name: harbor-secret
      containers:
      - name: mortal-frontend
      image: mortal.harbor.com/mortal-system/mortal-front:1.0-SNAPSHOT
      imagePullPolicy: Always
      ports:
      - containerPort: 80
      resources:
      requests:
      cpu: 100m
      memory: 128Mi
      limits:
      cpu: 500m
      memory: 256Mi
      livenessProbe:
      httpGet:
      path: /
      port: 80
      initialDelaySeconds: 30
      periodSeconds: 10
      readinessProbe:
      httpGet:
      path: /
      port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
      ---
      # 1. ClusterIP Service(仅集群内访问,实现 Pod 负载均衡)
      apiVersion: v1
      kind: Service
      metadata:
      name: mortal-frontend-svc
      namespace: mortal-system
      spec:
      type: ClusterIP  # 类型改为 ClusterIP(默认类型,可不写)
      selector:
      app: mortal-frontend
      ports:
      - port: 80  # Service 内部端口(集群内其他服务访问用:http://mortal-frontend-svc:80)
      targetPort: 80  # 对应容器端口
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
      name: mortal-frontend-ingress
      namespace: mortal-system
      annotations:
      nginx.ingress.kubernetes.io/use-regex: "true"
      # 1. 禁用 HTTPS 重定向(核心)
      nginx.ingress.kubernetes.io/ssl-redirect: "false"
      # 2. 禁用强制 SSL 重定向(覆盖全局)
      nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
      # 3. 禁用永久重定向(针对 308 状态码)
      nginx.ingress.kubernetes.io/permanent-redirect-code: "307"
      # 4. 明确指定后端服务用 HTTP 协议(避免默认 HTTPS 转发)
      nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
      # 5. 其他原有注解保留
      nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
      nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
      nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
      spec:
      ingressClassName: nginx
      rules:
      # 无域名规则(直接用 IP 访问)
      - http:
      paths:
      - path: /(.*)
      pathType: ImplementationSpecific
      backend:
      service:
      name: mortal-frontend-svc
      port:
      number: 80
  • 流水线中执行构建镜像命令:

    podman build --tls-verify=false -f Dockerfile -t mortal.harbor.com/mortal-system/mortal-front:1.0-SNAPSHOT .

    在这里插入图片描述

4. 推送镜像

  • 和后端推送进行一样,添加凭证 -> 登陆 harbor -> 推送镜像:

    # 登录 harbor
    podman login --tls-verify=false -u $HARBOR_USER -p $HARBOR_PASSWD mortal.harbor.com
    # 推送镜像
    podman push --tls-verify=false mortal.harbor.com/mortal-system/mortal-front:1.0-SNAPSHOT

    在这里插入图片描述

5. 部署服务

  • 执行我们的 deploy.yaml 来发布项目,和后端一样,添加凭证 -> 执行脚本:代码上没有任何变化

    mkdir -p ~/.kube
    echo "$KUBECONFIG_CONTENT" > ~/.kube/config
    envsubst < deploy/deploy.yaml | kubectl apply -f -

    在这里插入图片描述

  • 测试成功,并且能够成功访问前端项目:

    在这里插入图片描述
    在这里插入图片描述

小结

  • 至此便可通过流水线实现一键 CI/CD ,解决了前面我们使用命令行来部署服务的繁琐,并且可通过页面点击来实现服务的扩容与缩容,通过页面便可查看日志信息。
  • kubeSphere 流水线 也可设置触发机制,比如每次仓库更新,自动触发流水线。
posted @ 2026-01-14 20:42  yangykaifa  阅读(8)  评论(0)    收藏  举报