无服务器架构下的运维

前言

在介绍运维之前,大家先来快速了解一下无服务器(serverless)的概念。由于笔者的实战经验是在AWS平台上,本文中出现的无服务器均指使用AWS Lambda构建的serverless应用。Serverless的特点是用户无需预配置或管理服务器,只需要部署功能代码,服务会在需要的时候执行代码并自动伸缩,从每天几个请求到每秒数千个请求,轻松地实现FaaS(Function as a Service)。如下图所示:

(图片来自网络)

在传统的应用中,开发团队除了需要编写功能代码,还要监控实时负载,并相应地对应用进行伸缩,还要处理一些因非功能性故障导致的停机(硬盘、内存等)。而无服务器架构则将开发团队从服务器维护的工作中解放出来,继而能更专注在功能代码上(图中的Function)。在实际的项目里,开发者只需将功能代码打包上传到AWS Lambda,再进行少量配置(环境变量,触发条件,内存,超时时间等)即可将应用/服务上线。

以上是无服务器架构的基本概念。接下来,笔者将从日志,指标,监控及报警,灾备这四个维度来介绍无服务器架构下的运维。

日志

默认情况下,应用运行时产生的日志会保存在应用服务器本机,在需要查看日志的时候,需要运维人员远程登录到这台服务器获取日志信息。这种方式操作起来稍显繁琐,而且当应用服务器的数量增多后,由于需要先找出产生错误信息的那台服务器,会严重降低查找日志的效率。

一种解决办法是ELK(ElasticSearch, Logstash, Kibana),这三个开源工具各司其职,Logstash负责日志的推送和转换,ElasticSearch作为数据库与搜索引擎,Kibana作为图形界面。好处是搭建容易,良好的伸缩性,以及免费。但带来的额外成本是,独立出来的日志服务也需要做好全方位的监控(应用状态,硬盘,网络等),避免因为基础服务的问题导致系统全面故障。

AWS无服务器架构中的日志是一个开箱即用的服务,所有日志自动采集到AWS CloudWatch Logs中,只要根据服务名称找到对应的日志组,即可进行查询搜索,不需要任何配置,也没有任何维护成本。

指标

通常情况下,运维工作会包含采集线上应用的运行指标,来反映应用的健康状况,故障率,性能,访问量,访问频率等。这里以一个使用Spring Boot构建的API服务来举例,Spring Boot中的Actuator扮演了采集指标的角色。默认配置下,对于每个API,Actuator会自动采集以下几个指标:

  • uri,例如/api/person/{id}
  • method,例如GET或POST
  • status,例如200或500

当然我们可以通过实现一些接口来扩展/自定义采集指标,这里就不展开了。有了指标数据,还需要对应的报表或仪表盘工具,以便更好地查询和展示,可以选择像Prometheus,Grafana这样的工具。

那么AWS无服务器架构是否提供了类似的指标采集呢?答案是肯定的,AWS CloudWatch Metrics自动采集了Lambda function的以下四个指标:

  • Invocations(实际调用量)
  • Errors
  • Duration(执行时间)
  • Throttles(超过并行限制而被阻止的调用的数量)

Invocations和Errors取一段时间的总数,结合二者可以得出应用的错误率,如下

Duration则通过取平均数来反映一段时间的性能表现,在笔者的项目中Lambda function的耗时主要集中在SQL的查询上,这个数字可以相应地反映技术人员对查询优化的效果。当然,在实际情况中,这些检验都可以在预发布环境下进行,这个例子只是为了方便理解。

在笔者目前的项目中,Throttle并未被使用到,默认的并发限制是1000/秒,而用量最大的Lambda function的调用频率也不过每分钟150次,距离超限差得很远,不过这一数据对于并发高的应用有很重要的意义。

除了开箱即用的几个指标以外,还可以结合CloudWatch metrics的API,在相应的功能代码中埋点,定制化采集指标。例如,对于一个Lambda function,代码里三个子task,默认提供的Duration只能反映总体的运行效率,如果需要统计每个task的消耗,就需要用到AWS CloudWatch metrics API。

监控&报警

监控的意义在于全面了解应用的资源使用率,性能和运行情况,这些数据可以用来帮助团队及时作出调整,保证应用程序顺畅运行。这通常包括CPU使用率,数据传输,磁盘使用等。在突发状况导致系统不可用的时候,团队的响应速度,往往取决于监控和报警的及时性,全面性和准确度。如果能在对历史数据的分析之上对监控系统进行合理的配置,团队甚至能预测不好的事情将要发生,提前做好防范,未雨绸缪。

同上,这里还是以一个Spring Boot应用为例,在上一小节指标数据的采集中提到过Actuator,事实上Actuator除了可以记录上面提到的指标,还可以用来收集监控数据。这里我们只需要设置一个Spring Boot Admin应用,给需要进行监控的应用加上Spring Boot Admin client配置,监控数据就会通过Actuator暴露的API传递给Spring Boot Admin。

报警功能一般则要根据实际情况自行实现。Spring Boot Admin中实现了对Pagerduty,Slack等第三方工具的集成,如果只是需要简单的邮件提醒,实现起来也不复杂,这里就不展开了。

随着云上基础设施的普及,上面提到的监控和报警早已是各个平台的标准配置,根本轮不到开发者去操心如何实现及维护,运营团队可以把更多的精力放在配置优化的工作中去。

AWS默认提供了非常完备的监控数据,也允许自定义监控dashboard,通过把一系列重要的指标添加到创建好的dashboard中,应用的运行状况一目了然。

前面已经提到过,在出现错误,或性能底下时,根据某些关键指标的变动情况发送警告通知非常必要。笔者所在的项目的做法是使用AWS CloudWatch和AWS SNS提供的告警通知功能,只需要先选择指标然后设定触发阈值和检查间隔时间即可,AWS SNS支持HTTP、SMS、Email等多种订阅方式。下图展示了如何设定当某个Lambda在过去5分钟内发生了5次以上错误的时候发送通知。

灾难备份&恢复

在系统镜像,构建工具还有容器技术越来越普及的今天,灾难备份的意义很大程度上是为了有效保护重要数据。通常的做法是设定一些定期任务,将数据传输到远端的灾备中心,从物理上抵御不可抗灾难。如果数据量过大,出现网络传输效率跟不上的情况,可以参考AWS用卡车拉数据的解决办法。

真正需要用到灾难备份的情况在笔者有限的经历中还没有发生过,但是如果不未雨绸缪,真正发生时的后果将难以设想。笔者项目中用到的AWS RDS默认启用了以7天为周期的自动备份,这个配置可以手动调整也可以将配置写入构建基础设施的脚本中去。 如果灾难真的发生,光有数据备份是不够的,还需要能够快速重建应用运行时的基础设施。笔者所在的团队(下文简称团队)分别使用了AWS CloudFormationServerless framework,CloudFormation用来重建数据库、网络等基础设施,Serverless framework用来重建Lambda function,在重建数据库的时候,通过持续集成流水线,以环境变量的方式传入最近一次数据备份快照的Id,15分钟以内即可重建一套产品环境。

总结

笔者所在的团队是10个人左右的配置,采用结对编程的方式,3对pair,包含web端、业务层、数据层。从产品原型确定到第一次上线(MVP)耗时30天,每周至少发布一次新版本,story的平均交付时间(cycle time,从需求确定到上线)为8天。这样的速度也许不能算快,但是如果没有Serverless架构在运维端提供的支持,我们想要在交付速度上有更高的突破会困难得多。

最后来谈一下成本,俗话说抛开商业化谈技术都是耍流氓,大部分人看到一个强大易用的工具都会下意识里觉得开销会很大。实际上并不是这样,我们做了一个粗算,选用双核CPU,8G内存的M4型服务器,开销是$72每月。dev,staging,prod三个环境都用同样的配置就是$216每月,而实际上Lambda每个月的开销包含所有环境在$20左右,需要注意的是Lambda的计费是根据使用量来的,我们的API访问大约在150万每月的量级。可以预见到当访问达到一定数量的时候Lambda的开销会和使用服务器的方案持平甚至更大,但是在量小的时候优势明显。

得益于强大的AWS生态,利用Lambda构建的无服务器应用经过少量甚至无需任何配置,即可以极低的价格获得完整的运维功能和体验。与自己利用开源工具进行搭建的方式相比,研发团队可以从繁琐的运维工作——特别是基础工程搭建——中解脱出来,更加专注于产品本身,极大的提高软件交付速度,可用性、可靠性和可扩展性也相当有保障。换来的代价是更高的迁移成本,某些功能的不可定制化可能成为瓶颈,以及对底层实现原理的屏蔽也可能对开发者的学习和成长有影响。


更多精彩洞见,请关注微信公众号:思特沃克

Share

项目实施DevOps时,我们是如何做测试的

正如我们所知,DevOps最近几年很风靡,很多企业正在如火如荼的推行它。然而,你可曾想过,从传统到敏捷、再到DevOps,开发模式的不断革新对测试提出了怎样的挑战?

最近我们项目在实施DevOps,因此想趁热打铁,就DevOps模式下如何做测试,谈一谈自己的认知。

DevOps有什么特征

DevOps是一系列软件开发实践,强调开发人员(Dev)和运维人员(Ops)之间的沟通合作,通过自动化流程,使得软件构建、测试、发布更加快捷、频繁和可靠。

1. DevOps强调一种文化

在很多企业中,开发和运维人员通常隶属于不同部门,有着不同的工作环境,采用不同的沟通方式,使用不同的开发或运维工具,并且有着不同的业务目标,这使得他们之间形成一道参不透的墙。

DevOps实际是一种文化上的变迁,强调开发、运维、测试等环节之间的沟通合作。意在帮助这些人向着一个共同的目标努力:尽可能为公司提供更多价值。为了支持这种合作的发生,需要在团队内部文化和企业组织文化两个层面做出努力。

2. DevOps是一种实践

所谓DevOps,就是将敏捷方法延伸到Production!

DevOps主要是为了将敏捷开发实践扩展到运维阶段,进一步完善软件构建、验证、部署、交付等流程,使得跨职能团队能够完成从设计到生产支持等各环节的工作。

3. DevOps包含一系列工具链

DevOps是一种融合了一系列基本原则和实践的方法论,并从这些实践中派生出了各种工具。这些工具体现在软件开发和交付过程的不同阶段:

  • 编码:代码开发和审阅,版本控制工具、代码合并工具
  • 构建:持续集成工具、构建状态统计工具
  • 测试:通过测试和结果确定绩效的工具
  • 打包:成品仓库、应用程序部署前暂存
  • 发布:变更管理、发布审批、发布自动化
  • 配置:基础架构配置和部署,基础架构即代码工具
  • 监视:应用程序性能监视、最终用户体验

DevOps对测试提出了哪些挑战

刚参加工作时,我参与了某Audi系汽车电子的软件研发,采用的是传统瀑布开发模式。在整个项目生命周期中,前半部分设计和编码,后半部分用来测试。然而我在东家工作了两年,也没能等到产品交付到用户手上。直到去年,我们的软件才得以量产并投入市场。在这4年中,产品从未交到用户手上,因此无法验证它所带来的价值,也没有任何机会得到用户反馈从而适应变化。

后来,我又参与一个银行项目,我们采用敏捷的开发模式,全功能团队,开发测试并行,每2-3周就交付一个版本。但因为没有真正发布到生产环境,我们仍然无法及时得到有效的用户反馈。

现在,我们采用DevOps的优秀实践,开发和运维协同工作。每个迭代完成,或者每修复一个线上缺陷就立即部署到生产环境。这样,我们就能够迅速从用户处获得反馈并且快速做出响应。

通过参与传统、敏捷和DevOps的项目,我深深地感受到流程的改进对团队以及项目的产出和质量所带来的改变。

那么,这些改变究竟是对测试提出了什么样的挑战? 我认为有以下几点:

1. 频繁部署

在采用DevOps之后,我们能够根据项目具体情况做到每天甚至一天多次部署。在生产环境频繁部署软件,最大的挑战就是测试。以前,测试基本上都在开发阶段之后和产品上线之前完成。但现在,不再有充足的时间留给QA团队去发现问题再抛给开发团队来修复。那么,速度成了测试面临的一大挑战。

2. 自动化

DevOps强调将流程自动化,测试作为其中一个重要环节,势必要大规模实现自动化。因此测试人员的自动化编码能力正在面临极大的挑战。

3. 实践和反馈

敏捷提倡我们要拥抱变化,更多的是要适应需求的不断变化。虽然一部分功能性需求是明确又具体的,我们清楚的知道用户想要什么,也因此易于测试。然而,也有一些非功能性需求的验收标准没那么明确,比如:提高应用性能达到良好的用户体验。我们如何才能验证用户体验是否真的良好呢?仅仅通过性能指标吗?当然不是,满足指标只能说明一部分问题,唯有真实的用户数据和反馈才是可最靠的。

4. 协作

敏捷强调全功能开发团队的共同协作,但这仅仅止于开发阶段。而DevOps注重Dev、Ops和QA三个群体之间的密切协作。因此,良好的角色定位能够帮助测试人员将价值最大化。

我们是如何做测试的

Laurent曾经在Hiptest上发表了博客《Shift left and shift right: the testing Swing》,提出了一个有意思的测试矩阵,从四个维度进行分析,描述了当软件开发模式从瀑布到敏捷、再到DevOps转型时,测试该如何响应变化。

Laurent提出一个测试左移和右移的概念:

  • 测试左移,就是指在开发阶段之前定义测试。
  • 测试右移,就是直接在生产环境中监控,并且实时获取用户反馈。

在敏捷开发的生命周期中,我们通过每一次迭代来丰富和更新产品,以使其最大限度地符合客户对系统的需求。当时测试的关注点基本停留在开发阶段,以保证产品达到上线标准。引入DevOps之后,我们不仅要关注产品的质量是否达标,还需要使价值假设得到及时的验证。因此,我们不仅要将测试左移,在开发环境验证功能的可用性,还要进行测试右移,通过监控产品在生产环境的运作情况,来验证其价值并获得反馈,从而持续改进。基于这些理解,我在项目上做了初步的尝试并取得良好的效果。我将这些尝试和实践总结为以下几点:

1.如何保证新功能得以实现?

在开发环境,我们开发新功能,并且通过测试保证其达到产品验收标准。

首先,使用BDD(Behavior Driven Development,BDD)的方式定义用户需求,这样用特定的语言来描述用户行为,能够使各个角色(测试、开发、产品负责人、市场等)对业务价值达成一致的理解,从而使其从需求到最后的测试验证,进行高度的协作和沟通,最后交付最有价值的功能。同时,QA能够提前Review故事卡,补充验收标准。除此之外,BDD方式的用户需求可以直接指导测试,后续我会写到。

其次,采用单元测试来验证最基本的代码逻辑。在编写单元测试时,建议Dev和QA Pair工作。单元测试可以认为是编码的一部分,要对系统的代码逻辑有深入的了解,因此,Dev是最合适的人选,而QA可以帮助测试覆盖的更全面。

最后,每一个功能都要严格按照故事卡的AC(Acceptance Criteria)进行验收,并采用探索性测试方法来对新功能进行无死角测试。

2.怎样验证新功能的价值?

我们将新功能部署到生产环境以后,接下来就应该衡量业务价值是否达到预期

验证预期的一个好方法是衡量用户的行为变化。比如:在上传图片的功能后面添加了一个预览按钮,但用户却极少用它,很可能是因为用户根本不需要这个按钮,或者按钮放在了不恰当的位置导致用户不方便使用,亦或是按钮样式不够友好,导致用户没有欲望使用它。这时候,该按钮的业务价值就没有真正达到,是时候调整一下了。

3.如何确保已有功能不被破坏?

在软件开发中,任何代码都不可能完全独立存在,一行代码的变更也有可能导致系统的全面崩溃。那么,如何保证在开发新功能的同时,已有功能不被破坏?换句话说,如何做到全面的回归测试?人力是最高成本,也有现实的局限性,比如,人手不够,重复做同样的事情人会变得烦躁,手不够快导致效率低下等。因此,自动化测试才是不二选择。

将BDD需求直接转化为自动化测试用例。每个测试用例都应该讲一个关于应用程序的故事。当一个测试用例使用一致的业务术语定义时,它的可读性会比较高,且容易自动化。与此同时,上一个迭代的用例在下一个迭代就可以迅速转化为回归测试的基线。

支持BDD的工具有很多,比如:Cucumber。简单举个例子,如图:

BA用BDD方式定义用户需求,QA Review并补充AC,然后将其编写为自动化测试脚本。如果QA的编码能力较弱,可以让Dev协助完成代码实现的部分。这也充分说明了协作的意义。

最后,也是更重要的部分,测试应该集成在CI中。每一次Build或者每天都要去执行测试,验证已有功能是否完好。这样才会对没有预期到的变化产生的问题给出快速反馈。

另外,做一些性能测试、兼容性测试、和安全性测试等等。

4.怎样验证产品的可靠性?

有时候,某些缺陷并不是源于代码的错误,而是一个不好的用户体验,或者只有当数据达到一定量时才会出现,测试人员是无法模拟这种类型的测试的,因此直接在生产环境监控变得高效又可靠。通常我们需要监控两种特性:性能和可用性。

使用工具持续获取用户数据,或者使用log持续获取性能信息。这有助于监控产品部署到生产环境后是如何正确运作的。快速启用一个功能,在生产环境实时监控验证其业务价值,获取到有效且快速的用户反馈,加之拥有持续部署的能力,我们能够在出现问题的时候快速做出反应,从而使得我们的产品更加可靠。

这里实际上融入了《QA in Production》的理念。现如今,已经有很多工具和方法支持在生产环境做测试了。篇幅太长,这里就不做详细阐述了,请参考原文

到这里,再来回顾一下,我们的实践是否真的卓有成效。

  1. 用BDD的方式定义用户需求、编写测试,有益于不同角色之间的一致理解和共同协作。
  2. 自动化测试解决了频繁部署所带来的挑战,同时保证产品的整体功能持续得到回归和验证。
  3. 在线监控能有效地验证不确定需求,通过生产数据分析和预警问题的发生,并且快速获取用户反馈从而及时调整。除此之外,这一点也充分体现了Dev、QA和Ops的协作,像监控等原本只能Ops做的事,现在Dev或QA一样可以做。

写在最后

测试是一种活动,曾经我们通过它来验证产品是否达到上线标准。现在DevOps模式下,我们需要在各个阶段不断地执行测试活动,以达到产品质量的持续改进。

而QA(Tester)仅仅是一种较多进行测试活动的角色。敏捷一直强调“团队为质量负责”,测试不再是QA(Tester)的专属。DevOps模式更是对测试、尤其是自动化测试提出了更高的要求,也对QA的编码能力提出了极大的挑战。作为团队成员,每个人都有责任了解开发流程、提高测试技能,把好测试这一关。但是,测试活动作为QA(Tester)的主要职责之一,提高自动化测试技能,就是当下每个QA(Tester)最为紧急且重要的事情了。


更多精彩洞见,请关注微信公众号:思特沃克

Share

企业实施DevOps的七大挑战

DevOps这个词在近年来可谓大火。从2014年底我开始给一些企业做持续交付/DevOps相关的评估和咨询,似乎每个企业都表示想要推行DevOps,或者说他们正在做DevOps。这把火蔓延的速度远远超过当年敏捷在IT行业的传播。然而有些企业管理者对DevOps的认知让我们意识到,由于各种有意或无意的因素,这个概念不幸地成为了一个让人困惑的buzz word……

什么是DevOps?

这里我想列出四种我们在市场上、企业咨询以及社区交流过程中接触到的认知:

  1. 一些企业的运维部门找我们,说要搞DevOps。我请他们约开发部门的同事一起来沟通,却得到类似于“不用管他们,我们自己搞……”的回复。再问那打算搞啥呢?答案可能是“我们想谈谈自动化运维……”。
  2. 另一种认知是,敏捷宣言提出了“业务和开发要紧密协作,拥抱变化,将变化视为提升价值的机会而非麻烦。”那么DevOps则是将敏捷思想向运维延伸,通过开发和运维的紧密协作,让交付的最后一公里也能拥抱变化,兼顾吞吐量和稳定性。
  3. 进一步,有些企业提出了自运维“No-Ops”理念,让运维的职能融入产品交付团队,由团队自主、自助地完成部署发布,同时自己承担线上问题支持等工作,完全让运维工作去中心化,实现“Who build it, who run it”。
  4. 我们还看到,一些咨询或解决方案厂商的宣传将DevOps刻画成了一个全新的、从设计、需求到发布运维端到端的研发体系,似乎有了DevOps这把榔头,软件研发的各种问题都解决了。有了DevOps,苦逼的程序员们就迎来解放了…

作为企业管理者,要在组织中引入DevOps并推动变革,首先要对DevOps的目标有清晰的认识,并明确DevOps在自己企业的上下文中意味着什么。我反对一些厂商将DevOps吹得太大,但这也绝不仅仅是运维单方面的目标。DevOps运动本质上是关于开发(含测试)和运维的协作,在“为用户创造最大化价值”的一致目标下,让软件交付给用户并获得反馈的过程更加敏捷。至于要不要将开发运维一体化,则取决于具体产品的特征,在不同场景下可以有不同的协作模式。

DevOps行业报告提出了两个顶层的用于衡量IT组织效能的指标:吞吐量和稳定性。在一些人看来,这两个目标就像鱼和熊掌不可兼得。追求交付吞吐量,就会带来更大的不稳定性和风险;而传统运维管理以稳定性为目标,就必然牺牲对变化的响应力。之所以会有这样的悲观认知,是因为仅仅站在当前的时空看待问题,而无法超越自己的能力局限。企业管理者需要理解,进行DevOps转型,就是要超越自己的能力局限,超出当前的时空看问题,通过组织设计、过程改进和工程技术的提升让组织能力上升到一个新的维度,我们完全可以做到同时提高IT交付的吞吐量和稳定性,而不是在两者之间取舍平衡。

然而,要突破自身的能力局限,这并非易事。下面谈到的实施DevOps过程中的七大挑战中的每一个都需要组织下决心投入,并耐心等待回报,没有足够的认知转变和卓越领导力难以实现。

挑战一:自动化测试投入不足,收益低

敏捷宣言自提出时,就已经将自动化测试作为敏捷、极限编程的核心实践来强调。然而这么多年过去了,在组织中真正有效进行自动化测试的并不多,各种问题都在影响着组织和团队对自动化测试的信心。

要想同时提升吞吐量和稳定性,以自动化替代手工方式快速、频繁的对软件质量进行验证是首要的手段。如果说在以往谈论敏捷开发的时候,自动化测试是对团队的较高要求,那么到了DevOps时代,这就是最基本的入门要求。毫不夸张的说,如果软件系统没有一套较完善的自动化测试体系,就请不要谈DevOps了。

最直接的问题是投入不足。很多管理者意识里是将自动化测试看做一项额外的、可有可无的任务。他们关注的是短期的项目管理目标,而不是长期的产品持续演进,往往只有进度压力不大的时候才投入人力来做一做,或者单独聘请一个团队来补充测试用例,然后离开,而不是作为开发团队交付软件产品的一部分。这样的模式很难产生一套长期有效的测试套件,反过来进一步削弱了管理者对其进行投入的信心。

另外常见的一些问题包括:

  1. 缺乏对自动化测试策略的正确认知,过多集中在界面上做测试,缺少单元测试和API测试。界面功能测试案例的开发和维护成本高,执行速度慢;想想上千个案例全部执行完可能需要跑上半天、一天,然后有几十个案例因为环境或网络问题而执行失败,却不是因为代码问题。结果是我们看到不少团队从来没有一次将所有案例全量执行过,只能每次手动挑选一部分案例来跑。
  2. 缺乏一套独立的自动化测试环境,而是和手动测试共用一套环境。这种做法一方面会导致自动化测试和手动测试在资源和测试数据上相互影响,使得测试不稳定;另一方面自动化测试过多依赖外部集成环境,缺少必要的依赖隔离,使得测试案例执行不稳定、执行效率低。
  3. 自动化测试、手动测试和生产等各环境不一致,使得自动化测试的结果不够可信。
  4. 由测试人员或单独的团队来写自动化测试,而不是让开发人员写。这首先导致开发人员在设计和编码时很少考虑为了更高效稳定的自动化测试进行优化,加大了测试开发的难度;其次测试人员必须等到开发基本编码完成了才能开始写测试案例,并且需要请开发人员讲解API或界面元素的设计,这是一个低效的过程,浪费时间。
  5. 没有将自动化测试纳入持续交付流水线自动化地频繁执行。我们看到不少团队是在完成手动测试后、上线之前选择性地执行自动化测试案例来进行回归;这样的用法没有最大化其价值,对质量的反馈速度太慢。

要解决以上问题,并产生一套有效的自动化测试套件是一个巨大挑战,需要管理者和团队转变质量意识;需要企业从项目化的管理转向产品化的管理,人们才能真正长远地去考虑对自动化测试的投资;需要影响业务人员在需求容量上的期望,为书写自动化测试提供时间。

挑战二:高度集中的IT基础设施服务

在传统模式下,像服务器申请、配置变更等IT服务是由高度集中的基础设施管理团队负责。产品交付团队需要向集中的IT服务团队提出申请;而该团队往往承接着来自很多交付团队的需求,于是只能将请求进行排队依次处理,并且主要依靠手动处理;结果是交付团队不得不长时间等待,才能得到所需资源。这个过程中的手动操作,使得经过一段时间后,基础设施的配置变成了一个黑洞,没人能够说得清各个服务器之间的状态差异,当问题出现时需要耗费很长时间来进行分析定位。我把这样的时代称之为IT基础设施服务的“农耕时代”。

IT基础设施的管理要更加敏捷,提高变更吞吐量并同时提高稳定性,首先需要在基础设施的管理上实现这四个目标:

  1. 标准化
  2. 脚本化
  3. 版本化
  4. 可视化

在此基础上,基础设施管理团队不再排队处理所有交付团队的请求,而是专注于提供一个基于标准化、脚本化、版本化和可视化方式管理基础设施的自助服务平台;组织授权给各产品交付团队利用平台的能力,以代码化的方式随时按需进行基础设施的准备和变更。缩短等待时间的同时,因为进入生产环境的基础设施变更已经以一致的方式在各个测试环境经过了验证,减少了人为手动操作可能引入的错误和遗漏,确保了各个环境的一致性;也让前期的自动化和手动测试更加可信,从而使得系统的稳定性也得到提高。这样一个模式我称之为IT基础设施服务的“云时代”。

对企业来说,从这种基础设施管理集中式控制向去中心化授权的转变也是一个巨大挑战。首先基础设施自助服务平台的建设需要投入;更重要的是,能够授权交付团队依赖自动化方式,而非人工来保障基础设施配置的质量,本身就需要管理者的思想转变。在我看来,一些管理者倾向于依靠人来控制,而不信赖经过反复验证的自动化过程,只有一个原因:人出了错可以追责和惩罚,而自动化过程出了错,不容易找到某个单一的人来担责,总不至于惩罚机器。

这里还有一个挑战不得不提,这种转变带来了传统运维模式下运维人员的技能要求转变,从以往手动的服务器操作,变成需要写DSL、需要会编程。这必然影响到一群人的职业发展,这会给变革带来阻力;企业应当给这群人提供足够的培训,提供新的职业发展机会。

挑战三:部署与发布未分离

在产品交付团队追求频繁变更、提升交付吞吐量的时候,即便进行了严格的同行评审、通过了完善的自动化测试、确保了基础设施环境的一致性,但由于周期短、频率高,要平衡投入产出的收益,在软件进入生产环境时,还是有风险存在。因此一些管理者无论如何不敢在部署发布流程上进行放权,减少审批控制。这种不安全感是来自传统的发布过程缺少一种安全性策略,也就是没有将“部署”与“发布”分离。

“部署”和“发布”是两个不同的词,然而很多年里当提到将软件最后发布给用户使用时,两个词通常是混用的。为什么呢?以往,我们将软件发布给用户的手段很单一,就是将软件部署到生产环境跑起来,用户就可以用了,这两个词所代表的动作是同时完成的。

要让发布环节变得更加安全,就需要将这两个动作分离。“部署”即是让新的或修改的软件安装到目标环境上运行起来。这应当是一个技术决策,即是否执行这个动作应当完全由技术团队依靠对变更进行的同行评审和测试来决定,随时可以执行。这个动作过程中,技术团队重点关注的是:

  • 部署过程自动化
  • 版本更新过程对用户无感知
  • 能够快速回滚。

而“发布”应当是一个业务决策,即允许业务和产品人员来控制新特性对用户的可见性。首先对受控的小范围用户开放,经过一段时间的反馈信息收集,包括对系统稳定性和用户行为、喜好的观察,然后决定是否将其开放给更大范围的用户。如果系统存在质量或设计问题,可以很快关闭新特性,或回退到旧的版本。在这个发布的过程中,交付团队和业务人员重点关注的是:

  • 系统稳定性
  • 用户实验反馈

要实现这样的分离也是一个很大挑战。首先技术上,需要引入蓝绿部署、金丝雀发布,以及特性开关等手段;但要让每个团队都自己去建立这样一套机制成本太高,企业需要从平台战略的角度提供这样一种便捷的能力来实现灵活可配置的在线受控实验;另一方面,这样的分离意味着重新定义了在软件部署发布过程中IT团队和业务人员的职责,需要IT和业务的紧密协作。

挑战四:缺少自助式的持续交付平台

DevOps不仅仅是关于运维的自动化,同时也是关于开发、测试到运维各个职能围绕着每一次软件变更的紧密协作。在这个过程中,开发关心的是代码库、编译、构建;测试关心的是测试验证和测试环境;运维关心的是部署与发布控制、监控及支持等,各个环节的任务涉及到一系列工具构成的工具链。然而在对很多客户的调研中,我们发现普遍存在的现状是:

  1. 开发、测试和运维各自有自己的一套工具来完成自己关心的任务,而这些工具既不相同,也不相互关联;软件包在不同工具之间的转移更多依靠人工来完成;
  2. 由于工具上的割裂,每个人并不清楚同一个变更在其它角色哪里到底发生了什么,也不关心;
  3. 由于从获取代码、编译、扫描、构建、测试、部署、发布到获得反馈的整个过程中涉及到很多工具的运用,很难有哪个团队能够靠自身力量在每一个环节都做得成熟。

要在企业中实现DevOps,有一定规模的IT企业非常需要给产品交付团队提供一个软件持续交付平台,让软件从代码提交构建到交付给用户的整个过程得以在这个平台上完成,包括所有自动化任务的配置和调度,支持信息可视化辐射,和內建一些必要的流程控制环节,例如操作权限和信息审计等。这样一个平台应纳入IT企业的战略性平台之一,其价值我认为有几点:

  1. 作为一个杠杆,在规模化的组织中撬动各个交付团队的持续交付/DevOps工程技术能力,将其快速拉到一个基线,大大降低各团队自己实施的成本;
  2. 通过统一的部署流水线将从代码提交到交付给用户的整个过程高度可视化出来,信息透明;让开发、测试和运维以高度一致的方式工作在同一个流水线上,真正建立起协作;
  3. 每一次的软件变更在这个完整的流水线中得到充分的验证,尽早发现有缺陷的变更;而经过了完整验证的变更可以随时部署出去;
  4. 在组织级能够将一些必不可少的控制环节內建到自动化过程中,比如质量保障过程、过程度量、权限控制及过程审计信息等,从而弱化很多传统依靠人为检查的管理流程,实现精益敏捷的轻流程目标。

我们已经明显看到有不少互联网公司,比如阿里、腾讯在组织级提供类似这样的交付平台,然而更多IT企业还没有跟上。

还有一个更重要的关键词必须强调:“自助式”,这是平台设计的前提。我们在有些组织看到确实有类似的持续集成、持续交付平台。然而对这个平台的使用就如同前面提到的集中式IT基础设施服务一样,当交付团队需要为新的应用或服务建立一套新的自动化构建任务,或需要修改现有配置时,必须向平台的负责部门提出申请,由集中式的团队来帮助建立或修改配置。这些配置任务在集中式团队排队和等待,成为新的瓶颈。而产品交付团队自身始终不具备自动化能力,每次变更配置都不得不等待,导致需要的自动化任务跟不上架构的变化,任务失败后定位和解决问题很低效。最严重的是,团队的开发、测试人员根本不关心持续集成的执行和结果。这种模式下,平台其实远远发挥不了它应有的作用。

正确的做法是,平台团队只需要专注于提供自动化、自助式的持续交付平台,将产品交付团队当做自己的用户,听取使用反馈,持续演进;平台的设计必须要兼顾过程的标准化和流水线配置的灵活性;该团队不负责为各产品配置构建任务和流水线。这个配置工作应完全由各交付团队自己来完成,必须要具备“在需要修改配置时随时自己就可以修改”的能力。若没有该能力,组织就要提供培训和赋能。

挑战五:IT架构耦合度高

上图左下方的这栋建筑,住着很多户。如果其中某一户对自己房子的布局和功能不满意,想要重新设计,这时一个房间的设计改动必然影响到其它住户,甚至可能危机整栋建筑。如果要想允许每一户人随时修改自己房子,不用太担心危及整个系统,缩短整个改动的周期,就需要像图中其它的小房子一样,彼此之间松耦合,靠简单、标准的道路来连接。

我们的IT系统也是一样,要实现DevOps的目标,更快地响应业务变化、提高交付吞吐量,每个子系统的粒度就要小,彼此之间松耦合,各自可以独立地进行测试和部署。很多企业多个系统因为耦合紧密不得不在同一时间点部署发布,为了确保每一次投产不出问题,需要投入大量人力来进行协调,投产部署过程要处理更大的复杂性,也更容易引入质量问题。

另一方面的影响是,若单一系统规模大、复杂性高、系统间耦合度高,就难以给予交付团队更大授权、实现开发团队自主运维。

DevOps转型过程中的这一挑战在于,企业必须对现有IT系统进行解耦,将目前很多代码级依赖、数据库级依赖、或业务上的紧密依赖进行解耦,走向围绕业务领域边界建立的、靠轻量级服务和消息集成的服务化架构,要从设计上使得相互依赖的服务之间在升级时做到前向兼容,这是一个困难且耗时的过程;在这个过程中如果没有恰当的架构演进策略,缺少正确的方法引导,导致在服务拆分不合理,或缺少与之配套的服务治理能力,结果可能适得其反。这方面我们有过很多经验教训。ThoughtWorks在实践DevOps的过程中,往往就伴随着大量的向微服务方向进行架构拆分和改造的工作,这一过程可能长达数年,逐步演进。但绝不能知难而退,投入必不可少。

挑战六:职能化组织中的开发运维部门墙

在多年以前,当传统企业的业务发展对数字化的依赖程度还不高,当管理者将IT系统的开发视为一种耗费人力但又价值并不高的非核心能力时,快速膨胀的软件研发队伍纷纷从原有的业务部门中拆分出来,成为了独立的部门或信息技术子公司;随着软件系统的复杂性越来越高,在专业化、流程化的考虑下,实现功能的开发、保障质量的测试和保障运行稳定的运维按职责和技能不同被拆分成了各自独立、相互制衡的部门。结果是各部门有了自己的目标,彼此不同甚至相互冲突,都着眼于各自内部优化;但很不幸地,在这个过程中企业的终极目标——最大化为用户/客户创造价值,这个必须要所有职能作为一个有机的整体运作才能实现的目标——却被弱化了。如下:

在这样的组织设计中,各部分在一致目标下的协作不足,而更加注重过程控制和相互制衡,要真正实现DevOps是不可能的。举几个例子:

在给一些企业评估其持续交付和DevOps能力时,普遍的情况是开发完成的工作进入生产环境要经过冗长的审批过程,审批基于一大堆文档;然而事实是(不要欺骗自己),那些并不了解产品细节和每一次变更细节的审批者,很少甚至从来没有在审批过程中发现过潜藏的问题,但这一过程却严重拉长了新版本上线获得用户反馈的周期;可以说,如果开发团队在提交文档时,某些文档忘了修改、还保持和上一次申请时一模一样,估计那些审批者也发现不了(或者根本就不会细看);

另一个普遍的现实是前面提到过的,开发、测试和运维各自有一套工具来完成自己关心的任务,而这些工具相互割裂、重复建设,没有协作。不一致的工作方式和工具既降低了交付吞吐量,也给质量保障引入了更大风险。

让软件开发的最后一公里——运维环节变得更加敏捷和适应变化,开发和运维职能的紧密协作是DevOps运动的最核心思想。要达到该目标,企业如何为开发和运维建立一致的目标,通过协作而非制衡的方式来共同面对同时提升吞吐量和保障稳定性的挑战是企业实施DevOps最重要的命题!组织需要下面这样一种治理结构:

围绕着提供给用户的产品和服务,建立包括产品设计、开发、测试和运维在内的产品交付团队。这并不意味着组织一定要立即在汇报线的设置上做出改变,关键是如何设置目标和组织日常工作!除了各业务产品,同时集中的IT运维服务部门也应走向产品化,也就是从以往为各个业务产品提供运维支持,转向专注于为业务产品交付团队提供支撑其交付的平台,以及进行运维监控、运营分析的平台;可能也从用户支持统一体验的角度出发,给各业务产品提供面向最终用户统一的支持、服务热线和客户服务渠道。

这种转变对组织是很大的挑战,涉及到多年形成的治理结构的改变。首先需要各级管理者思想上的改变,从基于不信任前提的控制型、分化制衡型管理思想,转变为基于信任前提的服务型、协作型管理思想,这在ThoughtWorks提倡的适应性领导力中有深入探讨。这种转变从一开始,很难在组织大范围开展,建议的是先建立特区,再逐步试点扩大,最后实现突破;在转变的过程中必然会涉及到部门职责范围、绩效考评、人才能力模型等深层次的转变。这种转变需要组织管理者、转型推动者发挥领导力,展现出变革的魄力和执行力才能得以成功。

挑战七:缺少敏捷文化

前面谈到的强职能化组织结构也深刻地影响着一个组织的文化。在与曾经咨询过的一个客户探讨到如何进行DevOps转型时,开发和运维部门坐在一起探讨。大家就运维流程如何改变、自动化能力如何建设等都没有异议,然而自始至终无法突破的终极问题就是:无论我们如何改变,如果万一生产环境出了问题,谁承担责任?因为DevOps能力的建设需要一个过程,开发团队不敢承诺完全承担责任;而运维因为弱化审批和控制力,也认为不该为其承担责任。最终不了了之。

我认为,根本的问题出在文化,旧有的组织治理模式产生了各扫门前雪的官僚文化,没有责任共担,以及出现问题必然问责的文化。这种文化可能源自惯性的职能化思维,可能源自组织的绩效考评和激励制度。

现代关于“系统论”的研究已经在很多著作中强调,一个组织就是一个由人构成的复杂系统,组织中每一个人所能获得的信息是有限的(包括最高管理者也是),每个人或团队都只能基于自己有限的经验、有限的信息做出决策和行动。如果系统发生失败,例如生产环境出现问题,这必然是由于系统各个部分相互作用(从想法提出到软件投产各个环节的相互作用、系统与其它系统间的相互作用)产生的结果,对其中任何局部进行惩罚无非是寻找替罪羊,有害而无益。这时候组织真正应该做的,是相信每一个人都已经做出了最大努力,将相关干系人拉到一起对问题的根因进行分析,找到能够有效避免类似问题再次出现的解决方案,并确保该方案得到实施,对其效果进行验证。

再举一个例子,Petrik曾经在DevOpsDays上提到了一个DevOps的优秀实践:Chaos Monkey(混世魔猴)。这只自动化的猴子会每隔一段时间随机将生产环境服务器关闭,以此来测试生产环境的快速恢复能力,促使各团队提升系统的稳定性。我曾经和国内企业的开发、运维部门讨论过这个实践,有趣的是无论开发还是运维都跳出来反对该实践,认为无法落地。如果没有这只“猴子”,大家可以给领导讲自己的系统很稳定(只要没出问题);然而这只“猴子”可能会随时暴露出自己的系统并不像自己所宣称的那样稳定,会降低自己在上级心目中的“有能力”印象,随之而来的可能就是问责、惩罚。这样的文化下,大家真正关心的是如何给领导“表现”,而不是在真正的系统稳定性上追求卓越。

真正能够实现DevOps的组织,我们认为需要具备下面这样一些文化:

总结

无论是组织治理结构、管理流程、工程技术能力还是文化特征,DevOps运动都和精益产品开发、敏捷宣言所倡导的理念一致。我认为一个组织如果没有充分经历过敏捷文化的熏陶,也很难实现DevOps的目标,充其量在自动化工具和技术能力上有所提升,收益很有限。

因此我们不应当将DevOps作为一个孤立的运动去看待,更不能仅仅从工具角度去实施,而是应当将DevOps作为企业在数字化进程中为追求创新和快速市场响应、为提升组织适应力所进行的精益敏捷组织转型的一部分,这是一项系统工程。 尽管挑战重重,只要管理者首先从自身的管理思想出发做出改变,从组织小范围开始,将各种职能的人员聚拢到一起,设置共同的愿景和目标,打破束缚,给予足够授权,以紧密协作、责任共担的方式共同面对挑战,就能取得成功。然后再将小范围的经验在更大的范围逐步扩散,并适时地对企业深层次治理模式做出调整,就能够在整个企业范围内产生积极影响力,带来组织效能的巨大提升。


更多精彩商业洞见,请关注微信公众号:ThoughtWorks商业洞见

Share

DevOps团队之殇

“你在团队里是做什么的?”

“DevOps。”

“DevOps是什么呢?”

“DevOps是一种文化、一种实践,目标是加快软件迭代速度,让团队更快交付价值。”

“能不能具体点,你们日常工作的主要内容是什么?”

“修Pipeline…”

作为一名开发,在刚涉足DevOps领域的时候,最难的就是和传统运维撇清关系;等到DevOps不再被当成是运维,又容易被当成是专职修Pipeline的人。

DevOps在一遍遍被人们提及、一次次在项目中被实践时,也在不断地被重新定义,DevOps是什么?这个问题可能到现在也比较难说清楚,但是项目中的“DevOps”做了些什么,却是清晰可见的。

本文就结合笔者的切身经历,谈一谈关于DevOps交付的价值以及在企业转型过程中遇到的一些问题。

背景介绍

客户是一家澳洲大型金融保险企业,其IT部门总人数在千人以上,维护应用两百余个。在经历了几年的收购和合并之后,在业务上指定了“将收购来的多个品牌进行整合”的大方针,于是IT部门也开始面临系统整合、业务线整合、网站合并的问题,同时客户正在将他们的服务逐渐从自建数据中心向AWS公有云服务上迁移。

团队概览

在数字化转型的漫漫长路中,该企业已经在内部搭建起了一套持续交付系统,以Jenkins为中心,有制品库、依赖管理、代码管理、任务管理系统,敏捷实践成熟。

我所在的团队是在整个组织向DevOps转型中的一个比较关键的团队,肩负着CI/CD优化、持续交付改进、运维能力输出的重任。类似的团队应该在很多DevOps转型的组织里都有,负责维护CI/CD基础设施、搭建应用开发脚手架、维护基础设施变更、做各种自动化的工作(姑且就将这类团队称之为Platform团队)。

比较特殊的是我在的这个团队实行轮岗制,由产品团队的成员(通常是开发人员)定期轮换到Platform团队,带着在产品团队遇到但是没能解决的问题,在这个团队中寻求最佳实践和解决方案,一段时间后(通常是三个月),开发人员从Platform团队回到开发团队,同时将DevOps技能和最佳实践带到产品开发团队。

整个Platform团队基本维持在3-5人的规模,有一个IM(Iteration Manager迭代经理),其余全是开发人员。

取得的成就

回顾过去的五个月,Platform团队一共经历了10个迭代(每个迭代两个星期),我梳理了一下每个迭代的工作内容,整理出主要成就如下:

  • 围绕CI/CD做了很多优化,比如简化Jenkins slave创建流程、给自动化脚本(基础设施代码)贡献了许多新功能。
  • 新技术试点,比如尝试将静态文件部署到AWS S3中代替Apache服务。
  • 为应用设置监控,更新了基础设施脚本用于开启监控,并协助应用团队将配置脚本应用到各个环境。
  • 团队之间的沟通,了解开发团队痛点,帮助开发团队找到能够解决问题的团队(权限、责任划分、知识传递),技能培训等。
  • 响应变化,解决技术难题(虽然我认为这更像是一个沟通+权限的问题,但是其他所有团队都认为是技术难题,那我也就这样认为吧),以及修复一些类似于硬盘空间已满、网络延迟、权限的问题。

遇到的问题

当然在交付价值的同时,有很多痛点是非常折磨人的:

  • 权限分配:作为一个跨开发团队工作的团队,不但没有拥有比开发团队更多的权限,甚至连开发团队的一些权限都没有,比如不能向开发团队的代码库提交代码(修改基础设施代码需要这个权限),比如缺少Linux权限导致服务器底层问题没法直接修复,再比如 Jenkins 的问题追踪到了服务层需要维护Jenkins的团队支持,因为涉及到CI/CD的应用是由别的团队在管理。
  • 沟通效率:为了解决一个bug,有时候要花上两周的时间发邮件,找关键人物,组织会议,跟不同的人解释五遍以上的上下文(技术细节的上下文是很繁琐的),最后解决问题的人还很有可能不是自己团队的(没有权限)。因为大家平时都很忙,而且建卡工作的方式让一部分人对团队请求帮助的问题不是很热心,这种情况在沟通的时候如果表现得情商不够高,对方就会要你发邮件给他们团队然后等 IM 建卡,规划到迭代里再说了,我遇到过一次这样的情况,最后还是通过社工手段拿下了这个关键人物,过程不可谓不曲折。
  • 明确需求:Platform团队并不交付业务价值,因此没有BA(Business analyst业务分析师,通常扮演梳理需求的角色),建卡的事基本都由IM和Dev来做,虽然感觉上是合理的,但实施起来却遇到很多问题,究其根本就是对需求的定义和划分不够明确,导致最后挪卡的时候大家都说不准这张卡算不算完成了,只能用拍脑袋的方式来决定。
  • 质量分析:同上,团队缺少QA(Quality Assurance,质量工程师,测试人员),Dev们都是自己做卡自己测,有时候会结对测试,但也会因为对需求理解不充分,或者说拆卡拆得有问题,导致一些卡完成得质量不够,直接影响受依赖的卡。举个例子,部署监控需要自动化脚本的两个模块支持,两个模块被分为两张卡,在做第一张卡的时候遇到了诸多问题,好不容易把代码提交到别人的版本库里了,在做第二张卡的时候却发现第一张卡代码里多写了一对引号,导致整个逻辑实现失败,这个时候再回过头来改之前的代码,又要重新解决之前遇到的各种问题(沟通、权限,PS:这个时候做第一张卡的人还下了项目),周期和浪费的工时是可想而知的。
  • 人员轮岗:这是 IM 一直很头疼的一件事,Platform团队大量的时间花在给新来的团队成员输入上下文、同时又有成员离开团队要交接工作、尤其在沟通重要的工作中,成员的离开意味着需要新的人重新和干系人建立联系,再者,一些成员因为项目上的痛点,不是很有心思工作在团队的事务上,而是更关心自己过段时间会被分配到那个团队,如此种种都对团队的价值交付造成了很大的困扰。举一个例子,有一个端到端测试工具一直由Platform团队维护,从我加入Platform团队开始,这个测试工具就打算新增一个集成远程浏览器引擎的功能,这是一个非常有价值的功能,因为开发团队长期苦于浏览器版本支持过少,端到端测试不稳定;但是在实现过程中一直存在一个网络问题,这张卡先后被关闭、开启、标记完成、又重新开启,经历了大概五六个人的手,困扰我们的网络问题直到Platform团队解散,都没能解决。
  • 关键角色管理:做了什么很重要,有时候让别人知道你做了什么比做了什么更重要。这一点在 Platform 团队体现的得尤为明显;在交付团队中,开发如果发现资源不足,需要和TL(Tech Lead 或是Team Lead,可以理解为项目组长)或者PM(Production Manager 产品经理)沟通,如果缺少合适的汇报对象,一方面在团队需要外部支持或更多资源(比如权限)的时候得不到及时的支持,另一方面意味着团队缺少了更高的视角来实时回顾自己做的事情是否是正确的,方向有没有走偏,或者是不是又在造别人造过的轮子。我在团队解散后的回顾会议中,IM还坚持认为我们团队被解散是因为没有一个强有力的领导在背后支持,这也从侧面反映了我们没有找到合适的汇报人,告诉他,我们在做什么,听他说,我们下一步可以做什么。

分析

问题背后的原因及可能的改进方案

团队解散后经过一段时间的沉淀,我针对以上痛点与过往的成员一一交谈,了解了他们的想法,总结分析出了以下原因,以及可能的解决方案。

原因1:团队方向不清晰

不同于交付业务价值的产品团队,Platform团队不对某一个具体的产品负责,也不直接产出业务价值,加上Platform团队对交付的价值缺乏有效的指标度量,造成了团队方向不清晰的状况。

可能的改进方案:Platform 团队应该是属于架构师的一个机动团队,在团队方向不清晰的时候应该立即与利益相关者(Stakeholder)沟通,即与架构师取得联系,取得高视角的资源,最好能建立交付价值指标,比如Platform团队的目标是加快持续交付,提高交付质量,那就可视化开发团队发布周期、质量报告,让每个团队成员看到Platform团队交付价值的体现,从而明确团队方向。

原因2:团队角色缺失

在架构师不能全权参与团队工作的情况下(甚至Platform团队还可能没有IM),一帮Dev就很容易失去对团队整体的感知,每个Dev只关心自己手里的工作,迭代开始初期容易考虑不到全局影响、不能准确建卡,迭代进行时因为没有合适的汇报人因而跨团队交流困难,迭代结束时没有优质的回顾。 在Micromanagement Culture(微观管理文化)中有一个Alignment(校准)和Autonomy(自治)两个互斥的指标,我们使用这两个指标作为向量构成四个象限,如下图所示:

图片来源:Spotify Engineering Culture

  • 高校准、低自治的团队由领导决定做什么以及怎么做,团队只需要执行,这样会形成“领导说什么就是什么”的局面;
  • 而高校准且高自治的团队是由领导指出要解决的问题以及原因,然后由团队成员相互合作共同找到问题的解决方案;
  • 低校准、低自治的团队则缺乏活力,只能循规蹈矩;
  • 而高自治、低校准的团队成员可以做任何他们想做的事情,领导则很无助因为没有人关心真正需要解决的问题。

在敏捷团队中,如果团队成员只剩下Dev,情形则很有可能变成图中左下象限(也有些许右下)的情况,要想达到右上象限的期望状态,需要提高自治,更多的是校准。

可能的改进方案:在意识到这个问题的时候,团队需要一个关键人物出面充当领导者的角色,扮演这个角色的人必须关注团队交付价值、目标和方向,并且有强大的沟通能力让团队成员目标一致;和利益相关者加强沟通,保证团队方向不会跑偏。

根本原因

Platform团队成立初期被定义为一个立意高远(DevOps转型)的组织,但是在项目实施过程中变得越来越边缘化,其中有“人”的原因,有组织架构的原因,当然还有一些客观原因。但我突然意识到这背后有一个原因一直忽视了,那就是——我们在实践DevOps反模式。

国内近年来一直在对DevOps如何落地争论不休,DevOps提倡的是打破开发和运维的部门墙,将开发和运维(的能力)放在一个团队。然而国内大部分项目的现状是,开发不具备运维技能和意识,也不愿意做“背锅侠”(要求开发做运维一定程度上牺牲了开发的利益,比如亚马逊的开发每隔一周会被要求24小时On-call)。

因此一些公司选择了在项目中先成立一个 “DevOps团队” 作为过渡,再慢慢将CI/CD的理念和技能扩散到其他团队,但是这种方式稍不注意就会变成“换了个名字的Ops ”,因为工作内容相似,写脚本、做高可用,这些是传统运维也会做的事情,这种形式非常不利于团队思维的转变,“团队整体对最终交付物负责”才是DevOps的精要,而不是把团队按职责划分(只对流程负责)。

这样的要求无异是给项目成员增加了工作量和责任,对他们提出了更高的要求。然而很多职员不愿意无回报地多背负一些责任,比如说开发,谁不愿意每天写点代码一提交就早早回家,DevOps要求他们得看着新功能上线,确保无误之后才能离开;所以DevOps的推行在产品团队中是有阻力的,因此DevOps的成功不光需要团队内部努力,也需要得到高层支持并扫除障碍。

反思

在一个不确定性多发的时代,快速的从成败经验中学习比找寻正确的路径更加重要。——ThoughtWorks高级咨询师顾宇

  • 尽早找到关键角色,并且管理好利益相关人。这一点在一个扁平化组织里往往是最容易被忽视的,在意识到要和 Stackholders(利益相关者)建立联系之前,Platform 团队走了很多弯路,也错失了很多机会。
  • 让事情发生比如何发生更重要。应该说在这5个月的工作中,我认为最有价值的是最后两个迭代开始真正搜集来自应用团队的需求,开始在两地组织各个团队的 TL 开会搜集痛点和解决方案。作为 Platform 团队的一员,这件事其实我早就意识到会是非常有价值的,但始终没有去做,总是顾虑不知道怎么去开始、去推动,担心TL 们提出的问题不能得到真正解决。但是最后这件事终于发生了,才意识到真的是非常有价值,而且早该这么做了。关于这点在我还在 ThoughtWorks 试用期的时候我的 Buddy(由公司安排负责伴随新员工渡过试用期的人) 给了我一个非常好的建议,就是决定在讲一个分享之前先把日程表(邀请邮件)发出来,这种看似是“Deadline driven(截止日期驱动)”的方式,背后暗含了“这件事情必须发生”的道理,这和 MVP(Minumum viable product,产品原型) 的原理也是一样的,先上线,再搜集反馈,迭代改进;就算它是一个错误的行为,这也是一次有价值的试错。

我们是否还需要DevOps团队

结合我自身的经历,“DevOps 团队”应该是一次有价值的试错,让我看到了这种方式的一些弊端,应用开发团队自身如果不具备产品思维,要由一个独立的团队去影响它们是很难的,这种实践下的 DevOps 团队就像是披着 DevOps 外衣的 Ops 团队,不能产生理想的价值。

相比之下如果有一种自上而下的方式让开发团队基于已有业务基础之上去优化交付流程,并对每一个提交的最终价值负责,将产品思维真正植入到开发团队,从而达到全局优化的效果,这种做法才更符合真正的 DevOps 精神。


更多精彩洞见,请关注微信公众号:思特沃克

Share

DevOps实践-打造自服务持续交付-下

本文首发于InfoQ:

http://www.infoq.com/cn/articles/devops–build-self-service-continuous-delivery-part02

上一篇文章中,主要讲了DevOps转型的动机、策略和方法,本文将会为大家带来更多DevOps转型的落地策略和实践。

实践过程

下图是我们为团队设计的持续交付流水线,目的是能让Platform团队和交付团队之间的触点能够被融入到持续交付流水线中,并且以基础设施代码作为协同媒介,通过自动化的方式实现开发与运维(即基础设施与软件系统)的无缝对接。

我们来看看我们给持续交付流水线赋予了哪些能力:

  1. 站在交付团队的视角,我们决定将基础设施构建,流水线构建,部署等活动都代码化,与应用代码放在同一个代码仓库中。
  2. 交付团队通过提交我们的基础设施代码到仓库后,自动触发持续交付工具创建或更新流水线。
  3. 接着会自动触发构建,静态检查,测试覆盖率校测,代码规范验证等任务,最终输出构建产物并将构建产物推送到仓库。
  4. 然后会根据交付团队对基础设施和环境的定义到当前要部署的网络环境中去创建或更改虚拟机、网络、存储方式等
  5. 最后,当基础设施创建成功以后,就会去仓库下载指定版本的构建产物进行最终的部署活动。

但需要注意的是:

  1. 为了持续优化交付流程,我们对开发的许多活动进行的数据收集和分析,以报表的形式去分析展示代码提交频率,系统和代码的质量情况,缺陷和构建情况等,帮助团队找到自己的瓶颈或问题。
  2. 帮助团队能够实时监控自己应用的运行状态,设计和查看不同纬度的日志总汇等。

那我们来看看通过什么技术可以实现这样的持续交付流程:

我们选择了一种轻量级、低耦合的技术组合Ansible+Jenkins+AWS。我认为其核心是Ansible。

下面我们来看看Ansible可以帮助我们做些什么:

  1. 创建和更改AWS中的资源
  2. 自动化部署和基础设施测试
  3. 建立开发与平台团队之间的沟通体系

考虑到基于yaml语法的Ansible配置简洁且易读,所以我们选择直接用它作为提供给交付团队的公有DSL模板,利用Ansible Playbook的模块化思想将开发团队的职责和平台团队的职责很清晰的分离,平台团队关注Ansible提供给交付团队的服务是否满足需求和DSL模板是否易用,而交付团队只用关注如何基于公有DSL去定制自己的基础设施,环境依赖和部署等。

于此同时也满足了很多开发对于Ansible和AWS的兴趣和热情,更使得之后在交付团队落地变得更容易。

接下来通过一个实例来看看:

左边是Platform团队的仓库,这个仓库里面包含了创建基础设施、环境配置和部署的实现。

右边是交付团队的仓库,其中deployment目录下,是公有的DSL模板,其中包含多种环境(开发、测试、预生产环境等的独立配置),以及一套基于DSL的代码模板,其中包含创建基础设施和部署应用这两部分DSL代码模板。

接下来,我们来看看它们配合与集成的方式:

他们会在持续集成流水线中被动态组合到一起:

  1. 在创建基础设施和部署的时候会分别拉取基础设施代码库和应用代码库。
  2. 此时应用代码为调用入库,公有基础设施为功能框架库,两者配合,完成环境的创建和应用部署。

在做微服务的团队,接受度非常高,能够快速上手,而且甚至有团队因为自身的一些需求,自己去写一些Ansible模块,然后向我们发起pull request。

当然,我们在推广这套流程的过程中发现,一些实践能够帮助我们更快速落地:

  1. DevOps团队的成员由各交付团队和原运维团队组成,这样的组成方式,能够保证团队的视角可以关注到整个持续交付过程的每个环节。
  2. 交付团队成员与DevOps团队成员定期轮岗制,DevOps小组中的文化(如自动化优先)可以蔓延开,让交付团队更快适应。
  3. 结对、Showcase和培训,主要目的是知识的传递,让更多地团队逐步采用新的交付模式,得到更多改进中的反馈。
  4. 提供给交付团队的自服务代码仓库对每个人开放,交付团队被授权优化、新增基础设施,让DevOps文化和职责落地到交付流程中。

现在来看,集中式、审批式、被动响应请求的中央运维团队不再是整个交付流程中的依赖和瓶颈,已基本转向带自服务化、审查式、主动优化的去中心化交付团队:

我们通过技术驱动改进,让团队之间的合作方式发生了巨大改变,开发与运维之间的那道墙也渐渐消失,以前被动响应请求中央运维团队逐步被平台团队所替代,平台团队中一部分人会负责基础设施平台的发展,负责公有云与企业内部系统的对接、完善安全、灾备、提供基础设施的自服务机制,另一部分人会为产品团队提供可定制的工作、平台、并为产品团队赋能。这时交付团队开始管理自己的环境、维护流水线、负责生产环境变更。

在推广和落地自服务持续交付流程的过程中,我们也遇到了很多遗留系统和复杂部署应用的交付团队,他们无法直接对接这套交付流程。

例如有一个40-50人的团队,它是基于AEM开发整个公司所有的前端门户,AEM是Adobe公司的CMS系统,其安装和部署很复杂,以前都是通过手工安装和拷贝的方式进行部署,而且他们在开发-》测试-》部署阶段可能会动态扩张多套环境来支持,且每次代码变更的提交都会对已经安装的AEM进行修改、配置、重启等操作。

整个开发和测试流程都很复杂,而且效率很低,出现问题和故障的风险也很大,如果我们直接利用Ansible把AEM的安装和部署过程都自动化,由于AEM本身部署的复杂性,可以预见以后这部分更新和维护的工作还是很难交由交付团队自治。所以我们第一步要做的就是为其设计新的持续交付流水线,然后在这个流程中去定义和识别两个团队的职责和关注重心,最后再通过打造高效的自服务使整个交付流程得到改进。

首先我们根据校服团队提交变更的平率,从低到高依次定义了三条持续集成流水线(如下图):

  1. 创建和测试基础设施资源
  2. 配置基础设施资源和环境
  3. 部署应用程

因为AEM安装和更新很复杂,所以我们引入了镜像技术。基础设施和基础设施配置两条流水线的产物为一个image,应用流水线在部署阶段会去检查是否存在新的环境镜像,如果存在,就会基于快速创建一个新的AEM环境,然后进行应用代码的部署。

通过新的自动化持续交付流水线大大加速了AEM团队的开发和测试速度,也使得整个环境更加可控和易维护。对于交付团队来说,他们可以自己去维护包括基础设施、环境变更和应用部署等全生命周期交付活动。对于Platform团队来说,只用去考虑镜像的生命周期管理,如何去优化镜像的创建速度等,这些可以帮助到更多其它团队解决类似问题的领域。对于这种特殊情况,我们尽管引入很多与大多数团队不同的交付流程和技术,但所有的工作和优化都是基于之前打造的自服务持续交付流程、协议和工具平台之上的,保证了不同的交付团队与Platform的配合方式的一致性。

实践启示

通过在大量交付团队落地基于自服务的持续交付流程,两种团队的职责更加清晰了:

所有好的实践都必须考虑规模化的问题,如果无法大规模的被接受和落地,再好的实践也没用。对于咱们这个转型的过程,我也给出一个套路:(如下图)

有了套路,接下来总结一下应用这个套路进行DevOps转型过程中的一些经验和思考:

  1. 易用的通用DSL模板设计,提供交付与Platform团队统一的DSL模板(build and update anything)。
  2. 构建通用持续交付流水框架,提供给交付团队定制化流水线的能力,使流水线主要关注点始终在产品的成功交付。
  3. 以技术驱动DevOps文化大面积传播,让Platform团队成员走入交付团队,协作改进、知识传递,确保实践落地。
  4. 将一切自动化、自服务化。交付团队应该被授权优化、新增基础设施服务,让DevOps能力和职责在交付团队落地生根。

最后,我提取了5点对我们来说非常重要的策略或是推进方法:

  1. 小步快跑,在有大方向的基础上,需要将每一步改变都设计得足够小,这样才能足够快的去改进。
  2. 交付团队赋能,给每个人都留一扇门,在他意识到要做些事情的时候,可以很快付诸行动。
  3. 逐步用基础设施自服务化替代运维部门的审批流程。 建立持续反馈和改进机制。
  4. 以DevOps团队为杠杆,撬动更大范围自服务交付。

非常感谢你的耐心阅读,希望我的文章能够给你带来哪怕一点点启示。有任何问题或是想与我讨论的点都可以给我发Emial: jxzhong@thoughtworks.com


更多精彩洞见,请关注微信公众号:思特沃克

Share