git rollback代码都没了_基于Gitlab+Jenkins的代码自动化发布

这里所讲的自动化发布是指代码从提交到仓库,到发布到目标服务器的整个过程。

主要涉及到两个工具Gitlab,Jenkins,要完成自动化还需要rsync,qqbot,log,ant、shell脚本,python等。

Gitlab:我们主要用它来做代码的仓库

Jenkins:用来执行任务的持续集成,构建等。

一、大体的自动化思路:

开发人员push代码到gitlab,触发webhook,调用jenkins job 执行代码拉取,编译,调用loadblance,下架部分服务器更新代码,验证更新后的可用性,上线;再下架另一部分服务器,更新代码,再上线。再将本次发布状态推送给项目组。

二、实际工作中,我们遇到的上面要复杂。

服务器环境包括:测试环境,开发环境,预发布环境,生产环境等。 

代码仓库又分为多个分支:master分支,开发分支,项目分支,本地分支等。

因此要完成整个过程自动化,还需要整合多分支,多环境的情况。

三、测试环境的自动化思路:

  1. 建一个dev分支用来专门发布测试环境,此分支只允许开发人员合并和push,不能直接在上面改代码。

  2. 开发人员开发一个功能,先在本地建一个本地分支,写完后合并到dev,然后push到gitlab,gitlab触发钩子事件,调用jenkins完成项目的自动化部署。

以上实际还不能完全自动化,开发人员仍需花不少时间在分支的提交,切换、合并,push等重复繁琐的工作上。于是需对GIT操作自动化,将提交、切换、合并、push整合成工具,后面贴出工具源码。

四、预发布环境的自动化思路:

  1. 预发布采用和测试环境一样的思路,只是dev分支换成了master分支。

  2. master分支:我们用它来发预发布和生产,没错,两套环境用同一个分支,此分支只有项目经理有权限push,普通开发没权限操作。

    同样需要对项目经理git操作master自动化,后面贴出工具。

五、生产环境的自动化发布:

    生产环境的发布只是取消了webhook自动触发jenkins job,改为手动点击发布,主要是为发布安全考虑。

六、实操:

    1.设置webhook,对测试环境job和预发布环境job设置相应的钩子事件。

abe8cc97845d3626957b277fc122f630.png

    2.在jenkins中配置git插件

e8feb581747475a0cf6d9161b7b037ba.png

    3.配置jenkins job,这里用shell脚本做一系列的job,无需像网上安装各种繁琐的插件。

#!/bin/bash

#本案例中WORKSPACE=/root/.jenkins/workspace/dev_test

#源目录

src="$WORKSPACE/WebRoot/"

#发布的目标目录

dest="/usr/local/apache-tomcat-6.0.39/webapps/xiangmu/"

#目标主机用户

user="root"

#目标主机,测试机1、测试机2

host1="10.111.111.1"

host2="10.111.111.2"

# 需要发布的文件列表

cd $WORKSPACE

change_file_list=`git diff --name-only HEAD~ HEAD`

echo "需要发布的文件列表:$change_file_list"

#定义机器人发布消息功能函数

function qqbot_deploy(){

proj_name=`git show $commitid --pretty=format:"%s" |sed -n 1p`

author=`git show $commitid --pretty=format:"%an" |sed -n 1p`

now_time=`date "+%Y-%m-%d %H:%M:%S"`

qq send group IT群 "

QQ消息机器人:

【测试环境】 发布时间:$now_time 自动化发布完成

项目:$proj_name 状态:$status $solution

发布的文件列表:$change_file_list

发布人:$author" &

}

# 定义执行命令成功或失败日志记录功能函数

function log(){

 if [ $? -eq 0 ];then

     echo "执行'$arg'成功"

 else

     echo "执行'$arg'失败"

     status="发布失败"

     qqbot_deploy

     exit 1

 fi

}

# 定义java编译功能函数

function ant_shell(){

 #jdk需要基于1.7,ant低于1.9编译

 cd $WORKSPACE

 arg="编译"

 #ant >/dev/null 2>&1

 ant

 log

 # 一套代码,定义配置文件中心,拷贝不同的配置文件到不同的环境。这里拷贝测试环境配置文件到测试环境

 \cp -rf conf/xiangmu/dev/system_dev.properties WebRoot/WEB-INF/classes/system.properties

 \cp -rf conf/xiangmu/dev/ApplicationContext_dev.xml WebRoot/WEB-INF/classes/spring/ApplicationContext.xml

 \cp -rf conf/xiangmu/dev//ApplicationContext-service_dev.xml WebRoot/WEB-INF/classes/spring/ApplicationContext-service.xml

}

# 定义java发布功能函数

function deploy_java(){

   #1.编译

   ant_shell

   #2.对e互助测试1的操作

   #2.1修改测试机1的负载均衡的值为0

   arg="修改负载均衡的值"

   python ModifyLoadBalancerBackends_test1_value0.py

   log

   sleep 3

   #2.2发布测试机1的代码,rsync安静模式同步

   arg="发布$host1代码"

   rsync -e 'ssh -o stricthostkeychecking=no -p22' -qapgolr --progress --delete $src $user@$host1:$dest

   log

  #2.3重启测试机1的tomcat

   ssh $host1 /home/tomcat/ver/restart_tomcat.sh&

   sleep 18

   status_code1=`curl -I -m 10 -o /dev/null -s -w %{http_code} http://$host1/planweb/index.do`

   if [ $status_code1 -eq 200 ]

   then

       echo "http://$host1/planweb/index.do 打开正常"

   else

       echo "http://$host1/planweb/index.do 打开失败"

       #发布失败通知消息到qq群

       solution="原因和方案:可能tomcat启动时间过长的误报,延长sleep时间,重新发布一次"

       status="发布失败"

       qqbot_deploy

       exit 1

   fi        

   #3.上线测试机1,并下线测试机2,修改测试机1的负载均衡值为10,修改测试机2的值为0

   arg="修改负载均衡的值"

   python ModifyLoadBalancerBackends_test1_value10.py  

   log

#4.对测试机2的操作

   #4.1发布代码到测试机2

   arg="发布$host2代码"

   rsync -e 'ssh -o stricthostkeychecking=no -p22' -aqpgolr --progress --delete $src $user@$host2:$dest

   log

   #4.2重启测试机2的tomcat

   ssh $host2 /home/tomcat/ver/restart_tomcat.sh&

   sleep 22

   status_code2=`curl -I -m 10 -o /dev/null -s -w %{http_code} http://$host2/planweb/index.do`

   if [ $status_code2 -eq 200 ]

   then

       echo "http://test.xiangmu.com 打开正常"

           #4.3上线测试机2,修改测试1的值为10,全部上线

           arg="修改负载均衡的值"

           python ModifyLoadBalancerBackends_test2_value10.py

           log

           echo "测试机$host1,$host2上线java代码完成"          

           #动态文件,发布成功消息通知到qq群

           status="发布成功"

           qqbot_deploy

           #退出循环

           exit 0

   else

       echo "http://test.xiangmu.com打开失败"

       #发布失败通知消息到qq群

       status="发布失败"

       solution="原因和方案:可能tomcat启动时间过长,重置clb,查看tomcat启动log"

       qqbot_deploy

       exit 1

   fi

}

# 定义静态文件发布功能函数,无需重启tomcat

function deploy_static(){

   arg="发布$host1的静态代码"

   rsync -e 'ssh -o stricthostkeychecking=no -p22' -qapgolr --progress --delete $src $user@$host1:$dest

   log

   arg="发布$host2的静态代码"    

   rsync -e 'ssh -o stricthostkeychecking=no -p22' -qapgolr --progress --delete $src $user@$host2:$dest

   log

}

#异步执行:代码质量分析。

function code_quality_analysis(){

   if [ ! -f "sonar-project.properties" ];then

       echo -e "sonar.projectKey=dev_test \nsonar.host.url=http://localhost:9000/sonar \nsonar.projectName=dev_test \nsonar.projectVersion=1.0 \nsonar.sources=src \nsonar.java.binaries=build/WEB-INF/classes" >sonar-project.properties  

   fi

   BUILD_ID=

   /usr/local/sonar-scanner/bin/sonar-scanner &

   echo "开始异步运行代码质量分析"

}

#定义代码发布功能函数

function deploy(){

   #标记静态文件出现的次数,解决遇到静态文件重复同步多次的问题

   count=0

     #遍历发布的文件列表

   for i in $change_file_list;

   do    

       # 遇到有java等后缀需要编译的文件,则编译发布。

       if [ "${i##*.}"x = "java"x ] || [ "${i##*.}"x = "xml"x ] || [ "${i##*.}"x = "properties"x ];then

           #发布编译的代码

           deploy_java

       # 如果是前端静态文件,则无需编译直接发布。第一次遇到静态发布一次,再遇到静态则不发布。  

       elif [ ! "${i##*.}"x = "java"x ] || [ ! "${i##*.}"x = "xml"x ] || [ ! "${i##*.}"x = "properties"x ] && [ $count -eq 0 ];then

           #发布静态文件

             deploy_static

           #标记为1,记已同步一次代码

             count+=1

       fi

    done

     #全静态文件,发送消息通知到qq群

   status="发布成功"

   echo "全静态文件发布完成"

   qqbot_deploy

 }

#紧急回滚措施,只是发布回滚,实际git上面没回滚,事后得修改原先bug重新提交发布。

function rollback(){

   cd ${WORKSPACE}

   echo "commitid:$commitid"

   if [ ! $commitid ] && [ ! $file ];then

       echo "commitid和file至少填一个"

       exit 1

   elif [ ! $commitid ] && [ $file ];then

       #回滚某个文件到上一次的更改

       num=2

       commitid=`git log -n $num --pretty=format:"%H" $file |sed -n ${num}p`

       git checkout $commitid $file

       deploy

   else

       arg="回滚"

       # 回滚到指定的commit版本,或者回滚指定版本的某个文件

       # git log WebRoot/campaign/daily/share.js 可以查看share.js最近修改的记录

       git checkout $commitid $file

       log

       #发布回滚的版本    

       deploy

   fi  

}

case $select in

   Deploy)

       echo "select:$select"

       commitid=`git rev-parse remotes/origin/dev`

       #发布

       deploy

       ;;

   Rollback)

       echo "select:$select"

       #回滚

       rollback

       ;;

   *)

       echo "*select:$select"

       commitid=`git rev-parse remotes/origin/dev`

       deploy

       ;;

esac

    4.实际效果

e8259f4cc5f4d7ea278c896e7f274006.png

    5.开发人员自动化git工具

#coding:utf-8

#author:laocao

#date: 20181225

#测试环境运行在python3.6 windows上

import os

from time import sleep

code_dir = "D:\\proj\\xiangmu"

#code_dir = "D:\git\xiangmu-git"

print("------------提交合并本地分支的代码到dev----------")

print("注意:本程序运行的的前提,代码必须在D:\proj\xiangmu中")

print("")

print("")

os.chdir(code_dir)

print("当前工作目录:" + os.getcwd())

#输入分支名称,拉取远端dev最新代码到本地

my_branch=input('请输入您本地的分支名称:')

os.system("git checkout %s" % my_branch)

os.system("git pull origin dev")

#输入项目描述,并提交到本地

desc=input('请输入项目描述:')

os.system("git add -A")

os.system("git commit -am '%s'" % desc)

# 切换到dev分支,拉取dev最新代码

os.system("git checkout dev")

os.system("git pull")

#合并本地分支到dev,并推送

os.system("git merge %s" % my_branch)

os.system("git push")

#返回本地分支

os.system("git checkout %s" % my_branch)

print("提交成功,返回本地分支%s" % my_branch)

input("按任意键退出")

    6.项目经理自动化git工具,根据commitid合并

#coding:utf-8

#author:jorden

#date: 20181225

#测试环境运行在python3.6 windows上

import os

from time  import sleep

code_dir = "D:\\proj\\xiangmu"

#code_dir = "D:\git\xiangmu-git"

print("------------合并dev的代码到master----------")

print("注意:本程序运行的的前提,代码必须在D:\proj\xiangmu中")

print("")

print("")

os.chdir(code_dir)

print("当前工作目录:" + os.getcwd())

# 切换到dev分支,拉取dev最新代码

os.system("git checkout dev")

os.system("git pull")

# 切换到master分支,拉取master最新代码

os.system("git checkout master")

os.system("git pull")

dev_commitid=input('请输入dev中需要合并的commitid:')

print(dev_commitid)

os.system("git cherry-pick " + dev_commitid)

print("dev_commitid: %s" % dev_commitid)

os.system("git push")

print("git自动合并完成")

input("按任意键退出")

    7.项目经理自动化git工具,根据文件合并。

#coding:utf-8

#author:laocao

#date: 20181225

#测试环境运行在python3.6 windows上

import os

from time  import sleep

code_dir = "D:\\proj\\xiangmu"

#code_dir = "D:\git\xiangmu-git"

print("------------合并dev的代码到master,按文件合并----------")

print("注意:本程序运行的的前提,代码必须在D:\proj\xiangmu中")

print("")

print("")

os.chdir(code_dir)

print("当前工作目录:" + os.getcwd())

# 切换到dev分支,拉取dev最新代码

os.system("git checkout dev")

os.system("git pull")

# 切换到master分支,拉取master最新代码

os.system("git checkout master")

os.system("git pull")

#dev_commitid=input('请输入dev中需要合并的commitid:')

file_list = input('请输入dev中需要合并的文件列表:')

os.system("git checkout dev " + file_list)

print("file_list: %s" % file_list)

#输入项目描述,并提交到本地master

desc=input('请输入项目描述:')

os.system("git add -A")

os.system("git commit -am '%s'" % desc)

os.system("git push")

print("git自动合并完成")

input("按任意键退出")

    8.脚本完成了如下功能:

    编译:根据实际项目,这里用的ant。也可以maven

    动静分离发布:为满足前后端不同的发布需求,提高发布效率,采用了动静分离。纯静态直接同步到各服务器,只需几秒。动态文件发布则需编译,调用负载均衡,重启tomcat等,需1-2分钟。

    代码质量分析: 发布完,sonar自动分析开发人员代码仓库的代码质量,作为后期改进。

    代码同步:采用rsync ssh模式同步到目标服务器

    调用负载均衡api:通过python sdk调用腾讯云负载均衡api,来上下线服务器。

    日志记录: 每条命令的执行结果进行判断,出错则终止运行。

    定义代码配置中心:一套代码需要放在几个环境中运行,所以定义了不同的配置区分不同的环境, 发布时拷贝相对应的配置文件到目标服务器,这样就达到了管理一套代码,运行在不同的环境。

    代码回滚:有时发布上去的代码有问题,这时可以紧急回滚,此处提供了按commitid和文件两种回滚方式

    发布过程中对网站状态进行判断,若打开非200,则不上线。

   9.消息通知:用qqbot机器人自动发消息到群,让团队了解发布状态。qqbot采用smartqq协议,由于腾讯已下线,这里可用其他机器人插件替代(如酷Q)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值