本文件的是微服务、容器与持续交付【编者的话】就像木炭、火硝和硫磺遇到了一起。当微服务、容器和持续交付遇到了一起,这注定会掀起一场变革。
微服务
如果非要给微服务找一个理由,单一职责就足够了。我们把因相同原因而变化的东西聚合到一起,而把因不同原因而变化的东西分离开。我们称之为单一职责原则SRP。
尤其是大型和长期运营的项目群,随着时间的推移,需求一定是不断增加和变更的。但我们不希望掉进“焦油坑”。我们希望我们的项目群是符合“开闭原则”的。在某个时期我们寄希望于一个统一的“平台”,我们规定项目使用相同的架构和开发语言,使用统一的、集中式的数据库,我们要求平台上的每个项目或者模块高度的“标准化”。在一段时间内“平台”运行的非常良好,一切都在可控范围内。
直到有一些“怪”需求的出现,直到这些“怪”需求,得要一些“怪”技术才能实现。又直一个新的模块被合并到“平台”中需要不眠不休几个晚上,再直到运维的成本突破了“天际”……我们惊醒在《人月神话》的“焦油坑”中。
这道理很简单,耦合的越是紧密的整体,任何一个部分的失败,都是整体的失败。所以我们希望整体中的任何一个部分都和整体是松耦合的。整体中的任何一个部分我们都认为是能力的提供者。整体拥有什么样的能力,是由它聚合了什么样的部分决定的。而非它自己本身的能力。
微服务的理念完美的诠释了这一切。我们希望整体中的每一个部分是这样的:
- 小而自治
一个微服务就是一个SRP的独立个体。根据业务边界来确定服务边界。避免与其他服务共用资源,包括,数据库、进程、IP及端口。服务之间通过标准网络协议进行通信。服务会暴露出API,所有的调用均通过API完成。
- 技术异构
上面我们提到了“怪”需求,比如,大数据分析,分布式实时计算等等。其实需求并不怪,只是要实现这些需求要使用的技术不一定就是一个生态中的技术。又比如,你的团队擅长Java,而他的团队擅长.Net。只要能多快好省的实现功能,只要你的服务最终暴露出来的API是可用的,用什么技术又何妨呢?在要求技术统一的大一统时代这是不可想象的。
- 弹性伸缩
一个整体中总是有一些部分会被频繁的调用,也是压力和瓶颈的所在。我们希望这些部分可以实现弹性伸缩,当运行压力大的时候,这个部分可以被创建多个运行实例,以实现负载均衡。而这如果要在传统的铁板一块的系统中实现,是很笨拙的,因为他的复制是整体的。
- 适应组织结构
由多个团队维护一个耦合性很高的系统是非常困难的。微服务可以很好的将架构与组织结构相匹配。一个微服务由一个小团队独立完成。这也更符合康威定律。
- 简化部署
一个铁板一块的系统,不论是增加一个模块,还是修改一个模块,这都非易事,而且这个整体越庞大,这个过程会越恐怖。试想一个几百万行代码的系统,我只改了一行,现在需要发布,这个场景有多令人头疼。而一个小而自治的微服务,它的一切,包括程序,包括数据库,这些都是只属于它自己的。它的部署既不依赖其它服务,也不影响其他服务。这又证明了松耦合的微服务架构的优势。
- 可复用可组合
在微服务的架构下,应用是面向服务的。服务不再属于某一应用,而是可以为不同的应用提供相应的能力。换言之,若干个微服务的“组合”会“创生”出一个新的应用。
微服务的架构能帮助我们多团队、细粒度、更快速的交付软件。它在技术决策上给了我们极大的自由度,能使我们更快速的响应不可避免的变化。尤其是在当前的云架构下,微服务更是构建PaaS的最佳实践。
容器
利用微服务的思想,我们以业务边界确定服务边界,构建出若干个小而自治的微服务。这不仅解决了团队协作问题,也解决了系统的高耦合、复用、扩展等问题。但部署问题绝不是简单的一个“拆”字能解决的。
不管是你的服务还是应用,部署总归是一个复杂的事情,要考虑的因素太多,比如,硬件环境、操作系统、运行环境、网络、配置等等。在有了虚拟化技术之后这一问题好像有所缓解。我们把操作系统、运行环境、软件等打包成一个VM镜像。需要部署的时候只要启动这个镜像,就完成了部署。
但仍有几个问题难以解决:第一,组装应用或服务的VM镜像仍然不是一件容易的事情,而且很难自动化完成。第二,VM很重,里面有操作系统,在服务和应用需要扩展的时候,启动一个VM就是启动了一个操作系统,这至少是分钟级的。而且操作系统整个成为了应用或服务的“运行框架”,极大的浪费了资源,这就好比用一艘货轮运送一个包裹。我们虽然可以有微服务但是很难“微部署”。
容器技术的发展给我们带来了新的解决方案,以Docker为例。
第一,它非常轻量级。Docker容器也是基于镜像机制。在Docker镜像的底层是一个Linux内核,它远比操作系统要轻量级的多。启动一个容器是秒级的。
第二,一个操作系统上可以运行若干的容器。极大的节约了资源。
第三,容器成为了服务和应用的标准输出,极大的降低了因部署包差异性造成的运维成本。
利用容器技术,可以实现对微服务的“微部署”。进而利用诸如Kubernetes的容器管理平台,实现对容器的治理。不仅实现容器的编排、管理,还是实现了对容器的多集群管理、弹性伸缩等。
把原来的部署和运维的问题,由管理个性化的部署包,变更管理标准化的容器。
持续交付
当微服务遇到了容器,小而自治的服务有了小而自治运行框架。这时候的问题就是如何以最快的速度交付软件,并不断复制这一过程。
利用敏捷的方法,我们缩小了研发的周期,以快速交付可用的版本,持续的优化我们的产品。持续交付是这一过程的重要理论。
在持续交付中,我们试图构建一个“交付生态圈”,将开发、测试、运维、实施以及用户结合成一个整体。我们希望:
- 让软件构建、部署、测试和发布过程对所有人可见,促进合作。
- 有效的反馈,以便在整个过程中,我们能够更早地发现并解决问题。
- 使团队能够通过一个完全自动化的过程在任意环境上部署和发布软件的任意版本。
持续交付关注几个方面:
- 配置管理
配置管理是持续交付的先决条件,配置管理策略将决定如何管理项目中发生的一切变化。它记录了我们的系统以及应用程序的演进过程。更重要的是,也是对团队成员协作方式的管理。
在配置管理中我们以版本管理为手段,管理的内容包括:代码、依赖、配置以及环境。
配置管理的第一要务就是管理代码。只有频繁提交代码到主干你才能享受版本控制带来的众多好处。我们提倡:1)对所有内容进行版本控制2)频繁提交代码到主干3)使用意义明显的提交注释
- 持续集成CI
说到CI,就要说说CI的三个先决条件:版本控制、自动化构建、团队共识。
版本控制上面已经说过,其重要性不用赘述。自动化构建不管是使用TFS还是Jenkins,实现自动化构建不是难事。而在CI中最关键的其实是团队共识,团队共识是CI能够持续运行下去的一个重要条件。比如这些:
- 构建失败之后不要提交新代码
- 提交前在本地运行所有的提交测试,或者让持续集成服务器完成此事
- 等提交测试通过后再继续工作
- 回家之前,构建必须处于成功状态
- 时刻准备着回滚到前一个版本
- 在回滚之前要规定一个修复时间
- 为自己导致的问题负责
- 测试驱动开发
- 测试
将各种测试手段和方法结合到持续交付的各个环节中,是保证交付软件质量的重要环节。这里我们推崇TDD的方式,从软件的设计阶段就将测试考虑进来:
- 客户、分析师和测试人员定义验收条件
- 测试人员和开发人员一起基于验收条件实现验收测试的自动化
- 开发人员编码来满足验收条件
- 只要自动化测试失败,无论是单元测试、组件测试还是验收测试,开发人员都应该把它定为高优先级并修复它。
不论是单元测试、功能性测试、性能测试还是非功能性测试。绝不是在开发完成之后才开始考虑的。
对于测试,持续交付依然是推崇先立规矩再选工具。
在持续交付中,我们希望构建一个平衡的状态。在分支版本上进行开发,完成后合并入主干版本。利用CI,主干版本可以每日构建并发布到测试环境,期间以自动化的单元测试、功能测试、性能测试工具进行测试。发现问题及时回滚版本并进行反馈。构建的过程不单单是代码的编译,还包括依赖、配置以及环境。当构建和测试完成并通过后,按计划将标准的部署包发布到生产环境。在整个这一过程中,所有项目的干系人都将是持续交付团队的成员。
当持续交付遇到容器的时候,这一切又变得更为完美了。首先是配置管理环节中最为复杂的环境管理和依赖管理一下子就变得单纯了。首先由于容器对各种环境的隔离和封装,使我们在持续交付中可以更关注代码本身的版本控制。其次,微服务对整体的解耦可以大大降低依赖管理中对其他服务依赖,从而减轻了持续交付中依赖管理的难度。甚至如果你拥有一个PaaS,那么这个话题就完全可以抛给“服务治理”这个命题。
我们再来看,当微服务、容器和持续交付相遇的时候。容器使得微服务得以“微部署”。持续交付的整个理念又保证了微服务的交付速度与质量。而容器和微服务又使得持续交付变得单纯和可控。
微服务、容器和持续交付的相遇,云时代的一场变革!
原文链接:微服务、容器与持续交付(作者:刘玉龙)
原文发布时间为:2016-09-14
本文作者:刘玉龙
原文标题:微服务、容器与持续交付