运维|devops|Jenkins Pipeline流程构建 目录1. 运维|devops|Jenkins Pipeline流程构建1.1 Jenkins Pipeline1.1.1 Pipeline script vs Pipeline script from SCM(实操)1.1.2 Jenkinsfile 脚本内容的语法格式如下两种1.2 前置条件1.2.1 服务器端开启ssh登录1.2.2 Jenkinsfile文件和脚本创建1.3 创建Pipeline任务1.3.1 构建相关pipeline1.4 执行构建结果1.5 优化脚本1.5.1 优化脚本之后基于 jenkins Version 2.541.3 实操案例Jenkins Pipeline基于 Groovy 的持续交付流水线代码Pipeline as CodePipeline script vs Pipeline script from SCM(实操)Pipeline script流水线代码直接粘贴在 Jenkins 任务页面文本框内存储在 Jenkins 任务配置数据库中不关联 Git 仓库Pipeline script from SCM流水线代码Jenkinsfile存放在代码仓库 (Git/SVN)Jenkins 运行流水线时先拉取代码读取仓库内的 Jenkinsfile 执行Jenkinsfile 脚本内容的语法格式如下两种Declarative Pipeline声明式-实操语法严格、易读适合绝大多数项目bashpipeline { agent any stages { stage(构建) { steps { echo hello } } } }Scripted Pipeline脚本式原生 Groovy自由度高适合复杂逻辑bashnode { stage(构建) { echo hello } }前置条件git、ssh、jdk、maven 等配置服务器端开启ssh登录生成密钥bashssh-keygen -t rsa -b 4096将公钥添加到本机的 authorized_keysbashcat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys配置 SSH 服务/etc/ssh/sshd_config)bashPubkeyAuthentication yes PasswordAuthentication yes重启 SSH 服务bashsudo systemctl reload sshd将私钥拷贝到Jenkins全局令牌凭证中Jenkinsfile文件和脚本创建Jenkinsfile位置放入项目pom同级别位置参照baseCore仓库根目录父pom ├─ pom.xml 聚合父工程 ├─ common-core 公共依赖模块无需Jenkinsfile │ └─ pom.xml ├─ Core.Api 业务子模块 │ ├─ pom.xml │ └─ Jenkinsfile ✅ 当前模块流水线文件Groovy构建脚本(Jenkinsfile)bashpipeline { 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 StrictHostKeyCheckingno ${LOCAL_JAR_PATH} ${REMOTE_USER}${REMOTE_HOST}:${REMOTE_FULL_DIR}/${JAR_FILE} # 远程执行部署【修复pgrep匹配BUG】 ssh -i \$SSH_KEY -o StrictHostKeyCheckingno ${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 21 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任务构建相关pipeline脚本指向路径执行构建结果优化脚本增加git 打印、和后台应用日志bashpipeline { 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 StrictHostKeyCheckingno ${LOCAL_JAR_PATH} ${REMOTE_USER}${REMOTE_HOST}:${REMOTE_FULL_DIR}/${JAR_FILE} ssh -i \$SSH_KEY -o StrictHostKeyCheckingno ${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.encodingUTF-8 -jar \${JAR_FILE} app.log 21 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 流水线执行失败请查看日志排查问题 } } }优化脚本之后
运维|devops|Jenkins Pipeline流程构建
运维|devops|Jenkins Pipeline流程构建 目录1. 运维|devops|Jenkins Pipeline流程构建1.1 Jenkins Pipeline1.1.1 Pipeline script vs Pipeline script from SCM(实操)1.1.2 Jenkinsfile 脚本内容的语法格式如下两种1.2 前置条件1.2.1 服务器端开启ssh登录1.2.2 Jenkinsfile文件和脚本创建1.3 创建Pipeline任务1.3.1 构建相关pipeline1.4 执行构建结果1.5 优化脚本1.5.1 优化脚本之后基于 jenkins Version 2.541.3 实操案例Jenkins Pipeline基于 Groovy 的持续交付流水线代码Pipeline as CodePipeline script vs Pipeline script from SCM(实操)Pipeline script流水线代码直接粘贴在 Jenkins 任务页面文本框内存储在 Jenkins 任务配置数据库中不关联 Git 仓库Pipeline script from SCM流水线代码Jenkinsfile存放在代码仓库 (Git/SVN)Jenkins 运行流水线时先拉取代码读取仓库内的 Jenkinsfile 执行Jenkinsfile 脚本内容的语法格式如下两种Declarative Pipeline声明式-实操语法严格、易读适合绝大多数项目bashpipeline { agent any stages { stage(构建) { steps { echo hello } } } }Scripted Pipeline脚本式原生 Groovy自由度高适合复杂逻辑bashnode { stage(构建) { echo hello } }前置条件git、ssh、jdk、maven 等配置服务器端开启ssh登录生成密钥bashssh-keygen -t rsa -b 4096将公钥添加到本机的 authorized_keysbashcat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys配置 SSH 服务/etc/ssh/sshd_config)bashPubkeyAuthentication yes PasswordAuthentication yes重启 SSH 服务bashsudo systemctl reload sshd将私钥拷贝到Jenkins全局令牌凭证中Jenkinsfile文件和脚本创建Jenkinsfile位置放入项目pom同级别位置参照baseCore仓库根目录父pom ├─ pom.xml 聚合父工程 ├─ common-core 公共依赖模块无需Jenkinsfile │ └─ pom.xml ├─ Core.Api 业务子模块 │ ├─ pom.xml │ └─ Jenkinsfile ✅ 当前模块流水线文件Groovy构建脚本(Jenkinsfile)bashpipeline { 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 StrictHostKeyCheckingno ${LOCAL_JAR_PATH} ${REMOTE_USER}${REMOTE_HOST}:${REMOTE_FULL_DIR}/${JAR_FILE} # 远程执行部署【修复pgrep匹配BUG】 ssh -i \$SSH_KEY -o StrictHostKeyCheckingno ${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 21 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任务构建相关pipeline脚本指向路径执行构建结果优化脚本增加git 打印、和后台应用日志bashpipeline { 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 StrictHostKeyCheckingno ${LOCAL_JAR_PATH} ${REMOTE_USER}${REMOTE_HOST}:${REMOTE_FULL_DIR}/${JAR_FILE} ssh -i \$SSH_KEY -o StrictHostKeyCheckingno ${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.encodingUTF-8 -jar \${JAR_FILE} app.log 21 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 流水线执行失败请查看日志排查问题 } } }优化脚本之后