砍材农夫砍材农夫
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • llm wiki

    • 基于karpathy
    • gradle
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • 环境配置
    • 微信生态
    • 正则
    • 全栈技能
  • java圈

    • java基础
    • jdk体系
    • jvm
    • spring框架
    • 分库分表
    • zookeeper
  • python技能

    • python编程
    • python数据
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • AIoT
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • devops
  • 元宇宙
  • 区块链
  • 物联网
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • llm wiki

    • 基于karpathy
    • gradle
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • 环境配置
    • 微信生态
    • 正则
    • 全栈技能
  • java圈

    • java基础
    • jdk体系
    • jvm
    • spring框架
    • 分库分表
    • zookeeper
  • python技能

    • python编程
    • python数据
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • AIoT
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • devops
  • 元宇宙
  • 区块链
  • 物联网
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • nginx

    • nginx日常

      • 概念
      • 常用命令
      • nginx安装和部署
    • nginx实战

      • 基本配置拆解
      • 配置https证书
      • nginx负载配置
    • webUI

      • nginxWebUI
  • linuxs

    • 基础

      • 常用命令
      • grep
      • 防火墙
      • 基础常用命令
      • linux基础常用命令2
      • 配置应用自动启动
      • 自动同步北京时间
      • 防火墙操作
      • ifconfig无ip
      • Rocky-8无网络和局域网无法访问
    • 高级

      • 常用命令
      • vm虚拟机磁盘扩容
      • jdk安装
      • centos7 不显示IP
      • linux分析问题常用命令
      • linux任务管理
      • 权限控制
      • 记录用户操作日志
      • 日常分析问题命令介绍
      • 网络配置
      • cached过高问题
      • 找回删除文件
      • cpu负载突然升高
      • 磁盘爆满查找大文件
      • CentOS7系统配置国内yum源和epel源
    • vi

    • curl

  • docker

    • 基础
      • 安装和配置

        • window相关安装和配置
        • window基础简单操作
        • linux安装
        • 相关概念
      • 相关命令

        • 相关命令
        • docker镜像相关命令
      • 安装实例

        • 安装elasticsearch
        • docker其他常见快速部署
        • docker搭建mysql
        • docker备份mysql
        • docker更改mysql配置
        • docker搭建nexus
      • 其他

        • 镜像的迁移和备份
        • 网络
        • 常见错误集
        • docker部署hdfs
        • docker容器时间和本地时间不一致
        • docker批量操作
    • 日常运维

      • docker实例内文件下载
      • docker仓库搭建(Nexus)
      • docker仓库搭建(Hub)
    • docker-file

      • dockerfile入门
      • dockerfile(java应用)
    • docker-compose

      • docker-compose意义
  • k8s

    • 首页
      • window相关安装和配置
      • window基础简单操作
  • haproxy

    • haproxy部署实战

      • haproxy部署介绍
      • haproxy部署实战
      • haproxy案例分析
  • jenkins

    • 环境部署搭建
    • 自由风格构建应用发布
    • 获取远程git项目|分支选择
    • pipeline构建应用
    • pipeline结合docker构建应用
    • 权限管理
    • web项目构建
    • 集成maven获取远程项目
    • 视图细粒度权限管理
    • 其他日常操作案例
    • 版本升级或重装备份问题
    • 多模块关联关闭
  • prometheus

    • 首页
      • window相关安装和配置
      • window基础简单操作
  • gitlab

    • 首页
      • window相关安装和配置
      • window基础简单操作
  • maven

    • 首页
      • window相关安装和配置
      • window基础简单操作
  • elk

    • openobserve

      • docker部署openobserve
      • 采集器fluent
      • openobserve日常管理使用
  • 运维|devops|Jenkins|Jenkins Pipeline流程构建
    • Jenkins Pipeline
      • Pipeline script vs Pipeline script from SCM(实操)
      • Jenkinsfile 脚本内容的语法格式如下两种
    • 前置条件
      • 服务器端开启ssh登录
      • Jenkinsfile文件和脚本创建
    • 创建Pipeline任务
      • 构建相关pipeline
    • 执行构建结果
    • 优化脚本
      • 优化脚本之后

运维|devops|Jenkins|Jenkins Pipeline流程构建

基于 jenkins Version 2.541.3 实操案例

Jenkins Pipeline

基于 Groovy 的持续交付流水线代码(Pipeline as Code)

Pipeline script vs Pipeline script from SCM(实操)

  • Pipeline script

流水线代码直接粘贴在 Jenkins 任务页面文本框内,存储在 Jenkins 任务配置数据库中,不关联 Git 仓库

  • Pipeline script from SCM

流水线代码(Jenkinsfile)存放在代码仓库 (Git/SVN),Jenkins 运行流水线时先拉取代码,读取仓库内的 Jenkinsfile 执行

Jenkinsfile 脚本内容的语法格式如下两种

  • Declarative Pipeline(声明式-实操):语法严格、易读,适合绝大多数项目
pipeline {
    agent any
    stages {
        stage('构建') {
            steps {
                echo "hello"
            }
        }
    }
}
  • Scripted Pipeline(脚本式):原生 Groovy,自由度高,适合复杂逻辑
node {
    stage('构建') {
        echo "hello"
    }
}

前置条件

git、ssh、jdk、maven 等配置

服务器端开启ssh登录

  • 生成密钥
ssh-keygen -t rsa -b 4096 
  • 将公钥添加到本机的 authorized_keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
  • 配置 SSH 服务(/etc/ssh/sshd_config)
PubkeyAuthentication yes
PasswordAuthentication yes
  • 重启 SSH 服务
sudo systemctl reload sshd
  • 将私钥拷贝到Jenkins全局令牌凭证中

img

Jenkinsfile文件和脚本创建

Jenkinsfile位置放入项目pom同级别

  • 位置参照
Core(仓库根目录|父pom)
├─ pom.xml                聚合父工程
├─ common-core            公共依赖模块(无需Jenkinsfile)
│  └─ pom.xml
├─ Core.Api      业务子模块
│  ├─ pom.xml
│  └─ Jenkinsfile         ✅ 当前模块流水线文件
  • Groovy构建脚本(Jenkinsfile)
pipeline {
    agent any

    options {
        disableConcurrentBuilds()
        timeout(time: 20, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }

    parameters {
        booleanParam(
            name: 'AUTO_DEPLOY',
            defaultValue: false,
            description: '构建完成自动推送Jar并重启远程服务'
        )
    }

    environment {
        SERVICE_DIR = 'app'
        SERVICE_NAME = 'app'
        JAR_VERSION = '1.0.0-SNAPSHOT'
        JAR_FILE = "${SERVICE_NAME}-${JAR_VERSION}.jar"
        REMOTE_SUB_DIR = "${SERVICE_NAME}"
        REMOTE_FULL_DIR = "/usr/local/${REMOTE_SUB_DIR}"
        LOCAL_JAR_PATH = "${SERVICE_DIR}/target/${JAR_FILE}"
        JAVA_HOME = '/usr/local/jdk21'
        M2_HOME = '/usr/local/maven'
        // SSH 配置
        REMOTE_HOST = '192.168.0.66'
        REMOTE_USER = 'test'
        SSH_CREDENTIALS_ID = 'test'
    }

    stages {
        stage('1. 环境信息打印') {
            steps {
                echo "【构建信息】服务名:${env.SERVICE_NAME}|Jar包:${env.JAR_FILE}"
                echo "本地路径:${env.LOCAL_JAR_PATH}"
                echo "远端目录:${env.REMOTE_FULL_DIR}"
            }
        }

        stage('2. Maven编译打包') {
            steps {
                sh '''
                    test -d ${JAVA_HOME} || { echo "❌ JAVA_HOME目录不存在"; exit 1; }
                    test -d ${M2_HOME} || { echo "❌ M2_HOME目录不存在"; exit 1; }
                    ${JAVA_HOME}/bin/java -version
                    ${M2_HOME}/bin/mvn -v
                    cd ${SERVICE_DIR}
                    ${M2_HOME}/bin/mvn clean package -DskipTests
                '''
            }
        }

        stage('3. 归档构建产物') {
            steps {
                archiveArtifacts artifacts: "${env.LOCAL_JAR_PATH}", fingerprint: true, onlyIfSuccessful: true
            }
        }

        stage('4. 远程发布部署') {
            when {
                expression { params.AUTO_DEPLOY }
            }
            steps {
                echo "开始推送Jar包并远程重启服务"

                withCredentials([sshUserPrivateKey(
                    credentialsId: "${env.SSH_CREDENTIALS_ID}",
                    keyFileVariable: 'SSH_KEY',
                    usernameVariable: 'SSH_USER'
                )]) {
                    sh """
                        set -e -x
                        # 传输 JAR
                        scp -i \$SSH_KEY -o StrictHostKeyChecking=no ${LOCAL_JAR_PATH} ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_FULL_DIR}/${JAR_FILE}

                        # 远程执行部署【修复pgrep匹配BUG】
                        ssh -i \$SSH_KEY -o StrictHostKeyChecking=no ${REMOTE_USER}@${REMOTE_HOST} << 'EOF'
                            export JAVA_HOME=/usr/local/jdk-21.0.11
                            SERVICE_NAME=${SERVICE_NAME}
                            REMOTE_FULL_DIR=${REMOTE_FULL_DIR}
                            JAR_FILE=${JAR_FILE}

                            mkdir -p \${REMOTE_FULL_DIR}
                            cd \${REMOTE_FULL_DIR}

                            # 根据服务名杀死进程,不再写死jar名称
                            pkill -f "\${SERVICE_NAME}" || true
                            sleep 1

                            # 后台启动服务
                            nohup \${JAVA_HOME}/bin/java -jar \${JAR_FILE} > app.log 2>&1 &
                            sleep 3

                            # 校验进程:匹配服务名称,不再匹配jar短文件名
                            if pgrep -f "\${SERVICE_NAME}" > /dev/null; then
                                echo "✅ 服务启动成功"
                            else
                                echo "❌ 服务启动失败,打印最近日志"
                                [ -f app.log ] && tail -15 app.log || echo "app.log 文件尚未生成"
                                exit 1
                            fi
EOF
                    """
                }

                echo "远程部署流程执行完毕"
            }
        }
    }

    post {
        always {
            echo "【Post钩子】流水线构建结束"
        }
        success {
            cleanWs()
            echo "🎉 流水线全部执行成功!"
        }
        failure {
            echo "💥 流水线执行失败,请查看日志排查问题!"
        }
    }
}

创建Pipeline任务

img

img

构建相关pipeline

img

img

  • 脚本指向路径 img

执行构建结果

img

优化脚本

增加git 打印、和后台应用日志

pipeline {
    agent any

    options {
        disableConcurrentBuilds()
        timeout(time: 20, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }

    parameters {
        booleanParam(
            name: 'AUTO_DEPLOY',
            defaultValue: false,
            description: '构建完成自动推送Jar并重启远程服务'
        )
    }

    environment {
        SERVICE_DIR = 'app'
        SERVICE_NAME = 'app'
        JAR_VERSION = '1.0.0-SNAPSHOT'
        JAR_FILE = "${SERVICE_NAME}-${JAR_VERSION}.jar"
        REMOTE_SUB_DIR = "${SERVICE_NAME}"
        REMOTE_FULL_DIR = "/usr/local/${REMOTE_SUB_DIR}"
        LOCAL_JAR_PATH = "${SERVICE_DIR}/target/${JAR_FILE}"
        JAVA_HOME = '/usr/local/jdk21'
        M2_HOME = '/usr/local/maven'
        REMOTE_HOST = '192.168.0.66'
        REMOTE_USER = 'test'
        SSH_CREDENTIALS_ID = 'test'
    }

    stages {
        stage('1. 环境信息 & Git提交日志打印') {
            steps {
                sh '''#!/bin/bash
                    echo "==================== Git 最新提交信息 ===================="
                    echo "短提交号: $(git rev-parse --short HEAD)"
                    echo "完整commit: $(git rev-parse HEAD)"
                    echo "提交人姓名: $(git log -1 --pretty=%an)"
                    echo "提交备注:"
                    git log -1 --pretty=%B
                    echo "=========================================================="
                '''

                echo "【构建信息】服务名:${env.SERVICE_NAME}|Jar包:${env.JAR_FILE}"
                echo "本地路径:${env.LOCAL_JAR_PATH}"
                echo "远端目录:${env.REMOTE_FULL_DIR}"
            }
        }

        stage('2. Maven编译打包') {
            steps {
                sh '''#!/bin/bash
                    test -d ${JAVA_HOME} || { echo "❌ JAVA_HOME目录不存在"; exit 1; }
                    test -d ${M2_HOME} || { echo "❌ M2_HOME目录不存在"; exit 1; }
                    ${JAVA_HOME}/bin/java -version
                    ${M2_HOME}/bin/mvn -v
                    cd ${SERVICE_DIR}
                    ${M2_HOME}/bin/mvn clean package -DskipTests
                '''
            }
        }

        stage('3. 归档构建产物') {
            steps {
                archiveArtifacts artifacts: "${env.LOCAL_JAR_PATH}", fingerprint: true, onlyIfSuccessful: true
            }
        }

        stage('4. 远程发布部署') {
            when {
                expression { params.AUTO_DEPLOY }
            }
            steps {
                echo "开始推送Jar包并远程重启服务"

                withCredentials([sshUserPrivateKey(
                    credentialsId: "${env.SSH_CREDENTIALS_ID}",
                    keyFileVariable: 'SSH_KEY',
                    usernameVariable: 'SSH_USER'
                )]) {
                    // ===== 使用三双引号 """ 允许Groovy解析Jenkins环境变量 =====
                    sh """#!/bin/bash
                        set -e -x
                        scp -i \$SSH_KEY -o StrictHostKeyChecking=no ${LOCAL_JAR_PATH} ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_FULL_DIR}/${JAR_FILE}

                        ssh -i \$SSH_KEY -o StrictHostKeyChecking=no ${REMOTE_USER}@${REMOTE_HOST} << EOF
                            SERVICE_NAME=${SERVICE_NAME}
                            REMOTE_FULL_DIR=${REMOTE_FULL_DIR}
                            JAR_FILE=${JAR_FILE}

                            mkdir -p \${REMOTE_FULL_DIR}
                            cd \${REMOTE_FULL_DIR}

                            echo "【1】优雅停止旧服务进程"
                            pgrep -f "java.*\${SERVICE_NAME}" | xargs kill -15 2>/dev/null || true
                            sleep 2
                            pgrep -f "java.*\${SERVICE_NAME}" | xargs kill -9 2>/dev/null || true
                            sleep 1

                            echo "【2】启动新服务 >> 追加日志,不再清空日志文件"
                            # 远端服务器JAVA路径【硬编码】,彻底避开变量冲突大坑
                            nohup /usr/local/jdk-21.0.11/bin/java -Dfile.encoding=UTF-8 -jar \${JAR_FILE} >> app.log 2>&1 &
                            sleep 3

                            echo "========== 远端应用启动日志(尾部30行) =========="
                            [ -f app.log ] && tail -30 app.log || echo "app.log 文件尚未生成"
                            echo "===================================================="

                            echo "【3】校验进程状态"
                            if pgrep -f "java.*\${SERVICE_NAME}" > /dev/null; then
                                echo "✅ 服务进程启动成功"
                            else
                                echo "❌ 服务启动失败!"
                                exit 1
                            fi
EOF
                    """
                }

                echo "远程部署流程执行完毕"
            }
        }
    }

    post {
        always {
            echo "【Post钩子】流水线构建结束"
        }
        success {
            cleanWs()
            echo "🎉 流水线全部执行成功!"
        }
        failure {
            echo "💥 流水线执行失败,请查看日志排查问题!"
        }
    }
}

优化脚本之后

imgimg

最近更新: 2026/7/31 20:12
Contributors: kcnf
Prev
获取远程git项目|分支选择
Next
pipeline结合docker构建应用