攻克痛点:DevOps线上部署的最后一公里

杨彪 2017-12-05 14:04:58

本文根据DBAplus社群【运维技术月·第三周】分享整理而成,文末还有好书送哦~

 

讲师介绍
 
随着微服务的发展,DevOps的流行,以前每周或每月一次的更新变成了现在几乎每天都在更新上线产品了,最后一公里的线上更新部署的保障至关重要,今天借社群这个平台,跟大家分享下个人的经验。

 

因为DevOps打通了开发和运维之间以前不可逾越的鸿沟,使得线上部署已经不再仅仅是运维部门的事情了,所以要保障更新部署能顺利进行,就需要开发和运维一起共同配合才能很好地完成。因此,本次分享我将从开发侧和运维侧共同介绍的,主要包括三个方面的内容:

 

  1. 发布更新常用技术

  2. 线上项目部署拓扑结构

  3. 网关层和服务层的灰度发布实战

 

 

一、发布更新常用技术
 

 

本次分享主要以干货为主,所以让我们直接开始今天的主题吧。首先我给大家介绍下更新发布的一些常用技术,主要有以下几种:

 

  • 蓝绿部署

  • 滚动部署

  • 灰度/金丝雀发布

 

1、首先,什么是蓝绿部署?

概念

 

蓝绿部署是不停老版本,部署新版本然后进行测试,确认新版本没有问题了,再将流量切到新版本,然后老版本同时也升级到新版本。其特点是部署无需停机,并且风险较小,不过对服务器成本有点浪费,毕竟要同时部署两个版本。

部署过程

 

  • 保持旧的版本不变(线上更新前原始版本),此时所有流量都导向该旧版本的。

 

  • 部署新的版本,通过代理将流量慢慢地切到新的版本,观察测试。这里可以通过不同的规则先把公司人员先切到新版本测试,然后再切一小部分用户进行测试,最后切全量进行测试。

 

     

    • 如果新版本测试正常,就可以删除旧的版本资源,比如服务器或实例等,从此线上使用新的版本。如果测试过程中有任何问题,我们都可以立即把流量切回老版本进行回滚,这样风险非常的小。

     

    2、其次,什么是滚动部署?

    概念

     

    滚动部署一般是取出一个或者多个服务器停止服务,然后执行更新,并重新将其投入使用,周而复始地直到集群中所有的实例都更新到新的版本。这种部署方式相对于蓝绿部署,更加节约资源,因为它不需要运行两个集群、两倍的实例数。

     

    不过滚动部署有个最大的缺点,就是在更新的时候没有一个稳定的正式环境,如果在更新过程中出现了问题很难立即回滚。

    部署过程

     

    假设我们线上有100个服务实例,现在进行滚动更新。

     

    • 每次更新10个实例,每次更新间隔5分钟。

    • 周而复始地直到集群中所有的实例都更新到新的版本。

     

    3、最后,什么是灰度/金丝雀发布?

    概念

     

    灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度,而我们平常所说的金丝雀部署也就是灰度发布的一种方式。

     

    补充:17世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会立即发现,而当瓦斯含量超过一定限度时,虽然人类毫无察觉,但金丝雀却早已毒发身亡。在当时在采矿设备相对简陋的条件下,工人每次下井都会带上一只金丝雀作为“瓦斯检测指标”,以便在危险状况下紧急撤离。

     

    图一 灰度/金丝雀发布/金丝雀

    部署过程

     

    • 从负载均衡列表中移除掉“金丝雀”服务器,切断用户流量。

    • 然后对“金丝雀”服务器进行更新部署,此时该服务器为新版本。

    • 然后对“金丝雀”服务器上的新版本进行测试。

    • 然后再将“金丝雀”服务器重新添加到负载均衡列表中。

    • 如果“金丝雀”服务在线使用测试成功,继续升级剩余的其他服务器,否则回滚。

     

     

    二、线上项目部署拓扑结构
     

     

    介绍完常用的几种更新发布技术后,我将介绍一个线上实际项目的部署结构,先看看两张图:

     

    图二 游戏服架端构图

     

    SOA架构模式是一个经典的分布式软件架构模式,服务之间使用RPC运程调用功能,而服务的注册和发现则使用ZooKeeper这样的目录服务器。这样游戏服务就拆分为三层结构:最前边的网关(gate)服务器、中间为各游戏服务器(gameServer),最后边的数据库(DB)服务器。这样把网络功能单独提取出来,让用户统一去连接网关服务器,再由网关服务器转发数据到后端游戏服务器。而游戏服务器之间数据交换也统一连接到网关服进行交换。所有与DB交互的都连接到DB服务器来代理处理。

     

    我们在介绍完服务的架构后,再来看看具体的运维部署结构是什么样的?

     

    图三 服务部署拓扑结构

     

    从这张服务器部署拓扑结构图中我们可以看出,更新部署的关键痛点主要在ELB到gateway,gateway到sever的过程中。Gateway是通过ELB负责均衡实现的流量分发,而server和gateway主要通过zookeeper实现的服务注册与发现功能,所以接下来我将主要分成两部分来介绍它们的具体实现过程。

     

     

    三、网关层和服务层的灰度发布实战
     

     

    1、网关层的高可用自动发现实现方案

     

    在网关层我们主要采用Etcd+Confd+Nginx或Consul+Consul-Template+Nginx两种方式来实现,两种方式都差不多,我在这里主要介绍下后者如何实现的。

     

    图四 网关层的自动发现服务

     

    从上图可以看到,我们可以添加服务或移除服务,然后consul通过服务健康检测来实现的网关层服务自动发现,最后Nginx通过自动加载consul-template生成的新的配置文件来进行流量切换和负载。下面我将简单介绍下Consul+Consul-Template+Nginx的安装过程,其步骤如下:

     

    • 安装Consul服务端

     

    wget https://releases.hashicorp.com/consul/1.0.0/consul_1.0.0_linux_amd64.zip

    unzip consul_1.0.0_linux_amd64.zip

    mv consul /bin

    rm consul_1.0.0_linux_amd64.zip

     

    在/etc/consul/目录下添加配置项config.json文件,并且设置server=true,代表以服务启动。同时指定Consul机群中所有的ip来加入机群。

     

    {                                            

      "datacenter": "test-dc",                                          

      "data_dir": "/tmp/consul",

      "log_level": "DEBUG",                                            

      "node_name": "consul00",

      "server": true,                                              

      "bootstrap_expect": 3,                                              

      "ui_dir": "/opt/consul-ui",                                       

      "bind_addr": "192.168.0.101",                                         

      "leave_on_terminate": true,

      "start_join": [                                                  

        "192.168.0.101",                                                  

        "192.168.0.102",                                                    

        "192.168.0.103"

      ]                                              

    }

     

    • 启动Consul服务

     

    sudo service consul start

     

    • 安装Consul的客户端(如果使用程序主动向Consul注册服务可以省略)

     

    安装客户端和安装服务端方法一样,还在是在/etc/consul/目录下添加配置项config.json文件,只是不需要设置server属性(server默认为false)。

     

    {

      "datacenter": "test-dc",

      "data_dir": "/tmp/consul",

      "log_level": "DEBUG",

      "node_name": "web-1",

      "leave_on_terminate": true,

      "start_join": [

        "192.168.0.101",

        "192.168.0.102",

        "192.168.0.103"

      ]

    }

     

    • 使用consul members命令查看consul是否都启动正常

     

     

    • 在Consul客户端上添加服务,在/etc/consul目录下新建配置项web.json文件

     

    {

      "service": {

        "name": "apache",

        "tags": ["foo"],

        "address": "192.168.0.105",

        "port": 80,

        "enableTagOverride": false,

        "checks": [

          {

            "tcp": "localhost:80",

            "interval": "10s"

          }

        ]

      }

    }

     

    • 安装Consul-Template

     

    wget https://releases.hashicorp.com/consul-template/0.13.0/consul-template_0.13.0_linux_amd64.zip

    $ unzip consul-template_0.13.0_linux_amd64.zip

    $ rm consul-template_0.13.0_linux_amd64.zip

    $ mv consul-template /bin

     

    使用Consul-Template实现服务自动化添加和移除。

     

    首先启动consul-template,并指定模板地址和生成文件地址,以及执行nginx -s reload操作。

     

    sudo ./consul-template -template "/etc/consul-template/nginx.tmpl:/etc/nginx/sites-available/default:nginx -s reload"

     

    然后在/etc/consul-template/nginx.tmpl文件中添加Consul-Template模板配置,每次服务有变化都会自动生成ngnix配置文件/e

     

    tc/nginx/sites-available/default。

    server {

      listen 80 default_server;

      location / {

        proxy_pass http://frontend;

      }

    }

    upstream frontend { {}

      server {{.Address}};{}

    }

     

    当然除了上面介绍的从Consul主动去检测服务健康外,我们还可以通过程序主动向Consul注册服务,其Java代码如下。

     

    首先在pom.xml文件中引用Consul的依赖库。

     

     

        com.orbitz.consul

        consul-client

        0.17.0

     

     

    然后在Java启服代码中实现注册功能。

     

     

     

    介绍完网关层的实现后,接下来我们看看服务层又是如何实现的呢?

     

    2、服务层灰度发布方案

     

    由于服务层我们主要使用的是dubbo实现的RPC功能,dubbo的架构图如下:

     

    图五 dubbo架构图

     

    而dubbo可以使用group的方式进行灰度发布,具体步聚如以下三步:

     

    • 先现将服务提供者(provider)分为两组AB,将新版本的group修改为B组,如/service/B ,并将B组发布到线上。此时旧版本的group为A,如/service/A。

    • 然后将新版本的消费者(consumer)发布,并修改消费者(consumer)的group为 /service/B。

    • 结合网关层的服务自动发现机制,设置权重,切部分流量到goup为/service/B的消费者(consumer)上进行测试。

    • 如果测试没有问题,继续把旧的服务提供者(provider)和消费都(consumer)更新为新的版本,同时设置group为/service/B。

     

    这样就实现中服务层的灰度发,其中消费者(consumer)对应到我们服务架构中的网关服(gateway)。

     

    通过本次的分享,我们介绍了更新部署的技术和流程,并实现了服务的灰度发布功能,虽然还有很多可以继续优化提升的地方,不过它也能有效的保障了服务部署的稳定性和安全性。感谢大家今晚在百忙之中能参加我的分享,谢谢!

     

    Q&A
     

     

    Q1:问ELB这层一般用什么软件实现?

    A1:这里可以使用的解决方案挺多,比如我们使用的AWS的ELB服务,如果小的项目可以直接使用Nginx就足够了的,当然还有像LVS等。

     

    Q2:「问题1」服务器批量增加和删除怎么实现注入Consul的?

    A2:我在分享中有介绍过,分为两种:一种是Consul主动的检测,另一种为程序在启动的时候向Consul中注册。可看看我前面的介绍。

     

    Q3:问现在常提的API网关怎么理解?

    A3:网关层,主要是用于和前端直接产生交互的,是各种服务的统一入口,它屏蔽了服务直接暴露到前端。它最重要的是路由和过滤器功能,同时还会用来提供监控、授权、安全、调度等。

     

    直播链接回放
     

    https://m.qlchat.com/topic/details?topicId=2000000271740379&null

     
    活动预告