建)
運維|devops|Jenkins Pipeline流程構(gòu)建 目錄1. 運維|devops|Jenkins Pipeline流程構(gòu)建1.1 Jenkins Pipeline1.1.1 Pipeline script vs Pipeline script from SCM(實操)1.1.2 Jenkinsfile 腳本內(nèi)容的語法格式如下兩種1.2 前置條件1.2.1 服務器端開啟ssh登錄1.2.2 Jenkinsfile文件和腳本創(chuàng)建1.3 創(chuàng)建Pipeline任務1.3.1 構(gòu)建相關pipeline1.4 執(zhí)行構(gòu)建結(jié)果1.5 優(yōu)化腳本1.5.1 優(yōu)化腳本之后基于 jenkins Version 2.541.3 實操案例Jenkins Pipeline基于 Groovy 的持續(xù)交付流水線代碼Pipeline as CodePipeline script vs Pipeline script from SCM(實操)Pipeline script流水線代碼直接粘貼在 Jenkins 任務頁面文本框內(nèi)存儲在 Jenkins 任務配置數(shù)據(jù)庫中不關聯(lián) Git 倉庫Pipeline script from SCM流水線代碼Jenkinsfile存放在代碼倉庫 (Git/SVN)Jenkins 運行流水線時先拉取代碼讀取倉庫內(nèi)的 Jenkinsfile 執(zhí)行Jenkinsfile 腳本內(nèi)容的語法格式如下兩種Declarative Pipeline聲明式-實操語法嚴格、易讀適合絕大多數(shù)項目bashpipeline { agent any stages { stage(構(gòu)建) { steps { echo hello } } } }Scripted Pipeline腳本式原生 Groovy自由度高適合復雜邏輯bashnode { stage(構(gòu)建) { 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文件和腳本創(chuàng)建Jenkinsfile位置放入項目pom同級別位置參照baseCore倉庫根目錄父pom ├─ pom.xml 聚合父工程 ├─ common-core 公共依賴模塊無需Jenkinsfile │ └─ pom.xml ├─ Core.Api 業(yè)務子模塊 │ ├─ pom.xml │ └─ Jenkinsfile ? 當前模塊流水線文件Groovy構(gòu)建腳本(Jenkinsfile)bashpipeline { agent any options { disableConcurrentBuilds() timeout(time: 20, unit: MINUTES) timestamps() buildDiscarder(logRotator(numToKeepStr: 10)) } parameters { booleanParam( name: AUTO_DEPLOY, defaultValue: false, description: 構(gòu)建完成自動推送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. 環(huán)境信息打印) { steps { echo 【構(gòu)建信息】服務名${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. 歸檔構(gòu)建產(chǎn)物) { steps { archiveArtifacts artifacts: ${env.LOCAL_JAR_PATH}, fingerprint: true, onlyIfSuccessful: true } } stage(4. 遠程發(fā)布部署) { 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} # 遠程執(zhí)行部署【修復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} # 根據(jù)服務名殺死進程不再寫死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 遠程部署流程執(zhí)行完畢 } } } post { always { echo 【Post鉤子】流水線構(gòu)建結(jié)束 } success { cleanWs() echo 流水線全部執(zhí)行成功 } failure { echo 流水線執(zhí)行失敗請查看日志排查問題 } } }創(chuàng)建Pipeline任務構(gòu)建相關pipeline腳本指向路徑執(zhí)行構(gòu)建結(jié)果優(yōu)化腳本增加git 打印、和后臺應用日志bashpipeline { agent any options { disableConcurrentBuilds() timeout(time: 20, unit: MINUTES) timestamps() buildDiscarder(logRotator(numToKeepStr: 10)) } parameters { booleanParam( name: AUTO_DEPLOY, defaultValue: false, description: 構(gòu)建完成自動推送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. 環(huán)境信息 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 【構(gòu)建信息】服務名${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. 歸檔構(gòu)建產(chǎn)物) { steps { archiveArtifacts artifacts: ${env.LOCAL_JAR_PATH}, fingerprint: true, onlyIfSuccessful: true } } stage(4. 遠程發(fā)布部署) { when { expression { params.AUTO_DEPLOY } } steps { echo 開始推送Jar包并遠程重啟服務 withCredentials([sshUserPrivateKey( credentialsId: ${env.SSH_CREDENTIALS_ID}, keyFileVariable: SSH_KEY, usernameVariable: SSH_USER )]) { // 使用三雙引號 允許Groovy解析Jenkins環(huán)境變量 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】優(yōu)雅停止舊服務進程 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】校驗進程狀態(tài) if pgrep -f java.*\${SERVICE_NAME} /dev/null; then echo ? 服務進程啟動成功 else echo ? 服務啟動失敗 exit 1 fi EOF } echo 遠程部署流程執(zhí)行完畢 } } } post { always { echo 【Post鉤子】流水線構(gòu)建結(jié)束 } success { cleanWs() echo 流水線全部執(zhí)行成功 } failure { echo 流水線執(zhí)行失敗請查看日志排查問題 } } }優(yōu)化腳本之后