一键实现自动化部署(灰度发布)实践_回滚

在过去几年的DevOps的浪潮中,自动化、持续集成这两个概念早已深入人心(互联网技术人)。比尔盖茨先生曾经都说过:“任何技术在一个业务中使用的第一条规则就是,将自动化应用到一个高效的操作上将会放大高效。第二条就是自动化应用到一个低效操作上,则放大了低效率。”

自动化部署也逐渐成为各中小型企业追求的方向,那么,今天民工哥就自动化部署的概述、自动化部署的工具、自动化部署的流程、自动化部署实践等4个方面,与大家一同来讨论、交流一下关于中小企业自动部署的问题。

1、自动化部署概述

1.1 什么是自动化部署

一句简单的话概括:部署的过程中所有的操作全部自动化,无需人工手工干预。

1.2 自动部署的好处

传统的部署方式如下:

  • 运维人员手工使用Scp、Xftp等方式来传输数据
  • 手工登录服务器执行git pull 、svn update等命令进行更新代码的操作
  • 开发人员手工编译打包,然后通过内网传输给运维人员
  • 运维人员通过rz上传的方式上传到目标服务器,然后,执行重命名原包、拷贝新包到目标目录,再执行服务应用重启命令完成整个部署过程

看似非常简单,也不是很麻烦,但是一旦项目多,部署频繁,这种情况下就会大大降低工作效率。民工哥之前工作中就有这类体验,公司的活动类项目高达100+,很多都是需要快速上线及下线、或者更新的,手工部署真的累。

传统的部署方式有以下的缺点:

  • 整个过程都需要人员参与,占用大量的时间,效率低下
  • 上线、更新、回滚速度慢
  • 存在一定的管理混乱,人为误操作的机率增大

所以,自动化部署的优势就通过这种对比显现出来了!!

2、自动化部署的工具

有自动动部署的概念,就需要自动化部署的工具,今天来介绍下一些这方面的工具给大家,怎么用?如何用?大家根据实际需求来定,一切不以需求来定的工具、流程、方法等都是耍流氓。

2.1 Jenkins 

Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。Jenkins应该说是目前最好用的持续集成工具之一,它的插件非常多,安装也很方便,功能相当的强大、灵活,最大的缺点就是学习成本较高。

2.2 ElectricFlow ElecticFlow支持大量插件和基于Groovy的 DSL,CLI,APIs。 Visual Studio允许用户定义版本定义,自动化运行,跟踪版本等等。你可以在一台服务器安装或在Azure里做成实例。DeployBot提供大量集成,包括通过Slack部署的能力。TeamCity 有智能的配置功能和拥有官方Docker镜像服务器和代理。Bamboo公布“integrations that matter”并提供一个“small teams”包,捐赠给 Room to Read慈善事业。部署使用Jenkins触发。CircleCI提供从资源到创建到部署的解决方案,并且支持大量的语言和应用。Gradle使用Groovy创建脚本,按惯例构建框架,并认为构建工具同时作为Apache的Ant的通用工具。根据TechCrunch这篇文章,Distelli 在2015年12月获得了280万美元的资金,是由前AWS员工Rahul Singh创立的。Capistrano 文档具有脚本语言和“理智的,富有表现力的API。”Travis CI是一个免费的开源项目。 BuildBot是面向罐装的解决方案用例,目前还不够灵活。

3、自动化部署的流程

大概的流程步骤如下:

  • 获取代码
  • 编译打包
  • 移除目标服务器
  • 解压文件到目标目录
  • 拷贝差异化文件
  • 重启服务
  • 测试
  • 重新加入集群
  • 继续下一个节点或一组节点

一键实现自动化部署(灰度发布)实践_回滚_02

如果在测试时出现问题,则需要回滚到上一次稳定版本。

一般可以将需要回滚的版本先列出来,然后将现有的软链接文件删除,重新将上一个版本的源文件生成一个软链接至目标目录,然后重新启动服务,进行自动化测试,最终加入集群。

4、自动化部署实践

说完了一堆的理论东东,接下来就是需要实践操作了,我之前也写过一个自动化的脚本,如下图:

一键实现自动化部署(灰度发布)实践_git_03

这里列举两个实例,这两个实例是由网友西门飞冰投稿提供,具体的实例如下:

4.1 使用shell脚本实现java灰度发布

脚本使用环境:

1、操作系统:centos 6.5 64位

2、代码使用gitlab进行管理

3、代码每次上线通过tag控制

4、前端使用haproxy实现负载均衡,使用haproxy socat实现RS的平滑上下线

5、WEB container使用tomcat实现

6、项目构建使用maven

使用脚本注意事项:1、 发布机器需要能够解析web服务器主机名,并且配置ssh通信2、 变量中的目录以及用户等信息需要自己创建,脚本没有做判断自己创建。我这里web服务器是使用ansible进行部署的,相关目录和用户都会自动创建。3、代码的部署使用tag,但是代码的更新使用软连接来控制,回滚则切换到上一个软连接4、由于java是编译型语言,我们使用maven来进行编译,所以需要安装maven环境。5、关于环境配置文件:配置文件为自己手动维护,每次都是删除git仓库拉取下来的配置文件,把对应环境的代码文件复制进编译目录进行编译。

脚本代码大概的步骤如下:

#!/bin/bash

# 设置时间变量
CTIME=$(date "+%Y-%m-%d-%H-%M")
# 项目名称,建议和gitlab仓库名称一致
project=
# 本地代码目录(gitlab拉取代码后存放目录)
CODE_DIR=/data/gitlab/"$project"
# 临时代码目录,用来修改配置文件和编译打包代码
TMP_DIR=/data/tmp/"$project"
# 用来存放war包
WAR_DIR=/data/war/"$project"
# 对应环境配置文件
deploy_conf=/data/conf/pro/"$project"/*
# 代码中的配置文件路径
local_conf=$TMP_DIR/src/main/resources/config
# 远程主机名称
REMOTE_HOST="tomcat-01 tomcat-02"
# 远程主机代码目录
REMOTE_CODE_DIR=/data/webapps/"$project"
# 远程主机用户
REMOTE_USER=root
# 远程主机war包存放目录
REMOTE_WAR_DIR=/data/war/
# 代码临时目录
CODE_TMP=/data/code_tmp/
# 上线日志
DEPKOY_LOG=/data/log/pro_log.log

# 脚本使用帮助
usage(){
echo $"Usage: $0 [deploy tag | rollback_list | rollback_pro ver]"
}

# 拉取代码
git_pro(){
if [ $# -lt 1 ];then
echo "请传入tag"
exit 1
fi
tag=$1
cd $CODE_DIR && git checkout master && git pull && git checkout $1
if [ $? != 0 ];then
echo "拉取代码失败"
exit 10
fi
cd $CODE_DIR && git pull 2>/dev/null >/dev/null
# 推送代码到临时目录
rsync -avz --delete $CODE_DIR/ $TMP_DIR/ 2>/dev/null >/dev/null
}

# 设置代码的配置文件
config_pro(){
echo "设置代码配置文件"
rm -f $local_conf/config.properties
.........
}

# 打包代码
tar_pro(){
echo "本地打包代码"
cd $TMP_DIR && /usr/local/maven/bin/mvn clean compile war:war && cp target/"$project".war "$WAR_DIR"/"$project"_"$tag"_"$CTIME".war
}

# 推送war包到远端服务器
rsync_pro(){
echo "推送war包到远端服务器"
for host in $REMOTE_HOST;do
scp "$WAR_DIR"/"$project"_"$tag"_"$CTIME".war $REMOTE_USER@$host:$REMOTE_WAR_DIR
done
}

# 解压代码包
solution_pro(){
echo "解压代码包"
for host in $REMOTE_HOST;do
ssh $REMOTE_USER@$host "unzip "$REMOTE_WAR_DIR""$project"_"$tag"_"$CTIME".war -d "$CODE_TMP""$project"_"$tag"_"$CTIME"" 2>/dev/null >/dev/null
done
}

# api测试
test_pro(){
# 运行api测试脚本,如果api测试有问题,则退出部署
if [ $? != 0 ];then
echo "API测试存在问题,退出部署"
exit 10
fi
}


# 部署代码
deploy_pro(){
echo "部署代码"
...................
sleep 3
# 执行api测试
test_pro
ssh haproxy "echo "enable server $project/$host" | /usr/bin/socat /var/lib/haproxy/stats stdio"
done
}
# 列出可以回滚的版本
rollback_list(){
echo "------------可回滚版本-------------"
ssh $REMOTE_USER@$REMOTE_HOST "ls -r "$CODE_TMP" | grep -o $project.*"
}

# 回滚代码
rollback_pro(){
echo "回滚中"
for host in $REMOTE_HOST;do
.............................
sleep 3
ssh haproxy "echo "enable server $project/$host" | /usr/bin/socat /var/lib/haproxy/stats stdio"
done
}

# 记录日志
record_log(){
echo "$CTIME 主机:$REMOTE_HOST 项目:$project tag:$1" >> $DEPKOY_LOG
}

# 代码执行选项设置
main(){
case $1 in
deploy)
git_pro $2;
config_pro;
tar_pro;
rsync_pro;
solution_pro;
deploy_pro;
record_log $2;
;;
rollback_list)
rollback_list;
;;
rollback_pro)
rollback_pro $2;
record_log;
;;
*)
usage;
esac
}
main $1 $2

4.2 使用shell实现php代码自动发布

脚本适应环境:

1、操作系统:centos 6.5 64位

2、代码使用gitlab进行管理

3、代码每次上线和回滚通过tag控制

补充:如果需要在你的企业使用我的这种部署方式,还需要有相应环境规范以及git分支管理规范。

使用脚本注意事项:1、 发布机器需要能够解析web服务器主机名,并且配置ssh通信2、 变量中的目录以及用户等信息需要自己创建,脚本没有做判断自己创建。我这里web服务器是使用ansible进行部署的,相关目录和用户都会自动创建。3、代码的部署使用tag,回滚原则为回滚到上个tag版本,所以部署脚本本身没有备份代码。4、如果需要过滤一些临时目录或者日志目录,可以在rsync推送代码的时候使用–exclude选项进行过滤,示例脚本中过滤了.git目录和config.php文件是不会部署的。

#!/bin/bash

# 设置时间相关变量
CTIME=$(date "+%Y-%m-%d-%H-%M")
# 项目名称,建议和gitlab仓库名称一致
project=test
# 本地代码目录(gitlab拉取代码后存放目录)
CODE_DIR=/data/gitlab/pro/$project/
# 远程主机
REMOTE_HOST="LNMP-01.fblinux.com LNMP-02.fblinux.com"
# 远程主机代码目录
REMOTE_DIR=/data/www/fblinux/
# 远程主机用户
REMOTE_USER=root
# 远程主机代码执行用户
CODE_USER=php
# 上线日志
DEPKOY_LOG=/data/log/pro_log.log

#脚本使用帮助
usage(){
echo $"Usage: $0 [deploy tag]"
}

#拉取代码
git_pro(){
if [ $# -lt 1 ];then
echo "请传入tag"
exit 1
fi
echo "拉取代码"
cd $CODE_DIR && git checkout master && git pull && git checkout $1
if [ $? != 0 ];then
echo "拉取代码失败"
exit 10
fi
cd $CODE_DIR && git pull
}

#推送代码服务器
rsync_pro(){
for host in $REMOTE_HOST;do
echo "推送代码到服务器$host"
rsync -rPv -P --delete --exclude="config.php" --exclude=".git" $CODE_DIR -e 'ssh -p 22' $REMOTE_USER@$host:$REMOTE_DIR
if [ $? != 0 ];then
echo "推送代码失败"
exit 10
fi
echo "代码授权"
ssh $REMOTE_USER@$host "chown -R $CODE_USER $REMOTE_DIR"
if [ $? != 0 ];then
echo "代码授权失败"
exit 10
fi
done
}

#记录日志
record_log(){
echo "$CTIME 主机:$REMOTE_HOST 项目:$project tag:$1" >> $DEPKOY_LOG
}

main(){
case $1 in
deploy)
git_pro $2;
rsync_pro;
record_log $2;
;;
*)
usage;
esac
}
main $1 $2

以上就是两个实际的生产部署实例的配置环境、注意事项及代码等讲解。

读者如果需要上述两个实例的完整代码请在 民工哥技术之路 公众号后台回复自动化部署”来获取脚本完整代码的下载地址。

参考资料如下:

https://dzone.com/articles/21-automated-deployment-tools-you-should-know 

http://www.fblinux.com/?p=489    

http://www.fblinux.com/?p=476

在 民工哥技术之路 微信公众号对话框回复关键字:1024 可以获取一份最新整理的技术干货。


一键实现自动化部署(灰度发布)实践_回滚_04