DevOps Research and Assessment (DORA) 的研究指出,优秀的 DevOps 团队每天可执行多次部署,在一天内发布正式版应用更改,并且更改失败率仅为 0–15%。
本白皮书展示了如何将您的应用架构重新设计为云原生范式,即使在您扩大团队的同时,您也可以加快交付新功能的速度,同时提高软件质量并实现更高级别的稳定性和可用性。
许多公司使用单体式架构来构建自定义软件服务。这种方法的优势在于,单体式系统的设计和部署相对简单,至少一开始是这样。但是,随着应用的日益复杂,维持开发者的工作效率和部署速度会变得困难,导致系统更换昂贵且耗时,部署风险也很高。
随着服务(以及负责团队)的发展,服务往往会变得越来越复杂,更难以改进和运营。测试和部署令人头疼,增加新功能更加麻烦,维持可靠性和可用性也十分费力。
Google 的 DORA 团队进行的研究表明,各种规模和领域的组织都可以实现较高的软件交付吞吐量以及服务稳定性和可用性。高绩效团队能够每天部署多次,在不到一天的时间内将变更投入生产,在不到一小时的时间内恢复服务,并实现 0-15% 的变更失败率。1
此外,即使扩大团队规模,高绩效者也能够实现较高水平的开发者工作效率(以每个开发者每天的部署次数来衡量)。如图 1 所示。
本页面的其余部分介绍了如何将应用迁移到现代的云原生范式,以帮助获得这些结果。通过实现本白皮书中所述的技术做法,您可以达成以下目标:
1 通过 https://cloud.google.com/devops/,根据这四个关键指标了解您的团队表现
单体式应用必须作为一个单元进行构建、测试和部署。通常,应用的操作系统、中间件和语言栈会针对每个应用进行自定义配置。每个应用的构建、测试和部署脚本和进程通常也具有唯一性。这对绿地应用来说简单且有效,但随着应用的发展,更改、测试、部署和运营这些系统会变得更加困难。
此外,随着系统的发展,构建、测试、部署和运营服务的团队的规模和复杂性也会不断增加。一种常见但有缺陷的方法是按职能划分团队(导致团队之间的隔断),这往往会延长交货期并增加批次大小,导致大量返工。DORA 的研究表明,高绩效团队在单个跨职能团队中开发和交付软件的效率可能会翻倍。
此问题的现象包括:
相比之下,在云原生范式中:³
3 这并不是对“云原生”含义的完整描述:如需了解云原生架构的一些原则的讨论,请访问 https://cloud.google.com/blog/products/application-development/5-principles-for-cloud-native-architecture-what-it-is-and-how-to-master-it。
这种范式有许多优势:
更快的交付速度 | 可靠的发布 | 费用更低 |
由于服务较小且松散耦合,因此与这些服务关联的团队可以自主工作。这可以提高开发者的工作效率和开发速度。 | 开发者可以在类似生产的测试环境中快速构建、测试和部署新服务和现有服务。部署到生产环境也是一个简单的原子活动。这大大加快了软件交付过程并降低了部署风险。 | 由于平台提供了共享的标准化服务,并且应用在共享的物理基础设施上运行,因此测试和生产环境的成本和复杂性大大降低。 |
更好的安全性 | 可用性较高 | 满足合规性要求变得更简单、费用更低 |
供应商现在负责共享服务(例如 DBMS 和消息传递基础设施)的更新、修补和合规事务。由于有一种标准的方式来部署和管理应用,因此修补和更新应用也容易得多。 | 由于降低了操作环境的复杂性、易于进行配置更改以及能够在平台级别处理自动扩缩和自动修复,因此应用的可用性和可靠性得到了提高。 | 大多数信息安全控制都可以在平台层实现,这使得实现和证明合规性变得更加便宜和容易。许多云提供商保持对 SOC2 和 FedRAMP 等风险管理框架的合规性,这意味着部署在它们之上的应用只需证明符合未在平台层实现的剩余控制机制即可。 |
更快的交付速度
可靠的发布
费用更低
由于服务较小且松散耦合,因此与这些服务关联的团队可以自主工作。这可以提高开发者的工作效率和开发速度。
开发者可以在类似生产的测试环境中快速构建、测试和部署新服务和现有服务。部署到生产环境也是一个简单的原子活动。这大大加快了软件交付过程并降低了部署风险。
由于平台提供了共享的标准化服务,并且应用在共享的物理基础设施上运行,因此测试和生产环境的成本和复杂性大大降低。
更好的安全性
可用性较高
满足合规性要求变得更简单、费用更低
供应商现在负责共享服务(例如 DBMS 和消息传递基础设施)的更新、修补和合规事务。由于有一种标准的方式来部署和管理应用,因此修补和更新应用也容易得多。
由于降低了操作环境的复杂性、易于进行配置更改以及能够在平台级别处理自动扩缩和自动修复,因此应用的可用性和可靠性得到了提高。
大多数信息安全控制都可以在平台层实现,这使得实现和证明合规性变得更加便宜和容易。许多云提供商保持对 SOC2 和 FedRAMP 等风险管理框架的合规性,这意味着部署在它们之上的应用只需证明符合未在平台层实现的剩余控制机制即可。
但是,云原生架构有一些相关的取舍:
许多组织采用“直接原样迁移”方法将服务迁移到云端。在这种方法中,只需要对系统进行少量更改,云被视为传统数据中心。尽管与传统数据中心相比,云可以提供好得多的 API、服务和管理工具。但是,直接原样迁移本身并不具有上述云原生范式的优点。
许多组织因为将应用迁移到云原生架构的成本和复杂性而在直接原样迁移时停滞不前,这需要重新考虑从应用架构到生产操作以及整个软件交付生命周期的方方面面。这种担心是有道理的:许多大型组织已经被多年失败的“大爆炸式”平台更换努力给搞得灰心丧气。
正确的解决方案是采用增量、迭代和渐进的方法将系统架构重新设计为云原生架构,使团队能够学习如何在这种新范式中有效地工作,同时继续提供新功能:我们称之为迁移并改进的方法。
进化架构中的一个关键模式称为绞杀榕应用。4 与其从头开始完全重写系统,不如以现代的云原生样式编写新功能,但让它们与原始的单体式应用通信以获取现有功能。为了新服务的概念完整性,随着时间的推移而根据需要逐渐改变现有功能,如图 2 所示。
4 如 https://martinfowler.com/bliki/StranglerFigApplication.html 中所述
首先,快速推出新功能,而不是重现现有功能。关键指标是您可以多快开始使用新服务交付新功能,以便您可以快速学习和交流从此范式的实际工作中获得的良好实践。积极缩小范围,争取在几周(而不是几个月)内向实际用户交付一些功能。
第二,根据云原生的特点进行设计。这意味着使用云平台的原生 DBMS、消息传递、CDN、网络、blob 存储服务等,并尽可能使用平台提供的标准化应用栈。服务应容器化,尽可能使用无服务器范式,并且构建、测试和部署过程应完全自动化。让所有应用使用平台提供的共享服务进行日志记录、监控和提醒。(值得注意的是,这种平台架构可为任何多租户应用平台部署,包括裸金属本地环境。)下面的图 3 展示了云原生平台的高层架构。
最后,针对可测试和部署自己的服务的自治型松散耦合团队进行设计。我们的研究表明,最重要的架构结果是软件交付团队能否对以下 6 个问题作出“肯定”回答:
定期检查团队是否在朝这些目标努力,并优先考虑实现这些目标。这通常需要重新思考组织和企业架构。
特别是,关键在于以适当的方式组织团队,使得构建、测试和部署软件所需的各种角色(包括产品经理)协同工作,使用现代产品管理做法来构建和优化服务。您不必更改组织结构,只需使相关人员以团队形式进行日常协作(尽可能在同一个办公空间)。与开发人员、测试人员和发布团队独立运作相比,这可以大大提高工作效率。
我们的研究表明,团队同意这些陈述的程度强烈预示着软件的高性能:每天多次提供可靠的高可用性服务的能力。反过来,即使团队数量增加,这也使高绩效团队能够提高开发者的工作效率(以每个开发者每天的部署数量来衡量)。
采用微服务或面向服务的架构时,您必须遵守一些重要的原则和做法。最好从一开始就非常严格地遵循这些原则,因为后续再进行改造的成本更高。
这需要考虑很多方面,这就是为什么务必要与有能力尝试实现这些想法的团队一起测试这种工作的原因。既有成功也有失败 - 重要的是要从这些团队中吸取经验教训并在您将新的架构范式传播到您的组织时加以利用。
我们的研究表明,成功的公司使用概念验证并为团队提供分享知识的机会(例如通过创建实践社区)。提供时间、空间和资源,让各团体的成员定期碰面和交流想法。每个员工还需要学习新的技能和技术。投资于员工的成长,例如为他们提供购买书籍、参加培训课程和参加会议的预算。提供基础设施和时间,让员工可以通过公司邮件列表、知识库和线下聚会来分享系统知识和最佳实践。
在本部分中,我们将根据以下准则描述参考架构:
容器化云应用的基础是容器管理和编排服务。虽然存在各种各样的服务,但占据统治地位的显然是 Kubernetes。Kubernetes 建立了一个活跃的社区并获得了众多领先商业供应商的支持,已然成为行业中的容器编排标准。图 4 总结了 Kubernetes 集群的逻辑结构。
Kubernetes 定义了被称为 Pod 的抽象。每个 Pod 通常只包含一个容器(例如图 4 中的 Pod A 和 B),但也可以包含多个容器(例如 Pod C)。每个 Kubernetes 服务运行一个包含一定数量节点的集群,每个节点通常是一个虚拟机。图 4 仅显示四个虚拟机,但一个真实的集群可能轻易就包含 100 个或更多虚拟机。当 Pod 部署到 Kubernetes 集群上时,服务会确定该 Pod 的容器应该在哪些虚拟机中运行。由于容器指定了其所需的资源,因此 Kubernetes 可以智能地选择为每个虚拟机分配哪些 Pod。
Pod 的部署信息会指明应该运行的 Pod 实例(副本)数量。Kubernetes 服务随后会创建该数量的 Pod 容器实例并分配给虚拟机。例如,在图 4 中,Pod A 和 Pod C 的 Deployment 都请求了三个副本。但是,Pod B 的 Deployment 请求了四个副本,因此,此示例集群包含容器 2 的四个运行实例。如图所示,包含多个容器的 Pod(例如 Pod C)的容器将始终被分配给相同节点。
Kubernetes 还提供其他服务,包括:
重构单体式应用的一些好处(例如更低的费用)直接来自于在 Kubernetes 上运行。但是,最重要的好处之一 - 更频繁地更新应用的能力 - 只有在您改变构建和发布软件的方式时才有可能。如需获得此好处,您必须在组织中创建有效的 CI/CD 流水线。
持续集成依赖于可为开发者提供快速反馈的自动构建和测试工作流。它要求在相同代码(例如一个服务的代码)上工作的每个团队成员定期将其工作集成到共享的主线或主干中。每个开发者每天应至少进行一次集成,并且每次集成都需要由包含自动化测试的构建流程进行验证。持续交付的目标是快速、低风险地部署此集成代码,主要方式是自动执行构建、测试和部署流程,以使性能、安全性和探索性测试等活动持续执行。简而言之,CI 可帮助开发者快速检测集成问题,而 CD 可确保部署的可靠性和常规性。
为了更清楚地了解这一点,不妨查看一个具体的示例。图 5 显示了将 Google 工具用于 Google Kubernetes Engine 上运行的容器的 CI/CD 流水线的情况。
如图 6 所示,将流程分为两个部分来考虑很有用:
本地开发 | 远程开发 |
这里的目标是加快内部开发循环速度,并为开发者提供工具,以快速获得有关本地代码更改影响的反馈。这包括支持执行 lint 请求、自动补全 YAML 以及更快的本地构建。 | 提交拉取请求 (PR) 后,远程开发循环开始。这里的目标是大幅减少通过 CI 验证和测试 PR 以及执行漏洞扫描和二进制文件签名等其他活动所需的时间,同时以自动化方式推动发布批准。 |
本地开发
远程开发
这里的目标是加快内部开发循环速度,并为开发者提供工具,以快速获得有关本地代码更改影响的反馈。这包括支持执行 lint 请求、自动补全 YAML 以及更快的本地构建。
提交拉取请求 (PR) 后,远程开发循环开始。这里的目标是大幅减少通过 CI 验证和测试 PR 以及执行漏洞扫描和二进制文件签名等其他活动所需的时间,同时以自动化方式推动发布批准。
本地开发:提高开发者的本地应用开发工作效率至关重要。本地开发需要构建可部署到本地和远程集群的应用。在将更改提交至 GitHub 等源代码控制管理系统之前,快速的本地开发循环可确保开发者能够测试更改并将更改部署到本地集群。
为此,Google Cloud 提供了 Cloud Code。 Cloud Code 附带了 IDE 的扩展程序(例如 Visual Studio Code 和 Intellij),可让开发者在 Kubernetes 上快速迭代、调试和运行代码。Cloud Code 会在后台使用 Skaffold、Jib 和 Kubectl 等热门工具来帮助开发者实时并持续地获取有关代码的反馈。
持续集成:通过新的 Cloud Build GitHub 应用,团队可以从 GitHub 中基于不同的代码库事件(拉取请求、分支或标记事件)触发构建。Cloud Build 是一个完全无服务器的平台,可以根据负载进行扩缩,而无需预先配置服务器或为额外容量提前付费。通过 GitHub 应用触发的构建会自动向 GitHub 发回状态。反馈会直接集成到 GitHub 开发者工作流程中,从而减少上下文切换。
工件管理:Container Registry 允许团队在一个位置集中管理 Docker 映像、执行漏洞扫描以及通过精细的访问权限控制机制来决定谁可以访问哪些内容。漏洞扫描与 Cloud Build 集成后,开发者可以在 Cloud Build 创建映像并将其存储在 Container Registry 中后立即识别安全威胁。
持续交付:Cloud Build 使用构建步骤来帮助您定义构建、测试和部署过程中要执行的特定步骤。例如,创建新容器并将其推送到 Container Registry 后,下一个构建步骤可以将该容器与相关的配置和政策一起部署到 Google Kubernetes Engine (GKE) 或 Cloud Run。如果您采用多云策略,还可以部署到其他云服务提供商。最后,如果您希望实现 GitOps 形式的持续交付,Cloud Build 允许您使用存储在 Git 代码库中的文件(例如 Kubernetes 清单)以声明方式描述部署。
但是,部署代码并不是终点。 组织还需要在代码执行期间管理该代码。为此,Google Cloud 为运营团队提供了 Cloud Monitoring 和 Cloud Logging 等工具。
GKE 不要求必须使用 Google 的 CI/CD 工具,如果您愿意,也可以使用其他工具链。例如 CI/CD 使用 Jenkins,工件管理使用 Artifactory。
如果您像大多数组织一样使用基于虚拟机的云应用,现在可能没有一个运转良好的 CI/CD 系统。将其部署到位是从重新设计架构的应用中获益的重要部分,但这需要付出努力。您可以使用创建流水线所需的技术,这在一定程度上取决于 Kubernetes 的成熟度。不过,人员的变化可能比较大。交付团队中的人员必须具备跨职能技能,包括开发、测试和运营技能。转变文化需要时间,因此请准备好在员工开始从事 CI/CD 工作时努力改变他们的知识和行为。
根据云原生范式重新设计单体式应用的架构是一项重大变革。毫无疑问,这样做会带来您需要应对的新安全挑战。其中最重要的两个挑战是:
第一个挑战源于一个显而易见的事实:将应用分解为容器化服务(也可能是微服务)要求这些服务以某种方式进行通信。虽然它们可能都在同一 Kubernetes 集群上运行,但您仍然需要注意控制它们之间的访问。毕竟,您可能会与其他应用共享该 Kubernetes 集群,并且不能让容器向其他应用开放。
要控制对容器的访问,需要对调用方进行身份验证,然后确定这些其他容器有权发出的 17 个请求。目前通常使用服务网格来解决此问题(以及其他一些问题)。一个优秀的例子是 Istio,这是一个由 Google、IBM 和其他公司创建的开源项目。图 7 显示了 Istio 在 Kubernetes 集群中的位置。
如图所示,Istio 代理会拦截应用中容器之间的所有流量。这使服务网格可以提供多项有用的服务,而无需对应用代码进行任何更改。这些服务包括:
Google Cloud 允许您将 Istio 添加到 GKE 集群中。尽管不要求使用服务网格,但如果您知识渊博的云应用用户询问安全性是否达到 Istio 提供的安全级别,也无需感到意外。客户非常注重安全性,在基于容器的环境中,Istio 是提供安全性的重要部分。
除了支持开源 Istio 之外,Google Cloud 还提供 Traffic Director,这是一个完全由 Google Cloud 管理的服务网格控制平面,可在多个区域的集群和虚拟机实例之间提供全局负载均衡,从服务代理中卸载健康检查,并提供先进的流量管理功能和上述其他功能。
Traffic Director 的一项独特功能是网格中微服务的自动跨区域故障切换和溢出(如图 8 所示)。
您可以使用此功能在服务网格中将全球弹性与服务安全性相结合。
Traffic Director 提供多项流量管理功能,可帮助改善服务网格的安全状况。例如,您可以将图 9 所示的流量镜像功能轻松设置为政策,以允许影子应用接收由主版本处理的真实流量的副本。在处理后,影子服务收到的副本响应会被舍弃。流量镜像是一个强大的工具,可用于测试生产流量中的安全异常和调试错误,同时不会影响或损坏生产流量。
但是,保护容器之间的交互并不是重构应用带来的唯一新安全挑战。另一个挑战是确保运行的容器映像是可信的。为此,您必须确保软件供应链融入了安全性和合规性。
您需要执行以下两项主要操作(如图 10 所示):
漏洞扫描:Container Registry 漏洞扫描可让您快速获得有关潜在威胁的反馈,并在您的容器由 Cloud Build 构建且存储在 Container Registry 中后立即发现问题。Ubuntu、Debian 和 Alpine 的软件包漏洞会在应用开发过程中被识别出来;以后还会支持 CentOS 和 RHEL。这有助于避免代价高昂的低效率问题,并缩短修复已知漏洞所需的时间。
Binary Authorization:通过集成 Binary Authorization 和 Container Registry 漏洞扫描,您可以基于漏洞扫描结果对部署进行门控,并将其作为整体部署政策的一部分。Binary Authorization 是一种部署时安全控制措施,可确保在 GKE 上仅部署可信的容器映像,无需任何人工干预。
使用服务网格保护容器之间的访问以及确保安全的软件供应链是创建基于容器的安全应用的重要方面。此外还有许多其他方面,包括验证您在其上进行构建的云平台基础架构的安全性。但最重要的是认识到从单体式应用转变为现代云原生范式,会带来新的安全挑战。为了顺利完成这一过渡,您需要了解这些安全挑战,然后制定具体的计划来解决每个问题。
相反,现在就开始寻找一个有能力和专业知识的团队来开始验证概念,或者寻找一个已经完成这项工作的团队。然后,吸取经验教训并开始在整个组织中进行推广。让团队采用绞杀榕模式,在他们继续提供新功能时,以迭代方式逐步将服务迁移到云原生架构。
为了取得成功,团队必须拥有相应的能力、资源和权限,能使不断改进系统架构成为其日常工作的一部分。根据之前提出的六个架构结果为新工作设定明确的架构目标,但允许团队自由决定如何实现目标。
最重要的是,不要急于开始!对于组织的成功,提高团队的工作效率和敏捷性以及服务的安全性和稳定性将变得越来越重要。优秀的团队能够将规范的实验和改进工作融入日常工作。
Google 基于多年在内部使用的软件开发了 Kubernetes,这就是我们在云原生技术方面拥有丰富经验的原因。
正如我们的 CI/CD 和安全产品所证明的那样,Google Cloud 非常关注容器化应用。事实很明确:Google Cloud 在支持容器化应用方面是当今的领导者。
请访问 cloud.google.com/devops 进行快速检查,了解您的情况并获得有关如何继续前进的建议,包括实现本白皮书中讨论的模式(例如松散耦合的架构)。
许多 Google Cloud 合作伙伴已经帮助像你们这样的组织实现这种转变。既然我们可以将您与经验丰富的“导游”联系起来,为什么您还要自己开辟一条重新架构的“道路”呢?
如需开始使用,请与我们联系以安排与 Google 解决方案架构师的会议。我们可以帮助您了解变化,然后针对如何实现这种变化与您展开合作。
https://cloud.google.com/devops -《六年的 DevOps 现状报告》,这是由一组文章构成的报告,其中深入探讨了预测软件交付表现的功能,并提供了一项快速检查来帮助您了解自己的情况以及改善方法。
站点可靠性工程:Google 如何运行生产系统 (O'Reilly 2016)
站点可靠性工作簿:实施 SRE 的实用方法 (O'Reilly 2018)
构建安全可靠的系统:设计、实现和维护系统的最佳实践 (O'Reilly 2020)
《如何将单体式应用拆分为微服务:分离什么?何时分离?》(作者:Zhamak Dehghani)
《微服务:这一新架构术语的定义》(作者:Martin Fowler)
《绞杀榕应用》(作者:Martin Fowler)