运维|devops|Jenkins Pipeline流程构建
·
运维|devops|Jenkins Pipeline流程构建
📑 目录
1. 运维|devops|Jenkins Pipeline流程构建
1.1 Jenkins Pipeline
1.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 构建相关pipeline
1.4 执行构建结果
1.5 优化脚本
1.5.1 优化脚本之后
基于 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(声明式-实操):语法严格、易读,适合绝大多数项目
bash
pipeline {
agent any
stages {
stage('构建') {
steps {
echo "hello"
}
}
}
}
- Scripted Pipeline(脚本式):原生 Groovy,自由度高,适合复杂逻辑
bash
node {
stage('构建') {
echo "hello"
}
}
前置条件
git、ssh、jdk、maven 等配置
服务器端开启ssh登录
- 生成密钥
bash
ssh-keygen -t rsa -b 4096
- 将公钥添加到本机的 authorized_keys
bash
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
- 配置 SSH 服务(/etc/ssh/sshd_config)
bash
PubkeyAuthentication yes
PasswordAuthentication yes
- 重启 SSH 服务
bash
sudo systemctl reload sshd
- 将私钥拷贝到Jenkins全局令牌凭证中

Jenkinsfile文件和脚本创建
Jenkinsfile位置放入项目pom同级别
- 位置参照
base
Core(仓库根目录|父pom)
├─ pom.xml 聚合父工程
├─ common-core 公共依赖模块(无需Jenkinsfile)
│ └─ pom.xml
├─ Core.Api 业务子模块
│ ├─ pom.xml
│ └─ Jenkinsfile ✅ 当前模块流水线文件
- Groovy构建脚本(Jenkinsfile)
bash
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任务


构建相关pipeline


- 脚本指向路径

执行构建结果

优化脚本
增加git 打印、和后台应用日志
bash
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 "💥 流水线执行失败,请查看日志排查问题!"
}
}
}
优化脚本之后


更多推荐


所有评论(0)