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

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

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

一、自动化部署概述java

1.1 什么是自动化部署linux

一句简单的话归纳:部署的过程当中全部的操做所有自动化,无需人工手工干预。git

1.2 自动部署的好处web

传统的部署方式以下:shell

运维人员手工使用Scp、Xftp等方式来传输数据后端

手工登陆服务器执行git pull 、svn update等命令进行更新代码的操做centos

开发人员手工编译打包,而后经过内网传输给运维人员api

运维人员经过rz上传的方式上传到目标服务器,而后,执行重命名原包、拷贝新包到目标目录,再执行服务应用重启命令完成整个部署过程

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

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

整个过程都须要人员参与,占用大量的时间,效率低下

上线、更新、回滚速度慢

存在必定的管理混乱,人为误操做的机率增大

因此,自动化部署的优点就经过这种对比显现出来了!!

二、自动化部署的工具

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

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是面向罐装的解决方案用例,目前还不够灵活。

三、自动化部署的流程

大概的流程步骤以下:

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

clipboard.png

若是在测试时出现问题,则须要回滚到上一次稳定版本。

通常能够将须要回滚的版本先列出来,而后将现有的软连接文件删除,从新将上一个版本的源文件生成一个软连接至目标目录,而后从新启动服务,进行自动化测试,最终加入集群。

四、自动化部署实践

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

clipboard.png

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

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

一、操做系统:centos 6.5 64位

二、代码使用gitlab进行管理

三、代码每次上线经过tag控制

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

五、WEB container使用tomcat实现

六、项目构建使用maven

使用脚本注意事项:
一、 发布机器须要可以解析web服务器主机名,而且配置ssh通讯
二、 变量中的目录以及用户等信息须要本身建立,脚本没有作判断本身建立。我这里web服务器是使用ansible进行部署的,相关目录和用户都会自动建立。
三、代码的部署使用tag,可是代码的更新使用软链接来控制,回滚则切换到上一个软链接
四、因为java是编译型语言,咱们使用maven来进行编译,因此须要安装maven环境。
五、关于环境配置文件:配置文件为本身手动维护,每次都是删除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代码自动发布

脚本适应环境:

一、操做系统:centos 6.5 64位

二、代码使用gitlab进行管理

三、代码每次上线和回滚经过tag控制

补充:若是须要在你的企业使用个人这种部署方式,还须要有相应环境规范以及git分支管理规范。

使用脚本注意事项:
一、 发布机器须要可以解析web服务器主机名,而且配置ssh通讯
二、 变量中的目录以及用户等信息须要本身建立,脚本没有作判断本身建立。我这里web服务器是使用ansible进行部署的,相关目录和用户都会自动建立。
三、代码的部署使用tag,回滚原则为回滚到上个tag版本,因此部署脚本自己没有备份代码。
四、若是须要过滤一些临时目录或者日志目录,能够在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 能够获取一份最新整理的技术干货。

clipboard.png