• 对于注定会优秀的人来说,他所需要的,只是时间----博主
  • 手懒得,必受贫穷,手勤的,必得富足----《圣经》
  • 帮助别人,成就自己。愿君在本站能真正有所收获!
  • 如果你在本站中发现任何问题,欢迎留言指正!
  • 宝剑锋从磨砺出,梅花香自苦寒来!
  • 本站开启了防爆破关小黑屋机制,如果您是正常登录但被关进小黑屋,请联系站长解除!

<三十七>Jenkins实战应用–回滚方案的最佳实践之传统自由风格以及与ansible集成的配置

Jenkins eryajf 1个月前 (12-14) 397°C 已收录 0个评论
本文预计阅读时间 18 分钟

上周在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,自由风格单机部署回滚示例

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

定义三个参数,分别对应上边流程图中的三个节点,首先通过分支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

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

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

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

依旧是先定于参数如下:

然后定义脚本如下:

#!/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

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

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


weinxin
扫码订阅本站,第一时间获得更新
微信扫描二维码,订阅我们网站的动态,另外不定时发送WordPress小技巧,你可以随时退订,欢迎订阅哦~

二丫讲梵 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明<三十七>Jenkins实战应用–回滚方案的最佳实践之传统自由风格以及与ansible集成的配置
喜欢 (0)
[如果想支持本站,可支付宝赞助]
分享 (0)
eryajf
关于作者:
学无止境,我愿意无止境学。书山有路,我愿意举身投火,淬炼成金!永远不要忘记,激情的奋进,就是美好的未来!

您必须 登录 才能发表评论!