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

<三十八>Jenkins-pipeline学习笔记–pipeline中回滚方案的最佳实践以及与ansible集成的配置

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

传统的自由风格完成之后,来到流水线的配置事实上已经非常简单了,主题核心代码变化不多,只需要遵照流水线的语法合理配置使用即可,所以废话不多说,直接分享代码出来。

1,基于pipeline的定制化单机版本发布回滚配置管理

仍旧在原来代码的基础之上,将部署方式更改为流水线风格,目前实验做下来,与上边自由风格对比,大概有如下几点不同:

  • 1,时间戳不太容易定义,上边时间戳也只是在项目版本目录定义的时候使用,能够便于日常排查确认版本,不过现在流水线里边时间戳不太容易定义了,就干掉了时间戳为前缀,更改为项目名作为版本的前缀。
  • 2,目前来看流水线中通过cat写入脚本不是十分理想,于是这个脚本固定放在了项目工作目录。
  • 3,其他基本一样,部署也是一样,一般情况下,都采用手动部署的方式,部署的时候,直接填入将要构建的分支,直接填入即可触发构建。
  • 4,关于自动构建,可以在测试环境引用,不建议在线上环境中引用。

Jenkinsfile内容:

pipeline {
    agent any
    environment {
        project="admin-pipeline"
        git_url = "git@10.3.0.42:jenkins-learn/breeze-college.git"
        remote_port="22"
        remote_user="root"
        remote_ip="10.3.0.42"
        project_dir="/data/www/${project}"
        version_dir="/release/$project/${project}_${BUILD_ID}"
    }
    options {
        timestamps()
        disableConcurrentBuilds()
        timeout(time: 10, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    triggers{
        gitlab( triggerOnPush: true,
                triggerOnMergeRequest: true,
                branchFilterType: 'All',
                secretToken: "${env.git_token}")
    }
    parameters {
        string(name: 'branch', defaultValue: 'master', description: '请输入将要构建的代码分支')
        choice(name: 'mode', choices: ['deploy','rollback'], description: '请选择发布或者回滚?')
        string(name: 'version_id', defaultValue: '0', description: '回滚时用,默认回滚到上一次构建,如需要回滚到更早构建,请输入对应构建ID,只支持最近五次构建的回滚,部署请忽略此参数')
    }
    stages {
        stage('拉取代码') {
            steps {
                echo 'Checkout'
                script {
                    try {
                        git branch: "${branch}",url: "${git_url}"
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('定义版本管理脚本'){
            steps{
                script{
                    try {
sh '''                        
cat > keepfive.sh << 'EOF'
file_path="/release/admin-pipeline"
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
'''                      
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('部署') {
            when {
                environment name: 'mode',value: 'deploy'
            }
            steps {
                script {
                    ansiColor('xterm') {
                    try {
                        sh '''
                        echo "创建远程主机上的版本目录 :${version_dir}"
                        ssh -p $remote_port $remote_user@$remote_ip "mkdir -p ${version_dir}"
                        [ $? != 0 ] && echo "请注意,在创建远程主机上的版本目录时出错,故而退出构建,可联系运维同学处理!" && exit 1
                        echo "将代码同步到远程主机版本目录"
                        rsync -az -e "ssh -p $remote_port" --exclude='Jenkinsfile' --exclude='keepfive.sh' --delete ${WORKSPACE}/  $remote_user@$remote_ip:$version_dir/
                        [ $? != 0 ] && echo "请注意,在执行同步代码到版本目录时出错,故而退出构建,可联系运维同学处理!" && exit 1
                        echo "将代码同步到远程主机版本目录成功!"
                        echo "将项目部署到生产目录"
                        ssh -p $remote_port $remote_user@$remote_ip "ln -snf $version_dir $project_dir"
                        [ $? != 0 ] && echo "请注意,在将项目部署到生产目录时出错,故而退出构建,可联系运维同学处理!" && exit 1
                        echo "将项目部署到生产目录成功!"
                        echo "使版本目录保持五个版本历史"
                        ssh -p $remote_port $remote_user@$remote_ip sh < keepfive.sh
                        [ $? != 0 ] && echo "请注意,在执行版本清理时出错,将会影响回滚,故而退出构建,可联系运维同学处理!" && exit 1
                        echo "执行版本清理成功!"
                        echo "同步版本号到本地"
                        [ ! -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
                        echo "============"
                        echo "上线部署完成!"
                        echo "============"
                        '''
                    } catch(err) {
                        echo "${err}"
                    }
                }
                }
            }
        }
        stage('回滚') {
            when {
                environment name: 'mode',value: 'rollback'
            }
            steps {
                script {
                    try {
                        sh '''
                            if [ ${version_id} == "0" ];then
                                echo "选择回滚的版本是默认,将回滚到上次制品,回滚即将进行..."
                                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 ] && echo "请注意,在执行回滚时出错,故而退出构建,可立即联系运维同学处理!" && exit 1
                                echo "=============="
                                echo "项目已回滚完成!"
                                echo "=============="
                            else
                                echo "选择回滚的版本是:${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 ] && echo "请注意,在执行回滚时出错,故而退出构建,可立即联系运维同学处理!" && exit 1
                                echo "项目回滚到 ${version_id} 完成!"
                            fi
                        '''
                    } catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
    }
    post {
        success {
            dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=改成自己的',
            imageUrl:'https://ae01.alicdn.com/kf/Hdfe28d2621434a1eb821ac6327b768e79.png',
            jenkinsUrl: "${env.JENKINS_URL}",
            message:'构建成功 ✅',
            notifyPeople:'李启龙'
        }
        failure {
            dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=改成自己的',
            imageUrl:'https://ae01.alicdn.com/kf/Hdfe28d2621434a1eb821ac6327b768e79.png',
            jenkinsUrl: "${env.JENKINS_URL}",
            message:'构建失败 ❌',
            notifyPeople:'李启龙'
        }
    }
}

目前采用推送代码自动构建的方式,回滚的方式与上边自由风格一致。基本上各个步骤也都还比较清晰,这里只是把主体部署与回滚的步骤给定义了,如果自己生产当中还有其他的场景,可以自行配置添加。

后来又在一个地方学到了时间戳的定义方式,真正使用起来,似乎也并不复杂:

def createVersion() {
    return new Date().format('yyyyMMddHHmmss') + "_${env.BUILD_ID}"
}

pipeline {
    agent any
    environment {
        _version = createVersion()
    }
    stages {
        stage ("test") {
            steps {
                echo ${_version}
            }
        }
    }
}

如果引用这一变量,只需调整一下上边脚本引用的变量即可。

2,基于pipeline结合ansible的多主机批量发布回滚配置管理

流水线会涉及到更多内容,脚本如下:

def createVersion() {
    return new Date().format('yyyyMMddHHmmss') + "_${env.BUILD_ID}"
}

pipeline {
    agent any
    environment {
        _version = createVersion()
        // 需要修改此处,定义项目名称
        project="admin-ansible"
        // 定义项目git地址
        git_url = "git@10.3.0.42:jenkins-learn/breeze-college.git"
        remote_port="22"
        remote_user="root"
        // 定义项目的webroot目录        
        project_dir="/data/www/${project}"
        //定义项目的版本目录,一般不用更改
        version_dir="/release/$project/${_version}"
    }
    options {
        timestamps()
        disableConcurrentBuilds()
        timeout(time: 10, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    triggers{
        gitlab( triggerOnPush: true,
                triggerOnMergeRequest: true,
                branchFilterType: 'All',
                secretToken: "${env.git_token}")
    }
    parameters {
        string(name: 'branch', defaultValue: 'master', description: '请输入将要构建的代码分支')        
        choice(name: 'mode', choices: ['deploy','rollback'], description: '请选择发布或者回滚?')
        string(name: 'version_id', defaultValue: '0', description: '回滚时用,默认回滚到上一次构建,如需要回滚到更早构建,请输入对应构建ID,只支持最近五次构建的回滚,部署请忽略此参数')
        choice(name: 'remote_ip', choices: ['all','10.3.9.32','10.3.20.4'], description: '选择要发布的主机')
    }
    stages {
        stage('拉取代码') {
            steps {
                echo 'Checkout'
                script {
                    try {
                        git branch: "${branch}",url: "${git_url}"
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('定义版本管理脚本'){
            steps{
                script{
                    try {
sh '''                        
cat > keepfive.sh << 'EOF'
file_path="/release/admin-pipeline"
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
'''                      
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('定义部署主机列表'){
            steps{
                script{
                    try{
                        sh '''
                        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
'''
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('定义部署剧本'){
            steps{
                script{
                    try {
sh '''                        
cat > deploy.yml << EOF
---
- hosts: "remote"
  remote_user: root
  tasks:
    - name: "创建远程主机上的版本目录"
      file: path=/release/${project}/${_version} state=directory
    - name: "将代码同步到远程主机版本目录"
      synchronize: 
        src: ${WORKSPACE}/ 
        dest: /release/${project}/${_version}/  
        rsync_opts: --exclude-from=excludefile
    - name: "将项目部署到生产目录"
      file: path=/data/www/${project} state=link src=/release/${project}/${_version}
    - 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
'''                      
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('定义忽略文件'){
            steps{
                script{
                    try {
sh '''                        
cat > excludefile << EOF
hosts.ini
deploy.yml
Jenkinsfile
keepfive.sh
excludefile
rollback.yml
EOF
'''                      
                    }catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('部署') {
            when {
                environment name: 'mode',value: 'deploy'
            }
            steps {
                script {                    
                    try {
                        sh '''
                        ansible-playbook -i hosts.ini deploy.yml
                        '''
                    } catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
        stage('回滚') {
            when {
                environment name: 'mode',value: 'rollback'
            }
            steps {
                script {
                    try{
                        if (params.version_id == '0'){                        
                            sh '''
                                echo "选择回滚的版本是默认,将回滚到上次制品,回滚即将进行..."
                                Version="/release/$project/`tail -n2 /root/.jenkins/version/$project/version.log | head -n1`"
cat > rollback.yml << EOF
---
- hosts: "remote"
  remote_user: root
  tasks:
    - name: "将项目回滚到对应期望的构建"
      file: path=/data/www/${project} state=link src=${Version}
EOF
                                ansible-playbook -i hosts.ini rollback.yml
                                echo "=============="
                                echo "项目已回滚完成!"
                                echo "=============="
                                '''
                        } else{
                            sh '''
                                echo "选择回滚的版本是:${version_id},将回滚到 ${version_id} 的制品,回滚即将进行..."
                                Version="/release/$project/`grep "_$version_id" /root/.jenkins/version/$project/version.log`"
cat > rollback.yml << EOF
---
- hosts: "remote"
  remote_user: root
  tasks:
    - name: "将项目回滚到对应期望的构建"
      file: path=/data/www/${project} state=link src=${Version}
EOF
                                ansible-playbook -i hosts.ini rollback.yml
                                echo "项目回滚到 ${version_id} 完成!"
                                '''
                        }
                    } catch(err) {
                        echo "${err}"
                    }
                }
            }
        }
    }
    post {
        success {
            dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=改成自己的',
            imageUrl:'https://ae01.alicdn.com/kf/Hdfe28d2621434a1eb821ac6327b768e79.png',
            jenkinsUrl: "${env.JENKINS_URL}",
            message:'构建成功 ✅',
            notifyPeople:'李启龙'
        }
        failure {
            dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=改成自己的',
            imageUrl:'https://ae01.alicdn.com/kf/Hdfe28d2621434a1eb821ac6327b768e79.png',
            jenkinsUrl: "${env.JENKINS_URL}",
            message:'构建失败 ❌',
            notifyPeople:'李启龙'
        }
    }
}

依旧是把所有内容都集成在一个脚本当中,方便整体维护管理。

3,优化方案

在完成这个实验之后,我又继续前进,将脚本当中用到的ansible剧本进行了一波优化调整,以简化脚本当中的内容,让剧本兼容更多的项目构建,从而达到多用,复用的目录,新的思路也已经整理成文章,可以直接点击下边文章跳转。



Jenkins-pipeline学习笔记–pipeline结合ansible剧本进行批量的部署与回滚配置 |坐而言不如起而行! 二丫讲梵

之前还在头疼批量部署与回滚的事情,最近各方面接触ansible开始多起来,于是将ansible接入到了部署流程中,从而将批量部署与回滚变得简化起来。 先看一下ansible的剧本构造: [root@ops-eryajf-test-1 deploystatic]$tree . ├── hosts ├── README.md ├── roles │   ├── deploy │   │   ├── files │   │   │   └


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

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

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