锤子的墨村 之 程序猿眼中的REA DevOps

原创 2017年04月27日 近处的墨村


最热门文章:


(今天这个是纯IT题材,不懂的人现在逃走还来得及😄😄😄)

锤子两年前登陆墨尔本时,完全是DevOps小白。面试REA的时候,被问到什么是Continuous Delivery(持续交付),锤子诚恳地表示“不知道”。面试官不依不饶,“不知道不要紧,你想想怎么样才能做到Continuous Delivery?” 锤子回顾了一下自己维护项目时的噩梦,斟酌着用词说:“这需要好多自动化的工具支持,怎么测试,怎么接入不同的网络,怎么部署不同的环境,还有数据库的data migration和回滚,个顶个的都是痛点。”

之前锤子所做过的系统都是Monolith(单体)架构,所以,每次需要重启生产环境时,真得一而再,再而三地确认。所以当我们Squad(REA引入了Spotify模式[1])的同事给我讲解我们的微服务架构[2],和怎么做Continuous Delivery时,我问:“那最坏的情况就是重启系统了?”这个同事说:“不,重启系统是正常情况。”由此,锤子开始慢慢了解REA强大的DevOps。

什么是 DevOps?



DevOps 集文化理念、实践和工具于一身,可以提高组织高速交付应用程序和服务的能力,与使用传统软件开发和基础设施管理流程相比,能够帮助组织更快地发展和改进产品。这种速度使组织能够更好地服务其客户,并在市场上更高效地参与竞争。[3]


这幅图片[3] 可以看到发布生产线。 


如果我们想更好的解释DevOps,最好的方法是像解释Agile一样,把不同人的意见映射到不同的级别 如下所示[4]


  • DevOps价值观:敏捷宣言有效体现了DevOps的基本价值观 —— 需要稍微修改一点,改成关注发布给客户的业务或者软件的整体,而不是简单的“可工作的软件”。

  • DevOps原则:(来源于John Willis的 "CAMS"[5])

    • 文化(Culture): 人和过程优先。

    • 自动化(Automation): 一旦开始理解文化,这是可以开始的一个点。

    • 度量(Measurement):成功的DevOps实现需要尽可能多的度量其能度量的所有东西。

    • 共享(Sharing):共享似的CAMS形成回路。

  • DevOps实践:实现上述的概念和过程用到的特别的技术。

  • DevOps工具:DevOps原则落地使用到的工具。


接下来让我们看看REA的DevOps是怎样契合这些不同的方面。

REA DevOps

REA 价值观

REA采用了Spotify模式[1] ,你可以通过 The values we live by[6]了解REA的价值观。

  • Do it as one team

  • Do it with heart

  • Keep it real

  • inspire it

  • Own it

  • Re-imagine it

基于这些价值观,REA的所有IT小伙伴们一起合作,把最有价值的产品和功能发布给客户,这一切由分层协作框架支持。

REA DevOps的分层协作

REA DevOps的分层协作框架下,不同层面的问题由不同的组负责,如下图。 

每个Squads使用DevOps工具链开发和维护自己的微服务。详情会在下面一节进行介绍。

Delivery Engineering团队,顾名思义,就是为了让程序猿们更快更好地发布应用,主要职责是工具的开发和管理。包括创建Docker Registry,准备好已经安装了必要库的baked Docker image[7],有了这些基准的Docker Images,开发团队在为自己的微服务构建Docker Image的时可以有效节省时间,还能够规避各种库版本不一致的问题。Delivery Engineering还需要为不同部门配置Buildkite,Buildkite的Agents部署在AWS的EC2中,根据连接环境的不同,多个Agents分布在不同的VPC中。

Global Infrastructure & Architecture 团队负责基础设施建设,管理维护并开发相应的工具,包括网络、数据中心、AWS账号的管理、Splunk的集成等。比如,去年悉尼下大雨,Amazon的机房被水淹了,澳洲大批网站受到影响,也包括我们公司的一小部分,当时苦了GIA team的人了。

所有这些分层协作关注在怎样自动化整个发布流水线,解决其中的痛点。比如怎么样自动化所有流程?怎样为REA超过40个组管理AWS的账号?怎么为AWS里的测试环境和生产环境配置VPC?怎样把微服务部署到不同的环境?监控的策略怎么样实施,怎么样在不同的组之间协调?所有的几百个微服务,某些微服出了问题怎么办等等。想要解决这些问题,就必须有切切实实落地的工具链。

所以全工具链的配置和开发是Global Infrastructure & Architecture 和Delivery Engineering的职责,而作为程序猿的锤子,则是工具链的使用者。

那么REA的DevOps工具链到底是什么样的?

REA DevOps全工具链

REA实际使用到的全工具链包括:

  • 代码仓库:github企业版。

  • 构建和部署工具:Buildkite和Jenkins,还有一些老的项目依然在使用Bamboo。

  • 容器平台:微服务用Docker进行打包,Docker的引入让公司内部微服务的部署流程一致化。

  • 环境:目前绝大部分的service部署在AWS(Amazon Web Services)中,开发环境和测试环境使用同一套IAM,生产环境使用另一套IAM,三套环境通过Virtual Private Cloud (VPC)的设置进行隔离。不同部门的不同的组在IAM下拥有不同角色和访问权限。部署采用AWS Cloudformation服务,避免手动创建和更新使用到的AWS的业务。

  • 日志管理:splunk。Docker已经提供对Splunk的支持,所以所有微服务的日志都能够通过Splunk Agent发送到集中的Splunk服务器,以方便程序猿trouble shooting。完全避免了登陆到不同的机器收集log的窘境。

  • 监控:使用AWS Cloudwatch监控AWS的服务,比如某个SQS对应的dead-letter queue里是不是收到了消息,或者AWS Lamda执行是不是有错误等;NewRelic用来监控网络和设备的性能;Nagios提供服务可用性监控,可以直接使用REA内部的rea-health-check库,提供心跳API供Nagios的主动模式使用;通过设置接收相应的消息格式,Nagios也可以使用被动模式监控微服务。一旦无法ping通某个微服务或者在一定时间内没有收到微服务的消息,那么会马上产生一个PagerDuty告警来通知相关人员。

  • 告警:PagerDuty。前面提到的监控工具都可以配置相应的条件来产生告警,产生的告警都会通过PagerDuty用邮件,Slack,电话和短信的方式通知给当时的值日人员。PageDuty虽然是全天24小时运行,也只有极少部分高优先级的告警才会在非工作时间发出。还有一个告警的来源是Zendesk Ticket,这种信息通常直接来自于客户。就我们组而言,基本上都是一些数据错误,需要个别修正。

  • 协同工作:Leankit。


终于可以讲讲作为工具链使用者的程序猿锤子,日常工作是怎样的了。

程序猿DevOps日常

1. Coding

前面提到过代码库使用github企业版,采用github flow[8]

开发业务的过程中,大部分squad采用微服务的方式。

微服务

微服务有时被人诟病违背了DRY原则,但是Monolith架构下各种服务间的强耦合对于扩展部署都很痛苦,所以Don’t repeat yourself 诚然不错,微服务架构下,定义好边界之后(APIs),每个微服务独立存在,独立部署且可扩展,即使有一些简单的复制粘贴,其带来的灵活性也是Monolith架构不具备的。

在REA内部,为了保证某种程度的一致性,我们的微服务都需要遵循12 Factor[9]

  • 基准代码: 一份基准代码,多份部署

  • 依赖: 显式声明依赖关系

  • 配置: 在环境中存储配置

  • 后端服务: 把后端服务当作附加资源

  • 构建,发布,运行: 严格分离构建和运行

  • 进程: 以一个或多个无状态进程运行应用

  • 端口绑定: 通过端口绑定提供服务

  • 并发: 通过进程模型进行扩展

  • 易处理: 快速启动和优雅终止可最大化健壮性

  • 开发环境与线上环境等价: 尽可能的保持开发,预发布,线上环境相同

  • 日志: 把日志当作事件流

  • 管理进程: 后台管理任务当作一次性进程运行

不过不管微服务设计得如何精良,当一个“小而美”的团队(5-6名开发人员)需要同时开发维护生产环境中10个以上的微服务时,服务运行和管理上的额外复杂性使得全自动构建和部署变得不可或缺。DevOps的工具链恰恰提供了发布流水线自动化的功能。

微服务需要的部署脚本和AWS Cloudformation的信息,提供给不同监控工具的接口,fried Docker image[7] 定义等,也都是代码的一部分,需要开发人员完成。

2. 构建和部署

构建和部署就以Buildkite为例子,这是一个微服务的buildkite脚本。 

构建

这个流程里代码检查和单元测试自动化起来很容易,那么怎么做整合测试?REA基于Ian Robinson提出的用消费者驱动的契约进行面向服务开发的模式[10]开发了 开源的Pact 测试框架[11],用轻量级的契约测试来代替厚重的集成测试。Pact在消费端用单元测试的形式(更轻)来生成 pact 契约,服务端通过验证契约来保证两者稳定集成。一旦有一端契约未经协商发生改变,那么Pact测试就会失败。

构建成功之后,会把微服务打包成Docker Image然后上传到Docker Registry。我们会选择在Delivery Engineering提供的基准Docker Image之上来打包,这是一个微服务的Dockerfile的例子:


用这种方式,在buildkite上打包并上传到Docker Registry的时间小于三分钟。 

部署

开始进行部署时,部署脚本会调用Delivery Engineering开发的rea-shipper [12]

  • rea-shipper自动将监控和日志管理所需要的模块也用Docker打包,在部署的过程中与每个微服务的Docker Image整合,如下图所示。这样微服务的开发人员只需要关注业务的开发,而无需担心日志和监控的问题。 


    以我们一个实际的service charge-central为例,登陆到EC2 instance之后,可以看到正在运行的另外四个。

不同的环境下,Buildkite会选择不同的Agent进行部署:Test 环境的non-prod-corp:default和Prod环境的prod-corp:default。部署的时间通常10分钟以内,下面是一个微服务部署到test(6分1秒)和prod(5分43秒)的时间,图中能够看到Cloudformation更新的步骤。 

部署是全自动的,不过考虑到生产环境的重要性,我们还是选择谨慎地Block,需要某个开发人员手动触发。触发的时间没有特别的规定,不过在我们的kanban里面,deploy是最后一步,所以只有真正部署到生产环境,这个卡片才算完成。如果部署过程中出现失败,rea-shipper不会切换运行中的ASG(Auto Scalling Group),所以并不影响业务。如果部署的新版本发现某个bug,需要紧急回滚,因为所有的docker image都有版本信息,可以很容易的找到之前版本的docker image进行部署。

3. 运维

日常的运维如下图所示:


需要处理的问题一般有两种:

  • 直接源于客户的问题,使用Zendesk Ticket。

  • 源于生产环境的问题,比如PagerDuty告警。

我们Tribe有5个Squad,除了有超过30个microservice之外,还有跟不同系统的接口,如果不能组织好,开发人员每天必定会被各种问题打扰。所以如图所示,Tribe级别有Dingo(工作时间)或者Owl(非工作时间)作为接口人,负责处理和分发问题到Squad级别的Squid。Dingo,Owl和Squid都是有团队的开发人员轮岗。

总结

本文介绍了REA DevOps的实践,包括工具链,工具链的分层协作以及使用中的流程。再来对比一下Gene Kim的3个方法:流程,反馈和持续学习,这3个方法是DevOps的主要部分,提供一种路标来理解和执行DevOps[14]。锤子能够看到的是在REA DevOps实践中,每个开发人员都参与到流程的不断优化中,让流程变得更顺畅和快速;通过不同方式可视化监控和反馈,以达到更快的反馈路径;开放全代码库给所有开发人员,鼓励程序猿持续学习和改进等等。

以上种种,推荐阅读我们公司同事的文章来更深入的了解REA的文化。Scaling On-Call: from 10 Ops to 100 Devs[15],讲述了怎么从这样的状态: 

到达下面的状态:


这种变化并不是技术改进带来的,而是源于持续学习的企业文化。而这,正是DevOps最需要的。




封面图片来源:https://www.technolava.com/education/

参考文献:

 [1] https://labs.spotify.com/2014/03/27/spotify-engineering-culture-part-1/

 [2] https://martinfowler.com/articles/microservices.html

 [3] https://aws.amazon.com/cn/devops/what-is-devops/

 [4] https://theagileadmin.com/what-is-devops/

 [5] https://theagileadmin.com/2010/10/15/a-devops-manifesto/

 [6] http://careers.realestate.com.au/rea-culture/the-values-we-live-by/

 [7] http://www.capitalone.io/blog/baked-vs-fried-whos-hungry-on-the-cloud/

 [8] https://guides.github.com/introduction/flow/

 [9] https://12factor.net/zh_cn/

 [10] https://martinfowler.com/articles/consumerDrivenContracts.html

 [11] https://github.com/realestate-com-au/pact

 [12] https://speakerdeck.com/mdub/rea-shipper-at-infracoders

 [13] http://multithreaded.stitchfix.com/blog/2016/09/08/EmbracingImmutableServerPatternDeploymentonAWS/

 [14] http://www.yunweipai.com/archives/11859.html

 [15] http://rea.tech/scaling-on-call-from-10-ops-to-100-devs/




广告时间


下面推荐的两个公众号,都跟少儿英语学习有关。TripleZ是🔨的朋友自己运营,关注双语教育(没办法,谁让她有三个加拿大籍的Z开头名字的女儿们呢,知道TripleZ的来历了把);Locokids是锤子的同学的创业项目——一对一的少儿英语外教(想报名,找锤子,有亲友折扣哟)。家中有娃儿,想把双语教育进行的更好的小伙伴们猛击关注吧。




iOS用户打赏渠道, 别不好意思嘛。。


收藏 已赞