Jenkins 自动化流水线(CICD)

前期知识点系列回顾:

私有代码仓库搭建(GitLab)

私有镜像仓库搭建(Harbor)

kubernetes_v1.35.1高可用集群部署实战

Docker快速部署Java服务指南

docker-compose-安装jenkins指南

CD部署环境准备:

需要一个Kubernetes集群,单节点,多节点,高可用集群都可以,当前演示的是基于Kubernetes v1.35.1,如果不会部署K8S的可以参考:kubernetes_v1.35.1高可用集群部署实战

在软件开发过程中,代码从编写完成到最终上线往往需要经历编译、测试、打包、部署等多个环节。如果这些工作依赖人工操作,不仅效率低下,而且容易因为人为失误导致发布失败,甚至影响生产环境的稳定运行。

通过 Jenkins 自动化流水线,开发团队可以实现:

  • 代码提交后自动触发构建

  • 自动执行单元测试与质量检查

  • 自动打包生成发布产物

  • 自动构建 Docker 镜像

  • 自动推送至镜像仓库

  • 自动部署至测试环境或生产环境

  • 自动通知发布结果

从而将原本需要数十分钟甚至数小时的发布流程缩短至几分钟,大幅提升研发效率和交付质量。

通过学习本文,你将能够独立搭建一套完整的 Jenkins 自动化发布平台,实现从代码提交到应用部署的全流程自动化,为企业研发效能提升和 DevOps 体系建设奠定坚实基础。

我整理了这篇 2026 年最新 最完整的企业级 DevOps 全流程实战指南 。本文基于当前最稳定的版本:Kubernetes v1.35.1GitLab 18.10.3Harbor 2.11.0Jenkins 2.462.3,从最基础的环境准备开始,一步步带你完成:

文章没有空洞的理论,只有可直接复制执行的命令和配置文件。我会把自己踩过的每一个坑、每一个容易忽略的细节都毫无保留地分享给你。无论你是刚接触 DevOps 的新手,还是想要完善现有流水线的资深工程师,跟着本文操作,你将在半天内搭建起一套完整的、可用于生产环境的 CI/CD 流水线,实现代码提交后自动构建、自动测试、自动打包、自动部署到 Kubernetes 集群的全流程自动化。

一、部署前去工作节点确认基础信息

docker --version

docker Compose version v2.40.3

二、开始部署jenkins

Jenkins部署指南(docker)

Jenkins部署指南(k8s)

安装方式根据实际情况自选安装方式。

复制代码
docker pull jenkins/jenkins:2.555.1-lts-jdk21
docker tag jenkins/jenkins:2.555.1-lts-jdk21 192.168.1.20/jenkins/jenkins:2.555.1-lts-jdk21
docker push 192.168.1.20/jenkins/jenkins:2.555.1-lts-jdk21

使用新版本的jenkins启动依赖JDK版本是Java21或者更高版本,但是项目又是老项目使用jdk8,或者jdk17,需要把原理的配置"- PATH=...." 注释掉。

maven/go/nodejs/python 怎么用?打开 Jenkins → 系统管理 → 全局工具,配置新增 JDK/Maven/Golang,路径填你挂载的目录(如 /usr/local/maven),项目构建时直接选就行。

复制代码
  environment:
      - JENKINS_OPTS=--prefix=/jenkins
      - JDK17_HOME=/usr/local/jdk17
      - MAVEN_HOME=/usr/local/maven
      - PYTHON_HOME=/usr/local/python3
      - GOPATH=$HOME/go
      - GOROOT=/usr/local/go
      - TZ=Asia/Shanghai

还有想保留"- PATH=...." 的话,可以自行安装java21,并挂载:

复制代码
  environment:
      - JAVA_HOME=/usr/local/jdk21
      - JDK17_HOME=/usr/local/jdk17
      - MAVEN_HOME=/usr/local/maven
      - PYTHON_HOME=/usr/local/python3
      - PATH=$PATH:/usr/local/jdk17/bin:/usr/local/maven/bin:/usr/local/go/bin:/usr/local/nodejs/bin:/usr/local/python3/bin
      - GOPATH=$HOME/go
      - GOROOT=/usr/local/go
      - TZ=Asia/Shanghai

三、jenkins安装必要插件

Jenkins 安装必要插件

四、Jenkins 配置 Kubernetes 凭证

Jenkins 配置Kubernetes凭证

五、Jenkins 配置 gitlab 凭证

Jenkins 配置gitlab凭证

六、Jenkins 配置 Harbor 凭证

Jenkins 配置Harbor凭证

七、Jenkins 配置【系统配置】和【全局工具配置】

Jenkins 配置系统配置和全局工具配置

八、gitlab新建2个分支

开发主干develop

发版上线release/vx.x.x

8.1、新建开发分支develop

8.2、新建发版上线分支 ``release/vx.x.x

release/v1.0.0

8.3、两个分支创建完成

九、Jenkins流水线构建Java后端项目

Jenkins 流水线构建Java后端项目

Jenkins 之参数下拉框宽度调整

十、Jenkins 让GitLab自动触发构建

Jenkins 之GitLab自动触发构建

十一、Jenkins 流水线构建vue前端项目

11.1、安装流水线必要插件

Pipeline Stage View : 给你的 Pipeline 提供可视化的阶段进度视图。轻量可视化,不改变原有界面,只在构建详情页加一个进度条。

Blue Ocean: 给 Jenkins 提供一个全新的、更现代化的流水线专属 UI。全新 UI 体验,重写了 Jenkins 的流水线界面,更美观但资源占用稍高。

Slack Notification:企业微信 / 钉钉通知插件-根据团队沟通工具选择,实时推送构建结果。

List Git Branches Parameter:直接配置仓库 URL,不依赖任务 SCM 配置GitHub,获取多分支。

Active Choices :是 Jenkins 中一款功能极强的动态参数化构建插件,它解决了传统静态参数的局限性,让构建表单变得更智能、更灵活。

11.2、使用List Git Branches Parameter插件获取多分支

复制代码
toolbox-web
复制代码
参数化构建过程-->List Git branches (and more)
复制代码
List Git branches (and more):
    Name:BRANCH_NAME
    Description:选择要构建的toolbox-web分支
Repository URL:http://192.168.1.50:8980/aiops-team/toolbox-web.git
Credentials:gitlab开发组凭证
Parameter Type:Branch
Sort Mode: ASCENDING
Default Value: develop
其它保持默认

Pipeline script:

复制代码
pipeline {
    agent any
    environment {
        // 环境变量 PATH
        PATH = "${env.PATH}:" +
               "${env.JAVA_HOME}/bin:" +
               "${env.JDK17_HOME}/bin:" +
               "${env.MAVEN_HOME}/bin:" +
               "${env.GO_HOME}/bin:" +
               "${env.NODE_HOME}/bin:" +
               "${env.PYTHON_HOME}/bin"
    }
    stages {
        stage('获取分支') {
            steps {
                script {
                    echo "原始分支参数:${params.BRANCH_NAME}"
                }
            }
        }

        stage('拉代码') {
            steps {
                // 直接在行内替换 refs/heads/ 前缀,兼容两种格式
                git url: 'http://192.168.1.50:8980/aiops-team/toolbox-web.git',
                    credentialsId: 'gitlab-group-token',
                    branch: "${params.BRANCH_NAME.replace('refs/heads/', '')}"
            }
        }

        stage('前端构建') {
            steps {
                echo "=== NODE_HOME (${env.NODE_HOME}) ==="
                sh "node -v"
                sh "npm -v"
                sh "npm ci"
                sh "npm run build"
                sh "ls -la dist/"
            }
        }
    }
}

动态获取gitlab的分支:

11.3、使用Active Choices Parameter插件实时获取多分支

进入任务配置页:打开 toolbox-web 任务 → 点击「Configure」

开启参数化构建:勾选「参数化构建过程」

添加 Active Choices 参数:点击「添加参数」→ 选择「Active Choices Parameter」

1、Jenkins 连通性测试

在 Jenkins 服务器上执行以下命令,测试 GitLab API 是否能正常访问

复制代码
curl -H "PRIVATE-TOKEN: glpat-Ir1swBgzZEQ4q9Gs7sgHZW86MQp1OjEH.01.0w1r0a1al" \   "http://192.168.1.50:8980/api/v4/projects/aiops-team%2Ftoolbox-web/repository/branches"

2、Active Choices Parameter 配置

Name:

复制代码
BRANCH

Groovy Script:

复制代码
// 1. 配置GitLab 信息
def gitlabHost = "http://192.168.1.50:8980"
def projectPath = "aiops-team/toolbox-web"
def gitlabApiToken = "glpat-Ir1swBgzZEQ4q9Gs7sgHZW86MQp1OjEH.01.0w1r0a1al"
// 2. URL 编码项目路径(处理特殊字符,修正原脚本的转义问题)
def encodedProjectPath = URLEncoder.encode(projectPath, "UTF-8").replaceAll("\\+", "%20")
// 3. 调用 GitLab API 获取分支列表
def apiUrl = "${gitlabHost}/api/v4/projects/${encodedProjectPath}/repository/branches?per_page=100"
def connection = new URL(apiUrl).openConnection() as HttpURLConnection
connection.setRequestMethod("GET")
connection.setRequestProperty("PRIVATE-TOKEN", gitlabApiToken)
connection.setRequestProperty("Accept", "application/json")
// 4. 处理 API 响应
if (connection.responseCode == 200) {
    def response = new groovy.json.JsonSlurper().parse(connection.inputStream)
    def branches = response.collect { it.name }.sort()
    return branches
} else {
    // API 调用失败时返回空列表,避免构建报错
    return []
}

直接点击右边的 Approve script 按钮批准这个版本:

直接取消勾选脚本下方的 Use Groovy Sandbox 复选框:

Description:选择要构建的toolbox-web分支

3、流水线Pipeline 配置

复制代码
pipeline {
    agent any
    environment {
        // 合并系统PATH和自定义工具路径,确保所有命令都能找到
        PATH = "${env.PATH}:" +
               "${env.JAVA_HOME}/bin:" +
               "${env.JDK17_HOME}/bin:" +
               "${env.MAVEN_HOME}/bin:" +
               "${env.GO_HOME}/bin:" +
               "${env.NODE_HOME}/bin:" +
               "${env.PYTHON_HOME}/bin"
    }
    stages {
        stage('拉取代码') {
            steps {
                // 核心:直接使用 ${BRANCH} 引用用户选择的分支
                git(
                    url: 'http://192.168.1.50:8980/aiops-team/toolbox-web.git',
                    branch: "${BRANCH}", // 必须用双引号!
                    credentialsId: 'gitlab-group-token' // 你的凭据ID
                )
            }
        }

        // 验证分支是否正确获取
        stage('打印分支信息') {
            steps {
                echo "当前构建的分支是:${BRANCH}"
                echo "通过环境变量获取:${env.BRANCH}"
            }
        }

}

实时动态获取的项目分支:

通过环境变量获取:develop

11.4、分支正常获取完善编译流程

复制代码
pipeline {
    agent any
    environment {
        // 合并系统PATH和自定义工具路径,确保所有命令都能找到
        PATH = "${env.PATH}:" +
               "${env.JAVA_HOME}/bin:" +
               "${env.JDK17_HOME}/bin:" +
               "${env.MAVEN_HOME}/bin:" +
               "${env.GO_HOME}/bin:" +
               "${env.NODE_HOME}/bin:" +
               "${env.PYTHON_HOME}/bin"
    }
    stages {
        stage('拉取代码') {
            steps {
                // 核心:直接使用 ${BRANCH} 引用用户选择的分支
                git(
                    url: 'http://192.168.1.50:8980/aiops-team/toolbox-web.git',
                    branch: "${BRANCH}", // 必须用双引号!
                    credentialsId: 'gitlab-group-token' // 你的凭据ID
                )
            }
        }
        // 验证分支是否正确获取
        stage('打印分支信息') {
            steps {
                echo "当前构建的分支是:${BRANCH}"
                echo "通过环境变量获取:${env.BRANCH}"
            }
        }
        stage('前端构建') {
            steps {
                sh '''
                    set -e
                    # 配置国内npm源,解决依赖下载慢/超时问题
                    npm config set registry https://registry.npmmirror.com/
                    # 验证Node/NPM版本
                    node -v
                    npm -v
                    # 安装依赖(ci比install更稳定,适合CI环境)
                    npm ci
                    # 生产环境打包
                    npm run build
                    # 验证构建产物
                    ls -la dist/
                '''
            }
        }
    }
}

11.5、在项目下创建docker目录准备构建镜像

复制代码
docker pull nginx:1.31.1
docker pull nginx:1.31.1-alpine

docker save -o /home/nginx@1.31.1.tar  docker.io/library/nginx:1.31.1
docker save -o /home/nginx@1.31.1-alpine.tar  docker.io/library/nginx:1.31.1-alpine
docker tag docker.io/library/nginx:1.31.1 192.168.1.20/nginx/nginx:1.31.1
docker tag docker.io/library/nginx:1.31.1-alpine 192.168.1.20/nginx/nginx:1.31.1-alpine
docker push 192.168.1.20/nginx/nginx:1.31.1
docker push 192.168.1.20/nginx/nginx:1.31.1-alpine
复制代码
FROM 192.168.1.20/nginx/nginx:1.31.1-alpine
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/shanghai" > /etc/timezone
COPY ./dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN set -ex && \
    if ! id -u nginx >/dev/null 2>&1; then \
        useradd -r -s /sbin/nologin nginx; \
    fi && \
    chown -R nginx:nginx /usr/share/nginx/html && \
    chmod -R 755 /usr/share/nginx/html && \
    chmod 644 /etc/nginx/conf.d/default.conf \
复制代码
pipeline {
    agent any
    environment {
        // 合并系统PATH和自定义工具路径,确保所有命令都能找到
        PATH = "${env.PATH}:" +
               "${env.JAVA_HOME}/bin:" +
               "${env.JDK17_HOME}/bin:" +
               "${env.MAVEN_HOME}/bin:" +
               "${env.GO_HOME}/bin:" +
               "${env.NODE_HOME}/bin:" +
               "${env.PYTHON_HOME}/bin"
        // 私有Harbor仓库配置
        HARBOR_REGISTRY = "192.168.1.20"
        HARBOR_PROJECT  = "toolbox"
    }
    stages {
        // 验证分支是否正确获取
        stage('打印分支信息') {
            steps {
                echo "当前构建的分支是:${BRANCH}"
                echo "通过环境变量获取:${env.BRANCH}"
            }
        }
        stage('拉取代码') {
            steps {
                // 核心:直接使用 ${BRANCH} 引用用户选择的分支
                git(
                    url: 'http://192.168.1.50:8980/aiops-team/toolbox-web.git',
                    branch: "${BRANCH}", // 必须用双引号!
                    credentialsId: 'gitlab-group-token' // 你的凭据ID
                )
            }
        }
        stage('前端构建') {
            steps {
                sh '''
                    set -e
                    # 配置国内npm源,解决依赖下载慢/超时问题
                    npm config set registry https://registry.npmmirror.com/
                    # 验证Node/NPM版本
                    node -v
                    npm -v
                    # 安装依赖(ci比install更稳定,适合CI环境)
                    npm ci
                    # 生产环境打包
                    npm run build
                    # 验证构建产物
                    ls -la dist/
                '''
            }
        }
        stage('拷贝产物至docker目录') {
            steps {
                sh '''
                    set -e
                    # 如果docker目录不存在则自动创建
                    mkdir -p docker
                    # 递归拷贝dist全部文件到docker目录
                    cp -r dist docker/
                    # 校验拷贝结果
                    ls -la docker/
                '''
            }
        }
       stage('构建镜像并推送Harbor') {
           steps {
               withCredentials([usernamePassword(
                   credentialsId: 'harbor-creds',
                   usernameVariable: 'HARBOR_USER',
                   passwordVariable: 'HARBOR_PASS'
               )]) {
                   sh '''
                       # 进入docker目录
                       cd docker
                       # 拼接前端镜像标签:仓库/项目/应用名:分支-构建号
                       IMAGE_TAG="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/toolbox-web:${BRANCH}-${BUILD_NUMBER}"
                       echo "🔨 开始构建镜像:${IMAGE_TAG}"
                       # 构建Docker镜像
                       docker build -t "${IMAGE_TAG}" .
                       if [ $? -eq 0 ]; then
                           echo "✅ 镜像构建成功!"
                           docker images "${IMAGE_TAG}"
                       else
                           echo "❌ 镜像构建失败!"
                           exit 1
                       fi
                       # 登录Harbor仓库
                       echo "🔐 登录Harbor仓库:${HARBOR_REGISTRY}"
                       docker login "${HARBOR_REGISTRY}" -u "${HARBOR_USER}" -p "${HARBOR_PASS}"
                       if [ $? -eq 0 ]; then
                           echo "✅ Harbor登录成功!"
                       else
                           echo "❌ Harbor登录失败!"
                           exit 1
                       fi
                       # 推送镜像到Harbor
                       echo "🚀 推送镜像到Harbor:${IMAGE_TAG}"
                       docker push "${IMAGE_TAG}"
                       if [ $? -eq 0 ]; then
                           echo "✅ 镜像推送成功!"
                       else
                           echo "❌ 镜像推送失败!"
                           exit 1
                       fi
                       # 清理本地镜像,释放磁盘
                       echo "🧹 清理本地镜像"
                       docker rmi "${IMAGE_TAG}"
                       docker logout "${HARBOR_REGISTRY}"
                       echo "当前构建号:${BUILD_NUMBER}"
                       # 写入环境变量文件,供后续部署阶段读取
                       echo "IMAGE=${IMAGE_TAG}" > ../image.env
                       echo "BRANCH=${BRANCH}" >> ../image.env
                       echo "BUILD_NUMBER=${BUILD_NUMBER}" >> ../image.env
                       echo "APP_NAME=toolbox-web" >> ../image.env
                       echo "🎉 镜像构建推送完成!"
                       echo "📦 最终镜像地址:${IMAGE_TAG}"
                   '''
               }
           }
       }
    }
}

11.6、在项目下创建K8S目录并创建部署剧本

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: toolbox-web-platform
  labels:
    app: toolbox-web-platform
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: toolbox-web-platform
  template:
    metadata:
      labels:
        app: toolbox-web-platform
        version: v1
    spec:
      containers:
        - name: toolbox-web-platform
          image: ${IMAGE}
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          livenessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 10
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 3

apiVersion: v1
kind: Service
metadata:
  name: toolbox-web-platform-service
  labels:
    app: toolbox-web
spec:
  type: NodePort
  selector:
    app: toolbox-web-platform
  ports:
    - name: http
      port: 8080
      targetPort: http
      protocol: TCP
      nodePort: 30080

11.7、准备K8S集群config(客户端连接配置文件)

config 是kubectl 客户端连接 Kubernetes 集群的核心配置文件,它包含了集群地址、用户认证凭证、默认命名空间等所有必要信息。

复制代码
 stage('部署到K8S集群') {            steps {                withCredentials([file(                    credentialsId: KUBECONFIG_CRED,                    variable: 'KUBECONFIG_FILE'                )]) {                    // Kubeconfig写入方式                    sh '''                        rm -rf /root/.kube/config                        mkdir -p /root/.kube                        cp ${KUBECONFIG_FILE} /root/.kube/config                        chmod 600 /root/.kube/config                    '''                    echo "✅ Kubeconfig配置完成!"                    sh """                        # 验证K8S连接                        echo "🔍 验证K8S集群连接"                        kubectl cluster-info                    """                    // 清理敏感文件(增强安全性,避免凭证和临时文件残留)                    sh """                        # 删除Kubeconfig(包含K8s认证信息)                        rm -rf /root/.kube/config                    """                }            }         }

流水线和K8S集群交互正常:

11.8、流水线开始执行部署前端剧本

复制代码
pipeline {
    agent any
    environment {
        // 合并系统PATH和自定义工具路径,确保所有命令都能找到
        PATH = "${env.PATH}:" +
               "${env.JAVA_HOME}/bin:" +
               "${env.JDK17_HOME}/bin:" +
               "${env.MAVEN_HOME}/bin:" +
               "${env.GO_HOME}/bin:" +
               "${env.NODE_HOME}/bin:" +
               "${env.PYTHON_HOME}/bin"
        // 私有Harbor仓库配置
        HARBOR_REGISTRY = "192.168.1.20"
        HARBOR_PROJECT  = "toolbox"
       // K8s配置
        KUBECONFIG_CRED = "kubeconfig-cred"
        K8SNAMESPACE = "toolbox-bigdata"
        // 应用配置
        DEPLOYMENT_NAME = "toolbox-web-platform"
        K8S_DEPLOY_FILE = "k8s/deployment.yaml"
        K8S_SERVICE_FILE = "k8s/service.yaml"
    }
    stages {
        // 验证分支是否正确获取
        stage('打印分支信息') {
            steps {
                echo "当前构建的分支是:${BRANCH}"
                echo "通过环境变量获取:${env.BRANCH}"
            }
        }
        stage('拉取代码') {
            steps {
                // 核心:直接使用 ${BRANCH} 引用用户选择的分支
                git(
                    url: 'http://192.168.1.50:8980/aiops-team/toolbox-web.git',
                    branch: "${BRANCH}", // 必须用双引号!
                    credentialsId: 'gitlab-group-token' // 你的凭据ID
                )
            }
        }
        stage('前端构建') {
            steps {
                sh '''
                    set -e
                    # 配置国内npm源,解决依赖下载慢/超时问题
                    npm config set registry https://registry.npmmirror.com/
                    # 验证Node/NPM版本
                    node -v
                    npm -v
                    # 安装依赖(ci比install更稳定,适合CI环境)
                    npm ci
                    # 生产环境打包
                    npm run build
                    # 验证构建产物
                    ls -la dist/
                '''
            }
        }
        stage('拷贝产物至docker目录') {
            steps {
                sh '''
                    set -e
                    # 如果docker目录不存在则自动创建
                    mkdir -p docker
                    # 递归拷贝dist全部文件到docker目录
                    cp -r dist docker/
                    # 校验拷贝结果
                    ls -la docker/
                '''
            }
        }
       stage('构建镜像并推送Harbor') {
           steps {
               withCredentials([usernamePassword(
                   credentialsId: 'harbor-creds',
                   usernameVariable: 'HARBOR_USER',
                   passwordVariable: 'HARBOR_PASS'
               )]) {
                   sh '''
                       # 进入docker目录
                       cd docker
                       # 拼接前端镜像标签:仓库/项目/应用名:分支-构建号
                       IMAGE_TAG="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/toolbox-web:${BRANCH}-${BUILD_NUMBER}"
                       echo "🔨 开始构建镜像:${IMAGE_TAG}"
                       # 构建Docker镜像
                       docker build -t "${IMAGE_TAG}" .
                       if [ $? -eq 0 ]; then
                           echo "✅ 镜像构建成功!"
                           docker images "${IMAGE_TAG}"
                       else
                           echo "❌ 镜像构建失败!"
                           exit 1
                       fi
                       # 登录Harbor仓库
                       echo "🔐 登录Harbor仓库:${HARBOR_REGISTRY}"
                       docker login "${HARBOR_REGISTRY}" -u "${HARBOR_USER}" -p "${HARBOR_PASS}"
                       if [ $? -eq 0 ]; then
                           echo "✅ Harbor登录成功!"
                       else
                           echo "❌ Harbor登录失败!"
                           exit 1
                       fi
                       # 推送镜像到Harbor
                       echo "🚀 推送镜像到Harbor:${IMAGE_TAG}"
                       docker push "${IMAGE_TAG}"
                       if [ $? -eq 0 ]; then
                           echo "✅ 镜像推送成功!"
                       else
                           echo "❌ 镜像推送失败!"
                           exit 1
                       fi
                       # 清理本地镜像,释放磁盘
                       echo "🧹 清理本地镜像"
                       docker rmi "${IMAGE_TAG}"
                       docker logout "${HARBOR_REGISTRY}"
                       echo "当前构建号:${BUILD_NUMBER}"
                       # 写入环境变量文件,供后续部署阶段读取
                       echo "IMAGE=${IMAGE_TAG}" > ../image.env
                       echo "BRANCH=${BRANCH}" >> ../image.env
                       echo "BUILD_NUMBER=${BUILD_NUMBER}" >> ../image.env
                       echo "APP_NAME=toolbox-web" >> ../image.env
                       echo "🎉 镜像构建推送完成!"
                       echo "📦 最终镜像地址:${IMAGE_TAG}"
                   '''
               }
           }
       }
       stage('部署到K8S集群') {
            steps {
                script {
                    // 镜像和版本信息
                    def imageEnv = readFile('image.env').trim()
                    def envMap = [:]
                    imageEnv.split('\n').each { line ->
                        def parts = line.split('=', 2)
                        envMap[parts[0]] = parts[1]
                    }
                    def IMAGE = envMap['IMAGE']
                    def PROJECT_VERSION = envMap['PROJECT_VERSION']
                    def CURRENT_BUILD = envMap['BUILD_NUMBER'] as Integer
                    def PREVIOUS_BUILD = CURRENT_BUILD - 1
                    def PROJECT_ARTIFACT_ID = envMap['PROJECT_ARTIFACT_ID']
                    echo "📦 待部署镜像: ${IMAGE}"
                    echo "🔢 当前构建号: ${CURRENT_BUILD}"
                    echo "🔙 上一个构建号: ${PREVIOUS_BUILD}"
                     withCredentials([file(
                         credentialsId: KUBECONFIG_CRED,
                         variable: 'KUBECONFIG_FILE'
                     )]) {
                         // 使用withEnv临时设置KUBECONFIG环境变量(安全且正确的方式)
                         // 无需复制到全局目录,凭证仅在当前代码块内有效
                         withEnv([
                            "KUBECONFIG=${KUBECONFIG_FILE}",
                            "NAMESPACE=${K8SNAMESPACE}",
                            "IMAGE=${IMAGE}",
                            "PROJECT_VERSION=${PROJECT_VERSION}",
                            "CURRENT_BUILD=${CURRENT_BUILD}",
                            "PREVIOUS_BUILD=${PREVIOUS_BUILD}",
                            "PROJECT_ARTIFACT_ID=${PROJECT_ARTIFACT_ID}"
                        ]) {
                            sh '''
                                # Kubeconfig写入方式
                                rm -rf /root/.kube/config
                                mkdir -p /root/.kube
                                cp ${KUBECONFIG_FILE} /root/.kube/config
                                chmod 600 /root/.kube/config
                                # 验证K8S连接
                                echo "🔍 验证K8S集群连接"
                                kubectl cluster-info
                                if [ $? -ne 0 ]; then
                                    echo "❌ K8S集群连接失败,请检查kubeconfig凭证"
                                    exit 1
                                fi
                                # 验证部署文件存在
                                if [ ! -f "${K8S_DEPLOY_FILE}" ]; then
                                    echo "❌ 未找到K8S部署文件: ${K8S_DEPLOY_FILE}"
                                    exit 1
                                fi
                                # 替换部署文件中的变量占位符
                                echo "替换部署文件中的变量占位符"
                                sed -i 's|${IMAGE}|'"${IMAGE}"'|g' "${K8S_DEPLOY_FILE}"
                                # 预览变更
                                echo "即将应用的部署变更:"
                                kubectl diff -f "${K8S_DEPLOY_FILE}" -n ${NAMESPACE} || true
                                # 部署应用
                                echo "开始部署应用到命名空间: ${NAMESPACE}"
                                kubectl apply -f "${K8S_DEPLOY_FILE}" -n ${NAMESPACE}
                                # 部署Service
                                if [ -f "${K8S_SERVICE_FILE}" ]; then
                                    kubectl apply -f "${K8S_SERVICE_FILE}" -n ${NAMESPACE}
                                    echo "Service部署完成"
                                fi
                                # 等待部署完成
                                echo "等待Deployment滚动更新完成"
                                kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE} --timeout=300s
                                if [ $? -eq 0 ]; then
                                    echo "✅ 应用部署成功!"
                                    echo "📊 应用状态:"
                                    kubectl get pods -n ${NAMESPACE} -l app=${DEPLOYMENT_NAME}
                                else
                                    echo "❌ 部署失败,正在自动回滚到上一个稳定版本..."
                                    # ✅ 回滚到上一个构建号的镜像(构建号减1)
                                    PREVIOUS_IMAGE="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${PROJECT_ARTIFACT_ID}:${PROJECT_VERSION}-${PREVIOUS_BUILD}"
                                    echo "🔙 回滚到镜像: ${PREVIOUS_IMAGE}"
                                    # 更新Deployment到上一个版本的镜像
                                    kubectl set image deployment/${DEPLOYMENT_NAME} \
                                        ${DEPLOYMENT_NAME}=${PREVIOUS_IMAGE} \
                                        -n ${NAMESPACE}
                                    # 等待回滚完成
                                    kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE} --timeout=300s
                                    echo "✅ 回滚完成,请检查应用日志"
                                    exit 1
                                fi
                                # 清理临时文件
                                rm -f deploy.tmp.yaml image.env
                                # 删除Kubeconfig(包含K8s认证信息)
                                rm -rf /root/.kube/config
                            '''
                        }
                     }
                }
            }
         }
    }
}

查询前端端口:

复制代码
[root@master1 ~]# kubectl get svc -n toolbox-bigdata -w
NAME                           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
toolbox-web-platform-service   NodePort   10.96.247.208   <none>        8080:30080/TCP   13m

http://192.168.100.200:30080/

11.9、改造构建参数界面

添加一个输入框,如果输入了版本号,就 把develop-x 替换成输入的版本号

复制代码
docker pull 192.168.1.20/toolbox/toolbox-web:develop-1
复制代码
pipeline {
    agent any
    environment {
        // 合并系统PATH和自定义工具路径,确保所有命令都能找到
        PATH = "${env.PATH}:" +
               "${env.JAVA_HOME}/bin:" +
               "${env.JDK17_HOME}/bin:" +
               "${env.MAVEN_HOME}/bin:" +
               "${env.GO_HOME}/bin:" +
               "${env.NODE_HOME}/bin:" +
               "${env.PYTHON_HOME}/bin"
        // 私有Harbor仓库配置
        HARBOR_REGISTRY = "192.168.1.20"
        HARBOR_PROJECT  = "toolbox"
       // K8s配置
        KUBECONFIG_CRED = "kubeconfig-cred"
        K8SNAMESPACE = "toolbox-bigdata"
        // 应用配置
        DEPLOYMENT_NAME = "toolbox-web-platform"
        K8S_DEPLOY_FILE = "k8s/deployment.yaml"
        K8S_SERVICE_FILE = "k8s/service.yaml"
    }
    stages {
        // 验证分支是否正确获取
        stage('打印分支信息') {
            steps {
                echo "当前构建的分支是:${BRANCH}"
                echo "通过环境变量获取:${env.BRANCH}"
                echo "输入版本号:${VERSION}"
                echo "通过环境变量获取输入版本号:${env.VERSION}"
            }
        }
        stage('拉取代码') {
            steps {
                // 核心:直接使用 ${BRANCH} 引用用户选择的分支
                git(
                    url: 'http://192.168.1.50:8980/aiops-team/toolbox-web.git',
                    branch: "${BRANCH}", // 必须用双引号!
                    credentialsId: 'gitlab-group-token' // 你的凭据ID
                )
            }
        }
        stage('前端构建') {
            steps {
                sh '''
                    set -e
                    # 配置国内npm源,解决依赖下载慢/超时问题
                    npm config set registry https://registry.npmmirror.com/
                    # 验证Node/NPM版本
                    node -v
                    npm -v
                    # 安装依赖(ci比install更稳定,适合CI环境)
                    npm ci
                    # 生产环境打包
                    npm run build
                    # 验证构建产物
                    ls -la dist/
                '''
            }
        }
        stage('拷贝产物至docker目录') {
            steps {
                sh '''
                    set -e
                    # 如果docker目录不存在则自动创建
                    mkdir -p docker
                    # 递归拷贝dist全部文件到docker目录
                    cp -r dist docker/
                    # 校验拷贝结果
                    ls -la docker/
                '''
            }
        }
       stage('构建镜像并推送Harbor') {
           steps {
               withCredentials([usernamePassword(
                   credentialsId: 'harbor-creds',
                   usernameVariable: 'HARBOR_USER',
                   passwordVariable: 'HARBOR_PASS'
               )]) {
                   sh '''
                       # 进入docker目录
                       cd docker
                       echo "输入版本号:${VERSION}"
                       # 判断VERSION是否为空
                       if [ -z ${VERSION} ]; then
                            IMAGE_TAG="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/toolbox-web:${BRANCH}-${BUILD_NUMBER}"
                       else
                            IMAGE_TAG="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/toolbox-web:${VERSION}"
                       fi
                       # 拼接前端镜像标签:仓库/项目/应用名:分支-构建号
                       # IMAGE_TAG="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/toolbox-web:${BRANCH}-${BUILD_NUMBER}"
                       echo "🔨 开始构建镜像:${IMAGE_TAG}"
                       # 构建Docker镜像
                       docker build -t "${IMAGE_TAG}" .
                       if [ $? -eq 0 ]; then
                           echo "✅ 镜像构建成功!"
                           docker images "${IMAGE_TAG}"
                       else
                           echo "❌ 镜像构建失败!"
                           exit 1
                       fi
                       # 登录Harbor仓库
                       echo "🔐 登录Harbor仓库:${HARBOR_REGISTRY}"
                       docker login "${HARBOR_REGISTRY}" -u "${HARBOR_USER}" -p "${HARBOR_PASS}"
                       if [ $? -eq 0 ]; then
                           echo "✅ Harbor登录成功!"
                       else
                           echo "❌ Harbor登录失败!"
                           exit 1
                       fi
                       # 推送镜像到Harbor
                       echo "🚀 推送镜像到Harbor:${IMAGE_TAG}"
                       docker push "${IMAGE_TAG}"
                       if [ $? -eq 0 ]; then
                           echo "✅ 镜像推送成功!"
                       else
                           echo "❌ 镜像推送失败!"
                           exit 1
                       fi
                       # 清理本地镜像,释放磁盘
                       echo "🧹 清理本地镜像"
                       docker rmi "${IMAGE_TAG}"
                       docker logout "${HARBOR_REGISTRY}"
                       echo "当前构建号:${BUILD_NUMBER}"
                       # 写入环境变量文件,供后续部署阶段读取
                       echo "IMAGE=${IMAGE_TAG}" > ../image.env
                       echo "BRANCH=${BRANCH}" >> ../image.env
                       echo "BUILD_NUMBER=${BUILD_NUMBER}" >> ../image.env
                       echo "APP_NAME=toolbox-web" >> ../image.env
                       echo "🎉 镜像构建推送完成!"
                       echo "📦 最终镜像地址:${IMAGE_TAG}"
                   '''
               }
           }
       }
       stage('部署到K8S集群') {
            steps {
                script {
                    // 镜像和版本信息
                    def imageEnv = readFile('image.env').trim()
                    def envMap = [:]
                    imageEnv.split('\n').each { line ->
                        def parts = line.split('=', 2)
                        envMap[parts[0]] = parts[1]
                    }
                    def IMAGE = envMap['IMAGE']
                    def PROJECT_VERSION = envMap['PROJECT_VERSION']
                    def CURRENT_BUILD = envMap['BUILD_NUMBER'] as Integer
                    def PREVIOUS_BUILD = CURRENT_BUILD - 1
                    def PROJECT_ARTIFACT_ID = envMap['PROJECT_ARTIFACT_ID']
                    echo "📦 待部署镜像: ${IMAGE}"
                    echo "🔢 当前构建号: ${CURRENT_BUILD}"
                    echo "🔙 上一个构建号: ${PREVIOUS_BUILD}"
                     withCredentials([file(
                         credentialsId: KUBECONFIG_CRED,
                         variable: 'KUBECONFIG_FILE'
                     )]) {
                         // 使用withEnv临时设置KUBECONFIG环境变量(安全且正确的方式)
                         // 无需复制到全局目录,凭证仅在当前代码块内有效
                         withEnv([
                            "KUBECONFIG=${KUBECONFIG_FILE}",
                            "NAMESPACE=${K8SNAMESPACE}",
                            "IMAGE=${IMAGE}",
                            "PROJECT_VERSION=${PROJECT_VERSION}",
                            "CURRENT_BUILD=${CURRENT_BUILD}",
                            "PREVIOUS_BUILD=${PREVIOUS_BUILD}",
                            "PROJECT_ARTIFACT_ID=${PROJECT_ARTIFACT_ID}"
                        ]) {
                            sh '''
                                # Kubeconfig写入方式
                                rm -rf /root/.kube/config
                                mkdir -p /root/.kube
                                cp ${KUBECONFIG_FILE} /root/.kube/config
                                chmod 600 /root/.kube/config
                                # 验证K8S连接
                                echo "🔍 验证K8S集群连接"
                                kubectl cluster-info
                                if [ $? -ne 0 ]; then
                                    echo "❌ K8S集群连接失败,请检查kubeconfig凭证"
                                    exit 1
                                fi
                                # 验证部署文件存在
                                if [ ! -f "${K8S_DEPLOY_FILE}" ]; then
                                    echo "❌ 未找到K8S部署文件: ${K8S_DEPLOY_FILE}"
                                    exit 1
                                fi
                                # 替换部署文件中的变量占位符
                                echo "替换部署文件中的变量占位符"
                                sed -i 's|${IMAGE}|'"${IMAGE}"'|g' "${K8S_DEPLOY_FILE}"
                                # 预览变更
                                echo "即将应用的部署变更:"
                                kubectl diff -f "${K8S_DEPLOY_FILE}" -n ${NAMESPACE} || true
                                # 部署应用
                                echo "开始部署应用到命名空间: ${NAMESPACE}"
                                kubectl apply -f "${K8S_DEPLOY_FILE}" -n ${NAMESPACE}
                                # 部署Service
                                if [ -f "${K8S_SERVICE_FILE}" ]; then
                                    kubectl apply -f "${K8S_SERVICE_FILE}" -n ${NAMESPACE}
                                    echo "Service部署完成"
                                fi
                                # 等待部署完成
                                echo "等待Deployment滚动更新完成"
                                kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE} --timeout=300s
                                if [ $? -eq 0 ]; then
                                    echo "✅ 应用部署成功!"
                                    echo "📊 应用状态:"
                                    kubectl get pods -n ${NAMESPACE} -l app=${DEPLOYMENT_NAME}
                                else
                                    echo "❌ 部署失败,正在自动回滚到上一个稳定版本..."
                                    # ✅ 回滚到上一个构建号的镜像(构建号减1)
                                    PREVIOUS_IMAGE="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${PROJECT_ARTIFACT_ID}:${PROJECT_VERSION}-${PREVIOUS_BUILD}"
                                    echo "🔙 回滚到镜像: ${PREVIOUS_IMAGE}"
                                    # 更新Deployment到上一个版本的镜像
                                    kubectl set image deployment/${DEPLOYMENT_NAME} \
                                        ${DEPLOYMENT_NAME}=${PREVIOUS_IMAGE} \
                                        -n ${NAMESPACE}
                                    # 等待回滚完成
                                    kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE} --timeout=300s
                                    echo "✅ 回滚完成,请检查应用日志"
                                    exit 1
                                fi
                                # 清理临时文件
                                rm -f deploy.tmp.yaml image.env
                                # 删除Kubeconfig(包含K8s认证信息)
                                rm -rf /root/.kube/config
                            '''
                        }
                     }
                }
            }
         }
    }
}

192.168.1.20/toolbox/toolbox-web:v0.0.1

相关推荐
困意少年1 小时前
Linux 进程概念深度解析:从 `task_struct` 到进程状态、优先级、调度与上下文切换
linux·运维
一头老黄牛@2 小时前
飞书 × OpenClaw 接入指南:不用服务器,用长连接把机器人跑起来
数据结构·人工智能·程序人生·算法·决策树·自动化·推荐算法
V搜xhliang024610 小时前
AI智能体的数据安全与合规实践
人工智能·学习·数据分析·自动化·ai编程
杨浦老苏10 小时前
家庭实验室监控仪表盘HomeLab-Monitor
运维·docker·监控·群晖
见合八方10 小时前
【滤波器】用于红外微型光谱仪的可调谐MEMS-FP滤光片-综述
自动化·soa·光通信·激光雷达·半导体光放大器
回忆2012初秋10 小时前
【Nginx】原理、配置与运维实战(2)
运维·nginx·策略模式
Urbano11 小时前
工装外套全制作流程、工序痛点及自动化设备升级方案
运维·自动化
映翰通朱工12 小时前
工业4G网关无公网IP远程运维实战(内网终端异地访问方案)
运维·服务器·网络·安全·智能路由器
洪晓露12 小时前
将 rke2 集群证书延长至 10 年
运维·服务器·数据库