Jenkins 提供了强大的持续集成功能,本文将详细介绍如何利用 Jenkins 的 Pipeline 来实现并行发布与回滚。
环境准备
- Jenkins 安装并配置好环境
- 安装并配置好 Git 和 Maven
- 安装 Ansible
Jenkins Pipeline
在 Jenkins 中创建一个新的 Pipeline 任务,并在 Pipeline 脚本中粘贴以下代码。这个 Pipeline 实现了以下步骤:
- 拉取代码
- 编译代码
- 备份文件
- 发送通知到企业微信群
- 并行执行 Ansible playbook 进行发版
- 发版成功或失败后,发送通知到企业微信群
- 功能解释
- 环境变量设定(environment): 这部分定义了多个环境变量,包括应用名称、备份路径、备份名称、需要恢复的名称、Tomcat 路径、发布路径、本地路径、目标主机以及发版失败和成功的企业微信webhook通知。这些变量会在后面的步骤中使用。
- 参数设定(parameters): 这部分定义了用户可以在 Jenkins UI 中输入的参数,包括 Git 分支、部署状态(发布或回滚)、版本号(用于回滚)和备注说明。
- 发布或回滚(stage('发布或回滚')): 这个 stage 有两个 parallel stages,'Deploy' 和 'Rollback'。当用户选择 'Deploy' 时,脚本会拉取代码,编译代码并备份文件。当用户选择 'Rollback' 时,脚本将使用指定的版本号回滚到前一版本。
- 发布(stage('publish')): 在这个 stage 中,首先会给相关人员发送发版通知,然后会暂停一段时间(默认为10分钟)让编辑老师保存数据。接着会并行执行发布操作,其中包括 "公司内部老师发版" 和 "外部老师发版"。
- post 阶段(post): 在 build 成功或失败后,会发送对应的成功或失败的通知。
- 发送通知函数(sendNotification): 这是一个辅助函数,用于向企业微信发送通知。接收一个消息和一个 webhook URL 作为参数,发送一个包含指定消息的 POST 请求到 webhook URL。
import java.util.Calendar
import java.text.SimpleDateFormat
pipeline {
agent any
environment {
// 应用名称
VueName = "bxxAdmin"
// 备份路路径
BackupPath="/data/jenkins-backup/\${JOB_BASE_NAME}/${VueName}"
// 备份的名称
BackupName="${BackupPath}/${VueName}.war.\${BUILD_NUMBER}"
// 需要恢复的名称 和 BackupName 应该是一样的
BackupRollback="${BackupPath}/${VueName}.war.${params.Version}"
// tomcat 路径
TomcatPath="/usr/local/tomcat-admin-8081"
// 发布路径
DestPath="${TomcatPath}/webapps"
//应用名称
AppName="${VueName}"
// 本地路径
SrcPath="${WORKSPACE}/target/${VueName}.war"
// 指定要发版的主机或在cmdb中创建的组
TargetHost="bxx_admin_upload"
// 发版失败的企业微信webhook通知
FailureWebhookUrl="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=e0671a"
// 发版成功的企业微信webhook通知
SuccessWebhookUrl="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=d3c8"
}
parameters {
gitParameter (
branch: '',
branchFilter: 'origin/(.*)',
defaultValue: 'totest',
description: '分支变量',
name: 'branch',
quickFilterEnabled: false,
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'GitParameterDefinition'
)
choice (
choices: ['Deploy', 'Rollback'],
description: '''Deploy: 发布\nRollback: 回滚''',
name: 'Status'
)
string (
description: '''----此项为回滚版本号,如果发布请忽略----''',
name: 'Version'
)
string (
description: '''----备注说明----''',
name: 'remark'
)
}
stages {
stage('发布或回滚') {
parallel {
stage('Deploy') {
when {
expression {params.Status == 'Deploy'}
beforeOptions true
}
steps {
script {
stage ('拉取代码') {
git (
branch: "${params.branch}",
credentialsId: '7493a50b0867099e',
url: 'http://gitlab.sy.com/bxxjava/bxxAdmin2.git'
)
}
stage('编译代码') {
// One or more steps need to be included within the steps block.
echo "======status:${params.Status}========="
sh '''
source /etc/profile
sed -i 's#<bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath>#<bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>#g' pom.xml
mvn clean package
'''
}
stage ("备份文件") {
echo "======包到备份文件夹==============="
sh """
if [ -d ${env.BackupPath} ];
then
echo "The files is already exists "
else
mkdir -p ${env.BackupPath}
fi
cp target/${env.VueName}.war ${env.BackupName}
"""
echo "deploy done!"
}
}
}
}
stage('Rollback') {
when {
expression {params.Status == 'Rollback'}
beforeOptions true
}
steps {
script {
if (params.Version == null || params.Version == '') {
error("当“Status ”为“Rollback”时,需要指定Version")
}
}
echo "======status:${params.Status}========"
echo "======build_id:${params.Version}======="
echo "==============回滚包放到原来的地方==================="
sh """\\cp -r ${env.BackupRollback} ./target/${env.VueName}.war"""
}
}
}
}
stage('publish') {
steps {
script {
// 设置暂停时间(分钟)
int pauseMinutes = 10
stage("发版通知到互联网3.0企业微信群") {
// 计算 pauseMinutes 分钟后的时间
Calendar futureTime = Calendar.getInstance()
futureTime.add(Calendar.MINUTE, pauseMinutes)
// 格式化时间
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm")
String formattedTime = sdf.format(futureTime.time)
// 发送企业微信通知
sendNotification("各位老师, 包学习后台将于 " + formattedTime + " 进行发版更新操作。请各位老师做好数据保存工作!", "${env.SuccessWebhookUrl}")
}
stage("暂停${pauseMinutes}分钟给编辑老师保存的时间") {
// 暂停 pauseMinutes 分钟
sleep(time: pauseMinutes * 60) // 将分钟转换为秒
}
stage("并行发布") {
parallel(
"公司内部老师发版": {
ansiblePlaybook (
colorized: true,
disableHostKeyChecking: true,
installation: 'ansible',
playbook: '/data/ansible/prod/java/bxx-admin-update.yml',
extraVars: [
dest_path: "${env.DestPath}",
app_name: "${env.AppName}",
src_path: "${env.SrcPath}",
target_host: "${env.TargetHost}"
]
)
},
"外部老师发版": {
ansiblePlaybook (
colorized: true,
disableHostKeyChecking: true,
installation: 'ansible',
playbook: '/data/ansible/prod/java/without-bxx-admin-update.yml',
extraVars: [
dest_path: "${env.DestPath}",
app_name: "${env.AppName}",
src_path: "${env.SrcPath}"
]
)
}
)
}
}
}
}
}
post {
success {
script {
sendNotification("各位老师,包学后台发布完成。", "${env.SuccessWebhookUrl}")
}
}
failure {
script {
sendNotification('包学习后台发版失败', "${env.FailureWebhookUrl}")
}
}
}
}
def sendNotification(String message, String webhookUrl) {
// def webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_WEBHOOK_KEY"
// 解析 Webhook URL 的 Key 部分
def key = webhookUrl.split("=")[1]
def payload = """
{
"msgtype": "text",
"text": {
"content": "${message.trim()}",
"mentioned_list": ["@all"]
}
}
"""
// 发送 HTTP POST 请求
sh "curl -X POST -H 'Content-Type: application/json' -d '${payload}' '${webhookUrl}'"
}
发表评论
共 0 条评论
暂无评论