书名:企业级云原生架构:技术、服务与实践
ISBN:978-7-115-55174-0
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
著 刘景应(四牛)
责任编辑 武晓燕
人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书较为全面、系统地介绍了云原生架构相关的方法论与技术产品,并结合作者多年的大型项目建设实施经验,阐述了分布式环境下面向云原生的架构设计最佳实践。本书主要分为4个部分,分别是云原生概述、云原生技术、云原生服务、云原生架构实践。本书兼顾理论、技术与实践,对从事相关行业的读者具有很好的学习指导意义。
本书面向的读者对象为互联网行业的业务咨询师、系统架构师,以及相关领域的技术开发人员。
信息技术的发展日新月异。云原生(cloud native)的概念自2015年提出,迅速得到主流互联网公司和技术开发人员的支持,相关社区也非常活跃。云原生是一整套综合的技术体系,包括方法论和各个领域的技术产品。但目前市场上介绍云原生技术及其相关产品的图书非常匮乏。市面上这类图书大多只是介绍某一特定技术或其产品。
随着云计算作为一项国家基础建设战略向纵深发展,越来越多的企业把核心应用系统部署在云上。为更好地发挥云的价值,企业应用正经历从云托管(cloud hosting)到云原生的架构演进过程。顾名思义,云原生是面向“云”而设计的应用,而不仅仅是简单地把应用部署在云上的虚拟机或容器之中。云原生应用系统针对云的分布式、去中心化、一切资源服务化、弹性、快速迭代等特点,对应用系统进行完整的重构。云原生充分利用云基础设施的弹性和云资源服务的便捷性,可以为企业构建灵活多变、稳定可靠的在线业务系统。云原生正在通过方法论、工具集和理念重塑整个软件技术栈和生命周期,帮助企业和开发者在云上构建和运行可弹性扩展、容错性好、易于管理、便于观察的系统。有了诸多标准化的产品技术,企业上云的拐点已经到来,云原生已经成为企业共享云计算技术红利的便捷方法之一。
本书具有以下几个特色。
(1)技术全面覆盖。云原生涉及的技术领域非常多。CNCF生态蓝图就把目前云原生生态的参与者根据其提供的产品及服务,分为8个主要的方向,涉及技术产品达到数百个之多。本书虽无法涵盖云原生全部的技术产品,但针对IaaS、DaaS、PaaS不同技术领域核心主流的产品均有涉猎,让读者对云原生相关技术有一个相对完整的概念。
(2)内容深入浅出。本书在介绍云原生相关技术产品时,力求深入浅出,不仅有偏方法论的理论概述,也有技术原理的深入分析,让读者对这些技术产品知其然,更知其所以然。
(3)紧贴技术趋势。从技术发展的趋势,本书完整地介绍了企业应用架构的演进过程。从单体架构、分布式架构、SOA、微服务架构、Service Mesh架构、Serverless架构,讲述了不同架构的技术特点以及应用场景,让读者不仅了解企业应用架构的发展过程,还能紧紧把握当前主流的技术发展趋势。
(4)结构层次递进。按云分层的层次结构,自底向上地介绍云基础设施服务、数据资源服务、中间件服务等不同层次的产品及其技术,让读者的思维跟随本书所介绍的知识体系,逐步勾勒出企业应用系统技术架构的框图。
(5)理论与实践并重。本书融入了作者20年软件开发及架构设计的工作经验,分析和对比了各种技术产品的优缺点、适用场景,其中绝大部分产品及服务在实际应用系统开发过程中会用到,因此,本书具有很好的实践指导意义。本书第四部分还重点介绍了在一个大型分布式应用系统开发过程中所面临的高可用、数据一致性、容灾多活等3个方面的设计原则及解决方案。这些解决方案会综合使用前面章节介绍的技术及产品,让读者思考如何用技术产品及架构设计来应对现实系统所面临的问题和挑战。
本书内容涵盖云原生相关的技术、服务与实践,分为4个主要的部分,共计12章。
第1章初见云原生,介绍云原生的起源、云原生架构的特点。
第2章企业应用架构演进,介绍企业IT系统应用架构的演进过程。
第3章Docker,介绍容器技术的发展过程、Docker的技术原理。
第4章Kubernetes,介绍Kubernetes的系统架构、运行原理以及核心的技术组件。
第5章Prometheus,介绍Prometheus监控系统的组成及其架构。
第6章微服务,介绍微服务架构的特点、设计原则以及当前主流的微服务框架。
第7章云原生IaaS服务,介绍云原生基础设施服务,包括容器、镜像仓库、存储和网络。
第8章云原生DaaS服务,介绍云原生数据资源服务,包括数据库、对象存储、日志、消息队列、大数据等服务。
第9章云原生PaaS服务,介绍云原生中间件相关服务,包括分布式应用服务、配置中心、分布式数据库中间件、定时任务、业务实时监控、服务网关以及相关技术的组件的服务。
第10章高可用解决方案,介绍分布式实时在线应用系统如何实现7×24小时业务连续性高可用服务。
第11章数据一致性解决方案,介绍数据一致性的理论、实现原则以及在分布式环境下如何实现数据的一致性。
第12章容灾多活解决方案,介绍同城双活、两地三中心、异地双活、单元化多活等几种容灾多活实现方案的技术原理。
写书是一项极其琐碎、繁重的工作。云原生的技术还在不断发展完善之中,尽管本书作者已经竭力使本书和网络支持接近完美,但仍然可能存在很多漏洞和瑕疵。欢迎读者提供关于本书的反馈意见,帮助我们改进和提高,从而帮助更多的读者。如果你对本书有任何评论和建议,或者遇到问题需要帮助,欢迎致信作者邮箱liujy001@gmail.com,我们将不胜感激,并尽可能回复。
本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。
作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。
当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,点击“提交勘误”,输入勘误信息,点击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。
我们的联系邮箱是contact@epubit.com.cn。
如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。
如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/selfpublish/submission即可)。
如果您来自学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。
如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。
“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。
“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近 30 年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。
异步社区
微信服务号
第1章 初见云原生
第2章 企业应用架构演进
云原生是一种软件开发方法,它充分利用了云计算,使用开源软件技术栈将应用程序部署为微服务。通常,云原生应用程序构建为在Docker容器中运行的一组微服务,在Kubernetes中编排,并使用DevOps和Git Ops工作流进行管理和部署。使用Docker容器的优点是能够将执行所需的所有软件及环境配置打包到一个可执行包中。容器在虚拟化环境中运行,从而将包含的应用程序与其环境隔离。
——维基百科“Cloud Native”
信息技术的发展日新月异,过去几十年,企业IT架构经历了单体架构、分布式架构和云计算架构3个阶段的技术演进。尤其是云计算技术的发展,让企业的整个IT基础设施以及应用运行模式发生了革命性的改变。云时代的第一个十年,作为技术的创新探索先锋,互联网公司引领了云计算技术的发展趋势,大多数互联网应用从诞生之初就生长在云端。随着云计算技术的成熟,以及以移动互联网为特点的创新业务的驱动,很多传统行业(如金融、零售、能源、制造以及政务等领域)的企业和机构也逐渐将各自的业务从互联网数据中心(Internet Data Center,IDC)机房迁移至云上,充分利用云的弹性优势,实现系统的动态伸缩与业务的创新。
企业应用上云,也经历了从云托管到云原生的架构演进过程。上云初始阶段,多数企业仅仅是把应用从传统的IDC机房搬迁到云上的虚拟机,这是云托管模式,或者叫作基础设施即服务(Infrastructure as a Service,IaaS)上云。但要真正用好云,不仅是基础设施和平台的升级,应用也需要摒弃传统的设计方法,从架构设计、开发方式到部署维护的整个软件生命周期管理,都要基于云的特点进行重构,从而构建“原生为云”而设计的应用,这样才能在云上以最优的架构、最佳的模式运行,并充分利用和发挥云平台的弹性以及分布式优势。采用基于云原生的技术和管理方法,可以更好地把业务生于“云”或迁移到云平台,从而享受“云”的高效和持续的服务能力。作为诞生于云计算时代的新技术理念,云原生拥有传统IT无法比拟的优势,可帮助企业高效享受云的弹性和灵活性,以服务化的形态获取各种资源,降低大规模分布式高并发的技术门槛,从而实现快速开发、平滑迁移、稳定可靠、运维简便的应用构建模式。云原生已经成为云时代的新技术标准。
云原生的概念最早是谁提出的,业界并没有统一的说法。比较有影响力的是Pivotal(Spring开源产品的母公司)的技术产品经理 Matt Stine,他在2015年发表的电子书Migrating to Cloud Native Application Architectures(《迁移到云原生应用架构》)中,提出了将传统的单体应用和面向服务的架构(Service-Oriented Architecture,SOA)应用迁移到云原生架构所需的文化、组织和技术变革。Matt Stine认为云原生是一组思想集合和最佳实践,包括敏捷基础设施(agile infrastructure)、微服务(microservice)、DevOps、持续交付(continuous delivery)等,主要涵盖如下重要的内容。
(1)十二要素应用程序:云原生应用程序架构模式的集合。
(2)微服务:独立部署的服务,每个服务只做一件事情。
(3)敏捷基础设施:快速、可重复和一致地提供应用环境和后台服务的平台。
(4)基于应用程序接口(Application Programming Interface,API)的协作:发布和版本化的API,允许在云原生应用程序架构中的服务之间进行交互。
(5)抗压性:系统具备良好的健壮性,能够抵抗外界非预期的流量冲击。
从狭义上来讲,云原生包含以容器、微服务、持续集成和持续发布(Continuous Integration/ Continuous Delivery,CI/CD)为代表的云原生技术,使用一种全新的方式来构建、部署、运维应用。它不但可以很好地支持互联网应用,也在深刻影响着新的IT技术架构和应用架构。
从广义上来讲,云原生完全基于分布式云架构来设计开发应用系统,是全面使用云服务的构建软件。随着云计算技术的不断发展和丰富,很多用户对云的使用,不再是早期简单地租用云厂商基础设施(计算、存储、网络)等IaaS资源。
云原生是当前炙手可热且不断发展的技术方向,其定义也会在日后不断演进。据IDC的市场研究数据和报告,截至2019年,超过三成的企业使用了包含 Docker 在内的容器技术,50%以上的企业认为运维自动化和弹性扩容是容器技术的主要应用场景。Gartner报告指出,到2022年,75%的全球化企业将在生产环境中使用云原生的容器化应用。
云的核心理念是弹性,站在云的视角,过去我们常以虚拟化作为云平台和与客户系统交互的界面,为企业带来灵活性的同时也带来了一定的管理复杂度。容器的出现,在虚拟化的基础上向上封装了一层,逐步成为云平台和与客户系统交互的新界面之一,应用的构建、分发和交付得以在这个层面上实现标准化,大幅降低了企业 IT 实施和运维成本,提升了业务创新的效率。从技术发展的角度看:开源让云计算变得越来越标准化,容器已经成为企业应用分发和交付的标准,可以将应用与底层运行环境解耦;Kubernetes成为资源调度和编排的标准,屏蔽了底层架构的差异性,帮助应用平滑运行在不同的基础设施上;在此基础上建立上层应用抽象(如微服务和服务网格),逐步形成应用架构现代化演进的标准,开发者只需要关注自身的业务逻辑,无须关注底层实现。云原生正在通过方法论、工具集和理念重塑整个软件技术栈和生命周期,帮助企业和开发者在云上构建和运行可弹性扩展、容错性好、易于管理、便于观察的系统。有了诸多标准化的产品技术,企业上云的拐点已经到来,云原生已经成为释放云价值的最短路径之一。
云并非把原先在物理服务器上运行的东西放到虚拟机里运行,真正的云化不仅是基础设施和平台的事情,应用也要改变传统的做法,实现云化的应用——应用的架构、应用的开发方式、应用部署和维护技术等都要做出改变,真正发挥云的弹性、动态调度、自动伸缩等一些传统IT所不具备的能力。这里说的“云化的应用”也就是“云原生应用”。云原生架构和云原生应用所涉及的技术很多,如容器技术、微服务、可持续交付、DevOps等。
PC的普及,改变了人们加工处理个人数据的方式;移动互联网的普及,改变了人们获取信息的方式;即将到来的万物互联的时代,改变了人们与周围世界的交互方式。随着业务的发展,企业IT架构也随之发生巨大变化,而业务又深度依赖IT能力。
IT系统让人们的工作和生活越来越简单便捷的同时,其自身的架构却变得越来越复杂。随着技术的发展,业务规模的暴增,商业模式的创新,企业的应用系统也经历了单体应用、应用分层、分布式应用、云应用等不同应用形态。原来一个系统由一个团队就可以开发维护,慢慢发展到一个系统由数十个应用构成,需要几十个团队相互协作,甚至像淘宝、天猫这样的巨型系统,需要上千个应用,由几百个团队开发维护。微服务架构能够解决大型分布式系统的团队协作问题,每个团队独立负责一个或者若干个服务,团队对于所负责的服务拥有绝对的决策权,以减少组织的技术决策成本。服务之间通过契约化的接口以缩小沟通范围,只要接口不变,就无须关注外部的变化,从而减少组织的技术沟通成本。
在微服务架构中,应用的数量大幅增加,性能、一致性等问题越来越严重,架构变得越来越复杂,大量服务的治理也变得充满挑战,如何处理和解决这些问题?正如人类社会发展伴随着技术革命与社会大分工一样,云原生技术的出现解耦了很多复杂性,这是IT技术的进步。
(1)以Docker为代表的容器技术实现了应用与运行环境的解耦,众多业务应用负载可以被容器化,而且应用容器化满足了敏捷、可迁移、标准化的需求。
(2)Kubernetes的出现实现了资源编排调度与底层基础设施的解耦,应用和资源的管控也开始得心应手,容器编排实现资源编排、高效调度。
(3)以Istio为代表的服务网格技术实现了服务实现与服务治理能力的解耦。
业务的发展能驱动技术的进步,技术的进步又反哺业务创新。云原生概念及技术提出几年以来,得到众多软件厂商以及云厂商的参与支持,他们也在纷纷贡献自己的产品与技术,绝大多数云厂商提供了容器、Kubernetes编排管理的OpenAPI、软件开发工具包(Software Development Kit,SDK)等丰富的开发工具,实现第三方被集成,为云的生态伙伴提供更多的可能性。这样的技术分层推动了社会分工,极大促进了云原生技术和云原生生态的发展。
互联网(尤其移动互联网)的蓬勃发展提高了业务的推广速度,云产品以及服务大幅降低了海量数据与高并发的技术门槛,二者共同作用,使业务的创新速度达到了前所未有的程度。每天有无数的新App产生。一个App从最初上线到日活跃用户过十万、百万、千万,可能只需要短短几个月的时间。我们正处在一个业务快速增长的时代,产品既需要更快的交付速度以便验证业务可行性,又需要更好的用户体验以便在众多的App中脱颖而出。这也是传统企业竞争不过互联网公司的原因。其中一个重要的因素是产品的进化速度太慢,不能根据用户的反馈快速迭代。当某个功能用户使用频率比较高时,产品的发展方向可能会随时发生转变,需要不断在市场中调整和演进产品的发展路线。万众创业的时代机会转瞬即逝,如果不能在第一时间抓住市场的热点,企业很快就会被市场淘汰。有研究数据表明:中国互联网企业的平均生命周期普遍在3~5年。“3年”成为划分一个企业生命周期的分界线。
产品交付速度的提高不能以降低可用性为代价。我们知道,变更是可用性的“天敌”,以阿里巴巴为例,有统计数据表明,超过50%的线上故障是变更引起的,也正因如此,每逢重要的节假日或者大促活动节点,我们都会进行“封网”,以确保线上系统的稳定和可靠。当然这也是目前技术不够成熟,不得已而为之的折中和让步。就像目前很多传统企业的线上管理策略,提升可用性的一种方法就是少发布、多审核,这显然是和快速试错、快速交付、快速迭代的互联网思想背道而驰的。在传统行业中,企业的应用系统一般是有一个工作时间的,应用的发布和变更会选择在非工作时间进行。但在互联网行业中,尤其在全球化背景下,我们要求应用系统具有7×24小时不间断的在线服务能力,不存在非工作时间,甚至不存在业务低峰期,这就对企业的应用系统运维提出了更高的要求。云计算已经重塑了软件的整个生命周期,从架构设计到开发,再到构建、交付和运维等所有环节。云原生通过一系列产品、工具、方法减少变更导致的可用性问题,而不是因噎废食地控制变更、减少发布次数。
互联网公司经常提到他们每天实现几十次,甚至上百次的发布。为什么频繁发布如此重要?如果你可以每天实现上百次发布,那么你就可以几乎立即从错误的版本中恢复过来;如果你可以立即从错误中恢复过来,那么你就能够承受更多的风险;如果你可以承受更多的风险,那么你就可以做更“疯狂”的试验——这些试验结果可能会成为你接下来的竞争优势。
云最主要的特性之一就是弹性,这也是企业应用上云最核心的需求。随着移动互联网的普及,以及网红经济、热门事件营销、秒杀大促等商业模式的推陈出新,企业的业务流量变得无法预估。当然,为了应对突发流量的冲击,企业也可以购买更多更高规格的服务器;但对于绝大部分业务平峰期以及低峰期, CPU都是空闲的,这会让资源使用率指标很低。通过云的弹性伸缩,可以应对业务突发流量的冲击,保证业务的平稳运行,提高资源利用率,降低IT运营成本。
随着企业的应用系统进行分布式改造,应用由一个单体应用被分割为众多的微服务应用,整个应用集群的节点数由原来的数十个快速上升到了数百以至上千个,垂直拆分带来良好隔离性的同时,也使资源的利用率大幅下降。互联网公司通过以下两个开创性的举措来解决这个问题。
(1)不再继续购买更大型的服务器,取而代之的是用大量更便宜机器来水平扩展应用实例。这些机器更容易获得,并且能够快速部署。
(2)将大型服务器虚拟化成几个较小的服务器,并向其部署多个隔离的工作负载,从而改善现有大型服务器的资源利用率。
纵观IT应用服务器的发展历史:大型机→小型机→x86服务器→虚拟机→容器→Serverless,越来越朝着轻量化的方向发展,这也符合云原生敏捷基础设施的策略。轻量化意味着更好的弹性,应用部署时间相应减少:月(大型机)→天(小型机)→小时(x86服务器)→分钟(虚拟机)→秒(容器)→毫秒(Serverless)。极致的弹性是企业解决业务不确定性的有效手段。
云原生的核心技术之一是容器。容器技术的兴起源于2013年开源的Docker。容器的价值可以从下面两个层面阐述。
(1)从应用架构层面,容器技术可以方便地支持微服务架构实现应用的无状态化,更加灵活地应对变化和弹性扩展。在软件生命周期管理方面,容器技术可以帮助把DevOps等最佳实践落地成可运用的标准化工具和框架,大大提升开发效率,加速迭代。DevOps的概念最早起源于2009年的欧洲(更早的20世纪90年代提出的柔性生产模式中也有DevOps的思想),但一直不温不火,直到Docker容器技术的流行,最近几年DevOps才为人们所津津乐道。
(2)从基础架构层面,容器技术带来的可移植性,可以帮助开发者和企业更便捷地上云和迁云,让应用在自有数据中心和云端实现动态迁移。随着容器技术和云计算的计算、存储、网络的进一步融合,更快速地推动从传统以基础设施为中心,向以应用为中心的IT架构转变。
容器解决了应用与运行环境的解耦,把运行环境也作为一种资源支持可编程式的管理;Kubernetes的出现则让资源的动态编排与管理变得更加简单,充分满足业务不确定对资源的弹性要求。
综上所述,云原生不是一个产品,而是一套技术体系和一套方法论。企业数字化转型是思想先行,从内到外的整体变革,更确切地说,它是一种文化,更是一种潮流,是企业云计算战略的必然导向。
顾名思义,云原生是面向“云”而设计的应用,但要给云原生下一个明确的定义很难,所有的架构的目标都是解决特定的业务场景。一方面,业务场景千变万化,而每个人的技术背景不同,站的角度不同,所理解和设计的系统架构也就各不相同。另一方面,架构总是不断演进的,新的技术层出不穷,因此云原生的落地形式与能力边界也在不断演进中。
换一个思路,云原生所倡导的思想与设计原则,或许能更好地让大家理解什么是云原生,云原生具体解决哪一类问题。
中心化意味着单点,为了具备良好的线性扩展能力,分布式系统要求去中心化,避免单点故障。对于系统的服务能力,随着资源加入,微服务的性能和容量能够呈线性扩展。在微服务场景下,每个服务可以独立采用自己的技术方案或技术栈,每个微服务应用独立部署,服务之间进程隔离,每个服务都有独立的数据库,一个服务实例的失效不会导致大规模的故障。这也是微服务架构和SOA非常重要的区别之一。SOA一般有一个中心化的企业服务总线(Enterprise Service Bus,ESB)负责所有服务的注册发现以及调用路由;微服务架构虽然也有一个服务注册中心,但服务注册中心只负责应用启动或者状态变更时做服务推送,真正在运行过程中微服务之间的相互调用都是点对点直接调用,即运行时是去中心化的。
另外,从研发流程的角度来说,去中心化意味着关注点分离。云原生对开发团队一个很重要的要求是独立自主,每个服务由独立的团队负责开发运维,所有者的团队对服务具有决策权,可以自主选择技术栈以及研发进度,服务之间只要接口不变,外部就不必对其过度关注,更容易实现关注点分离。
(1)实现的松耦合:这是基本的松耦合,即服务消费端不需要依赖服务契约的某个特定实现,这样服务提供端的内部变更就不会影响消费端,而且消费端未来还可以自由切换到该契约的其他服务提供方。
(2)时间的松耦合:典型的是异步消息队列系统,由于有中介者(broker),因此生产者和消费者不必在同一时间都保持可用性以及相同的吞吐量,而且生产者也不需要马上等到回复。
(3)位置的松耦合:典型的是服务注册中心,消费端完全不需要直接知道提供服务端的具体位置,而都通过注册中心查找服务来访问。
(4)版本的松耦合:消费端不需要依赖服务契约的某个特定版本来工作,这就要求服务的契约在升级时要尽可能地提供向下兼容性。
为了保证系统的健壮性,软件设计领域中一个很重要的原则是,所有的外部输入和外部依赖都是不可信的,系统间依赖的调用随时可能会失败,也包括硬件基础设施服务随时可能死机,还有后端有状态服务的系统能力可能有瓶颈。总之在发生异常时能够快速失败,然后快速恢复,以保证业务永远在线,不能让业务半死不活地僵持着。
面向失败设计(design for failure),意味着所有的外部调用都有容错处理,我们希望失败的结果是我们可预期的、经过设计的。在微服务架构场景中,当服务数量越来越多,依赖越来越复杂时,出现问题的概率也就越大,问题定位也会越来越困难,这时再用传统的解决办法将是一个灾难。传统的方法通常是通过重试、补偿等手段尽可能避免失败,微服务架构下由于存在更多的远程调用,任何外部依赖都有可能失效或延迟,这是潜在的故障和瓶颈。故障总是无法避免的,设计的目标是预测和解决这些故障。因此在设计服务时,应充分考虑异常情况,从使用者的角度出发,能够容忍故障的发生,最小化故障的影响范围。系统架构设计时需要考虑到应用系统的每一个层面,包括硬件和软件是可能出现故障的,并据此在应用系统架构设计上消除单一故障点,从而实现高可用性(High Availability,HA)的系统架构。
云原生的应用服务设计尽可能是无状态的,使得业务天生具有扩展性,在业务流量高峰和低峰时期,依赖云的特性自动弹性扩容、缩容,满足业务需求。无状态指的是服务在处理请求时,不依赖除请求本身以外的其他内容,也不会有除响应请求之外的额外操作。这样如果要实现无状态服务的并行横向扩展,只需要对服务节点进行并行扩展,在服务之上添加一个负载均衡。
将“有状态”的业务处理过程改造成“无状态”的过程,思路比较简单,主要有以下两种手段。
(1)状态分离:服务端所有的状态信息统一保存在外部独立的分布式存储中(如缓存、消息队列、数据库)。
(2)请求附带全部状态信息:将状态信息前置,丰富请求的入参,将需要处理的数据尽可能都通过上游的客户端放到入参中传过来。
容器技术带来的最大优势,是通过镜像实现了可编程式的运行环境定义,从而实现了应用与运行环境的解耦。作为一种服务(IaaS),云原生基础设施提供可编程式的需求描述,并实现记录版本变更,保证环境的一致性。使用软件工程中的原则、实践和工具来加强基础设施服务的生命周期管理,这意味着开发人员可以更频繁地构建更强可控或更稳定的基础设施。对资源调度而言,我们希望所有的服务(包括环境)无差异化配置,实现标准化可迁移,而不希望在部署任何服务的过程中还需要手动操作,因为手动操作是无法批量化、自动化执行的,也是不容易回溯的。
实现不变性原则的前提是,基础设施中的每个服务、组件都可以自动安装、部署,不需要人工干预。所有的资源都可以随时拉起、随时释放,同时以API的方式提供弹性、按需的计算、存储能力。每个服务或者组件在安装部署完成后将不会发生更改,如果要更改,就丢弃老的服务或组件,并重新部署一个服务或组件。另外,为了提升可用性,我们应该尽量减少故障修复时间,要知道替换的速度远远快于修复的速度。
为了满足业务需求的频繁变动,通过快速迭代,产品能做到随时可发布,这是一系列开发实践方法。自动化驱动分为持续集成、持续部署、持续交付等阶段,用来确保需求的提出、设计开发测试,再到代码快速、安全地部署到生产环境中。持续集成是指每当开发人员提交了一次改动,就立刻进行构建、自动化测试,确保业务应用和服务均能符合预期,从而可以确定新代码和原有代码能否正确地集成在一起。持续部署是指使用完全的自动化过程把每个变更自动提交到测试环境中,触发自动化测试用例,测试验证通过后将应用安全地部署到生产环境中,打通开发、测试、生产等各个环节。持续交付是软件发布的能力,在持续集成完成后,能够提供到预发布之类的环境上,满足生产环境的条件。
应用系统的部署与运维的成本会随着服务的增多呈指数级增长,每个服务都需要部署、监控、日志分析等运维工作,成本会显著升高。在服务划分之前,应该首先构建自动化的工具及环境,开发、测试人员应该以自动化为驱动力,简化服务在创建、开发、测试、部署、运维上的重复性工作,尽可能通过自动化工具完成所有重复的工作。当提交代码后,自动化的工具链自动编译、构建、测试、集成。开发人员持续优化代码,当满足上线要求时,自动化部署到生产环境中。这种自动化的方式能够实现更可靠的操作,既避免了人为失误,又避免了微服务数量增多带来的开发、运维、管理的复杂化。
云原生架构是“原生为云”而设计的应用架构,因此技术部分依赖于在传统云计算的3层概念:基础设施即服务(Infrastructure as a Service,IaaS)、平台即服务(Platform as a Service,PaaS)和软件即服务(Software as a Service,SaaS),如图1-1所示。云原生架构意味着更快的迭代速度、持续可用的服务、弹性伸缩及其他一些非功能特性,包括快速试错以支持产品创新的技术挑战、以用户体验为中心的交互模式挑战、移动互联网时代的流量激增挑战等。
“架构”作为软件行业中一直存在的一个名称被普遍使用。架构一词原本来源于建筑行业,包括过程和产品,并且包括计划、设计、构建等全生命周期的过程。云原生架构包括一系列过程和方法,充分利用了云计算的弹性和分布式协同,使用开源软件技术栈将应用程序部署为微服务。通常,云原生应用程序构建为在Docker容器中运行的一组微服务,在Kubernetes中编排,并使用DevOps和Git Ops工作流进行部署和管理。使用Docker容器的优点是能够将执行所需的所有软件打包到一个可执行包中。容器在虚拟化环境中运行,从而将包含的应用程序与其环境隔离。云原生架构是一种包含技术实现与管理(组织流程)的软件开发方法论。技术实现部分主要包括敏捷基础设施、云公共基础服务和微服务;组织流程部分主要包括持续交付和DevOps。云原生应用架构包含3个特征:容器化、微服务和DevOps。
▲图1-1 云原生架构的内容
不管是传统应用,还是云原生应用,打包好的部署包(jar、war、镜像)最终都要部署在应用服务器上运行,应用服务器越来越朝着轻量化的方向发展(如图1-2所示),轻量化意味着更好的弹性、更短的启动时间。
▲图1-2 轻量化的IT应用服务器发展趋势
作为云原生应用的底座,敏捷基础设施主要为了解决传统基础设施所面临的挑战,包括以下几个方面。
(1)资源利用率低。传统基础设施的应用服务器一般由小型机、x86服务器、虚拟机等组成,因为缺乏弹性伸缩能力,所以为了确保业务的平稳运行,IT部门一般会按业务高峰期的流量并加上一定的富余,以此作为预估策略来配置服务器资源。然而业务高峰期可能只存在很短的时间,大部分业务平峰期或者业务低峰期期间,机器资源的利用率是非常低的,造成了资源浪费。
(2)资源扩容周期长。新业务上线或者已有业务规模变大时,为了确保业务的隔离,一般无法共享已有的服务器资源,需要采购新服务器,一般会在企业内部走层层审批流程,采购部署的周期长,效率低下。云带给开发运维人员最直观的感受就是不需要每年做大量的资源规划了,大家可以共享一个资源池。
(3)服务器数量暴增。由于微服务等应用架构的实施,单体架构下的服务器被拆分为虚拟机或容器,导致需要管理的节点数呈爆发性增长,传统的IT运维管理方式面临巨大的挑战。当应用节点个数达到成千上万的规模时,靠传统的单个节点监控运维的方式基本是不现实的,需要自动化批量化的工具来统一管理。
(4)缺乏标准化。开发、测试、生产等不同环境的配置靠人工维护,人为误操作的风险使线上变更引发故障的可能性大大增加(根据墨菲定律,可能出错的事总会出错),“人工操作”是不可靠的,尽可能把应用构建、环境准备、应用部署等过程标准化,通过工具自动化地完成。
正如通过业务代码能够实现产品需求、通过版本化的管理能够保证业务的快速变更一样,基于云原生的开发模式也要考虑如何保证基础资源的提供能够以可编程的方式自动实现需求,并实现记录变更,保证环境的一致性。容器技术真正实现了IaaS的理念落地。通过Dockerfile显式声明定义软件的运行环境,开发人员可以直接将所有的软件和依赖直接封装到容器中,打包成镜像,将应用和运行环境做到很好的统一。通过容器实现开发、测试、生产环境的一致,实现一次编写、到处部署的能力。
基础设施可以将基础设施配置完全当作程序代码来进行,这样做是为了提高效率,因为在整个研发交付环节中,人与人(特别是不同岗位角色的人)之间的沟通是非常浪费时间的,参与沟通的人越少,效率越高。可编程式基础设施可以让一个全栈工程师在没有运维人员参与的情况下,申请生产环境的资源,自动化配置、部署应用。
可编程式基础设施,也意味着开发人员可以更频繁地构建更强可控或更稳定的基础设施,无须运维人员参与,开发人员可以随时拉取一套基础设施来服务于开发、测试、联调和灰度上线等需求。当然,同时要求业务开发具有较好的架构设计,不需要依赖本地数据进行持久化,所有的资源都可以随时拉起、随时释放,同时以API的方式提供弹性、按需的计算和存储能力。这样做的好处是流程简单,速度比以前更快,而且摒弃了烦琐的人工操作。运维人员和开发人员一起以资源配置的应用代码为中心,不再是一台台机器;一切都可以通过工具(DevOps工具)完成,形成标准化变得更容易,比人工操作更可靠。
除了提供计算能力的容器,云环境下的其他基础设施资源(如存储、网络)可以以服务化(如OpenAPI)的方式提供资源申请和管理能力。
微服务架构是云原生架构的核心构成。随着企业的业务发展,传统的单体架构和分层架构面临着很多挑战。
(1)单体架构在需求越来越多时无法满足其变更要求,数百人的开发团队一起开发维护一个巨型应用工程,开发人员对大量代码的变更会越来越困难,同时也无法很好地评估风险,所以迭代速度慢。
(2)所有的应用都运行在一个进程内,无法隔离,经常会因为某处业务的瓶颈导致整个系统业务瘫痪,架构无法扩展,木桶效应显著,无法满足业务的可用性要求。
(3)整体组织效率低下,无法很好地利用资源,存在大量的浪费。
因此,组织迫切需要进行变革。随着大量开源技术的成熟和云计算的发展,服务化的改造应运而生,不同的架构设计风格随之涌现。
在过去几年中,“微服务架构”这一术语开始出现,它描述了一种将软件应用程序设计为一组可独立部署的服务的特定方式。虽然这种架构风格没有明确的定义,但在组织、业务能力上有一些共同的特征:自动化部署、端点智能化、语言和数据的去中心化控制。
——Martin Fowler,2014年3月25日
2014年,架构大师Martin Fowler和James Lewis共同提出了微服务的概念,定义了微服务是以开发一组小型服务的方式来开发一个独立的应用系统,每个服务都以一个独立进程的方式运行,每个服务与其他服务使用轻量级通信机制(如图1-3所示)。这些服务是围绕业务功能构建的,可以通过全自动部署机制独立部署,同时服务会使用最小规模的集中管理(如容器)能力,也可以采用不同的编程语言和数据库。
▲图1-3 单体架构与微服务架构(图片来自Martin Fowler个人网站)
由Martin Fowler给微服务的定义分析可知:一个微服务基本是一个能独立发布的应用服务,因此可以作为独立组件升级、灰度或复用等;对整个大型应用的影响也较小,每个服务可以由专门的组织来单独完成,依赖方只要定好输入和输出接口即可完成开发,甚至整个团队的组织架构也会更精简,因此沟通成本低、效率高。根据业务的需求,不同的服务可以根据业务特性进行不同的技术选型,无论是计算密集型,还是输入/输出(Input/Output,I/O)密集型应用都可以依赖不同的语言编程模型,各团队可以根据本身的特色独自运作。当某一个服务在压力较大时,也可以有更多容错或限流降级处理。
微服务将大型复杂软件应用拆分成多个简单应用,每个简单应用描述一个小业务,系统中的各个简单应用可以被独立部署,各个应用之间是松耦合的,每个应用仅关注完成一件任务并很好地完成该任务。相比传统的单体架构,微服务架构具有降低系统复杂度、独立部署、独立扩展、跨语言编程等特点。
微服务架构并不是技术创新,而是开发过程发展到一定阶段对技术架构的要求,是在实践中不断摸索而来的。微服务的核心思想是化繁为简的应用拆分,这不仅在技术上带来突破,还带来很多潜在的价值,如关注点分离、沟通效率提升、快速演进、快速交付、快速反馈等,这些都是云原生架构所倡导的软件开发模式。
微服务架构确实有很多吸引人的地方,然而它的引入也是有成本的,它并不是银弹,使用它会引入更多技术挑战,比如性能延迟、数据一致性、集成测试、故障诊断等。企业需要根据业务的不同阶段进行合理的引入,不能完全为了微服务而“微服务”。本书第四部分会对如何解决这些问题提供对应不同的方案。
架构的灵活、开发的敏捷同时带来了运维的挑战。应用的编排、服务间的通信成为微服务架构设计的关键因素。目前,在微服务技术架构实践中主要有侵入式架构和非侵入式架构两种实现形式。
微服务架构行业应用深入,侵入式架构占据主流市场。微服务架构在行业生产中得到了越来越广泛的应用,例如Netflix已经有大规模生产级微服务的成功实践。而以阿里巴巴HSF、开源Dubbo和Spring Cloud 为代表的传统侵入式架构占据着微服务市场的主流地位。侵入式架构将流程组件与业务系统部署在一个应用中,实现业务系统内的工作流自动化。
随着微服务架构在行业应用中的不断深入,其支持的业务量也在飞速发展,对于架构平台的要求也越来越高。由于侵入式架构本身服务与通信组件互相依赖,当服务应用数量越来越多时,侵入式架构在服务间调用、服务发现、服务容错、服务部署、数据调用等服务治理层面将面临新的挑战。
服务网格推动微服务架构进入新时代。服务网格是一种非侵入式架构,负责应用之间的网络调用、限流、熔断和监控,可以保证应用的调用请求在复杂的微服务应用拓扑中可靠地穿梭。服务网格通常由一系列轻量级的网络代理组成(通常被称为SideCar 模式),与应用程序部署在一起,但应用程序不需要知道它们的存在。服务网格通过服务发现、路由、负载均衡、健康检查和可观察性来帮助管理流量。
自2017年年初第一代服务网格架构Linkerd公开使用之后,Envoy、Conduit等新框架如雨后春笋般不断涌现。2018年年初,Google、IBM 和Lyft 联合开发的项目Istio 的发布,标志着服务网格带领微服务架构进入新的时代。
著名咨询公司ThoughtWorks的咨询架构师Jez Humble把持续交付定义为:
持续交付是指以一种可持续的方式安全、快速地将所有类型的更改(包括新功能、配置更改、错误修复和实验)交付到生产环境或用户手中的能力。
——Jez Humble
计算机软件诞生半个多世纪以来,从纯粹的科学计算,到信息数据的加工处理,到大数据人工智能,再到现在的万物互联时代,软件背后所代表的人与周围世界的信息交互,其系统复杂度和应用规模已经发生了质的改变。今天有一个非常流行的词汇叫“VUCA时代”,表示当今时代显现出“从复杂到超级复杂”的特征。VUCA对应4个英语单词的首字母:易变性(volatility)、不确定性(uncertainty)、复杂性(complexity)、模糊性(ambiguity)。这4个特性也是当前云架构模式下业务系统非常鲜明的写照。为了应对软件复杂的交付过程,人们以工程化的方式试图消除软件开发过程中的不可控因素,按期交付符合目标的软件产品。软件开发方法也经历了瀑布模型开发方法、敏捷软件开发方法、DevOps软件开发模式等不同的阶段。
持续交付代表一种软件交付的能力,打通开发、测试、生产的各个环节,自动持续、增量地交付产品,以达到随时都能发布的能力,涉及一系列的开发实践方法。持续交付分为持续集成、持续部署、持续发布等阶段。
得益于云原生环境下的敏捷基础设施以及容器+镜像技术,对于开发人员所提交的每一次代码变更,通过工具(如Maven、Jenkins)触发自动编译、构建、打包成镜像,自动部署到镜像仓库,持续交付服务器会将最新的镜像文件拉取到Kubernetes集群中,并采用逐步替换容器的方式对应用进行更新,在服务不中断的前提下完成应用自动更新。整个交付过程如工厂流水线一般逐个环节往下自动触发流转,如图1-4所示。
2006年,ThoughtWorks公司的 Jez Humble、Chris Read和Dan North共同发表了一篇题为“The Deployment Production Line”(部署生产线)的文章。文中讨论了软件部署带来的生产效率问题,并首次提出了“部署生产线”模式,对如何使自动化部署活动更轻松给出了5个指导原则。
(1)Automate your deployment process:自动化部署过程,无须人工干预。
(2)Each build stage should deliver working software:每个构建阶段都应该交付可工作的软件,即对中间产物的生产(如搭建软件运行环境)不应该是一个单独的阶段。
(3)Deploy the same artifacts in every environment:在不同环境中部署同一个构件(镜像),即将应用与运行时配置分开管理。
▲图1-4 交付过程(图片来自网络)
(4)Automate testing and deployment:自动化测试和部署,即根据测试目的,分层设置几个独立的质量关卡,只有满足预期的测试结果,才会执行后续的部署过程。
(5)Evolve your production line along with the application it assembles:部署生产线也应该随着应用程序的发展而不断演进。
持续交付关注“从提交代码到产品发布”的过程,随着某个构建逐步通过每个测试阶段,代码的质量一步步得以验证,我们对它的信心也在不断提高。当然,我们在每个阶段中对环境方面的资源投入也在不断增加,即越往后的阶段,其环境与生产环境越相似。持续交付是企业(尤其互联网企业)能够快速创新、可持续发展的重要技术保证,在高质量、低成本及无风险的前提下,不断缩短产品交付周期,从而与用户频繁互动,获得及时且真实的反馈,最终创造更多客户价值的产品能力。“目标驱动,从简单问题开始,持续改进”是持续交付过程的指导思想。为了获得健康良性的持续交付效果,我们总结了4个核心工作原则。
(1)坚持少做:小步快跑一直是互联网企业保持高速发展的制胜法宝,想办法对新业务、新创意尽早验证,通过不断反馈、迭代来演进完善我们的应用系统,而不是一次性设计一个“大而全且完美”的系统。
(2)持续分解问题:复杂的业务问题中一定会包含很多不确定因素,它们会影响解决问题的速度和质量。通过对问题的层层分解,可以让团队了解业务,更早识别出关键问题和风险。
(3)坚持快速反馈:需要第一时间分析和总结对已交付产品的反馈结果,了解已完成工作的质量和效果。
(4)持续改进并衡量:任何事必须有过程、有结果,无论做了什么样的改进,如果无法以某种方式衡量它的结果,就无法证明真正得到了改进。在着手解决每个问题之前,我们都要找到恰当的衡量方式,并将其与对应的功能需求放在同等重要的位置上,一起完成。
DevOps是一套将软件开发(Development,Dev)和系统运维(Operations,Ops)相结合的实践,旨在缩短应用系统开发生命周期,提供高质量的持续交付。
——维基百科“DevOps”
线上的任何操作及变更都可能产生不可预知的风险,因此一直以来,绝大部分企业对于IT系统执行严格的线上管控。线上系统的运维管理,经历了“PE、AppOps、DevOps、AIOps、NoOps”的不同发展阶段。从字面上来理解DevOps只是Dev(开发人员)+Ops(运维人员),实际上,它是一组用于促进开发人员和运维人员协作的过程、方法和系统的统称,如图1-5所示。
▲图1-5 IT部门内的DevOps协作
DevOps提倡通过一系列的技术和工具减少开发和运维之间的隔阂,实现从开发、构建到最终部署的全流程自动化,从而达到开发运维一体化。DevOps是一套实践方法,在保证高质量的前提下缩短系统变更从提交到部署至生产环境的时间。DevOps概念从2009年首次提出发展到现在,内容非常丰富,有理论,也有实践,包括组织文化、自动化、精益、反馈和分享等方面。
(1)组织架构、企业文化与理念等需要自上而下设计,用于促进开发部门、运维部门和质量保障部门之间的沟通、协作与整合。简单而言,组织形式类似于系统分层设计。
(2)自动化是指所有的操作都不需要人工参与,全部依赖系统自动完成,比如上述的持续交付过程必须自动化才有可能完成快速迭代。
(3)DevOps的出现,得益于软件行业日益清晰地认识到,为了按时交付软件产品和服务,开发部门和运维部门必须紧密合作。
质量很重要,而保障交付软件质量的办法,一方面是各种测试,从最细粒度的单元测试一直到最接近用户感受的集成测试;另一方面是递进式的发布,逐渐扩大变更影响到的用户范围,及时发现,及时止损。将DevOps的理念引入整个系统的开发过程中,能够显著提升软件的开发效率,缩短软件交付的周期,更加适应当今快速发展的云原生时代。DevOps强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件。图1-6所展示的是和DevOps相关的一些技术和工具。
▲图1-6 与DevOps相关的技术及工具(图片来自网络)
说到DevOps,就必然会提到持续集成。持续集成是指在软件开发过程中,软件开发人员持续不断地将开发出来的代码和其他开发人员的代码进行合并,每次合并后自动进行编译、构建,并运行自动化测试进行验证,而不是等到最后各自开发完成后才合并在一起。持续集成能从根本上提高一个团队的软件开发效率。在软件开发过程中引入持续集成,可以帮助团队及时发现系统中的问题,并快速做出修复。这样不仅可以缩短软件开发的时间,而且可以交付更高质量的系统。
一个DevOps开发环境需要满足以下8点要求。
(1)环境一致性:在本地开发出来的功能,无论在什么环境下进行部署,都应该能得到一致的结果。
(2)代码自动检查:每次代码提交后,系统都应该自动对代码进行检查,以便及早发现潜在的问题,并运行自动化测试。
(3)持续集成:每次代码提交后,系统可以自动进行代码的编译和打包,无须运维人员手动进行。
(4)持续部署:代码集成完毕后,系统可以自动将运行环境中的旧版本应用更新成新版本应用,并且整个过程中不会让系统不可用。
(5)持续反馈:在代码自动检查、持续集成、持续部署的过程中,一旦出现问题,要能及时将问题反馈给开发人员和运维人员。开发人员和运维人员收到反馈后对问题及时进行修复。
(6)快速回滚:当发现本次部署的版本出现问题时,系统应能快速回退到上一个可用版本。
(7)弹性伸缩:当某个服务访问量增大时,系统应可以对这个服务快速进行扩容,保证用户的访问。当访问量回归正常时,系统能将扩容的资源释放回去,从而实现根据访问情况对系统进行弹性伸缩。
(8)可视化运维:提供可视化的页面,可实时监控应用、集群、硬件的各种状态。
为了满足以上8点要求,设计出的DevOps开发环境如图1-7所示。
▲图1-7 DevOps开发环境
整个环境主要由以下6个部分组成。
(1)代码仓库 GitLab。
(2)容器技术Docker。
(3)持续集成工具Jenkins。
(4)代码质量检测平台SonarQube。
(5)镜像仓库Harbor。
(6)容器集群管理系统Kubernetes。
整个环境的运行流程主要分为以下6步。
(1)开发人员在本地开发并验证完功能后,将代码提交到代码仓库。
(2)通过事先配置好的Webhook通知方式,当开发人员提交完代码后,部署在云端的持续集成工具Jenkins会实时感知,并从代码仓库中获取最新的代码。
(3)获取到最新代码后,Jenkins会启动测试平台SonarQube对最新的代码进行检查以及执行单元测试,执行完成后在SonarQube平台上生成测试报告。如果测试未通过,则以发送电子邮件的方式通知研发人员进行修改,终止整个流程;如果测试通过,则将结果反馈给Jenkins并执行下一步。
(4)代码检查以及单元测试通过后,Jenkins会将代码发送到持续集成服务器中,在服务器上对代码进行编译、构建,然后打包成能在容器环境中运行的镜像文件。如果中间有步骤出现问题,则通过发送电子邮件的方式通知开发人员和运维人员进行处理,并终止整个流程。
(5)将镜像文件上传到私有镜像仓库Harbor中保存。
(6)镜像上传完成后,Jenkins会启动持续交付服务器,对云环境中运行的应用进行版本更新,整个更新过程中会确保对服务的访问不中断。持续交付服务器会将最新的镜像文件拉取到Kubernetes集群中,并采用逐步替换容器的方式对应用进行更新,在服务不中断的前提下完成更新。
通过上述几步,我们就可以简单实现一个DevOps开发环境,实现代码从提交到最终部署的全流程自动化。通过一系列工具和自动化的技术来降低运维的难度,促进研发运维一体化。一般来说,DevOps会要求研发人员负责更多的业务运维或应用运维的工作。在平台类软件维护的场景中,极端情况下会将传统运维的工作拆分为两部分——应用运维和平台运维。应用运维是指包括应用本身的可用性、容量、业务正确性、监控与告警在内的所有与业务相关的应用本身的运维。平台运维是指包括底层IaaS层以及支撑应用运维的系统本身的维护。研发人员负责应用运维,可以在不借助其他团队的支持且资源充足的情况下,自行完成应用的全生命周期的管理。
DevOps的完整执行需要企业内部组织流程的配合和改造。图1-8所示为某大型互联网公司内部研发体系与工作流程,不同岗位角色的人参与整个产品生命周期的不同阶段:市场→需求→视觉交互→demo原型→开发测试→集成部署→上线发布→评测反馈的完整的持续交付过程。DevOps鼓励小团队协作,因为小团队维护少量的服务,可以快速决策、快速发布,充分利用DevOps的能力。
“十二要素”英文全称为The Twelve-Factor App,其定义了一个优雅的互联网应用,在设计过程中,需要遵循的一些基本原则和云原生有异曲同工之处。十二要素由Heroku创始人Adam Wiggins首次提出并开源,由众多经验丰富的开发者共同完善。这综合了他们关于SaaS应用几乎所有的经验和智慧,是开发此类应用的理想实践标准和方法论指导。
(1)使用标准化流程自动配置,从而使新加入的开发者花费最低的学习成本快速上手这个项目。
(2)和操作系统之间尽可能地划清界限,在各个系统中提供最强的可移植性。
(3)适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。
(4)将开发环境和生产环境的差异降至最小,并使用持续交付实施敏捷开发。
(5)可以在工具、架构和开发流程不发生明显变化的前提下实现扩展。
这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。通过强化详细配置和规范,类似“约定优于配置”的原则,特别在大规模的软件生产实践中,这些约定非常重要,从无状态到水平横向扩展的过程,从松耦合架构关系到部署环境。如图1-9所示,基于十二要素的上下文关联,软件生产就变成一个个单一的部署单元;多个联合部署的单元组成一个应用,多个应用就可以组成一个复杂的分布式应用系统。
▲图1-8 某互联网公司内部研发体系与工作流程
▲图1-9 云原生应用十二要素
下面介绍十二要素的具体说明(这部分内容参考十二要素官网),很多开发人员在实际工作过程中可能也是按照其中的一些原则规范进行开发的,因此读者看到这些要素说明会觉得很熟悉和自然,事物原本就是这样的,只不过我们平时没有意识到这些抽象概念而已。
一份基准代码(codebase),多份部署(deploy)。
在类似于SVN等集中式版本控制系统中,“基准代码”是指控制系统中的代码仓库;而在Git等分布式版本控制系统中,“基准代码”则是指最上游的代码仓库。
基准代码和应用之间总是保持如下一一对应的关系。
(1)一旦有多个基准代码,就不能称为一个应用,而是一个分布式系统。分布式系统中的每一个组件都是一个应用,每一个应用可以分别使用十二要素进行开发。
(2)多个应用共享一份基准代码是有悖于十二要素原则的。解决方案是将共享的代码拆分为独立的类库,然后使用“依赖管理”策略去加载它们。
尽管每个应用只对应一份基准代码,但可以同时存在多份部署。每份“部署”相当于运行了一个应用的实例。通常会有一个生产环境,一个或多个预发布环境。此外,每个开发人员都会在自己本地环境运行一个应用实例,这些都相当于一份部署。
所有部署的基准代码相同,但每份部署可以使用其不同的版本。比如,开发人员可能有一些提交还没有同步至预发布环境,预发布环境也有一些提交没有同步至生产环境。但它们都共享一份基准代码,我们就认为它们只是相同应用的不同部署而已。
部署的环境性质多种多样,如应用环境既有开发环境、测试环境、生产环境等,也有某种环境的多个介质,如容器、虚拟机、物理服务器等。运行环境和配置参数有较大差别,但是程序源码只有一份基准的版本。
在云原生应用架构中,所有的基础设施都是代码配置(Infrastructure as Code),即可编程式基础设施,整个应用通过配置文件就可以编排出来,而不再需要手动干预,做到基础服务也可以通过版本跟踪管理。
显式声明依赖关系(dependency)。
十二要素规则下的应用程序不会隐式依赖系统级的类库,它一定通过“依赖清单”确切地声明所有依赖项。此外,在运行过程中,通过“依赖隔离”工具来确保程序不会调用系统中存在但清单中未声明的依赖项。这一做法会统一应用到生产环境和开发环境中,比如通过合适的工具(Maven、Bundler、NPM),应用可以很清晰地对部署环境公开和隔离依赖,而不是模糊地对部署环境产生依赖。无论用什么工具,依赖声明和依赖隔离都必须一起使用,否则无法满足十二要素原则。
在容器应用中,应用的依赖、环境的依赖和软件的安装等,都是通过Dockerfile来完成声明的,通过配置能明确把依赖关系(包括版本)都图形化地明确展示出来,不存在黑盒。
显式声明依赖的优点之一是为新进开发者简化了环境配置流程。新进开发者可以检出应用程序的基准代码,安装编程语言环境和它对应的依赖管理工具,只需通过一个“构建命令”来安装所有的依赖项,即可开始工作。
十二要素应用同样不会隐式依赖某些系统工具(如ImageMagick或curl)。虽然这些工具存在于几乎所有的系统中,但终究无法保证所有未来的系统都能支持应用顺利运行,或是能够和应用兼容。如果应用必须使用某些系统工具,那么这些工具应该被包含在应用之中。
在环境中存储配置。
通常,应用的配置在不同部署环境(预发布环境、生产环境、开发环境等)会有很大差异,这其中包括如下内容。
(1)数据库、Memcached,以及其他后端服务的配置。
(2)第三方服务的证书。
(3)每份部署特有的配置,如域名以及所依赖的外部服务地址等。
有些应用在代码中使用常量保存配置,这与十二要素所要求的代码和配置严格分离显然大相径庭。配置文件在各部署间存在巨大差异,代码却完全一致。
判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息。
十二要素推荐将应用的配置存储于环境变量(env vars、env)中。环境变量可以非常方便地在不同的部署中做修改,而不改变一行代码;与配置文件不同,不小心把它们签入代码仓库的概率微乎其微;与一些传统的解决配置问题的机制(如Java的属性配置文件)相比,环境变量与语言和系统无关。
实例根据不同的环境配置而运行在不同的环境中,此外,实现配置即代码(Configuration as Code)。在云环境中,无论是统一的配置中心,还是分布式的配置中心,都有很好的实践方式,比如Nacos通过命名空间实现不同环境的配置隔离,以及Docker的环境变量使用。
在十二要素应用中,环境变量的粒度要足够小,且相对独立。它们永远不会组合成一个所谓的“环境”,而是独立存在于每个部署之中。当应用程序不断扩展,需要更多种类的部署时,这种配置管理方式能够做到平滑过渡。
把后端服务(backing service)当作附加资源。
后端服务是指程序运行所需的通过网络调用的各种服务,如数据库、消息队列、简单邮件传输协议(Simple Mail Transfer Protocal,SMTP)邮件服务,以及缓存等。
十二要素应用不会区别对待本地或第三方服务。对应用程序而言,两种都是附加资源,通过一个统一资源定位器(Uniform Resource Locator,URL)或其他存储在配置中的服务定位/服务证书来获取数据。十二要素应用的任意部署都应该可以在不进行任何代码改动的情况下,将本地MySQL数据库换成第三方服务[例如云数据库关系型数据库服务(Relational Database Service,RDS)]。类似地,本地SMTP服务应该也可以和第三方SMTP服务互换。在上述两个例子中,仅需修改配置中的资源地址。
每个不同的后端服务是一份资源。例如,一个MySQL数据库是一个资源,两个MySQL数据库(用来数据分区)就被当作两个不同的资源。十二要素应用将这些数据库都视作附加资源,这些资源和它们附属的部署保持松耦合。
部署可以按需加载或卸载资源。例如,如果应用的数据库服务由于硬件问题出现异常,管理员可以从最近的备份中恢复,即卸载当前的数据库,然后加载新的数据库,整个过程都不需要修改代码。
严格分离构建和运行。
将基准代码转化为一份部署(非开发环境)需要经过以下3个阶段。
(1)构建阶段:是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包依赖项,编译成二进制文件和资源文件。
(2)发布阶段:会将构建的结果和当前部署所需配置相结合,并能够立刻在运行环境中投入使用。
(3)运行阶段(或者说“运行时”):是指针对选定的发布版本,在执行环境中启动一系列应用程序进程。
十二要素应用严格区分构建、发布、运行3个阶段。举例来说,直接修改处于运行状态的代码是非常不可取的做法,因为这些修改很难再同步回构建阶段。部署工具通常提供了发布管理工具,最引人注目的功能是退回至较旧运行稳定的发布版本。在云原生应用中,基于容器的Build-Ship-Run和这3个阶段完全吻合,也是Docker对本原则的最佳实践。
每一个发布版本必须对应一个唯一的发布ID,例如可以使用发布时的时间戳(2011-04- 06-20:32:17)或是一个自增的数字(v100)。发布的版本就像一本只能追加的账本,一旦发布就不可修改,任何的变动都应该产生一个新的发布版本。
新的代码在部署之前,需要开发人员触发构建操作。但是,运行阶段不一定需要人为触发,而是可以自动进行,如服务器重启,或进程管理器重启一个崩溃的进程。因此,运行阶段应该保持尽可能少的模块,这样假设半夜发生系统故障,即使缺少开发人员,也不会引起太大问题。构建阶段是可以相对复杂一些的,因为错误消息能够立刻显示在开发人员面前,从而得到妥善处理。
以一个或多个无状态进程运行应用。
在运行环境中,应用程序通常是以一个和多个进程运行的。十二要素应用的进程必须无状态且无共享。任何需要持久化的数据都要存储在“后端服务”内,如数据库。
所有的应用在设计时就被认为随时随地会失败,面向失败而设计,因此进程可能会被随时拉起或消失,特别是在弹性扩缩容阶段。
内存区域或磁盘空间可以作为进程在做某种事务型操作时的缓存,例如要下载一个很大的文件,对其操作并将结果写入数据库的过程。十二要素应用根本不用考虑这些缓存的内容是否可以保留给之后的请求来使用,这是因为应用启动了多种类型的进程,将来的请求多半会由其他进程来服务。即使在只有一个进程的情形下,先前保存的数据(内存或文件系统中)也会因为重启(如代码部署、配置更改或运行环境将进程调度至另一个物理区域执行)而丢失。
一些互联网系统依赖于“黏性session”(sticky session),这是指将用户 session 中的数据缓存至某进程的内存中,并将同一用户的后续请求路由到同一个进程。黏性session是十二要素极力反对的,session中的数据应该保存在诸如Memcached或Redis等带有过期时间的缓存中。
通过端口绑定(port binding)来提供服务。
互联网应用有时会运行于服务器的容器之中。例如PHP经常作为Apache httpd的一个模块来运行,正如Java运行于Tomcat中。
十二要素应用完全自我加载,不依赖任何网络服务器即可创建一个面向网络的服务。互联网应用通过端口绑定来提供服务,并监听发送至该端口的请求。
超文本传输协议(HyperText Transfer Protocol,HTTP)并不是唯一一个可以由端口绑定提供的服务,其实几乎所有服务器软件都可以通过进程绑定端口来等待请求。还要指出的是,端口绑定这种方式也意味着一个应用可以成为另一个应用的后端服务,调用方将服务方提供的相应URL当作资源存入配置,以备将来调用。
在容器应用中,应用统一通过暴露端口来提供服务,尽量避免通过本地文件或进程来通信,每种服务通过服务发现来路由调用。
通过进程模型进行扩展,以支持并发。
任何计算机程序,一旦启动,就会生成一个或多个进程。互联网应用采用多种进程运行方式。例如,PHP进程作为Apache的子进程存在,随请求按需启动。Java进程则采取了相反的方式,在程序启动之初Java虚拟机(Java Virtual Machine,JVM)就提供了一个超级进程储备了大量的系统资源(CPU和内存),并通过多线程实现内部的并发管理。在上述两个例子中,进程是开发人员可以操作的最小单位。
在十二要素应用中,进程是“一等公民”。十二要素应用的进程主要借鉴于Unix守护进程模型。开发人员可以运用这个模型去设计应用架构,将不同的工作分配给不同的进程类型。例如,HTTP请求可以交给web进程来处理,而常驻的后台工作则交由worker进程负责。
上述进程模型会在系统急需扩展时大放异彩。十二要素应用的进程所具备的无共享、水平分区的特性意味着添加并发会变得简单而稳妥。这些进程的类型和每个类型中进程的数量被称作进程构成。
在互联网的服务中,业务的爆发随时可能发生,因此不太可能通过硬件扩容来随时提供扩容服务,而需要依赖横向扩展能力进行扩容。
快速启动和优雅终止可使健壮性最大化。
十二要素应用的进程是易处理的(disposable),即它们可以瞬间开启或停止。这有利于快速、弹性地伸缩应用,迅速部署变化的代码或配置,稳健地部署应用。
进程应当追求最短启动时间。在理想状态下,进程从输入命令到真正启动并等待请求应该只需很短的时间。更短的启动时间提供了更敏捷的发布和扩展过程,此外还增加了健壮性,因为进程管理器可以在授权情形下容易地将进程移到新的物理机器上。
一旦接收终止信号(即SIGTERM),进程就会优雅地终止。就网络进程而言,优雅终止是指停止监听服务的端口,即拒绝所有新的请求,并继续执行当前已接收的请求,然后退出。此类型的进程所隐含的要求是HTTP请求大多很短(不会超过几秒),而在长时间轮询中,客户端在丢失连接后应该马上尝试重连。
对worker进程来说,优雅终止是指将当前任务退回队列,有锁机制的系统则需要确定释放了系统资源。此类型的进程所隐含的要求是,任务都应该“可重复执行”,这主要通过将结果包装进事务或使用重复操作幂等来实现。
进程还应当在面对突然死亡时保持健壮,例如底层硬件故障。虽然这种情况比优雅终止发生的概率小得多,但终究有可能发生。十二要素应用应该可以设计能够应对意外的、不优雅的终结。
云最大的优势就是弹性及分布式,根据业务的高低峰值,经常需要能实现快速灵活、弹性的伸缩应用。由于不可控的硬件等因素,应用可能随时会发生故障,因此需要应用在架构设计上尽可能无状态化,应用既能随时随地被拉起,也能随时随地销毁,同时保证进程最短启动时间和架构的可弃性,也可以提供更敏捷的发布及扩展过程。
尽可能地保持开发环境、预发布环境和线上环境相同。
从以往经验来看,开发环境和线上环境之间存在着很大差异,主要表现在以下3个方面。
(1)时间差异:开发人员正在编写的代码可能需要几天、几周,甚至几个月才会上线。
(2)人员差异:开发人员编写代码,运维人员部署代码。
(3)工具差异:开发环境或许使用Nginx、SQLite、Windows,而线上环境使用Apache、MySQL以及Linux。
十二要素应用想要做到持续部署,就必须缩小本地与线上差异,对应上面所述的3个方面如下。
(1)缩小时间差异:开发人员可以在几小时,甚至几分钟内就部署代码。
(2)缩小人员差异:开发人员不仅要编写代码,还应该密切参与部署过程以及关注代码在线上的表现。
(3)缩小工具差异:尽量保证开发环境与线上环境的一致性。
十二要素云原生应用与传统应用在环境及部署运维方面的差异如表1-1所示。
表1-1 云原生应用和传统应用部署运维的对比分析
对比项 |
传统应用 |
十二要素云原生应用 |
---|---|---|
每次部署间隔 |
数周 |
几小时 |
开发人员与运维人员 |
不同的人 |
相同的人 |
开发环境与线上环境 |
不同 |
尽量接近 |
后端服务是保持开发与线上等价的重要部分,例如数据库、队列系统,以及缓存。许多语言提供了简化获取后端服务的类库,例如不同类型服务的适配器。开发人员有时会认为在本地环境中使用轻量级的后端服务具有很强的吸引力,而那些重量级的、健壮的后端服务应该在生产环境中使用。
十二要素应用的开发人员应该反对在不同环境间使用不同的后端服务,即使适配器已经几乎可以消除使用上的差异。这是因为,不同的后端服务意味着会突然出现不兼容,从而导致测试、预发布时都表现正常的代码在线上可能会出现问题。这些问题会给持续部署带来阻力。从应用程序的生命周期来看,消除这种阻力需要付出很大的代价。
不同后端服务的适配器仍然是有用的,因为它们可以使移植后端服务变得简单。但应用的所有部署(包括开发、预发布以及线上环境),都应该使用同一个后端服务的相同版本。
在容器化应用中,通过运行Dockerfile文件构建的环境能做到版本化,因此可保证各个不同环境的差异性,同时能大大减少环境不同带来的排错等沟通成本问题。
把日志当作事件流。
日志使应用程序运行的动作变得透明。在基于服务器的环境中,日志通常被写在硬盘的一个文件里,但这只是一种输出格式。
日志应该是事件流的汇总,将所有运行中进程和后端服务的输出流按照时间顺序收集起来。尽管在回溯问题时可能需要看很多行,但日志最原始的格式确实是一个事件占一行。日志没有确定开始和结束,但随着应用在运行会持续增加。
十二要素应用本身从来不考虑存储自己的输出流,不应该试图去写或者管理日志文件。相反,每一个运行的进程都会直接地标准输出(stdout)事件流。在开发环境中,开发人员可以通过这些数据流实时地在终端看到应用的活动。
在预发布或线上部署中,每个进程的输出流由运行环境截获,并将其与其他输出流整理在一起,然后一并发送给一个或多个最终的处理程序,用于查看或长期存档。对应用来说,这些存档路径不可见也不可配置,而是完全交给程序的运行环境管理。
这些事件流可以输出至文件,或在终端实时观察。最重要的是,输出流可以发送到Splunk等日志索引及分析系统或Hadoop/Hive等通用数据存储系统。这些系统为查看应用的历史活动提供了如下强大而灵活的功能。
(1)找出过去一段时间内特殊的事件。
(2)图形化一个大规模的趋势,比如每分钟的请求量。
(3)根据用户定义的条件实时触发警报,比如每分钟的报错超过某个警戒线。
日志是系统运行状态的部分体现,无论是系统诊断、业务追踪,还是后续大数据的分析处理服务。Docker提供标准的日志服务,用户可以根据需求进行自定义的插件开发来处理日志。
后台管理任务当作一次性进程运行。
进程构成(process formation)是指用来处理应用的常规业务(比如处理Web请求)的一组进程。与此不同,开发人员经常希望执行一些管理或维护应用的一次性任务,举例如下。
(1)运行数据移植。
(2)运行一个控制台(也被称为REPL shell)来执行一些代码,或针对线上数据库做一些健康检查或安全巡检。
(3)运行一些提交到代码仓库的一次性脚本。
一次性管理进程应该和正常的常驻进程使用同样的环境。这些管理进程和任何其他的进程一样使用相同的代码和配置,基于某个发布版本运行。后台管理代码应该随其他应用程序代码一起发布,从而避免同步问题。
十二要素尤其青睐那些提供了 REPL shell 的语言,因为那会让运行一次性脚本变得简单。在本地部署中,开发人员直接在命令行使用 shell 命令调用一次性管理进程。在线上部署中,开发人员依旧可以使用ssh或运行环境提供的其他机制来运行这样的进程。
说到云原生,就不得不提及云原生计算基金会(Cloud Native Computing Foundation,CNCF)。CNCF由Google于2015年7月发起成立,隶属于Linux基金会。其目标愿景是“致力于使云原生计算具有普遍性和可持续性,维护和集成云原生开源技术,围绕一系列高质量项目建立社区,支持容器化编排的微服务架构应用”。其职责范围是促进云原生标准制定,促进生态系统的发展和演变,管理项目,推进云原生社区发展。CNCF自成立开始,便得到业界的广泛关注,众多世界知名云厂商以及相关云生态公司参与其中,短短几年,CNCF会员(白金会员、金牌会员、银牌会员)就达到四五百家(国内的阿里云、华为云、京东相继成为CNCF的白金会员)。
从2016年11月开始,CNCF开始维护了一个名为Cloud Native Landscape的生态蓝图(读者可在GitHub官网搜索“Cloud Native Landscape”查看),汇总目前比较流行的云原生产品及其技术,并加以分类,希望能为企业构建云原生体系提供参考。
CNCF列出的生态只是一个参考,很多产品并没有出现在这里,在构建云原生应用时不必拘泥于此。构建企业级云原生架构是一个过程,企业应用发展的不同阶段也会选择不同的工具和平台,并没有所谓“标准”的做法。CNCF把目前所涉及的云原生相关的产品、技术和生态分为8个主要的领域及方向,具体如下。
按云的部署位置可以分为公有云和专有云(私有云)。
公有云是指云基础设施部署在互联网上,用户可以通过互联网渠道直接获取云厂商提供的云产品服务(IaaS、PaaS、SaaS)。这样大大降低用户使用云产品的门槛,同时节省用户自建IDC机房的初期一次性投入,即开即用,按需付费。企业一般会选择其中一个云厂商提供的平台来使用,也有不少企业同时选择两种或者多种云服务商,以提高可用性和避免厂商锁定。
专有云是指用户在自己的IDC机房,采用云的技术及产品搭建自己专属的云平台环境。专有云平台除了可以使用商业云厂商提供的云底座,还可以使用开源的虚拟化技术搭建,如VMware、OpenStack、ZStack、CloudStack等。建设专有云的成本很高,但是出于数据安全以及自主可控的考虑,一些用户会选择专有云。另外,当公司成长到一定规模时,专有云建设也是必要的。除了能缩减成本,还能提高技术实力,而且有更高的灵活性满足内部的各种需求。
有了物理机和虚拟机,在运行容器服务之前,我们还需要为容器准备标准化的基础环境,如自动化部署工具、容器镜像工具、安全工具等,以支持基础设施的运维自动化。IaaS层提供了硬件网络基础,环境部署提供了软件工具底座,二者共同支撑了容器运行平台的地基。
运行时是容器核心的云原生技术,为容器运行提供虚拟化隔离的运行支撑环境,包括虚拟化的计算资源、虚拟化的存储资源、虚拟化的网络环境。
(1)云原生计算:Linux Container(LXC)容器是一种内核轻量级的操作系统层虚拟化技术,通过Linux的Namespace和Cgroup两大机制来实现资源的隔离和限制管理,它为应用软件及其依赖组件提供了一个资源独立的运行环境。LXC容器技术在2008年就已经出现,但一直不温不火。直到2013年年初,Docker开源容器引擎的出现,才让容器技术变得炙手可热。2015年,由Google、Docker、CoreOS、IBM、微软、红帽等厂商联合发起的开放容器联盟(Open Container Initiative,OCI)组织成立,并于2016年4月推出了第一个开放容器标准,标准主要包括运行时标准(runtime)和镜像标准(image)。标准的推出有助于为成长中的市场带来稳定性,让企业能放心采用容器技术,用户在打包、部署应用程序后,可以自由选择不同的容器运行时标准。同时,镜像打包、建立、认证、部署、命名也都能按照统一的规范来进行。随着容器运行时的稳定,普通用户对其关注度会逐渐下降。如果把运行时比作内核,那么容器调度系统就是操作系统,开发者应该更关心操作系统的功能和性能,只有遇到特殊需求或者问题时才会关注内核。
(2)云原生存储:容器从一出现就非常契合微服务中无状态服务的设计理念,因此初期甚至给一些人留下了容器只适合无状态服务的印象,但是随着容器技术的成熟和用户理念的变化,容器目前已经全面进入有状态服务领域。因为容器的生命周期很短的特点,所以容器的状态(存储的数据)必须独立于容器的生命周期,也正因如此,容器的存储变得非常重要。Docker的数据持久化存储主要有两种方式——数据卷(data volume)和数据卷容器(data volume container),在第3章会详细介绍。
(3)云原生网络:绝大部分云厂商为用户提供了虚拟专有云服务(Virtual Private Cloud,VPC),便于用户构建云环境下可定制的虚拟网络方案。网络最重要的功能是提供不同计算资源的连通,随着虚拟化和容器技术的发展,传统的网络方案已经无法满足云计算快速增长、不断变化的网络需求。Docker安装时会自动在宿主机上创建3个网络模式:主机(host)模式、桥接(bridge)模式、容器(container)模式。3.5节中将介绍Docker的网络模式与连接方式。
当在生产环境中使用容器时,单台主机上的容器已经不能满足需求,因而需要管理多主机容器集群,也就需要有一个工具能够提供资源管理、容器调度和服务发现等功能,保证多主机容器能够正常工作。可以说,对于云原生系统,容器编排调度才是核心。
Kubernetes 是世界上最受欢迎的容器编排平台和第一个 CNCF 项目。Kubernetes 帮助用户构建、扩展和管理应用程序及其动态生命周期。Kubernetes 最初是由Google开发的,现在有超过 2300 名贡献者,并且被世界上许多行业中一些具有创新性的公司使用。集群调度功能可以让开发人员构建云原生应用,更加关注代码,而不是操作。Kubernetes 面向未来的应用程序开发和基础设施管理可以在本地或云端进行,无须绑定供应商或云提供商。
容器平台最终还是要运行应用的,最主要的应用当然是各个公司的业务,除此之外还有一些比较通用的行业应用,可以根据需求提供类似于应用市场的功能。应用层提供的技术及产品,既包括涉及跟应用开发相关的基础产品(如数据库、消息队列、缓存、流计算等),也包括跟应用开发相关的软件过程管理(如代码库、镜像库、DevOps)。
技术是为业务服务的,应用仍旧是所有应用系统的最终目的。保证应用快速稳定地测试、构建、部署、升级、支持,减少代码开发时间,降低人力成本,快速响应业务需求,降低应用的运维和使用成本,这些目标在任何时代、任何技术变化趋势中都不会发生改变。
平台服务是指基于容器技术的更上一层的封装,对开发人员、运维人员提供更加友好的、便捷的、基于容器的应用开发能力,让容器作为一种基础设施服务开箱即用——容器即服务(Container as a Service,CaaS)。随着Kubernetes的快速发展,很多以Kubernetes为容器管理平台和应用管理的公司应运而生,大幅降低了用户使用Kubernetes管理容器的门槛。
容器技术把微服务的概念弄得火热,随后也让 Serverless 这个词出现了大众的面前。既然容器能够屏蔽基础设施,让开发者只关心交付的应用(容器镜像),那么我们可不可以更进一步,让开发者也不需要关心交付的镜像,而只关注业务的核心逻辑呢?这就是 Serverless 的想法。开发者定义好基于事件触发的业务逻辑,其他一切都交给平台,当用户发出请求或者其他事件发生时,平台会根据事先的配置自动运行相应的业务逻辑代码,从而实现真正的按需服务。如果说容器关心的是应用,那么Serverless关心的则是函数,由此也催生出一些新的应用开发模式,如函数即服务开发模式(Functions as a Service,FaaS)、后端即服务开发模式(Backend as a Service,BaaS)、小程序开发模式等。Serverless让用户零门槛地使用容器作为应用的部署载体,Serverless 不是没有服务器,而是应用不用关心服务器和系统,只需关注代码,平台提供者将处理其余部分工作,让应用开发更加专注于业务。
监控系统的运行健康,以确保业务的稳定可靠,是运维工作的主要内容。基于云原生的应用平台建立起来之后,我们要保证整个平台能够正常工作,保证运行在其上的服务不会因为平台错误而不可用,而且还要知道应用整体的运行情况,提前对某些可能出错的地方进行预警,一旦出错能够提供合适的信息进行调试和修复等,这都是监控(observability)和分析(analysis)要做的工作。
监控分析包括运行监控(主机监控、容器监控、应用监控)、分布式日志(日志采集、实时流计算、日志分析)、分布式追踪(全链路追踪、架构感知)等应用领域。监控分析是容器平台运维的重中之重,云原生建设降低了应用部署、升级、构建、测试的难度,但是把难度下沉到容器平台,原来的运维工具和思路需要变化以适应新的容器平台,了解集群中正在发生的事情、及时发现可能出现的问题,才能保证业务应用稳定高效地运行。
一个生态的良性发展一定少不了众多领域的参与者及合作伙伴。CNCF成立短短几年时间,得到国际知名云厂商以及众多软件服务商的支持和参与。截至2019年,CNCF会员(白金会员、金牌会员、银牌会员)已将近500家。不同厂商在云原生生态的不同领域贡献自己的产品、技术以及服务(认证、培训、咨询),让整个生态得到蓬勃发展。各种标准的制定也加速了云原生生态的融合,打通不同领域产品交互的屏障,降低用户技术选择与平台迁移的成本。
为了帮助企业推动云原生应用的落地,从而更好地适应环境与业务的发展,CNCF给出了云原生应用路线图——Trail Map(参考CNCF在GitHub官网的Landscape页面),以便在应用上云过程中为用户提供指导建议。路线图分成10个步骤来实施,每个步骤都涉及用户或平台开发者将云原生技术在实际环境中落地时需要循序渐进思考和处理的问题,企业在不同的步骤可以结合Landscape中列出的产品或服务进行选择。
(1)容器化。容器化是云原生的第一步,如果不对应用程序进行容器化,就无法实现云原生。容器是一个标准的软件单元,它将代码及其所有依赖关系打包起来,这样应用程序就可以从一个计算环境快速、可靠地运行到另一个计算环境。至于应用程序的大小和类型,都是无关紧要的。Docker是容器化的首选平台,你可以将任意大小的应用程序和依赖项,甚至在模拟器上运行的一些程序,都进行容器化。Docker 容器镜像是一个轻量级、独立、可执行的软件包,包含运行应用程序所需的所有内容。随着时间的推移,你还可以对应用程序进行分割,并将未来的功能编写为微服务。
(2)CI/CD。设置CI/CD环境,从而使源代码上的任意修改都能够自动通过容器进行编译、测试,并被部署到预生产环境,甚至生产环境中,部署过程中如果有任何异常,可以方便快速地回滚到上一个稳定的版本。软件开发模式从最初的瀑布模型,到后来的敏捷开发,再到今天的DevOps,这是现代开发人员构建出色产品的技术路线。随着 DevOps 的兴起,出现了CI/CD和持续部署的新方法,而传统的软件开发和交付方式在迅速变得过时。在传统开发模式下,多数公司的软件发布频次是每月、每季度甚至每年,而在DevOps时代,每周、每天甚至每天多次发布都是常态。
(3)应用编排。容器编排主要是管理容器的生命周期,尤其是在大规模复杂的生产环境中,软件团队使用容器编排来控制和自动化许多任务。Kubernetes是目前市场上应用编排领域中使用最广泛的工具,还有其他编排工具,如 Docker swarm、Mesos 等。Helm Charts可以用来帮助应用开发和发布者用于定义、安装和升级Kubernetes上运行的应用。
(4)监控和分析。在这个步骤中,用户需要为平台选择监控、日志以及跟踪的相关工具。Kubernetes提供了有关应用程序在容器集群上的资源使用情况的详细信息,并不提供应用运行监控的解决方案,但我们可以将许多现有的云原生产品集成到Kubernetes集群中。例如,将Prometheus用于监控、Fluentd用于日志、Jaeger用于整个应用调用链的追踪。通过这些信息,我们可以评估应用程序的性能,并可以消除瓶颈,从而提升整体性能。
(5)微服务及服务网格。容器技术激发了微服务及服务网格的快速发展,微服务是云原生架构下应用之间交互的主要方式。服务网格,顾名思义就是连接服务、发现服务、健康检查、路由,并用于监控来自互联网的入口。服务网格通常还具有更复杂的操作要求,如灰度发布、限流降级、访问控制和端到端身份验证。
Istio 提供了对整个服务网格的行为洞察和操作控制,提供了完整的解决方案以满足微服务应用程序的各种需求。CoreDNS 是一种快速灵活的工具,可用于发现服务。Envoy 和 Linkerd 都提供服务的健康检查、请求路由和负载均衡等功能,以支持服务网格体系结构。
(6)网络及策略。云原生架构下启用更灵活的网络层非常重要。要启用更灵活的网络,要使用符合容器网络接口(Container Network Interface,CNI)的网络项目,如 Calico、Flannel以及Weave Net等软件用于提供更灵活的网络功能。Open Policy Agent(OPA)是一种通用策略引擎,其使用范围包括从授权和准入控制到数据过滤等。
(7)分布式数据库和存储。实现持久层的分布式,根据其实现方案分为分布式数据库中间件与分布式数据库两种形式,其目标都是为了实现数据库持久层的弹性和伸缩能力。
分布式数据库中间件本身不是一个数据库,而是数据库之上的一层分布式代理,如阿里巴巴的分布式关系型数据库服务(Distributed Relational Database Service,DRDS)以及开源的Vitess、Mycat。分布式数据库中间件负责解析应用提交的SQL,根据拆分路由策略把解析后的SQL路由到后端的物理数据库中执行,以实现分库分表、读写分离、平滑扩容等功能。
分布式数据库本身提供了分布式的能力,不会出现单机数据库中可能会出现的单机资源性能的瓶颈。如阿里巴巴的PolarDB数据库产品,通过数据库的计算存储分离,可以提供很好的弹性和伸缩能力,但同时需要专业的容器存储予以支持,它既可以存储在同一物理位置的多台计算机中,也可以分散在彼此互联的计算机网络上。
CoreOS和Kubernetes等项目中都用到了etcd组件,其作为一个高可用强一致性的分布式键值数据库,用于服务发现。etcd安装配置使用简单,提供HTTP API访问。
(8)流和消息处理。当应用需要比JSON-REST这个模式更高的性能时,可以考虑使用gRPC或者NATS。gRPC是一个通用的远程过程调用(Remote Procedure Call,RPC)框架(类似各种框架中的RPC调用),NATS是一个发布、订阅和负载均衡的消息队列系统。
(9)容器镜像库和运行环境。可以使用Harbor作为镜像私库进行存储以及对镜像的内容进行扫描。容器并非只有Docker一种,容器的运行环境更是如此,可以选择不同的容器运行环境,但需要注意选择具有OCI兼容性的方案,比如containerd或cri-o。
(10)软件分发。最后可以借助Notary等软件用于软件的安全发布。Notary实现了更新框架(The Update Framework,TUF);TUF提供了一个框架(一组库、文件格式和使用程序),可用于保护新的和现有的软件更新系统。该框架应该能够使应用程序免受软件更新过程中所有已知攻击的影响。它不涉及公开关于正在更新的软件(以及客户机可能正在运行的软件)或更新内容的信息。
移动互联网的飞速发展带动各种创新业务的涌现,企业的业务需求发生了根本的改变。传统的IT系统是基于业务需求实现的,它忠实地反映了系统设计的初衷,这也是IT系统应该做到的,如果业务需求不再发生变化,它将非常完美。但是事与愿违,业务需求远没有那么稳定,它的变化速度远远超出信息系统的应变能力。从业务角度来看,这样快速的变化是正常的,也是企业应对客户与市场变化的必然要求。随着业务需求的不断变化,系统持续增加、流程不断优化、系统越来越不堪重负,传统企业的IT架构正面临着诸多的挑战,如图1-10所示。在大规模分布式业务构建的统一计算环境中,企业业务协作的范围已经从企业内部走向基于极端开放、动态的产业生态链按需协同。前所未有的分布和开放的特性,意味着企业IT系统的应用架构、开发与运维、互操作框架、通信协议、高可用要求等多个方面与传统架构有着本质的区别。
一场以IT技术为主体的科技革命浪潮正席卷而来,云计算、大数据、人工智能、物联网、区块链等新技术正加速应用落地。在这些新技术中,作为基础设施,云计算是这场科技革命的承载平台,全面支撑着各类新技术和新应用。伴随着这波浪潮,数字经济已经成为发展趋势,各企业都在进行或准备进行数字化转型,而上云则是企业数字化转型的起点。工业和信息化部于2018年印发《推动企业上云实施指南(2018—2020年)》,其中指出:到2020年,力争实现企业上云环境进一步优化,企业上云意识和积极性明显提高,上云比例和应用深度显著提升,云计算在企业生产、经营、管理中的应用广泛普及。上云给企业带来新的发展动力,通过技术变革驱动流程创新和业务创新。应用上云是企业实现数字化转型的第一步,它会给企业带来很多好处,如图1-11所示。
▲图1-10 传统企业架构面临的问题和挑战
▲图1-11 应用上云为企业带来新的发展动力
云平台能促进软件架构复用,架构和开发技术栈统一,提高开发效率,加快应用部署,缩短业务开发周期,帮助企业降低时间成本,方便其更加专注于自身业务的拓展。据IDC预测,全球数据量正迎来爆发,将从2018年的33 ZB增长到2025年的175 ZB。推动这一增长的重要因素之一是云计算具备弹性扩容、按需使用、按量付费等优点,云数据中心正成为企业新的数据存储库,2021年公共云数据量将超过传统数据中心,如图1-12所示。
▲图1-12 存储在公共云和传统数据中心的数据对比
在实现应用迁移上云的过程中,一般会面临已有业务系统改造和新建业务系统两种场景。新建业务系统只需要按照应用上云的标准要求进行架构设计、开发、编码和测试,实现相对简单。已有业务系统迁移上云则需要面临数据迁移以及业务系统改造等问题。应用迁移上云一般分为迁云方案制定、迁云过程执行、云上应用护航3个主要的过程,如图1-13所示。
▲图1-13 企业应用迁云过程
企业应用上云,按其使用云产品的深入程度分为云托管模式(IaaS 上云)和云原生模式(PaaS上云)两种类型。IaaS解决了物理机资源的资源管理和资源供给问题,通过对计算、存储和网络的统一和抽象化实现基础资源的统一化供给。IaaS没有跨越开发和运维之间的鸿沟,开发人员仍然需要关注运行在操作系统上的各种基础中间件。PaaS的目标是为应用提供运行所需的各种基础软件,提供实际业务的开发运行环境,从而让业务系统的开发更加简便、高效。
企业上云是指企业通过互联网将企业的基础设施、管理及业务部署到云端上,即可利用网络便捷地获取云计算服务商提供的计算、存储、软件、数据等服务,从而提高资源配置效率、降低信息化建设成本、促进共享经济发展、加快新旧转换。企业把生产和管理的数据存储到云上,把企业日常经营管理非涉密的系统或软件部署到云上,把企业生产能力、设计(开发)能力及产品放在云上,也可以从云上获取企业想要的计算(存储)资源、软件资源、订单资源、第三方服务资源等。企业应用上云的第一阶段是基础设施上云(IaaS层),类似于阿里云、华为云、微软Azure、亚马逊AWS等,都提供云计算、云存储、云上开发等基础设施服务。根据云的部署位置又可以进一步细分为公有云、专有云(私有云)和混合云3种不同的云形态。
对于基础设施上云,我们一般称之为“云托管模式”,企业只是把原本部署在IDC机房服务器上的应用改为部署在云上虚拟机(或容器)中,应用的架构基本没有发生任何改变,上云的改造成本低、风险低。基础设施上云给企业带来的好处是减少机房一次性投入的资金压力,业务流量变化时可充分利用云的弹性随时扩缩容,提高资源利用率,利用云厂商提供的专业且统一的云资源运维可大幅降低企业的IT运维成本,降低运维风险,提高系统的稳定性、可靠性。表1-2所示为云托管与传统的自建IDC机房的优缺点对比。
表1-2 云托管与自建IDC机房对比
对比项 | 云托管模式 | 自建IDC机房 |
机房部署 | 云厂商统一考虑能源优化设计,电源使用效率(Power Usage Effectiveness,PUE)低 | 传统交流电服务器设计 PUE高 |
骨干机房,出口带宽大,独享带宽 | 机房质量参差不齐,用户选择困难,以共享带宽为主 | |
边界网关协议(Border Gateway Protocol,BGP)多线机房,全国访问流畅均衡 | 以单线和双线为主 | |
操作易用 | 内置主流的操作系统 | 需用户自备操作系统,自行安装 |
可在线更换操作系统 | 无法在线更换操作系统 需要用户重装 |
|
Web在线管理,简单方便 | 没有在线管理工具,维护困难 | |
手机验证密码设置,安全方便 | 重置密码麻烦,且被破解的风险高 | |
容灾备份 | 三副本数据设计,单份数据损坏时可在短时间内快速恢复 | 用户自行搭建,使用普通存储设备,价格高昂 |
用户自定义快照 | 没有提供快照功能 无法做到自动故障恢复 |
|
发生硬件故障事故时可快速自动恢复 | 数据损坏时需用户修复 | |
安全可靠 | 有效阻止MAC欺骗和地址解析协议(Address Resolution Protocol,ARP)攻击 | 很难阻止MAC欺骗和ARP攻击 |
有效防护DDoS攻击,可进行流量清洗和黑洞 | 清洗和黑洞设备需要另外购买,价格昂贵 | |
端口入侵扫描、挂马扫描、漏洞扫描等附加服务 | 普遍存在漏洞挂马和端口扫描等问题 | |
灵活扩展 | 开通云服务器非常灵活 可以在线升级配置 |
服务器交付周期长 |
带宽升降自由 | 带宽一次性购买,无法自由升降 | |
在线使用负载均衡,轻松扩展应用 | 硬件负载均衡,价格昂贵,设置也非常麻烦 | |
节约成本 | 使用成本门槛低 | 使用成本门槛高 |
无须一次性大投入 | 一次性投入巨大,闲置浪费严重 | |
按需购买,弹性付费 灵活应对业务变化 |
无法按需购买 必须为业务峰值满配 |
从上面的对比分析不难看出,与传统的自建IDC机房相比,企业直接利用云厂商提供的基础设施具有更高的成本优势,以及高可用性、安全性和弹性等优势,云托管极大地简化和降低了提供IT服务的复杂性和成本,减少企业的IT运维人员投入。而且随着资源规模扩大到一定阶段,系统的复杂度将会由量变引起质变,自建IDC机房的风险及成本会大幅提高,相比较而言,用云厂商IaaS基础设施的优势将会更加明显,如图1-14所示。
▲图1-14 自建机房与云上IaaS的TCO&复杂度对比曲线
IaaS是企业应用上云的初始阶段,重点解决成本及运维的问题,应用的系统架构几乎没有发生任何改变,只不过把原先部署在IDC机房服务器中的应用改为部署在云上的虚拟机或容器中。业务系统上云,不是为了上云而上云,最重要的是要能够发挥出云的特点,达到原生云的效果,实现CI/CD,DevOps一体化敏捷管理。要实现系统的敏捷部署、弹性扩展、动态迁移、故障自愈、数据更加安全可靠等,就需要系统针对云原生的分布式、去中心化、一切资源服务化、弹性等特点,做相应的改造或者开发新的业务系统来代替原业务功能。
业务应用在云上的演进方向是,通过云上现有的服务构建系统,基于云产品来做技术选型,使应用开发、工具链、CI/CD、运行托管、运维诊断都在云上完成。
原有的IT架构难以向云端迁移。云大多以虚拟化、开源技术、分布式技术为主,而原有的IT架构大多使用了小型机或x86服务器、相对重量级的中间件和数据库、以闭源厂商的产品为准,因此无法把现有的系统直接搬上云,必须做云化改造。采用云原生架构,使用适合云部署的技术,如虚拟化、容器化、微服务化,同时基础设施要建立相应的计算、网络、存储等资源池,采用计算虚拟化、软件定义存储(Software Defined Storage,SDS)、软件定义网络(Software Defined Network,SDN)、容器Docker等技术,提供IaaS、PaaS、SaaS、CaaS等云服务。只有采用云原生架构去重构应用系统,才能充分发挥云的优势,为应用提供高可用、弹性伸缩、稳定可靠、开发与运维一体化的持续敏捷发布能力,赋予业务快速低成本试错的能力,以技术驱动业务创新。云原生架构的优势如图1-15所示。
IaaS云改变了服务器的使用方式,新上一套系统,用户无须新部署一台新服务器,而是新建一个虚拟机就够了。但用户还必须创建好虚拟机、配置好运行环境才能部署系统。使用PaaS云,既不用创建虚拟机,也不用配置环境了,用户需要做的就是把应用部署到云平台上,即可使用。要想使用数据库,既不必使用数据库服务器、安装操作系统、安装数据库,也无须完成复杂的配置,所要做的只是在云平台上选择创建一个数据库服务,然后绑定到应用上就可以使用了,这就是PaaS云带来的变化。
这样做的好处很多。首先,PaaS云为我们完成了除应用本身之外几乎所有的配置管理工作,我们所关心的只是与自身应用相关的开发部署运维管理,对应用的管理也变成了只是一条指令或者一个按钮就可以完成的事情。而像数据库、缓存、消息队列等基础工具,PaaS云平台也都将其作为服务提供给我们,开箱即用。其次,PaaS云还将系统冗余变成了常规功能。在传统架构中,冗余是很昂贵的,这意味着我们需要配备冗余服务器或者设计一套分布式的软件架构。但在PaaS云上,只需一条指令就可以为一个应用创建多个实例,几乎是零成本。最后,PaaS还可以自动实现资源扩展,应用故障时自动重启等功能,相当于一个24小时不间断服务的运维工程师。
更进一步,由于PaaS云将底层的基础运行环境标准化为容器,因此进一步提升了软件开发的自动化程度,开发人员提交代码即可。对于集成测试、打包、部署、启动、运维,PaaS云全部无须考虑,这就是所谓的DevOps。PaaS云的出现缩短了代码开发到应用部署所花费的时间,降低了软件开发运维的成本。这就意味着更少的人可以做更多的事情,更短的时间可以做出更加快速的响应。PaaS云平台将分布式架构的开发成本降得极低,所以我们可以将大而全的系统分拆成一个个小的服务,即所谓的微服务架构。微服务架构提高了大型系统开发团队的协同效率,有效规避了单体架构下牵一发而动全身的迭代风险。每个小团队负责开发运维若干微服务,小团队可自主选择微服务内部的技术栈及产品发布策略,跨团队之间通过接口契约进行交互协同,职责边界清晰,小步快跑的互联网发布思维能更好地支撑业务的持续创新。
▲图1-15 云原生架构的优势