Jenkins + Kubernetes 多模块微服务一键流水线:从 Maven 打包到滚动发布完整脚本

文章简介

  • 上次写过一篇使用 Jenkins 在远程服务器上部署 docker 镜像的通用脚本,这次这份脚本是基于上次那份脚本修改而来,用于 Kubernetes 部署镜像使用。
  • Kubernetes 部署相关信息可以查看这篇文章:Kubernetes 生产入门:Deployment 与 Service 配置实战
  • 本文介绍的部署脚本适用于单工程下多 module 的微服务,单工程服务需要阅读脚本自行微调。不过我建议使用本文脚本的每一位朋友都能够阅读所有的代码,确定是否符合自己的需求。

脚本变量

  • 定义、设置变量主要是为了形成一个通用型脚本,部署多个服务尤其微服务时,编写好一个流水线脚本,其他流水线可以直接复制使用,复制后只需修改此处变量即可。
  • 此处有部分变量嵌套使用 MODULE_NAME、MODULE_PATH 变量复用相同参数,使用本文脚本的朋友一定要观察此处的变量是否与你们工程一致。
  • 具体参数信息代码中已有注释,不过多赘述
ini 复制代码
environment {
    // 模块信息
    MODULE_NAME = "xxx-service" // 模块名称
    MODULE_PATH = "./${MODULE_NAME}" // 模块路径,适用于微服务多 module
    // Git 仓库配置
    GIT_URL = 'git@git.xxx.com:xxx.git' // 替换为你的代码仓库
    GIT_KEY_ACR_CRED = 'git-ssh-key'
    BRANCH = 'master'
    // Docker 镜像相关配置
    DOCKER_IMAGE_REGISTRY = 'registry.xxx.aliyuncs.com'  // 替换为你的镜像仓库
    DOCKER_IMAGE_ACR_CRED = 'docker-cred'
    IMAGE_PRE_NAME = 'xxxx'  // 镜像名称前缀
    IMAGE_NAME = "${MODULE_NAME}"  // 镜像名称
    DOCKERFILE = "${MODULE_PATH}/Dockerfile" // 用来构建镜像的 dockerfile 文件
    // Kubernetes 相关配置
    KUBERNETES_CONFIG = "kubernetes-config" // Kubernetes 配置文件凭证
    RESOURCE_NAME = "${MODULE_NAME}" // 资源类型名称,这里为 deployment 名称
    CONTAINER_NAME = "${MODULE_NAME}" // 容器名称
}

工具设置

这里设置构建代码的 Maven 工具

groovy 复制代码
tools {
    // Install the Maven version configured as "M3" and add it to the path.
    maven "Maven3"
}

拉取代码

拉取仓库中的代码

  • git branch: BRANCH:指定拉取的分支
  • url: GIT_URL,设置代码仓库地址
  • credentialsId:仓库访问凭据
groovy 复制代码
stage('Checkout') {
    steps {
        git branch: BRANCH, 
        url: GIT_URL,
        credentialsId: GIT_KEY_ACR_CRED
    }
}

打包

由于是多 module 多微服务项目,此处使用 mvn 指定模块打包命令,防止构建不相关模块,且指定为 pro 配置

groovy 复制代码
stage('Package') {
    steps {
        // 执行 Maven 打包命令,只打包指定模块
        sh "mvn -pl ${MODULE_PATH} -am -B clean package -Ppro -Dfile.encoding=UTF-8 -DskipTests=true"
    }
}

构建、推送 Docker 镜像,删除本地镜像

  • 此处使用当前时间为镜像设置 tag
  • 镜像名称格式:<镜像仓库地址>/<镜像名称前缀>/<应用名称>:<当前时间>
  • sh "docker build -t ${fullImageNameWithTimestamp} ."
    • 使用 docker 构建镜像
  • withCredentials 使用凭据登陆、推送镜像
    • 登陆仓库: sh "docker login --username REG_USER -p REG_PASS $DOCKER_IMAGE_REGISTRY"
    • 推送镜像:sh "docker push ${fullImageNameWithTimestamp}"
    • 删除本地镜像:sh "docker rmi ${fullImageNameWithTimestamp}"
    • 将镜像名称保存到环境变量,供后续步骤使用:env.BUILT_IMAGE = fullImageNameWithTimestamp
groovy 复制代码
stage('Build Docker Image') {
    steps {
        script {
    
            // 生成时间戳
            def timestamp = new Date().format('yyyyMMddHHmm', TimeZone.getTimeZone('Asia/Shanghai'))
            def imageTag = "${IMAGE_NAME}:${timestamp}"
            def fullImageNameWithTimestamp = "${DOCKER_IMAGE_REGISTRY}/${IMAGE_PRE_NAME}/${imageTag}"
    
            // 使用 Docker 构建镜像
            echo "Building Docker image: ${fullImageNameWithTimestamp}"
            sh "docker build -t ${fullImageNameWithTimestamp} -f ${DOCKERFILE} ${MODULE_PATH}"
    
            withCredentials([usernamePassword(credentialsId: DOCKER_IMAGE_ACR_CRED, usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
                // 登录到镜像仓库
                echo "Login Docker..."
                sh "docker login --username $REG_USER -p $REG_PASS ${DOCKER_IMAGE_REGISTRY}"
                // 推送镜像
                echo "Push Docker Image ${fullImageNameWithTimestamp}"
                sh "docker push ${fullImageNameWithTimestamp}"
                // 推送完成后,删除本地镜像
                echo "Remove Docker Imag ${fullImageNameWithTimestamp}"
                sh "docker rmi ${fullImageNameWithTimestamp}"
            }
            
            // 输出构建信息
            echo "Successfully built and pushed image: ${fullImageNameWithTimestamp}"
            
            // 将镜像名称保存到环境变量,供后续步骤使用
            env.BUILT_IMAGE = fullImageNameWithTimestamp
        }
    }
}

部署到远程 Kubernetes 集群

  • withCredentials:使用凭据连接 Kubernetes 集群
  • 设置集群连接配置:sh "export KUBECONFIG=$KUBECONFIG"
  • 设置集群对应 Deployment 中的镜像信息:sh "kubectl set image deployment/ <math xmlns="http://www.w3.org/1998/Math/MathML"> R E S O U R C E N A M E {RESOURCE_NAME} </math>RESOURCENAME{CONTAINER_NAME}=${BUILT_IMAGE}"
  • 备注:Kubernetes 集群中 Deployment 配置内镜像信息修改后,集群会自行拉起新的 Pod,关闭旧的 Pod。
groovy 复制代码
stage('Deploy to Remote Kubernetes') {
    steps {
        script {
            withCredentials([file(credentialsId: KUBERNETES_CONFIG, variable: 'KUBECONFIG')]) {
                // 设置KUBECONFIG环境变量
                sh "export KUBECONFIG=$KUBECONFIG" 
                // 更新Deployment中的镜像信息
                // kubectl set image <资源类型>/<资源名称> <容器名称>=<新镜像>:<标签>
                sh "kubectl set image deployment/${RESOURCE_NAME} ${CONTAINER_NAME}=${BUILT_IMAGE}" 
            } 
        }
    }
}

附源码

groovy 复制代码
pipeline {
    agent any

    environment {
        // 模块信息
        MODULE_NAME = "xxx-servcie" // 模块名称
        MODULE_PATH = "./${MODULE_NAME}" // 模块路径,适用于微服务多 module
        // Git 仓库配置
        GIT_URL = 'git@git.xxx.com:xxx.git' // 替换为你的代码仓库
        GIT_KEY_ACR_CRED = 'git-ssh-key'
        BRANCH = 'master'
        // Docker 镜像相关配置
        DOCKER_IMAGE_REGISTRY = 'registry.xxx.aliyuncs.com'  // 替换为你的镜像仓库
        DOCKER_IMAGE_ACR_CRED = 'docker-cred'
        IMAGE_PRE_NAME = 'xxxx'  // 镜像名称前缀
        IMAGE_NAME = "${MODULE_NAME}"  // 镜像名称
        DOCKERFILE = "${MODULE_PATH}/Dockerfile" // 用来构建镜像的 dockerfile 文件
        // Kubernetes 相关配置
        KUBERNETES_CONFIG = "kubernetes-config" // Kubernetes 配置文件凭证
        RESOURCE_NAME = "${MODULE_NAME}" // 资源类型名称,这里为 deployment 名称
        CONTAINER_NAME = "${MODULE_NAME}" // 容器名称
    }

    tools {
        // Install the Maven version configured as "M3" and add it to the path.
        maven "Maven3"
    }

    stages {

        stage('Checkout') {
            steps {
                git branch: BRANCH, 
                url: GIT_URL,
                credentialsId: GIT_KEY_ACR_CRED
            }
        }

        stage('Package') {
            steps {
                // 执行 Maven 打包命令,只打包指定模块
                sh "mvn -pl ${MODULE_PATH} -am -B clean package -Ppro -Dfile.encoding=UTF-8 -DskipTests=true"
            }
        }

        stage('Build Docker Image') {
            steps {
                script {

                    // 生成时间戳
                    def timestamp = new Date().format('yyyyMMddHHmm', TimeZone.getTimeZone('Asia/Shanghai'))
                    def imageTag = "${IMAGE_NAME}:${timestamp}"
                    def fullImageNameWithTimestamp = "${DOCKER_IMAGE_REGISTRY}/${IMAGE_PRE_NAME}/${imageTag}"

                    // 使用 Docker 构建镜像
                    echo "Building Docker image: ${fullImageNameWithTimestamp}"
                    sh "docker build -t ${fullImageNameWithTimestamp} -f ${DOCKERFILE} ${MODULE_PATH}"

                    withCredentials([usernamePassword(credentialsId: DOCKER_IMAGE_ACR_CRED, usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
                        // 登录到镜像仓库
                        echo "Login Docker..."
                        sh "docker login --username $REG_USER -p $REG_PASS ${DOCKER_IMAGE_REGISTRY}"
                        // 推送镜像
                        echo "Push Docker Image ${fullImageNameWithTimestamp}"
                        sh "docker push ${fullImageNameWithTimestamp}"
                        // 推送完成后,删除本地镜像
                        echo "Remove Docker Imag ${fullImageNameWithTimestamp}"
                        sh "docker rmi ${fullImageNameWithTimestamp}"
                    }
                    
                    // 输出构建信息
                    echo "Successfully built and pushed image: ${fullImageNameWithTimestamp}"
                    
                    // 将镜像名称保存到环境变量,供后续步骤使用
                    env.BUILT_IMAGE = fullImageNameWithTimestamp
                }
            }
        }


        stage('Deploy to Remote Kubernetes') {
            steps {
                script {
                    withCredentials([file(credentialsId: KUBERNETES_CONFIG, variable: 'KUBECONFIG')]) {
                        // 设置KUBECONFIG环境变量
                        sh "export KUBECONFIG=$KUBECONFIG" 
                        // 更新Deployment中的镜像
                        // kubectl set image <资源类型>/<资源名称> <容器名称>=<新镜像>:<标签>
                        sh "kubectl set image deployment/${RESOURCE_NAME} ${CONTAINER_NAME}=${BUILT_IMAGE}" 
                    } 
                }
            }
        }


    }
}
相关推荐
2501_9418814013 小时前
Kubernetes 容器集群资源调度与弹性扩容高可用架构在互联网业务实战经验总结
云原生·容器·kubernetes
究極の法則に通じた野犬13 小时前
k8s设计理念-k8s中哪些服务要部署成StatefulSet哪些部署成Deployment
云原生·容器·kubernetes
wuxingge13 小时前
k8s集群误删node节点,怎么添加回去
云原生·容器·kubernetes
观测云17 小时前
Kubernetes CRD 方式配置容器日志采集最佳实践
容器·kubernetes·日志分析
star_111219 小时前
Jenkins部署后端springboot微服务项目
spring boot·微服务·jenkins
运维-大白同学1 天前
2025最全面开源devops运维平台功能介绍
linux·运维·kubernetes·开源·运维开发·devops
敲上瘾1 天前
【探索实战】:Kurator分布式统一应用分发平台的全面解析与实践指南
分布式·容器·kubernetes·serverless
Connie14512 天前
记一次K8s故障告警排查(Grafna告警排查)
云原生·容器·kubernetes·grafana
谷隐凡二2 天前
Kubernetes主从架构简单解析:基于Python的模拟实现
python·架构·kubernetes