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

4次阅读

共计 7039 个字符,预计需要花费 18 分钟才能阅读完成。

在过去几年的 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
ElectricFlow 是一个发布自动化工具,提供免费的社区版本,你可以在 VirtualBox 上运行。ElecticFlow 支持大量插件和基于 Groovy 的 DSL,CLI,APIs。

2.3 Microsoft Visual Studio
微软 DevOps 产品的基础之一是 Visual Studio。Visual Studio 允许用户定义版本定义,自动化运行,跟踪版本等等。

2.4 Octopus Deploy
Octopus Deploy 创建目的是为了.NET 应用的自动化部署。你可以在一台服务器安装或在 Azure 里做成实例。

2.5 IBM UrbanCode
2013 年被 IBM 公司收购,UrbanCode 自动化部署到本地或云环境。

2.6 AWS CodeDeploy
Amazon 的自动化部署工具 CodeDeploy, 有着令人印象深刻的客户名单、平台与语言无关。

2.7 DeployBot
DeployBot 可以链接任何 Git 存储库,并且允许手动或自动部署到多种环境。DeployBot 提供大量集成,包括通过 Slack 部署的能力。

2.8 Shippable
Shippable 规定了它们自己的“DevOps 支柱”和它们自己的 CI 平台,运行依靠称为 minions 的基于 Docker 的容器。

2.9 TeamCity
TeamCity 是一个来自 Jet Brains 的 CI 服务器。TeamCity 有智能的配置功能和拥有官方 Docker 镜像服务器和代理。

2.10 Bamboo
Bamboo Server 是 CI,由来自在 Atlassian 的人们提供,他们是 Jira 和 Confluence 的制造者。Bamboo 公布“integrations that matter”并提供一个“small teams”包,捐赠给 Room to Read 慈善事业。

2.11 Codar
Codar 是一个 HP 的持续部署解决方案。部署使用 Jenkins 触发。

2.12 CircleCI
CircleCI 是一个 CI 解决方案,强调灵活性、可靠性和速度。CircleCI 提供从资源到创建到部署的解决方案,并且支持大量的语言和应用。

2.13 Gradle
Gradle 是一个被一些业内最有名的例如 LinkedIn, Netflix, 和 Adobe 所使用的创建工具。Gradle 使用 Groovy 创建脚本,按惯例构建框架,并认为构建工具同时作为 Apache 的 Ant 的通用工具。

2.14 Automic
Automic 试图应用 DevOps 原理给一些后端应用,允许他们从已经在过去几年里许多前端、基于 web 的应用相同的实践上受益。

2.15 Distelli
Distelli 专门在任何地方部署 Kubernetes 集群,除了可以在任何云或物理服务器上使用。根据 TechCrunch 这篇文章,Distelli 在 2015 年 12 月获得了 280 万美元的资金,是由前 AWS 员工 Rahul Singh 创立的。

2.16 XL Deploy
XL Deploy 是一个来自 XebiaLabs 的应用发布自动化工具,支持大量插件和环境,使用无代理架构。

2.17 Codeship
Codeship 是服务器托管 CI 解决方案,通过原生 Docker 支持定制。

2.18 GoCD
一个 CD 服务器,强调可视化工作流,GoCD 是一个开源项目,由 ThoughtWorks 公司赞助开发。

2.19 Capistrano
Capistrano 是一个开源部署工具,使用 Ruby 开发。Capistrano 文档具有脚本语言和“理智的,富有表现力的 API。”

2.20 Travis CI
Travis CI 可以同步到你的 GitHub 账户,允许自动化测试和部署。Travis CI 是一个免费的开源项目。

2.21 BuildBot
BuildBot 是一个开源的基于 Python 的持续集框架,自称为“内含有电池的框架”。BuildBot 是面向罐装的解决方案用例,目前还不够灵活。

3、自动化部署的流程

大概的流程步骤如下:

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

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

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

4、自动化部署实践

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

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

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…
http://www.fblinux.com/?p=489
http://www.fblinux.com/?p=476

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

正文完
 0