二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Nexus系列文章

  • Jenkins系列文章

    • Jenkins入门系列笔记汇总整理
    • 前言与介绍
    • Jenkins初始部署与简单配置
    • Jenkins各配置选项介绍
    • Jenkins中一个项目的构建
    • Jenkins配置项目构建的钉钉通知
    • Jenkins忘记管理员密码怎么办
    • Jenkins与gitlab的交互探微
    • Jenkins根目录详解
    • Jenkins插件之显示构建时间
    • Jenkins插件之批量修改配置
    • Jenkins配置简单构建邮件推送
    • Jenkins复杂邮件推送配置详解
    • Jenkins配置复杂构建邮件推送
    • Jenkins构建安卓项目之前的一些唠叨
    • Jenkins构建安卓项目配置
    • Jenkins与Gitlab分支的交互
    • Jenkins构建nodejs项目
    • 使用docker部署Jenkins及初始配置
    • 配置gitlab提交代码Jenkins自动构建
    • Jenkins回滚方案探微
    • Jenkins角色控制(小黄锁)探微
    • Jenkins构建的应用配置问题解决探微
    • Jenkins构建中tag的应用
    • Jenkins插件之Ansicolor(神器)
    • 最基础核心的Jenkins功能部署一个java应用
    • Jenkins+sonar构建代码扫描
    • Jenkins+docker+gitlab将应用部署到docker
    • Jenkins参数化构建犀利插件Active-Choices-Plugin
    • 记一次将代码中参数外显到构建历史中的操作
    • Jenkins升级与迁移的经验分享
    • pipeline笔记之从一个简单的项目构建开始
    • Jenkinsfile声明式语法详解
    • 自动构建的原始配置以及pipeline中的用法
    • 多分支构建的实践与思考
    • 使用Jenkinsfile类前端项目的部署与回滚
    • 如何在Jenkinsfile中定义一个全局的时间戳变量
    • Jenkins中自由风格回滚方案的最佳实践
      • 1,思路整理
      • 2,自由风格单机部署回滚示例
      • 3,自由风格结合 ansible 多机批量部署回滚示例
    • Jenkins中pipeline风格回滚方案的最佳实践
    • pipeline结合ansible剧本进行批量的部署与回滚配置
    • 最近配置安卓iOS打包本地化流程中一些值得记录的内容
    • pipeline中如何在environment环节声明一个含有通配符的变量
    • git-Parameter插件在pipeline共享库中的实践详解
    • jenkins作为ci检测代码是否合并的实践
    • 将Jenkins共享库的Jenkinsfile放到ci静态检测的实践
    • Jenkins的pipeline实践之GitSCM参数配置项详解
    • Jenkins中pipeline对接CMDB接口获取主机列表的发布实践
    • Jenkins有任务无法kill提示即将关闭
    • Jenkins基于Share Library共享库的最佳实践探索
    • Jenkins结合MySql Database插件的平台化实践思路
    • Jenkins-Groovy中三元表达式的用法
    • Jenkins-Groovy中Switch的高阶用法
    • Jenkins-pipeline之利用activity choice插件对接查询MySQL数据实现动态参数化的功能
    • CentOS通过yum快速安装Jenkins
    • Jenkins-pipeline语法之错误处理详解(文末有干货)
    • Jenkins常用插件汇总以及简单介绍
    • Jenkins所遇报错汇总及解决
    • Jenkins管理维护运维规范
  • ELK笔记

  • Kubernetes笔记

  • LLM专题

  • 系列专题
  • Jenkins系列文章
二丫讲梵
2019-12-14
目录

Jenkins中自由风格回滚方案的最佳实践

文章发布较早,内容可能过时,阅读注意甄别。

上周在 Jenkins 中文社区做了一次关于回滚那些事儿的分享,因为要准备这样一次分享,所以很多以前放下的事情,又都捡拾起来了,瞬间又有了不少奇思妙想出来,这种收获,是不进行这次经历无法获取的,分享常常使我更加成长,尽管分享的东西,已经是自己所熟悉的,熟悉的东西多加巩固,就会有意外收获。

曾经我一直以为,Jenkins 对比所谓 Gitlab 的 cicd,以及 drone 等的发布工具,可能在对发布的历史版本回滚的操作上,有天生不足(前边提到的两者都是直接基于 git 自身的版本控制进行发布,回滚的时候也直接基于历史版本重新发布即可),我一度以为这是 Jenkins 无尽美好中的唯一缺憾。

后来工作中接触到 walle 的部署,当我了解了 walle 的发布思路之后,就像忽然打开了一扇大门一样,忽然觉得 Jenkins 同样可以借鉴这样一个思路来进行发布的工作,于是,在工作之余,我做了五大实验:

  • 基于 freestyle 的定制化单机版本发布回滚配置管理
  • 基于 pipeline 的定制化单机版本发布回滚配置管理
  • 基于 freestyle 结合 ansible 的多主机批量发布回滚配置管理
  • 基于 pipeline 结合 ansible 的多主机批量发布回滚配置管理
  • 基于 pipeline 结合优化版 ansible 的多主机批量发布回滚配置管理

今天将针对这些方案一一解析与分享,本文将分享 基于freestyle的定制化单机版本发布回滚配置管理和 基于freestyle结合ansible的多主机批量发布回滚配置管理 这两种。

现在,进入正题。

# 1,思路整理

如果是发布 PHP 项目:

  1. 同步到远端的版本目录,目录使用时间 + build id命名
  2. 将新的应用版本软链到项目 root 目录
  3. 确保远程目录只保留五次(可自定义次数)历史

如果是回滚:

  1. 构建参数当中添加一个回滚 ID,默认情况下,将回滚到上次构建
  2. 如果输入自定义 ID,则回滚到对应构建
  3. 支持灵活在五次构建内回滚

这一思路的流程图大概如下:

现在通过实际例子来实现一下上边这个思路,大概将进行四个实验,或者更多,首先是类前端项目发布,静态部署,PHP 项目等都可采用这种方案。

# 2,自由风格单机部署回滚示例

创建一个自由风格的测试项目,核心当然是在参数化的配置,以及脚本的灵活定义,因此这里就展示这两个部分,先看参数化部分配置:

image

定义三个参数,分别对应上边流程图中的三个节点,首先通过分支 branch 进行下发,接着通过 mode 进行部署或者回滚,如果是回滚,则再针对版本 ID 进行一下判断即可。

脚本内容:

#!/bin/bash
##set color##
echoRed() { echo $'\e[0;31m'"$1"$'\e[0m'; }
echoGreen() { echo $'\e[0;32m'"$1"$'\e[0m'; }
echoYellow() { echo $'\e[0;33m'"$1"$'\e[0m'; }
##set color##
source /etc/profile
project="admin"
remote_port="22"
remote_user="root"
remote_ip="10.3.0.42"
Date=`date "+%Y%m%d%H%M%S"`
project_dir="/data/www/${project}"
version_dir="/release/$project/${Date}_${BUILD_ID}"
cat > keepfive.sh << 'EOF'
file_path="/release/admin"
while true;do
A=`ls ${file_path} | wc -l`
B=`ls -lrX ${file_path} | tail -n 1 | awk '{print $9}'`
if [ $A -gt 5 ];then rm -rf ${file_path}/$B;else break;fi;done
EOF
if [ $mode == "deploy" ];then
    echoYellow "创建远程主机上的版本目录 :${version_dir}"
    ssh -p $remote_port $remote_user@$remote_ip "mkdir -p ${version_dir}"
    [ $? != 0 ] && echoRed "请注意,在创建远程主机上的版本目录时出错,故而退出构建,可联系运维同学处理!" && exit 1
    echoYellow "将代码同步到远程主机版本目录"
    rsync -az -e "ssh -p $remote_port" --exclude='Jenkinsfile' --exclude='keepfive.sh' --delete ${WORKSPACE}/  $remote_user@$remote_ip:$version_dir/
    [ $? != 0 ] && echoRed "请注意,在执行同步代码到版本目录时出错,故而退出构建,可联系运维同学处理!" && exit 1
    echoGreen "将代码同步到远程主机版本目录成功!"
    echoYellow "将项目部署到生产目录"
    ssh -p $remote_port $remote_user@$remote_ip "ln -snf $version_dir $project_dir"
    [ $? != 0 ] && echoRed "请注意,在将项目部署到生产目录时出错,故而退出构建,可联系运维同学处理!" && exit 1
    echoGreen "将项目部署到生产目录成功!"
    echoYellow "使版本目录保持五个版本历史"
    ssh -p $remote_port $remote_user@$remote_ip sh < keepfive.sh
    [ $? != 0 ] && echoRed "请注意,在执行版本清理时出错,将会影响回滚,故而退出构建,可联系运维同学处理!" && exit 1
    echoGreen "执行版本清理成功!"
    echoYellow "同步版本号到本地"
    [ ! -d /root/.jenkins/version/$project ] && mkdir -p /root/.jenkins/version/$project
    ssh -p $remote_port $remote_user@$remote_ip "ls /release/$project" > /root/.jenkins/version/$project/version.log
    echoGreen "============"
    echoGreen "上线部署完成!"
    echoGreen "============"
else
    if [ ${version_id} == "0" ];then
        echoYellow "选择回滚的版本是默认,将回滚到上次制品,回滚即将进行..."
        Version="/release/$project/`tail -n2 /root/.jenkins/version/$project/version.log | head -n1`"
        ssh -p $remote_port $remote_user@$remote_ip "ln -snf $Version $project_dir"
        [ $? != 0 ] && echoRed "请注意,在执行回滚时出错,故而退出构建,可立即联系运维同学处理!" && exit 1
        echoGreen "=============="
        echoGreen "项目已回滚完成!"
        echoGreen "=============="
    else
        echoYellow "选择回滚的版本是:${version_id},将回滚到 ${version_id} 的制品,回滚即将进行..."
        Version="/release/$project/`grep "_$version_id" /root/.jenkins/version/$project/version.log`"
        ssh -p $remote_port $remote_user@$remote_ip "ln -snf $Version $project_dir"
        [ $? != 0 ] && echoRed "请注意,在执行回滚时出错,故而退出构建,可立即联系运维同学处理!" && exit 1
        echoGreen "项目回滚到 ${version_id} 完成!"
    fi
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

核心部分也就是脚本内容了,以上即是脚本内容,采用的逻辑也都比较容易理解,只要读一下就能理解,可用于生产,可能只需要调整一下几个变量,或者路径就可以直接投入使用。

# 3,自由风格结合 ansible 多机批量部署回滚示例

自由风格之下,同样首先创建对应的参数用于传递,然后这里又新增了一个参数用于传递远程主机,以实现单机或者批量发布都可的功能。

依旧是先定于参数如下:

image

然后定义脚本如下:

#!/bin/bash
##set color##
echoRed() { echo $'\e[0;31m'"$1"$'\e[0m'; }
echoGreen() { echo $'\e[0;32m'"$1"$'\e[0m'; }
echoYellow() { echo $'\e[0;33m'"$1"$'\e[0m'; }
##set color##
source /etc/profile
project="tale"
remote_port="22"
remote_user="root"
project_dir="/data/www/${project}"
version_dir="/release/$project/${Date}_${BUILD_ID}"
cat > keepfive.sh << 'EOF'
file_path="/release/tale"
while true;do
A=`ls ${file_path} | wc -l`
B=`ls -lrX ${file_path} | tail -n 1 | awk '{print $9}'`
if [ $A -gt 5 ];then rm -rf ${file_path}/$B;else break;fi;done
EOF
cat > excludefile << EOF
hosts.ini
deploy.yml
Jenkinsfile
keepfive.sh
excludefile
EOF
Rs(){
if [ $remote_ip == "all" ];then
cat > hosts.ini << EOF
[remote]
10.3.9.32 ansible_port=34222
10.3.20.4 ansible_port=34222
EOF
else
cat > hosts.ini << EOF
[remote]
$remote_ip ansible_port=34222
EOF
fi
}
Rb(){
cat > rollback.yml << EOF
---
- hosts: "remote"
  remote_user: root
  tasks:
    - name: "将项目回滚到对应期望的构建"
      file: path=/data/www/${project} state=link src=${Version}
EOF
}
Rd(){
cat > deploy.yml << EOF
---
- hosts: "remote"
  remote_user: root
  tasks:
    - name: "创建远程主机上的版本目录"
      file: path=/release/${project}/${project}_${BUILD_ID} state=directory
    - name: "将代码同步到远程主机版本目录"
      synchronize:
        src: ${WORKSPACE}/
        dest: /release/${project}/${project}_${BUILD_ID}/
        rsync_opts: --exclude-from=excludefile
    - name: "将项目部署到生产目录"
      file: path=/data/www/${project} state=link src=/release/${project}/${project}_${BUILD_ID}
    - name: "使版本目录保持五个版本历史"
      script: keepfive.sh
    - name: "生成远程版本号"
      shell: "ls /release/${project} > /release/version.log"
    - name: "同步版本号到本地"
      synchronize: "src=/release/version.log dest=/root/.jenkins/version/${project}/version.log mode=pull"
EOF
}
if [ $mode == "deploy" ];then
    Rs && Rd
    ansible-playbook -i hosts.ini deploy.yml
else
    if [ ${version_id} == "0" ];then
        Rs
        echo "选择回滚的版本是默认,将回滚到上次制品,回滚即将进行..."
        Version="/release/$project/`tail -n2 /root/.jenkins/version/$project/version.log | head -n1`"
        Rb
        ansible-playbook -i hosts.ini rollback.yml
        echo "=============="
        echo "项目已回滚完成!"
        echo "=============="
    else
        Rs
        echo "选择回滚的版本是:${version_id},将回滚到 ${version_id} 的制品,回滚即将进行..."
        Version="/release/$project/`grep "_$version_id" /root/.jenkins/version/$project/version.log`"
        Rb
        ansible-playbook -i hosts.ini rollback.yml
        echo "项目回滚到 ${version_id} 完成!"
    fi
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

这里把所有内容都集成到一个脚本,便于维护管理。这是我现在比较推崇的一种配置习惯,日常使用过程中,可能我们经常需要调试一些东西,如果一个构建调用的脚本要放好几个地方,那么维护起来是非常痛苦的,莫不如直接全部都集成在 Jenkins 当中,任何时候需要排查某个项目,直接到 Jenkins 中打开配置查看即可,而不需要再找几个地方。

如上两种方式都是紧贴合文章开头的流程图所为,也就几个大佬口中简单的 if/else 而已,但是就已经足够满足并实现我们的需求了。

微信 支付宝
#jenkins#回滚
上次更新: 2024/07/04, 22:40:37
如何在Jenkinsfile中定义一个全局的时间戳变量
Jenkins中pipeline风格回滚方案的最佳实践

← 如何在Jenkinsfile中定义一个全局的时间戳变量 Jenkins中pipeline风格回滚方案的最佳实践→

最近更新
01
理论正确,事实错误
06-21
02
学习周刊-总第216期-2025年第25周
06-20
03
睡着的人不关灯
06-12
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式