提升微服务实施效率的7个步骤

《微服务进展缓慢的5个难点》中描述了实施微服务常见的主要阻碍。本文针对前文提到的5个难点提出了7个步骤。每个步骤分别包含了管理和技术两方面的建议。

本文首发于GitChat,经作者同意授权转发。转载请联系作者或GitChat。

《微服务进展缓慢的5个难点》中描述了实施微服务常见的主要阻碍。本文针对前文提到的5个难点提出了7个步骤。每个步骤分别包含了管理和技术两方面的建议。

如果以上5点都让你膝盖中箭。那么根据我个人的经验,综合解决微服务实施难点的第一步就是:

步骤1:以终为始,先构建一个独立的敏捷微服务团队

我们对微服务的期待就是:可以独立开发、独立部署、独立发布,并且进行去中心化的管理。那么,我们就先构造一支这样的团队。

这个团队为了达到上述目标,会采取各种方法(例如:DevOps、全功能团队)解决阻碍”独立开发、独立部署、独立发布和去中心化的问题。而根据康威定理,系统的架构会慢慢向“去中心化”方向发展。

一定要意识到,这个过程会打破大型系统自上而下的既有流程并采用更有生产力的方式构建新的组织结构。你唯一需要做的就是要充分信任团队,把它看做是一个微型的技术管理创新。不要用老的方式控制团队的运作,这会打击团队的士气。

管理建议:

  • 让微服务团队完全脱离之前的工作,专心于微服务的工作中。如果分心同时做几件事,每件事都不会做到最好。
  • 给微服务团队一些特权,为了满足“全功能微服务团队的”诉求,特事特办。
  • 如果团队在执行的过程出现了依赖,进而阻碍了进度。则需要把依赖标明出来。代码中的依赖容易看见,但组织中的流程依赖很难发现。
  • 为了避免团队对外部的“依赖惯性”,让团队自己想办法在内部解决依赖。
  • 组织流程的改变也是很重要的微服务架构产物,而不仅仅是微服务代码或基础设施。

技术建议:

  • 为微服务建立一个全新的代码库,而不要从原先的代码库上克隆或者复制,避免和原团队的开发依赖。
  • 建设一个独立的持续交付流水线,最好是通过“流水线即代码技术”(例如Jenkinsfile)来自动生成流水线。

步骤2:构建微服务的“电梯演讲”

成立了微服务团队之后,接下来就是要选择第一个实现的微服务。但是“这个微服务应该多大,边界在哪”是个问题。这不需要进行严格的设计和反复的论证,只要发现当前的痛点或者想要完成一个假设就足够上路了。让整个过程变轻,而不是变重。

我的建议是通过“微服务电梯演讲”的方式来定义微服务。格式可以是:

  • (XX微服务)用来
  • 在(出现痛点的场景)的情况下
  • 解决(解决现有的某个问题)
  • 从而(达到什么样的效果)
  • 提升(微服务的价值)

例如:

  • (订单查询微服务)用来
  • 在(订单查询数量快速)的情况下
  • 解决(访问数量迅速升高导致整体应用性能下降的问题)
  • 从而(分离了订单查询请求)
  • 提升(其他功能的性能)

当构造了微服务的电梯演讲,团队就可以以此为原则来启动了。当碰到和现有系统冲突的问题,替换几个词比较能帮助你做决策。(语言在一定程度上也是具有魔力的)

把“拆分”换成“移除”。例如:“从现有系统中拆分出订单查询功能”转变为”从现有系统中移除订单查询功能”。思维方式就从一个团队负责两个系统变成了两个团队负责两个系统。

把“集成”换成“调用”。例如:“用户注册和用户登录需要集成”转变为“用户登录服务需要调用用户注册服务的信息”。思维方式的转换就把两个系统的关系更精确了,从而明确了微服务之间的关系和沟通方式。

管理建议:

  • 把微服务的电梯演讲打印出来挂到墙上,让团队成员铭记于心。这会强化组织对微服务的边界认识。
  • 随着团队的反思和学习,电梯演讲有可能会变更,但一定要让团队形成共识和一致的意见。
  • 不要期望一次就能划分正确。划分是一个持续权衡取舍的过程。

技术建议:

  • 明确了微服务的职责和边界之后再去看代码,否则会被代码的复杂度影响。
  • 领域驱动设计(DDD)可以帮助你更好的划分微服务。领域驱动设计很好的遵循了“关注点分离”(Separation of concerns,SOC)的原则,提出了更成熟、清晰的分层架构。
  • 不会领域驱动设计(DDD)也没有关系。简单的使用“关注点分离原则”也可以帮你达到这一点。例如:从接口中分离出流量较大的接口独立部署,把读数据库和写数据库的API分开独立部署,把静态和动态访问分离……

步骤3:以最小的代价发布出第一个微服务

要注意两个关键点:一个是“最小的代价”,另一个是“发布”(Release)。

正如前文所述,微服务架构本身就决定了微服务一定是低成本低风险的渐进式演进。而最大的浪费在于:

  1. 级别/职责分工明确的组织沟通结构。
  2. “长时间,慢反馈”的行动习惯。
  3. 先进且学习成本较高的技术栈。

因此,“最小的代价”包含了以下三个方面:

  1. 最精简的独立敏捷全功能团队。
  2. 最快的时间。
  3. 代价最小的技术栈。

此外,很多微服务的“爱好者”由于害怕失败,因此将微服务技术始终放在“实验室”里。要勇于面对失败,在生产环境中面对真实的问题,但要采取一些规避风险的措施。

管理建议:

  • 尽量让现有微服务团队自己学习解决问题,成为全功能团队。如无必要,绝不增添新的人手。
  • “扯破嗓子不如甩开膀子”,先动起来,在前进中解决问题。
  • 先考虑最后如何发布,根据发布流程倒推。

技术建议:

  • 根据当前技术采用的情况选择代价较小的技术栈。
  • 采用动态特性开关(Feature Toggle),在发布后可以在生产环境动态的控制微服务的启用,降低失败风险。
  • 如果采用了特性开关,一定要设立删除特性开关和对应旧代码的时间,一般不超过两个月。否则后面大量的特性开关会带来管理成本的提升和代码的凌乱。
  • 由于团队比较小,功能比较单一,不建议采用分支来构建微服务,而应该采用单主干方式开发。

步骤4:取得快速胜利(Quick wins),演示(Showcase)驱动开发

刚开始进行微服务改造的时候一定会是一个试错的过程。如果目标定得太大,会让团队倍感压力,从而士气低落。而制定每日的短期目标,赢得快速胜利则会不断激励团队的士气。通过“设定当天结束的产出来确定今天需要做什么”是一个非常有效的办法。

每日演示(Daily Showcase)就是一种推进产出的做法。每天向团队分享今天的工作内容,使小组能够共同学习。并且以当天或者明天的showcase作为目标。每个人showcase的内容一般不超过20分钟,一天的showcase时间不超过一小时。可以早上showcase,也可以下班后showcase。

常见的快速胜利目标如下:

  • 构造第一条微服务流水线。
  • 上线第一个微服务HelloWorld
  • 构造出第一个微服务自动化测试。

而以下的目标不适合作为快速胜利的目标:

  • 构造出微服务DevOps平台。
  • 完成整个产品的微服务架构拆分。
  • 构造微服务自动化运维体系。

管理建议:

  • 要防止团队画大饼,完成好每日和每周的工作目标即可。微服务开发本身就没有很长周期。
  • 强迫团队有所产出,这样才能用关键产出驱动开发。产出不一定是代码或者基础设施,一篇总结,或者学习的文章分享,甚至是踩过的坑和遇到的问题都可以展示,目的是要打造自治学习的团队。
  • 贵在坚持,不要计划太远。超过一个月,就要对目标是不是范围过大进行反思。
  • 以天为单位拆分任务,超过一天的必须要拆分。无法在一天完成的工作需要拆分出阶段性产出。
  • 如果能结对,并且能够每天交换结对,showcase不必要。
  • 可视化所有任务,用敏捷看板来管理任务是了解现状的最好方式。

技术建议:

  • 想办法让第一个微服务尽快发布到生产环境,生产是最重要的。
  • 完成了HelloWord的发布,就要考虑如何对发布流程进行改进。而不是着急准备下一个业务上线。

步骤5:代码未动,DevOps先行

微服务解耦的本质是把代码内部的复杂性通过一些工具转化外部复杂性。把代码内部的复杂性分散到各个微服务中以降低整体复杂性和架构风险。在这个过程中会大量采用DevOps技术和工具。也可以说,微服务是DevOps文化和技术在走到极致的必然结果。

以J2EE的应用为例,以前Web Server + App Server + MiddleWare + Database的传统架构被更多的基础设施工具所取代,所需要的编程工作量更小。因为基础设施相对于应用代码来说更加稳定,更加利于扩展。

我把微服务的技术架构问题比作“搭台唱戏”:首先需要建立好微服务交付和运行的平台,然后让微服务上台“唱戏”。

这个平台一开始不需要很完善,只需要满足生产上线的必要要求即可。而在很多企业里,这个部分是由Ops团队在交付流程的末尾把关的。因此,把最后一道关卡的确认工作放到最前面考虑可以减少后期的返工以及不必要的浪费。

以前,软件的开发和测试过程是分开的。然而,随着DevOps运动和各种自动化运维工具的兴起,这之间的必要性有所降低,只要有足够的自动化测试做质量保证,就可以很快的将微服务快速部署和发布到生产环境上。

最开始的时候,哪怕是发布一个Hello World程序,都表明微服务的持续交付和运行的平台已经搭建好,微服务交付流程已经打通,这一点是重中之重。

从技术交付产物来说,DevOps主要交付两点:

  • 持续交付流水线。
  • 微服务运行平台。

为了保证微服务交付的高效,需要把这二者通过自动化的方式有机的结合起来,而不是各为其主。让开发和运维的矛盾变成“自动化的开发运维矛盾”

此外,DevOps指的不光是一系列技术,更是一种工作方式。从团队工作方式来说,DevOps要做到:

  • 要让Dev和Ops共同参与决策、设计、实现和维护。
  • 团队完全独立自主,打破对现有流程的依赖。
  • 不断的追求改进,让团队形成改进的团队文化。

管理建议:

  • “新程序快速投入生产”能给团队继续前进最大的动力。
  • 如果你的组织是Dev和Ops分离的组织,先咨询一下Ops工程师的意见。最好是能够给微服务团队里面配备一名Ops工程师。
  • 如果不具备实施DevOps的条件,微服务架构就要从运维侧,而不是开发侧开始进行。

技术建议:

  • 微服务的平台一开始可以很简单,以后慢慢增强和扩展。但是一定要部署到生产环境里使用。
  • 如果想使用现成的微服务平台,可以参考Spring Cloud。
  • 微服务运行平台可以通过灰度发布技术在生产环境并行运行。
  • 采用灰度发布技术在生产环境中逐步提升微服务的使用占比。
  • 基础设施即代码是DevOps核心实践,可以帮助开发人员迅速在本机构建生产环境相似的开发环境,减少环境的不一致性。可以采用Docker,Ansible,Vagrant等工具来完成。
  • 基础设施对微服务应该是透明的。微服务不应该也没必要知道运行环境的细节。只要能够正常启动并执行业务就完成了它的任务。因此,基础设施代码要和微服务业务代码分开,且微服务不应该告诉平台自己如何部署。
  • 服务注册和发现是微服务架构的核心部分。consul和Eureka是这方面的佼佼者。
  • 部署(Deploy)和发布(Release)要分开。

步骤6:除了提交代码和发布,微服务平台一切都应当自动化

在完成了微服务的基础设施和交付流程之后,就可以开始实现微服务的业务了。这时候需要依据电梯演讲划分出来的微服务进行业务逻辑的开发。在以DevOps的方式工作一段时间之后,团队应该养成了一些自动化的习惯,如果没有,就应该检查一下自己的自动化程度。最佳的自动化理想的状态就是除了代码提交和发布,在这之间的每一个流程和环节都应当由自动化的手段来完成。

当然,也有不能自动化的部分。根据我的经验,不能自动化的原因主要来自于流程管理的制度要求,而非技术困难。这往往是组织没有依据微服务进行流程变革导致的。这时候需要检讨不能自动化的部分是不是有存在的必要。

另一方面,虽然自动化可以大量缩短微服务交付时间,提升微服务交付效率。但是自动化的同时需要考虑到安全因素和风险,不能顾此失彼。对于生产来说,可用性和安全性是最重要的部分。 关键的自动化:

  • 自动化功能性测试(UI/集成/单元/回归)
  • 自动化构建
  • 自动化部署
  • 自动化性能测试
  • 自动化安全扫描

管理建议:

  • 团队成员自发的进行自动化的改进,这会给未来微服务批量开发带来很多益处。
  • 不要一开始就追求全面的自动化,自动化需要花费一定时间。根据团队的进度视情况适度进行。

技术建议:

  • 采用TDD的方式开发不光可以提升质量,也完成了测试的自动化。
  • 契约测试可以解耦微服务提供者和消费者的开发。但是要注意始终保持契约的有效性,一定要先改契约后开发。
  • 注意自动化的安全隐患。机密信息需要独立管理,例如可以采用 Hashicorp Vault 这样的服务。
  • 关键步骤需要准备自动、手动两种方式,必要时可以干预自动过程。
  • 采用git的hook技术,在代码push之前就可以完成测试和静态检查,提升CI的成功率。

步骤7:总结并复制成功经验,建立起微服务交付的节奏

当完成了第一个微服务,不要着急开始进行下一个微服务的开发。而是需要进行一次关于可复制经验的总结,识别微服务开发中的经验教训并总结成可复制的经验和产出。

以下是一些需要总结出来的关键产出:

  • 微服务开发到发布的端到端流程规范。
  • 微服务开发的技术质量规范。
  • 团队合作中坚持的最佳实践。
  • 常见技术问题总结。

有了以上的关键产出,就可以对微服务开发团队进行扩张。这时候有了微服务开发的老司机,带着刚加入的同事一起开发,风险会相对低很多。

管理建议:

  • 刚开始的时候可以每周举行一个回顾会议,团队需要快速的反馈和调整。
  • 不要急于扩张团队,要在成功经验稳定并形成模式之后再快速扩充。
  • 避免微服务良好的开发氛围被稀释,刚开始的时候扩充团队可以慢一点。新老成员的配比不要超过1:1。
  • 虽然微服务平台趋于稳定,但在微服务没有上规模之前,不要让团队里缺少Ops成员。
  • 注意知识的传递和人员的培养。

技术建议:

  • 不要急于在微服务应用规模不大的时候形成微服务模板,这会限制未来微服务的开发和扩展。
  • 在微服务不成规模的时候不要放松对微服务平台和交付流程的改进。要做到最快的时间交付和发布微服务。

参考书目

  • 《微服务设计》是一本有关微服务各个方面技术的综合参考材料。如果你在实施微服务的过程中碰到了问题,它就是一个解决方案的分类汇总。
  • 《持续交付》汇集了很多交付最佳实践,当你的微服务实施碰到阻碍时,里面的建议或许能够让你解决当前的困境。
  • 《领域驱动设计》《实现领域驱动设计》为拆分微服务提供了方法论,当团队之间对于微服务的拆分有困难的时候,采用领域驱动的方法往往会得到更好的效果。·
  • 《微服务那些事儿》是一本快速启动微服务的工具和实践的总结,能够帮助微服务入门者快速跨越门槛。

更多精彩文章,请关注微信公众号:软件乌托邦

Share

微服务进展缓慢的5个难点

笔者从2013年加入ThoughtWorks至今共4年时间。在这4年时间里,我分别以开发人员、DevOps工程师、DevOps咨询师、微服务架构师以及微服务咨询师的角色参与了共计7个产品和项目的微服务咨询和实施。其中有成功,有失败,有反思,更多的是学习和总结。以下是我这些年来在微服务咨询上的经验总结,希望能给陷入微服务实施困境的人带来一些帮助。

本文首发于GitChat,原作者顾宇,经作者同意授权转发。转载请联系作者或GitChat。

前言

笔者从2013年加入ThoughtWorks至今共4年时间。在这4年时间里,我分别以开发人员、DevOps工程师、DevOps咨询师、微服务架构师以及微服务咨询师的角色参与了共计7个产品和项目的微服务咨询和实施。其中有成功,有失败,有反思,更多的是学习和总结。以下是我这些年来在微服务咨询上的经验总结,希望能给陷入微服务实施困境的人带来一些帮助。

难点1:“一步到位”的认知错觉

这些年微服务大红大紫,但是真正能够拿出来做为可实践案例的少之又少。大部分的微服务案例只能看到微服务架构的“演进结果”,但是看不到其“演进过程”。这就像每个人可以看到一个架构的高峰,却看不到攀登高峰的路径。

这就造成了一个假象:微服务的架构是通过能力极高的架构师一步到位设计出来的。

这和很多团队自上而下的架构设计感受很相似。于是架构师们蜂拥而至,各种分析方法论层出不穷,讨论和分享络绎不绝。然而真正落地实施的却很少,使得微服务在网络上慢慢变成了一种“玄学”:微服务的实施一直在“理论研究”的阶段。

这违反了软件架构的最基本规律:架构是通过解决当前的需求和痛点而演进的,无法根据没有出现的问题和痛点进行设计。因此,一步到位的、整体的微服务架构设计完全没有必要。况且一个集中化的设计,很难体现微服务的轻量级优势。

我相信技术一定是向不断降低成本的方向发展的。如果新技术没有降低成本反而提升了成本,要么这个新技术有问题,要么是姿势不对、走错了路。

因此,准备实施微服务一定要有一个长期的思想准备。不过跨过了最初的门槛之后,剩下的工作可以被复制、而且速度会越来越快。

难点2:“架构师精英主义”

很多产品对架构师的依赖很大,即“架构师精英主义”:认为只有这个组织的“技术精英”——架构师才可以完成该产品的架构,而团队其它成员只需要实现架构师的设计就可以。这是大型企业和大型系统的常见问题,来源于长期以来重量级企业级架构的习惯。

而微服务则类似于一种“敏捷边际革命”:即由一个不超过2~8个人的小团队就可以完成的轻量级架构。而且对于这种规模的团队而言,即使把整个微服务团队从产品团队移除也不会对整体产品的研发进度产生影响。因此,即使失败了也不会带来太多的损失。不过,当第一个微服务改造成功,那么成功经验的复制带来的乘数效应却能带来很大的收益。

从架构改造投资的风险收益比来看,这是非常划算的。

因此,微服务团队完全没必要大张旗鼓,只需要两三个人就可以动工。但是,谁也没有微服务的实践经验啊,万一失败了怎么办?

这就带来了下一个难点。

难点3:缺乏一个信任并鼓励创新的环境

面对未知的领域,失败再所难免。而处在这个不确定性频发的世界,成功和失败已经不再重要:也许今天的失败,明天再看就是成功,反之亦然。

成功只是表明结果符合自己的假设预期,而失败仅仅意味着结果不符合自己的假设预期。但是无论成败,我们都能在行动的过程中有所学习和反思,而这样的经验才是研发活动中最有价值的。

然而,很多组织,尤其“精英主义”的产品团队,责任和压力往往从上至下分解。由于组织庞大,金字塔的结构往往会构建一种以“不信任”为基础的制度。这种制度营造了一种“宁可不作为,也不能犯错”的文化。由于上层需要对失败负责,使得所有创新只能停留在上层,难以落实推进。在这种情况下,组织的长期合作形成了稳定的工作习惯和思维定势,并形成了利益平衡,这会使得整个组织在面对创新的时候“卡壳”。

当微服务以一种政治任务从上而下派发的时候,为了避免失败,团队内部会相互推诿。通过不断的分析讨论和设计来论证这个事情的难度。在我看来,只要想搞,就一定能找到办法,而不是先设想出一堆还没有遇到的问题和责任。在行进中解决问题是比设计和讨论更加有效率的方法。

而组织解决“卡壳”的办法就是引入“背锅侠”:例如新聘请的架构师或外部咨询师,来完成这个事情。出了问题就不用自己来承担责任了。这样虽然是解决问题的一种折中办法,可以让事情毫无风险的执行下去。但这是一种短期效应,无法解决组织本身的创新窘境,长期依赖外部力量来解决最有价值的问题不会让自己提升,反而形成了对外部力量的依赖。对于凝聚组织来说不是一件好事。

只有打破当前的工作习惯和思维定势,充分认识到创新的困难、风险以及价值,才可以占领创新的高点,吸引人才。

难点4:微服务技术栈的“选择困难症”

由于“精英主义”的架构师需要担负很大的责任和压力。他们必须要为微服务架构谨慎的选择技术栈。因此会在不同的技术栈之间不断尝试。对于习惯了在大型研发组织里“精心设计,加班生产 ”的架构师而言。“长设计,慢反馈”节奏似乎是理所应当的。

微服务开源社区的快速发展滋长了“架构师焦虑”:如果采用落后的技术会被同行鄙视,被不懂技术的老板鄙视,甚至被下属鄙视。因此架构师们疲于在各种新型的技术栈之间比较和学习。此外,不熟悉技术往往会增大风险,架构师就需要更多的时间研究。带着“一步到位”的架构幻想对微服务技术栈精挑细选,而不会采用现有低成本的方案快速迭代的解决问题。

微服务的核心在于采用“小规模,快反馈”的机制降低软件系统的复杂性并通过虚拟和自动化技术分散风险,从而及时应对市场变化带来的各种挑战、进行快速销售创新,获得市场的反馈。而不仅仅是利用到了时下新兴的语言,编程框架或工具。

学习和实践是相辅相成的过程,在实践中学习,并把学习到的知识应用到实践中。这不同于准备一场考试:先停下来学习,准备好了再全力以赴。

以上四点会让大型组织在微服务实施中“卡壳”,这往往会导致微服务实施忽略最重要一点,也是我认为也是核心的一点。

难点5:对微服务的技术变革预估过高,而对微服务带来的组织变革预估不足

作为架构师,永远要不要低估康威定理的威力:“设计系统的组织,其产生的设计和架构等价于组织间的沟通结构。”

从制度经济学角度来讲,软件产品本身就是企业内部组织(员工)和外部组织(用户)沟通制度的计算机程序表达。这个制度一定会朝着缩短组织内外部沟通成本的方向发展。

因此,系统架构一定是和组织架构相吻合的,如果不吻合,势必会阻碍组织的渐进。

这就引出了一个推论:如果企业组织的架构不是唯一的,那么微服务的架构方案也不是唯一的。

当架构和组织结构相一致的时候,一切都会很顺畅。反之,就会出现各种问题。

这个关系就像鞋和脚的关系,只有穿上合适的鞋,走起路来才会舒服。过大过小的鞋都无法让你加快前进的步伐。当然,你可以选择买鞋(引入产品),虽然并不是很合脚,但还可以凑合穿,只是在换鞋的时候你不得不停下来试。你也可以花高价为自己定制一套,这个不会让你在短时间内走得更快,只会越来越合脚。

如果所有人穿上了新鞋,都能跑得很快,只有你不能,那么这就不是鞋的问题,而是你脚的问题,这就不是换鞋能解决的了。你得先把脚的问题解决了,然后再看鞋的问题。当然,也可以通过鞋来矫正脚,只不过会花些功夫,但一定会比不停的换鞋更加有效。

很不幸,大多数的组织并没有准备好迎接微服务架构带来的组织变化。仍然把“系统架构问题”和“组织问题”割裂成两个不同领域的问题:微服务是技术问题,组织问题是管理问题。

有竞争力的组织,是能够通过融合优势达到1+1>2效果的组织。而不是把优势割裂开,让1+1<=2的组织。因此,技术问题和管理问题并不是两个问题,而是同一个问题的两个侧面。

因此,如果你的组织结构是去中心化的小团队结构,那么不用担心,你的应用架构会朝组织架构的方向演进。反之,如果你不是一个去中心化的小团队结构,那么微服务的架构会和组织架构格格不入。

如何解决这些问题?

作为微服务的实践者,对微服务不应该是“叶公好龙”,仅仅停留在研讨的层面。而应该采用敏捷和精益的方式迅速开始,在行进中解决碰到的问题。每个组织的组织结构和业务结构都有所不同,微服务实施所面对的挑战也截然不同。在实施的过程中快速学习并改进,没有必要进行周期较长的总体设计。

关于如何解决本文提到的5个问题,请参考下篇《提升微服务实施效率的7个步骤》。


更多精彩内容,请关注微信公众号:软件乌托邦

Share

避免CI成为一个安全隐患

持续集成本身是开发的最佳实践,但如果缺乏安全的意识,一味的追求方便和高效,则会带来很大的安全隐患。通过一些简单而基础的措施和手段,我们就能大大的降低风险。

背景

最近临时交接了一个客户测试环境和产品环境的维护工作。交接的客户资产包含:代码库、生产环境主机、测试环境主机、搭建在测试环境主机上的持续集成服务器以及对应的账号密码。这个持续集成服务器采用Jenkins搭建,并且可以用来部署测试环境和生产环境的应用。

不久,接到了客户的一个维护请求:把最新的生产环境数据同步到测试环境里。

这个维护任务需要通过SSH登录到测试环境主机上进行操作。测试主机是通过authorized_keys进行SSH认证的,只要你自己的ssh-key被添加到了主机上,就可以实现无密码登录。这样有两个好处:一方面维护人员无需使用密码,避免了生产环境密码的泄露。另一方面可以按需吊销不再使用的客户端,及时回收权限。所以我需要把自己的sshpublickey交给管理员,让他把我的key加到可访问列表里。

悲剧的是,前管理员告诉我,他的key因为更换电脑的关系没有及时更新。所以,他也无法登录主机。而且之前参与维护的其它管理员的key也都失效了,这意味着我们失去了对主机的控制。此时,我手上只有登录Jenkins的的用户名和密码,于是一个邪恶的想法就诞生了:

既然Jenkins可以执行脚本,那么我是否可以通过Jenkins把我的key注入进去?

于是我把ExecuteShell的Job变成了我的命令行,通过运行日志得知了宿主用户的文件目录信息。然后把自己的sshpublickey加到了登录列表里(此处省略敏感信息):

sudo sh -c“cp~/.ssh/authorized_keys~/.ssh/authorized_keys.bak”

sudo sh -c"echo‘{我的sshpublickey}’>>~/.ssh/authorized_keys"

It works !

我成功的登录了机器,但这却暴露了一个问题:持续集成服务器成为了一个安全隐患。

首先,持续集成服务器可以执行代码。这就意味着它有可能执行有害代码。

其次,持续集成服务器缺乏足够的用户鉴权,这很有可能导致未授权用户访问。

无权限控制的服务器+可以执行代码=裸奔的肉鸡

那么,如何构建一个更安全的持续集成服务器服务器?

rootless原则

“神操纵着万物,你感觉得到他,但永远看不见他。”——《圣经·希伯来书11:27》

在服务器的世界里,root用户就是神,拥有至高的权力和力量。如果有人获得了“神之力”,后果可能不堪设想。

无论是Web服务器、数据库服务器还是持续集成服务器。都是这个世界里的二等公民,权限和力量都应该受到约束。执行的时候应该受到控制。

此外,应该极力避免sudo的滥用,尤其是对那些从外部访问的用户。很多情况下,为了操作方便,很多用户都有sudo的权限。但这恰恰造成了低权限用户通过提升自己的访问权限进行有害操作。

在上述的故事里,因为没有对Jenkins的主机用户做有效隔离,导致了我可以用sudo注入自己的key获得机器的访问权限。

沙盒隔离原则

因为持续集成服务器会执行脚本或运行程序,而这些程序和脚本有可能是存在恶意代码的。所以,对应的任务应该在隔离的安全沙盒中执行,例如:受限的用户,受限的权限,受限的空间。

在上述的故事里,我就通过CI执行了一段不安全的脚本成功获得了登录主机的权限。

如果这些任务在隔离并受控的Docker容器里执行,那么会安全得多。

当然,也可以考虑采用TravisCI这样的第三方持续集成服务来保证安全性。

备份和备份核查原则

在上述故事里,因为缺乏有效的备份机制,导致了所有人都无法访问主机。此外,我在修改authorized_keys的时候先进行了备份。这样,如果我注入失败,还可以还原。

这里的备份,不光是对配置、数据的备份,还有岗位的备份。

如果管理员有备份,完全不会出现无法登陆的事情。

如果有备份QA服务器,完全可以不需要当前的QA服务器。

在做任何变更前,都应该做好备份以及还原的准备。因为任何变更都会带来“蝴蝶效应”。

但是,光备份是不够的。如果备份不能有效还原,那和没有备份没有什么区别。所以,要定时的进行备份恢复测试。确保备份在各种情况下可用。

多重要素身份验证原则

上述的持续集成服务器是暴露在互联网中的,任何一个人访问到这个站点,通过一定程度的密码破解,就可以获得这个持续集成服务器的访问控制权限。从而可以做出上述的操作。

所以,有了用户名和密码,并不一定是可信用户。还需要通过更多的手段,诸如手机短信验证码或者第三方认证集成来验证用户的身份。

关键操作手动验证原则

试想一下,如果在上述的例子中我并没有服务器的访问权限。而是通过提交未经审查的代码自动运行测试脚本。实际上也会造成同样的效果。

有时候我们会为了方便,让持续集成服务器自动触发测试。但是,恰恰是这种“方便”带来了额外的安全隐患。而这样的方便,不光方便了自己,也方便了恶意入侵者。

所以,不能为了方便而留下安全隐患。在关键操作上设置为手动操作,并通过一定机制保证关键操作的可靠性才是最佳实践。

构建安全CI的几个实践:

采用Sibling的方式在Docker里运行任务。

账户密码管理统一采用LDAP认证,如果过期则从外部修改。

CI的登录权限和其它的认证方式(比如GitHub、Okta等)集成起来。并用组限制登录。

对于生产环境的CI,通过更加细粒度的权限限制来隔离一些危险操作。

官方的安全指南

不少持续集成工具的官方都提供了最佳实践以及安全指南帮助我们构建持续集成服务器。请务必在构建持续集成服务器前阅读并理解这些安全实践和措施,并遵照安全最佳实践构建持续集成服务器:

Jenkins最佳实践:https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Best+Practices

Jenkins官方安全指南:https://wiki.jenkins-ci.org/display/JENKINS/Securing+Jenkins

如果没有这些如果

上面提到了太多的如果。如果这些“如果”能发生在事前,这些问题就不会产生。持续集成本身是开发的最佳实践,但如果缺乏安全的意识,一味的追求方便和高效,则会带来很大的安全隐患。通过一些简单而基础的措施和手段,我们就能大大的降低风险。


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

Share

DevOps发展的9个趋势

DevOps包含了太多方面的技术和实践,很难通过一个统一的工具链来描述其发展。即便如此,我们仍然可以从ThoughtWorks技术雷达的条目变动中看出一些趋势。今年,我有幸作为主编参与了最新一期技术雷达的译制,作为DevOps的爱好者,十分高兴能在这一过程中看到DevOps未来发展的几个趋势,总结成了这篇文章。

DevOps包含了太多方面的技术和实践,很难通过一个统一的工具链来描述其发展。即便如此,我们仍然可以从ThoughtWorks技术雷达的条目变动中看出一些趋势。今年,我有幸作为主编参与了最新一期技术雷达的译制,作为DevOps的爱好者,十分高兴能在这一过程中看到DevOps未来发展的几个趋势,总结成了这篇文章。

趋势1:微服务目前仍然是DevOps技术应用和发展的主要领域

微服务将单块应用系统切割为多个简单独立的应用。从技术上说,这是通过工具把应用程序的内部复杂度转化为外部复杂度,需要一系列工具支撑微服务本身以及服务之间的通信。从组织上说,微服务团队要满足“快速发布,独立部署”的能力,则必须具备DevOps的工作方式。

如何拆解微服务一直是微服务技术应用的最大难点之一,领域驱动设计是比较理想的微服务拆解方法论。社会化代码分析帮助团队通过更精确的数据找到更加合适的拆分点。CodeScene是一个在线服务,它能帮助识别出热点和复杂且难以维护的子系统,通过分析分布式子系统在时间上的耦合发现子系统之间的耦合。此外,它还能帮你认识组织中的康威定律,这会大大降低微服务解耦的难度。

此外,微服务系统本质上是一个分布式系统,分布式系统之间的通信一直是很重要的问题。本期介绍的Kafka StreamsOpenTracing就是这类技术的条目。Kafka作为一个成熟的分布式消息系统已经被广泛采用,而Kafka Streams则将最佳实践以“库”的方式呈现给开发人员,使得操作Kafka更加自然和简单。而OpenTracing则弥补了跨越多个微服务之间请求追踪的空白。

另一方面,无服务器风格的架构(Serverless architecture)把DevOps技术在微服务领域的应用推向极致。当应用程序执行环境的管理被新的编程模型和平台取代后,团队的交付生产率得到了进一步的提升。一方面它免去了很多环境管理的工作,包括设备、网络、主机以及对应的软件和配置工作,使得软件运行时环境更加稳定。另一方面,它大大降低了团队采用DevOps的技术门槛。

然而,端到端交付以及微服务中的函数管理问题日渐突出。尽管AWS API gatewayAWS Lambda几乎成了Serverless架构的代名词,但这二者结合的开发者体验并不佳。于是出现了Serverless frameworkCLAUDIA这样的管理工具。

AWS Lambda带来的优势也深深影响了企业级应用领域,Apache OpenWhisk就是企业级无服务器领域的选择之一,它使得企业级应用也可以采用无服务器风格的架构构建应用程序。

在微服务端到端交付流程上,Netflix开源了自家的Spinnaker,Netflix作为微服务实践的先锋,不断推出新的开源工具来弥补社区中微服务技术和最佳实践的缺失。而Spring Cloud则为开发者提供了一系列工具,以便他们在所熟悉的Spring技术栈下使用这些服务协调技术(coordination techniques),如服务发现、负载均衡、熔断和健康检查。

而在微服务的安全上,最常见的需求之一 是通过身份验证和授权功能来保护服务或API。这部分功能往往是最重要且不断重复构造的。而Keycloak就是一个开源的身份和访问管理解决方案,用于确保应用程序或微服务的安全。且几乎不需要编写代码,开箱即用。它支持单点登录,社交网络登录和标准协议登录(如OpenID Connect,OAuth2和SAML等)。

趋势2:以Docker为核心的数据中心方案逐渐走向成熟

在过去的两年,Docker社区有了突飞猛进的发展,似乎每期技术雷达都会出现Docker相关的条目。而Docker往往和DevOps联系起来,被认为是推动DevOps发展的杀手级工具,以至于有些人会以团队是否采用Docker作为团队是否具备DevOps能力的标志。

而这一社区的创新数量则日渐平缓。一方面,开源社区激烈的竞争淘汰了一部分技术。另一方面,以Docker为中心的完整数据中心解决方案在不断的整合开源社区的零散工具并形成最佳实践。为端到端的开发和运维提供更完整的交付体验,各大厂商也相继开始推广自己的企业级整体收费解决方案,这表明Docker的使用已经走向成熟。

​在本期的技术雷达里的条目中出现了Mesosphere DC/OS,这是构建统一技术栈数据中心的一个征兆。在这方面Docker EERancher都是非常有力的竞争者。根据我的判断,在未来的Docker社区里,统一容器化数据中心的竞争者将会进一步减少。而之前的私有云方案则慢慢会被“以Docker为核心数据中心级全栈交付”取代。

趋势3:不完整的DevOps实践阻碍着DevOps的发展

很遗憾看到单一持续集成实例不完整的持续集成(CI Theatre)这样的条目出现在技术雷达里。可以感到企业应用DevOps技术的紧迫性。这同时也暴露了DevOps领域里“缺乏门槛较低且成熟的技术实践”的问题。

大部分企业在DevOps转型中仅仅关注到了工具的升级。却忽视了价值流、生产流程中各个活动中的最佳实践以及DevOps团队文化的构建,这会使团队陷入“已经完成DevOps转型的假象“,而停止了团队的自我改进。

DevOps的实践包含组织改进和技术升级两个部分,技术往往是最容易的部分。而缺乏组织改进的技术提升往往很难给组织带来质的飞跃。具备DevOps文化的团队则会不断反思和学习,通过共担责任和相互合作不断完善组织的DevOps实践。

趋势4:领域特定的DevOps实践开始出现

DevOps的最早实践来自于互联网企业的Web应用,相应的思想被引入企业级应用并促进了一系列工具的发展。虽然并不是每一种应用软件交付形式都适合DevOps,但随着DevOps的工具不断成熟。其它领域的DevOps实践也开始尝试借鉴Web应用领域的自动化工具,并逐渐形成领域级的DevOps实践。

在人工智能领域,TensorFlow就是这样一个例子,它可以有多种DevOps友好的安装和部署方式 ,例如采用Docker进行部署。

在区块链领域,超级账本(HYPERLEDGER) 就是这样一个例子,它提供了一套工具和服务,结合DevOps相关技术和实践形成了一个完整的解决方案。

随着DevOps相关概念和技术不断向各个产业领域的深入发展,可以看到DevOps技术和实践带来的巨大影响力。然而,每个技术领域都有自己所关注的特性,并不是以往的DevOps实践可以全覆盖到的,这恰恰成为了DevOps技术和实践发展的契机。我很期待领域特定的DevOps技术实践给DevOps带来的发展。

趋势5:采用DevOps进行技术债务重组和技术资产管理

技术债务类似于金融债务,它也会产生利息,这里的利息其实就是指由于鲁莽的设计决策导致需要在未来的开发中付出更多的努力。

投资银行业往往采用多种金融工具组合的方式来处理企业的不良债务。而清理技术债务的实践和工具却乏善可陈。

技术债务不光阻碍了企业通过新技术带来便利,还使企业偿还技术债务所承担的成本越来越高,例如技术人才的流失,技术利息等综合性风险。

虽然极少会出现企业因技术债务而走向衰败的案例,但新晋企业凭借新技术和商业模式颠覆传统行业并夺取市场份额的报道却不断发生。 这从另一方面说明技术债务综合提升了采用新技术的机会成本,使企业不断失去创新和领先的巨大潜力。

DevOps技术栈的多元化为分散遗留系统技术债务风险提供了一套灵活而又低风险的工具和方法论。不断帮助企业从遗留系统的负担中解脱出来。

而微服务则是首先通过领域拆分技术债,并用相应工具重组技术债。分离优质技术资产和不良资产,通过分散风险来降低抛弃成本。 而将API当做产品(APIs as a product)可以从一个全新的演进视角去看待技术债,通过可用性测试和用户体验研究帮企业剥离出技术债务中的优质资产和不良资产。

另一方面,本期技术雷达中出现了封装遗留系统这样的实践,它往往配合着Vagrant,Packer和Docker这样的工具一起使用。一方面它将技术债务的风险进行了隔离,另一方面它防止了遗留系统上产生的技术债利息的增长。

趋势6:安全成为推动DevOps全面发展的重要力量

安全是DevOps永远绕不开的话题,也往往是新技术在传统行业(例如金融和电信)应用中的最大阻碍。一方面,组织结构的转型迫使企业要打破原先的部门墙,这意味着很多原先的控制流程不再适用。另一方面,由于大量的DevOps技术来源于开源社区,缺乏强大技术实力的企业在应用相关技术时不免会有所担忧。

从代码中解耦秘密信息的管理则让我们避开了一些开发过程中可能会产生的安全隐患。采用git-crypt这样的工具可以帮我们保证在开发的过程中源代码内部的信息安全。而采用HashiCorp Vault则提供了脱离应用程序代码的秘密信息存储机制,使得应用在运行过程中的秘密得到了有效保护。

Linux Security Module则一直在技术雷达的“采用”区域,通过SELinux和AppArmor这样的LSM兼容帮助团队评估谁可以访问共享主机上的哪些资源(包括其中 的服务)。这种保守的访问管理方法将帮助团队在其SDLC流程中建立更好的安全性。以往这是Ops团队需要考虑的问题,而对DevOps的团队来说,这是每一个人的事情。

“合规性即代码”(Compliance as Code)是继“基础设施即代码”,“流水线即代码”之后的又一种自动化尝试。InSpec作为合规性即代码的提出者和实现者,通过自动化手段确保服务器在部署后的运维生命周期中依然保持安全与合规。它所带来的意义在于将规范制度代码化,得到了确定性的结果和解释。

在不远的将来,不难想象人们所面对的法律和法规规定不再是一堆会导致歧义的语言文字条目,而是一组由自动化测试构成的测试环境。

安全性和易用性往往被认为是鱼与熊掌不可兼得的两个方面。在DevOps之前,团队吞吐量和系统稳定性指标曾经也面临这样的境遇,然而DevOps使得二者可以兼得。同样我也有信心看到在未来DevOps的领域里,更多易用且安全的工具将会不断出现。在降低DevOps所带来的安全风险的同时,也提升团队开发过程的顺畅性和用户便利性。

趋势7:Windows Server和.NET平台下的DevOps技术潜力巨大

长期以来,Windows和.NET平台下的DevOps一直都是一个被低估的领域。一方面,社区缺乏对 Windows Server平台的兴趣。另一方面,Windows Server却有接近90%的市场占用率,在Web服务器领域则有33.5%的市场占有率

有充足理由证明这是一个潜力巨大的市场。 我们看到了CAKE和FAKE这样的条目,作为.NET平台下替代MSBuild的构建解决方案, 它增强了.NET平台自动化方面的能力。而HANGFIRE则提供了更易用和灵活的自动化进程调度框架。我很期待未来有更多Windows Server和.NET平台领域的创新。不久前,Docker已经可以在Windows下运行。可以预见到,Windows Server和.NET平台将会是下一阶段DevOps技术实践中值得深入发掘的领域。

趋势8:非功能性自动化测试工具的逐渐完备

自动化测试水平往往是衡量DevOps技术能力高低的重要指标,尤其是针对生产环境应用程序的非功能性自动化测试工具。一直以来,技术雷达都在尝试从不同的角度宣扬自动化测试的重要性,从软件的开发阶段延展到了整个应用生命周期甚至整体IT资产的管理上。

这期的技术雷达仍然关注了非功能性自动化测试,TestInfra是ServerSpec的Python实现,它使得用Pytest测试基础设施成为可能。而MOLECULE旨在帮助开发和测试Ansible的Role 。通过在虚拟机或容器上为正在运行的Ansible Role测试构建脚手架,无需再手工创建这些测试环境。正如技术雷达所说的:“虽然这是一个相当年轻的项目,但我们看到了其蕴含的巨大潜力。”

趋势9:Python成为DevOps工作中所不可或缺的语言

早在DevOps刚刚开始盛行的时候,Python就是一个被寄予厚望的语言,因为大部分DevOps工具和实践都需要用到Python。虽然也有人尝试用Ruby或者NodeJS构建DevOps工具,然而都没有Python所构建的工具流行。与此同时,仍然不断有人把其它语言下编写的工具转化为Python的版本,TestInfra就是这样一个例子。

随着Python在大数据、人工智能、区块链、微服务以及Docker中的发展,可以预见Python在日后的领域仍然会发挥重要的作用。

以上对DevOps趋势的解读仅为个人观点,如有不当之处还望指出。关于更多技术在技术雷达中的使用建议请参考这里,谢谢。


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

Share