jenkins声明式pipline和shell从环境变量配置到打包构建再到发布到k8s

shell

shell 复制代码
mvn clean package -U -DskipTests=true
JAR_NAME=hotel-directsales-data-web.jar
JAR_DIR=hotel-directsales-data-web
SHORT_COMMIT_ID=${GIT_COMMIT:0:7}
Image_Name=hotel-directsales-data-sync
Image_Repository=aliyun-regirest-vpc.cn-shanghai.personal.cr.aliyuncs.com/tengrong-pro/xinlimei
short_branch=$(echo "$GIT_BRANCH" | awk -F'/' '{print $2}')
Image=$Image_Repository:$Image_Name-$short_branch-$SHORT_COMMIT_ID
Deployment=hotel-directsales-data-sync
NameSpace=pro
PODNUM=5
PodPort=8080
SKYWALKING_URL="aliyun-skywalking:8000"
SKYWALKING_AUTH="aliyun-skywalking-secret"
APOLLO_URL="http://apollo.com.cn  "
EurekaUrl="k8s-eureka.com.cn:8761"
cpuLimit=4
memoryLimit=10241Mi
cpuRequest=1
memoryRequest=6144Mi
HEAP="-Xms4g -Xmx4g \
-Dserver.port=8080 \
-Deureka.client.serviceUrl.defaultZone=http://k8s-eureka.com.cn:8761/eureka/   \
-Dxxl.job.admin.addresses=http://k8s-xxljob.com.cn/   \
-Drocketmq.name-server=rocketmq-namesrv.com.cn:19876 \
-Dspring.activemq.broker-url=failover:(tcp://activemq.com.cn:61616) "
ENVIROMENT="pro"
#cd到项目目录下
cd $JAR_DIR
#拷贝Dockerfile文件
cp -rf /data/Dockerfile-pro/Dockerfile-xlm ./Dockerfile
#构建镜像
docker build \
--build-arg APOLLO_URL="$APOLLO_URL" \
--build-arg SKYWALKING_URL="$SKYWALKING_URL" \
--build-arg SKYWALKING_AUTH="$SKYWALKING_AUTH" \
--build-arg JAVA_NAME_ARG="$JAR_NAME" \
--build-arg SERVICE_NAME="$Deployment" \
--build-arg HEAP="$HEAP" \
--build-arg ENVIROMENT="$ENVIROMENT"  \
-t $Image .
#替换资源模版变量
cp /data/Dockerfile-pro/xinlimei-template-k8s-memory.yml ./application.yml
sed -i "s/ProjectName/$Deployment/g" application.yml
sed -i "s#imageName#$Image#g" application.yml
sed -i "s/NameSpace/$NameSpace/g" application.yml
sed -i "s/PODNUM/$PODNUM/g" application.yml
sed -i "s/PodPort/$PodPort/g" application.yml
sed -i "s/EurekaUrl/$EurekaUrl/g" application.yml
sed -i "s/cpuLimit/$cpuLimit/g" application.yml
sed -i "s/memoryLimit/$memoryLimit/g" application.yml
sed -i "s/cpuRequest/$cpuRequest/g" application.yml
sed -i "s/memoryRequest/$memoryRequest/g" application.yml
cat application.yml
#推送镜像
docker push $Image
#滚动更新
kubectl --kubeconfig=/data/Dockerfile-pro/pro-kube/config -n $NameSpace apply -f application.yml
#健康检查
kubectl --kubeconfig=/data/Dockerfile-pro/pro-kube/config -n $NameSpace rollout status --timeout=480s deployment/$Deployment

pipline

pipline 复制代码
pipeline {
    // 使用任意可用的agent执行
    agent any
    
    // 定义环境变量,这些变量将在整个Pipeline中使用
    environment {
        // ========== 项目配置 ==========
        // JAR包名称
        JAR_NAME = 'hotel-directsales-data-web.jar'
        // 项目目录名
        JAR_DIR = 'hotel-directsales-data-web'
        // 镜像基础名称
        Image_Name = 'hotel-directsales-data-sync'
        // 阿里云镜像仓库地址
        Image_Repository = 'aliyun-regirest-vpc.cn-shanghai.personal.cr.aliyuncs.com/tengrong-pro/xinlimei'
        // Kubernetes部署名称
        Deployment = 'hotel-directsales-data-sync'
        // Kubernetes命名空间
        NameSpace = 'pro'
        // Pod副本数量
        PODNUM = '5'
        // 容器端口
        PodPort = '8080'
        
        // ========== SkyWalking APM配置 ==========
        // SkyWalking服务地址,用于链路追踪
        SKYWALKING_URL = 'aliyun-skywalking:8000'
        // SkyWalking认证信息(secret名称)
        SKYWALKING_AUTH = 'aliyun-skywalking-secret'
        
        // ========== 中间件配置 ==========
        // Apollo配置中心地址
        APOLLO_URL = 'http://apollo.com.cn'
        // Eureka注册中心地址
        EurekaUrl = 'k8s-eureka.com.cn:8761'
        
        // ========== K8s资源限制配置 ==========
        // CPU限制(最大可用)
        cpuLimit = '4'
        // 内存限制(最大可用)
        memoryLimit = '10241Mi'
        // CPU请求(最小保证)
        cpuRequest = '1'
        // 内存请求(最小保证)
        memoryRequest = '6144Mi'
        
        // ========== JVM及Java应用参数 ==========
        // Java堆内存设置及服务配置
        HEAP = '-Xms4g -Xmx4g -Dserver.port=8080 -Deureka.client.serviceUrl.defaultZone=http://k8s-eureka.com.cn:8761/eureka/ -Dxxl.job.admin.addresses=http://k8s-xxljob.com.cn/ -Drocketmq.name-server=rocketmq-namesrv.com.cn:19876 -Dspring.activemq.broker-url=failover:(tcp://activemq.com.cn:61616)'
        
        // 运行环境标识
        ENVIROMENT = 'pro'
        
        // ========== 动态生成的变量(将在Pipeline中赋值) ==========
        // 短提交ID(Git commit前7位)
        SHORT_COMMIT_ID = ''
        // 短分支名(去掉origin/前缀)
        short_branch = ''
        // 完整镜像标签
        Image = ''
    }
    
    // 选项配置
    options {
        // 构建历史保留策略:保留最近10个构建
        buildDiscarder(logRotator(numToKeepStr: '10'))
        // 禁止并发构建,防止资源冲突
        disableConcurrentBuilds()
        // 控制台输出带时间戳
        timestamps()
        // Pipeline超时设置为30分钟
        timeout(time: 30, unit: 'MINUTES')
    }
    
    // 定义构建触发器(可选,根据需要启用)
    triggers {
        // 每15分钟检查一次代码变更(轮询SCM)
        // pollSCM('H/15 * * * *')
    }
    
    // 构建阶段定义
    stages {
        // ========== 阶段1:初始化与变量准备 ==========
        stage('初始化环境') {
            steps {
                script {
                    // 获取Git提交ID前7位作为版本标识
                    env.SHORT_COMMIT_ID = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown"
                    
                    // 提取短分支名:去掉origin/前缀,只保留分支名
                    // 例如:origin/release/1.0 -> release/1.0
                    if (env.GIT_BRANCH) {
                        def branchParts = env.GIT_BRANCH.split('/')
                        if (branchParts.length > 1) {
                            // 去掉第一个元素(origin),用剩下的部分重新组合
                            env.short_branch = branchParts[1..-1].join('/')
                        } else {
                            env.short_branch = env.GIT_BRANCH
                        }
                    } else {
                        env.short_branch = "unknown"
                    }
                    
                    // 组合完整的镜像地址:仓库/命名空间:镜像名-分支-提交ID
                    env.Image = "${env.Image_Repository}:${env.Image_Name}-${env.short_branch}-${env.SHORT_COMMIT_ID}"
                    
                    // 打印关键变量用于调试
                    echo "=========================================="
                    echo "Git分支: ${env.GIT_BRANCH}"
                    echo "短分支名: ${env.short_branch}"
                    echo "提交ID: ${env.SHORT_COMMIT_ID}"
                    echo "构建镜像: ${env.Image}"
                    echo "=========================================="
                }
            }
        }
        
        // ========== 阶段2:Maven编译打包 ==========
        stage('Maven构建') {
            steps {
                // 进入项目子目录执行构建
                dir("${env.JAR_DIR}") {
                    // 使用Maven构建
                    // clean: 清理目标目录
                    // package: 打包
                    // -U: 强制更新依赖快照
                    // -DskipTests=true: 跳过测试加速构建(生产环境建议开启测试)
                    sh '''
                        mvn clean package -U -DskipTests=true
                    '''
                }
            }
        }
        
        // ========== 阶段3:Docker镜像构建 ==========
        stage('构建Docker镜像') {
            steps {
                dir("${env.JAR_DIR}") {
                    script {
                        // 拷贝生产环境Dockerfile到项目目录
                        sh 'cp -rf /data/Dockerfile-pro/Dockerfile-xlm ./Dockerfile'
                        
                        // 构建Docker镜像,通过build-arg传递配置参数
                        // 这些参数将在Dockerfile中用于配置Java应用
                        sh """
                            docker build \\
                                --build-arg APOLLO_URL="${env.APOLLO_URL}" \\
                                --build-arg SKYWALKING_URL="${env.SKYWALKING_URL}" \\
                                --build-arg SKYWALKING_AUTH="${env.SKYWALKING_AUTH}" \\
                                --build-arg JAVA_NAME_ARG="${env.JAR_NAME}" \\
                                --build-arg SERVICE_NAME="${env.Deployment}" \\
                                --build-arg HEAP="${env.HEAP}" \\
                                --build-arg ENVIROMENT="${env.ENVIROMENT}" \\
                                -t ${env.Image} .
                        """
                    }
                }
            }
        }
        
        // ========== 阶段4:K8s部署模板处理 ==========
        stage('生成K8s部署配置') {
            steps {
                dir("${env.JAR_DIR}") {
                    script {
                        // 拷贝K8s模板文件到项目目录
                        sh 'cp /data/Dockerfile-pro/xinlimei-template-k8s-memory.yml ./application.yml'
                        
                        // 使用sed替换模板中的占位符变量
                        // 注意:使用#作为分隔符避免URL中的/冲突
                        sh """
                            sed -i "s/ProjectName/${env.Deployment}/g" application.yml
                            sed -i "s#imageName#${env.Image}#g" application.yml
                            sed -i "s/NameSpace/${env.NameSpace}/g" application.yml
                            sed -i "s/PODNUM/${env.PODNUM}/g" application.yml
                            sed -i "s/PodPort/${env.PodPort}/g" application.yml
                            sed -i "s/EurekaUrl/${env.EurekaUrl}/g" application.yml
                            sed -i "s/cpuLimit/${env.cpuLimit}/g" application.yml
                            sed -i "s/memoryLimit/${env.memoryLimit}/g" application.yml
                            sed -i "s/cpuRequest/${env.cpuRequest}/g" application.yml
                            sed -i "s/memoryRequest/${env.memoryRequest}/g" application.yml
                        """
                        
                        // 打印生成的K8s配置用于审查
                        echo "========== 生成的K8s部署配置 =========="
                        sh 'cat application.yml'
                        echo "======================================="
                    }
                }
            }
        }
        
        // ========== 阶段5:镜像推送 ==========
        stage('推送镜像到仓库') {
            steps {
                script {
                    // 将构建好的镜像推送到阿里云私有镜像仓库
                    // 需要确保Jenkins节点已配置镜像仓库登录凭证(docker login)
                    sh "docker push ${env.Image}"
                    
                    // 可选:清理本地镜像释放空间
                    // sh "docker rmi ${env.Image} || true"
                }
            }
        }
        
        // ========== 阶段6:Kubernetes部署 ==========
        stage('部署到K8s集群') {
            steps {
                dir("${env.JAR_DIR}") {
                    script {
                        // 使用kubectl apply部署到Kubernetes集群
                        // 指定kubeconfig文件路径和命名空间
                        sh """
                            kubectl --kubeconfig=/data/Dockerfile-pro/pro-kube/config \\
                                -n ${env.NameSpace} \\
                                apply -f application.yml
                        """
                    }
                }
            }
        }
        
        // ========== 阶段7:部署验证与健康检查 ==========
        stage('健康检查') {
            steps {
                script {
                    // 使用kubectl rollout status检查部署状态
                    // 等待Deployment滚动更新完成,超时时间为480秒(8分钟)
                    // 会检查Pod是否成功创建并达到就绪状态
                    sh """
                        kubectl --kubeconfig=/data/Dockerfile-pro/pro-kube/config \\
                            -n ${env.NameSpace} \\
                            rollout status \\
                            --timeout=480s \\
                            deployment/${env.Deployment}
                    """
                    
                    echo "✅ 部署成功!应用已在Kubernetes集群中正常运行。"
                }
            }
        }
    }
    
    // ========== 后置处理 ==========
    post {
        // 无论构建成功与否都执行
        always {
            script {
                // 清理工作区(可选,根据磁盘空间需求决定)
                // cleanWs()
                
                echo "Pipeline执行完成,构建结果: ${currentBuild.currentResult}"
            }
        }
        
        // 构建成功时执行
        success {
            script {
                echo "🎉 构建部署成功!"
                echo "部署镜像: ${env.Image}"
                echo "K8s部署: ${env.Deployment}"
                echo "命名空间: ${env.NameSpace}"
                
                // 可以在这里添加通知,如钉钉/企业微信/邮件等
                // dingtalk(
                //     robot: 'jenkins-robot',
                //     type: 'MARKDOWN',
                //     title: '部署成功通知',
                //     text: "${env.Deployment} 部署成功\n镜像: ${env.Image}"
                // )
            }
        }
        
        // 构建失败时执行
        failure {
            script {
                echo "❌ 构建失败,请检查日志定位问题"
                
                // 可以在这里添加失败通知
                // 钉钉/企业微信/Slack通知等
            }
        }
        
        // 构建不稳定时执行(如测试失败但构建成功)
        unstable {
            script {
                echo "⚠️ 构建状态不稳定"
            }
        }
        
        // 构建被中止时执行
        aborted {
            script {
                echo "🛑 构建被手动中止"
            }
        }
    }
}

deployment优雅上下线(nacos)

yaml 复制代码
[root@jenkins Dockerfile-pro]# cat template-k8s.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: ProjectName
  name: ProjectName
  namespace: NameSpace
spec:
  progressDeadlineSeconds: 600
  replicas: PODNUM
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: ProjectName
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: ProjectName
      annotations:
        alibabacloud.com/burst-resource: eci
    spec:
      containers:
        - env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.podIP
            - name: PODNAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_PORT
              value: 'PodPort'
            - name: POD_NAME
              value: Nacos_AppName
            - name: NAMESPACE_ID
              value: NAMESPACEID
            - name: NACOS_URL
              value: 'NacosUrl'
          name: ProjectName
          ports:
            - containerPort: PodPort
              name: app-port-PodPort
              protocol: TCP
          image: imageName
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command:
                  - /bin/sh
                  - '-c'
                  - >-
                    curl -X PUT
                    "${NACOS_URL}/nacos/v2/ns/instance?serviceName=${POD_NAME}&ip=${POD_IP}&port=${POD_PORT}&ephemeral=true&weight=0&namespaceId=${NAMESPACE_ID}"
                    & sleep 5
                    curl -X PUT
                    "${NACOS_URL}/nacos/v2/ns/instance?serviceName=${POD_NAME}&ip=${POD_IP}&port=${POD_PORT}&ephemeral=true&weight=0&namespaceId=${NAMESPACE_ID}"
                    & sleep 5
                    curl -X PUT
                    "${NACOS_URL}/nacos/v2/ns/instance?serviceName=${POD_NAME}&ip=${POD_IP}&port=${POD_PORT}&ephemeral=true&weight=0&namespaceId=${NAMESPACE_ID}"
                    & sleep 35
          livenessProbe:
            failureThreshold: 10
            initialDelaySeconds: 50
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: PodPort
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 10
            initialDelaySeconds: 50
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: PodPort
            timeoutSeconds: 1
          resources:
            limits:
              cpu: 'cpuLimit'
              memory: memoryLimit
            requests:
              cpu: 'cpuRequest'
              memory: memoryRequest
          volumeMounts:
            - name: localtime
              mountPath: /etc/localtime
      dnsPolicy: ClusterFirst
      imagePullSecrets:
        - name: aliyun-pro-register
      restartPolicy: Always
      terminationGracePeriodSeconds: 120
      volumes:
        - hostPath:
            path: /etc/localtime
            type: ''
          name: localtime

deployment优雅上下线(eureka)

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: ProjectName
  name: ProjectName
  namespace: NameSpace
spec:
  progressDeadlineSeconds: 600
  replicas: PODNUM
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: ProjectName
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: ProjectName
      annotations:
        alibabacloud.com/burst-resource: eci
    spec:
      containers:
        - env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.podIP
            - name: PODNAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_PORT
              value: 'PodPort'
            - name: POD_NAME
              value: ProjectName
            - name: EUREKA_URL
              value: 'EurekaUrl'
          name: ProjectName
          ports:
            - containerPort: PodPort
              name: app-port-PodPort
              protocol: TCP
          image: imageName
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command:
                  - /bin/sh
                  - '-c'
                  - |
                    curl -X PUT "${EUREKA_URL}/eureka/apps/${POD_NAME}/${POD_IP}:${POD_PORT}/status?value=OUT_OF_SERVICE"
                    sleep 45
                    sleep 15
          livenessProbe:
            failureThreshold: 10
            initialDelaySeconds: 50
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: PodPort
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 10
            initialDelaySeconds: 50
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: PodPort
            timeoutSeconds: 1
          resources:
            limits:
              cpu: 'cpuLimit'
              memory: memoryLimit
            requests:
              cpu: 'cpuRequest'
              memory: memoryRequest
          volumeMounts:
            - mountPath: /etc/localtime
              name: volume-localtime
      dnsPolicy: ClusterFirst
      imagePullSecrets:
        - name: aliyun-pro-register
      restartPolicy: Always
      terminationGracePeriodSeconds: 120
      volumes:
        - hostPath:
            path: /etc/localtime
            type: ''
          name: volume-localtime
相关推荐
SelectDB16 小时前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode2 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220703 天前
如何搭建本地yum源(上)
运维
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质6 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工6 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智6 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_6 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉6 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造