Microservices 场景下的持续部署

内容简介

近两年作者在海外交付中参与   microservices   下的团队,为客户提升   Finance   系统的扩展性。 作者所在团队,3   对开发(pair   programming,   2     dev     pair)为客户支撑着   11     services,持续部署流水线(CD   pipeline)是其中必不可少的一个技术实践。本次分享作者将从实践的角度分享   microservices   架构下的持续部署(CD)。 内容概述

microservices 概述

当提到   microservice   的时候,我们通常会从下图开始:

为了从业务和技术方面得到更好的扩展能力,我们将单一架构的系统(Monolithic   architecture),拆分成若干的微服务(Microservices   architecture),这种拆分是架构演进的一个过程。 在整个拆分过程中,对团队的组织架构,数据的管理方式,部署监控技术方面都带来极大的挑战。 持续部署(简称   CD)是   microservices   架构中一个必备的实践之一。本文将介绍基于Docker     CD   方式。

部署方面带来的挑战

单一架构下(Monolithic),我们的系统   Code   base   可以在一个项目中,这个系统采用一个持续集成(简称:CI)   pipeline,并且此时我们也可以采用持续集成(简称:CD)pipeline,最终将系统持续部署到生产环境中。 在这种情况下,每当系统引入一个改变的时候,CI,CD   pipe   line   都会执行一次。例如:
  • - 10   mins   Unit   Test
  • - 2   hours   Acceptance   Test
  • - 15   mins   package
  • - 20   mins   deployment
上面列举的例子并不算坏,更庞大的系统可能会需要更多的时间。 当我们将   Monolithic   系统拆分成多个   micro   services   时,并且将每个   services   进行独立部署。每当系统引入一个改变的时候(code   change),它只会影响个别   service,我们只需要部署发生改变的部署,从新运行一个   service     CI,CD   pipeline:
  • - 1   mins   Unit   Test
  • - 1   mins   Integration   test
  • - 5   mins   package
  • - 5   mins   deployment
这种拆分之后,更符合我们对解耦的追求: 『当代码引入一个改变的时候,它应该影响的改动最小』 此时所提到的改变涉及整个开发流程,从代码到部署的影响做到了最小。 拆分   services   之后的代价是,每个   service   都需要独立部署,我们需要为每个   service   搭建   CD   pipeline。   microservices   场景下,不同的   service   按照需求可能会采用不同的技术栈。并且在每次新建   service   时,配套的日志,监控,报警系统也需要进行配置。 这个对   CD   提出了很大的挑战。

持续部署方面的实践

当我们谈持续部署的时候,此时也会包括持续集成。持续部署的整个过程会从代码   push     master   开始:

我们采用   Docker   来解决技术栈差异的问题,DevOps   创建部署工具将部署,监控,报警等配置模板化。 实践:
  • - 使用   Docker   构建和发布   service
  • - 采用   Docker   Compose   运行测试
  • - 使用   Docker   进行部署
准则:
  • - Build   pipe   line   as   Code
  • - Infrastructure   as   Code(base   on   AWS)
  • - 共享构建脚本

使用   Docker   构建和发布   service

  • - 使用   Docker   构建   service,service     docker   image   的方式发布
  • - 将   docker   发布到   docker   registry
  • - 从   docker   registry     pull   docker   image   进行部署

使用   Docker   Compose   运行测试

可以将多个   docker   image   进行组合。有些   service   需要访问数据,我们可以通过   docker   compose     service   image     database   image   组合在一起。 组合之后,我们可以采用   docker   compose   运行持续集成。 下面这个实例展示如何进行这种组合: https://gist.github.com/lvjian700/7c295e6a596e96526049f831d0eb8b13#file-docker-compose-yml

Build   pipeline   as   Code

通常我们使用   Jenkins   或者   Bamboo   来搭建   CI/CD   pipeline,每次创建   pipeline   需要进行大量的手工配置,此时很难自动化   CI   服务器配置。 Build   pipeline   as   Code,即使用代码来描述   pipeline,这样做可以带来非常好的可读性和重用性。我们可以很容易的做到   CI   服务器配置。 今年团队将所有   pipeline     Bamboo   迁移到了   BuildKite 。在   BuildKite   上可以使用如下代码描述上图的   pipeline: https://gist.github.com/lvjian700/7c295e6a596e96526049f831d0eb8b13#file-buildkite-yml

Infrastructure   as   Code

如果我们要发布一个基于   HTTP   协议的   REST-ful   API   service,我们需要   service   准备如下基础设施(Infrastructure):
  • - 可部署的机器
  • - 机器的   IP   和网络配置
  • - 设备硬件监控服务(GPU,Memory   等)
  • - 负载均衡(Load   Balancer)
  • - DNS
  • - AutoScaling   (services   自动伸缩服务)
  • - Splunk   日志收集
  • - NewRelic   性能监控
  • - Sentry.io     PagerDuty   报警
这些基础设施的搭建和配置我们希望将其模板化,自动化。我们才用代码描述基础设施,DevOps   提供工具模板化基础设施的描述。 实践:
  • - 采用   AWS   云服务进行部署
  • - 采用   AWS   CloudFormation   描述和创建资源
  • - 将对资源操作的脚本进行   source   control
准则:
  • - 对资源的描述和操作应该在   git  
  • - 在所有环境中采用相同的部署流程
  • - 使用   ssh   等手动操作资源的方式,只能用于测试环境和做一些   debug。

共享构建脚本

在为多个   services   搭建   CD   pipeline   之后,我们将   CD   pipeline   归纳为三部: 分别为这三步提取出   shell   scripts:

之后为上述脚本创建   git   repository,并且将其以   git   submodule   的方式引入各个项目。 持续部署了之后呢?

  CD   pipeline   服务团队的工作流程

我们搭建好   CD   pipeline,需要让它在团队的敏捷开发流程中发挥为威力:

团队职责:
  • - 团队主要分为   BA,Developer(简称   Dev),Tech   Lead(简称TL)
  • - BA   负责分析业务,并在故事墙上创建   Story
  • - Dev   负责开发,QA,运维(跨能型团队)
  • - Tech   Lead   负责技术
工作流程:
按照以上流程,团队可以快速从   CI/CD   pipeline   上得到反馈,高度自动化的   CD   pipeline   可以让团队做到按照   Story   进行   service   发布。

Summary

Microsservices   在业务和技术的扩展性方面带来了极大的便利,同时在组织和技术层面带来的极大的挑战。 由于在架构的演进过程中,会有很多新服务产生,持续部署是技术层面的挑战之一,追求极致的自动化,可以让团队从基础设施抽离出来,关注与产生业务价值的功能实现。

Q&A Q1:你们的docker是用什么来管理的?k8s,swarm   还是其他什么?

A1:   K8S,   Swarm   都没使用,对这两个服务我也只是听说过。   每个独立的   service   Docker   image   会单独运行在   AWS   EC   2   Instance。管理一般也都是围绕   EC   2   Instance   来做。关于     Docker   Images   仓库,采用自建的   Docker   Registry   服务来   push     pull   docker   image。 ================ Q2:如何做跨语言的服务集成 A2:     我们做过   Ruby     Node.js   的集成。服务器间通信采用   HTTP   协议,JSON   作为传输格式,   JSON   基于   hyper   media   link   的实现之一   HAL       如何解决   service   之间的约定,我们采用   Consumer   Driven   Contract   的方式,使用单元测试代替集成测试,这部分实现采用   Pact   ================ Q3:service的粒度如何确定 A3:   这是一个非常好的问题,也是很难回答的问题。     我个人觉得   microservices   中最难回答的两个问题是: 1.   什么拆分出一个   service? 2.   怎么拆分?(也就是拆分多细,系统边界如何确定) service   粒度如何确定,一句话来回答(TL;DR):『采用领域驱动设计(DDD)的方式拆分』。 更长版本,我们项目是为客户解决已运行10年以上财务生态系统的拆分问题。也就是老系统改造,也是我觉得最适合实施   micro   services   的场景。老系统存在很多痛点,并且需求较为稳定。 那么如何拆: 1.   需要引入业务专家,技术专家,相关利益人一起分析业务场景,系统构成确定领域语言对业务进行建模。 2.   将以前以业务切分系统的思路转为按照数据模型切分的思路。 3.   每个类数据模型可以划分多种子模型来辅助主数据模型。 4.   service   的粒度一般以数据模型的粒度来确认。 还有一些按照非功能性需求来切分的原则,比如实施   CQRS   的时候,将读写拆成两部分,采用   Even   Sourcing   解决分布式系统数据状态同步的问题。 ================ Q4:为什么没有考虑gocd,gocd可是first   class的CI/CD工具 A4:     好问题,这个我需要找   ThoughtWorks   负责   GoCD   的同时聊聊销售问题。BTW,我个人还没机会使用过   GoCD ================ Q5:目前发现从esb     soa转microservice,原本进程内的调用关系变成了网络调用,一次rpc变成了几次或者几十次rpc,同等条件下性能损失严重。这个问题如何得到解决? A5:     好问题,性能问题也是被同事问得最多的问题。关于性能问题我没遇见过高并发的场景,当时对于降低   services   依赖,控制网络请求我们是有一些解决方案。 1.   所有   services   基本都部署在同一个网络,比如   AWS   的网络上,可以讲起想想成内部局网,HTTP   call   带来的性能损耗目前为止还算可以接受。

2.   从系统设计的角度讲,与其降低HTTP请求的消耗时间,不如减少HTTP   请求的发送次数。从系统设计上考虑,大部数据模型都是   immutable   (不可变得),在系统系统间我们将数据缓存,减少   HTTP   请求的次数。(全文完)


扩展阅读

微服务架构云端应用

如何提高微服务架构的可用性

老司机带你玩PPmoney微服务【加强版】

中生代技术下期分享预告

我来评几句
登录后评论

已发表评论数()