云原生反模式-全-
云原生反模式(全)
原文:
annas-archive.org/md5/a1c5690c57b9079ba10b18ae6595981d译者:飞龙
前言
健全的云原生采用方法可以成为重要的业务推动器。它可以加速创新周期,改善我们的上市时间,增强韧性,提高安全姿态,并为数据、API 和连接性提供可观察性和灵活集成能力。尽管云原生带来了诸多潜力,但本书的作者们见证了许多问题的发生,并参与了跨软件开发生命周期的纠正步骤,也有机会从零开始构建新的能力。云原生之旅不仅仅关乎技术和工具。它始于文化转型,利用正确的工作方式将我们的公司转变为学习型组织。采用还要求在治理、安全、所有权和持续改进架构与技能方面进行转变。伴随着强大的能力,责任也随之而来。本书提供了云计划往往出现问题的洞察,如何在问题开始显现时发现这些反模式,以及如何通过纠正措施推动成功的云采用。通过阅读本书,您将学习以下内容:
-
如何识别在转向敏捷云原生交付时遇到的常见反模式
-
高效的云原生交付看起来如何
-
如何发现组织中的反模式并分析其长期影响
-
如何纠正反模式的建议指南
本书面向谁
本书适用于具有信息技术解决方案基础知识并希望提升其云原生知识的以下受众:
-
云平台工程师和软件工程师
-
云或解决方案架构师
-
质量和测试工程师
-
企业架构师
-
技术团队负责人
-
工程经理
本书涵盖的内容
第一章,云原生的好处和常见误解,探讨了好处、DevOps 文化与 CI/CD、可观察性和韧性,并澄清了一些常见误解。
第二章,不明确目标和战略的成本,讨论了常见的战略错误,如外包知识或缺乏路线图和合作伙伴战略,以及如何过渡到良好的实践。
第三章,在云原生范式中重新思考治理,详细介绍了常见治理反模式,如低估文化影响和学习成本,并讨论了如何养成良好习惯。
第四章,FinOps – 如何避免账单惊吓,讨论了包括缺乏标记强制执行、专注于成本节约而非价值优化等错误。对于每个领域,我们还将解释好的实践是什么,以及如何实现它。
第五章,如何快速持续交付而不妥协安全性,分析了包括文化影响、保障措施和向左移动等问题领域。当然,我们还将探讨如何改进我们的组织。
第六章,如何实现你的安全性和合规性目标,讨论了诸如权限管理不当、供应链挑战和依赖渗透测试等陷阱。我们将一步步探讨如何转变为良好的习惯。
第七章,在应用程序代码中表达你的业务目标,探讨了与应用程序相关的反模式,例如紧耦合和有状态的应用程序,以及如何过渡到良好的习惯。
第八章,不要迷失在数据丛林中,讨论了与数据相关的反模式,包括手动数据摄取和缺乏数据可观察性,我们将帮助你采用良好的实践。
第九章,将一切连接起来,讨论了在讨论网络相关的陷阱之后,如何采纳未来-proof(未来证明)的网络架构,诸如忽视延迟或带宽、没有 DNS 策略等问题。
第十章,观察我们的架构,探讨了与可观察性相关的反模式,例如捕获一切或忽视机器学习和人工智能能力,这些都会加重我们的组织负担,我们将探讨如何改善可观察性。
第十一章,如何运行而不破坏,讨论了与操作相关的陷阱,如低估学习曲线和考虑云服务提供商(CSP)SLA。我们还将讨论采纳良好的运营实践。
第十二章,从遗留系统迁移到云原生解决方案,探讨了迁移反模式,例如缺乏规划和利益相关者承诺,或坚持使用本地安全控制,这些都会阻碍云采用的成功,我们将讨论如何避免这些不良实践。
第十三章,如何确保一切正常工作?,探讨了与测试相关的陷阱,例如未提前考虑非功能性需求或依赖人工测试,这些方法无法扩展,且会拖慢我们的进度。我们将探讨如何避免这些反模式。
第十四章,如何开始你的云原生改进之旅,讨论了如何为成功的云采用之旅做好准备,包括如何为自己和我们的组织做出规划。我们将总结如何发现反模式,并定义最佳结果。
第十五章,向云原生良好习惯过渡,深入探讨了利益相关者对齐、增强我们的路线图,并为组织设定持续改进的框架。
为了最大化本书的价值
为了充分利用本书,你需要具备一些基础的信息技术知识,无论你的背景是开发、运维、测试、技术领导、治理、安全性还是战略。此书无需你安装软件。为了跟进一些动手示例,你可以选择免费创建一个 AWS、Azure 或 GCP 的账户。
使用的约定
本书中使用了多种文本约定。
Code in text:表示文中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 账号。示例:“ WARN:当出现临时问题时,例如在向 AWS RDS 发出支付请求时发生超时,将生成一个 WARN 日志:”
代码块以如下方式显示:
WARN: Payment service timeout - user_id=12345, transaction_id=txn001, retry_attempt=1
当我们希望你注意某个代码块中的特定部分时,相关的行或项会以粗体显示:
INFO: Payment initiated - user_id=12345, session_id=abc987, transaction_id=txn001, amount=49.99
任何命令行输入或输出均按如下方式书写:
gcloud services enable cloudasset.googleapis.com
粗体:表示新术语、重要词汇或屏幕上看到的词汇。例如,菜单或对话框中的词汇会以粗体显示。示例:“ 聚合和集中日志:每个服务的日志通过 AWS CloudWatch Logs 进行集中管理。”
提示或重要说明
显示如下。
联系我们
我们总是欢迎读者的反馈。
一般反馈:如果你对本书的任何方面有问题,请通过 customercare@packtpub.com 给我们发邮件,并在邮件主题中提及书名。
勘误:虽然我们已尽一切努力确保内容的准确性,但错误还是会发生。如果你在本书中发现错误,请向我们报告。请访问 www.packtpub.com/support/errata 并填写表格。
盗版:如果你在互联网上发现任何非法复制的作品,我们将非常感激你能提供其地址或网站名称。请通过 copyright@packt.com 联系我们并提供该资料的链接。
如果你有兴趣成为作者:如果你对某个主题有专业知识,且有意向撰写或贡献书籍,请访问 authors.packtpub.com。
分享你的想法
阅读完 Cloud Native Anti-Patterns 后,我们很想听听你的想法!请 点击这里直接进入亚马逊的书评页面 分享你的反馈。
你的评价对我们和技术社区都非常重要,并将帮助我们确保提供高质量的内容。
下载本书的免费 PDF 版本
感谢购买本书!
你喜欢随时阅读,但又无法随身携带纸质书籍吗?
你的电子书购买是否与您选择的设备不兼容?
别担心,现在每本 Packt 书籍,您都可以免费获得该书的无 DRM PDF 版本。
随时随地,任何设备上阅读。可以搜索、复制并将您最喜爱的技术书籍中的代码直接粘贴到您的应用程序中。
福利不仅仅止步于此,您还可以获得独家的折扣、新闻通讯,并每天在邮箱中收到精彩的免费内容。
按照这些简单的步骤获取福利:
- 扫描二维码或访问以下链接

packt.link/free-ebook/9781836200598
-
提交您的购买证明
-
就是这样!我们会将免费的 PDF 和其他福利直接发送到您的邮箱。
第一部分:介绍与概览
本部分将概述云原生的概念及其好处。随后,我们将探讨 DevOps 文化在解决安全问题中的重要性,也被称为 DevSecOps。我们还将讨论建立自动化和可观察性能力,并澄清常见误解。本部分将解释为第二部分和第三部分所需的基础知识。
本部分包含以下章节:
- 第一章,云原生的好处与常见误解
第一章:云原生的好处和常见误解
几千年前,家庭需要挖掘并建设水井,从河流中取水,或者搭建雨水收集桶来收集水源。他们需要管理水的过滤和净化,以确保水是安全的,适合饮用及其他用途,并且需要维护这些基础设施。通过集中式市政供水系统,水供应成为了一种商品。现在,用户只需通过水龙头即可获取干净的水,并按使用量付费。
同样,云原生使得我们过去需要管理的信息技术方面变得商品化。它可以简化解决方案架构和运营复杂性,也可以使得应用程序的安全更容易,帮助我们实现合规目标。这种商品化的特性可以让我们更轻松地管理和更新数据。在之前的句子中故意使用了can一词。所有四位作者都曾在专注于云技术的专业服务机构工作。云技术提供了重大的新机会,但我们必须理解其中的风险、反模式,以及如何降低这些风险。尽管云原生带来了巨大的潜力,但我们也看到了许多令人难以置信的问题。这包括整个环境的意外删除、秘密泄露等,书中的核心部分将聚焦于此。我们经常参与修复这些应用程序,或帮助客户解决安全漏洞和数据丢失问题。当然,也有时我们参与的是绿地解决方案的工作,能够帮助避免反模式。
本书的目标是帮助我们远离这些反模式,修复它们,并朝着最佳实践迈进。在本章中,我们将阐述基础内容,后续章节将在此基础上扩展。因此,理解本章中的信息至关重要,其中包括以下内容:
-
云原生的演变
-
云原生的好处
-
DevSecOps 文化、基础设施即代码(IaC)和持续集成/持续交付(CI/CD)
-
可观察性和弹性
-
常见的误解
云原生的演变
云原生并非一夜之间发生的。许多事件促成了这一范式的变化。让我们回顾一下历史,探讨一些关键概念,这将帮助我们理解云原生。为什么它在今天被认为是必需的?我们是如何走到今天的?我们从过去中学到了什么?以下是影响我们现在所知的云原生的关键历史事件的快速回顾。我们将按时间顺序来审视这些事件,因此,我们会穿梭于硬件、软件和设计范式之间。
机器学习、人工智能和跨职能团队的基础
机器学习(ML)和人工智能(AI)如今在讨论云原生时经常被提及,许多云服务提供商(CSPs)提供了许多预打包的 ML 和 AI 服务。这一历史可以追溯很久。
1950 年,英国数学家艾伦·图灵发表了论文计算机器与智能,提出了图灵测试作为衡量机器智能的标准。美国科学家和研究人员在 1956 年达特茅斯会议的提案中创造了人工智能(AI)这一术语。
许多人将虚拟化视为迈向云原生开发的一个重要基础性步骤。虚拟化始于 1960 年代,当时 IBM 发布了控制程序/剑桥监控系统。这一系统使硬件组件的划分成为可能。例如,多个虚拟机(VMs)可以在一台物理计算机上运行,共享相同的物理处理器和内存。虚拟机允许多个用户共享硬件资源。
1967 年,梅尔文·爱德华·康威提出了一种名为“康威定律”的理论。该理论描述了互相交互的软件组件的设计师们必须互相沟通的现象。康威用以下名言总结了这种行为:“设计系统的组织(在此广义上所用)被约束于产生这些组织沟通结构的设计的复制品。”这是一个重要的发现,影响了我们今天如何构建团队。我们使用诸如小组、敏捷团队和 DevOps 这样的术语。我们知道,必须建立跨职能团队,并在协作中表现出色,以交付适合云计算的解决方案。
虚拟化时代
IBM 在 1980 年继续开发进一步的增强功能。然而,当时市场还没有准备好广泛商用虚拟机。个人计算机在 1980 年代开始流行,减缓了虚拟机市场的发展。直到 1990 年代末,虚拟机才开始成为主流。VMware 是市场的领导者之一。
分布式应用的开始
一种新的设计范式——面向服务架构(SOA)应运而生。它引入了服务的概念并推动了可重用性。SOA 常被视为微服务的前身。与此同时,一家名为亚马逊的小书店意识到,他们需要改变架构,以一种具有未来保障的方式进行扩展。亚马逊的一群聪明工程师发布了内部出版的分布式计算宣言,解释了我们的应用架构需要能够扩展,以应对比当时规模大 10 倍的需求。该论文指出,应用程序不应紧密耦合。它解释了基于服务的模型,并提出了一种三层架构,分别用于表示层(也称为客户端或应用)、业务逻辑和数据。
它还描述了在需要立即响应时应使用同步操作。对于不要求立即结果的工作流,可以使用异步调用。工作流只需推进到下一阶段。异步 API 调用在亚马逊的订单处理流程中显得非常合理。Amazon Web Services (AWS) 在几年后以新品牌推出。第一个公共 web 服务发布,首次公开推出的是一个名为 Simple Queue Service (SQS) 的消息队列服务。
队列哲学与 分布式计算宣言 完美契合。Elastic Cloud Compute (EC2) 作为虚拟化服务,以及名为 Simple Storage Service (S3) 的 Blob 存储服务接踵而至。S3 成为云原生历史演进中的一个重要里程碑。2000 年,Roy Fielding 在其博士论文 网络基础软件架构的架构风格与设计 中定义了 REST 架构。REST 旨在支持可扩展的客户端-服务器应用程序。REST 提出,客户端与源服务器之间的耦合应尽可能松散。在 REST API 的上下文中,“无状态”意味着从客户端到服务器的每个请求都必须包含所有必要的信息,以便理解和处理该请求,而不依赖于服务器上存储的任何上下文。这确保了服务器在请求之间不会保留任何会话状态,从而实现可扩展性和可靠性。
敏捷、DevOps 和云的崛起
2001 年,17 名软件工程师在犹他州聚集,制定了敏捷软件开发的价值观和原则。这些工程师中的一些人成为了著名的敏捷开发倡导者,包括阿里斯泰尔·科克本、马丁·福勒和肯特·贝克。通过这次聚会,他们创建了 敏捷软件开发宣言,通常被称为 敏捷宣言。该宣言强调了在软件开发工程团队和客户之间,个人和协作的重要性,以更高效地交付更好的软件。协作方面解决了在康威定律中描述的一些问题。这种跨职能团队的方式至今仍然嵌入大多数敏捷交付框架中。
Google Cloud Platform (GCP) 和微软的 Azure 云平台于 2008 年推出。就在同一年,谷歌发布了 App Engine,这是最早的无服务器计算服务之一。它包括带有 60 秒超时的 HTTP 函数以及带有超时设置的 Blob 存储和数据存储。
在这一十年中,合作的需求变得愈加明显,软件行业的专家指出了将开发与运维分开所带来的问题。
DevOps 这个术语应运而生。第一届 DevOpsDays 大会于 2009 年在比利时举行。在最初的阶段,DevOps 关注的是 持续集成/持续交付 (CI/CD) 和基础设施自动化。
边缘计算——微服务,以及解决安全问题
2010 年,边缘计算变得越来越重要,尤其是在物联网(IoT)领域。边缘计算是云计算的扩展,它将云基础设施的入口点更接近消费者。一些关键的好处包括延迟减少以及提高系统的韧性和可靠性。边缘计算的使用场景自那时以来发生了变化。例如,内容可以被缓存到离最终用户更近的地方。这种缓存方法被称为内容分发网络(CDN)。知名的 CDN 解决方案由 Cloudflare、Akamai 和三大云平台(AWS、GCP 和 Azure)提供。
2011 年,微服务一词在软件工程界流行起来。微服务通过强烈关注持续增量变更以及服务和端点之间的轻量级通信,增强了面向服务架构(SOA)。有时,人们将微服务与云原生这两个术语交替使用。我们将在探讨常见误解时深入讨论这一点。
Heroku 的工程师在那个时期还开发了 12-Factor App 方法论。12-Factor App 原则为构建可扩展和可维护的软件即服务(SaaS)应用程序提供了最佳实践指导。它们强调声明式配置、与底层操作系统的清晰契约,以及在执行环境之间的最大可移植性。一些关键原则包括将配置与代码分开管理,将后端服务视为附加资源,以及严格分离构建、发布和运行阶段。
在 2012 至 2013 年之间,DevSecOps一词被越来越多地提及。它被视为 DevOps 的扩展。DevSecOps 提倡在软件开发过程中尽早嵌入安全性,自动化安全测试,并在团队之间倡导共享安全责任的文化。
容器和功能即服务
2013 年,Docker 容器发布。虚拟机(VMs)和容器之间的主要区别在于,虚拟机提供了物理机器整个硬件的抽象版本,包括 CPU、内存和存储。另一方面,容器是软件的便携实例。容器无法感知主机操作系统上运行的其他进程。
Google 大约一年后发布了 Kubernetes,它是一个容器编排平台。Kubernetes 至今仍广泛用于容器的扩展、容器管理、可扩展性和自动化部署。
第一个函数即服务(FaaS)功能是在 2014 年发布的。AWS 发布了 Lambda 函数。后来,其他 CSP 也采纳了 FaaS,如 Microsoft 的 Azure Functions 和 GCP 的 Google Cloud Functions。FaaS 提供一个完全托管的运行时环境,我们只需要管理我们的代码。这是一个根本性的转变,使得 DevSecOps 从业人员能够专注于区分他们组织与其他组织的工作,包括应用程序代码和架构设计。我们只需在函数运行时付费,当函数未被调用时没有任何费用。
服务网格的概念也是在那时引入的,它是一个专门的基础设施层,用于监控、管理和保护云原生应用程序中微服务之间的网络通信。
云原生和最佳实践
云原生计算基金会(CNCF)是一个 Linux 基金会项目,始于 2015 年。两年后,在 2017 年,Google、IBM 和 Lyft 开源了流行的服务网格实现 Istio。
2018 年,国家标准与技术研究院(NIST)和国家网络安全卓越中心(NCCoE)的研究人员发布了零信任架构(ZTA)框架。它描述了一种“永不信任,总是验证”的方法。这要求对每个尝试访问资源的设备和人员进行严格的身份验证,无论其位于网络内部还是外部。ZTA 现在在云原生架构中变得越来越重要。它被视为减少数据泄露风险并执行最小特权访问方法的可靠方式。
OpenTelemetry 是一个开源的可观察性框架。它是在 2019 年 CNCF 合并了 OpenCensus 和 OpenTracing 两个项目时创建的。它的目的是收集追踪、指标和遥测数据。OpenTelemetry 通常用于监控微服务和其他分布式应用程序。
FinOps 基金会于 2019 年成立,并在 2020 年成为 Linux 基金会的一个项目。它致力于“通过最佳实践、教育和标准,推动实践云财务管理学科的人群。”
在 2020 到 2012 年间,GitOps 从 DevOps 演变而来。它是一种使用 Git(分布式版本控制系统)作为基础设施和应用配置的真实来源的 CD 实践。
2023 年,Open Policy Agent(OPA)作为一个安全框架出现在 Kubernetes 社区中。它解决了多个使用案例,包括 REST API 端点调用的授权、将自定义授权逻辑集成到应用程序中,以及为云基础设施管道提供基于代码的策略框架。它此前是一个 CNCF 孵化项目。
同样在 2023 年,ML 和 AI 集成的趋势开始出现。主要的 CSP 发布了他们的托管服务,包括 Google 的 AI 平台、Amazon SageMaker 和 Azure ML。
我们现在处于什么阶段,未来将带来什么?
许多描述的框架和最佳实践将在 2024 年继续流行。最大的趋势之一是嵌入式 AI 服务,涵盖生产力、运维和安全性。在讨论云原生的好处之前,让我们先来看一些例子。
运维中的 AI(AIOps)提供预测性洞察、异常检测和自动化响应。云原生应用保护平台(CNAPP)解决方案正席卷全球。它们在软件开发生命周期(SDLC)的各个阶段,从开发到运维,提供全面的保护和合规性验证。帮助开发人员并提高生产力的聊天机器人和其他生成式 AI 服务也在迅速流行。
AI 趋势包括 OpenAI 的 ChatGPT、微软的 GitHub Copilot、AWS Code Whisperer、Amazon Q 和谷歌的 Cloud AI 与 Vertex AI 等技术。关于生成式 AI 服务存在法律方面的顾虑。其中一个问题是我们的敏感数据可能会被用来训练 AI 模型。主要的顾虑是数据是否会暴露给第三方,以及数据是否会保留在我们的地区,这可能是合规性要求。另一个问题是知识产权归属。如果生成式 AI 服务生成了基础部分,而人类对该生成结果进行了增强,结果的归属应该归谁?不同的法域有不同的法律,而且由于这是一个相对较新的问题,常常存在灰色地带。这些问题的讨论可能会持续一段时间。
我们现在对促成云原生概念的重要事件有了较为清晰的认识。但云原生的实际好处是什么?为什么它对现代架构如此重要?我们将在下一部分进行探讨。
云原生的好处
什么是云原生?有很多不同的定义,针对本书的上下文,我们将采用 CNCF 的定义:
“云原生技术,也称为云原生技术栈,是用来构建云原生应用的技术。这些技术使得组织能够在现代和动态的环境中,如公共云、私有云和混合云,构建和运行可扩展的应用,同时充分利用云计算的优势。它们从一开始就设计用来发挥云计算的能力,容器、服务网格、微服务和不可变基础设施体现了 这一方法。”
根据 Gartner 的说法,“云原生”这一术语指的是“旨在最佳利用或实现云特性的做法”。这里的关键短语是“最佳利用或实现云特性”。这一领域恰恰是我们看到许多大型组织出错的地方。很多时候,他们将云当作与他们数据中心相同的东西来处理。我们将在接下来的章节中深入探讨这一点,详细介绍反模式。
更快的市场时间
让我们从第一个关键好处开始:更快的市场时间。这是许多初创公司开始使用云原生服务的关键驱动因素之一。那些初创公司没有遗留系统,需要快速展示成果,以获得风险投资并创造增长收入流。开发者可以利用自助式资源供应,相比于传统机制需要请求基础设施部署的方式,这节省了大量时间。
采用云原生方法,他们可以快速创建新的环境或无服务器功能。根据资源类型,供应可能需要几秒钟或几分钟。数据库供应通常需要几分钟,而像 Amazon S3 桶或 FaaS 这样的 Blob 存储可以在几秒钟内部署。这有助于实现更快的市场时间目标,也有助于更快的创新周期。如果我们想进行概念验证,比较使用不同编程语言的生产力,使用 FaaS 可以节省大量时间,因为运行时已经由我们的 CSP 预先配置。尝试在 Golang 中运行一些函数,或在 Rust 或 Java 中运行其他函数非常简单。供应和退役的工作量很小,开发人员可以专注于应用程序开发,而不需要等待。
可扩展性和弹性
可扩展性和弹性基础设施是其他好处。应用程序可以根据需求轻松地扩展或缩减。云原生架构通常利用水平扩展而非垂直扩展。这对于流量有显著波动的应用程序,如购物网站或支付应用程序,是一个很大的优势。它们需要在白天的高峰时段或季节性高峰时段进行扩展。一旦流量激增减少,我们可以自动缩减底层基础设施。
这与传统的本地部署方式有很大的不同,在传统方式中,我们需要永久性地为最高的流量量预留资源以避免停机。而云基础设施是弹性的,定价模型在某种程度上也是如此。例如,如果我们在扩展事件后处置计算实例,我们将不再为其付费。然而,如果我们存储数据却没有删除它,我们仍然需要支付存储费用。
管理服务
托管服务由云服务提供商(CSP)管理,它们提高了客户的操作效率、可靠性和可用性。因此,它们是云原生架构中的一个重要优势。CSP 管理托管服务的基础设施。根据服务的不同,这可能包括应用程序本身,例如队列或通知应用程序。托管服务包括资源的配置、维护和网络结构。如果我们使用托管关系型数据库服务,如 Amazon 关系型数据库服务(RDS)、微软 Azure 数据库或 Google Cloud 数据库,CSP 将负责底层基础设施的修补和升级,包括数据库引擎。托管数据库服务还会执行符合行业规定的安全性和合规性,直到数据库层级。客户则负责该层之上的安全性,例如数据加密。我们企业实现商业价值的方式并不会受到如何修补数据库或运行虚拟化管理程序的影响。托管服务抽象化了大量操作开销,这使得我们能够专注于业务区分点,如应用逻辑和数据提供。托管服务通常提供监控和报告功能,例如 FaaS 的调用方法。托管数据库或数据存储服务通常提供开箱即用的备份和恢复机制。托管服务可以自动扩展,并具备内置的成本管理和优化功能。
安全性与合规性
云原生架构的进一步安全性和合规性优势包括统一的访问控制。基于角色的访问控制(RBAC)、基于属性的访问控制(ABAC)和身份与访问管理(IAM)服务确保我们能够实施最小权限原则。默认启用的加密机制可确保数据在传输和静止状态下得到保护,从而确保客户数据始终可以加密,这是一种最佳实践,并且在许多受监管行业中也是强制要求的。
还内置了安全特性,例如DDoS(分布式拒绝服务)保护、防火墙、网络访问控制列表(NACLs)和安全信息与事件管理(SIEM)工具。大多数 CSP 还支持多因素认证(MFA)和单点登录(SSO)。实施这两个控制通常是内部安全要求。MFA 也是一些监管要求强制的,例如支付卡行业数据安全标准(PCI-DSS)。SSO 集成使得集中管理人类和机器的访问权限变得更加容易。这种集中化的方式减少了运营工作量,并有助于满足合规性要求。
云原生还提供了预防性和侦测性护栏,这对于保护我们的团队免受某些人为错误至关重要。预防性护栏确保某些特定操作,如删除备份库,永远无法执行。侦测性护栏仍允许某些操作,但如果发生特定事件,它们可以发送通知,并且可以在仪表板上可视化发现。例如,我们希望查看开发环境中是否有任何未加密的数据库。我们可以通过预防性护栏强制对测试或生产等更高环境进行加密。侦测性护栏还可以触发现有云资源的自动修复。如果某个 Blob 存储没有启用访问日志记录,自动修复可以执行该更改。自动化漏洞扫描是许多云服务提供商(CSP)提供的另一项功能。它们帮助扫描虚拟机、容器、FaaS 代码和网络。这些扫描工具通常提供带有发现和修复建议的报告。
可靠性与可用性
云原生应用程序还有其他的可靠性和可用性优势。异常检测服务帮助检测由于缺陷导致的可疑用户行为或异常系统行为。它们有助于在早期阶段识别事件。部署架构可以轻松利用一个地理区域内的多个独立位置。可用区(AZ)彼此物理隔离,具有独立的电源供应和连接性,但区域内有高速互联。一个区域可以是悉尼或新加坡。独立的位置称为可用区(AZs)。术语AZ在不同的云服务提供商(CSP)中有不同的含义,但目前这个定义对我们来说已经足够了。最佳实践是将我们的应用架构设计为利用多个可用区,理想情况下是我们所在区域内的所有可用区。多可用区部署有助于从一个可用区自动故障转移到另一个可用区。在一个可用区发生故障时,其他可用区可以分担负载并响应传入的请求,如 API 调用。这个故障转移是一个内置功能,但应用程序需要正确架构,以便利用这些优势。我们甚至可以将应用程序部署到多个区域。在极不可能发生的区域完全故障的情况下,第二个区域可以承载全部负载并响应传入请求。区域完全故障的可能性非常小。因此,这种用例比全球部署的其他用例要少见。
区域性故障是我们想要讨论的下一个优势的引入。
全球部署
通过全球部署,对于在多个国家甚至全球运营的组织来说,这使得在部署架构中处理这些问题变得更加容易。全球部署能够减少客户设备与应用程序之间的延迟。我们可以利用 CDN,这样可以将数据缓存更靠近客户,并且如果客户不在我们的地理区域内,这会非常有帮助。例如,假设我们的应用程序托管在澳大利亚东部的悉尼,而我们的客户位于距离 4,000 公里外的澳大利亚西海岸。在这种情况下,我们可以利用 CDN 将可缓存的信息存储在位于西海岸的珀斯。这些分布式位置称为边缘位置。我们甚至可以在边缘位置上运行某些形式的身份验证,以减少登录过程的延迟。这个额外的缓存层提高了内容的可用性。它还可以减少带宽成本,因为需要由源服务器提供的数据量减少,因此,我们的出站数据费用会较低。我们还可以有可能缩减我们提供的基础设施。CDN 可以处理大规模的流量峰值,因此,它们可以防止 DDoS 攻击。
另一个全球部署的驱动因素可能是合规性要求,例如数据主权法。对于受监管的行业,如金融服务或健康服务,客户数据必须存储在原始地区。例如,美国公民的数据必须存储在美国境内,欧洲客户的数据必须存储在欧盟境内。通过全球部署,部署应用程序到不同地区变得更加容易。应用程序将把数据存储在该地区并保持在那里。通过 CDN,我们还可以使用云原生的地理限制。我们可以将内容限制在特定的大陆或国家,通常可以定义允许和拒绝列表。这些地理限制就是为什么某些媒体内容在其他国家不可用。电子商务平台通常也会全球部署其应用程序。这样,他们可以为每个地区提供不同的产品目录,并享有所有的可靠性和可用性优势。全球部署的低延迟也是它们在游戏或大型物联网解决方案中普遍应用的原因。全球部署的另一个应用场景是灾难恢复(DR)。数据可以在不同的地区进行备份,以提高业务的弹性。
CI/CD – 自动化一切
云原生通常提供 CI/CD 的自动化功能。它们能够实现应用程序的自动构建、测试和部署。
在使用 CI/CD 时,每次变更都经过一个受控的流程,其中应包括同行审查代码变更。由于一切都是基于代码的,临时创建新环境的工作量非常低。在其他地区创建环境或拆除临时环境也很容易。自动化有助于缩短上市时间、提升变更管理过程的鲁棒性、实现环境间的一致性、提高安全性和可靠性,并帮助降低成本。
成本效益与范式转变
将我们的应用托管在云端而不是本地部署,意味着成本模式从前期资本支出(CapEx)投资转变为按需付费模式。我们不再每五年进行大规模的基础设施投资,而是会在云端持续产生支出。
一些前面提到的功能,如自动扩展和自动化,有助于在云中进行成本优化。但还有更多本地功能。每个云资源都应该有标签。标签是描述资源的元数据。常见的标签包括环境、数据分类、成本中心和应用所有者。标签可以用于成本拆解或安全控制。本地成本仪表板提供成本洞察,并根据标签、地区或资源类型(如虚拟机或托管 API 网关)提供不同的视图。成本仪表板解决方案包括 AWS 成本资源管理器、Google Cloud Billing Reports 和 Azure 成本管理与账单。
我们还可以设置预算,确保如果预计支出超过预期支出时会收到通知。我们可以手动定义预算,或者使用内建的人工智能功能来设置预算值。人工智能组件通常需要几天时间来了解常见的支出高峰和低谷。大多数云服务提供商(CSP)也提供资源优化建议服务。该服务帮助减少因客户过度配置资源(如虚拟机或数据库)而产生的费用。CSP 还提供承诺支出计划,如果我们承诺在一年以上的时间内达到一定支出额,还能获得折扣。
可移植性
云原生还带来了一些可移植性好处。容器和编排工具如 Kubernetes 促进了标准化的配置和部署过程。一个容器托管的应用可以轻松迁移到不同的 CSP。云原生解决方案是混合云兼容的,并且可以与我们的数据中心集成。混合部署在大规模应用迁移中非常普遍,特别是在从本地部署到云端的迁移过程中,这一过程通常会持续很长时间。通常,应用的前端部分首先迁移到云端,从 CDN、API 和用户界面等组件开始。对于需要低延迟和减少抖动的场景,我们可以使用云原生连接服务。这些连接服务要求我们的数据中心位于 CSP 的一个共址位置,并且数据中心的基础设施需要发生变化,例如新的电缆连接等。例子包括 GCP Cloud Interconnect、AWS Direct Connect 和 Azure ExpressRoute。
云原生架构提供了许多好处。然而,我们仅仅触及了云自动化的皮毛,甚至还没有讨论文化层面的内容。现在让我们来探讨这个话题。
DevSecOps 文化、基础设施即代码(IaC)和持续集成/持续交付(CI/CD)
在云原生的演进一节中,我们讨论了康威定律、敏捷宣言、敏捷软件开发的崛起以及 2009 年的第一次 DevOps 大会。那么,DevOps 到底是什么呢?
文化层面
DevOps是开发和运维的跨职能组合。其主要特点包括共享所有权、工作流自动化和快速反馈。DevOps 利用文化行为、实践和工具来自动化开发和运维,从而改善端到端的 SDLC。其目标是提高软件质量并缩短从提交变更到生产环境的时间。DevOps 主要关乎文化,因此它会影响软件工具链。DevOps 采纳中的文化变革往往被低估。让我们详细讨论这些影响,以便理解为何会出现这种情况。
DevOps 的采纳意味着不同学科的人员共同协作,我们称之为跨职能团队。两块披萨团队结构是亚马逊的杰夫·贝索斯在 2000 年代初提出的一种策略,旨在通过确保团队足够小到只需要两块披萨就能满足其需求,来保持团队的小巧和高效。这种方法促进了团队内部更好的沟通、敏捷性和生产力。你构建它,你运维它的理念促进了业务敏捷性,使团队能够更快反应并创新交付客户价值。这也带来了高质量的成果,因为人们被激励避免发生会让他们被召集处理的事件。这些应该已经听起来很熟悉了。现在让我们来看一看在加入安全性因素之后,会是什么样子。
DevSecOps
成熟的 DevSecOps 文化采用Shift-Left方法。功能性和非功能性的质量控制在软件开发生命周期(SDLC)初期就开始执行。Shift Left意味着测试活动(如需求定义和设计)开始得早,因此测试人员能够提前参与。测试通常会高度自动化,包括单元测试、集成测试、非功能性测试、回归测试、合同测试等。静态代码分析工具有助于分析代码质量。
DevSecOps增强了 DevOps,并建议在软件交付过程中嵌入安全性。这使得开发团队能够生产满足安全和法规要求的高质量变更。DevSecOps 将安全工具集成到 CI/CD 工具链中。此集成包括静态应用安全测试(SAST)工具,用于分析源代码中的漏洞。软件组成分析(SCA)是对定制源代码的分析,用以检测嵌入的开源软件或库,并验证它们是否是最新的且没有安全漏洞。其他常见的安全扫描包括秘密扫描,以确保代码中没有嵌入安全密钥或密码。漏洞扫描检查机器镜像、容器镜像和源代码中的常见漏洞和暴露。这些扫描变得越来越重要,因为供应链攻击的激增。供应链攻击利用第三方工具或服务渗透系统或网络。
有许多新兴趋势与Ops相关。其中一个备受关注的是AIOps,它提倡利用 AI 技术并将其嵌入 DevSecOps 方法中,以便及早识别异常和可疑行为。因此,我们希望看到交付和运营的改进,接下来我们将探讨这一点。
衡量进展
DevOps 研究与评估(DORA)团队发布了 DORA 指标,其目的是衡量并提高软件开发过程的性能和效率。提供可操作的见解有助于识别瓶颈并改进过程。四个关键的 DORA 指标如下:
-
变更的交付时间(LTFC)是从第一次代码提交到部署的时间。较短的交付时间意味着可以更快地交付业务价值。
例如,我们可以跟踪开发者从提交更改到发布到生产环境的时间。平均而言,这需要 24 小时,这使得公司能够迅速响应市场需求和用户反馈。
-
部署频率(DF)是指在给定时间段内的部署次数。高频率表示能够交付新功能和修复 bug,并响应客户需求。
例如,我们每周发布两次移动应用更新。这种频繁的部署有助于快速将新功能和错误修复交付给用户,确保应用保持竞争力和用户友好。
-
更改失败率 (CFR) 是所有更改中失败更改的百分比。较低的比例表示发布的质量和稳定性较高。
例如,在一个月的 50 次部署中,5 次由于错误或问题导致回滚或需要热修复。这为我们的组织提供了 10% 的 更改失败率 (CFR),突出了他们的测试和审查过程中的改进空间。
-
恢复时间中位数 (MTTR) 衡量从系统故障中恢复所需的平均时间。较短的 MTTR 表示能够从事件中快速恢复。
应对文化挑战
现在我们已经了解了 DevSecOps,我们可以看到其采纳并非易事。需要考虑的因素很多。从瀑布式软件开发方法入手将会是一个陡峭的学习曲线。相当一部分人对文化变革有一定的抵触。如果一个组织被划分为孤岛,它将需要一段时间才能打破这些障碍。DevSecOps 需要更多的协作和更广泛的技能。因此,提供足够的培训至关重要。培训将是获得云原生知识所必需的,包括用于构建、测试和部署代码的工具。
正如 DevSecOps 中的术语 Ops 所暗示,团队还负责应用程序的运行。因此,团队有动力发布高质量的代码,以确保他们不需要解决太多的故障。这种拥有感方法是与传统方法的一个重要区别,在传统方法中,开发和运维是分开的。这也意味着团队成员需要具备构建可观察性能力并响应事件的技能。学习这些内容将需要培训,这可以是课堂培训、在线培训课程和结对编程的结合。提供用于实验和创建概念验证的学习环境对于提升团队技能也非常有效。这些环境通常被称为 沙坑 或 沙箱。我们在这里使用 开发者 一词,因为他们可能会编写应用程序、测试、基础设施或配置代码。但这个术语可以与工程师、软件工程师、全栈开发者等互换使用。
组织可以通过不同的方式推动文化变革。自上而下意味着变革举措从领导层开始,而自下而上意味着它从交付团队开始,最终到达管理层和领导层。为了成功采用 DevSecOps,我们需要获得领导层的支持。否则,所需的文化变革将无法实现。当 DevSecOps 首先在已经采用敏捷交付方式的部分组织中进行时, adoption 过程通常会更为成功。这些团队会更容易体验到 DevSecOps,过一段时间后,他们可以开始进行集体合作。这意味着团队成员可以被扩展,并且可以作为其他团队的导师。如果我们刚开始转型旅程,寻求 DevSecOps 咨询公司提供外部帮助是非常有益的。外部顾问可以指导团队,贡献代码库,并确保最佳实践得以应用。为了确保 DevSecOps 旅程的成功,顾问们必须将知识转移给内部开发团队。
IaC
源代码是每个云原生解决方案的真相来源。负责基础设施的人通过基础设施即代码(IaC)创建基础设施或模式。IaC 在代码中定义了诸如网络构件、服务器、策略、存储和 FaaS 等组件。
云原生 IaC 与云无关 IaC 的区别
CSP 提供了自己的 IaC 技术,也有一些第三方产品是平台无关的:
-
云原生 IaC:
CSP(云服务提供商)为其平台提供了自己的 IaC 服务,包括 AWS CloudFormation、Azure Resource Manager(ARM)和 Google Cloud Deployment Manager。这些服务带有自己特定的 IaC 语言。与 Golang 或 Java 等高级编程语言相比,IaC 语言较为简单,可以快速学习。简洁性对有着强大基础设施背景的人非常有利,即使他们并不一定有太多的编码经验,除了 Bash 或 PowerShell 脚本之外。
-
平台无关的 IaC:
也有一些 IaC 工具使用一种通用语言来部署到多个云平台和本地平台。Terraform 是一个流行的 IaC 工具,可以部署到所有主要的 CSP 以及数千个其他平台,包括协作平台、防火墙、网络工具和源代码管理工具。Terraform 曾是开源的,但当它在 2023 年转为商业源许可证时,社区迅速作出了反应。代码库被分叉,一个名为OpenTofu的新开源项目成立了。
听起来,IaC 有潜力带来显著的优势,接下来我们将讨论这些优势。
IaC 的优势
通过 IaC 定义云资源有什么优势?每当我们重复部署某些东西时,例如临时或新的测试环境,架构和部署方式将始终保持一致,且这种方式易于重复。通常,我们会为不同的环境使用不同的参数,例如为不同的网络段使用不同的 IP 范围,或者为非生产环境使用更小的自动扩展组。其余的代码保持不变。因此,IaC 在实现可扩展性或实施全球部署方面也非常高效。配置和代码都在 Git 中进行版本控制。因此,回滚到以前的版本非常容易。
如果我们希望生产环境比开发环境滞后,版本固定(version pinning)也可以很容易地使用。基础设施即代码(IaC)还帮助实现良好的灾难恢复响应时间。我们可以通过 IaC 和 CI/CD 技术,完全自动化灾难恢复环境的构建,而不是手动或半手动地构建新的灾难恢复环境,这一点我们稍后会详细讨论。IaC 还帮助满足安全性和合规性要求。安全性要求嵌入在代码中。例如,如果我们只允许 HTTPS 流量,我们的代码将只开放端口443,然后我们将在源代码中明确这一点。作为最佳实践,代码会经过同行评审,以确保我们满足要求。在重新部署时,我们可以确信不会暴露我们的应用程序,因为部署将提供一个可重复的结果。所有更改都在 Git 中进行跟踪,有助于审计和合规性。一些监管框架要求采取可重复的方法,这正是 IaC 所建立的。此外,IaC 还有成本效益。由于创建和销毁资源非常简单,它有助于避免过度配置。如果测试环境不再需要,那么可以在不需要时轻松关闭资源。如果我们采用完全无服务器的方式,就不需要过多担心这个问题。我们稍后会在讨论策略时谈到这一点。
我们如何部署通过 IaC 定义的云资源?我们如何构建和部署我们的应用程序代码?我们如何以自动化的方式执行所有功能和非功能测试?答案就是 CI/CD,我们现在就来探讨它。
CI/CD
CI/CD 是持续集成(Continuous Integration)和持续交付(Continuous Delivery)的结合,有时也称为持续部署(Continuous Deployment)。主要的区别在于,持续交付需要手动审批步骤,而持续部署在代码更改后会自动部署。CI/CD 弥合了开发和运维之间的差距。在构建过程、功能和非功能测试以及部署过程中,它强制执行自动化。
定义结构
CI/CD 过程有很多种结构方式,甚至有更多工具组合。微调将很大程度上取决于组织和监管需求。我们将采用一种标准结构,在这种结构中,我们希望采用“左移”方法。以下图表帮助我们逐步了解这一过程:

图 1.1 - 简化的概念性 CI/CD 过程
这个过程从开发者使用首选的集成开发环境(IDE)开始。有时候,开发者仅使用命令行工具。然而,IDE 通常被广泛使用,因为它们提供了实用的内置功能和插件架构。这种架构支持安装扩展或插件。Visual Studio Code 是由微软开发的流行开源 IDE。尽管该软件是开源的,但可用的扩展未必是开源的。IDE 通常具有内置的 Git 集成。然而,我们可以安装一个额外的扩展来可视化 Git 仓库和 Git 分支。
Git 分支与左移
Git 分支是为新变更创建的代码仓库的独立版本。有不同的分支模型,比如基于主干的开发或功能分支。我们将在第五章中详细讨论这一点,作为我们的示例,我们将使用功能分支模型。当开发者想要将变更提交到仓库时,重要的是要基于仓库中的最新版本进行操作(仓库的简称为 repo)。因此,需要使用git pull命令来确保本地副本是最新版本。之后,开发者创建一个新的功能分支并更新代码。现在可以自动运行许多检查,以提供早期反馈。例如,一个安全扩展可以扫描代码并识别潜在的弱点。例如,如果代码是一个定义了公共 Amazon S3 桶的 Terraform 模板,那么插件可以提供反馈,提醒该桶应该是私有的。S3 桶是 AWS 中的二进制存储构造,配置错误的 S3 桶已成为许多数据泄露的原因。这种早期反馈就是“左移”的例子,开发者可以在代码通过 CI/CD 管道验证之前修复代码。代码格式化、代码检查和语法验证通常在客户端运行。一旦开发者对更改满意,代码就会提交到 Git 仓库。
可选地,一个提交可以触发预提交钩子,执行我们刚才描述的步骤。它还可以自动生成文档。
批准与部署
开发人员随后提交拉取请求(PR)。有人会进行同行评审。如果代码符合预期,PR 会被批准。然后,代码会被合并到主分支。合并将触发管道运行。最初,会有一些验证步骤,类似于开发人员已经运行过的步骤。但我们希望确保某些验证是强制性的,并且不依赖于个人。接下来,构建过程将启动,并运行一些静态代码分析、功能性和非功能性测试以及进一步的安全扫描。一旦管道运行成功,授权人员可以触发部署。这些步骤是 CI/CD 管道的一个简单示例。
我们可以看到自动化这些步骤的许多好处。为一个组织构建所需的管道需要一些时间,但一旦它们建立起来,开发过程变得更加迅速、可靠和安全。但我们如何验证它是否按预期运行呢?让我们来看看。
可观察性与弹性
我们已经涵盖了云原生解决方案的许多方面,包括文化影响、跨职能团队、DevSecOps 文化和工具复杂性。现在我们将研究可观察性和弹性,这两个在云原生解决方案的早期设计阶段需要更多关注的领域。
如果我们没有建立全面的可观察性,我们就无法知道是否达到了目标,例如响应时间。如果我们失败了,我们也无法知道瓶颈在哪里。因此,我们需要制定全面的日志记录、监控和可观察性策略。承受故障的能力也是如此。我们需要洞察力来验证我们的部署架构是否符合弹性预期。我们将探讨这两个方面,从可观察性开始,并在云原生环境中了解其含义。我们无法修复我们看不见的东西。可观察性帮助我们深入了解应用程序的内部状态,并通过评估输出进行度量。
日志记录 – 可观察性的推动者
日志是监控和可观察性的关键推动者。日志的范围非常广泛,可以包括操作系统日志、访问日志、应用程序日志、基础设施日志、网络流量日志、域名服务(DNS)日志等。日志使得监控、警报、调试、事件发现和性能优化成为可能。在本章前面,我们已经阐明,典型的 DevSecOps 团队(即产品小组)编写代码并管理他们的应用程序,也称为“产品”。因此,该团队将有动力建立良好的可观察性实践和工具。
当团队在开发和运维之间具备良好的技能和经验混合时,可以实现良好的成熟度水平。拥有运维经验的人员了解可观察性的重要性。具有软件工程背景的人也会看到可观察性的重要性,尤其是在应用层。
然而,有时候,其他层级,如网络层或操作系统层,需要更多的关注。获取涵盖所有层级的整体视图对于深入了解我们的系统至关重要。能够关联数据也至关重要。例如,如果我们有一个混合云应用,一个业务事务可能从 CDN 开始,经过 API 层,然后写入云托管的队列,在那里本地的业务逻辑从队列中拉取数据并将其写入本地托管的数据库。
此外,还有一个本地防火墙,它检查所有进来的流量。这个架构很复杂,但也很常见。如果我们有服务级别协议(SLAs),我们不仅需要衡量端到端的事务时间,还需要在可能无法满足这些 SLA 的情况下识别瓶颈。问题可能出现在整个流量路径的任何地方。良好的洞察力将帮助我们确定瓶颈。收集所有这些日志会带来另一个挑战。因为我们知道需要收集所有相关日志,很容易陷入过度收集的陷阱,从而导致告警疲劳。我们将在第十章中探讨典型的反模式,并讨论如何解决这些陷阱。
日志质量
一致性、标准化和良好的日志信息质量是有用的仪表板和有意义的告警的基础。
为了实现这一目标,需要考虑几个方面。我们需要就要记录的严重性级别达成一致。并非所有严重性级别都需要始终记录。例如,调试级别应该仅在我们调试时记录。如果我们不明智地决定在何时使用什么严重性级别,以及哪些级别需要记录,我们将会得到不一致的日志文件。而且,很可能我们会记录过多的内容。这意味着我们需要更大的日志文件索引器,从而增加运营开销。日志量的增加使得在发生事故时更难找到相关信息,尤其是在没有标准化日志结构的情况下。
因此,我们还需要定义日志文件中捕获的信息,以及其顺序和结构。像 JSON 这样的结构化数据格式有助于实现这一点,并且有助于包含键值对以提供上下文。日志条目可以包括一个 userID 或 sessionID 的键,以及实际的 ID 作为值。日志条目还应包含在故障排除过程中其他有用的上下文信息,例如时间戳、事务 ID 和关联 ID,以便跟踪和关联微服务之间的请求。我们不应在日志文件中存储敏感信息,如信用卡详细信息、客户姓名和地址。某些监管框架,如 PCI-DSS,规定了不能存储在日志文件中的数据类别。集中式日志记录还将有助于找到数据关联,因为来自 API、数据库和基础设施事件的日志将保存在相同的存储中。流行的开源日志工具包括 Logback、Graylog 和 Log4j。后者因 2021 年的 Log4 Shell 漏洞而广为人知,该漏洞使黑客能够控制运行未打补丁版本的 Log4j 的设备。因此,我们应该始终保护自己免受漏洞攻击,我们将在第六章中详细讨论这一点。一些服务网格解决方案,如 Istio 或 Linkerd,开箱即用地提供日志、指标和追踪。
那么我们还需要考虑日志的哪些方面?我们需要确保只有授权的个人和系统可以访问日志文件。如果它们包含敏感信息,则需要加密。然而,我们需要与适用的监管框架和内部安全政策进行核实,以查看是否允许这样做。如果我们的源代码包含递归,我们应确保相同的异常或错误不会被多次记录。我们还必须考虑日志文件的数据保留策略,以避免账单冲击。一个合理的日志记录方法将能够提供良好的监控和可观察性能力,接下来我们将讨论这一点。
监控与可观察性
需要一个监控解决方案来解析日志,并且我们需要设置警报,以便在发生任何关键事件时收到通知。
OpenTelemetry 是一个开源的可观察性框架。它旨在捕获和处理遥测数据,包括来自云原生应用程序的度量、日志和追踪数据。它提供了一套 API、库、代理和工具,用于帮助 DevSecOps 团队监控应用程序的行为。它促进了跨应用程序和环境的数据收集标准化和一致的可观察性。一个显著的好处是与各种后端系统的互操作性。因为通过 OpenTelemetry,我们可以为代码提供标准化的工具,这样就可以轻松地切换到不同的后端和工具。这减少了供应商的锁定。OpenTelemetry 拥有强大的社区支持,并得到了主要云服务提供商和可观察性供应商的支持,确保了持续的改进、广泛的兼容性以及共享的知识和最佳实践。在选择新的可观察性产品时,值得将 OpenTelemetry 支持作为评估标准。
支持 OpenTelemetry 的流行开源工具包括用于度量收集的 Prometheus、用于可视化的 Grafana、用于日志收集的 Fluentd 和用于分布式追踪的 Jaeger。
在设置警报时,考虑值班团队成员的排班时间也至关重要。这定义了某个特定的 DevSecOps 团队成员何时需要待命以解决事件。它还应提供一定的灵活性,并允许在个人因个人原因无法参与时临时调整排班。如果我们的团队跨越多个时区,工具必须能够解决这个问题。流行的商业产品有 PagerDuty 和 Atlassian Opsgenie。可观察性有助于实时获得应用程序的洞察,并能够迅速应对任何意外行为。我们的目标是构建强大、可扩展和弹性的解决方案。但我们也需要处理从事件中获得的洞察,以提高系统的韧性,这将在下一节中详细阐述。
韧性
在云原生架构中处理韧性问题对于理解应用程序如何承受故障至关重要。故障可能发生在架构中的任何层级和任何相关组件中。AWS 发布了 AWS Well-Architected Framework 的第一个版本,微软在 2020 年发布了 Azure 版本,谷歌则在 2021 年发布了 Google Cloud Architecture Framework。这三个框架中都有一个关于 可靠性 的支柱或章节。然而,这一领域通常被误解,特别是在云采纳的初期阶段。设计和实施能够应对可能故障的应用程序是架构师和工程师的责任。如果我们利用托管服务,云服务提供商将考虑到许多因素,我们可以减少需要管理的可靠性表面。我们将在 第七章 中详细讨论这一点。
人类可能会失败——云也会失败
尽管云服务提供商(CSP)负责云服务的弹性,停机事件仍然可能发生。亚马逊首席技术官沃纳·沃格尔(Werner Vogels)曾说过一句名言:“一切都会失败,始终如此”。
在 CSP 方面,有多种基础设施故障场景,例如服务中断、可用区中断、区域中断或全球服务中断,如 DNS 中断。这些只是一些例子,当然,我们也可能在实际应用中遇到故障。例子包括负载均衡或数据库连接池的配置错误、磁盘或存储空间用尽、未分配足够的计算能力(如内存或 CPU 大小)、意外的配置漂移或软件漏洞。在架构弹性时,我们需要考虑一些指导原则,接下来我们将逐一讨论这些原则。
自动化恢复
首先,应用程序应该能自动从故障中恢复。这种行为也被称为自愈。必须发现故障才能启动自动恢复过程。我们会设置健康检查,这些健康检查可以触发后续的操作。例如,我们可以在负载均衡器上配置健康检查,如果负载均衡器后面的容器实例发生故障,它将被自动替换为新的实例。在这种恢复场景中,快速启动时间至关重要。因此,像 Docker Alpine 这样的精简容器镜像被广泛使用。
另一个指导原则是所有变更必须通过代码和自动化进行管理。自动化能够确保可重复的结果,并允许所有变更被追踪和审查。当我们进入云原生世界时,CI/CD 成为我们最好的伙伴之一。写入访问权限应仅限于 CI/CD 流水线。除沙箱环境外,开发人员应仅限于对所有环境的只读访问权限。如果在发生事故时需要人工干预,则应该有一个破玻机制。这意味着提升的权限仅限于所需的时间框架,并且审计日志会捕获所有手动执行的更改。
弹性与可扩展性
必须测试恢复程序。一个有效的备份程序并不能保证备份的完整性或恢复程序能够按计划正常工作。我们的业务连续性计划需要涵盖恢复测试。我们必须在恢复测试期间验证文档,并在必要时更新恢复步骤文档。一个数据重要性框架将有助于定义适当的恢复时间目标(RTOs)和恢复点目标(RPOs)。RTO 定义了恢复失败应用程序的最大时间。RPO 定义了我们能容忍的数据丢失最大时间。例如,如果 RPO 是 1 分钟,那么我们接受可能会丢失 60 秒的数据风险。因此,我们需要配置每分钟一次的自动备份。RTO 越短,我们需要进行备份的频率就越高。我们需要考虑成本和性能的权衡,以做出明智的决策。我们还必须测试其他恢复场景,例如网络恢复。
另一个弹性指导原则是,应用程序应横向扩展以提高可用性。横向扩展意味着在流量激增时进行扩展。通常,额外的实例会在负载均衡器后面启动以分担负载。如果我们为自动扩展架构解决方案,容量预估就变得不那么重要了。我们仍然需要考虑云服务商发布的硬性服务限制。但通过动态配置和自动扩展,我们对容量估算的依赖减少了。自动扩展还有助于降低云服务提供商的成本,因为我们可以根据动态需求变化来调整资源,而不是为峰值时段静态配置。
测试恢复能力
游戏日是验证弹性并发现需要修复的弱点,以提升应用程序可靠性或安全性的一种绝佳方式。这些是结构化的事件,团队模拟不同的故障场景,以测试自动恢复、人工流程的效率和恢复文档的准确性。游戏日的目标需要在选择故障场景之前定义清楚。我们还需要一个可以模拟停机的环境。如果我们的应用程序,包括基础设施,是以代码定义并且可以通过 CI/CD 管道进行部署,那么为此目的创建一个临时环境将变得很容易。游戏日通常以团队简报开始,然后才进行事故模拟。典型的场景包括关闭服务器或容器、限制网络带宽或模拟云服务停机。
我们可以使用故障注入模拟器模拟停机。Netflix 为此开发了工具,并在 2011 年发布了 Chaos Monkey,它会随机终止实例。随后,出现了其他工具,包括 Latency Monkey,用于模拟网络延迟或不可靠的网络状况。如今,主要的云平台都提供了云原生故障模拟器:AWS 故障注入服务、Azure 混乱工作室和 Google Cloud 混乱工程。
一旦开始故障注入,团队成员需要通过使用可观察性工具和诊断结果来检测问题所在。数据恢复需要验证,验证包括数据完整性验证和性能测试。
获得的洞见将促使采取缓解措施,例如改善数据恢复或修复配置错误的自动扩展。一天的工作结束时,我们会分析什么做得好,什么做得不好。这些需要改进的地方将在后续阶段再次实施并测试。游戏日是将反馈循环嵌入我们的 DevSecOps 文化中的一个好方法。
现在我们已经探讨了云原生的整体优势,包括文化和技术方面,我们将在本章最后澄清一些常见的误解。这些知识将帮助我们避开接下来将要讨论的反模式。
常见的误解
到目前为止,我们已经对云原生有了很好的理解。但为什么还是会有这么多误解呢?这些概念复杂,需要不同的工作方式。技术变化迅速,且缺乏标准化,这导致了各种不同的解读。向云原生转型需要大量的培训和全新的思维方式。
误解可能导致以下不足:
-
市场进入时间缓慢
-
缺乏安全性
-
缺乏容错性
-
缺乏备份和恢复
-
无效的 DevOps 和 CI/CD 最佳实践
-
增加了操作工作量
-
增加了总拥有成本(TCO)
现在我们将探讨一些常见的云原生误解,每一个都会导致上述几种不足。
共享责任模型
不理解云服务提供商与客户之间的共享责任是一种误解,后果非常严重。共享责任模型明确了安全性和合规性所有权。云服务提供商(CSP)负责“云的安全性”。这意味着他们保护运行客户服务的底层基础设施。这些包括数据中心和提供云服务的基础设施。客户则负责“云中的安全性”,例如他们的数据,或确保启用了加密。
在基础设施即服务(IaaS)模型中,客户拥有最高的责任级别。云服务提供商(CSP)只负责管理基础设施,例如网络、数据存储和可以托管客户操作系统的虚拟机(VM)。
客户的责任是管理其网络构造,例如网络地址转换(NAT)网关。客户还必须管理应用级控制、身份和访问管理、终端以及数据。
在平台即服务(PaaS)模型中,CSP 管理基础设施和平台组件,如操作系统、库和运行时。客户负责其应用的数据管理和用户访问。
在 SaaS 模式下,SaaS 提供商管理大部分安全责任,包括软件、基础设施、网络和应用级安全。客户负责数据保护、账户管理和用户访问。
下图展示了当我们从本地部署迁移到 IaaS、PaaS 和 SaaS 时,责任如何变化。无论我们选择 IaaS、PaaS 还是 SaaS,以下几个领域始终是我们的责任:数据、终端、访问管理以及账户或订阅管理。

图 1.2 - 共享责任模型
当我们查看像 FaaS(AWS Lambda、Azure Functions 和 GCP Cloud Functions)这样的无服务器技术时,客户的责任介于 SaaS 和 PaaS 之间。客户用户对无服务器服务的部署代码和用户定义的安全或配置选项负责。许多组织有一个云平台团队,为产品团队建立一个平台。他们通常会使用云原生登陆区服务,提供一个预配置、安全且可扩展的环境,旨在简化云的采用、增强安全性和合规性,并提高操作效率。在大型组织中,云平台团队通常管理 AWS 账户、Azure 订阅和 Google 项目。云平台团队将利用云原生账户供应服务,例如 AWS 账户供应服务或 Azure 订阅供应服务来执行此任务。
云平台团队通常提供包含自助服务项目的服务目录,例如容器、路由的网络构造、护栏、可观察性工具等。一些项目将在自动化账户创建过程中提供,包括网络构造、日志和监控功能以及护栏。产品团队可能会将其他项目发布到服务目录或容器注册表中。在这种情况下,我们有一个三级共享责任模型:CSP、云平台团队和产品团队。这可能导致操作模型上的困惑,我们将在接下来讨论。
操作模型上的困惑
操作模型需要解决责任模型,明确的 RACI 矩阵将帮助每个人理解该做什么(RACI代表负责、可问责、咨询和知情)。RACI 矩阵应涵盖软件开发生命周期(SDLC)的所有阶段,从源代码到操作。一些应包含在 RACI 矩阵中的任务有证书管理、DNS 管理、密钥管理、备份和恢复。
当我为一家云计算和 DevOps 咨询公司工作时,我开始与一所教育机构合作。这是我第一天早上到现场时,一位管理员不小心删除了整个数据仓库环境。不幸的是,这个环境是唯一的非生产环境。数据仓库是一个非常关键的业务应用程序,因为它管理着所有大学申请者和学生的数据。我们随后尝试从备份中恢复。不幸的是,数据恢复从未经过测试。备份数据已损坏,因此无法使用。
另一位管理员随后问我们是否可以联系亚马逊并请求他们提供备份。这个问题表明共享责任模型并不总是被理解。管理员本不应有权限删除环境。访问和身份管理,包括最小权限原则的执行,是客户的责任。此外,数据管理,包括备份和恢复测试,也是客户的责任。在那次事件之后,我们为客户构建了一个自愈解决方案,并改善了权限模型。
忽视文化转型
另一个常见的误解是云原生仅仅是关于技术。我们之前讨论过 DevSecOps 文化。只有在我们改变文化时,云原生的全部潜力才能得到充分利用。否则,业务创新将受到限制。在云端进行实验,创建新的概念验证,拆除它们或改变它们是很容易的,但只有在建立了成熟的自动化实践,并且具备 DevSecOps 思维时,才能实现这一点。我们需要付出努力进行文化转型,并利用培训和团队扩展。否则,变革的抵抗将持续,快速变化和发布周期的机会将永远无法释放。
缺乏 DevSecOps 成熟度将导致治理差、敏捷性受限、对市场需求的响应缓慢。开发和运维分离的孤岛式做法将在应用程序结构中反映出来,正如康威定律所描述的那样。最终,最终用户的体验将无法达到最佳。另一个需要考虑的因素是成本管理和所有权与本地资本支出(CapEx)模型不同。我们正在转向运营支出(OpEx),而如果没有成本所有权和成本标签,我们无法实现有效的成本回显或费用分摊模型。
如果仅将云原生视为技术推动者,我们将无法实现高效的成本管理。同时也会面临安全挑战,这引出了我们以下的基本误解。
将云计算视为本地环境
认为云中的安全控制与本地环境相同,也可能导致许多反模式。这种错误观念带来了重大的安全风险和挑战,并可能显著降低效率,拖慢市场响应时间。
我们必须为本地环境管理数据加密、访问控制和备份。云服务提供商(CSP)提供加密和访问控制的本地安全控制。然而,这些控制需要由客户进行配置。理解责任划分至关重要,这也显示了理解共享责任模型的重要性。换句话说,我们在云端建立数据安全控制要容易得多,但我们仍需记住审视我们的安全和合规要求,并评估攻击面。
由于云计算的全球性特点,复制数据到不同区域也变得非常容易。跨区域支持是一个特性,但也可能成为一个严重的陷阱。由于区域之间的切换非常简单,因此建议建立一个代码化政策框架,防止这种情况的意外发生。
为了管理本地网络安全,我们使用防火墙、VPN 和入侵检测与防御系统,这些都需要我们自己管理。云原生提供虚拟网络分段和安全功能,如网络访问控制列表(NACLs)、安全防火墙和托管防火墙服务。这些控制需要由客户配置,但比在本地更容易实现。如果通过源代码管理这些控制,并通过 CI/CD 管道进行部署,我们可以确保环境之间的一致性安全控制。这种方法与应用安全类似。对于本地工作负载,我们需要建立所有控制措施,包括漏洞管理和应用防火墙。如果我们使用托管服务,比如托管数据库服务或函数即服务(FaaS),CSP 已经为我们处理了大部分工作。我们仍然需要安全编码实践并扫描代码,但不需要扫描托管的运行时环境。CSP 会为我们管理这一部分,他们有全面的合规覆盖。这些覆盖至少适用于 CSP 管理的层级,我们可以下载合规报告以供外部审计。客户仍然需要负责共享责任模型中描述的上层内容。然而,云原生提供了可以根据我们需求配置的合规性和审计功能。云原生服务包括 Azure 合规管理器、AWS Config 和 Google Cloud 合规资源中心。
升级与迁移将充分利用云计算的潜力
认为“提升和迁移”方法能够充分利用云的所有好处是另一种广泛传播的误解。提升和迁移意味着将应用程序从本地迁移到云端,而不进行重构和改造。提升和迁移无法利用任何云原生的好处。比如,数据库不会利用托管数据库服务,而是通过虚拟机(VM)搭建,这需要安装操作系统和数据库。这意味着我们必须对数据库服务器进行修补,扫描漏洞,并从头开始开发和管理整个安全性,而不是利用内置功能。如果我们能够将数据库迁移到托管数据库服务中,情况会简单得多。那样,我们就可以显著减少操作复杂性,简化安全管理。云原生服务还内置了可扩展性、韧性和可观察性等功能。这些功能简化了应用程序架构,并使得操作应用程序变得更加容易。提升和迁移方法成本很高,这种应用程序的运营成本可能高于本地部署。推动提升和迁移的一个原因可能是数据中心退出战略。整体的努力成本会更高,因为我们需要传统地构建所有的安全控制和构建块,然后将应用程序重构为云原生架构。重复的努力带来了许多挑战,并且预算超支的可能性很高。
容器解决一切
“将所有东西都迁移到容器中就能让我的应用程序成为云原生的”是另一个广泛存在的误解。容器化应用程序并不一定能利用我们已经探讨的所有云原生特性。这种误解有几种变体。另一个变体是云原生需要容器。尽管容器是这一领域的基础技术,但并非一定需要容器。如果 FaaS(功能即服务)是一个符合我们目标的架构方案,我们可能会使用它。在这种情况下,我们就不需要管理容器或集群。容器误解的进一步变体是需要使用 Kubernetes。Kubernetes 是最流行的容器编排平台,云服务提供商(CSP)也提供托管的 Kubernetes 服务。它有一些非常优秀的应用场景,比如微服务架构。然而,与 FaaS 相比,它的学习曲线较陡,常常被低估。此外,还值得检查团队所在的地理市场是否具备所需的技能。
安全性可能会被忽视
一个令人担忧的误解是,安全性可以事后加上去。安全性必须从一开始就考虑并集成进来。“安全性是零号工作”是 AWS 首席信息安全官在 2017 年首次提到的名言。这意味着安全性是每个人的责任,应该被视为所有云和 IT 操作中的基础性优先事项,甚至要比其他工作或任务更先考虑,因此被称为零号工作。在本章的 DevSecOps 部分,我们讨论了如何尽早解决安全问题,理想的做法是从 IDE 中的安全检查开始,在 CI/CD 流水线中嵌入扫描,并在我们的环境中继续进行扫描。如果安全性是事后补上的,很多端到端的覆盖将不存在。这意味着应用程序的攻击面增加,数据泄露的可能性增大,因为缺乏防护措施。可能会出现操作中断,可能是因为云原生防火墙没有从一开始就使用,导致无法防止 DDoS 攻击或 SQL 注入攻击。又或者证书过期,因为没有使用云原生证书管理器来进行证书的续期。还可能会面临合规性要求无法满足的风险。这些因素可能会导致声誉损害,负面影响我们的业务。因此,最好从一开始就解决安全性问题。
云原生与微服务
另一个误解是,云原生和微服务是同一个概念。人们有时将这两个术语交替使用,但它们在某些方面是不同的。云原生是一种宏观方法,包括了一系列的实践和工具,用于在云中开发和运行应用程序。它关注可扩展性、弹性、持续交付,并利用云基础设施。云原生包括容器化、编排、DevSecOps 文化,以及通过 CI/CD 流水线实现的自动化。它涵盖了整个 SDLC 和云中的操作。微服务概念则提供了关于如何将应用程序拆分为更小的、可独立部署的组件的架构指导。云原生应用程序利用云中的特性和基础设施,设计上是为了在云中运行的。微服务架构可以应用于任何应用程序,无论是托管在本地还是在云中。托管在云中的微服务可以是云原生策略的一部分。
其他误解
这些是主要的误解,我们再快速地梳理几个其他的误解。
云原生采纳将自动节省成本。这只有在解决方案正确架构的情况下才成立。当我们谈到提升与迁移以及容器时,我们已经讨论过这一点。另一个误解是,云原生不如本地部署安全。这也是完全错误的:云原生的安全控制与本地部署不同。如果我们利用托管服务,那么安全的复杂性将会降低。
采用云原生堆栈有许多驱动因素,例如业务敏捷性、运营效率、市场时间、开发者生产力等。我们的关键驱动因素将取决于我们的业务战略。云战略需要与业务战略对齐或嵌入其中,以确保云原生采纳能够带来最佳的结果。我们将在下一章探讨战略。
总结
本引言章节已经涵盖了很多内容。我们了解了云原生的演变和优势。我们讨论了文化是如何成为云原生的一部分,以及 DevOps 如何演变为 DevSecOps。考虑安全性贯穿整个软件开发生命周期(SDLC)至关重要。我们还探讨了 CI/CD、可观察性和韧性的基础。我们还澄清了常见的误解,这将对与利益相关者的对话以及本书的后续内容有帮助。现在我们已具备了良好的基础理解,准备开始探讨反模式。在下一章中,我们将从目标和战略开始,因为它们将在云原生采纳初期就被定义。
第二部分:为成功设立您的组织
第二部分专注于我们云采纳旅程中的战略领域。这些领域包括战略、治理、FinOps、DevSecOps 文化、持续集成和持续交付(CI/CD)以及安全性。在每个领域中,我们将探讨常见的反模式,然后讨论什么是正确的做法以及如何过渡到良好的习惯。
本部分包含以下章节:
-
第二章**,不明确的目标和战略的成本
-
第三章**,在云原生范式中重新思考治理
-
第四章**,FinOps – 如何避免账单震惊
-
第五章**,快速持续交付而不妥协安全性
-
第六章**,如何实现您的安全性和合规性目标
第二章:不明确的目标和策略的代价
每个运作良好的组织都有商业策略。我们从第一天起就需要它。如果我们经营的是一家初创公司,我们需要它来获得融资;如果我们经营的是一家成熟的公司,我们会知道它对于设定愿景和目标、并让员工能够遵循是必不可少的。战略是显而易见的常识。那么,为什么我们会有这么多围绕战略方面的反模式呢?公平地说,这是一个快速变化的世界:创新周期非常快。我们需要确保更新我们的架构,以便能够在其他技术之上构建,进而增加商业价值。
这意味着我们需要为持续变化和技术采用创建一种组织思维方式。消费市场竞争激烈。二十年前,我们的应用程序季度发布或月度发布就足够了。而现在,我们需要持续的增量变化。监管框架要求更加严格,网络安全漏洞的数量也在增加。由于外部因素的变化,我们需要准备好迎接持续的内部变化。
“生活中唯一不变的就是变化”是希腊哲学家赫拉克利特的名言。从某种程度上来说,这与人类的天性相违背。但我们需要准备好迎接持续的变化和持续的改进。因此,我们需要指导,了解哪些类型和规模的变化能使我们的组织受益。这就是为什么我们需要策略的原因。我们不仅需要策略,而且需要一个与时俱进、涵盖所有相关问题的策略。
在本章中,我们将讨论战略性挑战,以及如果我们不解决这些挑战,将会产生的重大后果。以下是本章中讨论的常见战略性挑战:
-
缺乏明确的目标和策略
-
缺乏迁移策略
-
外包云知识和治理
-
缺乏合作伙伴策略
-
我们的云采用框架中的差距
我们现在已经清楚地了解了本章的学习目标。让我们从本书中的第一个反模式开始,找出它们为什么会使组织面临风险,然后看看如何将这些反模式转变为最佳实践。
缺乏明确的目标和策略
“我们需要做的是始终迎接未来;当世界在你周围变化时,当它对你不利时——曾经的顺风变成了逆风——你必须迎接这个挑战,并弄清楚该怎么做,因为抱怨不是一种策略”是亚马逊首席执行官杰夫·贝索斯的名言。
一位能够将小书店发展成全球在线巨头、发布 Kindle 设备、将公司扩展为全球云服务提供商(CSP),并将焦点转向太空旅行的人,可能对战略及其重要性有着相当深刻的了解。不完整的战略将在我们云采用过程中拖我们后腿,我们将无法充分利用云计算的所有好处。因此,我们将涵盖以下内容:
-
常见的战略反模式
-
理解业务目标
-
确定技术目标和原则
-
确定我们的战略基础并利用护栏
接下来我们将开始讨论常见的战略反模式。
常见反模式
现在我们将通过两个常见的反模式,来探讨它们为什么会阻碍云采用的进程。
自下而上的战略陷阱
这种反模式的第一个变体始于自下而上的云采用方法,通常会带来一些快速的成功。数字化转型计划的利益相关者意识到,发布一个应用程序的交付时间应该更短。这些包括等待时间,例如,因为各种部门(包括法务、采购和税务)需要批准,或者供应商只能在几周后交付所需的硬件。然后,软件产品需要安装、配置、测试,并在资产登记簿中注册。接着,发起人请求一个价值流图,该图展示当前的流程和时间表,并与可行的方案进行对比。
事实证明,如果团队采用云原生方法,可以在一半的时间内交付产品。听起来不错,不是吗?特别是在看到快速成功并确信可以满足关键的上线截止日期时。但长期的运营考虑往往得不到足够的重视。组织内部的标准化几乎不会被考虑,因为实际的视角是该计划,可能是一个项目、产品或业务领域(多个项目的组合)的一部分。
缺乏标准化会影响文化方面,例如DevSecOps和技术。在这种情况下,我们可能会有与某个项目/产品或产品组合的业务对齐,但却没有全企业的对齐。这种不对齐会导致组织内部文化的不均衡,并且技术堆栈的不一致。只有在某个业务单元与其他业务单元没有协同作用时,这种情况才是可持续的。换句话说,该业务单元完全自给自足,无法利用其他业务单元的共同构建模块。然而,这种情况通常并不成立,它揭示了这种反模式的自下而上的变体。即使在这种情况下,孤岛效应仍然是一个真实的问题,因为它可能对协作、学习和生产力产生负面影响。
让我们来看看这个反模式的自上而下变体,它带来了不同的挑战。
自上而下的战略陷阱
技术领导团队研究后发现,像poly-cloud或multi-cloud这样的词听起来非常适合解锁云原生的所有好处,并减少供应商锁定。这两个词到底是什么意思呢?Poly-cloud旨在利用特定 CSP 的优势。例如,面向客户的 API 可能托管在AWS上,因为其可扩展性,GCP可能用于机器学习和人工智能,Azure可能用于身份验证和授权。
多云的主要驱动力是避免供应商锁定,云分割通常是由更广泛视角中的能力优势推动的。多云和混合云的采用会导致非常陡峭的学习曲线。常见的场景如下:
-
根据使用情况,可能意味着数据团队需要学习如何在多个云中管理数据。
-
如果数据在一个云中管理,而其他一切都在其他云中,那么网络团队需要具备所有相关云的技能,以便在云之间建立冗余连接。
我们可以想象,当涉及多个云服务提供商(CSP)时,操作模型变得多么复杂。一些基础性构造,例如可用区,在不同的 CSP 之间有所不同。即使是术语Private Link,AWS 和 Azure 使用的一个服务名称,也有很大不同。CSP 还会收取数据出口费用。如果我们在 Azure 上运行一个应用,而数据存储在 AWS 中,我们必须支付 AWS 的数据出口费用。这个场景的另一个常见副作用是,只实现公共标准以确保跨云平台的一致性,这会阻止我们充分利用 CSP 的特性。自上而下的方法虽然有好的初衷,但并没有充分考虑文化挑战、陡峭的学习曲线以及高程度的协作和变更管理要求。
在一次咨询服务中,我帮助一所大学建立其多云治理框架。他们希望采用 Azure 和 AWS 的多云方法。几天的现场工作后,我发现这是他们的第三次尝试。过去三年里,前两次尝试都失败了。而现在他们又尝试了同样的多云方法。一个月后,合作再次暂停。历史名言“吃大象只有一种方法:一点一点地吃”再次显示出它的相关性。在我们的情境中,这意味着,如果我们采取逐步推进的方式,朝着可以随着时间发展演变的目标架构迈进,成功的可能性更大。如果我们开始云原生的采用旅程,它需要一步一步地进行,这样我们才能积累势头,合理的云战略也应精确解决这一点。为了实现有影响力的云采用,我们需要清晰地了解我们的业务目标,并从那里继续前进。让我们讨论一下在此过程中需要考虑的事项。
理解业务目标和我们当前的状况。
我们如何从缺乏明确目标和战略,转变为拥有良好架构的云原生战略?我们将从讨论战略方面开始。
战略方面
我们需要一个强有力的业务战略,而云原生战略需要是这一战略的延伸。要实现良好的业务结果,理解这一点至关重要。我们常听说技术战略需要与业务战略保持一致,几乎所有企业都依赖技术。这就是为什么技术战略应该是业务战略的延伸。这种思维方式将自动确保一致性。这样,我们就能确保我们的技术决策能提供最佳的业务结果,无论这是否需要新的功能,或者改善我们的合规性。在我们启动战略改进计划时,首先需要了解我们今天所处的位置,以及我们想要达到的目标。就像我们的自上而下场景中一样,当我们仅仅知道我们想去的地方时,往往会设定不切实际的目标。我们怎么知道我们现在的位置,相对于周围的一切?在现实世界中,我们使用地图来找出我们的位置,并定位我们想去的地方,地图会引导我们到达那里。如今,这很可能是一个导航应用或系统,但结果是相同的。
知道我们现在的位置
沃德利映射,以西蒙·沃德利命名,是一种战略框架,能够通过视觉方式表示一个业务或系统的组成部分、其成熟度阶段以及其对用户的价值。它们有助于理解一个组织的环境,识别潜在的变化,并就资源投资做出明智的决策。在沃德利映射中,我们将价值链的各个组成部分进行定位。这些组成部分可能是一个数据存储库,也可能是与云无关的东西。
沃德利映射有两个维度:
-
垂直维度描述了终端用户的可见性,如客户或内部用户。
-
水平维度代表了商品化的演化,从起源到定制构建,再到产品和商品。
沃德利映射可能帮助我们识别出我们过度依赖定制构建的组件,而没有利用那些已经是产品或商品的功能,例如FaaS。现在我们知道了我们的业务战略是什么,以及我们当前的立场,我们更有能力理解我们的技术目标需要是什么,现在我们将讨论这个问题。
定义技术目标和原则
具备良好的云原生思维,我们希望在实现目标的同时,支持业务并提高效率。目标的典型驱动因素包括业务敏捷性、市场上线时间和全球覆盖。让我们来看看如何解决这些问题。
应对我们的目标
我们可以通过转向已有的商品化产品并集中精力在有特殊需求的定制构建上来实现这些目标。提高弹性是另一个常见的目标,这意味着我们必须为容错和恢复进行架构设计。增强安全性和合规性则需要将安全性和合规性融入我们的向左移转方法。在定义目标之后,我们需要获得利益相关者的支持,接下来我们将进一步探讨这个问题。
协作与认同
现在我们已经能够阐明目标,我们可以进行协作并记录它们。我们需要获得领导层的支持,以确保采取行动来实现我们的目标。与首席信息官(CIO)及其他领导团队成员建立紧密联系非常重要。我们必须建立信任,提供新方向的可见性,并确保领导团队理解我们的意图。战略必须支持我们的开发团队,同时也需要来自高层的支持。
利益相关者管理
组织层级越多,信息传递和消化的时间就越长。即使目标没有提供明确的指导,尽早沟通它们仍然很重要。这样,当人们接到关于下一阶段详细信息的指示时,就不会感到惊讶。如果我们陷入这种反模式,可能就无法建立一个有效的实践社区。在此期间,我们必须利用其他沟通与协作平台,如架构和工程立会。接下来,我们将定义原则,为利益相关者提供早期的可见性。
定义原则
定义整体战略需要时间,但在这个过程中我们不想让利益相关者感到茫然。否则,技术债务将继续积累。提供早期可见性的一个极好方式是阐明云原生原则。这些原则使组织能够建立具有弹性、可扩展、安全的架构,推动更快的创新,提高成本效益,并增强敏捷性。让我们来看几个主要的示例:
-
CSP 选择:这将阐明我们唯一的 CSP,或者在选择 A 还是 B 时提供明确的指导。一个例子是“在这个业务领域管理的每个产品都使用 GCP,否则使用 AWS。”稍后我们将讨论云平台选择框架。
-
CI/CD 标准化阐述:这样做是为了实例化云资源。对于通过 CSP API 创建的每个基础设施组件(如 API 网关),都使用 Terraform。
-
GitHub Actions 使用:将其用于所有与应用相关的操作,如部署新的无服务器函数(FaaS)。
-
SaaS 使用:优先使用 SaaS,其次是无服务器容器化服务,最后如果没有其他可行方案,则使用 IaaS。这可以包括内容管理系统或 CI/CD 平台。
一旦我们完成这一阶段,我们将确保继续进行利益相关者的参与,接下来我们将讨论这个话题。
继续进行利益相关者的参与
这份指南将帮助在不需要定制构建的情况下优先选择商品化产品,正如之前在沃德利映射(Wardley Mapping)中所述。在我们能够起草战略之前,继续推广指导原则并通过现有的治理论坛达成共识是有益的。论坛成员需要同意这些原则。接受这些原则将确保采取行动,并使后续的战略批准变得更加容易。现在,我们已经准备好定义我们的战略基础。
定义我们的战略基础
当我们着手定义或重新构建现有战略时,我们需要检查是否涵盖了与人员、流程和技术相关的各个方面。战略应从愿景开始,接下来我们将深入探讨:
-
愿景:需要明确谁是赞助人,我们将在战略中记录这一点。云平台负责人可以是云平台的赞助人,而产品负责人则负责产品开发。接下来,我们将已制定的指导原则添加到战略中。我们需要非常清楚我们的 CSP(云服务提供商)是谁。如果这不是一个指导原则,我们需要明确这一点。如果这一点没有清晰阐明,可能会引起混乱。我们希望避免针对单个工作负载做个别决策。那些细节对于扩展和提供一致的支持模型至关重要。
-
人员:一旦我们对当前的工具和目标状态有了清晰的认识,就可以确定团队需要哪些新技能,以便最大化工具的使用效果。由于 DevSecOps 也涉及文化的变革,我们需要确定哪些培训是必要的。团队成员是否已经精通敏捷方法,还是需要进一步的提升?课堂培训可能有帮助,但最好的实践经验来自于将敏捷教练嵌入到团队中。从跨职能团队的角度来看,DevSecOps 的采用也是一样。如果这是团队的新内容,增加 DevSecOps 顾问可以实现快速学习曲线。团队需要经历这种文化变革,才能理解它如何为团队提供最佳的效果。职位描述必须更新,并且需要咨询人力资源部门。这对组织来说是一次重大变革,变革管理人员将帮助推动组织转型。
-
流程:流程的重要性常常被低估。我见过很多案例,组织实施了工具,但由于流程不够成熟,未能将技术采纳转化为成功的案例。例如,如果我们部署了漏洞扫描工具,它将提供我们所需的可视性。然而,这并不意味着漏洞会被修复。需要有流程,例如自动化生成关键警报的工单以及升级程序。否则,其他事情将优先处理,而根本问题永远得不到解决。
-
技术:在这一阶段,我们还必须阐明核心技术栈,涉及容器编排、安全工具、CI/CD 和可观测性。工具必须与云原生愿景保持一致。传统的本地部署 CI/CD 工具在迁移到 DevSecOps 模型时可能成为负担,因为网络、操作、安全和合规管理的复杂性增加。例如,我们每次连接到新的构建代理时都需要更新本地防火墙规则,还需要修补实际的服务器和证书,此外,与 SaaS 解决方案相比,我们需要提供更多的合规证据。在探索新工具时,评估它是否能够开箱即用非常重要。如果我们迁移到新的工具,例如新的 CI/CD 工具链,我们还需要考虑迁移策略,这将在下一节中讨论。
为了减少破坏性变更的风险,我们需要防护措施,这是我们接下来要讨论的内容。
将防护措施添加到我们的战略中
我们需要考虑我们希望建立的质量控制。由于我们现在专注于战略,因此我们可以在第五章中详细讨论,快速持续交付而不妥协安全性,但全面覆盖是目前的重点,接下来我们将查看一些防护措施的例子。
在我们的软件开发生命周期(SDLC)中的防护措施示例
软件开发生命周期(SDLC)早期阶段的质量控制包括通过更新 CI/CD 平台代码库中的配置文件来创建代码库和流水线:
-
变更需要拉取请求的批准。
-
批准将触发一个流水线运行,验证新的代码库和流水线名称是否符合命名标准。
-
如果是这样,流水线将创建两个新资源:一个 Git 代码库和一个新的 CI/CD 流水线。
-
在开发阶段,其他的防护措施包括代码扫描、代码格式检查、文档生成和最小权限执行。
部署前防护措施的价值
防护措施可以在部署前验证数据主权、加密、可靠性以及各种治理、合规性和成本方面的要求。
一个流行的政策即代码框架是开放策略代理(OPA)。作为下一步,我们可以将所需的护栏映射到我们的 SDLC 中,以获得一个坚实的端到端视图。
跨 SDLC 的整体端到端视图
护栏可以在我们的 SDLC 各个阶段设置,以下图例展示了护栏映射可能的样子。

图 2.1 – 将护栏映射到我们的 SDLC
护栏还可以包括成本优化控制,例如预算警报、低利用率和资源调整警报,以及异常检测。
实施这些护栏可能需要数年时间,具体取决于可以分配的人力资源。因此,确定优先级和技术依赖关系至关重要。这将帮助我们明确路线图。为了可视化护栏领域的进展,我喜欢在每个框前加上一个小小的Harvey ball。Harvey ball 是一种圆形表意符号,表示成熟度水平,或者在我们的案例中,我们也可以用它们来展示进展。如果某个领域完成了 25%,它会从圆形的顶部到右边缘的 3 点钟方向进行着色。以下图示展示了不同进度阶段的例子:

图 2.2 – Harvey ball 示例
我们的战略中还有更多内容需要补充,接下来我们将进行探索。
增强我们的战略
“没有战术的战略是通向胜利的最慢路线;没有战略的战术是失败前的噪音,”《孙子兵法》作者孙子如是说。
这句话阐明了多维方法的需求。我们的战略必须包括对云原生计划的全面视图,涵盖 CI/CD,包括安全工具、可观察性和所有云原生能力。在我们为路线图定义时间线时,需要考虑我们组织的成熟度水平。如果我们已经完成了 Wardley Mapping 过程,我们将清楚地了解我们的现状,但我们还需要考虑我们的文化进程位置:
-
更新频率:由于路线图通常比战略更新得更频繁,因此路线图有时会单独维护在一个文档中。然而,它也可以是战略文档的一部分。云服务提供商(CSP)的功能和服务时刻在变化,我们的业务目标或监管要求也可能随时发生变化。因此,我们需要定期更新我们的战略。
-
变更管理:当我们继续推进我们的战略时,需要再次检查之前提到的变更管理和培训方面是否覆盖到位。对于技术方面,结合我们的 CSP 的Well-Architected Framework(良好架构框架)进行交叉检查将非常有帮助。我们还将在后续章节中讨论另一个框架——云采用框架。
-
批准:赞助人和管理机构必须批准战略。这可能是云部门负责人和架构社区。只有战略得到批准,才能追究责任,只有这样,人们才会遵循明确的指引。我见过许多组织只有草拟的战略。人们把草拟版更多看作是建议,而非指导方针。我们希望我们的云原生之旅能够支持业务,因此我们需要获得支持。
在经过一系列战略错误和最佳实践的探讨,明确我们的目标和战略后,我们已经准备好进入下一个战略环节:为成功的云迁移之旅做好准备。
缺乏迁移战略
我们在上一章讨论的一些常见误解导致了这一反模式,这些误解包括以下几点:
-
对云计算好处的困惑
-
低估技能差距
-
低估文化变革
-
缺乏标准化和服务目录
例如,缺乏明确定义的云原生战略也会促成这种反模式,特别是当我们认为迁移到云端自动减少运营成本时。在没有明确指导的情况下,我们无法知道迁移后的目标状态应该是什么。低估技能差距和文化变革也是常见的因素。另一个重要因素是缺乏服务目录。在探讨反模式后,我们将讨论一个适用于我们应用程序的迁移框架,如何启动业务案例,以及如何启动实施并取得进展。让我们从这个反模式的变体开始。
常见的反模式变体
让我们从三种常见的反模式变体开始,首先探讨云足迹自然增长的迷思。
自然增长云足迹
这一反模式开始于组织希望自然地扩展其云端存在。结果,没有迁移计划,这导致了云端扩展缓慢,通常仅限于新应用程序。一些现有的本地应用程序可能由于本地可扩展性问题而被扩展到混合云解决方案中。
一个典型的案例涉及到内容分发网络(CDN)、一个网络应用防火墙、一个 API 网关以及云中的队列。云原生组件可以处理峰值负载,而本地应用程序可以从队列中拉取数据。最初打算是临时的,但由于没有强烈的动力将其余部分迁移到云端,它很容易变成永久性解决方案。毕竟,团队成员从未积累过足够的迁移经验。这里的负担在于,故障排除变得更加复杂,因为错误可能出现在两边。对于合规审计的证据收集也是一样的。我们见过一些组织,虽然它们的云采用已经有 8 年历史,但只有 20%的工作负载在云端,剩下的依然在本地。绝大多数云应用是新应用。问题在于,单靠自然增长是不太可能获得势头的。
因此,我们将长期处理遗留应用程序,无法充分释放云原生堆栈的潜力。
缺乏迁移指导
这种反模式的另一个变体是没有迁移决策框架。如果没有一个指导我们选择迁移到哪个云平台的框架,我们就必须逐个案例做决策,这将耗时过长,而且决策也不一致。我们也不知道实际的迁移处理方案应当是什么样的。处理方案会描述我们需要采取哪些重构步骤,使应用程序更加适合云环境。没有这一框架的组织会逐个案例做决策,这会带来几个问题。由于缺乏标准化,决策将不一致,这将增加操作复杂性。决策过程将更长,因为它没有标准化。迁移过程将更长,因为每次迁移处理方式不同。这对应用团队来说是一个巨大的负担。由于所有的缺点,迁移将被认为是痛苦且消耗精力的。这将降低迁移更多应用的意愿。最终结果与这种反模式的前一种变体一样:我们无法充分利用云原生的所有优势,因为我们在本地遗留环境中停留的时间太长。这也意味着我们仍然需要继续进行数据中心更新计划。一旦硬件更新,我们就已经花费了本可以用于迁移的相当多的资金。
我们可以看到这变成了一段冗长的故事,似乎没有尽头。那么我们该如何解决这个问题呢?我们如何制定一个结构化的迁移策略,帮助我们标准化迁移,降低学习曲线,加快迁移进度,并交付支持业务敏捷性的强大云原生解决方案?我们已经看到,缓慢的有机方法并不能帮助我们获得动力。只有当我们获得了动力后,才能加速云迁移,提升迁移效率,改进应用程序的运营效率和业务敏捷性。现在是时候探索一个框架,帮助我们实现可重复的成果并获得动力了。
缺少服务目录
服务目录包含可以自助部署的蓝图。服务目录提供可重用的构建模块。没有服务目录,我们的迁移将是不一致且缓慢的。我们需要为我们的服务目录项设定优先级,确保高影响项优先实施。我们还需要确保我们正确地解决了需求,包括非功能性需求。否则,当我们开始加速迁移时,会遇到问题。
服务目录项的一个例子是发布和订阅模式。这个服务目录项可以在 CI/CD 管道中被引用。然后,它将创建一个队列和通知结构, optionally 还可以带有死信队列(DLQ)。可以通过输入参数来启用 DLQ。主要的 CSPs 提供了它们的本地服务目录产品。SaaS CI/CD 解决方案,如 Terraform Cloud,也提供这种服务。
服务目录的优势在于它们促进标准化,并且可以有可靠性和安全性的默认配置。在迁移过程中,它们显著加速迁移,并帮助我们标准化迁移方法,简化操作方面。
服务目录还提供以下几个优势:
-
它们可以显著加速本地到云的迁移,因为构建模块可以被重用。
-
它们促进标准化,并且可以内置可靠性和安全性默认配置。
-
它们通过标准化帮助减少操作复杂性,从而带来环境间的一致性。
为了避免迁移的反模式,我们需要一个框架来指导我们的迁移旅程,接下来我们将探讨这个框架。
一个框架来引导我们的迁移旅程
我们需要一个强大的框架,帮助我们做出决策并通过标准化的处理方式来获得进展。2010 年,Gartner 发布了使用R 模型进行云迁移策略的概念。该模型提供了一个框架,用于根据应用程序的迁移适应性对其进行分类。Gartner 的框架包含了 5 个 R。AWS 发布了一个包含 6 个 R 的框架,后来又发布了包含 7 个 R 的更新版本,这个模型被称为云迁移的 7 个 R。这现在已经成为云迁移的事实标准框架。微软随后在他们的云采用框架中采用了非常相似的框架,术语也非常相似。GCP 使用了不同的分组方式。在本书的剩余部分,我们将遵循 AWS 和 Azure 的术语。我们将按照常见的优先顺序逐步介绍这些变化,优先级最高的是第一个:
-
重构:意味着重新架构应用程序,以充分发挥其云原生潜力。这是改善弹性、可扩展性、性能和操作复杂性的最大潜力所在。重构需要更多的时间和精力,但可以带来长期的投资回报。
-
重新平台化:意味着在迁移过程中对应用程序进行轻微修改。也称为提升、迁移并调整。这些轻微的修改可能是操作系统升级,或者将数据库迁移到云原生的托管数据库服务中,如AWS RDS、Azure SQL或GCP Cloud SQL。CSP 提供了针对这一目的的数据库迁移服务。这减少了操作复杂性,有可能降低运行成本并提高弹性。
-
重新采购:也称为购买并替换,即将现有的本地应用程序替换为现成的商业产品(COTS)解决方案,通常是 SaaS 产品。值得比较供应商网站提供的解决方案与 CSP 市场中的产品。有时,许可模型会有所不同。
-
重新托管:指的是将应用程序从本地云原生虚拟机迁移到云平台,如AWS EC2、Azure VMs或Google GCE。在这种迁移路径中,使用的是 CSP 的虚拟化管理程序。该路径通常被称为提升与迁移,比重新定位策略更接近云原生解决方案。CSP 提供迁移服务,帮助完成这种类型的迁移,包括AWS 服务器迁移服务、Azure 迁移和GCP 计算引擎迁移。
-
重新定位:指的是将应用程序迁移到云端,但不进行架构变更,使用与本地相同的虚拟化管理程序。VMWare与主要 CSP 建立了合作关系,以简化这种类型的迁移。当目标是快速迁移时,例如因为数据中心退出策略,通常会使用重新定位策略。
-
保留:这意味着应用程序不会被迁移。这也被称为不做任何操作的决策。当现在进行迁移太困难,或者应用程序有既定的停用日期且不需要新功能时,通常会选择这种方式。一个例子是传统的抵押贷款系统,因为抵押贷款合同有很长的运行时间。任何新的抵押贷款申请将由更新的应用程序来管理。
-
退役:这指的是系统的停用。通常发生在执行小任务的小型定制遗留系统中。停用通常发生在迁移工作接近尾声时,因为功能可以被其他应用程序吸收。这是云迁移计划中使应用程序变得过时的目标状态。
以下图表概述了 7 个 R 策略:

图 2.3 – 7 个 R 策略
该图表总结了框架,并为迁移选项的导航提供了良好的指导。框架为我们的目标状态提供了可重复的指导。现在,我们需要对迁移候选者进行分类,开始制定业务案例,这将是我们的下一步。
转向业务案例
接下来,我们将探讨如何根据我们组织的需求创建一个 7R 决策树,但首先,我们需要开始构建一个迁移初步方案。这是迁移计划的初步简化草案,列出了应用程序清单、业务目标的时间表以及 7 个 R。
现在,我们将探讨一些初步方案的方面,首先从创建开始:
-
创建初步方案:初步方案的创建通常是在一天的工作坊中进行的。如果是现场工作坊,可以使用白板绘制一个时间表,表示业务目标,并用不同颜色的七个便签标记。我们可以通过应用程序清单,将应用程序名称写在便签上,并根据最适合的迁移路径将其贴在相应的彩色便签旁边。当然,这也可以通过虚拟白板工具,如Miro或Mural,来完成。
-
目的:初步方案的目的是建立一个可以后续审查和完善的基本结构。它还将帮助尽早识别挑战,并为详细且全面的迁移计划奠定基础。
-
时间表和资源:在这一阶段,我们可以定义高层次的时间表和迁移路径所需的资源。这些时间表和资源不会非常准确,但它们将帮助引导关于优先级的讨论,以及应该优先选择哪一个 7R 策略。
-
成本效益:我们还需要查看通过减少本地数据中心占用空间而节省的成本。这些数字通常已经在预算中,因此是已知的。
-
其他好处:示意图将成为我们迁移商业案例的重要输入。由于我们有了高层次的工作量估算,我们可以量化 迁移成本。我们还将量化商业利益,例如 提高业务敏捷性、提升韧性 和 减少 技术债务。
-
商业案例:获得批准的商业案例对于获得动力至关重要。这是许多组织失败的关键点。因为迁移没有预算,他们就陷入了 缺乏迁移 策略 的反模式。
我们将快速进入下一步骤,因为我们将在 第十二章 中逐步了解迁移细节。下一个目标是加速我们的迁移进程,接下来我们将讨论如何实现这一目标。
启动实施并获得动力
我们将启动 迁移加速计划,从资金请求开始:
-
资金:我们的 CSP 可以帮助我们确定一个咨询公司来实现这一目标。我们的 CSP 可以通过其倡议提供资金或信用点:AWS 迁移加速计划 (MAP)、Azure 迁移与现代化计划 (AAMP)、以及 GCP 快速迁移与现代化计划 (RaMP)。
-
准备性评估:下一步是 迁移准备评估,它分析我们当前的云环境是否为迁移计划做好准备,并指出其中的差距。评估内容包括运营模型、着陆区的成熟度以及其他通常在 云采纳框架 (CAF) 中定义的因素,我们将在后续部分进行讨论。
-
迁移规划:在实际迁移开始之前,必须进行迁移规划。我们看到的一个有效方法是通过选择四到五个我们首先要迁移的应用程序来实施概念验证。它们应该有不同的迁移路径;例如,一个 重新托管,两个 重新平台,以及一个 重构 候选。应用程序必须足够复杂,以验证我们的迁移方法和工具集。
-
概念验证:概念验证有助于阐明我们的处理计划,这是 7 Rs 的扩展部分。它还将为我们组织的背景提供支持。我们不应单独开始这一旅程。我们应该得到曾经做过此类工作的咨询公司的支持。咨询人员必须融入我们的团队中,以确保知识传递有效。
-
治疗计划:治疗计划将成为我们迁移战略的一个宝贵扩展,并作为一个反馈回路来验证战略是否与我们在这一过程中获得的更详细发现保持一致。如果我们的组织有多云或混合云战略,它还将阐明云部署决策。治疗计划中还能看到什么?通常我们会有指导性问题,涵盖所需的业务收益,例如提高业务敏捷性。
-
简化治疗计划示例:以下插图展示了一个非常简化的视图,但它向我们展示了指导性建议如何发挥作用。请注意,迁移路径类型的顺序并不反映我们的优先级,而是最适合于排除选项。我们也没有考虑迁移选项,因为该选项主要与数据中心退出策略相关。

图 2.4 – 治疗计划示例
上述图表展示了一个简化版本,可以根据我们的组织需求轻松调整。
-
组织背景:治疗计划会因组织的不同而有所差异,因为它涉及公司的背景、业务战略和云原生战略。一旦我们决定了迁移路径,我们必须识别出所需的变更领域:数据存储与数据库、应用重构以及CI/CD 变更。
-
量化变更:下一步,我们可以量化变更。通过回顾治疗计划并结合所获得的洞见,我们可以重新测试决策。如果有认证的 CSP 合作伙伴协助我们,这一过程将更加顺畅,因为他们已经多次做过此类工作。
每个咨询公司会有不同版本的框架,并使用不同的工具来捕捉所有的发现。这并不重要。关键成功因素是拥有指导性建议和可重复的迁移路径决策方法。这将有助于制定出有效的迁移战略。我们将在第十二章中讨论迁移工厂和工具。我们已经足够准备开始迁移战略,并利用治疗计划建立反馈回路。
如果我们为迁移加速或其他云原生举措寻求外部帮助,我们需要在组织内部具备足够的知识,以便能够治理这些举措,我们将在下一节探讨这一点。
云知识与治理外包
组织可能需要几年时间才能意识到自己陷入这种反模式,因为在我们讨论云原生时,很多内容都属于知识的范畴。在我们深入讨论这种反模式如何开始以及它的影响之前,先详细阐述一下我们对云知识的理解。
治理云原生举措需要什么?
云原生项目可能非常复杂,并且对企业的成功至关重要。因此,我们需要一个完善的治理方法,现在我们将探讨这个问题。
人员和组织方面
从文化和软技能的角度来看,我们需要理解 DevSecOps 实践,正如我们在第一章中讨论的那样。我们需要了解我们组织中的变更管理流程。我们需要知道使用哪些沟通渠道来进行有效沟通和协作,以及如何使用我们的协作工具进行文档编制和团队合作。
我们需要理解业务驱动因素及如何支持它们,并阐明我们的云原生战略。这包括业务敏捷性或韧性等方面的要求。我们必须了解我们的利益相关者,如何与他们互动,以及如何管理关系和期望。这包括我们的业务伙伴,如 SaaS 供应商和 CSP。理解治理框架、如何平衡集中和分散的治理、所需的治理控制以及如何建立成熟的治理和合规自动化也至关重要。在这一部分,我们将按以下顺序逐一探讨这些方面:
-
管理云原生项目所需的条件
-
外包的驱动因素
-
常见的反模式
-
这些反模式的指示器
技术方面
从技术角度来看,我们需要了解我们的云服务提供商(CSP)提供的服务以及最佳实践,如何将它们结合并编排。还需要了解良好架构框架,并知道如何在战略上以及针对单个项目应用它。还至关重要的是,了解如何定义与最佳实践和业务目标对齐的可重用架构构建块,并将它们转化为我们服务目录中的可重用工件。
我们需要跟进新的云原生发展,确保不会被旧技术所困,正如我们之前在分析沃德利图(Wardley maps)时所讨论的那样。我们需要验证我们的CI/CD 工具链是否满足需求,并了解如何利用工具链建立一致的架构。理解网络概念以及如何将应用程序连接到业务伙伴、公共互联网、内部部署,甚至可能的其他云服务提供商(CSP)是至关重要的。我们还需要了解部署最佳实践,如蓝绿部署,以决定所需的部署架构。当然,我们还需要理解数据最佳实践、微服务、容器技术、成本管理等多个方面。我们还必须理清业务和技术的依赖关系,以制定发展路线图。
运维方面
我们需要操作知识,以理解日志记录、监控和警报的最佳实践,以及如何利用我们的可观察性工具并在需要的地方建立集中式日志记录,例如安全或审计日志。操作知识包括管理可扩展性、优化高可用性性能、优化云资源利用、云成本管理和FinOps 最佳实践。还需要了解安全和合规性,以实施正确的控制措施。这些措施包括数据和网络流量分段、加密、网络安全控制等。我们需要知道如何评估权衡,例如安全性与成本之间的关系。
这不是实现我们战略所需知识的详尽列表。然而,它为理解所需知识的内容和为什么云原生知识对组织至关重要提供了一个良好的起点。
外包驱动因素
永无止境的学习是一个大挑战。它是一些组织试图避免的挑战。外包一个问题听起来很诱人,而且这种决策有多个驱动因素。有时候,决策是在没有完全理解问题空间的情况下做出的。以下是一些典型情况:
-
技术不是我们的核心业务。为什么我们要处理所有这些复杂性呢?让我们把它外包出去。良好的合同和供应商管理实践将解决问题。
-
我们希望精简的团队能够根据需求随时扩展或缩减,以应对高峰季节或突发的市场反应。当我们拥有临时外部资源时,比如来自业务合作伙伴的顾问或自由职业者,我们可以更容易地做到这一点。自由职业者是独立承包商。
-
招募高技能的技术人才非常耗时。如果我们与一家大型咨询公司签订合同,他们会为我们提供市场上最优秀的人才。
-
我们希望减少行政管理负担。如果我们有更少的正式员工和更多的自由职业者或顾问,我们就不需要管理培训计划、绩效评审或假期批准。
两种外包场景(自由职业者和咨询公司)有很多相似之处。我们现在将探讨这种反模式如何在现实中展开。
常见反模式
本节将介绍一些常见的战略反模式,这些反模式正在制约组织的发展。
知识外包给自由职业者
我曾为一家政府机构做自由职业者,在信息和技术部门中,超过 75%的人都是自由职业者。每个独立承包商都带来了他们自己的经验、知识文档、偏爱的编程语言、编码风格、库、工具和设计模式。不知不觉中,他们甚至可能有自己喜爱的反模式,并一直在使用。
成为自由职业者的动力通常是独立性和更高的报酬,具体取决于就业市场。下一次选举对政府组织产生了间接影响。已经在那里的自由职业者合同超过三年的无法续签。新承包商被引入,他们面前有一大堆工具、框架和编码实践。问题是他们无法挑选和选择,必须全部消化。因此,学习曲线陡峭,存在许多未知因素。这增加了新团队成员变得富有生产力所需的时间,并且由于这些未知因素,也带来了额外的风险。只有通过分配时间和预算来进行修复计划,才能解决这一情况。
知识外包给咨询公司
另一次,我受雇于一家咨询公司,该公司与一家银行有云计算/DevOps 相关的项目。客户有许多不同的咨询公司参与其中。业务部门可以决定选择哪家咨询公司。专注于软件工程和 API 的第三方被分配给一个业务单元,另一个则被分配给另一个,另外还有专门从事 AWS 和 Azure 的咨询公司。有些咨询公司已经在那里多年,他们的技术框架在长期合作中发生了变化。许多咨询公司参与其中,再加上不断变化的技术栈和模式,显而易见,这个系统包含了许多动态因素。显然,缺乏统一的治理结构。CI/CD 工具链和应用程序变得无法管理。当然,咨询公司也需要轮换员工,因为顾问的一个个人驱动力是频繁接受新的挑战,而不是陷入一成不变的环境中。这一点需要在项目计划中考虑,因为需要为交接工作分配额外的时间。一家全球大型咨询公司也引入了许多初级顾问,以最大化其利润,而资深顾问并未挑战质量问题。
如果我们最终遇到这些类型的反模式,不仅框架和技术会不一致,质量、自动化水平、可观察性粒度、日志语句、部署架构、恢复程序等也会存在不一致。因此,组织将会陷入瘫痪,无法迅速应对市场变化。理解这一点至关重要:顾问和自由职业者应该被视为加速器,而非内部知识的替代品。那么,我们如何识别这些反模式,确保采取正确的措施呢?接下来我们将通过研究指示器来找出答案。
反模式指示器
文化指示器
这些是表明知识外包存在问题的文化观察例子:
-
上手时间:新加入的员工需要花费不合理的时间才能变得高效并理解工作环境。如果即使是资深开发者或工程师也需要超过三个月才能跟上进度,这通常是一个强烈的信号,表明 CI/CD 环境可能是碎片化的或已经过时,或者工作流程和工作方式没有达到应有的敏捷性。在这种情况下,询问新员工他们遇到的挑战并收集结构化反馈是一个好主意。我们还可以聘请第三方评估当前的 CI/CD 和云环境,并提出建议和优先级。
-
资源瓶颈:如果最了解情况的人缺席,项目将受到影响。这通常表明知识没有在组织内得到共享,这是一个重大风险,尤其是在那个人离开组织或需要临时请假的时候。配对编程、影子学习和反向影子学习可以弥补知识差距。我们还需要有一个明确的准备定义,这意味着需求已经准备好开始设计,或者设计已经准备好实施。这将取决于团队内部的定义。
-
外包所有工作:越来越明显的是,大多数云项目需要外包。这可能是由于内部资源的限制,或缺乏内部的技能和经验。让我们更详细地探讨这个问题:
-
内部资源不足:如果我们没有足够的资源,就必须验证是否为团队成员与外部合作伙伴合作分配了足够的时间。我们必须理解并影响决策,使之与我们的愿景、最佳实践和运营需求保持一致。否则,我们会遇到技术和框架泛滥的问题,团队也不会了解由咨询公司交付和部署到生产环境中的应用或产品。即使团队已经接受了云平台和 CI/CD 所需的培训,他们也无法深入了解已经交付和部署到生产环境中的内容。
-
技能缺乏:如果内部团队因缺乏技能和经验而无法实施新的云项目,那显然需要更多的培训。我们不仅需要标准化的云和 CI/CD 学习,还需要结合实际情况的学习,了解如何在我们组织中应用这些知识。这可以通过团队扩展和与外部方合作来实现。知识转移必须在工作声明(SoW)中说明,并且需要在咨询过程中定期验证。
-
-
DevSecOps 文化:知识差距的另一个明显信号是缺乏 DevSecOps 文化或 CI/CD 流程中的手动步骤。我们之前提到过 DevSecOps 文化,我们可以通过团队扩充来改进或建立这种文化。CI/CD 流程中缺乏自动化并依赖手动步骤的主要原因是知识不足,或者是由于紧迫的截止日期而忽视了质量。两者都是组织面临的风险,需要通过分配足够的时间来解决问题,并确保团队拥有所需的知识,或者能够通过之前提到的学习方法获得这些知识。
如我们所见,这类问题的根本原因通常是缺乏培训和经验,无法建立有效的治理程序。但还有其他领域也表明存在问题,我们现在来看看这些领域。
我们文档和系统中的指标
以下指标可以在现有的文档中找到,包括合同和我们使用的系统中:
-
外包合同缺乏基本信息:在合作开始之前,双方通常会签署一份合同,通常称为 SoW(工作范围声明)。如果 SoW 中没有提到内部的 CI/CD 实践,如代码扫描、分支模型、CI/CD 工作流、编码风格指南和可观察性标准,那么这应该引起警觉。如果这些标准和框架已经到位,必须在 SoW 中有所提及。否则,结果将无法达到我们的预期,我们将面临技术债务、治理挑战、维护复杂性和可避免的操作复杂性。如果我们没有这些标准,是时候立即采取行动了。如果内部团队成员无法清晰阐述这些标准,那么与我们可信赖的云咨询公司下一次的合作应当是建立或完善这些标准。这一合作需要技术和业务团队的全力支持。这是一个很强的信号,表明我们缺乏治理云原生项目的知识。这意味着治理发生在组织外部。这注定会导致失败,因为这种方式无法满足我们组织的需求和战略方向。我们需要将这项标准化工作作为优先事项。更重要的是,我们需要有一个能够与咨询公司紧密合作、学习最佳实践的人,同时还需要进行一些理论教育,如课堂或在线课程。
-
分析培训预算和技能认证:数字不会撒谎。如果没有专门的培训预算来支持持续学习,我们的团队成员无法报销培训或会议费用,除非我们使用一些创意会计技巧。有些团队成员可能愿意自己承担这些费用。从公司角度来看,为此预算并支付这些费用是公平的。否则,我们的公司如何期望跟上技术领域创新的快速步伐,而不支持员工保持与时俱进的知识呢?最终,我们将实现更好的公司成果。我们需要制定一个与团队结构的经验水平相一致的培训计划。
-
云原生技能未体现在职位描述中:如果职位描述中没有明确要求的经验水平,或者无法量化,那么我们需要为每个经验水平制定一个技能矩阵。然后,我们可以进行差距分析,看看哪些领域需要改进。这将有助于查找我们需要的培训内容以及其费用。培训计划中需要涵盖以下几个领域:DevSecOps 和敏捷、信息安全、CI/CD、治理和技术,包括开发、运维和可观察性。将这些数字纳入下一个预算非常重要。如果当前财政年度的预算可以重新分配,那我们已经处于一个更有利的位置,因为我们已经制定了培训计划,分析了差距,并评估了收益。
-
过度授权的用户权限:另一个表明我们正在走向这一反模式的方式是验证我们身份和访问管理角色中的人工权限。如果没有人具备验证这些权限的技能,那应该引起警觉。如果我们发现人工拥有一些在成熟的 DevSecOps 文化中不应该需要的权限,那这就是迫切需要培训的强烈信号。如果人工需要写权限来修改数据库模式或将数据导入数据库,可能有两种原因:要么这些权限不必要,要么我们没有遵循最小权限最佳实践。更可能的情况是,我们的团队没有遵循 DevSecOps 最佳实践。在这种情况下,我们必须分配时间来建立这些能力。以我们的示例为例,我们将需要阐明数据导入模式,说明工具如何帮助导入数据。如果团队在这一领域没有经验,这将突出显示另一个培训需求。到现在为止,我们知道学习包括课程中提供的普遍知识,并与那些之前做过的人进行配对学习。
与文化指标类别类似,我们可以看到缺乏培训和经验正在导致问题,稍后我们将解释这如何影响操作和交付。现在我们已经很好地理解了如何在文档和系统中识别指标,我们将继续探讨运营和交付指标。
运营和交付指标
在我们运营应用程序或希望实施更改或新特性时,以下指标变得非常明显:
-
每一个小的变化都需要不合理的时间:这表明由于治理缺口导致了技术和框架的蔓延。这些缺口可能是因为缺乏足够的知识来治理技术和流程决策。我们必须提升团队的技能,以便有效治理项目、评审结果并提出建议。
-
没有长期解决方案来应对故障:虽然出现了故障,团队能够迅速修复,但却不知道如何从战略上改善这种情况。这表明缺乏可观察性,并可能是技术更新滞后的表现。这些问题可能是由于时间压力、缺乏可观察性经验或工具造成的。这需要进行根本原因分析,以确定需要采取的措施。
-
建议工具中的重大问题:一个建议扫描工具,如云原生应用保护平台(CNAPP),发现了许多问题。这些问题包括未加密存储、未连接的磁盘卷、低利用率实例、缺失的访问日志、可靠性差距和超过一年的未旋转密钥。这表明我们可能是由于时间限制而被动操作,或者我们没有采用最佳实践。第一种情况可能意味着我们没有成熟的风险管理流程和责任定义,例如缺少操作模型和 RACI(负责、账户、咨询、告知)矩阵,以明确职责、责任和需要咨询或告知的人。第二种可能的原因是缺乏最佳实践的采用,这也是培训需求的另一个迹象,团队需要有时间来实施这些最佳实践。通常,这两种原因往往是共同存在的。
我们已经探讨了内部指标、它们引发的问题以及如何解决这些问题。根据公司规模、蔓延程度和复杂性,恢复这些问题可能需要很长时间。持续关注这些指标非常重要。但也有一些外部指标可以揭示这种反模式,接下来我们将讨论这些外部指标。
外部指标
以下信号可能由第三方提供:
-
审计中发现重大问题:审计发现了许多需要修复的问题,包括最小权限方法漏洞和容器及虚拟机中的漏洞。根本原因与建议工具(例如 CNAPP 解决方案)发现的问题类似。
-
过度依赖渗透测试:渗透测试包括一些本可以通过成熟的 DevSecOps 文化避免的问题,比如过时的镜像、缺乏网络安全控制或已安装的恶意软件,因为我们暴露于供应链攻击中。这表明我们在 DevSecOps 文化和 CI/CD 工具链中没有解决诸如漏洞扫描等实践。通常这不是技术问题,因为大多数 CSP 都提供该服务。这很可能表明需要更多的 DevSecOps 技能提升。
-
合作伙伴反馈:CSP 或软件供应商提供的反馈是,我们没有充分或正确地使用工具。我们需要与第三方建立功能性关系,以便他们能诚实地提供反馈。CSP 的反馈可能是,如果我们有无服务器策略,我们的虚拟机使用量需要减少。这可能表明我们的无服务器策略没有得到充分传达,或者我们的团队不知道如何编写无服务器应用程序,更愿意按照传统方式在虚拟机上运行应用程序。如果我们有承诺支出并且工具严重低使用率,供应商可能会提供反馈。我之前的一位客户有一个针对安全和合规性的 SaaS 产品的承诺支出,但他们只利用了 10% 的许可量。原因是只有那些发起购买的人知道如何使用工具,但他们在购买后不久就离开了。幸运的是,供应商主动联系了我们,我们能够举办一些培训课程。这有助于工具的快速上手,并为合规和安全的当前成熟度水平创造了可见性。
学到的教训
从 CSP 或软件供应商的反馈中学到的教训是什么?他们通常会提供培训,而我们需要确保充分利用这些培训。只有这样,我们才能保证从购买中获得良好的价值。如果该产品是我们的战略选择,我们需要确保建立良好的关系。这将确保我们获得诚实的反馈,并且能够得到我们可能有的问题的答案。在下一部分中,我们将更详细地讨论这个问题,探索合作伙伴战略。
缺乏合作伙伴战略
“伙伴关系不是两个平等个体之间的法律契约,而是两个致力于彼此成功的人的情感联盟”是沃伦·巴菲特的名言。我们在日常生活中依赖伙伴关系,例如与工作同事、朋友、配偶和其他人。组织层面上,伙伴关系同样具有重要意义。我们希望避免凭直觉做出伙伴选择,而是依靠逻辑和战略思维来决策。无论我们在哪个市场运营,都必然会面临竞争,我们希望走在行业前沿。我们无法独自实现所有目标。让我们来看看一些反模式,这些反模式可能会降低伙伴关系的价值,给我们的组织带来负担,并阻碍我们的进步。
我们将探讨两种反模式,一种是针对专业服务,另一种是针对技术合作伙伴。我们将识别出一些指标、合作伙伴选择的考虑因素,以及如何改善与我们的 CSP(云服务提供商)之间的合作关系。让我们从反模式开始。
常见的反模式
由于恐慌驱动的合作伙伴选择
在我之前的一个职位中,我为一个云平台团队规模非常小的组织工作,考虑到他们对云原生的雄心。为了区分咨询公司与客户,我们将其称为“客户”。客户非常依赖一家云咨询公司。这家本地咨询公司员工不到 500 人,只在亚太地区的小范围内运营。它们的顾问技术水平高,拥有丰富的云原生知识,并通过 Meetup 讲座、会议演讲和博客文章向社区做出贡献。他们获得了多个 AWS 合作伙伴奖项,展现出了真正的奉献精神。该公司能够在几乎无需指导的情况下运作,工作效率高,实施最佳实践,始终愿意进行知识转移或以团队增强的方式开展工作。这家小型云咨询公司文化契合度极高,能够理解客户的商业目标,同时拥有所有所需的技术专长。
后来,客户在一年内发生了两次本地服务中断。由于违反服务水平协议,他们不得不为这些中断支付罚款。此外,这些中断还引起了媒体的关注,进一步加大了压力。
只有 25%的应用程序在云端运行,其余的大多数都托管在本地。领导团队引入了一家全球知名的咨询公司,调查整个组织的韧性问题。该国际公司以其在流程设计和管理咨询方面的专业知识而闻名。国际咨询公司首先进行了本地分析并提出了设计建议。不幸的是,一旦这家全球咨询公司开始进行云端发现工作坊,本地云咨询的预算就被重新分配了。这家大型咨询公司尝试重复使用之前为客户规模比当前大 20 到 50 倍的企业所用的幻灯片。这些幻灯片过于通用,并没有针对客户的具体情况。在与新合作伙伴进行的第一次云端工作坊中,显然他们的云端经验无法满足预期。这些经验差距非常大。他们的大多数顾问都专注于本地环境。那些有些云端经验的人只是一些刚毕业的员工,他们几乎没有时间从错误和反模式中学习。
发现阶段后产生的建议幻灯片并没有反映现实。所选语言含糊不清。咨询公司没有理解当前的自动化和合规性差距,这在回顾会议中变得十分明显。当我们(客户)试图澄清误解时,我们意识到咨询公司根本不了解云原生的基本概念。我们一致认为,云端团队需要更早地参与审查过程,以提高质量。咨询公司随后引入了更多顾问来收集详细需求,并进入了后续的工作阶段。
我们进行了一些审查会议,会议中有 2 名来自云端团队的成员和 12 名来自咨询公司的成员。咨询公司提供的设计文档缺少大多数合规性和安全性要求。过了一段时间,客户云端团队的一些成员花费了 50%的时间进行审查和反馈。与之前的战略云咨询公司相比,咨询公司的心态有很大不同。他们的行为较为被动,主要的驱动力是将 Jira 板上的任务从“进行中”移动到“完成”状态。质量低到无法提供价值,云端团队花了更多时间协助顾问,帮助他们将质量提升到可接受的水平。6 个月后,只有 25%的预定范围得以交付。这是一次令人疲惫的经历,且对团队成员的士气产生了负面影响。如果我们选择了合适的供应商来解决适当的问题领域,这种反模式是可以避免的。选择合适的合作伙伴需要一些规划和数据点的收集,以查看如何随着时间的推移提高工作速度。但如果我们做出反应式的决策,这些事情就无法发生。
一失足成千古恨
另一个常见的缺乏合作伙伴关系反模式是处于被动模式,而非主动模式。这通常发生在我们没有云迁移策略并且希望通过自然增长来扩展云服务时。因此,我们无法获得足够的动力。迁移进程将会很慢,就像我们在缺乏迁移策略反模式中所讨论的那样。因此,我们不会在战略关系上投入足够的时间和预算。当这种情况发生时,我们可能已完成所有必要的许可证协议,但我们不一定正确使用这些工具和平台。我们可能也没有专注于在组织内建立足够的云原生知识。我们没有与合作伙伴定期进行协作。我们会错失团队能够获得的培训机会。同时,我们也不会得到有价值的反馈,或者利用合作伙伴进行审查。这些都将限制我们的进步。让我们总结一下战略合作伙伴关系的好处,以确保我们能够充分利用它们。
战略合作伙伴关系的价值
合作伙伴关系是互惠的关系。合作伙伴希望帮助我们,因为他们也希望有一个成功的客户故事。如果我们没有建立强大的战略合作伙伴关系,我们会错失什么?
-
合作伙伴可以帮助我们制定培训计划、开展培训课程和搭建实验环境,使我们的团队成员能够跟随讲师进行更多的实践体验。通过一个良好的合作伙伴关系,我们可以充分利用这些好处。
-
如果我们与合作伙伴的关系不够紧密,他们将不会提供有价值的反馈来改进我们的工作方法并提高效率。合作伙伴已经看到过许多客户案例,亲眼见证了哪些做法失败,哪些有效。他们希望帮助我们,因为客户的成功也意味着他们有一个好的客户故事。
-
我们不会获得路线图的洞察,这对于避免积累技术债务并避免定制解决方案很有帮助,特别是当我们知道很快会有现成的功能推出时。
-
我们还将无法获得所需的支持。我们提问的响应时间将比理想的要慢,或者质量较低,因为更强的关系会得到更多的关注。
-
我们的创新进程不会像拥有一个能加速转型并确保我们使用最佳实践的合作伙伴那样快速。后者还可能影响安全性和可靠性。
-
其他改进的领域可能包括:合作伙伴的 SME(领域专家)能发现的成本效率问题,或者由于我们没有签订高级合作协议,支持响应时间较慢。AWS、Azure 和 GCP 的响应时间根据我们选择的支持级别有所不同。更高的支持级别也意味着更高的费用;我们必须评估其收益。
什么指标表明我们正在走向这种反模式,或者已经受其影响?我们接下来会讨论这些。
这个反模式的一般指标
无文档化的供应商入职
一种潜在的弱关系迹象是,如果供应商的入职从未被文档化,也没有经过正式的认可过程。这表明合作伙伴从未经过评估,以确保他们符合我们的法律和合规要求。我们可能对除购买的 SaaS 解决方案外,合作伙伴的整个服务提供内容一无所知。在这种情况下,我们可能会错过能够为团队提供的免费培训。如果我们从未做过尽职调查,供应商可能并不符合我们的目标。我们必须评估是否愿意投入更多的时间和预算到这个合作关系中。如果我们认为产品符合我们的需求,但从供应商那里得到的支持不多,我们需要与他们进行对话,讨论他们还能为我们提供什么。只有在与供应商签署了保密协议(NDA)的情况下,我们才能获得产品路线图的见解。如果没有保密协议,这表明我们可能没有进行有意义的讨论以达成我们的业务目标,或者存在法律问题。
被动行为
如果我们认为我们的业务合作伙伴是被动的,这也是弱关系的一个信号。其症状可能以多种方式表现出来。比如,当我们提问时,他们的响应速度可能会更快;他们可能不参加会议,或者经常迟到;我们可能会从公司内部的利益相关者那里收到负面反馈。合作伙伴可能从不提供关于我们如何使用他们工具的反馈,或者他们不提供任何路线图的见解。可以看出,如果我们没有与合作伙伴建立强大的关系,很多方面可能会制约我们的进展。
缺乏节奏感
另一个表明我们没有建立强大关系的指标是,如果与供应商没有定期的合作节奏。对于一个小型 SaaS 解决方案,我们可能不需要强有力的合作关系,但对于与我们的 CSP 以及核心 CI/CD 工具链或安全和可观察性产品的供应商的合作关系,这是至关重要的。弱合作关系会严重影响我们的生产力、可靠性、安全性和工作方式。那么,这种合作节奏应该是什么样的呢?让我们从我们的 CSP 开始。
让我们来探讨在建立新合作关系或重新评估现有合作关系时需要关注的关键领域,以及强大合作关系的关键益处。
选择合作伙伴的考虑因素
选择 CSP 的考虑因素
我们希望利用合作伙伴的专业知识,这些合作伙伴可能是 CSP、咨询公司或技术供应商:
-
主题专家(SMEs):他们拥有专业知识和一支主题专家团队。首先,我们需要清楚了解我们的目标。CSP 拥有安全、无服务器、网络可靠性等领域的技术主题专家。他们也有非技术领域的主题专家,如合规性、变更管理、培训与教育或特定行业领域。他们可能会提供课堂培训或通过支持协议订阅他们的在线培训平台。我们在评估这种反模式的指示时,与 CSP 的客户经理和解决方案架构师讨论了定期会议。这些定期的主动会议将帮助我们改进架构,并有效、高效地利用云原生功能。
-
合作伙伴生态系统:CSP(云服务提供商)周围也有一个生态系统,专业服务组织是其中的一部分。这里还有一个重要的社区层面。CSP 拥有社区项目,如Google Cloud Innovators、AWS Heroes 和 Community Builders、以及Microsoft Most Valuable Professionals。个人通过贡献内容,如聚会演讲、博客文章、视频等,来参与其中。如果我们的团队成员对他们的云平台充满热情,他们将利用这些信息渠道并继续他们的学习旅程。或者,更好的是,他们可能会贡献自己的内容。当我们的员工为社区做出贡献时,我们的品牌名称将在云计算社区中广为人知。这将帮助公司吸引技术人才,并被认为是我们行业中的技术专家。
选择咨询合作伙伴的考虑因素
寻找新咨询合作伙伴时,我们需要评估他们当前的专业领域和战略增长领域:
-
战略对齐:如果我们正在寻找一个专业服务合作伙伴,我们必须确保他们的战略目标与我们的目标一致。如果咨询公司希望扩展其 AI 和 ML 实践,而我们想要专注于物联网,那么就存在战略不一致的问题。我们需要验证我们需要指导的技术领域,包括 CSP 服务、CI/CD、数据能力、可观察性等。我们将检查他们是否拥有足够的 CSP 认证和客户成功案例。咨询公司需要覆盖我们的时区,并在需要举办工作坊时能够到现场。如果我们希望他们帮助我们进行文化 DevSecOps 转型,我们必须验证并比较他们的文化价值观与我们的价值观是否一致。我们可能需要帮助进行培训、利益相关者参与或变更管理,因此需要验证这些能力。
-
当前重点领域:咨询公司通常按实践划分结构。实践中的个人可以在某个特定领域深入研究,并帮助我们获得我们内部没有的深入知识。我们还可以通过团队增能来提升团队成员的技能,提升我们的成熟度,并帮助我们避免反模式。我们的合作伙伴的专业知识可以帮助我们建立势头,提高速度,并实现敏捷性。合作伙伴有工具和框架来帮助我们加速云原生的采用。如果我们能够提高效率,我们就能更多地关注创新以及那些使我们与竞争对手区分开来的方面。
选择软件供应商时的考虑因素
如果我们正在寻找软件供应商合作伙伴关系,我们还必须进行尽职调查评估。如果创新处于我们的最前沿,我们必须选择一个在创新上投入足够多并且能够快速交付创新周期的供应商:
-
公开信息:如Forrester、G2和Gartner等网站发布市场研究,表明供应商在特定问题领域的创新情况。我们不希望依赖单一的意见,获得多个视角是有益的。供应商通常会提供现有客户的参考,并与现有客户建立联系。这样,我们就可以了解其他组织如何采用某个产品或服务,他们面临的挑战以及该产品或服务如何帮助他们。
-
架构契合度:我们还需要验证架构的契合度。该产品或产品套件是否符合我们的集成需求?与源代码库的集成至关重要。例如,如果我们有一个最小权限扫描解决方案,可以识别需要更新的机器角色策略。在这种情况下,指引我们到相应的代码并建议修改代码会非常有帮助。如果我们有数百或数千个 Git 仓库,这将节省大量时间,避免我们在寻找宝藏。
-
合规性与安全性:如果合规性和安全性至关重要,我们必须验证是否能够满足这些要求。一切数据是否都在静态和传输中加密?存储了什么数据?这些数据是否存储在我的地区?你们是否符合SOC2或PCI标准?他们是否满足我们的法律要求,且管辖权是否位于我们运营的国家?他们是否符合我们的安全要求?例如,他们是否只使用强加密套件进行加密?他们能否提供培训,并且是否有集成合作伙伴?这些只是我们需要评估的一些方面。
技术供应商会了解其工具的最佳实践以及如何使用它们而不会积累技术债务。他们还可以提供关于其发展路线图的见解,这对于我们在做战略设计决策时非常有帮助。例如,如果某个特性即将发布,我们可以避免使用自定义代码,或者我们也许能加入预览计划。
改善我们的 CSP 合作伙伴关系
有几个方面需要考虑,以改善 CSP 合作伙伴关系:
-
不同角色:根据我们的支持计划,可能会有不止一个联系人,关注的领域将会分配给他们。如果我们不确定某个具体领域应该联系谁,我们需要向我们的云服务提供商(CSP)询问清楚。这对于确保我们能够及时获得帮助,并能够与合适的人安排周期性会议至关重要。例如,客户经理可能负责商业协议、法律审批或培训计划。这将是我们在需要帮助时与支持计划相关、确保获得最佳折扣或寻找专业服务组织时的联系人。
-
针对问题领域的合适联系人:当我们与客户经理设置周期性会议时,我们需要确保来自我们团队的合适人员参加这些会议。他们是负责商业事务的经理,并且可以联系法律或采购团队处理任何问题或正式事务。他们还可以帮助规划更大的项目,比如迁移计划。有时,业务客户经理和技术或交付经理之间会有所分工。技术客户经理将是处理更多技术问题和高级架构问题的联系人。另一个可能的联系人是具有丰富经验的解决方案架构师,他们可以帮助我们解答架构或工程方面的问题。此外,他们还与各领域专家(SMEs)及行业专家有广泛的内部联系。我们可以安排各种周期性会议和研讨会。
-
周期:如果我们快速构建新的架构模式或采用新服务,我们需要与我们的解决方案架构师(SA)频繁开会,可能是每周一次或每周两次。与客户经理的会议可能只需要每两周一次。与解决方案架构师讨论我们的思路总是很有价值,因为他们可能有不同的思路来处理问题。
架构周期示例:我们发现与解决方案架构师(SA)讨论新模式对挑战我们的思维并获得反馈非常有帮助。有时,某些模式由于监管要求而变得非常特定于问题空间或复杂,以至于解决方案架构师必须邀请领域专家(SMEs)加入我们的研讨会。只有在建立了强有力的合作伙伴关系后,我们才能获得这一好处。当我们有关于云服务路线图的问题时,解决方案架构师是我们的第一个联系人。在这些会议中,我们的组织通常由首席云架构师和首席云平台工程师代表。为了确保这些会议和研讨会富有成效,必须确保代表合适领域且参与人数不宜过多。
结论
这些是合作伙伴评估的一些常见方面和评估领域。大型组织通常已经有了第三方评估框架,而小型组织则不一定有。不管怎样,全面的尽职调查是做出明智决策所必需的。一个商业伙伴也可能识别我们尚未发现的风险,并帮助我们减轻这些风险。我们的组织可以从良好的战略伙伴关系中受益的原因有很多。我们知道它们对云原生转型至关重要,现在我们可以继续讨论本章中的最后一个反模式,即缺乏 CAF。
云采纳失控列车
“生存下来的物种不是最强的,也不是最聪明的,而是最能适应变化的。”
– 查尔斯·达尔文
我们周围的一切都在不断变化。因此,我们需要适应并采纳。尽管这两个词的意思截然不同,但它们往往是相辅相成的。适应意味着我们调整或适应。采纳意味着我们将某些东西作为自己的,例如已被证明成功的方法论。CAF 帮助我们进行云之旅。没有官方的 CAF 定义,每个 CSP 都有自己的定义。因此,我们将采用一个准确且符合主要 CSP 定义中立场的定义:CAF 提供最佳实践、工具和指导,帮助有效的云采纳。它涵盖不同的生命周期阶段,确保组织通过利用云原生技术实现其业务目标。
各大 CSP 的不同 CAF 有着相同的目标,旨在帮助组织规划和实施云采纳之旅。然而,所有框架都有不同的结构、方法、术语和针对 CSP 服务的具体指导。本节将讨论它们以及常见的反模式。然后,我们将以总结和本章的关键学习内容作为结尾。现在让我们深入了解 CAF。
CAFs
AWS CAF
AWS 将 CAF 组织为六个视角:业务、人员、治理、平台、安全和操作。它还概述了云转型价值链,由转型领域表示。技术转型促进了流程转型,进而推动了组织转型,最终实现了产品转型。这最终带来了业务成果,如以下图所示。

图 2.5 – AWS CAF(来源:https://d1.awsstatic.com/whitepapers/aws-caf-ebook.pdf)
前面的图表提供了 AWS CAF 的简洁总结,强调了运营卓越和安全性,并包括资源参考,如AWS Well-Architected Framework、AIOps和AWS Prescriptive Guidance。
Azure CAF
Azure CAF 由以下几个阶段组成:定义、规划、准备、采纳、安全、管理和治理。下图概述了这些阶段以及框架如何使用方法论来克服障碍。

图 2.6 – Azure CAF(来源:https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/_images/caf-overview-graphic.png)
CAF 提供了详细的治理和管理指导,具有强烈的企业聚焦。它参考了Azure 蓝图和Azure 政策用于治理和合规性。它还参考了Well-Architected 框架和Microsoft Learn培训平台。它还参考了架构模板,包括最佳实践和对可扩展性、可用性、安全性、韧性以及设计其他方面的考虑。
GCP CAF
GCP CAF 被组织为四个领域:领导、学习、扩展和安全。领导领域指出,我们需要来自上层的赞助授权和来自团队跨职能合作的自下而上的推动力。GCP CAF 强调持续学习和创新,并且高度关注数据、机器学习和人工智能能力的利用。
我们可以在以下图表中看到所有领域:

图 2.7 – GCP CAF(来源:https://services.google.com/fh/files/misc/google_cloud_adoption_framework_whitepaper.pdf)
CAF 之间的共性
三个 CAF 都有相似的覆盖范围,并针对各个 CSP 的优势进行阐述。
通过比较不同的 CAF,两个方面变得显而易见:
-
首先,云采纳是复杂的,需要考虑的方面很多。这就是为什么 CAF 的某些方面经常被遗忘,导致我们对云采纳过程的认识不完全。因此,我们可能会忘记或不足够关注诸如培训、文化影响或变更管理等方面。这些是云采纳计划失败并需要重新启动的常见原因。这不仅是一项代价高昂的工作,还可能导致员工因为无法控制的挫折而离开组织。
-
其次,本章已经考察了 CAF 范畴内的各个领域,包括战略、学习以及缺乏云知识的后果,包括治理缺口。在第一章中,我们还考察了一些文化方面的内容。因此,我们现在将重点讨论我们尚未讨论的两个战略反模式。
常见的反模式
忽视蓝图和 CI/CD 最佳实践
这种反模式的第一个变体是忽视蓝图。这是我们多次看到的一个非常常见的场景。我们通过一个场景来说明这种反模式,并探讨其中的各个步骤:
-
云采用是自下而上的。领导团队意识到它带来了巨大的机遇,但并没有参与治理。然而,足够的严格措施确保了使用统一的框架、CI/CD 工具和编程语言。
-
产品团队开始开发第一个服务目录项目,以确保代码可以被其他团队复用。CSPs(云服务提供商)在这方面使用了不同的术语。它们可能会使用像产品、蓝图、解决方案或模块等术语,而不是服务目录项目。为清晰起见,我们将使用产品目录项和模块这两个术语。这样可以清楚地表明这些是由我们的组织实现的,而不是 CSP 提供的。服务目录项可以包括 API 网关、数据库服务等。
-
团队非常兴奋,因为他们在云采用方面远远领先于公司其他部门。过了一段时间,团队遇到了一个部署问题。部署成功了,但部署工件存在问题,部分 API 功能出现错误。发布的 Golang 代码版本比之前在 UAT(用户验收测试)中测试过的版本要新。
-
一名团队成员通过发布最新的测试版本修复了问题,应用程序恢复了稳定性。幸运的是,这个问题在几分钟内就能解决。在根本原因分析中,团队发现来自开发环境的构建工件不知何故被发布到了生产环境。
-
每个人都认为他们在实践良好的环境推广,这意味着构建工件只有在测试过后才能部署到下一个更高的环境中。我们只能将开发环境中的构建工件部署到测试环境,而不能部署到 UAT 或生产环境。结果发现,没有设置防护措施来强制执行使用预定义的工作流程来验证环境推广。一名新加入的团队成员并不知道这一最佳实践,因此为部署设置了一个自定义的 CI/CD 管道。我们不能责怪新加入的成员。
如果我们能够利用防护措施来保护他和我们的组织,或许这次初步事件就不会发生。这一防护措施在第一次事件中被忽视了。CAFs 解释了 CI/CD 最佳实践,包括环境推广。
CAFs 的价值
CAFs 提供了关于实施 CI/CD 管道的全面指导,强调自动化测试、集成和部署策略,以确保无缝的环境推广和可靠的软件交付。
AWS CAF 从平台和运营两个角度初步描述了 CI/CD 和环境推广。Azure CAF 涵盖了准备、采用和管理阶段下的环境推广。GCP CAF 则在规模领域描述了 CI/CD。接下来,我们将探讨如果我们不遵循操作最佳实践会发生什么。
忽视操作最佳实践
这种反模式的第二种变体是忽视运营最佳实践。我们将研究我多次见到的场景:
-
合作伙伴门户团队正在为合作伙伴集成构建一个面向公众的网站。该解决方案利用服务目录项目,包括一个用于传输层安全(TLS)证书管理的项目。
-
我们快进跳过接下来的 13 个月。合作伙伴解决方案的产品负责人接到一个电话。TLS 证书已过期,第三方想要知道网站发生了什么事情。产品负责人正在与团队核实。
-
他们可以确认证书已过期,但不确定是如何发生的。第三方证书提供商发放的证书默认有 13 个月的有效期限。TLS 模块不支持自动化第三方证书轮换。
-
不幸的是,这在模块文档中没有记录。花了几天时间重新发放和导入了新的证书。目前,这是手动完成以摆脱困境。希望在下次到期之前会有更好的机制。我多次观察到这种反模式。
-
当安全或网络团队要求使用第三方证书时,这种情况主要发生。与使用 AWS 的 Amazon 证书管理器生成的云原生证书相比,这带来了额外的复杂性。
-
然而,即使 CSP 不提供该功能,他们仍会在他们的 CAF 中描述有关证书管理和更新的最佳实践。
我们需要确保全面了解整体情况,并采取必要的严谨和自动化措施。我们还希望确保在遵循架构良好框架的同时阅读并理解 CAF 指南。
忽视编码最佳实践
我们正接近本章的最后一种反模式变体。我们将经历一个事件,这个事件在某种程度上是具有挑战性的,同时也让我为那个比他们期望得到更多关注的人感到抱歉。
-
多年前,我曾与一个政府部门进行咨询。政府部门正在急于进入云端。一些时间表已经被媒体宣布,事情必须迅速发生。
-
几乎没有治理。项目团队约 80%是自由职业者,包括临时首席信息官,其余是顾问。当然,没有提供培训,正如我们在知识外包反模式中所描述的那样。没有规定的模式或最佳实践。
-
预期所有团队成员都需要在现场进行生产发布。总体沟通很差,有时计划的发布未通知所有人。因此,关键团队成员错过了,周日接到电话询问为何没有参与上线,他们甚至不知道有这个活动。
-
换句话说,这是一个无政府状态。负责任的人对全局图景没有兴趣,更不用说定义 CAF 了。每个人都只想求生存。当组织陷入这种被动模式时,它变得非常脆弱。
-
当自由职业者不满意并在一周的通知期内辞职时,情况变得更糟了。新人经常出现。有一天,代理 CIO 非常紧张地走进来。他在半夜收到了来自 CSP 的电子邮件,通知他云凭据已经泄露到公共 GitHub 存储库中。
-
联邦警察的电话叫醒了他,他们对政府的安全感到担忧。因此,每个项目团队成员都必须签署协议,承诺不泄露机密信息,并完成警方审查报告的文件工作。他还解释了发生了什么。
-
两个月前开始的 JavaScript 自由职业者希望在他的个人公共 GitHub 存储库上展示他的技能。不幸的是,开发人员忘记从代码中删除访问密钥。这些密钥本来就不应该首先出现在代码中。那天早上,联邦警察突袭了开发者的家并没收了所有设备。没有恶意意图。
这仅仅是因为缺乏 CI/CD 和安全的防护栏、培训和最佳实践。所有这些领域都在 CAF 中有所描述。
开发安全最佳实践在安全支柱中描述,同时也在 Azure CAF 的ready、adopt和manage阶段中描述。AWS CAF 从安全的角度描述了这一点,而 GCP CAF 则包括在security领域中。
这是一个卓越展示,陷入了被动模式,没有按照 CAF 和 Well-Architected Framework 提供的指导步骤进行步骤,并且在没有足够考虑的情况下开始了云之旅。这一事件不应使我们放弃采用云原生方式。它应激励我们看到更大的图景:机遇、风险、做出明智的决策,但最重要的是利用规定的指导,包括 CAF 和云架构框架,以及我们的 CSP 所提供的 Well-Architected Frameworks。
这些框架非常重要,因为它们提供了结构化的指导,确保顺利高效地过渡到云端。它们帮助将我们的业务目标与云策略对齐,确保您的投资产生最大价值。CAF 为管理安全性、合规性和运营卓越提供了最佳实践,这些对于维护强大安全的云环境至关重要。
摘要
在本章中,我们讨论了云采纳旅程的战略方面。我们从目标和战略开始,指出云原生战略应视为业务战略的延伸。我们探讨了自下而上和自上而下的反模式。我们讨论了如何启动迁移战略,包括构建初步方案、启动商业案例以及获得动能。我们探讨了知识外包的风险,以及缺乏知识如何导致质量平庸,进而带来可靠性、安全性、合规性和操作复杂性方面的问题。我们讨论了合作伙伴关系的价值,最后,我们研究了 CAF 的价值。通过遵循 CAF,我们可以避免常见的陷阱,比如由于蓝图忽视导致的架构差距、部署问题和泄露的机密。所获得的知识为我们探索下一个问题空间——重新思考治理打下了基础,我们将在下一章中继续探讨。
第三章:在云原生范式下重新思考治理
在快速发展的云原生架构中,传统的治理方法常常难以跟上敏捷性、可扩展性和快速创新的需求。随着组织采用云原生实践,他们往往会无意中陷入反模式,这些反模式是低效或误导的行为,会减缓进展、增加风险并抑制创新。这些反模式源于未能调整治理模型以适应云环境的流动性和去中心化特征。本章探讨了组织如何发展其治理策略,以避免这些陷阱并构建韧性强、可适应的系统。本章将涵盖以下反模式:
-
学习会奇迹般发生
-
文化不需要改变
-
集中式治理将会扩展
-
我们的业务太特殊,不适合有保护性框架或标准
-
缺失反馈循环
学习会奇迹般发生
在传统的 IT 世界中,治理专注于集中的控制结构。而云原生环境则有所不同。云原生环境需要敏捷性、可扩展性和去中心化的决策。有效的云治理确保合规性、安全性和高效运营,从而加速创新。组织可以利用自动化政策、持续监控以及采用新服务,而不牺牲安全性,从而将云战略与业务目标对齐。
组织往往将治理视为一个涵盖技术与非技术控制机制的总称,用于管理基础设施并定义应用运行框架。虽然这一总称通常偏向于最佳实践的应用(试想一下,使用操作手册/运行手册),但往往忽视了治理中的非技术性方面,而这些方面一旦管理不当,就会导致反模式和结构的崩溃。造成这一现象的主要因素之一,就是本节所涵盖的模式,称之为学习会奇迹般发生。
忽视学习的代价
传统组织中的技能提升和当前技术栈知识往往受到在自己的时间里学习或我们没有时间培训你心态的限制。在这种情况下,工程师有两种选择。要么工程师会在一个公司工作几十年,专注于一个系统,要么他们会寻找其他职位,从而导致人才流动率高。
高人才流动率是工程团队面临的主要挑战。每一位新员工都需要入职培训,而在此过程中,资深工程师必须花费时间进行培训,这会影响整体生产力。在正常的 2-3 年流动率下,这是可以预期的,但一旦流动率变为 6 到 12 个月,就会成为时间的浪费和整体损失。2021 年的“大辞职潮”是这一点的一个很好的参考。每位新工程师都有一个初始的入职阶段;如果没有必要的学习材料,例如文档,那么这将变成一种负担。
花费时间手把手指导,而不是提供合适的文档,导致许多工程师离开,寻找更好的机会,因为文档致死在技术负债严重的组织中是很常见的现象。
这是一个你应该避免陷入的位置,因为这样不仅浪费了时间和金钱,还会错失创新机会。这已经导致许多组织的基础设施和软件团队解散。
在 IT 的产品和咨询方面工作过,并且曾在托管服务提供商工作过,我们遇到过这种情况。我们能理解为什么传统组织会这样做。对他们来说,最重要的是日常业务(BAU);从短期的角度来看,这样做是有道理的。从基本层面来看,组织关注的焦点是确保他们的产品创造价值,无论是金钱上的还是其他方面的。当面临提升技能或创建文档等任务时,很容易让工程师“在自己的时间里学习”,因为在他们看来,工作日的八小时确实应该花在产品上。我想在这里指出,工作时间以外的学习对于职业成长至关重要;即使每天只有一个小时,未来也会有所回报。然而,这不应该是唯一的学习来源。
从长期来看,这种做法是失败的;工程人才最终被锁定在他们产品的局限性中,除此之外没有任何其他发展机会。如果你被放置在一个没有任何收获的环境中,如何能在你的典型知识体系之外进行创新或创造价值呢?对于咨询公司来说,这是非常有利的;这正是他们介入并提供价值的地方,执行那些本应由内部工程人才完成的任务。对于云服务公司来说,这是一个需要解决的平衡问题。如果没有在工作时间内学习的自由,就会产生障碍,从而在服务或产品改进时,传统上需要外部帮助。
以以下图示为例:

图 3.1 - 消费者和生产者
从技术上讲,生产者到消费者的绑定上下文是一个功能模型;然而,这种方式在 BAU(做中学)工作方式中并没有改进的空间。这个模型中的服务可能是已知的,但并不深入到可以提出建议以改进设计的程度。
解决反模式
当面对一个充满 Word 文档或无数 Confluence 页面共享驱动器时,边工作边学习系统、构建或支持的概念似乎是更好的选择。但组织往往会把这一概念推得太远。工程师刚开始理解他们所从事的产品时,所有的时间都集中在产品上,结果没有时间提升他们的技能。
提供持续教育和职业发展的资源与支持至关重要。组织的目标是平衡工作负荷,确保员工有时间学习并应用新技能,同时避免过度的上下文切换。在传统组织中,我们在学习/自我教育的决策过程中所看到的情况如下:

图 3.2 - 传统自学决策树
大多数人陷入了一个永无止境的循环:推迟自学 -> 稍后评估,承诺自学但始终未兑现。更进一步,云原生组织致力于解决问题的根源。学习将奇迹般发生这一心态之所以持续存在,其中一个主要原因是无法管理的日常任务带来的沉重负担。这一挑战通常根源于积累的技术债务,而这并不是新现象。通过识别并积极解决这个问题,组织可以逐步释放时间用于自我导向的学习和职业发展。此项倡议必须由领导层牵头并得到支持,领导层必须保持警惕,防止积压工作量不断增加。此类积压应视为需要立即并持续关注的关键问题。

图 3.3 - 评估“REDRAW PLEASE”原因
这种方法基于这样一种信念:知识和经验是创造持久影响的基础。当员工在工作时间内被鼓励学习和成长时,他们更能有效探索新技术、实现创新功能,并推动组织发展。如果没有这种对持续学习的承诺,公司就会面临停滞风险,限制了创造独特解决方案的能力。通过将教育融入到日常工作环境中,组织不仅能赋能员工,还能确保员工在不断变化的环境中长期发展和适应。这种支持可以通过提供培训资料、工作坊和在工作时间内安排学习时间的方式来实现。可以通过在日程中预留时间来轻松实现。如果需要重新安排该时间(例如用于处理事件),则将该时间块移到日程中。要严格拒绝在该时间段内安排会议。
以下表格提供了一系列全面的选项,包括一些内部选项和外部选项。表 3.1 展示了相当多的选项,其中一些比其他的更难实现,但在这些选项中,认证和培训是最好的起点。
| 类别 | 描述 | 频率 | 参与者 | 方式 |
|---|---|---|---|---|
| 入职培训营 | 集中式的课程,帮助新员工专注于云原生工具和实践。 | 入职后的第一个月 | 新员工 | 实践实验,工作坊,辅导 |
| 持续学习时间 | 每周指定时间进行自我驱动的学习和探索。 | 每周 | 所有工程师 | 在线课程,阅读,实验 |
| 认证与培训 | 支持获得行业认可的认证(例如,AWS 或 Kubernetes 等云服务商)。 | 持续进行 | 有兴趣的工程师 | 在线课程,外部培训提供商 |
| 技术讲座和午餐交流会 | 工程师就特定主题分享知识的非正式会议。 | 每两周一次 | 所有工程师 | 演示、现场演示、问答环节 |
| 技术债务日 | 专门的时间来处理技术债务,同时了解遗留系统。 | 每季度一次 | 所有工程师 | 配对编程,重构会议,Confluence/文档奖励 |
| 导师计划 | 将经验较少的工程师与资深工程师配对,进行引导性学习。 | 持续进行 | 初级和资深工程师 | 一对一辅导,代码审查 |
| 技术写作 | 集中的文档存储库,记录最佳实践和经验教训,展示工程卓越。 | 持续进行 | 所有工程师 | 博客/白皮书,内部文档 |
表 3.1 - 内部学习选项
云原生厂商通常有自己的认证路径。对于 AWS,我们可以通过 AWS Skill Builder、Tutorial Dojo 或 Learn.Cantrill 等平台进行认证培训;对于 Azure,使用 Pluralsight 和 Microsoft Learn;对于 GCP,则使用 Google Cloud Training 和 Whizlabs。你获得的学习成果可以并且应该得到充分利用。比如,我们学习了如何通过 AWS 开发者认证使用 S3 存储桶来托管静态网站,一个简单的博客可以通过这一方式搭建,或者教育结果可以促使内部产品的推荐,特别是像 S3 静态托管这样的方法。
为了防止在云原生环境中产生反模式,创新的学习活动发挥着至关重要的作用。定期安排的活动,如黑客马拉松、游戏日、学习社区和外部会议,确保工程师的持续教育参与和操作准备。这些活动促进了创新、协作和安全意识的积极文化,这对于应对云原生技术的复杂性至关重要。这样的社区方法还将提供外部见解,否则这些见解是无法获得的。表 3.2 详细列出了这些变革性活动的频率、参与者和方法:
| 类别 | 描述 | 频率 | 参与者 | 方法 |
|---|---|---|---|---|
| 黑客马拉松 | 聚焦于构建原型和实验新技术的活动 | 每季度 | 跨职能团队 | 协作编程、问题解决 |
| 游戏日 | 模拟关键事件、安全事件等,以评估反应的活动 | 每年一次 | 工程师 | 全天灾难恢复测试、通过渗透测试或其他测试进行安全模拟 |
| 学习社区 | 专注于特定技术(例如 DevOps、安全)的专门小组 | 每月聚会 | 具有共同兴趣的工程师 | 讨论、合作项目 |
| 外部会议 | 参加行业会议,以保持对最新趋势的了解 | 每年一次 | 精选工程师 | 主旨演讲、工作坊、网络交流 |
表 3.2 - 外部学习选项
在云原生环境中,必须打破“学习会奇迹般发生”的迷思,组织才能成功。治理不仅仅是技术控制,还包括促进持续学习的文化。传统的集中控制向敏捷创新的转变,需要解决人的因素,确保工程师有足够的时间和资源来发展他们的技能。
学习不能被边缘化或期望在工作之外发生。为了将学习融入组织的文化中,公司必须提供结构化的开发机会,并将学习整合到日常工作流程中。这使得工程师在贡献业务目标的同时,能够不断精进自己的技能,从而带来更多的创新和更强的团队。云原生世界中的持续成功取决于将学习作为工作的一个不可或缺的部分。当组织将学习作为核心战略时,它们能够赋能团队推动技术变革,确保长期成功。在下一部分中,我们将探讨没有文化转变,这种转型是如何无法发生的。
文化不需要改变
推动成功组织文化发展的驱动力是变革。Salesforce CEO Marc Benioff 曾说过:“科技行业中唯一不变的就是变化。”我们可能会认为 Marc 只是指我们在这里构建和使用的技术。然而,隐含的意思是,文化和支撑行业的技术都在变化。采纳云原生方法不仅仅是实施新技术;它更是拥抱组织文化的根本性转变。许多组织误认为,只需将云技术覆盖到现有的做法中,而无需做出重大的文化改变。
本节旨在帮助读者掌握理解云原生采纳文化影响的技能。同时,它还将讨论低估文化变革、忽视关键利益相关者以及忽视变革管理的危险,这些问题可能导致员工的反感和抵制。
云原生采纳的文化影响
当一个组织采纳云原生范式时,必须超越技术,着眼于如何影响团队的工作方式、沟通方式以及解决问题的方式。云原生的采纳鼓励持续集成、持续交付/部署以及各种工程文化,如 DevOps/SecOps 或平台工程等做法。这些做法需要一种协作性、灵活性和主动性强的文化,能够适应快速变化,这与传统 IT 组织的文化截然不同。
Spotify – 文化变革的影响
Spotify 提供了一个优秀的案例,展示了如何通过拥抱云原生文化实现变革性成功。当 Spotify 决定迁移到云端时,它意识到这一转变不仅仅需要技术上的变化,还需要对组织文化进行根本性的重新思考。为了实现这一目标,Spotify 采用了一个以自主性、协作和持续改进为核心的独特模式。云原生的做法最好通过他们创建的“squads”(小队)来体现:这些小队是小型的跨职能团队,具有高度的自主性。
每个小队负责 Spotify 服务的一个特定方面,并且有自由决定如何实现他们的目标。这种结构使得团队能够快速地进行实验、迭代和创新,而不会被官僚主义流程所拖慢。小队模式还促进了责任文化的形成,团队对自己的工作从头到尾负责,培养了对成果的归属感和自豪感。除了小队,Spotify 还引入了tribes(部落)、chapters(章节)和guilds(公会)的概念,以保持组织内部的协调,同时保持自主性。下表详细介绍了每个概念。
| 概念 | 描述 | 影响 |
|---|---|---|
| 小组 | 负责 Spotify 服务特定方面的小型、自治的跨职能团队 | 促进快速实验、创新和自主权 |
| 部落 | 在 Spotify 服务的更广泛领域内工作的相关小组 | 确保各小组之间的对齐与合作 |
| 章节 | 在部落内部的学科特定小组,确保实践的一致性(例如,前端开发人员) | 维持最佳实践和技术标准 |
| 行会 | 跨组织的非正式兴趣社区,促进知识共享与合作 | 鼓励跨职能的学习与创新 |
表 3.3 - Spotify 团队模型解析
注意这种方法;所呈现的概念不会制造孤岛,而是创造重叠的群组,鼓励并支持团队之间的沟通。
Spotify 的成功故事展示了将文化变革与技术变革对齐的力量。他们的云原生转型不仅仅是采用新技术,更是培养了一种重视自主性、合作、持续改进和从失败中学习的文化。这一文化转变在 Spotify 能够大规模创新、保持高服务可靠性并在竞争激烈的音乐流媒体行业中保持领先地位方面发挥了关键作用。
要真正理解文化变革成功的原因,我们的学习需要集中在不改变的风险上。
忽视文化变革的隐藏成本
组织往往过度关注技术方面,忽视了人性化因素,这可能导致一系列问题。这些问题是由领导决策、对未知的恐惧以及领导层缺乏认同感的结合所造成的。让我们更仔细地看看这些问题的影响。
对变革的抵抗
习惯于传统工作流程的员工可能会抵制采用新的云端实践,拖延进展并导致低效。例如,在与一家金融科技组织的多云咨询中,尽管遗留流程效率低下,如需要两天时间才能配置一个新的 AWS 账户并依赖定制脚本,但工程团队依然不愿采纳云原生解决方案来简化工作流程。该组织也抗拒第三方云管理,因此我们为各个云团队使用了每个云供应商的本地工具。
很明显,工程师的犹豫不决通常源于多个因素,其中学习曲线是最重要的因素之一。每次变革都会带来一个不可避免的问题:“我们如何适应?”这种恐惧是完全合理的。
请考虑一下来自学习将奇迹般地发生部分的一个例子,来自于传统组织中的一位资深工程师。尽管企业可能非常看重他们的深厚经验和忠诚,但他们对变革的抗拒可能成为整个组织文化的重大障碍。这种抗拒不仅仅是因为不愿意改变;它源于多年积累下来的固有做法,已经成为他们的第二天性。他们的深厚专业知识虽然宝贵,但通常将他们与遗留系统和过时的流程绑定在一起,这些流程虽然舒适,但已不再适应现代需求。这种犹豫源于对未知的恐惧,对熟悉日常工作的强烈偏好,以及对变革的普遍抗拒。让我们来看看如何克服这种对变革的抵触情绪。
克服对变革的抵触情绪
克服这种抵触情绪需要持续而深思熟虑的努力:
-
提供项目后支持:直面解决问题,向工程师们保证他们的专业知识仍然受到重视,新工具是为了增强而不是替代他们的工作。
-
提供全面的培训和支持:这不仅包括表面上的介绍,还深入探讨新系统,通过动手实践的研讨会、Confluence 中的详细文档以及 GitHub 中的 Markdown 文件,为工程师们提供量身定制的内容,帮助他们弥合旧工作方式与新工作方式之间的差距。
-
培养重视持续改进的环境:创造一种将学习和适应视为持续过程而非一次性事件的文化。这有助于逐步引导工程师们适应新方法,确保他们不会感到不知所措或被边缘化。
为了使变革成功,必须采取明确的行动,而不仅仅是空谈,以克服经验丰富的工程师们的抵制。这需要建立坚实的基础,基础包括清晰的沟通、强大的支持系统以及对持续改进的承诺。这一基础是克服阻力的必要“破冰者”,使组织能够顺利过渡,并确保即使是最有经验的团队成员,在转型过程中也能感到安全和值得重视。
现在让我们来讨论缺乏支持的情况。
缺乏支持
在克服了实施初期的抵制后,推动文化变革的下一个关键障碍是获得员工和关键利益相关者的支持。如果没有对云原生采用能带来好处的深入理解,抵抗几乎是不可避免的。这种缺乏支持往往表现为敷衍的实施努力,其中推动项目前进所需的热情显著缺乏,从而导致项目失败的高风险。
在我们与一家金融科技公司的合作过程中,我们遇到了这种典型的情况。他们的本地基础设施存在诸多低效问题,包括以下几方面:
-
部署时间过长
-
可扩展性有限
-
累积技术债务
-
缺乏韧性
尽管现有的系统存在缺陷,但它们是熟悉且舒适的,这创造了一种虚假的安全感,使得云原生解决方案看似威胁到了这种安全感。抵抗并不仅仅是关于技术的,它涉及到挑战现状,摆脱那些长期固守的惯例,尽管它们效率低下,却已深深植根于公司的运营结构中。
我们清晰地概述了转向云服务的众多优势,例如以下几点:
-
提升的敏捷性
-
运营模式的成本节约
-
增强的安全性
-
快速扩展性
我们解释了向云原生转型是精心设计的,旨在简化操作、减少风险并确保合规。然而,依然存在抵抗的声音。缺乏热情不仅仅是一个小障碍;它是一个重大障碍,导致了执行的冷淡。团队对完全采用新工具和新流程持犹豫态度,将变革视为表面变化,而不是组织运营方式的根本转变。
克服缺乏认同感
为了克服这个挑战,建立一个关于云文化变革的有力论据至关重要,重点包括以下几点:
| 策略 | 描述 | |
|---|---|---|
| --- | --- | |
| 将技术优势与更广泛的组织目标联系起来 | 确保云采用的优势与公司整体目标清晰相关,帮助员工看到更大的图景 | |
| 广泛的培训与支持 | 提供深入的培训课程,解开新工具和流程的神秘面纱,旨在改变思维模式并减少恐惧感 | |
| 创建持续改进的文化 | 培养一种重视学习和适应的环境,鼓励团队将变革视为成长的机会,而非威胁 | |
| 强化长期利益 | 持续强调云采用的长期收益,帮助组织将视角从短期的不适转变为未来的优势 |
表 3.4 - 变革策略
最终,克服缺乏认同感不仅需要技术解决方案,还需要一种全面的方法,涉及到文化和心理层面的变化。通过将云原生战略与组织的核心价值观对齐,并确保每个团队成员都感到被纳入其中并受到重视,我们能够将怀疑转化为支持,并将最初看似无法克服的抵抗转变为共同推动成功实现云原生的动力。
下一部分讨论了沟通不畅,并提供了来自 Grammarly 的案例研究。
沟通不畅 – 案例研究
没有明确沟通变革的原因和其好处,可能会导致工程师之间的困惑和焦虑。这在我们领导的一个项目中表现得尤为明显,该项目旨在 AWS 上建立云基础设施,并在短时间内交付最小可行产品(MVP)。项目赞助商——架构负责人对结果感到非常高兴。尽管领导层对此感到欣喜,但在一次全体会议中,很明显,广泛的团队对于项目的目的和原理并不清楚。
观众提出的问题暴露了一个明显的沟通鸿沟。项目赞助商未能充分向更广泛的组织传达云原生转型的信息,导致了不必要的焦虑和担忧。这一经验强调了在云原生采纳过程中,清晰和一致的沟通至关重要。领导者必须确保组织内的每个人不仅理解变革的原因,还要明白它带来的好处以及如何影响他们的角色。这种一致性对任何转型举措的成功至关重要,并通过培养共同的目标感和对新方向的承诺,帮助减少抗拒。例如,Grammarly 就公开发布了他们的相关发现。
Grammarly 在 2022 年 10 月的两周时间里发现了以下问题:
-
15%的员工表示,沟通不畅让他们考虑更换团队。
-
25%的员工表示,沟通不畅加剧了他们与当前团队的关系紧张。
-
22%的员工表示,沟通不畅使他们考虑找新工作。
这些因素都最终回归为云原生文化变革的阻碍因素。

图 3.4 - Grammarly 案例研究摘录 (www.grammarly.com/blog/poor-communication-work-stress/)
克服沟通不畅
领导力在推动云原生采纳的支持方面发挥着至关重要的作用。它不仅仅是关于强制变革;更是关于传达一个能够在整个组织中引起共鸣的愿景。
领导者必须清晰且有说服力地阐述云原生采纳的好处,将这些优势与组织的整体目标以及团队成员的个人愿景相联系。通过这样做,他们可以将怀疑转化为热情,将障碍转化为成长的机会。一位鼓舞人心的领导者通过自身示范来引领变革,并以实际方式展示其价值。
耐心和毅力同样重要,因为获得认同不是一蹴而就的;这需要持续的参与、不断的教育,并庆祝每一个小小的胜利,这些胜利共同为更广泛的转型积累动力。针对我们目前阅读的内容,下一节将为我们提供可以采纳的策略和框架。
云原生转型中文化变革的有效策略
成功采用云原生方法的有效策略包括以下几点:
-
促进跨职能合作:通过鼓励跨职能团队协作,打破孤岛。采用敏捷、DevOps/DevSecOps/现代工程文化,促进创新,并确保在决策过程中考虑多样化的观点。
-
鼓励实验和学习:为员工创造一个安全的环境,让他们可以进行实验并从失败中学习。倡导成长型思维,并提供持续学习和发展的机会。
-
赋予团队自主权:给予团队自主决策的权力,并让他们对项目负责。这种授权可以带来更多的创新、更快的解决问题的能力和更高的工作满意度。
-
促进开放沟通:保持开放、透明和一致的沟通。定期更新员工有关云计划的进展,并提供反馈和讨论的论坛。
-
变革管理框架:利用结构化方法,如 Prosci 的 ADKAR 模型和 Kotter 的 8 步变革模型,有效管理变革。
向云原生转型的旅程强调了文化演变与技术进步并行的必要性。正如 Spotify 等公司所展示的,成功的云原生转型不仅仅是技术上的,它还需要培养一种自主性、协作性和持续改进的文化。
克服源于恐惧、固守的惯例或误解的抵触情绪至关重要。通过教育倡议、领导力支持和文化再造,组织可以将新工具与核心目标对齐,帮助每个利益相关者拥抱这一转型。
下一节将讨论集中式治理将扩展这一反模式。从这些文化转变中汲取的教训,突显了支持复杂云环境的可扩展治理结构的重要性。
集中式治理将扩展
回顾 IT 行业的历史,可以发现集中式治理一直是常态。传统上,组织内的每个组件都被视为关键,导致了一个所有决策、改进和监督都从一个单一权威点发出的治理结构。最初,这一模型运行得很有效,由一个由资深工程师或项目经理领导的小团队进行管理。
然而,随着组织的发展,这种集中式方法往往变得繁琐且缓慢。随着组织更广泛地接受云原生技术,强大的治理框架的重要性变得愈加明显。有效的治理对维护安全、确保合规性以及优化运营效率至关重要。该领域的一个普遍观点是,集中治理可以在多样化的组织结构中有效地扩展。
本节将深入探讨这种方法的细微差别、不足的去中心化治理指南带来的危险,以及根深蒂固的官僚主义和缺乏专门的云卓越中心(CCoE)或实践社区(COP)所带来的挑战。
在本节中,我们将深入了解如何在云中建立 CCoE 的最佳实践,以及组织应努力避免的关键反模式。本节将探讨组织如何成功地从僵化的集中式系统过渡到更具动态性、去中心化的治理框架,以更好地支持其不断发展的需求。
集中治理 – 应对挑战并制定解决方案
虽然治理实施至关重要,但缺乏去中心化治理指南可能会将锚固变成枷锁,剥夺灵活性,消除短期和长期创新的潜力。拥抱标准化是至关重要的,无论是在技术还是实践中,赋能工程团队去应对这些既定框架。去中心化治理的一个好处是,它能够加快决策过程,增强自主性,并迅速应对不断变化的市场环境。以下小节提供了关于缺乏去中心化治理的一些见解。
缺乏去中心化治理所带来的挑战
缺乏去中心化治理可能会带来多个挑战:
-
创新受限:过度的集中监管,缺乏灵活性,可能会阻碍团队主动改进现有流程。这种僵化的控制抑制了对技术进步至关重要的探索性思维。
-
操作瓶颈:集中决策通常会带来延迟,妨碍在快速响应至关重要时的灵活性,尤其是在像无服务器计算和 AI 开发等动态领域。
-
团队参与度下降:没有推动有意义变革的自主权,团队可能会感到动力和参与度下降,从而导致生产力和创新力的降低。
以下图表展示了集中治理和去中心化治理的对比:

图 3.5 - 集中治理与去中心化治理(请重新绘制)
中心化的模型,类似于传统的 IT 框架,通常将权力和决策集中在组织的核心。这种中心化依赖关系形成了瓶颈,每个决策,不论多么微小,都必须通过层级上报,通常导致延迟和响应能力降低。相比之下,去中心化的云原生模型将权力分散到信息和行动的源头附近。这种接近性使团队能够根据对问题的直接理解迅速做出决策,从而促进了更敏捷和更具响应力的环境。
当决策权从日常运营的参与者中剥离出来时,可能会导致团队成员产生失能感,他们可能觉得自己的专业知识和见解被低估。这会降低工作满意度并增加员工流失,从而进一步破坏组织的稳定性。中心化的模型在动态环境中往往难以有效扩展。随着组织的发展和运营的复杂化,中央决策机构会因为决策请求的增加而不堪重负,导致响应时间变慢,并且可能错失快速发展的行业中的机会。例如,我们曾与大型关键基础设施组织合作,如大型电信公司,工程师们可能会发现优化网络流量的创新方法,但由于没有经过繁琐审批流程,他们无法实施这些变更,从而导致挫败感,并且觉得自己的技术专业性得不到重视。这种脱节不仅阻碍了创新,还可能导致工作满意度下降和员工流失,进一步动摇了组织的稳定性。
在大规模应用中,去中心化治理取得了很大的成功。以下是 AWS 的一个例子。
两比萨团队 – 去中心化治理
去中心化治理的典型例子就是 AWS 的两比萨团队框架。该模型提倡小而灵活的团队,赋予团队自主决策的权力,从而创造出一种创新与敏捷的文化,同时确保与更广泛的组织目标保持一致。
例如,AWS 的无服务器计算服务 Lambda 背后的团队就是一个典型案例。该团队能够快速将客户反馈整合进新功能的开发中,充分体现了去中心化治理所带来的竞争优势,进一步巩固了 AWS 在无服务器计算领域的领先地位。
每个两比萨团队,专注于特定的服务或功能,凭借创新和推动其议程的自主权蓬勃发展,能够快速调整以更好地满足客户需求并保持市场领先地位。以下表格突出了两比萨团队的优势:
| 优势 | 成功指标 |
|---|---|
| 增强的敏捷性 | 更小的团队能够更快行动,并且在没有繁琐流程的情况下迅速适应。 |
| 增强的自主性 | 团队成员较少减少了误解,并增强了在快速发展的项目中的协调性。 |
| 改善沟通 | 因为团队成员减少,误解减少,并且在快速推进的项目中增强了一致性。 |
| 更大的问责性 | 小团队内明确的责任划分提升了对行动和结果的问责。 |
| 更快的决策制定 | 由于减少了官僚层级和必要的审批,决策流程更加高效。 |
| 提高专注力 | 小团队能更加集中的专注于具体目标,而不受更广泛的组织干扰。 |
表 3.5 - 两比萨模型的详细优势
集中治理解决方案
在详细探讨了集中治理所带来的挑战后,必须解决其中一个最具破坏性的因素:僵化的 官僚主义。这一现象代表着那些变得如此僵化和过时的流程,以至于严重妨碍了组织创新和适应能力的发挥,而这些能力在快速发展的云技术领域中至关重要。
僵化的官僚主义的症状
僵化的官僚主义最明显的迹象之一就是决策迟缓。在许多传统组织中,决策流程因为管理层级和不再具有价值的程序步骤的累积而变得拖沓。这些层级是过去结构的遗留物,它们不是出于必要而存在,而是由于惯性维持着,导致了不仅令人沮丧而且成本高昂的延误,特别是在错失机会的情况下。这种症状在较大和较老的组织中尤为明显;我们多次听到在政府部门工作或与之合作的人提到,单凭官僚主义,变革被扼杀。
另一个症状是对变革的抵制。虽然我们在之前的章节中已经深入探讨了这一部分,但它同样与集中治理有关。传统组织常常表现出对采纳新技术或新方法的深刻抗拒,这种抗拒源于对变革的恐惧。这种恐惧并非没有根据,因为新技术可能会扰乱既定的角色和流程。但这种抵制也源于对现状的舒适感和对未知的回避。这种抵制会阻碍组织在技术适应性对于生存至关重要的行业中保持竞争力。
破除僵化的官僚主义的策略
为了应对僵化的官僚主义的惯性,特别是在需要云技术提供的高敏捷性的环境中,组织可以采取若干有效策略:
-
简化流程:定期审查所有流程以简化它们是至关重要的。这意味着要去除冗余步骤,简化程序,以提高运营效率和响应能力。
-
赋能团队:将决策权直接下放给一线团队,可以显著提高敏捷性。这种赋能使得最了解当前问题的团队成员能够迅速且有效地实施解决方案,而无需经历层级上升下降的延误。
-
促进持续改进的文化:培养一个重视持续评估和改进过程的组织心态,确保这些过程始终保持相关性和有效性。这种文化鼓励创新和实验精神,这对于充分发挥云计算技术的潜力至关重要。
通过解决僵化官僚体制的症状和根本原因,组织不仅能增强适应性和效率,还能营造一个有利于创新和快速技术采纳的环境。
从僵化的官僚体制到动态响应的官僚体制的转变,不仅仅是过程上的变化,更是组织文化的转型,使其与云时代的需求保持一致。
在接下来的部分中,我们将深入探讨 CCoE 在应对云治理复杂性方面的关键作用,并确保组织在避免官僚停滞的陷阱的同时保持敏捷性。这些框架对于明确角色、简化决策过程以及在云原生环境中培养持续改进的文化至关重要。
缺乏 CCoE
CCoE 的目的是建立一个集中化的团队或职能部门,在推动整个组织的云计算采用、治理和最佳实践方面发挥关键作用。在这里,我们可能会问:“如果我们转向云原生的组织结构,为什么还需要一个集中化团队?” 简而言之,通过建立 CCoE,组织能够有效管理其云环境,优化业务运营,并为客户和社区提供更大的价值。
通过将云计算计划与组织的更广泛业务目标紧密关联,CCoE 确保云的采用不仅仅是技术上的转变,更是与长期目标相一致的战略举措。CCoE 的一个关键职能是制定和执行云使用的最佳实践和标准。这些标准对于保持组织内部的一致性和效率至关重要。
CCoE 为资源配置、成本优化和安全控制建立了指导方针,确保所有云活动都与组织的运营和战略需求相一致。AWS 发布了一篇关于如何构建 CCoE 的白皮书,接下来让我们深入探讨其关键建议。
CCoE 结构
AWS 发布了一篇关于建立 CCoE 的白皮书,以帮助组织进行转型。根据这篇白皮书,CCoE 通常分为两个团队:
-
云业务办公室(CBO):CBO 将 CCoE 提供的产品和服务与企业客户和领导层的需求对接。它充当技术团队与业务利益相关者之间的桥梁,确保云项目与组织的目标和优先事项保持一致。
-
云工程:该团队将标准云服务配置与组织的企业标准之间的差异进行编码。他们将这些编码后的模式打包,并持续改进,使其成为可供客户自助部署的产品。
让我们探讨构建有效 CCoE 的策略。
创建 CCoE 的推荐策略
以下是一些创建 CCoE 的推荐策略:
-
定义明确的目标和长期愿景:CCoE 应当具备明确的、可衡量的目标,并且这些目标要与组织的整体业务目标保持一致。通过制定包含雄心勃勃项目的长期路线图,可以推动云计算的采纳和创新。
-
发展深入的云计算专业知识:CCoE 需要对目标云平台有深入的了解,包括其服务、性能、监控、成本优化和安全最佳实践。这种专业知识对于引导组织顺利实施云计算至关重要。
-
建立云治理和政策:CCoE 负责制定和执行云治理政策,以确保成本效益、安全性和合规性。这包括定义云架构原则、部署标准和自动化实践。
-
衡量成功并进行迭代:CCoE 应当收集与云项目相关的指标和关键绩效指标(KPI),并将其与既定目标进行比较。这些数据有助于判断 CCoE 是否提供了预期的价值,并识别需要改进的领域。随着条件的发展,CCoE 战略应做出相应的调整。
总结来说,一个建立良好的 CCoE 对于有效管理云环境至关重要。它确保组织能够优化运营、快速创新,并为客户提供显著价值,同时保持合规性和安全性。没有这样一个集中式的职能,组织可能会面临碎片化的努力、错失机会以及增加的摩擦和低效,尤其是在全球项目中。
在我们总结集中治理和明确角色与责任的重要性时,必须认识到,并非所有组织都相同。虽然一个结构良好的治理框架对于保持云环境中的安全性、合规性和运营效率至关重要,但一些组织可能会抵制标准化,认为其独特的业务需求过于专业化,无法采用此类做法。
在下一节中,我们将详细探讨这种思维方式,讨论拒绝标准化治理框架所带来的风险和挑战,以及这如何导致低效、增加风险和错失云操作中的机会。
我们的业务太特殊,不能采用保护措施或标准
这是一个常见的误解。在我们的经验中,几乎每个组织都认为其 IT 环境过于独特或复杂,无法实施标准化的保护措施或治理做法。然而,当审计时间临近时,这些相同的组织往往发现自己不得不匆忙建立他们最初抵制的控制措施。感知到的复杂性掩盖了对实施必要控制措施的深层次犹豫。无论业务看起来多么专业化,在遵守政府、金融或行业特定标准时,这些要求都必须得到满足。
真实的挑战不在于业务的独特性,而在于其是否愿意克服这种抵触情绪,建立必要的治理结构。
在本节中,我们将探讨数据洞察的重要性、治理、风险和合规性(GRC)政策的关键作用,以及清晰的责任、问责、咨询和告知(RACI)模型的必要性。
了解保护措施的概念和优势
云治理中的保护措施是关键工具和预定义的政策与实践,它们引导团队朝着合规和安全使用云资源的方向发展,营造一个在不妥协安全的情况下促进创新的环境。
作为集中治理的基础元素,这些保护措施提供了一种平衡的方式,既允许在操作中灵活性,又确保基本控制措施牢固到位。它们既是指导方针也是边界,赋能团队在执行强有力的保障措施的框架下,有效地利用云资源,以确保遵守法规、标准和组织政策。
通过在整个组织中促进一致性、可扩展性和问责制,保护措施确保了管理云资源的统一方法。接下来将概述保护措施的优势以及为何使用它们的原因。
保护措施的关键优势
以下是保护措施所提供的一系列优势:
-
增强的安全性:保护措施在组织中强制执行安全协议,确保遵循保护敏感信息和关键系统的做法。这些协议可能包括对传输和静态数据的强制加密、基于最小权限原则的访问限制以及自动化的安全更新。通过标准化安全措施,保护措施减少了风险并增强了云环境的安全性。
-
合规性保障:自动化合规性以满足监管要求,降低违规和罚款的风险。保护性控制通过限制数据存储在特定区域或确保遵循如 HIPAA 或 PCI-DSS 等法规来执行数据主权法。这种自动化减少了人工监督的需求,帮助组织轻松保持合规。
-
一致性与标准化:在所有团队中强制执行标准化的政策和流程,确保云资源的一致部署与管理。这可以减少配置错误、提高云服务之间的互操作性,并简化新团队成员的入职与培训。
-
审计与报告:保护性控制通过提供审计轨迹和云使用与合规性详细报告来改善治理。这些功能帮助组织识别低效、管理风险,并为内部审计或外部审查提供问责制,支持云战略的持续改进。
保护性控制通过将合规性直接集成到部署过程中,简化了云原生环境中的生产路径。AWS Config 合规性规则、AWS SCP 和 Azure Policy 合规规则等工具使开发人员和工程师在发布更新或新功能时可以更加专注。这种专注不会造成信息孤岛,而是建立了明确的可执行边界。请看下面的图示,它展示了 AWS 组织中的一组 AWS 账户。

图 3.6 - 带成员账户的 AWS 组织 OU(请重新绘制)
在这个示例中,应用账户级别的规则,指定只能部署明确的资源,如 Lambda 函数或 Fargate 任务。这种设置形成了一种一致的保护性控制,确保只有在明确批准的情况下才会发生偏差,从而在部署过程中保持合规性和控制力。为了优化保护性控制的使用,必须区分不同类型的保护性控制。下一节将提供详细的概述。
理解应使用哪些保护性控制
随着我们对保护性控制的理解不断深入,为了更好地利用它们,我们应当将其划分为两个部分:主动式和侦测式。
主动式保护性控制对于云治理至关重要,因为它们可以在问题发生之前防止问题,而侦测式保护性控制则是在问题发生后识别并处理问题。主动式保护性控制在确保云环境安全和合规方面发挥着重要作用,减少了对反应性措施的依赖。事实上,预防性和主动式保护性控制的设计目的是防止在环境中创建不合规的资源。为了简便起见,我们将它们统称为主动式保护性控制。
主动式保护性控制的好处包括以下几点:
-
最小化安全漏洞:从一开始就实施主动措施和最佳实践可以显著减少安全事件。例如,强制执行仅授予必要权限的身份和访问管理(IAM)策略可以防止过度权限。
-
确保持续合规:部署过程中的自动化检查验证是否遵守法规,保持持续合规。例如,护栏可以通过标记个人数据并限制部署到批准的地区,强制执行 GDPR 合规性。
-
减少运营开销:主动型护栏在问题发生之前就加以防范,从而减少了人工干预的需求,节省了资源。例如,强制资源标记可以确保从一开始就准确分配成本,简化成本分析。
-
标准化部署:护栏确保云中配置的一致性,减少复杂性并提高可管理性。例如,带有护栏的基础设施即代码(IaC)模板为所有 Web 服务器标准化安全组、补丁计划和监控。
-
加速安全开发:将安全性和合规性检查嵌入部署过程中,加速了安全应用程序的交付。例如,CI/CD 管道中的护栏在部署前自动扫描代码中的漏洞和合规性。
侦测型护栏通过在资源部署后检测违反安全政策的资源来工作。当与自动修复结合使用时,它们被称为修复控制。
侦测型护栏的好处包括:
-
识别问题:这些护栏持续监控云环境,以检测和标记已发生的不合规资源或行为,为潜在的安全漏洞、配置错误或可能已通过预防措施的政策违规提供洞察。
-
事后处理:侦测型护栏允许在部署后识别和修复问题。虽然它们不适用于严重的安全问题,但它们对于识别和解决轻微的合规性偏差或被忽略的设置非常有用。
-
监控和报告违规行为:侦测型护栏提供持续监控和详细的违规报告,帮助组织保持对其云环境的可见性。例如,AWS Config 规则可以监控和报告违反组织政策的资源配置,而 AWS CloudTrail 可以记录未经授权的 API 调用或对关键资源的更改。
通过理解和实施侦测型与主动型护栏,组织可以建立一个安全、合规且高效的云环境,不仅能保护免受潜在威胁,还能优化运营和成本。
下一部分将详细介绍 RACI 模型,进一步解释如何划分角色和责任,以增强组织效率并澄清云治理中的职责。
RACI 模型
明确组织内的角色和责任至关重要。只有做到这一点,才能避免模糊责任和低效等陷阱,这些问题可能会破坏云计划的顺利推进。RACI 模型是一种责任分配矩阵,作为一种有效的工具,帮助定义这些角色和责任,确保云运营模型中的每项任务都能精准和负责任地执行。
在本节中,我们将探讨云治理中的 RACI 模型,说明其组成部分,并详细阐述一个实施不当的 RACI 模型如何导致更多云原生反模式的出现。
RACI 模型有助于澄清在云治理框架内,谁对各种任务负责、问责、咨询和知情。以下是一个表格,概述了如何将 RACI 模型应用于云治理中的关键任务:
| 任务 | 负责人 (R) | 问责人 (A) | 咨询人 (C) | 知情人 (I) |
|---|---|---|---|---|
| 定义云治理框架 | 平台工程团队 | CIO/CTO | 安全团队、合规团队 | 所有利益相关者 |
| 建立治理政策 | 平台工程团队 | CIO/CTO | 法务团队、安全团队 | 全体员工 |
| 实施安全控制 | 安全团队 | CISO | 平台工程团队 | 所有利益相关者 |
| 监控合规性 | 安全与合规团队 | 合规官 | 安全与平台工程团队 | 所有利益相关者 |
| 云资源配置 | 平台工程团队、运营团队 | 平台工程经理 | 应用负责人、安全团队 | 所有利益相关者 |
表 3.6 - RACI 细分示例
理解和解决云治理 RACI 模型中的以下反模式至关重要,因为这些陷阱可能会显著削弱云操作的有效性,导致操作效率低下、责任不明确以及风险增加。通过识别这些常见错误,组织可以更好地调整其治理结构,以与战略目标保持一致,从而确保更顺畅的执行、更强的协作以及在云环境中的更可靠合规性。下表突出显示了 RACI 模型的典型挑战以及应采取的解决方案:
| 挑战 | 解决方案 |
|---|---|
| 角色过载与模糊不清 | 通过确保每个角色都有明确的范围来澄清和限制角色。避免将过多任务分配给单一角色,并定期审查角色,防止瓶颈问题。 |
| 将 RACI 作为万能工具 | 通过聚焦于关键治理领域,选择性地使用 RACI。避免过度细化,确保其能有效解决具体问题。 |
| 缺乏协作 | 通过让所有相关团队(包括 CCoE)参与 RACI 的制定,促进跨团队协作。鼓励开放对话,确保覆盖所有责任。 |
| 未更新 RACI | 定期审查和更新 RACI,以与不断发展的治理实践保持一致。确保其反映云策略和责任的变化。 |
表 3.7 - 使用 RACI 模型解决挑战
这引出了一个强大云端 GRC 框架的重要性。尽管 RACI 模型有助于明确角色和责任,但云原生 GRC 政策为解决现代云操作的复杂性提供了必要的结构,尤其是对于那些认为自己过于独特以至于无法采用标准化守则和实践的组织。
在下一部分,我们将深入探讨云原生 GRC 框架如何解决这些问题,提供一种综合治理方法,平衡灵活性需求与合规性和安全性的要求。
得到认可的 GRC 政策的必要性
没有任何企业过于特殊或独特到可以绕过强有力的 GRC 政策的需求。这些框架对于有效管理风险、确保合规性以及在任何组织内部建立一个坚实的治理结构至关重要。没有得到认可并且持续执行的 GRC 政策,企业很可能会遇到实施不一致、增加操作成本和容易缓解的脆弱性等问题。
GRC 政策的关键要素
以下是 GRC 政策的关键要素及其描述:
| 关键要素 | 描述 |
|---|---|
| 治理 | 建立组织内决策、问责和监督的框架。这包括定义角色和责任、设定战略目标,并创建监控和报告的流程。有效的治理确保云项目与整体业务目标保持一致,并且对于云相关的决策有明确的责任追究。 |
| 风险管理 | 包括识别、评估和缓解可能影响组织的风险。在云原生治理中,风险管理涵盖了数据安全、供应商锁定和与云采用相关的合规风险等问题。 |
| 合规性 | 确保遵守监管要求、行业标准和内部政策。在云环境中,合规性可能涉及确保数据驻留要求得到满足、维持适当的访问控制以及实施必要的加密标准。 |
表 3.8 - GRC 政策要素
执行 GRC 政策的重要性
即使是最精心制定的 GRC 政策,如果没有适当的执行,也会变得无效。当这些政策没有被一致应用或责任不明确时,它们就会退化为仅仅是指导方针,缺乏推动真正治理或有效减少风险的力量。这种执行不足会导致显著的治理漏洞,增加操作成本、带来脆弱性,并削弱组织处理突发事件和维持合规性的信任。
请注意以下执行 GRRC 政策的挑战。
执行 GRC 政策的挑战
以下是执行 GRC 政策的挑战:
-
应用不一致:当 GRC 政策在不同团队、部门或项目之间应用不一致时,会造成治理执行中的差异。这些不一致可能导致某些领域的治理不足,造成可以被利用的漏洞。这种不一致性还使得衡量政策有效性变得困难,因为不同的团队可能以不同的方式解读和执行政策。
-
缺乏问责制:如果角色和责任没有明确界定,执行 GRC 政策就会成为一项挑战。当没有建立问责制时,合规性就没有明确的责任人,容易导致合规问题未被发现或未得到解决。这种缺乏问责制的情况可能导致一种文化,其中政策被视为可选,从而进一步削弱治理框架。
-
增加运营负担:GRC 政策执行不一致需要额外的资源来管理和修正偏离既定标准的情况。这种反应式方法不仅消耗资源,而且效率低下,因为它通常是在问题已经造成干扰后才进行处理。持续的纠正需求增加了运营成本,并使资源从更具战略性的工作中转移。
-
跨层复杂性:在组织的各个层面执行 GRC 政策,如网络、基础设施、操作系统、应用程序、数据、边缘计算和Web 应用防火墙(WAFs),会增加显著的复杂性。每一层可能都有其独特的需求和挑战,这使得确保一致的政策执行变得困难。此外,管理跨层控制,如凭证扫描和确保一致的政策应用,需要精密的协调和监控。在不同层由不同团队管理的环境中,这种复杂性更加严重,可能导致执行上的漏洞,并增加风险。
如果没有严格执行,即使是最有意图的 GRC 政策也无法提供组织在云端安全、高效运营所需的安全性、合规性和风险缓解。持续的执行确保 GRC 政策不仅仅是理论性的指导方针;它们成为组织运营架构的不可或缺的一部分,推动合规性,降低风险,并增强组织在应对现代云环境复杂性方面的信心。考虑到这一点,我们进入最后一部分,关于缺失的反馈回路。
缺失的反馈回路
在动态的云计算领域,由于该领域的快速发展性质,反馈循环至关重要。反馈循环促进持续改进,使组织能够随时间调整和完善其云治理实践。
在本节中,我们深入探讨了缺失反馈循环的重要后果,强调了强大的变更管理流程的重要性,以及左移以培养积极文化的必要性。我们将探讨这些概念如何无缝集成到操作模型中,通过现实世界的例子和讨论云反模式来说明这些关键点。
反馈循环是什么?
将反馈循环视为云治理的雷达系统。就像雷达扫描环境以检测变化和潜在威胁一样,反馈循环实时监控我们的云战略的有效性。它们为我们提供持续的洞察力,展示我们的治理框架表现如何,突出成功和改进的领域。
在快节奏的云计算世界中,新技术和威胁经常出现,这些循环对于确保我们的政策和实践保持相关、有效并与我们的整体业务目标一致至关重要。反馈循环通过收集来自我们云基础设施的每个层面的数据,从网络配置到应用性能,再到安全事件和合规检查。然后分析这些数据以识别模式、趋势和异常,为我们提供可操作的见解。通过将这些见解整合回我们的治理策略,我们可以做出明智的调整,增强我们的云环境的安全性、合规性和效率。
为什么我们不能忽视反馈循环
无论您是开发/DevOps/DevSecOps/平台工程师,在整个云原生组织中反馈循环都是至关重要的,不仅提高效率,还增强响应能力。在警报的情况下,当 CPU/内存或存储达到临界点时,它们是即时反馈提供者,可能导致我们整个应用程序崩溃。
现在,对于传统的 IT 组织来说,反馈循环并不新鲜;通过诸如 Nagios 和 Zabbix 等监控工具,它们已经存在一段时间了。然而,它们只解决了整个反馈系统的一部分。对于云原生,我们希望它从端到端 - 部署工具、操作系统、容器、无服务器函数调用,所有这些都要涵盖。要问的问题是,如果忽视它会对我们的组织产生多大影响,这是需要思考的。为了更好地理解这一点,让我们看看为什么我们不能忽视反馈循环:
-
持续改进:反馈循环对于在问题升级成更大难题之前识别治理框架中的弱点至关重要。无论是加强安全控制、优化资源分配,还是完善合规实践,反馈循环都使我们能够进行持续的、数据驱动的改进,从而保持云环境的安全、合规和高效。
-
提高响应能力:反馈循环使我们能够迅速应对新的挑战,无论是合规要求的突然变化、新的安全威胁,还是业务战略的调整。通过定期的反馈评审,我们可以实时调整治理实践,确保云端操作保持敏捷并与组织目标保持一致。在这里,我们需要的是一个主动设置和反应机制。
-
增强决策能力:不再是依赖直觉或不完整信息做决策的时代。反馈循环为我们提供了做出明智决策所需的硬数据。通过监控关键指标,如合规率、安全事件和成本趋势,我们能够清晰地了解哪些措施有效,哪些需要调整。这种数据驱动的方法使我们能够做出既有效又符合长期战略目标的决策。
在实施这些反馈循环时,我们不仅仅是在创建一个反应性的云治理框架;我们是在构建一个有能力应对挑战的主动型组织。
时间和精力的成本
在云原生开发的快节奏世界中,缺失反馈循环可能会严重阻碍开发过程的效率和效果。缺乏及时的反馈不仅会拖慢开发周期,还会增加开发人员的压力,导致挫败感、错误和错过截止日期。
假设一个开发团队使用 GitHub Actions 自动化将其应用程序部署到 AWS。虽然 GitHub Actions 提供了一种简化的方式来构建、测试和部署代码,但这一过程中缺乏强有力的反馈循环可能会带来重大挑战。
如果没有即时反馈,团队可能会将变更推送到主分支并启动部署过程,但直到很久之后才发现,由于基础设施配置错误或代码中的漏洞,部署失败。这种延迟发现问题意味着开发人员长时间处于未知状态,不知道他们的变更已经引入了问题。因此,他们继续在错误的假设下工作,认为一切正常,从而加剧了问题。
开发周期放缓,压力增加
在这种部署过程中缺乏反馈循环会减慢整个开发周期。开发人员不是在部署失败或性能问题发生后立即收到通知,而是在这些问题有机会显现并可能影响生产环境之后才得知。这种延迟的反馈迫使团队进入被动模式,在问题被引入很久之后,他们必须匆忙诊断和修复问题。缺乏主动警报意味着问题通常在最糟糕的时候被发现,即在关键的生产时间或重大发布之前。
这种被动的方法不仅减缓了开发过程,还给开发人员增加了压力。没有早期警告系统,开发人员不得不承担额外的烦恼,解决问题,这些问题本可以在管道的早期阶段被预防或捕获。不断应对问题的压力可能导致疲劳,生产力下降,并且开发人员匆忙应对以满足截止日期,代码质量也会下降。为避免这些陷阱,至关重要的是在开发和部署过程中实施健壮的反馈循环。
这种确切的情况曾发生在我们的一个客户身上。我们从头到尾构建了他们的流水线作为 MVP,展示了 GitHub Actions 和 Kubernetes 良好配合的效果。为了确保一致性,在容器构建后我们提供了测试以确保应用程序能够运行。考虑到它是一个 Docker 容器,可移植性至关重要,因此我们在流水线中进行了测试,而不是在另一个集群中进行测试。在 MVP 后,构建了更多的流水线,但没有包括我们之前为其创建模式的测试,并将容器部署到 Kubernetes 集群中。没有进行适当的测试,混乱随之而来。
假设非生产环境和测试环境并非完全关乎业务关键性,但在这种情况下,新的容器使集群崩溃,因为它们导致了其他依赖的 API 失效,从而影响了其他团队。在 GitHub Actions 的情况下,集成自动化测试、基础设施检查和实时监控等反馈机制可以为开发人员提供所需的信息,使其能够迅速做出明智的决策。例如,如果由于配置错误导致部署失败,应立即向开发团队发送通知,详细说明失败的原因并建议可能的修复方法。
通过纳入这些反馈循环,开发过程变得更加灵活和响应迅速。开发人员可以在问题出现时立即解决,从而减少问题升级为重大事件的风险。这种主动的方式不仅加速了开发周期,还减轻了开发人员的压力,使他们能够专注于编写高质量代码并进行创新,而不必时时担心不可预见的问题会扰乱他们的进度。以下图表提供了有关在开发管道中何处应用反馈的见解:

图 3.7 - 带反馈循环的 CI/CD 管道(请重新绘制)
反馈循环赋予我们适应变化的能力,无论是好是坏。这自然引出了我们的下一个话题——变革管理。基于我们对云治理中反馈循环的讨论,必须理解,采用“左移”方法如何通过提前解决开发过程中的潜在问题,进一步增强这些实践。
变革管理在云治理中的作用
就像在传统 IT 组织中一样,在云原生组织中,变革管理依然至关重要;不同的是,它们的调用和运行方式有所不同。通过一个合适的反馈循环系统,我们可以依赖于每次变更时,成功与失败的影响都能被提前了解,在达到目标之前,变革管理将会按其流程进行。
在传统 IT 组织中,对于大多数环境,从开发到生产,变更需要通过某种形式的IT 服务管理系统(ITSM)提交变更请求。然后,变更请求需要提交给变更咨询委员会(CAB),在那之后,变更才可以进行。
云原生组织不能完全摆脱变革管理,因为没有变革管理会导致以下后果:
-
不一致的实施:我们一再看到,变化在各团队和环境中实施不一致,导致治理和安全方面存在显著差距。这就像没有蓝图建房子:表面看起来稳固,但随着这些不一致的存在,它崩塌只是时间问题。
-
抗拒变革:工程师们对新流程产生抗拒,因为他们感到信息不足或没有参与其中。这就像试图将方形的钉子塞进圆孔里:根本不合适。结果是采用率低,且可能引发冲突,甚至会打乱最周密的计划。
-
运营中断:这可能会导致停机、效率低下以及更高的错误风险。这就像在没有指南针的情况下航行在风暴海上:没有明确的方向,我们可能会迷失方向,且难以保持航向。
通过理解这些困难,我们可以制定一个有条理的变更管理程序,直接应对这些问题。
GitOps 模型是云原生组织正在采用或已采用的现代管理流程。在 GitOps 模型中,变更管理深度集成到版本控制系统中,利用 Git 作为所有基础设施和应用配置的唯一真实来源。这种变更管理方法确保了对系统的每一次修改,无论是代码更新、配置调整,还是基础设施变更,都能被追踪、审计且可回滚。该过程本质上是协作性的,通过拉取请求(PRs)提出、审查和批准变更,确保所有利益相关方在实施任何变更之前都能有可见性并提供意见。
当通过 PR 提出变更时,它会触发一系列自动化流程,包括测试、验证和部署。这不仅加快了变更过程,还降低了错误的风险,因为每次变更在合并到主分支并应用到生产环境之前都会经过充分的审查和测试。
以下表格进一步详细说明:
| 阶段 | 描述 |
|---|---|
| 拉取请求 | 开发人员或工程师通过在 Git 仓库中创建 PR 来提出变更。PR 包括对代码、配置或基础设施即代码(IaC)文件的具体更改。 |
| 自动化测试 | PR 触发自动化测试流水线,运行单元测试、集成测试和安全扫描,确保变更不会引入任何问题。 |
| 代码审查 | 团队成员对 PR 进行审查,提供反馈并建议改进。审查过程确保在变更合并之前,多个利益相关方达成一致。 |
| 审批流程 | 一旦审查完成并且任何要求的更改已进行,PR 将由授权人员(如高级开发人员或团队负责人)批准。 |
| 自动化部署 | 经批准后,变更将自动合并到主分支中。此合并触发部署流水线,将变更应用到相关环境中(例如,预发布、生产环境)。 |
| 监控与回滚/前进 | 部署后监控确保变更按预期行为运行。如果出现问题,变更可以通过回滚 PR 快速恢复系统到先前的状态。 |
表 3.9 - GitOps 变更请求详情
将变更管理集成到操作模型中
为了将变更管理有效地整合进云治理操作模型,组织将采纳以下实践:
-
明确目标:任何成功变革计划的第一步是定义明确的目标。我们希望通过这次变革实现什么?明确我们的目标将简化后续的步骤。
-
让利益相关者参与进来:这包括高层管理人员、IT 团队和最终用户——任何将受变革影响的人。通过从一开始就让他们参与并持续保持沟通,我们将确保他们的支持和全面的准备。
-
提供培训和支持:既然我们已经组建了团队,现在是时候为他们提供成功所需的培训和资源了。这可以包括研讨会、网络研讨会,甚至是个人辅导课程。通过投资团队的发展,我们将减少对变革的抵触情绪,并提高实施成功率。
-
监控和回顾:最后,持续监控变化的影响并收集利益相关者的反馈至关重要。这将帮助我们识别进一步改进的领域,并做出数据驱动的决策。
左移原则
这种方法的核心在于将质量和安全性实践尽早集成到开发生命周期中,而不是等到最后才解决这些关键问题。通过将这些过程左移,靠近开发周期的开始,我们能够预见问题并在问题出现之前加以防范。
左移的好处
左移的好处包括以下几点:
-
及早发现问题:想象一下,在设计阶段发现错误,而不是在生产部署后。左移方法使我们能够及早识别并解决问题,从而节省大量时间、精力,避免后续麻烦。
-
提高质量和安全性:通过从一开始就将质量和安全性实践嵌入其中,我们确保这些元素成为开发过程的核心。这就像有一个超级英雄团队的质量和安全专家,日夜不懈地工作,确保我们的应用程序从第一天起就安全无忧。
-
更快的市场响应时间:后期缺陷通常会延迟发布。通过左移,我们可以告别这些临时出现的问题。通过尽早解决问题,我们能够比以往更快地将应用程序推向市场。
在之前的一次咨询合作中,我们为一家准备在澳大利亚开展业务的跨国金融集团优化了开发流程。此方法确保了完全遵守澳大利亚的网络安全控制和 PCI-DSS 要求,同时防止 个人身份信息(PII)在公共云基础设施上的存储。为此,我们将安全性和合规性检查直接集成到 CI/CD 管道中。
使用了 Bitbucket 管道来自动化构建和部署流程,并且结合使用了 AWS Config 和 Security Hub,持续监控资源是否存在任何偏离既定政策的情况。
对于那些不熟悉 AWS Config 的人来说,它是一项服务,提供关于您账户中 AWS 资源配置的详细视图。其他云平台也提供类似的服务:
-
在微软 Azure 中,相应的服务是 Azure 策略,它允许你创建、分配和管理策略,以便在你的资源配置中执行规则。
-
在谷歌云平台中,Cloud Asset Inventory 提供了一种方式,可以查看、监控和分析所有 Google Cloud 和 Anthos 资产,跨项目和服务进行管理。
这些服务对于确保遵守组织指南和监管标准至关重要。例如,AWS Config 利用功能即服务(FaaS)来修复检测到的问题。Azure 和 Google 也可以通过 Azure Functions 和 Cloud Run 实现相同的功能。
通过向左移动并实施自动化治理检查,我们可以在开发过程的早期发现并解决安全漏洞和合规性违规问题。
云治理的卓越不仅仅是执行最佳实践;它还需要培养一种主动参与和创新的文化,在这种文化中,团队能够预见挑战并推动持续改进,且具备相应的能力和授权。
创建主动的文化
在云治理中培养主动文化始于领导力。作为领导者,我们必须通过参与技术细节、强调质量和安全的重要性,并积极支持团队,来展示我们希望团队看到的行为。这为主动行为设定了明确的标准,而这种行为对于保持强大的云治理至关重要。
然而,以身作则仅仅是第一步。为了赋能我们的团队,我们必须为他们提供实施最佳实践所需的知识和工具。这包括投资于全面的培训项目,提供对最新云治理技术的访问权限,以及整理一套技术资源库。更为重要的是,识别和奖励主动行为,比如早期发现安全漏洞或提出改进建议,有助于加强这些行为的价值,并帮助在组织中深入根植主动思维。
这里将详细讨论一些策略:
-
以身作则:有效的云治理始于领导力。作为领导者,展示我们期望团队展现的主动行为至关重要。这包括直接参与技术细节,展示质量和安全的重要性,并积极支持我们的团队。通过这样做,我们设定了一个鼓励他人效仿的标准。
-
提供培训和资源:仅仅有领导力还不够;我们还必须赋能团队,提供他们所需的知识和工具。这包括投资于全面的培训项目、整理一套最新的技术资源库,并确保能够访问最新的云治理工具和技术。团队得到充分装备后,更能从一开始就实施最佳实践。
-
识别并奖励积极主动的行为:最后,至关重要的是要承认并奖励那些表现出积极主动行为的人。无论是早期识别潜在的安全漏洞,还是建议改进云治理框架,庆祝这些贡献能够强化其价值,并鼓励整个组织内持续改进的文化。
一个积极主动的文化需要一个可以在其上进行操作/构建的环境。这里的沙盒环境对于实现积极主动的文化至关重要,并帮助避免早期的反模式,即学习会 神奇地发生。
激励和提升
通过将沙盒环境融入我们的开发流程,并促进积极主动的文化,我们显著降低了生产环境中出现意外问题的可能性。这种方法确保变更经过彻底测试和验证,从而导致更可靠和更有信心的生产发布。我们通过以下方式实现这一目标:
-
自动化测试:在沙盒环境中实施自动化测试,确保变更符合我们的质量和安全标准。通过尽早发现潜在问题,可以减少将变更推向生产环境时的意外风险。
-
持续集成与持续交付(CI/CD):利用 CI/CD 流水线自动化地将变更从沙盒环境部署到生产环境,确保一致性和可靠性。这一简化的流程最小化了人为错误的风险,并提高了我们开发周期的效率。
-
定期反馈与审查:持续收集沙盒测试的反馈,使我们能够优化和改进开发流程。通过使用这些数据做出明智、数据驱动的决策,我们可以优化云治理框架,并确保持续改进。
在云计算中,缺乏反馈循环和有效的变更管理会阻碍效率,导致实施不一致、抵制变革和运营问题。基于 GitOps 的方法,通过 PR 跟踪和审查每一个变更,确保了透明性、问责制和与业务目标的一致性。
反馈循环对持续改进和快速决策至关重要,而“左移”原则则能在开发早期发现问题。强有力的领导力、适当的培训和用于测试的沙盒环境,共同构建了一个具有韧性的治理框架,能够减少风险、加速创新并增强生产信心。
摘要
在云原生环境中,治理必须随着这些架构所要求的敏捷性和创新而发展。传统的治理模型通常是集中的、僵化的,这些模型不适用于云技术去中心化、快速发展的特性。正如本章所述,组织必须从过时、控制过重的方法转向更具适应性和灵活性的治理策略。
这包括解决一些关键的反模式,例如假设学习是自然而然发生的,或者认为集中式的方法能有效地扩展。通过培养持续学习的文化,鼓励反馈循环,并建立清晰的去中心化治理实践,组织可以避免这些陷阱。最终,云原生治理的核心是赋能团队创新的自主权,同时保持安全性、合规性和运营效率。
第四章:FinOps – 如何避免账单震惊
“FinOps 是将财务责任引入云的可变支出模型的实践,使分布式团队能够在速度、成本和质量之间做出商业取舍。”
– J.R. Storment,FinOps 基金会执行董事
我们如何知道我们投入的资金应该带来什么回报呢?为了进一步探讨这个问题,我们可以将其与建造房屋并需要设定预算的情况进行比较。我们知道需要多少个房间,需要多大的车库空间,依据气候区域的不同,我们还需要多少隔热层、空调或供暖能力。这些是立即的建造费用。然而,我们还需要考虑长期的因素。我们是否想要更好的隔热和太阳能系统以减少持续的电力费用?这意味着更高的前期成本,但也有长期的持续成本降低效益。
同样,我们需要考虑 FinOps 的短期和长期收益。这变得更加复杂,因为我们的云环境比静态建筑施工更具动态性。FinOps 需要成为一种持续的纪律。那么,我们如何在支付合理价格、实施合适解决方案、满足时间要求并获得最佳价值之间找到正确的平衡呢?
“价格是你支付的;价值是你得到的”——这是沃伦·巴菲特的名言。换句话说,我们需要关注投资带来的价值,而不仅仅是看价格。在我们的案例中,投资指的是我们在构建企业云平台和在其上运行的应用程序时所付出的所有努力。我们需要评估获得的价值,如业务灵活性和增强的韧性,而不是单纯关注成本降低。
本章的目标是理解我们如何在云原生环境中获得良好的价值。我们将重点关注以下几个方面:
-
错失良好的标签实践的潜力
-
未充分利用云原生工具
-
忽略不明显的云服务提供商(CSP)费用
-
过于专注于节省成本,而忽略驱动价值
这其中有很多内容,我们将逐步进行分析。在我们能够衡量价值、提升成本治理、并处理成本所有权之前,我们将先探讨如何在云中启用成本分配。一切都从元数据开始,也叫做标签或在云资源管理范围内的标记。让我们深入了解一下。
错失良好的标签实践的潜力
标签是作为云资源元数据的键值对。标签是一种将标签分配给云资源以描述它们的做法。标签有助于高效地组织、管理和追踪资源。
标签不仅有助于提供成本细分,还能帮助管理、识别、组织、搜索和筛选资源。标签的好处如下:
-
资源管理:标签有助于按产品或项目、环境、成本中心、业务单元等类别组织资源。这使得搜索特定资源变得更加容易。
-
安全性和合规性:标签可用于强制执行身份和访问策略,并控制对资源的访问。例如,如果某个资源标签描述了一个存储信用卡信息的数据库,我们可以实施一项策略,确保人类无法读取该数据。
-
自动化:标签可以用于驱动部署和自动扩展行为,或自动关闭资源。
-
操作效率:标签在发生事件时有助于故障排除,因为它们提供了额外的上下文。它们还可用于精细化监控,并驱动警报行为。
-
成本管理:标签有助于分配和跟踪成本。我们可以使用它们来细分成本并组织我们的资源。在本节的其余部分,我们将重点关注这一方面。
即使标签简单到只是描述键值对,许多问题仍然可能出现,我们将讨论两种反模式。
常见的反模式
与标签相关的反模式通常始于我们在标签标准或标签强制执行方面的不足,接下来我们将深入探讨这些领域。
缺乏标签标准
第一个反模式是缺乏标签标准,我已经见过很多次。这种反模式发生的原因有很多。可能是由于云原生采用没有得到足够关注,因为一个组织试图有机地扩大云足迹,并且云迁移始终没有取得进展。也可能是因为公司陷入了被动模式,无法进行战略性操作,或者是因为优先事项冲突。
事情通常是这样发展的:一个组织正在采用云技术。然而,云采用模型存在一些漏洞,特别是在治理、自动化、标准化和服务目录提供方面。因此,分散的产品团队在配置云资源时管理方式各异。应用标签是可选的。尽管团队最终会决定应用标签,但不同团队之间的标签不会一致。
这意味着我们将会有一些资源根本没有标签,或者只有部分标签,而且这些标签本身很可能不一致,无论是键、值,还是两者都不一致。因此,我们将错过许多 FinOps 的守护措施,我们将在分析第二种反模式后进一步探讨这一点。
缺乏标签强制执行
第二种变体是有强制的标签标准,但未进行强制执行。因此,我们的标签覆盖率可能会比第一种变体更好。然而,我们仍然依赖于人工的完美执行。
每个工程师都必须确保为每个云资源分配了所有标签。这意味着键和值必须完美匹配。
在一次咨询项目中,我分析了不同云环境中的标签。随着时间的推移,成本中心的标签已经多次更改。客户使用了以下几种组合作为关键字:“cost-centre”(英国拼写)、“cost-center”(美国拼写)、“costcentre”(全小写)、“CostCentre”(Pascal 命名法)、“costcentre”和“costcenter”。
由于标签在 AWS 中是区分大小写的,这导致了六种不同的标签类别。因此,计费报告也以六种不同的变体进行了可视化,要求手动修正才能实现成本分解。另一个常见的错误是使用产品所有者的姓名作为标签值。然后,个人离开组织并且他们的账户被停用。这样我们就会有一个无效标签,甚至不知道之前的应用程序所有者属于哪个部门。如果没有所有权空缺,这会让追踪新的应用程序所有者变得困难。
正如我们所能想象的那样,这并不是一个令人兴奋的活动,每个月都必须执行,并且增加了人为错误的风险。
不良标签实践的后果
如果没有足够的标签,我们将面临多个影响:
-
成本分配变得具有挑战性:我们无法将成本分配到成本中心、利润中心或部门。这使得追踪和管理预算变得困难。成本分配不清晰的常见结果是缺乏所有权和问责制。
-
成本优化变得具有挑战性:没有足够的标签,我们将很难识别未充分利用或未使用资源的所有者。因此,没人会采取行动来调整资源规模或关闭不必要的资源。
-
财务报告不准确:财务报告依赖于准确的标签。这意味着我们需要手动分配成本,或者接受不准确的报告。在后一种情况下,意味着我们无法公平地分配成本。
-
标签不完整也会导致预算不精确:这可能导致预算超支和预测不足。如果没有正确反映当前的支出,我们将难以预测未来的费用。
-
缺乏显示回溯或分摊回收费流程:“分摊回收费后果”模型,即将费用计回发生费用的部门或产品团队,极度依赖于准确的标签。没有准确的标签,实施一个公平和透明的回收费系统变得困难,并且需要大量人工处理数据。使用显示回溯模型时,部门会看到其云支出,但不会实际计费。标签不足可能减少透明度,导致争议、混乱,甚至可能产生不信任。
-
缺乏所有权:如果没有有效的回收费流程,就无法明确所有权,而明确所有权对于实现良好的价值至关重要。因此,我们将错失良好的 FinOps 实践,包括超支,因为我们未充分利用云资源。
-
缺乏策略执行:云治理政策通常依赖标签来强制执行规则和最佳实践。不足的标签化可能削弱治理,导致成本失控。标签提供了对组织内资源使用情况的可见性。没有标签,很难确保资源的使用符合政策要求,并且效率得以保障。
发现未打标签资源
不足的标签化的常见根本原因包括部署方法不一致、未利用策略即代码框架、缺乏标签标准以及缺少自动化,导致标签强制执行的遗漏。验证标签键和值将为我们带来确定性。根据云服务提供商(CSP)的不同,有不同的方法来实现这一点。我们现在从 AWS 开始研究。
AWS 中的未打标签资源
如果我们有访问控制台或云 Shell 的权限,可以自己进行验证。如果我们想在 AWS 账户中查找未打标签的资源,可以使用 AWS 资源浏览器中的资源搜索功能,并使用tag:none过滤查询。如我们所见,这个方法相当直接,接下来我们将探讨如何在 Azure 中解决这个问题。
Azure 中的未打标签资源
在 Azure 中,我们可以使用 PowerShell 命令,如下所示:
$resources = Get-AzResource
$untaggedResources = $resources | Where-Object { -not $_.Tags }
$untaggedResources | Format-Table Name, ResourceType, ResourceGroupName, Location
在前面的代码片段中,发生了以下操作:
-
第一个命令获取所有资源
-
第二个命令过滤所有未打标签的资源
-
第三个命令以表格格式显示所有未打标签的资源,表格展示了资源名称、资源类型、资源组名称以及位置(区域)。
现在我们将研究在 GCP 中所需的步骤。
GCP 中的未打标签资源
在 GCP 中,我们也可以使用云 Shell 搜索未标记的资源,如下所示:
gcloud asset search-all-resources \
--scope='projects/<project_name>' \
--asset-types='container.googleapis.com/NodePool' \
--filter=-labels:*
如果我们还没有启用云资产 API,可以通过第一个命令来启用。第二个命令列出了所有没有标签的 Google Kubernetes Engine 节点池。在此范围内,我们需要将project_name替换为我们的项目名称。labels:*过滤器会将搜索结果限制为无标签的资源。
如果我们没有控制台或云 Shell 的访问权限,可以请有权限的人运行前面的命令,验证标签的覆盖范围和准确性。否则,我们还可以联系管理 CSP 账单的人员,验证当前的成本拆分是否准确。验证这两个选项是个好主意,因为组织内部可能会有不同的看法。在这种情况下,组织一个研讨会,通读证据,包括最后的账单、CSP 的成本仪表板,并运行一些命令验证标签,将非常有帮助。
一旦了解了我们当前的状态和不足之处,我们必须确定我们的目标状态。对于本章内容,我们将只专注于与 FinOps 相关的标签,而不是可能对安全、合规性、可观察性或其他操作方面有帮助的标签。良好的实践是什么, 我们从哪里开始?
采用标签分类法
我们将从定义标签分类法开始,并为标签键、值和语法建立标准。
标签键
我们需要知道我们希望从标签中提取什么信息,并指定有效且必需的标签值和键。通常,这些信息包括以下内容:
-
成本中心和/或业务领域/单位或产品组合名称:如果成本中心与业务单位之间没有 1:1 映射,且两者对费用回溯或费用分摊方法都相关,我们将需要同时使用这两个标签。
-
dev、test、uat、preprod和prod也应该在我们的标签策略中得到考虑。这为我们提供了良好的视角来验证我们在每个环境中的花费。 -
业务负责人:这应该是职位名称或角色,而不是个人的名字。它帮助我们识别业务负责人,尤其是在我们采用费用回溯模型并需要提供成本细目时。如果我们使用费用分摊模型,我们就知道该将账单信息发送给谁,并提供成本建议和预测见解。
-
技术负责人:这也需要是一个职位名称或负责人,这些信息与业务负责人一样有用。有时这可能是组织内的相同职位职能,在这种情况下,我们可以将这两个标签值合并。
-
应用程序和/或服务标识符:这些信息对于将数据与我们的应用程序清单关联非常有用。通过这种方式,我们可以回答有关应用程序清单的成本相关问题。添加应用程序功能标签也是有帮助的。
应用程序功能 有时也称为 应用程序角色,它描述一个组件是否代表数据库、展示层、业务逻辑层或数据层。它对于准确的费用回溯或费用分摊模型并非必需,但它为我们提供了关于花费的良好洞察。它能告诉我们 CSP 成本是发生在展示层、业务逻辑层、集成层还是数据层。当我们考虑重构应用程序时,这为我们提供了额外的数据点。
标签值
我们还需要标准化我们的标签值。我们必须达成一致,决定是使用单一值还是可以在键中使用列表。值需要清晰定义。例如,成本中心的正确格式是由两位数字和四个字符组合而成,或者有效的应用程序功能,如db代表数据库,api代表 API 层,int代表集成层,等等。理想情况下,这些标签应该作为 CI/CD 管道的一部分进行分配。在这种情况下,我们可以通过我们的政策即代码框架验证键和值。
语法
标记语法对键和值也很重要。语法示例包括全部小写 (costcenter),驼峰式 (costCenter),帕斯卡式 (CostCenter),蛇形式 (cost_center) 和连字符形式 (cost-center)。无论使用哪种语法,它都需要保持一致,并且我们需要检查该语法是否被我们的 CSP 支持。这适用于标记键和值。
持续改进
一旦我们建立了我们的分类法,我们需要继续建立其他标记最佳实践,以实现良好的成本控制治理模型。
标记自动化和强制执行
我们希望确保每个支持标记的资源都有一个有效的标记。我们可以使用工具如 AWS 标签策略和 AWS Config,Azure 策略或 Google Cloud 资源管理器。这将确保合规性并防止未标记的资源。如果我们有服务目录,标记应该是强制的输入参数。
对于应用功能,我们可以在服务目录项中包含默认标记,例如数据库或 API 网关。我们有多种方式可以确保良好的标记实施:
-
我们可以使用OPA或我们 CSP 的策略框架来实施政策,以确保未标记的资源除了沙盒环境外永远不能被部署。
-
当我们使用 CSP 的开发框架时,我们也可以通过类似单元测试的方法验证标签和标签。AWS 云开发工具包 (CDK) 支持断言,我们可以用它来验证标签。Azure 资源管理器 (ARM) 模板测试工具包可以用来验证 Bicep 或 ARM 模板的结构和属性。在 GCP 中,我们可以使用 Google Cloud SDK 编写单元测试来验证标签。
-
一些基础设施即代码 (IaC) 工具,如 Terraform,支持在部署级别上声明标记。这样,我们可以在部署级别上定义通用标记,如成本中心,并且只需要定义在部署或服务目录级别未定义的细粒度标记。
如果我们拥有一个政策即代码框架,我们可以强制执行标记,并拒绝创建未标记或标记不足的云资源。这样的政策可能会在我们自动定期清除资源的沙盒环境中跳过。如果我们已经建立了成熟的 DevSecOps 文化,我们希望只能通过我们的 CI/CD 管道修改标记。在这种情况下,我们可以使用防护栏来确保标记不能通过人员访问修改。
使用云原生工具进行定期审计
我们应定期审计标记,以确保其正确应用和更新。CSP 提供工具,如 AWS 标签编辑器,Azure 成本管理和 Google Cloud 资源管理器。一旦生成合规性报告,我们可以识别缺失或不正确的标记并采取纠正措施。
持续改进
我们工具或审计中的任何发现需要得到解决,确保它们能够永久修复,避免成为长期负担。一旦我们建立了标签系统,就能获得有价值的洞察。以下 Azure 图示说明了如何使用标签继承功能。启用后,标签继承会将计费、资源组和订阅标签应用于子资源使用记录。在这种情况下,我们就不需要为每个资源打标签了。这是一个非常强大的功能。

图 4.1 – Azure 示例,展示标签继承(来源:learn.microsoft.com/en-us/azure/cost-management-billing/costs/enable-tag-inheritance)
现在,我们知道如何为我们的组织设置一个稳固的标签实施。一旦我们建立了一个完善的标签框架和流程,许多其他与 FinOps 相关的服务都可以利用它,并提供良好的可视化效果。这包括成本异常检测、预算和成本警报、资源优化建议,以及制定承诺支出折扣计划的规划。
我们已经讨论了标签反模式以及如何利用云原生服务将其修复并转化为最佳实践。我们尚未讨论第三方工具,现在我们将探讨它们是否有存在的空间。
未充分利用 CSP FinOps 服务
主要的 CSP 提供商提供各种 FinOps 服务,包括成本分析工具、成本报告、预算管理、资源优化建议、节省计划、成本趋势分析、预测和警报。这些服务已经很成熟,但并不总是被使用。如果成本节约没有成为优先事项,尤其是在安全性、韧性和合规性等其他挑战需要优先解决的情况下,这种情况尤其明显。在我们探讨反模式之前,我们要明确一点,商业第三方成本管理工具是有其用武之地的。
有两个主要驱动因素可能促使我们考虑使用第三方工具进行成本管理和 FinOps 实践。第一个是如果我们有多云或多云策略。在这种情况下,我们可能需要跨多个云平台获得统一的视图。这将取决于我们的操作模型。如果我们准备在每个云平台使用不同的 FinOps 服务(例如,GCP 和 Azure),那么我们就不需要走这条路。如果团队使用多个云平台,这会增加成本管理的复杂性。也许这是一个集中式的云平台团队,负责创建成本仪表盘。
第二个驱动因素是我们是否希望在我们的 FinOps 方法中包含 CSP 平台以外的内容——例如,包含 CI/CD 工具或 SaaS 监控解决方案。在这种情况下,我们必须定义我们的需求并评估第三方工具的好处。一些 CI/CD 工具具有原生的成本控制功能,比如 GitHub 的计划和使用功能。如果我们能接受查看多个仪表盘,可能就不需要投资其他的 FinOps 第三方工具。我们需要考虑成本的权衡。我们在流程上花费的额外时间与商业产品的许可证费用相比是多少?现在,是时候探索我们如何陷入不利用云原生 FinOps 服务的反模式了。
常见反模式
我们的云服务提供商(CSP)所提供的 FinOps 服务的力量和范围常常被忽视,接下来我们将探讨两个相关的反模式。
账单会自行解决
在云采用初期或组织试图通过自然增长的方式扩大云端存在而未实施费用分摊模式时,不使用任何成本控制服务是很常见的。
我在生产规模上第一次的云端经验是在一个政府组织。我的经理知道我有 AWS 经验,他给了我他的信用卡,好让我为一个项目团队创建 AWS 账户。这种情况后来发生了好几次。几个月后,在十二月,我们举办了年终庆祝活动,费用是通过同一张信用卡支付的。因此,信用卡额度用完了,AWS 的月度付款在一月被拒付。
在二月,AWS 试图收取一月和二月的费用,导致了另一笔未付款项的情况,三月也发生了同样的事情。到那时,我们已经收到了几封自动警告邮件,警告如果未付款,AWS 账户将被关闭。
如果我们将成本管理置于更高优先级,我们本可以设置警报并主动反应。相反,我们只能对 AWS 发来的邮件作出反应,并且涉及了采购部门。由于政府组织有严格的流程,他们未能迅速作出反应。最终,支付方式从信用卡支付转为持续采购订单。然而,成本控制直到一年后才使用云原生功能实现。
几个月后,一位项目经理要求我将账单货币从美元(USD)更改为澳大利亚元,我照做了。不幸的是,采购部门未能准备好支付下一张发票,因为货币与采购订单中的货币不匹配。如果我们熟悉内部成本管理流程,这种问题是可以避免的。部门之间的协作有助于跨越这些组织边界。我们看到一个行之有效的方法是组建一个跨职能团队,定期与扩展团队代表召开会议。这些代表包括采购、财务和招聘部门。这样可以帮助我们提前发现任何潜在问题并迅速解决。这个故事应该清楚地表明:工具只是成功采用 FinOps 的一部分。在我们的运营模式中,清晰的流程和责任的定义至关重要。现在是时候研究这个反模式的另一种变体了。
匆忙使用第三方产品
我们已经探讨了为什么商业第三方产品可能有意义的原因。现在我们将讨论一个不需要使用第三方产品的场景。这两种情况有一个共同点:低水平的云采用成熟度。在这种变体中,我们希望快速取得成功。
可能的原因是,由于其他紧迫问题,如安全性、合规性和可靠性(特别是在故障后),价值实现从未成为优先事项。另一个原因可能是我们正在将财务策略从成本中心转变为利润中心。因为需要加快进度,我们没有充分考虑长期的成本影响。
在之前的公司中,我曾遇到过这样的情况:我们已经在一个开发组织中实施了基础的成本管理能力,包括成本拆分、预测、预算提醒、异常检测和承诺节省计划。不幸的是,云平台团队完全被其他团队的帮助工作压得喘不过气来,没有足够的时间来细化和严格测试这些功能,最终无法将其发布到生产组织供所有业务单元使用。
与此同时,新财年开始了,公司也从成本中心转变为利润中心。这意味着成本需要精确分配。然而,遗留应用的标签实施存在缺口。因此,一位团队经理不得不每月花费超过一天的时间来正确分配云账单。领导团队(LT)注意到了这一点,但他们只了解了一半的情况。他们低估了已经在生产组织中部署的现有成本管理服务目录项目所带来的业务利益。
一位 LT 成员参加了一个会议,并看到了一款具有漂亮用户界面的 FinOps 工具的演示。他感到好奇,在演示后提出了一些问题。仅此就足以让销售团队将公司标记为一个重要机会。供应商随后通过午餐邀请进行了跟进。根据产品的好评程度来看,那顿午餐一定非常棒。接下来的步骤是非常强烈地希望实施价值验证。由于公司运营在一个高度监管的环境中,这导致了一个全面的供应商选择过程。
这种模式导致我们将自己锁定在持续的支出中。第三方 FinOps 许可费用通常基于我们的云支出。云支出越高,我们为商业工具支付的费用就越多。
影响
通过反模式,我们已经看到了它的一些后果,现在我们想简要总结一下:
-
缺乏价值优化:如果我们没有使用 FinOps 工具,就无法优化我们的云原生堆栈的价值。我们将无法优化资源并做出正确的财务权衡决策,例如是否选择节省计划。
-
缺乏成本可见性:我们将无法提供高效且正确的费用分摊方法。因此,我们无法将责任指向业务利益相关者,这意味着缺乏优化价值实现的动机。
-
增加的供应商管理工作量:如果我们使用第三方产品,我们将需要管理一个额外的供应商。我们之前讨论过合作伙伴关系。这是一个战略合作伙伴关系吗?
-
增加的持续成本:如果我们使用第三方工具,我们将支付许可费用,这通常基于我们的云支出。我们花得越多,许可费用就越高。供应商没有激励去减少我们的云成本,因为那样也会减少他们的收入。
-
手动负担和财务报告延迟:我们将需要更多的人工工作来管理财务报告,这也会延长报告时间。因此,将很难实时了解费用或相应调整预算和预测。
即使我们具备了正确的工具,我们仍然需要建立与我们的运营模型对齐的成熟流程和责任。否则,我们将无法发挥工具的潜力。接下来我们将探讨流程和云原生服务。
从 SDLC 视角看成本管理
我们现在正在逐步了解 FinOps 的能力,并将其与 软件开发生命周期(SDLC)的简化概述对齐。下表提供了 SDLC 阶段的概览以及该阶段的 FinOps 服务的逻辑名称。我们将逐一讨论每个阶段,并探讨在为我们的应用堆栈建立良好的商业价值时需要考虑的事项。
我们已经讨论了标签管理,它需要在实施与测试阶段建立,这一阶段是该阶段的主要内容。因此,在 SDLC 流程中,我们将在讨论时将这一阶段与部署阶段合并。我们可以看到,维护与改进阶段需要考虑的事项最多。我们需要吸收这些洞察,以便在我们的迭代交付中规划和设计改进。
| 计划与设计 | 实施与测试 | 部署 | 维护与改进 |
|---|---|---|---|
| 设计原则 | 标签策略 | 预防性警戒 | 侦测性警戒 |
| 成本计算器 | 标签管理 | 组织设置 | 成本探索器 |
| 预算和警报 | 标签执行 | 自动化成本估算 | 顾问工具 |
| 成本效率架构设计 | 数据生命周期 | 成本异常检测 | |
| 资源优化建议 | |||
| 承诺支出 |
表 4.1 – SDLC 阶段及支持的 FinOps 服务
接下来,我们将查看支持第一阶段的 FinOps 服务:计划和设计。
计划与设计
FinOps 在计划和设计阶段的考虑事项和工具如下:
-
设计原则:内部的指导原则和 SLA(如 RTO 和 RPO)将推动我们的成本模型。各个 CSP 提供的 Well-Architected 框架也将提供指导。如果一个解决方案需要具备弹性,它将有一个故障转移数据库,这会增加成本。熟悉我们的需求后,我们可以开始使用绘图工具设计解决方案。现有很多可供选择的工具,Diagrams.net 是一个免费的绘图工具,而 Lucid Chart 是一个流行的商业化产品,具备企业级协作功能。该图表将帮助我们全面可视化我们希望使用的服务。
-
成本计算器:我们可以使用 CSP(云服务提供商)的定价计算器。AWS 定价计算器、Azure 定价计算器和 Google Cloud 定价计算器都提供了用户友好的界面,并支持大部分云服务。它们都支持承诺支出节省计划,提供可共享的计算 URL,并支持报告导出。使用所有成本计算器时,我们需要特别注意选择正确的区域,因为价格会有所不同。我们还需要估算使用量。对于 API 服务,我们通常需要估算 API 调用次数;对于数据服务,我们需要知道数据量、增长情况以及是否需要故障转移数据库或额外的只读数据库。对于任何出站数据,例如从一个云平台到另一个云平台,我们还需要知道数据量。如果我们实现了一个新解决方案,这些数据中的一部分将包含在业务案例和设计中。对于其他指标,我们需要做粗略估算,并可以在设计阶段进行调整,或者在解决方案部署并投入使用后建立反馈循环。
-
预算和警报:所有主要的云服务提供商(CSP)都提供预算和警报服务。预算可以通过不同方式定义——可以是静态方式,即定义一个月度预算或月度百分比增长,也可以创建动态预算。通过机器学习(ML)增强的服务可以从之前的开支中学习,并预测未来几个月的成本趋势。这是一种减少人工操作的方法,同时仍能利用成本防护措施。以下 AWS 截图显示了一个为期 12 个月的预算定义。自动填充预算金额功能会基于初始预算数额和月度百分比增长预填充过去 11 个月的数据。

图 4.2 – AWS 示例 – 预算定义(来源:AWS 控制台)
然后,预算可以用于配置触发警报,如果我们达到某个阈值,或趋势表明我们将在定义的周期结束时超出预期金额。这些警报有助于在我们收到下一个账单之前发现意外成本。
- 面向成本效益的架构设计:当我们使用成本管理和预测工具时,可以实现成本透明度。这使得我们能够将财务因素纳入架构决策中。例如,我们可能会转向无服务器架构,并为容器选择更小的实例,因为水平扩展具有更高的成本节省潜力。能够做出明智的决策,也有助于我们规划在软件开发生命周期(SDLC)后期可以使用的适当防护措施。
实施、测试和部署
这些是我们在部署阶段可以采取的措施。第一个是实施和测试阶段的一部分,其他则属于部署阶段:
-
数据生命周期:我们可以在应用代码中建立数据生命周期。例如,不同的存储层次将是数据在其生命周期中的存储位置。对于操作数据,我们可以定义数据在热存储层保存 3 个月,然后转移到低频访问存储层,再保存 6 个月后转移到归档存储层。对于受监管的工作负载,如与 PCI 相关的应用程序,我们可以确保数据仅在 7 个月后删除。通过建立预定义的生命周期,我们可以降低成本并在组织中建立标准化。
-
预防性防护措施:此组中的第一个与部署相关的度量标准是预防性或主动防护措施。我们可以限制在开发环境中允许的实例大小。防护措施将确保超过某一大小的实例无法部署。重要的是要传达这些限制,使其被理解并且不会在开发团队中引发挫败感。
另一个与成本相关的部署控制措施是拒绝在工作负载账户中创建高成本服务,因为这些服务已经在共享账户中建立,并且可以从那里消费。可以通过 AWS 服务控制策略、Azure 策略、GCP 组织策略服务或 Open Policy Agent(OPA)策略建立预防性控制措施。我们还需要审查访问控制,以确保只有授权人员能够部署到生产环境中。这有助于防止意外或未经授权的支出。我们还在 第三章 中探讨了控制措施和非成本相关控制措施的好处。
-
组织设置:为你的云环境设置一个组织结构也有助于成本控制和拆分。不同的 CSP 提供此功能的方式不同。在 AWS 中,这被称为 AWS Organizations,微软称其为 Azure Management Groups,而在 GCP 中,它被称为 Google Cloud Resource Manager。
我们可以在 组织单元(OU)级别应用预防性控制措施。在这种情况下,我们“开发”组织单元下的任何账户都无法部署超大实例。我们还可以使用组织单元结构进行成本拆分,例如,如果我们将所有共享服务(如应用日志或数据湖)放在一个共享服务的 OU 下。
-
自动化成本估算:一些部署工具提供即将部署的栈的成本估算。HCP Terraform 提供了这一功能,此外,还有一些开源工具可以嵌入到我们的 CI/CD 管道中。开发者可以在继续部署之前查看估算的成本。这有助于发现一些小错误,比如选择了错误的实例类型,而这些错误可能会带来巨大的成本影响。
维护和改进
我们现在将探讨在 维护和改进 阶段需要采取的措施。最重要的是,我们需要建立正确的流程、责任归属和问责机制,以便有效利用这些工具。如果没有人查看仪表板或没有采取任何行动,那么即便有很好的仪表板和自动化推荐也毫无意义。通过这一阶段获得的见解和经验,我们可以建立一个反馈循环,帮助我们未来改进 FinOps 实践:
-
侦测性控制:侦测性控制允许部署,但不符合规定的规则会在仪表板上标记出来,并触发通知。我们可以在我们的开发 OU 中对超大实例应用此策略。这样,我们就不会阻止团队的部署,但仍然可以提供对这一问题的可视化。通常的做法是先在侦测模式下测试控制措施,然后再将其转化为预防性控制。
-
成本探查器和使用报告:AWS 成本探查器、Azure 成本管理和 GCP 成本管理有许多相似的功能,帮助我们获得成本见解。这三种服务都提供按服务、云资源、项目、账户或资源组的成本细分。可定制的成本报告和仪表盘有助于可视化支出模式并识别成本驱动因素。以下来自 AWS 控制台的屏幕截图展示了成本和使用报告。我们可以看到按服务细分的成本,并可以修改时间范围的粒度。

图 4.3 – AWS 示例 – 成本和使用报告(来源:AWS 控制台)
-
建议工具:这些工具提供了减少支出的见解。AWS 可信顾问提供关于各个改进领域的见解,例如,未充分利用的实例。Azure 顾问采取类似的方法,并提供成本建议,例如购买 Azure 预留实例。GCP 也有类似的服务——Google Cloud 推荐器,其中包括删除未使用的磁盘等成本相关建议。这些见解有助于我们初步了解哪些地方可以改进。
-
资源调整建议:资源调整建议帮助我们调整工作负载的大小。这有助于降低成本,并将节省下来的资金用于其他地方。AWS 提供资源调整建议和计算优化器服务来协助此项工作。此功能部分包含在 GCP 云推荐器和 Azure 顾问中,正如我们之前讨论的那样。GCP 和 Azure 还将资源调整建议作为 Azure 成本管理与计费服务和 Google Cloud Active Assist 的一部分。重要的是要先在低环境中测试资源调整,避免直接进入生产环境以防止出现大小问题。
-
成本异常检测:这些服务帮助我们识别异常的流量激增和异常的支出模式。我们可以触发警报,立即接收通知并进行调查。异常模式的原因可能是部署中的错误。AWS 的服务叫做 AWS 成本异常检测,Azure 和 GCP 也在各自的 Azure 成本管理与计费服务和 Google Cloud 成本管理服务中提供此功能。
-
承诺支出:承诺支出计划是减少我们云账单的另一种方式。承诺支出可以应用于各种资源类型,如实例(虚拟机)、容器或 FaaS。计划可以有一年、两年或三年的时长。推荐选择一年期计划,因为计算技术总是在发展。一年后,我们可以选择更新的、更强大的实例代际计划,以应对更高的负载。我们可能想要应用于节省计划的几种策略:
-
首先,如果我们有一个去中心化的治理模型,那么各业务单元或产品组合将负责制定他们的计划。他们最了解自己的应用程序,同时也清楚业务目标和预期增长。
-
第二个战略方面是,我们可能想要有多个储蓄计划。这样,我们可以错开它们并更频繁地调整。一个储蓄计划可以从 1 月开始,另一个从 7 月开始。这给了我们每年更新两次的灵活性。
以下 GCP 截图显示了承诺使用折扣(CUDs)。它向我们展示了当我们选择通用内存实例和 Cloud SQL 数据库虚拟机时,潜在的成本节省。
-

图 4.4 – GCP 示例 – 承诺使用折扣(来源:cloud.google.com/static/billing/docs/images/cud-dashboard.png?dcb_=0.5258774275081315)
正如我们所看到的,如果我们想要充分利用 CSP 提供的所有工具,就有很多内容需要消化。在进入下一部分之前,我们想要再次强调几点:
-
我们总是在低环境中测试与大小相关的更改,然后才进行生产环境的更改。
-
工具很棒,但我们需要责任感和可追溯性,以确保行动得到执行。
-
我们需要了解我们的应用程序在做什么,以便做出明智的权衡决策。
现在,我们进入云成本部分,这部分并不直观,可能在定义我们的云策略或设计时被忽视。
忽略不明显的 CSP 成本
“每天四美元的咖啡习惯,20 年后的实际成本是 51,833.79 美元。那就是复利效应的力量,”《复利效应》一书的作者达伦·哈迪(Darren Hardy)说道。
那四美元可能不包括服务税,那么复合效应就更大了。我们到底想表达什么呢?云中的成本模型比一杯咖啡要复杂得多。我们过去可能遇到过咖啡费用的惊讶,但几乎可以肯定,我们在云中遇到过某些成本上的“惊醒”,要么是因为在演示后留下了一个实例,要么是因为我们没有考虑到某些成本方面。
不同的抽象层级,如 IaaS、PaaS 或完全托管服务,具有不同的价格组件。数据库和存储解决方案、API 服务、日志记录和监控解决方案也是如此。我们使用的云资源类型越多,成本的复杂性就越大。尤其是在我们拥有混合云架构时,这种复杂性更加突出,特别是当我们使用多个 CSP 时,这就形成了多云或混合云策略。这些复杂的场景增加了意外费用的可能性,尤其是在设计时没有创建成本估算,且没有将实际费用与计划费用进行对比验证时。问题在于,我们越是推迟发现意外费用,我们的架构就越会演变,但可能朝着我们看到成本影响时会后悔的方向发展。等待的时间越长,修复问题就越困难。因此,我们希望揭示一些常见的错误,这些错误会导致这种反模式。我们从第一个开始。
常见的反模式
一些持续的 CSP 费用并不显而易见,如果我们在架构中没有解决这些问题,可能会不必要地增加我们的账单。接下来我们将讨论两种常见的反模式。
忽视数据传输费用
将数据导入我们的云平台通常不会产生数据传输费用,因为 CSP 希望吸引客户将更多应用程序带入其云平台。然而,其他类型的传输费用则不同,其中一些费用有可能被低估,甚至被忽视。我们将讲解一些常见类别,它们可能导致意外费用。由于价格本身不断变化,我们将关注需要考虑的领域,而非具体价格:
-
出口传输费用:当我们将数据从 CSP 导出到互联网、另一个云平台或我们的数据中心时,会产生这些费用。在之前的一次项目中,一家云咨询公司帮助搭建一个大规模数据湖解决方案。该方案需要将数据持续导出到一个尚未迁移到云端的、仍在本地运行的数据分析平台。该咨询公司提供了一个成本预测。CSP 指出,他们在成本估算中没有看到出口数据传输费用。这个事实不知为何被忽视了。设计决策是基于出口数据费用没有被计入持续成本的假设。结果发现,出口费用每年可能会达到数十万美元。这导致了严重争议。咨询公司不得不自掏腰包解决问题,并且需要赔偿部分已经发生的出口数据费用。
这个场景还突显出,采用多云灾难恢复(DR)策略是一项非常昂贵的操作。当我们希望在不同的云平台中恢复时,需要确保数据被持续复制。风险和业务连续性团队在想要最小化 CSP 破产风险时,往往会忽视这一点。一个可能的结果是出现多云成本灾难,且很难恢复过来。还值得注意的是,不同地区的价格不同。例如,将数据从美国地区导出到公共互联网,可能比将数据从亚洲或南美地区导出到互联网更便宜。
-
区域之间的转移费用和跨区域架构影响:区域之间的数据传输涉及转移费用。与前面的例子类似,价格取决于源区域和目标区域。跨区域复制在我们有雄心勃勃的灾难恢复(DR)目标时很常见。虽然完全的区域故障是可能发生的,但它的可能性非常小。跨区域的 DR 策略可以帮助我们防范这种风险。相比跨洲数据复制,同一洲内的数据传输费用通常较低。
-
同一区域内的数据传输费用(跨可用区):一些云原生服务也会收取同一区域内的数据传输费用。与跨区域和外部传输费用相比,这些费用较低。如果多个 EC2 实例(虚拟机)部署在多个可用区(AZ)之间,并且需要相互传输数据,AWS 会收取区域内的数据传输费用。至少在本书写作时是这样的,随时可能会发生变化。Azure 已取消了虚拟机的区域内传输费用,而 GCP 通常不收取此费用。我们已经指出,这些变化可能会很快发生。因此,使用我们的云服务提供商(CSP)的成本计算器并尝试不同的数据传输量组合是很重要的。
没有考虑长期存储费用
当我们赶时间或没有预定义的服务目录项时,很容易忽视解决方案的成本方面。我们通常专注于技术细节,以解决启动或验证价值结果所需的迫切问题。接下来,我们将探讨一些常见的陷阱,这些陷阱会增加 CSP 账单的费用:
- 数据生命周期:一个常见的错误是忘记为 Blob 存储或共享驱动器配置数据生命周期。在这种情况下,累积的数据会不断增加。由于 Blob 存储相对便宜,因此可能需要一段时间才能意识到成本的持续增加。存储在数据库、完全托管的日志服务或磁盘卷中的数据价格较高,账单的冲击可能更为明显。下图展示了 AWS S3 可能的数据生命周期转换过程,AWS S3 是一种 Blob 存储服务。我们可以看到,标准存储层可以转换为更便宜的存储层。最便宜的存储层称为 S3 Glacier Deep Archive,需要一定的数据检索时间。

图 4.5 – AWS 示例 – Blob 存储的数据生命周期转换(来源:docs.aws.amazon.com/AmazonS3/latest/userguide/lifecycle-transition-general-considerations.html)
-
磁盘备份和未附加卷:在一个以前的项目中,我们的任务是为数据仓库(DWH)解决方案建立一个自愈机制。数据仓库的一部分部署在虚拟实例上。
这本身就是一种反模式,但它是一个老旧的第三方产品,供应商从未为云环境架构过该产品。我们当时正在处理一个自愈场景,旨在解决实例故障和磁盘卷故障的问题。为此,我们自动化了一个组合方案,包括每小时的快照(即增量备份)和测试环境中所有三个卷的全量备份。突然间,优先级发生了变化,我们不得不在不同的问题空间中帮助解决问题。由于我们希望实现快速的灾难恢复结果,因此在测试过程中没有实现备份数据生命周期。在我们重新专注于自愈解决方案时,已经有数百个备份文件被创建。
下一张 CSP 账单显著增加。产品经理的第一反应是虚拟高容量磁盘太贵了,它们比较慢的磁盘更贵。但真正的问题在于没有配置数据生命周期。这个缺口很快就会影响到业务,而在那种情况下,确实发生了。
-
待机数据库或只读副本数据库:这两种是不同的使用案例。待机数据库(DBs),也叫做次级数据库,帮助提高可用性。如果主数据库发生故障,待机数据库可以在主数据库自动切换到次级数据库后接管数据负载。如果主数据库的数据量增加,次级数据库或只读副本数据库的大小也会增加。这意味着我们为多个数据库支付更多的存储费用,这一点需要纳入成本考虑。
-
日志记录:很少能看到一个清晰的日志记录策略被严格实施。有时我们会看到生产环境甚至记录“信息”日志级别。这会产生大量日志,并且我们需要为此付出代价。如果这个反模式与缺失的数据生命周期结合在一起,那么情况会更糟。我们需要清楚了解需要记录什么,日志文件需要发送到哪里,以及我们需要将日志文件存储在热存储与不常访问的冷存储中的时间。
现在我们已经讨论了与数据相关的成本问题,接下来我们将探讨其他几个成本因素。
其他不明显的成本因素
数据传输成本和长期存储成本是非常常见的陷阱,但也有其他因素,我们现在将进行分析。
空闲或过度配置的资源
空闲资源可能发生在我们创建概念验证后忘记清理的情况下。它们也可能是手动扩展操作的结果,例如用于产品发布、压力测试或类似黑色星期五的销售活动。然后,团队忘记在事件结束后进行缩减,接下来的月度账单将成为一个严峻的提醒,提醒我们需要再次缩减。主要的 CSP 提供资源优化建议。这些建议可以在控制台中看到,就像我们在下一个 GCP 截图中看到的那样。它们还提供 API 支持,如果检测到资源优化建议,我们可以实现自动化警报。我们还可以自动化实际的资源优化,但这需要在生产环境调整工作负载之前进行前期测试。

图 4.6 – GCP 示例 – 资源优化建议(来源:cloud.google.com/compute/docs/instances/apply-machine-type-recommendations-for-instances)
合规工具
对于受监管行业,合规性是必需的,而且并不简单。任何支持合规性自动化的服务都会收取费用。如果并非所有工作负载都需要合规性,那么在选择何时和何地使用合规工具时区分开来是有意义的。
如果我们同时使用来自供应商和 CSP 的合规性工具,我们需要确保不重复使用过多。通常,我们无法避免某些程度的重叠,因为我们必须避免漏洞。
机器学习服务
机器学习(ML)服务需要大量的 CPU 功率来训练模型。资源优化和持续利用验证在这里非常重要。例如,我们需要在所需的训练数据量与学习模型中更高准确度的收益之间找到平衡。否则,成本超支几乎是必然的。
公共 IPv4 地址
IPv4 地址有限,因此主要的 CSP 开始对分配给虚拟机的公共 IPv4 地址收费。收费很少,但对于大规模部署,我们需要考虑这一点。
在深入分析最常被忽视的成本方面后,我们现在将探讨这些后果是什么。
忽略非显而易见的成本的影响
现在我们已经对需要考虑的成本因素有了清晰的理解,我们将探讨不解决这些问题的后果。这里有一个剧透警告:这些影响远不止是增加的 CSP 账单。
跨区域不一致的费用标签
一个经常被忽视的方面是,不同区域之间不一定具备相同的功能。某项服务在次要区域可能不存在,或者该服务存在,但只有部分功能。
我在之前的一次顾问合作中遇到过这种情况,当时无服务器数据库服务在两个区域都存在,但其中一个区域缺少几个功能,包括开箱即用的时间点恢复功能。因此,第二个区域需要不同的设计、不同的基础设施即代码(IaC)和不同的灾难恢复测试场景。这些额外的设计、构建和运营工作不会在云账单上体现出来。然而,我们的团队将需要投入更多时间并特别注意细节,操作风险也会增加。
架构多区域灾难恢复(DR)策略的影响
如果我们没有考虑到多区域数据传输费用,我们将意识到我们的多区域灾难恢复策略的成本显著超出预算。这将取决于我们需要做出的风险/成本权衡决策。如果我们决定修正方案并转向单区域灾难恢复解决方案,那么我们需要调整我们的架构和实施,并将现有备份迁移到主区域。
架构多云策略的影响
如果我们采用多云策略,并且需要在 CSP 之间持续传输数据,数据传输费用将令人震惊。如果我们在选择 CSP 过程中没有考虑到这一点,那么我们已经做出了一个很难回撤的架构决策,尤其是当我们在云端采用过程中已经投入了大量时间。
在这种情况下,我们需要在长期的成本节省、减少运营复杂性和增加的迁移与测试工作之间做出权衡决策。另一个关键点是需要考虑我们可以获得的架构优势。
多云采用的常见后果是,跨云平台只使用共同的基础功能,以确保我们有一致的做法。例如,所有的服务都必须运行在虚拟机或容器中。因此,我们无法充分利用云原生的全部潜力,如托管的 API 网关或数据库。这增加了运营复杂度。通过解开多云策略,我们可以利用这些优势。
增加的云端运行时成本
这是最显而易见的影响。成本将高于我们的预算。如果我们不调整架构,这将产生长期影响,特别是当我们将更多的应用迁移到云端,或者应用变得更受欢迎并创造更多流量时,这个问题只会变得更严重。
其他影响
如果我们有很多闲置资源,比如未附加到虚拟机的磁盘卷,在发生故障时很难识别出合适的资源。闲置资源仍然会对外部审计产生影响,并增加额外的管理工作。如果我们有闲置的虚拟机在运行,这也会不必要地增加碳足迹,从而影响潜在的可持续发展目标。
这些是关键的影响因素,如果业务收益无法匹配或超过额外的费用,我们肯定要避免这些情况。某些迹象应该促使我们进一步调查,接下来我们将探讨这些迹象。
指标
有几个指标可以识别这种反模式。我们现在将逐一查看它们,并从最明显的一个开始:
-
账单震惊:我们收到了 CSP 的账单,并且可以看到费用趋势比预期更陡峭,或者有一个大幅波动,无法与之前几个月的费用趋势相匹配。
-
缺乏洞察力:在本章前面,我们讨论了 FinOps 工具。如果我们缺乏预算、警报和资源优化建议等机制,那么可能存在一些我们没有意识到的隐性成本。启用这些功能将有助于我们获得更清晰的视图。
-
缺乏所有权和责任感:如果产品团队没有动力去优化价值生成,他们就不会有动力去识别意外费用,并将其考虑到架构决策中。
-
没有承诺的支出计划或抢占实例:如果我们没有承诺的支出计划,比如 AWS 节省计划、Azure 预留或 GCP 承诺使用合同,那么我们将为计算资源支付全价,例如实例、容器和 FaaS。如果我们有可能出现中断的工作负载,比如批处理作业或低环境中的实例,那么我们需要考虑利用 AWS 抢占实例、Azure Spot 虚拟机或 GCP Preemptible 虚拟机。这些措施应当结合使用,如果其中任何一项没有实施,我们就会出现过度支出的情况,即使在云账单中看不出来。
-
缺乏战略评估:如果我们有多云或多区域策略,而且业务价值从未重新评估过,那么很可能缺乏当前的洞察力。
-
未跟踪的试用服务:CSP 和 SaaS 提供商提供免费试用。如果我们没有跟踪使用时间或免费配额,当达到限制后,我们将不得不支付额外费用。
-
没有部署成本预估:一些部署工具在部署之前提供成本预估。虽然这些预估可能不是 100% 准确,因为数据传输和流量会有所变化,但它们能在我们做错什么的时候提供有价值的洞察。如果我们不小心部署了一个过大的实例,我们可以看到意外的额外费用。
纠正措施
现在让我们看看如何才能达到一个良好的目标状态:
-
前期成本计算:当我们需要设计一个新方案时,我们会创建一个展示所有触发成本的组件的方案图。此概览将展示我们需要考虑哪些云服务。我们还需要非功能性需求,如数据量指标、请求数量、数据增长、RTO(恢复时间目标)和 RPO(恢复点目标)来制定准确的估算。
数据流图还可以帮助识别数据传输费用。增强现有架构时也是如此。如果当前状态已经部署并上线,那么我们可以从 CSP 账单中计算出实际费用。然后,我们可以将其与目标状态进行比较,找出我们的费用如何变化。
-
建立 FinOps 工具:我们在前一节中讨论了这个问题,没有利用 CSP 的 FinOps 服务,所以这里简短提及。FinOps 工具帮助我们建立良好的成本洞察力,并发现不明显的费用。现在,我们了解了数据传输、存储和其他成本陷阱,知道需要注意什么。
-
架构审查:一旦方案设计成熟,我们可以进行架构审查。CSP 提供的架构框架将指导我们提出正确的问题并验证设计。我们也可以请咨询公司提供独立意见。对于已经部署的工作负载,我们也可以进行类似的操作。在这种情况下,我们还可以使用前面提到的咨询工具来帮助我们验证当前状态。
-
服务目录:服务目录有助于我们实现良好的自助服务体验,且结果可重复。这也有助于我们在成本方面的处理。存储服务目录项可以具有内置的数据生命周期。用户只需要选择所需的标准化生命周期。这样,我们可以确保始终有一个生命周期在使用中。
-
缺乏防护措施:预防性防护措施可以防止某些成本影响,包括将非常大的实例部署到开发环境中。另一种预防性防护措施可以是用户只能部署产品目录项或批准的云服务。侦测性防护措施可以在防护措施不符合要求时通知我们。
-
加密密钥:客户管理的密钥会产生额外的成本,包括实际密钥存储或版本控制的费用,以及每次操作的费用,包括密钥创建、加密和解密。一些监管框架要求使用客户管理的密钥,甚至有些要求使用专门的密钥存储解决方案。这意味着物理存储是专门为一个云客户提供的。专用服务会有额外的费用,其中包括 AWS CloudHSM(HSM 代表 硬件安全模块)、Azure Dedicated HSM 和 Google Cloud HSM。
-
其他架构考虑因素:如果我们使用内容分发网络(CDN),我们需要支付额外费用。然而,它会在边缘提供额外的保护。由于数据被缓存于边缘,不是每个请求都需要从我们的后端系统获取数据。因此,根据我们的架构,它可以减少后端组件的数据传输费用,但与不使用 CDN 相比,整体成本仍然较高。
在深入了解意外成本以及如何发现和修正它们之后,我们将探讨如何专注于推动业务价值。
专注于节省成本而非创造价值
“重要的不是你是否对或错,而是当你对时能赚多少钱,错时能亏多少钱” 这是全球最成功的投资者之一乔治·索罗斯的名言。
做出战略性云决策与做交易不同。然而,我们必须做出正确的决策,以优化我们的云价值。我们需要的不是买卖,而是建立合适的能力,并在时机成熟时逐步移除这些能力。这将帮助我们提高投资回报率。为了做好准备,我们必须发展我们的架构、工作方式和文化方法,同时确保我们的团队在这段持续的转型旅程中获得培训。这些是推动我们云原生技术栈价值时需要考虑的关键内部和外部因素:
-
变化的业务需求和竞争优势:需求可能会发生变化,因为我们的业务在发展,我们所处的市场在进步,或者我们尝试进入新的市场细分领域。无论哪种情况,我们都希望能够迅速发布新功能。因此,我们必须加速创新、进行实验,并最大化产出。
-
技术进步:我们之前讨论过沃德利映射。云服务,如 FaaS,已经成为商品化服务。为了支持业务的敏捷性,我们必须避免没有差异化的繁重工作,并更新我们的技术栈。如果我们可以使用像 FaaS 这样的完全托管服务,而不是容器或实例,那么我们就不需要管理操作系统和应用程序的补丁、自动扩展和安全性。
-
合规性和安全要求的变化:我们必须保护客户数据,实施更多控制,并确保在客户请求时能够删除其数据。因此,我们不能依赖低成本的手动解决方案,因为它们无法扩展。我们需要推动自动化。
-
供应商和合作伙伴生态系统:减少软件供应商或咨询费用可能会导致长期成本增加。我们需要了解第三方产品路线图与我们组织的 SaaS 解决方案的契合度。对于咨询公司,我们需要了解他们的战略方法是否与我们的愿景一致。我们在第二章中详细讨论了这一点。
-
人才与技能可得性:当我们决定使用何种技术或框架时,我们必须考虑是否已有足够的内部技能,或者在我们的人力资源市场上是否有足够的技术人才。节省 5%的许可费用或云运营成本,可能会被找不到合适资源,或者需要支付更高的顾问费或薪水所抵消。具备云原生技术理解的专业人才的可得性,可能会影响我们构建和维护架构的效率。
-
培训与协作:我们必须确保团队在架构设计和实施云原生技术栈方面接受充分的培训,以便以最佳的方式为我们的业务服务。节省培训和协作上的费用将导致技术债务,并带来可观的额外成本。
优化业务价值是一个重要的驱动力。然而,在云采纳的初期,企业往往过于关注成本削减。在本节中,我们将探讨过度关注成本可能如何在云采纳过程中制约我们。现在让我们来看一下常见的反模式。
常见的反模式
接下来,我们将探讨两个常见的反模式及其带来的后果。我们将从单纯关注成本削减而忽视整体视角的影响开始。
小气节约
有时,寻找便宜货很诱人;每个人都曾尝试过。对于我们来说,当以折扣价购买到相同产品和质量时,比较变得简单。但当涉及到云原生解决方案以及我们必须考虑的长期运营问题时,情况就变得复杂了。
几年前,我与一位工程师合作,他在业余时间经营一家云托管业务。他的目标群体是需要托管应用的小型企业。这位工程师管理着共享责任模型的上半部分,即云中的安全性。客户提供的服务包括一个标准的三层 Web 架构,具有公有和私有子网。由于某些原因,私有子网需要与互联网进行出站连接。这也是一个安全反模式,但我们现在的关注点是如何利用业务价值。
为了建立从私有子网到互联网的连接,NAT 网关(NAT-GW)解决方案是必需的。这位工程师比较了云服务提供商(CSP)完全托管的 NAT-GW 服务和从头开始手工打造 NAT-GW 解决方案的成本。完全托管的服务包含额外费用,用于持续的修补、高可用性、安全控制、现成的日志和监控集成等。然而,他决定采用手工制作的解决方案。这意味着他必须管理虚拟机的持续镜像更新、不断的修补过程、安全控制、日志记录和监控等。
这种解决方案也会导致监管解决方案需要大量额外的合规工作,因为他们需要提供诸如最小权限实施、日志完整性、高级用户访问日志记录等证明,尽管这只是一个小规模的托管业务,只有 100 个客户。
如果我们希望扩大客户基础和商业价值,这种方法是无法扩展的。我们可能需要一段时间才能意识到积累技术债务的后果。这也是云迁移中常见的结果,特别是在优先考虑“提升并迁移”(lift and shift)迁移计划,而非通过重构应用程序以利用所有云原生优势来获得战略价值的情况下。
不投资于持续改进
在一次之前的合作中,我曾为一家金融服务组织的客户工作,该客户需要满足多个监管要求。为了应对外部审计,收集所需的证据手动操作花费了 1 年 3.5 个月的时间。这一工作量是由负责审计的云团队成员全职完成的。这段时间涵盖了云技术栈,其他团队则参与了本地工作负载的处理。
需要提供所有处理信用卡信息的环境的截图、日志文件示例和流程描述。云团队主要依赖外部咨询资源,因此内部人员减少到最低限度。
我们已经知道,明年我们必须改进方法,转向自动化。我们评估了几种 SaaS 工具,这些工具可以帮助改善安全性和合规性姿态,并将审计工作量减少到最低限度。如果我们的组织状态良好,我们可以向外部审计员提供只读访问权限,查看合规自动化工具。这样,他们可以验证所需的控制措施是否到位。这意味着双方的整体工作量减少了,同时我们还可以获得持续的保障性见解,帮助我们不断改进。
不幸的是,公司决定不再投资于持续改进,并将预算分配给其他项目。随后的外部审计更加具有挑战性。我们不再使用先前版本的合规框架,而是必须遵守一个新的、更为严格的版本。这增加了整体工作量,我们不得不聘请一名承包商工作 3.5 个月,以满足审计时间表,并确保人手不足的云团队仍然能够运作并持续完善云平台。
关键点是,额外临时资源的整体支出,虽然可以解决一些短期问题,但如果将这些支出用于战略性改进,将会带来可持续的解决方案,并减少长期的努力。犯错并不罕见,但我们需要利用所学的教训进行改进。重复犯同样的错误令人痛心。事后看,感觉就像是在慢动作中看到车祸发生。幸运的是,没造成身体伤害,但痛苦却没有忘记。接下来,让我们总结并量化将焦点放在节省成本而非推动价值上的影响。
影响
将节省成本置于推动价值之上,会产生一些显著的长期负面影响,我们现在将一一探讨:
-
错失商业机会:如果我们不推动价值链的改进,我们将错失那些能够让我们与竞争对手区分开的客户体验改进。如果我们不持续改进我们的云原生技术栈,我们将增加技术债务,并且当前功能的市场推出时间将缩短。如果我们希望创新、应对市场变化或遵守监管要求,这将是一个劣势。
-
运营复杂度增加:如果没有持续改进,我们将错失充分利用云计算潜力的机会。托管服务的创新和改进速度远超我们自己能够实现的。如果我们不更新架构,架构很快就会过时。托管服务的运营优势包括内建的可观察性和弹性。那些可以避免的运营复杂度增加将给我们的团队带来负担,因为运营成本将不必要地增高。
-
生产力下降:过度节俭可能会对团队的士气产生负面影响。结果将导致参与度、动机和合作减少。因此,生产力将低于我们在追求价值创造时可以达到的水平。
-
安全性和合规性受损:单纯关注成本削减可能导致在安全工具、监控和合规服务上的投资不足。这增加了安全漏洞、数据丢失和不符合监管要求的风险,可能会产生重大影响。如果不启用如网络防火墙、入侵检测系统或漏洞扫描等服务,将使我们的应用程序暴露于漏洞中,并导致不符合如 PCI-DSS 等监管框架的要求。
-
降低用户体验:削减成本的措施可能会影响服务的可靠性和可用性,导致客户不满并可能引发流失。为了节省成本而减少冗余或备份频率,可能导致服务中断或数据丢失,从而影响可靠性和客户体验。
-
收入和增长潜力的丧失:减少云支出可能会影响我们的架构,并限制我们在需求高峰时快速扩展的能力。这可能限制我们利用临时市场机会的能力,例如因商业新闻引发的交易高峰或像黑色星期五这样的临时零售高峰。
专注于成本优化会带来显著影响,并可能在长期内损害我们的业务和声誉。但我们如何才能意识到自己走错了路并做出反应呢?我们接下来将探讨这个问题。
问题指标
我们并不总是容易意识到自己是否已经陷入这种反模式,因此我们将探讨一些早期迹象:
-
服务降级和性能问题:关于应用程序性能变慢、延迟增加或频繁服务中断的投诉增多,可能表明公司正在关注成本削减。由于资源不足而导致的性能下降,例如缺乏自动扩展或边缘计算,表明成本优先于业务成果。
-
减少安全控制:减少对云安全工具、服务或人员的投资,或者明显下降的安全监控和合规活动,都是成本反应的迹象。这些措施可能增加数据泄露和合规失败的风险,表现出在成本节省与必要的安全控制之间的危险权衡。
-
缺乏标准化:不成熟的标准化包括缺乏编码标准、标准化的 CI/CD 流水线、基于容器的镜像、服务目录等。这些问题的后果是增加了操作复杂性,延缓了市场推出时间,从而减少了价值创造。
-
缺乏计费回退和问责:如果没有计费回退模型,我们就没有明确的责任划分。因此,产品团队将不会推动投资回报率(ROI)。在这种情况下,我们很可能会采用以成本为中心的集权治理模式。一个不成熟的运营模式也属于这一类。
什么才是理想状态,我们如何才能达到这个目标?
我们需要解决以下问题领域,以实现有价值的成果。如果我们及时且充分地解决这些挑战,它们将成为推动发展的领域:
-
责任和问责:需要明确责任划分。云平台团队可能负责建立所有网络基础设施并管理服务目录。产品团队则负责应用程序、数据和持续优化工作。这包括合理配置计算实例,决定哪些备份和数据生命周期计划必须满足所有需求,并避免资源的低效利用。建立计费回退模型将有助于推动经济行为。这将引导我们进入下一个要点。
-
承诺的开销与现货虚拟机:拥有权和责任感也会激发产品团队节省成本的思维,因为节省的云成本可以用于创新。如果团队了解他们的责任,他们将会对利用成本承诺计划以获得折扣感兴趣。这也会促使使用现货实例来进行测试环境或可以接受中断的批处理任务。与按需实例相比,现货虚拟机的运行成本更低。
-
采取长期交付视角:项目通常具有短期视角,因为它们只规划项目的时间跨度。之后,项目会转移到业务运作(BAU)状态,由运营团队来管理。然而,解决方案未必会随着时间的推移而改善。这导致遗留架构无法充分利用最新的云原生功能。转向产品团队模式将使运营责任更加靠近产品团队。产品团队将非常关注减少运营复杂性,并持续改进应用。
-
技术债务记录:它将帮助我们跟踪我们所做的任何战术决策。这可能是我们正在使用的旧版 Java 运行时,或者是一个不是我们战略选择的数据库引擎。如果我们以后使用较新的运行时创建新的应用容器镜像,我们就能够消除技术债务,因为我们将拥有清晰的可视性。
-
数据洞察:与其仅仅关注总的云成本,我们通过数据点并建立关联性可以获得更清晰的全貌。这样,我们就可以发现因为我们在 CI/CD 管道成熟度上投入更多,我们能够更频繁地发布,从而在线销售数字增加了多少。
-
合作伙伴生态系统:建立合作伙伴战略是一个好的起点,但我们还需要确保建立良好的关系。像 CSP(云服务提供商)、SaaS 供应商或咨询公司这样的合作伙伴是该领域的专家,他们能够提供有价值的建议,帮助我们改进或共同创新,创造新的商业机会。
-
投资长期收益:短视的费用观念会导致错失战略机会。如果我们评估提供可重复、安全和可靠结果的成熟 CI/CD 管道的价值,我们可以缩短市场推出时间。举例来说,包括自动化的性能、可靠性或回归测试。
-
临时环境和自动销毁:建立沙盒环境,让开发者可以在其中尝试新的云服务或 CI/CD 工具链,将有助于教育培训。沙盒环境带来成本意外的风险,因为通常情况下,并非所有资源在不再需要时都会被销毁。我们可以实现自动销毁机制,确保在特定时间间隔(例如每个周末)删除不再需要的资源。我们可以通过云原生 CI/CD 工具、SaaS 解决方案,或像 AWS Nuke 这样的开源解决方案来实现。虽然实现这一机制需要前期投资,但最终会带来回报。同样的原则也适用于可以在非工作时间关闭的临时环境。
在本章中,我们探讨了许多内容,现在将总结我们学到的知识,以便快速消化信息。
摘要
我们从标签管理开始,这是我们日常工作中的基础,目的是实现准确的成本拆分。为了建立一个有效的费用返还模型,我们需要明确的标签标准和强制执行措施。我们还探讨了云原生的 FinOps 服务,如成本探测器、预算、警报和成本异常检测。这些都是获得早期洞察和成本警报的宝贵功能,而不是被动等待下一次的云账单震惊。我们讨论了数据传输费用,以及它们如何在我们的云平台内以及在混合云或多云流量中产生。接着,我们通过探索业务价值创造,强调了不仅仅是采取短期的成本最小化立场。只有从长远的角度出发,才能帮助我们最大化利用云原生技术栈所能创造的业务价值。
现在,我们准备迎接下一个挑战,即安全性和合规性目标。
第五章:快速且持续地交付而不妥协安全性
到目前为止,我们已经看过了云原生开发所需的组织变革。在本章中,我们将开始探讨为了向云原生转型所需的文化和开发实践。在转向云原生软件开发时,我们常常被快速交付和安全系统的梦想所吸引。然而,只有在实现了相应的组织和文化变革后,这一目标才能在实践中实现。让我们探讨在软件交付生命周期中常见的反模式是如何干扰我们成为高绩效云原生组织的道路的。
在本章中,我们将涵盖以下主要内容:
-
低估文化影响
-
频繁变更以满足业务需求
-
防护栏
-
向左移动
-
自给自足的团队
低估文化影响
快速且安全地交付云原生项目主要是一种文化变革。为云原生交付所需的技术和业务流程变革,支持着文化变革。我们需要使团队的心态与结果的共同责任对齐,打破现有交付过程中可能存在的孤岛。产生变更或功能的团队应负责将其交付到生产环境中。这一转变是快速交付的最根本方面。在本节中,我们将从回顾一个常见的部署流程开始,这个流程通常出现在刚刚开始云原生之旅的客户中。
孤岛式模型 – 通向生产的漫长道路
让我们来看看一个良好意图却仍然是孤岛式的交付流程,通常这是将本地发布方法应用于云原生交付时产生的产物。

图 5.1 – 一个典型的孤岛式发布流程 – 有许多接触点,但缺乏端到端的责任
当发布过程庞大且繁琐,需要大量努力才能部署,并且推送不良变更的后果很难恢复时,这种模型是有效的。我们可能会在部署到具有不同容量和能力的本地客户服务器群时使用该模型。而在云环境中,这些限制并不存在。如果出现问题,我们可以迅速进行更改并快速修复;单一、统一、同质化的生产环境简化了部署和修复过程。
在这种模式下,我们会对所有代码进行严格审查,确保它在进入生产环境之前无误。然而,它的僵化性也是其缺点。当其中某个阶段不可避免地出错时,通常的做法是,开发者已经开始着手下一个功能时,必须放下手头的工作,去修复已经达到审查阶段的错误。这个临时的变更很可能不会经过审查流程,因为该流程无法承受从头开始的风险。
DORA – 衡量道路
“如果你不能衡量它,你就无法改进它。”我们理解,当应用于云原生软件时,孤立的模型是有限制的,但当我们改变交付过程时,我们如何知道我们的变更正在把业务推向正确的方向?
在前面,第一章中,我们介绍了 DORA 指标来衡量团队的表现。如果你对这些指标背后的科学感兴趣,我们推荐阅读《DORA 报告》或《加速:精益软件和 DevOps 科学:构建与扩展高效能技术组织》。回顾一下,这些指标如下:
-
部署频率
-
变更的前置时间
-
变更失败率
-
恢复服务的时间
如果这些是最准确预测团队表现的指标,我们可以看到交付的责任不是可选的。
在孤立配置中,部署频率是次优的,因为我们被束缚在繁琐的发布过程中。这个发布过程还决定了我们变更的前置时间,因为所有变更必须与预估的时间表对齐。我们同时还在部署更大规模的代码包,这使得其中某个特性导致变更失败的几率大大增加,因为这个概率现在是每个子组件概率的总和。最后,恢复服务的时间也因为要回滚大量变更或从庞大的发布中筛选出问题并进行热修复(这也很可能不会经过发布过程)而大大增加。
摒弃高效团队的指标,我们还会遇到另一个关于责任的问题。谁负责这个变更并对其成功负责?是写代码的开发者吗?是批准变更的审批委员会吗?如果是安全问题,责任是否属于安全团队?将发布过程孤立也意味着孤立了责任;没有端到端的过程责任,问题就更难解决。
授权团队 – 提升你的速度
这将我们带回到赋能团队的概念。如果是你的团队编写的代码,你就负责它从开发到生产的整个过程。或者更简洁地说,“你建造它,你运行它。”我们不能把所有团队丢到深水区,然后指望他们游得起来;他们需要得到支持。这时之前那些孤立的团队就发挥作用了。它们从生产环境之旅的守门人转变为帮助开发团队自行承担这段旅程的推动者。
注意
赋能并支持团队拥有他们的输出是快速和安全交付的核心。
因此,为了在不妥协安全性的情况下快速交付,文化转变是最重要的方面之一,同时也是公司未能着重解决的方面。为了让团队拥有自己的输出,每个团队必须具备交付工作所需的技能和能力,或者通过组建跨职能团队在内部实现,或者通过赋能团队在外部实现。本章后面我们将探讨如何通过“左移”和“下压”的方法来解决这个问题。关键在于,不能将所有控制权交给交付团队,而是要确保他们获得传统孤立职能的赋能和支持,才能真正拥有自己的输出。
最简单的方法是同时给开发团队提供胡萝卜和大棒。赋能团队必须提供开发团队能够使用的平台和工件,以便他们按照公司标准完成工作。这可能以身份验证库、基础设施即代码模式、通用 UI 组件库等形式呈现。接着,赋能团队应当努力自动化“护栏”,以帮助开发人员确保他们所编写的代码符合之前手动执行的标准。这可以通过使用 QA 测试套件、静态应用安全测试(SAST)和在可观察性平台中为站点可靠性警报自动创建工单系统来实现。通过这种方式赋能开发人员,我们让他们能够拥有自己的输出,并将部署过程的责任向左移。
DevSecOps – 通往生产的高速公路
现在让我们回顾一下我们的部署模型:

图 5.2 – 可部署工件所有权的目标状态
我们的其他团队依然留在组织中。相反,他们维护着三组工件:
-
平台工具:开发人员用于生产符合责任团队需求的软件工件的系统和工具,例如共享的身份验证库、结构化日志库或云基础设施模块。
-
自动化流水线:此流水线规范了每个团队的期望,而不是依赖于手动审查。如前所述,这可能包括自动化 QA 测试、SAST 或容器扫描工具。
-
可观察性平台:该平台规范了关于应用程序性能的期望,并在操作超出正常参数的情况下,提醒开发人员,同时存储关于这些事件的信息。
这里的关键区别在于,开发团队不再需要与五个不同的团队对接来将特性推送到生产环境,而是有能力拥有他们所编写的代码,并将符合基准标准的工件部署到生产环境。他们还可以通过可观察性平台查看他们生产的工件的性能。因此,我们已经将文化从守门转变为赋能。这正是 DevSecOps 的核心,赋能软件团队开发、保障和运营他们所编写的代码。
这种变化的规模在经历云原生转型的组织中通常被低估。人们可能会对被从关键路径上移除感到反感,因为这意味着他们放弃了之前拥有的一部分权力。需要在这些团队中树立的心态是,他们不再通过阻止开发团队部署到生产环境来与开发团队对立,而是成为开发团队的专业领域的管理者,提供文档并提供洞察,帮助引导开发团队朝着自己的安全、高质量、可观察的工件前进。
结果,开发团队变得更加跨职能,团队成员需要在这些支持团队的指导下,提升安全性、质量保证和站点可靠性工程的技能。
现在我们可以看到减少这些摩擦点的几个明显优势:
-
部署频率提高,因为我们不再按计划打包,而是尽快部署。这也导致了更短的变更交付时间,因为一旦变更准备好并通过了我们的流水线检查,它就可以轻松地部署到生产环境。
-
我们现在部署的是更小的代码单元,通常只包含几个特性,这减少了变更失败的可能性,并降低了变更失败率。
-
我们有一个平台来观察我们的应用程序,这意味着任何导致停机的变更都能迅速被识别,并且修复可以通过自动化流水线推送。这是一个关键的区别,因为通常情况下,热修复需要脱带应用,而我们无法将修复通过整个流水线运行。相反,自动化流水线仍然可以使用,因为开发人员无需与其他团队接触就能部署修复。因此,我们已经转向了持续改进和持续交付(CI/CD)的过程。
保持在正轨上
另一个公司可能很容易陷入的谬误是,认为使用 DevSecOps 和 CI/CD 原则交付特性将导致开发速度的大幅提升,这意味着更紧迫的截止日期。虽然确实,流程中基础的改进会转化为特性的更快交付,但仅仅专注于交付时间表,最终会因为文化转变而破坏效率提升。
如果你正在从一个有固定发布时间表、严格的截止日期和僵化的业务流程中迁移过来,可能会很诱人地将这种方式直接转化为新范式中的交付时间表。相反,通过将特性工作与发布过程解耦,我们让开发团队专注于输出质量,只有在从多方面角度准备好时才发布特性。这确保了我们在不妥协代码质量的前提下保持开发速度的提升,从而带来的是可持续的,而非暂时的,开发速度提升。
康威定律指出,“设计系统的组织会被约束,以生产出这些组织通信结构的副本。”当我们让团队之间形成孤岛时,我们不可避免地将他们的输出限制在开发/部署过程的某一特定部分及其职责上,并产生一个复制这些团队通信路径的部署过程。因此,合乎逻辑的结论是,为了保持我们在本章中所规定的所有文化变革,我们必须鼓励团队实现自给自足。这将使我们能够自动化并独立地进行变更生产,这是我们所期望的。
绘制一张新地图
最后,当我们完全转向云原生时,最难打破的反模式之一可能是服务与其运行的计算资源之间的耦合。新服务的创建、维护和运行成本低廉。因此,我们可以形成有限的服务上下文,封装一个业务领域。
领域驱动设计 是该领域的一本好书;它深入探讨了这一主题。这使我们能够根据业务领域的需求演进我们的架构,而不是因为我们安装了特定数量的服务器就将业务需求强加给架构。稍后本书将深入探讨如何将你的业务问题转化为应用代码,并介绍耦合和内聚的概念。本章的关键是打破架构必须适应预定义配置的思维方式。康威定律同样适用于你的架构,正如我们在部署过程中打破孤岛一样,我们还必须打破开发团队之间的孤岛,以使我们能够在正确的地方构建正确的解决方案。
正如我们所看到的,创建真正的云原生解决方案所需的文化转变可能会让一些组织感到措手不及,因此必须充分考虑其影响力。思维的核心转变在于赋能团队,使其自给自足,并拥有从功能构想到生产环境运行的交付全过程,通过从孤立所有权和交付模式转变为精益所有权模式,开发人员对自己所做的变更负责,并通过 DevSecOps 能力得到支持。赋能开发将使我们能够更快地交付变更,因此让我们深入探讨如何实现频繁的小型变更以达成我们的业务目标。
为了实现业务目标频繁地进行变更
在上一章中,我们介绍了“赋能开发团队”的概念。我们着重于减少发布过程中的孤岛现象,使得团队能够拥有端到端的发布过程。在这一过程中,我们能够更频繁地发布新版本。让我们深入探讨那些使我们能够在这种新范式下工作的开发变更。
修剪 Git 分支
大多数部署策略都会是多阶段的。例如,您可能会有名为 开发、集成测试 和 生产 的环境。基本理解是,较早的环境会先部署变更,这样我们就可以在将变更发布到生产环境之前进行测试。在多阶段部署模式下,我们推荐的一个模式是先在较低环境中测试功能,由开发团队或通过自动化测试对实时环境进行验证,然后再将变更部署到生产环境。采用这种策略时,可能会倾向于使用 Gitflow 模式,其中每个环境都是一个独立的分支。让我们来看一下典型的 Gitflow 实现。

图 5.3 – 典型 Gitflow 分支模型
这种反模式会产生一种错误的安全感,因为我们假设变更在推送到更高环境之前已经在较低环境中经过了充分的测试。然而,随着更多的人参与到代码库中,并且团队在应用热修复时,每个分支的内容随着时间的推移会逐渐发生偏差。在前面的图示中,我们可以看到我们对生产环境应用了热修复,而我们第一次测试我们的已部署功能时,它实际上是在生产环境中进行的。这种不确定性就是我们在维护特定环境代码库时面临的风险。它也会导致文化态度的倒退,因为在环境迁移之间引入手动检查的诱惑可能会带来不良后果。相反,采用单一代码库多次部署的原则能有效限制环境偏差。一个非常好的在线资源《12 因素应用》(The 12 Factor App),(12factor.net) 将其作为第一项原则。
那么,我们如何有效地操作单一代码库呢?选择基于修订的分支策略,比如基于主干的开发,是确保我们从单一代码库中操作的最简单方法。我们不是让某个环境在环境分支中运行最新配置,而是为运行已知的最后正确配置在单一分支中制定规则,并在需要时将其推广到更高环境。让我们来看一下典型的基于主干的开发模型。

图 5.4 – 基于主干的开发分支模型
在这个例子中,每个环境都是从主分支部署的,较低环境会包含最新的更改以供测试,而较高环境则落后于主分支。通过持续集成和部署,我们减少了变更的交付时间,并增加了部署频率。
解耦集成和发布
现在,提升每个环境的复杂性已经得到解决,但我们遇到了一个在按环境分支或代码库系统中并不明显的问题。我们如何在一个环境中测试或更改功能,但又不让它们阻碍其他功能在更高环境中的部署呢?在之前的系统中,我们可以挑选提交来推广特定功能。解决这个问题的方法是双重的:我们需要一个简单的方式让开发人员在合并之前测试他们的功能,并且需要一个简单的方式来管理在不同环境中已合并的功能。
管理已合并功能的最简单方法是将功能在最终产品中的表现与其在代码库中的包含解耦。例如,一个功能可以已经完成并合并,但不出现在已部署的系统中。为了实现这一点,我们使用了一个被称为功能标志的概念。
功能标志允许我们在应用程序中保护特定的条款。一个简单的例子是 if 语句,如果功能标志关闭,那么我们就不会显示按钮。当开发团队在本地开发此功能时,可以打开功能标志进行测试。已部署的环境没有打开功能标志,因此我们可以将该功能合并到主代码库中,而不会影响已部署的应用程序。一旦功能完成,我们可以在较低环境中打开功能标志,以便在实际环境中测试该功能。通过将功能的开发与其在最终应用中的表现解耦,我们还将功能发布决策从技术驱动(即,功能已存在于代码库中,因此它将出现在已部署的应用程序中)解耦到业务决策层面;我们可以根据需求添加功能。
要真正将功能发布决策与技术实现解耦,将功能配置存储在应用环境中至关重要。在这种情况下,反模式是将名为features.prod.yml和features.dev.yml的文件提交到版本控制中,因为我们再次在代码库中创建了具体化的检入物。
特征标志的最佳方法是向版本控制中检入一个文件,该文件定义了可用的特征标志及其状态。在此文件中,我们更喜欢使用非布尔值来表示特征标志,因为这样后续扩展起来更加困难。通常,我们依赖枚举。例如,一个枚举可以包含名为Baseline、Configurable和Off的值。在这种情况下,Baseline确保在所有环境中都启用了一个特征,并且在我们部署新环境时默认启用。这些标志代表了成熟的功能,稳定到可以始终启用,并且可以安全地用作新功能的基础。Configurable标志是我们希望能够在各种环境中更改其表达方式的特性。这些可能表示尚未发布的特性、正在测试的特性或尚未完成但处于可用状态的特性。这些特性需要在部署环境中可以打开或关闭的方法。如果系统规模较小,我们可以通过应用配置来实现这一点;如果功能列表很长,我们可以通过数据库表来支持。最后,我们有配置为Off的特性;这些是不应在任何环境中可用的特性标志,但是它们用于正在进行中的功能,并且需要能够在本地表达。
为了解决开发者需要本地测试的问题,这正是构建云原生软件的优势所在。我们常见的一个反模式是试图在本地环境中复制云环境,许多服务都会这样做。然而,没有什么能替代在云中实际运行你的代码。使用云原生软件,利用基础设施即代码(IaC)和无服务器/托管服务等原则,开发者完全可以创建一个隔离的开发云环境。这个做法让开发者真正能够在云中开发。它还确保了你的 IaC 避免了反模式,比如硬编码引用,因为我们会定期创建和销毁新环境。开发团队现在也可以独立于已部署环境测试基础设施变更。这种解耦有助于强化“授权团队”这一概念;开发者现在可以控制运行的代码、其运行的基础设施以及它与之交互的服务。他们还熟悉部署过程,更接近“你构建,你运维”的理想状态。通过让开发者在云中进行测试,并将测试范围限制在他们正在测试的短暂环境中,我们可以进行更多具有破坏性的测试。我在短暂环境上的负载测试不会影响你在你自己的短暂环境中的测试。通过在管道中允许这种类型的全面测试,我们降低了变更失败率。
逆转不可避免的变更
没有系统是完美的,随着我们部署频率的提高,某个变更失败的可能性最终会变得必然。根据 DORA 报告,变更失败率是我们应该追踪的一个组织绩效指标。尽管我们力求将这个指标保持在尽可能低的水平,但如果发生失败,另一个 DORA 指标——恢复时间中位数(MTTR)就会发挥作用。三个关键的反模式会阻碍我们优化 MTTR,当原因是变更失败时:
-
可变工件
-
毁灭性变更
-
没有变更的反向定义
第一个反模式是使用可变工件,所有产生的工件必须是不可变的。当你的自动化构建管道生成一个工件作为部署候选项时,我们必须在随后的构建管道运行中保持该工件不变。这种不可变性可以像容器注册表中的容器版本控制一样简单,或者使所有以前版本的内部库在任何时候都可供安装。通过使用不可变工件,可以轻松将系统回滚到已知的正确配置。我们只需部署早期的工件,然后在较低环境中进行修复,直到我们准备好再次部署到生产环境中。
第二种反模式是破坏性变更。系统新版本的部署应该允许我们回滚到之前的应用程序实例。例如,破坏性变更可能是删除数据库表或删除数据存储。当我们部署这些变更时,我们永远无法将系统回滚到上一个已知的正确配置,因为在破坏性变更中我们丢失了系统的状态。如果需要进行破坏性变更,应该在最终应用破坏性变更之前经过弃用计划,以确保删除功能不会影响其他应用领域。
最后的反模式是没有逆向定义的变更。这个反模式主要适用于应用程序状态的存储,例如数据库或基础设施变更。它与第二点密切相关:如果变更是破坏性的,基本上就无法逆转。这个规则的扩展是,任何对系统状态、架构或数据的变更都必须是可恢复的。某些工具提供了这种功能,例如,Terraform 比较已部署的基础设施与状态文件,或通过 DACPAC 部署的 SQL Server 项目。在其他场景中,迁移必须显式定义正向和逆向操作,例如通过使用 Flyway 或 Entity Framework 迁移的数据库 SQL 迁移。我们在这里看到的常见反模式是,草稿中的变更包含了详细的向上迁移,但没有人构建或测试向下迁移。这种策略意味着当我们需要回滚变更时,通常需要进行大量工作,因为逆向迁移可能需要时间来创建,或者如果没有进行测试,可能会失效。这导致了高压、高风险的情况,我们必须在生产环境受到影响时制作变更,导致“只为让它重新运行”而偷工减料。
总结这一部分,复杂的发布流程由于开发与生产之间的高壁垒,允许出现不良实践。我们可以通过去除这些壁垒并支持良好实践来优化交付和提高服务的正常运行时间。关键在于频繁、标记清晰、经过充分测试的变更,这些变更是不可变的、无害的,并且在需要时易于恢复。这使得我们能够更快地开发,但我们仍然需要确保开发人员在做正确的事情,为此,我们通常会使用护栏措施。
护栏措施
我们已经讨论了如何赋予开发人员更多的权力,并让他们完全负责他们所做的变更。然而,开发人员并不是专家;我们在采纳“左移”思维时看到这种根本性的反模式。我们不应该期望开发人员成为安全性、站点可靠性工程(SRE)、DevSecOps 等方面的专家。开发人员需要对这些主题有一定的了解,但应该能够有信心地进行部署,而不必成为专家。
保持开发人员在正轨上
我们在这个领域经常看到的一个常见反模式是,由于我们正在将责任向左移交给开发团队,开发团队在云环境中需要更多权限来完成他们的工作。事实正好相反。开发人员应该有一组受限的权限来诊断、检查和支持云环境。相反,特权的升级应该发生在 CI/CD 管道中,这是通过提供具有提升权限的工具来启用我们的开发人员的方式。通过这样做,我们确保开发人员可以独立部署,但不会超出 CI/CD 环境的限制。这个过程通过手动配置限制了环境漂移的可能性,从而保留了灾难恢复功能。
使开发人员能够放心部署的主要方法是在部署过程中提供防护栏。这些防护栏定义了开发人员可以采取的一组可接受的操作。例如,基础设施防护栏可能防止在没有Web 应用程序防火墙(WAF)前端的情况下部署内容传递网络(CDN)。代码级防护栏可能避免使用不安全的哈希函数。在这两种情况下,我们防止变更在部署到生产环境时达到最低标准。
我们可能会部署防护栏,以满足法规合规要求。例如,可以采用云范围策略,防止在特定地区部署任何资源,以支持数据主权要求。这个例子非常适合来自亚马逊网络服务(AWS)的服务控制策略(SCP)。这些策略允许我们在不同粒度的层次上强制执行可接受使用的边界,从组织范围到个人账户。例如,我们将各种账户锁定到特定地区,全局上,我们防止所有账户在出口管制区域部署资源。
在安全领域中的一个反模式是将渗透测试误认为是关键部署路径上的防护栏。渗透测试是一个重要的安全步骤,但应该在部署路径之外进行。相反,它应该与部署过程并行进行。我们应该自动化部署路径中的所有步骤。如果你想动态测试应用程序安全性,考虑在预生产环境中使用动态应用程序安全测试(DAST)框架作为预提升检查。防护栏的关键因素是开发人员应能够按需访问防护栏评估。
防护栏的类型
我们通常看到两种主要类型的防护栏:预防性和检测性。
预防性防护栏是主动的防护栏,指定了开发人员可以做的外部边界;这些防护栏是惩罚性的,若防护栏被激活,管道就会停止部署。这种方法适用于应用容易定义的启发式规则(例如,我们的哈希算法不应该使用 MD5)。我们常见的错误是,预防性防护栏通常被实现后,开发人员被留给自己去应对。如果防护栏失败,他们必须返回并修复它。一个更好的工作流程是能够观察防护栏的激活情况。这些指标可以告诉你开发人员在哪些地方遇到最多的问题,从而通过提供培训、正确实现的库,或者更好的方法——一个可行的工具,来让开发人员的工作更轻松。
接下来,我们介绍侦测性防护栏。这些反应型防护栏会扫描你的环境以检查不合规的情况,然后会提出问题或采取纠正措施。例如,我们可以允许开发人员通过 CDN 部署具有公共访问权限的存储。然而,如果我们对包含个人身份信息(PII,Personally Identifiable Information)的特定存储进行标记,这一标记过程可能与存储本身的部署不一致。在这种情况下,我们可以添加一个侦测性防护栏,检查是否存在具有公共访问权限的存储,检查该存储账户是否有标记表示它包含 PII,然后激活防护栏。这种控制方式通常最不理想,因为它要求环境中先存在不安全的配置,才能检测到问题,而不是主动评估问题。
防护栏的一个典型驱动因素是安全性。现在有一些工具可以执行静态应用安全测试(SAST),以发现常见错误,并允许安全团队定义他们想要查找的自定义规则。这个领域有许多优秀的开源工具(如 Semgrep)以及许多专有的解决方案。虽然需要一些前期工作来编写想要捕捉的反模式,但每一条编写好的启发式规则都意味着安全团队不再需要手动审查。许多现有的工具不仅限于安全启发式,还能检查诸如深度嵌套的循环或认知复杂性等反模式。
防护栏可观察性的案例
构建护栏是至关重要的,但同样重要的是监控它们。开发人员使用可观察性平台来更好地理解用户行为,并对他们构建的应用程序进行更改以支持这些行为。我们也应该为我们的开发团队做同样的事,他们实际上是我们的用户。通过监控护栏,我们可以看到开发人员常遇到的摩擦点,并主动修复常见问题。假设我们之前的预防性护栏要求开发人员在 CDN 前面部署 WAF。我们可能会注意到开发人员经常遇到这个护栏,因此,利用我们收集的护栏激活指标,我们构建了一个启用工件。这个工件使开发人员能够避免触发护栏,且在没有额外返工的情况下生产出更安全的工件。
启用工件的关键在于通过合理的默认设置来抽象化标准配置。继续以 WAF 和 CDN 为例,作为安全团队,如果开发人员忘记明确指定 WAF,我们可能会引入一个默认的 WAF,该 WAF 会被添加到每个 CDN 部署中。如果我们已经为这种情况设立了侦测性和预防性护栏,那么启用工件将减少我们遇到的激活次数。在跟踪这些单元的指标时,我们建议监控所有内容。关于启用工件的指标告诉我们默认 WAF 激活的频率。这些指标很有帮助,因为它们是衡量启用工件对开发团队影响的好方法。
如果启用工件是预防性护栏的对应物,那么侦测性护栏的等价物就是自动修复。对于我们的 PII 标签解决方案,我们可以监听护栏激活事件,并启动一个过程,撤销对存储桶的公共访问。这使我们的系统在不需要外部干预的情况下,在简单用例中保持安全。
因此,对于我们应用程序中的漏洞或配置错误,首选是通过启用的工件(如库或自动化管道工具)添加一个合理的默认设置,然后对于超出此范围的情况,通过预防性护栏进行捕获,最后,如果配置错误到达生产环境,则启动自动修复或手动过程进行修正。
这些工具可以始终存在于管道和环境中。该系统的最终安全层应该是渗透测试,但需要注意的是,这一过程必须与应用程序的部署和开发异步进行。理想情况下,渗透测试的结果将反馈到我们的护栏系统中,帮助我们开发新的启用工件和预防/侦测控制,以防止问题重新出现。
示例护栏
在云环境中,系统的交互方式常常不寻常,因为不仅可以让已部署的基础设施和服务相互交互,还可以让它们与这些资源的底层定义进行交互。接下来,我们将介绍一些容易应用的常见护栏。虽然这并非详尽无遗,但它会为你提供一个起步点。作为我们的示例,我们将使用 AWS。
我们将使用以下的护栏示例:
-
权限过多的 IAM 账户
-
公共 S3 存储桶
-
数据主权要求
-
公共可访问的远程管理工具
一个简单的起点是 IAM 权限策略。我在这里不打算详细讨论最小权限原则,我们会在后续章节中介绍,但通常会看到定义了过多权限的账户或角色。通常,这种情况发生是因为用户无法找到正确的权限来执行所需的操作,于是他们最终分配了一长串权限或通配符权限,试图让其工作。实际上,这对我们之前讨论的三种控制方法来说是一个很好的候选对象;我们可以构建包含预批准策略的常见权限策略,用于完成常见任务,例如将 Lambda 函数连接到特定的 DynamoDB 表。接着,我们还可以添加预防性控制,例如在账户或组织中使用 SCP,禁止访问不再使用的特定 API。最后,我们可以添加侦测性控制,监控我们所有的活动角色,检查是否有包含通配符权限的策略,并在发现时撤销所有相关的授权和信任策略。
另一个常见的配置错误,适合用护栏来管理的是 S3 存储桶的公共访问。任何使用公共访问的 S3 存储桶场景,通常更适合通过使用 CloudFront 分发和源访问身份来解决。我们可以通过创建 Terraform 模块来构建一个启用的构件,该模块为存储桶设置默认配置并禁用公共访问。我们还可以构建一个预防性护栏,检查我们的基础设施计划,以防止出现此配置。最后,我们可以建立一个侦测性护栏,扫描已部署的基础设施,确保没有公共存储桶存在,如果存在,则撤销公共访问。
许多企业也面临数据主权要求的约束;某地区的实体数据必须存储在该地区。通过将资源部署到符合数据主权要求的区域,我们可以做到合规。然而,我们无法证明已合规,因为这种方法需要不断执行流程。相反,我们可以使用预防性控制:可以构建 SCP(服务控制策略),将账户中的资源锁定,禁止其部署到我们未指定的区域。这种方法必须是前瞻性的,因为它仅适用于新的 AWS API 调用。
我们看到的最后一种常见配置错误是直接将远程管理工具暴露到互联网上。例如,你的 EC2 实例可能会暴露端口22以允许开发者通过 SSH 连接,但这就意味着这些实例的攻击面增加了,具体取决于它们运行的 SSH 版本。这个问题应该在网络层面进行强制执行,通常,最好在这种情况下同时设置侦测性护栏(除了预防性护栏)。开发者很容易将 SSH 端口设置为22并开放无限制访问,然后自动关闭它。
希望通过阅读本节,你已经理解了可以配置的护栏类型,以及如何让开发者在不影响其开发速度的情况下,最好地在你设置的边界内工作。我们还讨论了监控组织护栏的重要性,这些指标为我们提供了清晰的视角,既能看出我们的安全态势,也能了解开发者的体验。最后,我们还探讨了一些常见的配置错误,并分析了护栏和启用的工具如何降低对业务的风险。因此,既然我们已经拥有了使开发者能够安全且可靠地管理输出的工具,让我们来看一下如何将生产安全工件的责任左移到开发团队。
左移
我们已经提到过将功能性和安全性的变化责任交给开发团队的需求。到目前为止,焦点主要放在了开发团队的外部因素上。本节将讨论将责任左移对开发团队的影响,以及我们可以使用哪些技术来满足对他们施加的新期望。如果你是开发者,建议阅读这一章,因为你将学习到一些有价值的工具;如果你是外部职能的一部分,这一章也能帮助你更好地支持开发团队。
作为一个迭代过程的开发
一种常见的反模式是,在开发者认为一个功能已经完成后,再启用质量保证(QA)而不是在整个软件开发生命周期中进行迭代过程。我们之前提到过临时环境,这对于开发者在隔离的环境中开发功能并提供一个可以在功能不完整时进行测试的环境非常有帮助。不同的公司有不同的 QA 功能,可能来自专门的 QA 角色,或者是产品团队的一部分。这里的关键是,临时环境让你可以在过程的早期就将 QA 功能引入其中。
另一个反模式是使用长期存在的特性分支和短暂的环境。我们在多个小分支上开发特性,每个分支包含整个特性所需的一部分工作。短暂环境为我们提供了一个替代部署方式,允许未完成的特性启用。我们通过从第一次提交开始就让 QA 参与,建立开发者和 QA 流程之间的快速反馈循环。将 QA 并行或集成到开发中,有助于我们减轻一个重要特性在完成后可能未通过 QA 测试的风险,从而需要大量返工来修复。它还通过促进 QA 和开发功能之间的协作,使我们更接近无隔离的模型。
先测试,后编码
团队通常认可但未能正确实施的反模式之一是测试驱动开发(TDD),以及行为驱动开发(BDD)。当询问开发团队是否使用 TDD 或 BDD 时,他们通常会肯定回答,但当被问到何时编写测试时,他们会回答说是在编写代码之后才写测试。撇开认知失调不谈,真正的 BDD 包括在实际实现系统之前,定义系统的行为并编写可以检查该行为是否符合要求的测试。实现 BDD 时另一个常见的误区是采用瀑布式的编码测试方法,预先列出所有预见到的边缘情况并编写过多的测试。许多系统的行为和需求只有在实际实现系统过程中才会显现出来,而过早编写过多的测试只会妨碍这一发现过程。相反,在 BDD 中,一个很好的方法是使用红绿重构系统。你首先定义期望的行为,并编写简单的测试来确保系统能实现这个行为。这些测试会失败(红),然后我们会实现一个能够通过这些测试的系统(绿)。通过设计这个系统,我们再对实现和测试用例进行重构,以准确展现期望的行为,并测试系统的 emergent 行为。我们必须与产品负责人一起创建初步的期望行为,以确保期望行为测试能够准确反映最终产品所需的行为。这个过程将会将期望行为的描述“提前”,直到我们开始编写任何代码之前。
一旦我们创建了测试,它们应该进入部署管道的关键路径。这个实践可以确保系统的未来更改不会阻止其展现所需的行为。团队在这一阶段容易陷入的一个常见反模式是无法完全信任测试的输出。在极端情况下,这可能表现为接受一定比例的失败测试作为“正常现象”。这种对测试缺乏信心削弱了整个测试套件的价值,因为开发人员不再相信他们的更改不会导致现有行为的回归。
第二种更常见的模式是间歇性的测试失败。当测试未能正确隔离时,通常会发生间歇性失败,而一个测试的副作用可能会影响另一个测试的结果。在这种情况下,开发人员通常会重新运行管道,直到间歇性测试通过。这种行为是适得其反的,原因有两个:首先,我们增加了开发人员等待管道执行完成的时间;其次,我们忽略了一个失败的测试。在这种情况下,与其忍受多次管道运行的不便,不如充分地重新确定测试的边界,并创建一个新测试来检查间歇性行为的回归。通过严格执行这些测试套件,我们将检测和纠正回归的责任“左移”到负责回归的开发人员身上,让他们在开发过程中处理,而不是等到回归在最终产品中显现出来。
输出的共享责任
考虑弗雷德·布鲁克斯(Fred Brooks)的名言:“一个程序员在一个月内能做到的事情,两个程序员可以在两个月内做到。”虽然是半开玩笑的,但这种情绪在我们独立编程时仍然成立。增加的沟通渠道和知识分发可以使开发过程更加苛刻,这导致我们第三个常见的反模式,孤立开发。我们看到过软件团队,他们只在每日站会中与彼此交互。这种系统会回到我们旧的慢反馈周期的模式。如果我在每日站会后完成并需要另一名团队开发者的输出来推进我的特性,可能会在站会后 5 分钟完成,而我需要等到第二天才能听到相关情况。我见过高效开发团队在虚拟呼叫中整天工作,根据需要分拆出主要呼叫以进行配对编程和集体编程。关键的不同点在于,高效的团队将他们的交付视为共同的输出,而不是个人的输出。这种不同点也需要在我们如何跟踪生产力指标方面得到体现,这些指标应该反映团队的生产力,而不是个人的。个人的管理受到来自其他团队成员的反馈的指导,因为团队是我们希望优化的价值。
小而定期的变更,合并回代码库,从代码审查的角度来看也至关重要。向开发者展示一个 12 行的拉取请求,他们会有很多评论。向他们展示一个 1,200 行的拉取请求,你可能会得到零评论。也许你会得到一个“看起来不错。”的回复。这种方法的主要敌人是长期运行的功能分支。如果你不定期将代码合并到主分支中,那么审阅者就无法理解变更的范围。在这里,支持小而原子化变更的开发过程至关重要,比如前面在本章讨论过的基干开发和特性标志。在努力满足截止日期时,通常会倾向于批准拉取请求,以更宽松的标准整合变更。然而,这种方法是一种虚假的经济。通过批准宽松的变更,比如不符合编码标准的代码或具有高认知复杂性的代码,我们只是在削弱未来的速度,并积累技术债务。这个问题的另一面是,当我们在拉取请求阶段严格执行编码标准时,我们慢慢开始看到团队的提升,同一个团队成员未来的拉取请求不太可能出现同样的错误。不执行编码标准是我们虚假经济的关键。执行与不执行编码标准最终会让您达到等效或增加的开发速度。
早期实验和及早获得反馈
我们已经检查了典型软件开发业务功能中的反馈循环。然而,您还应该关注可能更具体于您业务的反馈循环。一个例子可能是来自金融系统的订单匹配引擎可能需要过去六个月的数据输入系统,以确保它达到与现有引擎相同的目标状态。为了将这一过程向左转型,我们可以使用较小的时间范围和虚拟数据,让开发人员在本地运行,以便获得即时反馈。向左转型的关键是识别这些反馈循环,并将其直接交给开发人员,或者在开发的早期阶段使开发人员能够与负责业务单元互动。这个业务过程的优化确保了我们减少了流程后期出现重大更改的机会。为了促进这一点,我们建议绘制出所有部署过程中,开发人员完成更改后发生的部分,并找到这一过程中发生最多故障(即需要开发人员返工)的区域。这些过程部分是您向左转型的最佳候选。需要注意的是,您仍然需要有关流程的度量数据,以识别这些阶段,因此,部署过程的可观察性在其有效性中是一个重要因素。
向左转型还要求开发团队在解决某个功能时成为真实信息的来源。开发团队必须被允许在承诺解决方案之前进行实验。一种很好的方法是通过限定时间的技术探针(timeboxed technical spikes),如果需要测试不同方法的有效性,可能会同时进行多个技术探针。这里的关键因素是允许开发人员进行实验,并通过他们的工作成果来验证一个想法或假设,而不是引入更改或新特性。这一过程是短暂环境(ephemeral environments)发挥作用的又一个领域。拥有一个没有后果的沙盒来测试概念验证(proof-of-concept)想法,使开发团队能够以马克·扎克伯格的话说,"快速行动并打破事物"。尽管这种方法并不旨在产生可见的成果,但通常情况下,如果这些技术探针成功,它们将成为新更改或新特性的基础。因此,尽管目标不是创建更改,但技术探针通常并不会导致生产力的浪费。
从一开始就将安全性构建进来
shift-left 方法的最终要求是确保安全性从变更开始时就融入到云原生解决方案中。开发人员必须意识到他们的决策对整体解决方案安全姿态的影响。开发人员不需要成为安全专家,而是需要将思维方式从“它能达到预期目标吗?”转变为考虑他们的变更可能带来的新攻击面。一个优秀的方法是将威胁建模作为开发过程的一部分,来引导刚刚采用 shift-left 方法论的开发团队。通过转变为攻击者的思维方式,我们可以迅速识别威胁并采取缓解措施加以防御。如果安全团队参与到前几次的尝试中,这个练习将更加有效。尽管团队的目标是实现自给自足(这是我们稍后会讨论的主题),但利用支持团队来确保跨团队的一致性质量仍然至关重要。
通过 shift-left 方法,我们使开发人员能够生产安全、完整且适合生产环境的变更。使用适当的工具和业务流程提高了开发速度,并赋予了开发人员控制权和适当的保障措施,使他们能够专注于寻找最佳解决方案。现在,随着团队开始负责自己的产出,接下来我们将探讨如何让这些团队真正实现自给自足。
自给自足的团队
通过在文化、流程、工具和交付方面做出的所有变更,我们期望我们的团队成为自给自足的变更工厂。但我们如何调整团队的内部结构,以确保团队能够组织和支持这些新的工作方式呢?
三位一体领导力
Spotify 推广了一种被称为 Squad Model(小队模型)的模式。虽然通常它也包含独立小队之外更大规模的结构,但我们将专注于小队本身的结构。对于更大模型的批评是有其有效性的,但这并不影响原子团队结构的有效性。团队的核心在于它是一个专注于特定产品的单位。它包含三位领导者,负责指导小队的发展工作。这三位领导者分别是工程经理,负责团队的技术方向;产品负责人,代表客户;以及 Scrum Master,组织团队的工作。通过将团队的责任封装在团队内部,并允许团队能够跨整个产品进行工作,我们可以横向扩展这些小队,而不会线性增加管理开销。现在,我们进入了可扩展的敏捷交付,这与云原生开发的要求非常契合。
成功实施这种格式的关键是理解,虽然领导层是三位一体的,但实际责任之间的重叠很小。这个领域中一个常见的反模式是所有开发者都向工程经理汇报。开发者是变更的实施者,产生系统变更比技术方向更为复杂。相反,开发者成为他们所做变更的管理者,理解背后的产品思维以及实施所需的技术方向。传达这一点的一个很好的方式是通过一个叫做指挥官意图的概念。它指的是领导指令的抽象,以涵盖目标,从而使我们的方法更加灵活。在最初的形式中,命令可能要求我们前往战场上的特定位置,但意图是与其他单位一起攻占某个特定的山丘。如果我们专注于如何(移动到位置),我们可能会错过完成什么(占领山丘)的机会。
同样地,如果我们强制开发者按照规定的步骤实现某个功能,那么那些只有实现者才能看到的新兴机会可能会被忽视。这种情况下,三位一体的领导和协作模式(Squads)非常有效。我们不仅能传达特定变更的指挥意图,而且开发者还拥有本地的权威来源,以便展示这些新机会和战略方向。
之前,我在一个组织工作,使用一种特定的框架,试图在保持对产品团队的完全控制的同时安全地扩展敏捷开发。这个框架的实施导致了战略方向的不一致。换句话说,这个过程没有使团队具备自给自足并抓住机会的能力,因为要求在我们采取行动之前,要在多个层级上展示这些机会。自给自足的团队正是这一范式的对立面。我们不再强调控制,而是寻求授权并提供战略方向,同时促进战略机会。
团队的拓扑结构
在他们的开创性著作《团队拓扑》中,Matthew Skelton 和 Manuel Pais 确定了在一个 DevSecOps 聚焦的组织中四种类型的团队,如下所示:
-
流程对齐团队
-
赋能团队
-
复杂子系统团队
-
平台团队
流程对齐团队是业务领域的专家,其输出与该业务领域的战略方向保持一致。这个团队是你组织的主要团队,直接专注于解决业务或客户问题的变化。请注意,这些团队的组织是按业务领域划分的,而康威定律假设这些领域会在我们的架构中自然形成有界上下文。我们不应将团队限制为只拥有和操作代码库中的某一部分。
启用团队通过提供技术指导和支持开发团队的工作成果,帮助其他类型的团队实现目标。例如,专门的安全团队可能协助那些在开发过程中面临独特安全问题的团队。需要注意的是,这些团队的存在并不意味着可以免除其他团队的责任。这些团队是增强者,而非取代自给自足的角色。
复杂子系统团队处理的是需要深入技术或工程能力的子系统。这种类型的团队通常是唯一会被分配到组织架构中特定部分的团队,通常,这个团队的角色是将复杂的子系统抽象出来,供业务的其他部分与之交互。一个典型的例子可能是某个仍在使用大型主机的银行;我们通过复杂子系统团队来管理该主机,并为其他团队提供接口以便交互。
平台团队是开发团队为开发人员所建设的团队;他们为其他团队提供内部产品,其他团队则是这些产品的使用者。平台可能包括标准化的构建流水线和护栏、启用的工件和工具,如 Git、票务管理软件等。正如我们之前讨论过的,你的度量标准和客户开发团队应该引导该团队的战略方向。该团队有三种主要的运作模式:
-
协作:这涉及到团队之间的长期合作。这些可能是进行相关变更的团队,或是流线型团队与平台团队合作开发新工具,亦或是团队与复杂子系统团队共同努力,以推动服务的演进。
-
X 即服务:这种模型通常指的是复杂的子系统团队将技术上复杂的功能抽象成服务,供其他团队使用。
-
促进:这涉及到团队合作以实现特定团队的目标。例如,安全启用团队可能促进对流线型团队所需的授权逻辑的变更。这种模式通常也包括赋能团队,以便在未来能够自给自足。
在识别这些运作模式时,出现了一些反模式。最常见的一个是认为组织中的许多部分都是复杂的子系统。关键的区别在于,复杂的子系统团队专注于某些技术复杂的内容。复杂的业务领域并不是一个复杂的子系统。这种思维方式将我们带回了一个陷阱:将团队与现有架构对齐,而不是与业务领域对齐,并且让架构从这些新兴领域的自然边界上下文中发展出来。
当支持团队需要促进与流对齐团队目标的实现时,他们常犯的一个错误是,假设作为该领域的专家,他们应该直接做出所需的改变。从根本上说,为了促进团队的自给自足,支持团队需要指导流对齐团队,提高团队的能力。
最后,对于那些整个组织负责的事务,使用 X-as-a-service 模式可能会很有诱惑力。一个关键的例子就是安全性。安全性不是我们可以独立开发并作为服务提供给开发者的系统。它是每个团队成员的责任。我们可以构建我们的平台工具,并使支持团队能够激励并培养良好的安全实践。X-as-a-service 交互模式的目的是将技术责任从服务消费者身上移除,而在安全性的情况下,这种做法是适得其反的。
冠军和 T 型工程师
随着我们从传统交付模型转向云原生交付模型,我们也在拓宽可以使用的服务范围。我们不再一次又一次地用相同的方式解决业务问题,而是有机会利用云原生服务。然而,随着我们视野的拓宽,我们必然需要教育我们的团队关于这些新型服务的最佳实践。在传统模型中,每个开发者都能够理解所需的架构和代码模式。指望我们的团队一夜之间成为专家是不现实的;然而,我们的每个开发者都需要获得关于云原生服务的广泛知识,以便在某些模式需要使用时能够识别出来。这种广泛的知识构成了 T 型工程师的顶端,它是通过自学获得的广泛但浅显的知识。当他们反复使用某些模式时,他们会深入理解所涉及服务的特定实现特点,形成深厚的知识。这构成了我们 T 型工程师的竖直部分,它是深度但范围有限的专业知识。这个理念是,当团队中有几个 T 型工程师时,我们就能够获得多样的技术意见来指导团队的技术方向。
对于公司范围内的零基础倡议,例如安全性、可访问性或代码质量,我们建议在团队内选举出冠军人物,以便为自给自足的团队提供满足目标的内部能力。然后,由支持这一倡议的管理团队(可能是支持团队)负责支持这些冠军人物在各自领域的发展。这可能包括通过认证路径支持自学,资助他们参加会议,以及提供内部知识共享机会。关键在于,公司必须投资于其员工,才能使倡议成功并取得成果。仅仅按部就班地继续开展业务是远远不够的。在云技术领域,技术和实践发展迅速;作为一家公司,为了最大化云投资的回报,必须对员工进行投资。
在团队中构建云原生能力需要时间;认识到需要为团队提供所有工具和机会,以使其具备自给自足的能力至关重要。为此,我们探讨了产品负责人、工程经理和敏捷教练的三重领导模式。同时,我们也研究了团队如何组织相互之间的互动。最后,我们考虑了如何在组织内推动倡议并通过鼓励 T 型工程师和冠军计划提供多样化的意见。
摘要
通过对成果的 ownership(所有权)和团队赋能,我们已将开发团队转变为真正自给自足的强大力量。我们通过自动化流程和保护措施来调节他们的产出,确保他们在我们业务所需的约束条件下工作。我们还考虑了如何减少任何一个负面变化对整个系统的影响。这些原子化的变化将成为我们未来发展模型的基础。接下来,我们将深入研究如何在云原生环境中保持安全性和合规性。
第六章:如何达成您的安全性和合规性目标
在今天的数字化世界中,保持组织安全是一个持续的过程——这绝不是一次性完成的任务。随着云环境的崛起,风险比以往任何时候都要大。本章将深入探讨我们面临的一些最大挑战,从过度授权访问的风险,到在发布前只进行一次渗透测试就认为足够的误区。我们还将拆解供应链安全问题,并澄清共享责任模型的任何困惑。无论你是 IT 领域的资深人士,还是刚刚开始接触云安全,你都会找到一些实用的建议,帮助保护你的组织。
本章将描述常见的安全和合规反模式。这些反模式暴露了您的组织,并使通过外部合规审计变得具有挑战性。
本章将涵盖以下主题:
-
如何管理权限而不造成过度授权
-
安全中的持续合规性的重要性
-
主动监控
-
共享责任模型
-
供应链安全隐患
如何管理权限而不造成过度授权
在本节中,我们将探讨在云架构中,作为人类为了完成日常工作所需的权限,无论是作为解决方案架构师、DevOps 工程师,还是作为财务角色中的账户管理者。每个人根据其在业务中的角色需要不同的权限。接着,我们将看看你需要应用于服务和设备的权限,以便个人在某个角色中能够访问所需的资源。同时,我们将确保我们以最低的必要权限来处理这些权限,遵循最小权限原则,以便在相关角色中发挥作用。
这些行为将帮助我们避免作为人类犯下大规模的错误,这些错误可能会损害您的商业声誉。
高权限账户的安全
从我们注册云服务提供商账户的那一刻起,我们创建了一套凭证来根据需要设置我们的云架构。每个云服务提供商可能会有不同的定义,但三大云提供商是这样定义的:
-
Amazon Web Services (AWS):在 AWS 注册时使用的电子邮件地址被视为高权限账户(即根账户)
-
Microsoft Azure (Azure):在这里,它被称为“全局管理员”
-
Google Cloud Platform (GCP):这被称为“所有者”角色。
这种级别的访问既方便又高风险,原因如下:
-
对所有资源和操作的无限制访问:为某人提供对云环境的无限制访问可能会让事情变得更简单,但这是一个重大风险。拥有完全控制权限的用户可能会不小心删除关键资源、错误配置安全设置,或访问不该看到的敏感数据。如果他们的凭据被泄露,攻击者可能会造成严重损害——从摧毁基础设施到泄露机密信息。正因为如此,最小权限原则至关重要——它将访问权限限制在必要的范围内,减少了意外错误的可能性,并在出现问题时最小化影响。
-
不可逆损害的潜力:过多的访问权限意味着打开了不可恢复错误的大门。拥有完全控制权限的人可能会不小心删除数据库、损坏备份,甚至关闭生产环境。一旦损害发生,就无法保证能恢复——数据可能会永久丢失,停机时间也可能给您带来巨大的成本。因此,限制访问权限并设置保护措施至关重要,以防止任何人进行无法撤销的更改。关键在于避免出现单点故障,避免一切崩溃。
-
攻击者的高价值目标:具有无限制访问权限的账户对攻击者来说如同黄金。如果他们掌握了这些账户,就可以窃取敏感数据、禁用服务或完全接管您的系统。损害将是即时且深远的,直接影响到您的安全、声誉和底线。因此,这些账户需要通过强有力的控制手段加以保护,如多因素认证,并且权限需要保持有限。关键是确保您不会成为攻击者的容易目标。
可以遵循一些基本的最佳实践,以确保您的高权限账户尽可能安全。
-
设置强密码,并将其存储在安全的密码库中。
-
启用多因素认证。这样可以确保您在登录时需要通过物理方式证明自己是账户的拥有者,可以通过 6 位数验证码或生物识别信息来验证身份。关于这方面的更多内容,请参见后续“实施多因素认证(MFA)”一节。
重要提示
对于根账户或类似账户,如果它是唯一账户而非角色,尽量使用硬件令牌,并将其保存在安全的地方。
-
创建用户账户或实施单点登录提供商,并为用户分配相关权限。
-
不要允许高权限账户具有程序化访问权限
-
监控账户活动。如果在此账户级别检测到使用,请确保向相关领导或管理层发送警报。
-
限制此账户级别的使用。有时我们确实需要登录此账户级别,但这应该是例外情况,而非常规操作。
将高权限账户视为与您的建筑租约或交易许可证同等重要。这是你在云世界中作为企业的身份认证,如果有人破坏了这个账户,你将很难证明你是你所声称的那个人。
即使你没有使用类似 root 的访问账户,账户也应像上面所述一样确保安全。
过度特权用户和服务
你有多少次听过以下短语或类似的话?
“给我访问所有东西, 这样更简单!”
“只给他们一个临时管理员角色以 节省时间”。
在云环境中,过度特权访问意味着用户可能并不需要被分配给他们的所有权限。
想象一个繁忙的办公室,从实习生到 CEO,每个人都有每个门的主钥匙。虽然这看起来很方便,但它带来了显著的安全风险。任何人都可能访问敏感区域、机密文件,甚至 CEO 的办公室,无论他们是否需要进入。这个场景类似于云环境中过度特权用户的问题。
第一类过度特权用户是云服务提供商为你设置的默认账户,现在你应该已经确保了该访问控制的安全性。
无论你是刚起步的单个开发者,还是一家市值数百万美元的公司,你都需要确保只使用你所需要的权限。同样,如果你允许资源对服务执行操作,你需要确保为此部署的服务账户仅被授予访问特定资源/对象/文件/服务的权限。
人员权限
在云世界中,过度特权用户就像拥有主钥匙的员工。他们拥有比执行工作所需更多的访问权限。这种情况通常发生在授予广泛权限似乎比根据特定角色定制访问权限更容易的情况下。然而,这种便利性对安全性造成了很高的代价,在某些情况下,还可能影响合规性,例如:
-
增加的泄露风险
-
人为错误
-
责任问题
从本质上讲,管理云环境中的用户访问是关于在便利性和安全性之间找到合适的平衡。通过解决过度特权用户问题,并采用最小特权和基于角色的访问控制(RBAC)等最佳实践,组织可以保护其云资源并维持一个安全、高效的环境。记住,在安全性上,越少往往越多——尤其是当涉及到权限时。
就合规性而言,你需要查看你的具体标准以及过度特权用户可能带来的影响。例如,PCI DSS 要求遵循最小特权原则,否则你将未能通过审计,进而影响商业优先事项。
服务权限
在云计算中,服务帐户就像工厂中的机器。这些帐户由应用程序和自动化过程用于与云服务交互。权限过多的服务帐户拥有执行其功能所需的过多权限,就像一台能够访问工厂每个部分的机器。
那么,为什么这会成为一个问题呢?
-
安全漏洞:服务帐户可能成为攻击者的易攻击目标。如果被攻破,它们可以被用来访问敏感数据、破坏服务或在云环境中提升权限。
-
无意的访问:由于过度权限的服务帐户可能拥有额外的权限,这可能导致无意的操作,如删除数据或修改配置。
现在我们来学习如何管理人类用户和服务帐户的过度权限访问。
应用最小权限原则
管理过度权限的访问,对于人类用户和服务帐户来说,对维持安全性和运营效率至关重要。按照以下步骤实现最小权限原则:
理解访问要求
设置访问要求时,尝试:
-
首先,确定每个用户和服务的特定访问要求。
-
确定执行其工作职能所需的最小权限集。
-
根据这些要求定义角色,确保角色与组织内的特定任务或职责相匹配。
基于角色的访问控制(RBAC)
基于角色的访问控制可能更加安全,因此值得调查是否可以使用此方法。在创建角色时,请考虑以下事项:
-
开发具有特定权限的角色,使其与工作职能相匹配,并将用户分配到这些角色中。此方法仅限于为角色分配所需的访问权限。
-
按功能和责任划分角色,以防止重叠,并确保权限分配的清晰性。
利用身份和访问管理工具
有许多不同的工具集可以帮助你管理云环境中的身份和访问控制。在使用这些工具时,考虑以下最佳实践:
-
使用云服务商提供的 IAM 工具来创建和管理角色及策略,执行最小权限原则。
-
将角色分配给用户和服务,而不是直接授予权限,以确保访问控制并可审计。
-
实施控制策略以设定权限边界,防止用户超出其预期访问权限。使用访问策略定义用户和服务可以执行的操作,并确保这些策略在所有资源上始终如一地应用。
-
开发定制角色,专门针对组织的具体需求,确保角色仅包含用户执行任务所需的权限。定制角色有助于防止使用带有预定义角色的过度权限。
-
利用集中式 IAM 解决方案管理所有云服务的用户身份和访问权限。这种方法可以实现一致的策略执行和简化的访问管理,减少处理权限时的复杂性。
实施多因素认证(MFA)
在保护云环境时,多因素认证(MFA)是至关重要的一步,但它也有其挑战。
-
在你的云服务的身份与访问管理仪表板或控制面板中,确保强制要求使用 MFA 访问敏感资源,增加额外的安全层,即使凭证被泄露,也能减少未经授权的访问风险。
-
确保你使用的 MFA 机制不会成为单点故障。例如,你登录工作邮箱、社交媒体或云账户时,使用手机上的应用(如 Google Authenticator)设置虚拟 MFA 设备。然后你丢失了手机,现在你无法登录任何账户,直到你通过一个有时较长的过程来证明你的身份并重置 MFA。
-
有些人更喜欢使用硬件 MFA 解决方案,如 RSA 密钥,它会提供我们最熟悉的六位数字代码,或者更流行的 Yubikey 风格设备,它提供单次触摸的二次身份验证方法。这样,他们就不必依赖于几乎是一次性或容易更换的技术。然而,这些方法仍然可能像我们的钥匙或手机一样丢失。而且,由于它们体积小,也很容易被隐蔽,万一有人想偷走它们以访问不该访问的资源。
至少有两种妥协方案可以使用。
-
提供备份和多设备访问的虚拟化 MFA 软件平台(例如 1Password、Authy、LastPass 等)。
-
如果支持,可以对账户应用多重 MFA 方法。这样,你可以使用手机的身份验证器和硬件设备。这样,无论哪种设备都能让你保持访问权限。
提示:
如果可以使用生物识别(指纹、人脸识别等)认证,请这样做!生物识别认证通过将访问权限与个人的独特特征绑定,增加了安全性,使攻击者更难伪造或窃取。
定期审查和审核权限
定期审计权限,确保它们与当前的工作职能和责任保持一致。删除或调整不再需要的权限。
使用自动化工具和脚本识别并报告权限过高的账户和不必要的权限。大三云服务提供商的工具有:
-
AWS
-
AWS 身份与访问管理(IAM)访问分析器:发现外部共享的资源并标记过度权限,确保你的 IAM 策略安全且合规。
-
AWS 配置:跟踪资源变更,确保您的 IAM 角色和权限保持合规,且没有配置错误。
-
AWS CloudTrail:记录 API 活动,提供关于谁在做什么的可见性,并标记任何异常行为。
-
-
Azure
-
Azure AD 特权身份管理(PIM):监控和控制对关键资源的访问,帮助您识别并修正过度授权的账户。
-
Azure 策略:强制执行合规性并审计资源,确保您的权限和访问控制符合安全标准。
-
Azure 安全中心:提供全面的安全态势视图,自动检测和修正高风险权限。
-
-
GCP
-
Google Cloud IAM 策略分析器:分析您的 GCP 设置中的访问情况,发现过度授权的账户并评估相关风险。
-
Google Cloud 资产库存:提供清晰的资源和权限审计轨迹,突出潜在的安全漏洞。
-
Google Cloud 安全指挥中心:集中管理安全视图,同时跟踪权限、角色和高风险配置。
-
使用临时和细粒度访问
关于身份访问的其他考虑事项可能包括:
-
利用临时访问凭证,如 AWS 安全令牌服务(STS)、Azure 管理身份,或 GCP 服务帐户密钥,配合时间限制访问,以减少长期凭证暴露的风险。
-
应用细粒度权限限制用户和服务可以执行的操作,如特定 API 调用或访问特定数据集。
实施日志记录和监控
正如你在 第十章 中可能看到的那样,了解架构中发生的事情非常重要。这同样适用于您的身份管理,并且可以通过日志记录和监控来实现:
-
启用日志记录和监控,跟踪用户和服务执行的访问和操作。使用云原生工具,如 AWS CloudTrail、Azure Monitor 和 GCP Cloud Logging。
-
设置可疑活动或试图访问超出授权权限的资源的警报。
教育和培训用户
最后,为了遵循最小权限原则,我们需要确保用户充分了解我们的安全目标:
-
定期向用户提供关于最小权限原则及维护安全环境最佳实践的培训。让他们了解过度授权访问的潜在风险和后果。
-
举办威胁建模研讨会,帮助用户理解潜在的安全威胁及其缓解方法。通过分析威胁,用户能更好地理解适当访问控制的重要性,以及它们在保护组织中的作用。
-
保持用户了解访问政策和程序的更新。确保他们理解这些变化的理由,以及这些变化如何与整体安全战略对齐。
不是所有的日志记录都是相同的
如前所述,日志记录非常重要。然而,必须注意应用日志和安全日志之间的区别。
应用日志是关于跟踪软件的性能和行为的。它是调试和性能优化的基础。当出现问题时,这些日志告诉你发生了什么,在哪里发生,为什么发生。它们专注于应用程序的内部工作——例如跟踪用户活动、错误和系统事件,帮助你改善用户体验。
另一方面,安全日志是你对抗威胁的防线。这些日志旨在捕捉任何可疑活动,从未经授权的访问尝试到异常的行为模式。它们不仅关注应用程序内部发生的事情,还关注周围发生的情况——例如,谁试图进入以及他们进入后在做什么。安全日志为你提供了在潜在泄露升级之前检测和应对的洞察。
简而言之,虽然应用日志帮助你保持系统平稳运行,但安全日志则是为了保护安全。这两者都是必不可少的,但它们服务于不同的目标。确保同时关注两者,因为忽视其中任何一个都可能让你暴露在风险中。
依赖长期静态凭证
在云管理和安全领域,常见的反模式是,一旦我们配置了用户,就往往忘记管理该用户。我们有时会犯错误,也有时会在错误的时间复制和粘贴错误的内容。
静态凭证是我们在管理控制台、笔记本电脑或个人电子邮件中设置的凭证类型。偶尔,它们会在 90 天(约 3 个月)以上的时间内长期有效,有时甚至超过 120 天(约 4 个月)。随着密码设置的时间延长,它被泄露的可能性也会增加。常见的泄露方式包括:
-
忠诚卡系统将其数据库复制到公共源中。
-
服务提供商不小心将开发 API 留公开
-
将凭证复制并粘贴到源代码库中
-
将数据备份到公交车或火车上的 USB 驱动器中
这也不是潜在泄露的限定列表,发挥创造力,如果你能想到,它可能已经发生过。
一旦恶意行为者获取了你的数据,这些数据已经在暗网出售或以恶意方式使用。这些数据可能包括你的姓名、电子邮件地址、用户名和密码。
小贴士:
长时间保存密码是不好的,将密码在不同系统之间重复使用同样不好!
作为人类,我们喜欢在生活中重复使用模式,因为这有助于让事物变得熟悉。所以,那些在暗网上被转售的密码很可能已经在工作中使用过,并且在我们的云环境中也被用过,这就意味着它容易通过猜测机制遭到攻击。一旦恶意行为者获得了一份电子邮件地址和密码的列表,他们会开始将这些密码应用到许多其他服务上,仅仅是为了猜测,以尝试破坏并获取他们以前无法访问的资源。
举个例子,如果我刚刚从暗网上收到了一份来自咖啡店忠诚度计划的用户表格,内容如下:
用户名:“user1@bigcorp.com”
密码:“Thi!Sh0uldHaveB33nMySuperStrongPassword”
从中,我们已经可以识别出这个人工作的公司,他们的企业 ID 用户名,以及他们的密码。此人设置密码时遵循了最佳实践。然而,像这样泄露的密码无论多强大都无济于事。
既然这个密码已经曝光,那么很有可能它也是他们公司电子邮件、VPN、单点登录等的密码。随着时间的推移,这个密码会在互联网上传播,并最终落入错误之手,进而被恶意使用。
一家云服务提供商,AWS,建议每 90 到 120 天更换一次密码,因为在这个时间点之后,密码被认为已经泄露并且被攻破。可以通过控制台中的 IAM 用户控制或其他云服务提供商的类似功能来实现密码轮换。
在轮换密码时,我们还需要记住,有时我们有其他静态凭证,比如开发人员使用 AWS CLI、AWS CDK 或 SDK,并向他们的应用程序提供了访问密钥和秘密密钥。这些也需要轮换,可以使用云服务提供商的原生功能或通过 Lambda 或其他功能使用自定义轮换策略来实现。
静态凭证也可以存在于数据库和 API 中,这些凭证通常可以持续多年,甚至在某些情况下能维持十年之久。云服务提供商提供了专用的秘密金库,可以让你安全地存储凭证并进行轮换,从而避免密码以明文形式或环境变量的方式使用,并且能够充分地进行轮换。
API 密钥更难更改,因为它们可能被客户使用,而不仅仅是你的应用程序。在这种情况下,你需要通过确保访问密钥、IAM 身份或 API 密钥无法访问除该客户数据以外的任何人的数据来减少影响范围,并确保你拥有精细的控制来隔离多租户系统中的客户数据。你可以在本章的最后一节“供应链不安全性”中阅读更多相关内容。
威胁建模
在向人员或系统授予任何计划的权限之前,了解在做出这些决策时所面临的威胁级别是非常重要的。
问问自己以下四个问题:
-
我们在做什么?
-
会出什么问题?
-
我们该怎么做?
-
我们做得够好吗?
一旦你回答了这 4 个问题,你应该能更清楚地了解当时的威胁等级。这就是基本的威胁建模。
威胁建模完全是为了在安全方面抢占先机。这是一个拆解系统以发现潜在漏洞并找出它们如何被利用的过程。通过像攻击者一样思考,你可以识别出弱点并采取措施在问题发生之前将其加固。这是主动出击,而非被动反应,给你一个方法来优先处理和应对风险,避免被突如其来的威胁所打乱。简而言之,威胁建模帮助你始终走在潜在威胁的前面。
威胁建模作为一项实践,可能会成为一本完整的书,内容非常广泛,但这里看到的一个主要反模式是对这项实践的无知或天真。
确保所有与代码或基础设施相关的员工都经过威胁建模的培训。不要让它成为一次性培训,这应该每年重新审视一次,并将其作为人力资源标准入职流程的一部分。
安全中持续合规性的重要性
在推出新的应用或系统时,通常会急于在大规模上线前完成最后一次渗透测试。但问题是:仅依赖一次测试就像是给你的车做一次检查,然后希望一切顺利,前提是你不会在路上遇到麻烦。安全和合规性需要持续关注和努力。在这一章中,我们将揭示合规性的真正含义,以及为什么它必须超越一次性测试,融入到你的安全策略中。
打破一次性测试的迷思
你一定听过这个迷思“一次渗透测试就足够”。
现在就打破这个迷思。一次发布前的渗透测试不足以保证你应用的安全性。它能给你提供一个当前状况的良好视图,那一瞬间的快照,可能足以让你做出红灯/绿灯,“是否继续”的决定。
那下周呢?下个月呢?
安全威胁随着时间的推移而演变,有时甚至是过夜的事。安全需要是一个持续的过程,是你始终在进行的工作,并且始终保持可见性。不是临时抱佛脚。将其融入到你的应用、架构和基础设施中。将其成为你工作文化的一部分。
一夜之间的变化
2021 年 11 月 23 日,成千上万的软件开发人员、CTO、CIO 和工程经理们在一片安宁中入睡,全然不知他们的应用栈可能存在问题。像电影情节一样,第二天早晨他们被突如其来的安全漏洞问题惊醒,这个漏洞被认为是史上最严重的安全漏洞之一。
“Log4Shell”(CVE-2021-44228)是一个在流行的 Java 日志框架 Log4J 中发现的漏洞。它在 CVE 指数上被评为 10 分,这是可以给予的最高评分,允许恶意行为者在使用 Log4J 的服务器上执行任意代码。这个漏洞自 2013 年起一直处于潜伏状态,直到 8 年后才被发现,并且修补这个漏洞又花费了近一个月的时间。
但一旦这个漏洞成为已知漏洞,这就是“零日”漏洞。恐慌的时刻。此时你最脆弱,因为漏洞已经为全世界所知,黑客可以利用这一武器对任何想造成恶意损害的人进行攻击。与此同时,当局,“我们的电影中的好人”,正在寻找解决办法,修补并防止这一漏洞的影响。
如果你是一个 Java 软件开发人员或拥有 Java 技术栈的 CTO,你会愿意对这种情况一无所知吗?还是宁愿被警报或电子邮件唤醒,及时获取正确的信息以减轻这一情况的影响?
持续安全和合规性的重要性
Log4Shell 的故事鲜明地提醒我们,安全永远不是一劳永逸的任务。即使你的系统今天通过了渗透测试,明天也可能会发现新的漏洞。应对这些威胁的唯一方式是通过持续的安全监控和合规性验证。
合规性不仅仅是一个检查清单
合规性不仅仅是为了填满一堆复选框或避免严厉的罚款。它关乎保护你的知识产权、组织和声誉,并与客户建立信任。当你将合规性整合到安全策略中时,你不仅仅是在遵循一些松散的指导方针,你还在保护自己和你的系统免受重大威胁。
想象合规性是将你的安全策略联系在一起的框架。如果没有它,即使是最先进的安全措施也可能在新的漏洞或法规要求面前崩溃。这就是为什么将合规性作为一个持续的过程而非每年一次的审计至关重要。
合规框架
有许多合规框架和蓝图可以供你参考。值得注意的是,一旦你遵循了某个合规框架,这就像是一种荣誉徽章,一种信任印章,客户和供应商都可以看到并知道你遵循了某些标准。目前一些流行的框架包括:
-
ISO/IEC 27001:2022 - 信息安全、网络安全与隐私保护:主要关注信息安全管理系统(ISMS),它为持续保护敏感信息和实施及维护数据保护完整性提供了蓝图。ISO27001 要求定期审计以确保标准得到维护,并且是全球公认的标准。
-
PCI-DSS - 支付卡行业数据安全标准:PCI-DSS 专注于确保处理、存储或传输支付卡数据的任何组织都能够保护支付卡数据。该标准规定了严格的要求,从加密到访问控制,确保持卡人信息免受泄露。合规性不是可选的——如果你处理支付卡,遵守 PCI-DSS 是合法、安全运营的必要条件。
-
SOC-2 - 系统与组织控制 2:SOC 2 的核心在于确保你的组织在安全性、可用性和隐私控制方面达标,特别是当你是技术或云服务提供商时。它分为两种类型:
-
Type I 检查你在特定时间点的控制,而
-
Type II 查看它们随时间的表现如何。
这个标准对于证明你能够安全、可靠地处理客户数据至关重要。
-
每一个这些标准都要求每年进行审计以证明合规性。
全球范围内还有许多其他框架,但这些可能是我们在实际中看到的最受欢迎的框架。
如本节中已多次提到的,长期保持这些标准非常重要,因此,每个框架都需要进行每年的重新审计和重新合规。
合规性持续成功和通过审计的关键不在于每年审计,这可能需要几个月的准备时间,同时将工程师或运营人员从可计费的岗位中抽出长时间。而是通过将这些框架融入到你的文化中来取得成功。每个人都应将这些框架作为日常工作的一部分,这样通过审计就会变成一种自然反应,而不是需要特别准备的事项。
这就是我们所说的“持续合规性”。
自动化在安全性和合规性中的作用
鉴于威胁演变的速度,手动安全检查显然不够。自动化在确保你的安全态势保持稳固以及持续维护合规性方面起着至关重要的作用。
自动化工具可以帮助你实时监控系统,检测潜在威胁,并确保你的安全控制始终与最新的合规标准保持一致。通过自动化这些过程,你不仅提高了效率,还减少了人为错误的风险。
每个三大云提供商都提供持续合规工具,帮助确保标准的维护:
-
AWS:AWS 安全中心为你提供一个集中平台,让你能够查看 AWS 中的安全状态。它从各种 AWS 服务和第三方工具中汇集数据,持续检查你的环境是否符合最佳实践,并帮助你优先处理需要修复的问题。
-
Azure:Azure 安全中心(现在的 Microsoft Defender for Cloud)为 Azure 提供了类似的功能。它会监控你的资源,提供安全评估、威胁防护,并提供一个仪表盘来跟踪你的合规情况。不过,它不仅限于 Azure——它还涵盖了混合云和多云设置,因此无论数据存储在哪儿,你都能得到保护。
-
GCP:Google Cloud 安全指挥中心 (SCC) 是 GCP 对集中安全管理的解决方案。它为你提供清晰的 Google Cloud 环境视图,跟踪配置错误、漏洞和威胁。SCC 还帮助你保持合规,并与 Google 的安全服务集成,快速发现并应对问题。
也有第三方解决方案可以在你的云环境外部实现这一目标。你通常会为其提供访问权限,通过角色或访问凭证来查看你的云账户,并让它定期扫描。可以考虑将其视为一双新眼睛审视你的架构,提供一些超出本地工具可能提供的能力。这些工具集有各自的费用,因此可能需要在安全性和成本优化之间做权衡。
构建积极主动的安全文化
参考 第五章**,低估文化影响,要真正保护你的组织,安全性和合规性需要融入公司文化。这意味着从开发人员到高层管理人员,每个人都应该理解安全性的重要性,并致力于维护它。
定期的培训课程、安全演习和意识提升项目有助于构建这种文化,确保每个团队成员都知道自己在维护组织安全中的角色。当安全成为每个人的责任时,你就不太可能被新的威胁措手不及。
顶级建议:
不要自己进行渗透测试——请引入独立评审者。你离自己的设置太近,这意味着容易忽略盲点。外部专家能带来新鲜的视角,发现你没看到的弱点,并为你提供一个真正公正的评估,帮助你满足合规要求。
总结合规性
所以,你已经通过了渗透测试并且发布了你的应用程序。接下来是什么?这才是实际工作的开始。持续的安全评估、定期的合规检查以及对持续改进的承诺,才是长期保持应用程序安全的关键。
记住,安全不仅仅是一个目标,它是一个过程。在这个过程中,没有任何松懈的空间。一旦你放松警惕,就会为潜在威胁敞开大门。但通过将安全性和合规性视为一个持续的过程,你可以保护组织免受未来可能出现的挑战。
Log4Shell 的故事不仅仅是一个警示故事,它更是一个行动的号召。它提醒我们,在安全领域,没有所谓的“足够”。上线前的一次渗透测试可能会给你带来暂时的安全感,但真正保护你的组织的,是持续的工作——持续监控、合规验证和积极的安全文化。
最终,安全不仅仅是保护你的系统;它关乎建立信任、维护声誉,并确保你组织的长期成功。所以,不要停留在上线的那一刻。继续前进,不断改进,并确保你的安全和合规工作始终贯穿于你所做的每一件事中。
积极监控:不要等到外部审计才发现问题
启动一个新的应用程序或系统是一个令人兴奋的里程碑,但也是确保你的安全措施到位的关键时刻。在上线前仅依赖一次漏洞扫描或渗透测试,就像在跨国公路旅行前对你的汽车进行一次检查,然后寄希望于最好的结果。安全不是一次性的事件;它是一个持续的过程,需要保持警惕。通过整合定期的安全评估并利用自动化,组织可以保持持续合规,并在漏洞变成大问题之前解决它们。
持续安全评估的重要性
一次性的安全评估只能给你当前状态的快照,但它们无法预测未来的变化或新兴威胁。为了保持领先,你需要一种专注于持续改进和主动防御的思维方式。请参考以下最佳实践:
漏洞扫描和渗透测试
定期的漏洞扫描和渗透测试对于发现和修复安全弱点至关重要。这些评估能够揭示攻击者可能利用的漏洞,让你在问题变得严重之前采取行动。
持续监控
设置定期扫描和测试的计划,以确保你的安全姿态始终保持最新。这种方法有助于及时发现并解决新漏洞,确保系统的安全。例如,许多组织会定期进行每季度一次的边界扫描,并且每年进行一次更深入的外部渗透测试。通过这种方式,他们可以获得有关网络或应用程序漏洞的见解。
主动防御与持续合规
通过定期评估,你可以预测威胁并增强针对不断变化的攻击向量的防御。保持对潜在攻击的领先地位是维持强大安全姿态的关键。这些评估不一定是精心策划的活动,它们可以是自动化系统,之后向相关方发送警报。
全面覆盖
确保你的漏洞扫描和渗透测试涵盖所有领域,从网络到应用程序再到基础设施。全面了解你的安全态势,确保没有遗漏任何细节。关键点可能包括:
-
外部网络端口扫描:哪些网络端口和协议是暴露的?
-
应用渗透测试:我们能利用任何暴露的漏洞吗?
-
源代码扫描:你可以扫描管道中的源代码或存储库中的源代码。
-
内部配置检查:检查资源是否已正确配置,确保即使意外(或故意)暴露也不会引发任何问题。
别忘了,有些暴露的端口是故意开放的,比如 HTTPS 或 SMTP 端口。因此,确保这些版本是安全的并且是最新的。
自动化安全流程
使持续的合规和安全评估成为可能需要自动化。通过自动化常规的安全检查,组织能够简化工作并确保持续的保护,同时释放资源用于更具战略性的活动。在实施时考虑以下内容:
-
自动化处理重复性任务,让你的团队能够专注于更关键的工作。从定期运行漏洞扫描到部署补丁,自动化流程确保安全措施的一致性和高效性。
-
使用自动化工具执行扫描、分析结果并生成报告。自动化使你能够在不压倒团队的情况下扩展安全工作,确保在大规模环境中也能覆盖到。
-
自动化工具能够比手动过程更快地检测到异常和潜在威胁,从而更迅速地做出响应并最小化潜在的损害。
-
自动化支持敏捷的合规方式,允许更频繁的检查点和基于实时洞察的调整。这种敏捷性确保你的安全措施始终符合最佳实践和规定。
持续合规验证
每年的合规检查已经成为过去式。如今,随着动态威胁环境的发展,持续的合规验证成为了未来的发展方向。这意味着要定期评估和更新安全控制措施,以保持与当前标准的对齐。以敏捷合规为例,敏捷合规意味着将合规检查整合到常规的开发和运营过程中,确保合规性始终关注,而不是在最后时刻匆忙完成。
-
在一年内建立多个合规检查点,持续验证你的安全措施,确保它们满足不断变化的要求。
-
利用持续评估的洞察力实时调整你的安全态势,使你的组织保持弹性,随时准备应对未来的挑战。
-
鼓励安全、合规和开发团队之间的合作,确保安全和合规性贯穿于开发生命周期的每一个阶段。
外部审计的作用
虽然内部评估和自动化在维持安全中起着重要作用,但外部审计提供了新的视角和额外的保证。这些由独立第三方进行的审计,可以识别盲点,并提供内部团队可能忽视的见解。
-
外部审计提供了对您安全状况的客观评估,突出了那些日常操作中可能被忽视的改进领域。
-
审计员根据行业标准和监管要求评估您的安全实践,确保您的组织符合或超越合规基准。
-
成功完成外部审计可以通过展示您维护强大安全姿态的承诺,增强客户、合作伙伴和利益相关者的信任。
-
外部审计员可以提供切实可行的建议,帮助改进您的安全策略并弥补已识别的漏洞。
构建主动安全文化
为了支持持续的合规和安全评估,培养主动的安全文化至关重要。这意味着将安全视为运营的一个不可或缺的部分,得到领导层的支持,并被每个人所接受。通过以下方式教育您的团队:
-
定期教育员工有关安全和合规的重要性,使他们能够识别和应对潜在的威胁。
-
赢得领导层的支持,优先考虑安全举措并分配必要的资源。领导支持推动文化变革,并使安全始终保持首要地位。
-
从安全事件和评估中汲取经验教训。利用这些反馈来完善安全政策和实践,推动持续改进。
总结来说,安全和合规不仅仅是在上线前要勾选的任务——它们是持续的承诺,需要不断关注和调整。通过拥抱持续的安全评估、利用自动化和采纳灵活的合规做法,您可以维持强大的安全姿态,领先于潜在的威胁。这种主动的做法不仅保护了您的资产,还建立了与利益相关者的信任,确保了在不断变化的数字环境中的长期成功。通过将安全融入您组织的结构,并利用外部审计提供额外的见解,您可以自信地应对当今复杂的威胁环境。
误解共享责任模型
在云计算的世界里,共享责任模型是一个基础概念,决定了云服务提供商和其客户之间如何分担安全和合规责任。尽管其重要性不言而喻,这一模型常常被误解,从而导致安全漏洞和增加风险。本章探讨了关于共享责任模型的常见误解,并提供了如何有效驾驭和利用这一模型的指导,以增强您组织的安全姿态。
最终,我们探索“云的安全”与“云中的安全”之间的区别
理解并解决共享责任模型中的误解
共享责任模型是一个框架,定义了云服务提供商与其客户在安全性和合规性方面的劳动分工。云服务提供商负责保护运行所有服务的基础设施,而客户则负责保护他们的数据、应用程序和配置。
云服务提供商的责任
云服务提供商,如 AWS、Azure 和 Google Cloud,负责云的安全性。这包括数据中心的物理安全、底层硬件、网络基础设施和基础服务的安全。
云服务提供商确保物理基础设施和网络组件的安全,防止未经授权的访问和篡改。他们还维护与各种行业标准和认证的合规性,为客户提供一个安全的平台来构建。
客户的责任
客户负责云中的安全。这意味着他们必须确保云环境中的应用程序、数据和配置的安全。
客户必须通过加密、访问控制和定期备份来保护他们的数据,同时确保运行在云中的应用程序免受漏洞和潜在攻击的威胁,这也是客户的责任。客户还必须实施强有力的身份和访问策略来控制对云资源和数据的访问。
三大云服务提供商的共享责任模型
尽管共享责任模型是所有云服务提供商的常见框架,但三大云厂商(AWS、Azure 和 GCP)在实施时存在细微差异,客户需要了解这些差异。
AWS(亚马逊云服务)
AWS 通过使用两个不同的术语或短语来阐述其共享责任模型:“云的安全”与“云中的安全”
-
在前者的“云的安全”中,AWS 负责保护运行 AWS 云中所有服务的基础设施。这包括硬件、软件、网络和设施。
-
在后者的“云中的安全”中,客户负责确保其在 AWS 上运行的数据、操作系统和应用程序的安全。这也包括配置和访问控制。
下图详细说明了 AWS 共享责任模型的划分区域。

图 6.1 – AWS 共享责任模型(来源:aws.amazon.com/compliance/shared-responsibility-model/)
微软 Azure
Azure 遵循类似的共享责任模型,其中微软负责底层云基础设施的安全性,包括数据中心、物理主机和网络。客户则负责确保他们的工作负载、应用程序、数据和配置在 Azure 环境中的安全。Azure 还强调使用内置安全工具来有效地管理和监控客户的责任。
这张图展示了责任的划分:

图 6.2 – Azure 共享责任模型(来源:learn.microsoft.com/en-us/azure/security/fundamentals/shared-responsibility)
微软的期望是你是数据的所有者,因此你要对其负责。你还需要对帐户和身份以及你可能配置和使用的任何设备或用户端点保持所有权和责任。
GCP(谷歌云平台)
谷歌还遵循与其他提供商非常相似的模型,谷歌负责全球基础设施、网络和基础服务的所有权,因此也承担相应责任。同样,客户需管理他们的数据、应用程序和访问控制。
与其他服务提供商不同,值得注意的是,谷歌采用了一种稍作增强的共享责任模型,称为“共享责任与共享命运”。这将地理位置和行业也纳入了考虑范围。
地理位置意识从根据你部署工作负载和客户数据存储位置来审视你的责任开始。例如,如果你在欧盟部署,你可能需要遵守 GDPR(通用数据保护条例)的要求,并确保你的数据不会离开欧盟。
各个行业可能有不同的监管合规框架,这些框架可能规定了你如何处理数据。例如,支付卡行业数据安全标准规定了支付处理方如何保护其数据,并对某些数据类型进行隔离。
在这两种情况下,谷歌有一个独立的责任矩阵,以确保服务和架构在设计时就是安全的。

图 6.3 – GCP 共享责任共享命运(来源:cloud.google.com/architecture/framework/security/shared-responsibility-shared-fate)
常见误解
尽管共享责任模型十分明确,但仍然存在一些误解,这可能导致安全上的疏忽和漏洞。
误解 1:服务提供商处理一切
有一个常见的误解是认为云服务提供商处理安全的所有方面。虽然提供商确保基础设施的安全性,但他们不管理客户特定的配置或数据安全。
现实检验
客户必须在云环境中积极参与保护其应用程序和数据的安全。忽视这一责任可能导致数据泄露和符合性失败。
误解 2:内置安全工具
一些组织认为使用云提供商自动包含全面的安全工具。虽然提供商提供各种安全服务,但客户需要有效配置和使用这些工具。
现实检验
客户必须选择、配置和管理适当的安全工具,以满足其特定的需求和合规性要求。
误解 3:合规性是有保证的
另一个误解是通过使用符合标准的云提供商可以保证符合行业标准。然而,符合性是共同的责任,客户必须确保他们特定的配置和数据处理实践符合法规要求。
现实检验
客户应定期进行合规性评估和审计,确保他们在云中的操作符合所有相关标准。
云提供商的合规性证明
关于后一种误解,值得注意的是,每个云服务提供商将为您提供他们在共同责任模型的一部分中的合规性声明。例如,云服务可能会变得符合 FedRAMP 或 HIPAA 标准。但我们如何证明这一点呢?
-
AWS: AWS Artifact 是您在使用 AWS 时抓取所有符合性文档所需的快速访问门户。无论是 SOC 报告、ISO 认证还是 PCI-DSS 承诺,Artifact 都能一网打尽,节省您在需要证明环境符合行业标准时的烦恼。
-
Azure: Azure 合规管理器不仅为您提供必要的合规报告访问权限,还通过清晰的仪表板和内置的工作流程帮助您管理合规姿态。一切都是为了简化合规性,为您提供洞察和工具,以应对法规要求,而不至于陷入困境。
-
GCP: Google Cloud 合规报告管理器简化了一切,为您提供了一个集中的位置来下载与您的 Google Cloud 服务相关的合规文档。从 SOC 报告到 ISO 认证,应有尽有,让您在展示合规凭据时从未感到手忙脚乱。
常见的配置错误
为了更具体地说明这些常见误解,由于误解或忽视共享责任模型而在实际中见到的最常见的配置错误列在此处:
-
不当的访问控制导致未经授权的访问敏感数据和系统,进一步导致数据泄露、账户被攻破以及内部威胁。
-
未对云中存储的敏感数据或系统之间传输的数据进行加密,导致数据暴露,特别是在发生数据泄露或传输过程中被截获的情况下,可能导致机密性丧失和不合规。
-
未及时修补操作系统或更新应用程序和软件,导致容易受到已知漏洞和攻击的威胁,从而可能导致系统被攻破、数据泄露以及遭受恶意行为者的利用。
-
使用过于宽泛或宽松的安全组设置或防火墙规则,允许不受限制的进出流量。这可能会增加未经授权的网络访问风险,使系统暴露于潜在攻击,如分布式拒绝服务攻击(DDoS)、端口扫描或未经授权的数据外泄。
-
错误配置云存储服务,如 Amazon S3、Azure Blob Storage 或 Google Cloud Storage,允许访问敏感数据,导致意外的数据暴露,从而引发重大声誉损害。
这并不是一个详尽的列表,然而,数据、声誉的损失以及由此导致的声誉严重损害最终会导致商业失败。
总之,理解共享责任模型对于有效保护云环境至关重要。通过认识到云服务提供商和客户的不同角色,组织可以确保其安全措施全面且强大。教育团队、实施强有力的安全控制措施,并利用服务提供商的工具是成功应对这一模型的关键步骤。通过承担起自己的责任,您可以保护组织的数据和应用,确保合规,并在当今动态的数字环境中建立与利益相关者的信任。
供应链不安全
安全中被忽视的一个关键领域是供应链。把您的业务看作是一系列互联的部分,而您是其中的中间环节。您有供应商、供应商和合作伙伴,他们彼此就像自行车链条一样相连。突然间,这些环节中的一个被破坏,您的链条就有了薄弱点。你们都可能处于风险之中。
在云环境中,您的数据和系统通常与第三方的系统交织在一起。如果您的合作伙伴没有采取强有力的安全措施,这种相互依赖性可能会使您的组织暴露于漏洞之中。供应链中的一处漏洞可能会引发连锁反应,导致数据泄露、服务中断以及声誉损害。
然而,我们不能在没有供应商与客户之间关系链的情况下开展日常业务。这些关系对我们开展业务至关重要。因此,我们必须考虑如何安全、可靠地交换信息和数据。
供应链安全的挑战
供应链安全中的常见挑战可能来自于:
-
缺乏可见性:通常,各种规模的组织对其供应商的安全实践了解有限。这种缺乏可见性使得有效评估和管理风险变得具有挑战性。
-
安全标准差异:不同的供应商可能具有不同的安全成熟度,从零信任到没有强制标准和临时控制措施。虽然一些供应商可能具有严格的安全措施,但其他供应商可能无法达到相同的标准,从而在你的安全态势中留下漏洞。
-
复杂的关系:管理与多个供应商的关系可能很复杂。确保所有合作伙伴之间的安全实践一致需要付出努力和协调。
-
第三方访问:供应商通常需要访问你的系统和数据以提供服务。如果没有适当的访问控制,这可能导致权限过度,从而增加未经授权操作的风险。
避免供应链风险
为了尽量降低不安全供应链的风险,可以尝试采纳以下最佳实践:
-
基于供应商的风险管理:在接纳新供应商之前,让他们完成安全审计或风险评估。检查他们是否遵循安全最佳实践。在此阶段,建立你对风险容忍度的基础非常关键,也许根据他们可能需要访问你环境的级别来对不同的风险进行分类。同样,在这些审计中,遵守如 GDPR、CCPA 和 HIPAA 等法规要求也非常重要。你还可以考虑将地理位置作为优先级评估的一个因素。
-
风险的定期审查:完成风险评估不应是一次性的活动。供应商通常不在你的监管范围内,情况可能迅速变化。如果我们的供应商更换了新的 CTO 或 CEO,并宣布采取成本削减措施或提高效率,他们可能会认为某些安全标准或做法需要改变,甚至被移除,如果他们认为这会带来过多的开销。这可能会改变你供应商的风险状况,但你可能对此并不知情。
在这里,定期审查风险或每年的安全评估可能有助于识别任何变化的风险。
-
需求的定期审查:就像供应商的情况可能发生变化一样,你自己组织内部的情况也会发生变化。你可能会淘汰某些系统、添加新系统或更改数据位置。在这种情况下,你与供应商关系的访问要求也会发生变化。新增服务的访问权限很容易被授予,但我们常常忘记撤销旧的访问权限。这个审查应该尽可能识别过多的权限。
-
供应链中的事件响应:当你的供应链中的某个环节发生安全事件时会发生什么?我听到你问:“这是个好问题。”因为在这种关系中可能存在紧密的相互依赖关系和共享的风险,你将需要制定一个事件响应计划。这个计划需要简洁的行动和清晰的沟通。谁向谁报告什么?为什么?哪个团队的哪些成员需要执行什么?在这个时候,诚实是最好的政策,正如人们所说。确保政策排除任何责备的成分,以确保事件响应计划能够迅速有效地执行。
值得注意的是,每个云服务商也提供了一系列剧本/运行手册,以便在发生安全漏洞时提供帮助。
| AWS | AWS 事件响应剧本示例 | github.com/aws-samples/aws-incident-response-playbooks |
|---|---|---|
| Azure | 事件响应剧本 | learn.microsoft.com/en-us/security/operations/incident-response-playbooks |
| GCP | 数据事件响应流程 | cloud.google.com/docs/security/incident-response |
表 6.1 - 云服务商事件响应剧本
这些剧本在大多数情况下是为了增强你自己的流程,而不是作为唯一的资源来依赖。
供应链安全隐患示例
很多时候,直到为时已晚,你才会意识到自己有供应链安全问题。这些现实世界中的供应链安全隐患示例可以帮助你通过他人的错误汲取教训:
示例 1
一个常见的例子是向供应商、供应商或客户提供第三方 API 密钥或访问密钥。这些密钥往往没有更新,因为第三方那边的系统复杂性和/或缺乏政策。第三方也可能没有以安全的方式存储凭证,导致密钥暴露。这意味着,由于他们缺乏强有力的安全措施,你的系统可能会受到攻击。
示例 2
2016 年,一个名为 left-pad 的小 npm 包在整个 JavaScript 世界引起了巨大的混乱。Left-pad 的功能很简单——在字符串的左侧添加填充——但它是数千个项目的依赖项,其中包括 React 等主要项目。突然,开发者因与其他事务的纠纷而决定从 npm 中移除 left-pad。瞬间,全球的项目都崩溃了,开发者们忙着修复这个突如其来的问题。
这个事件是一个关于供应链不安全的严峻教训。它展示了当我们依赖外部依赖而没有采取保障措施时,软件生态系统是多么脆弱。如果像 left-pad 这么小的东西都能导致这么多项目崩溃,显然我们需要更加警惕。这意味着验证包的完整性、制定备份计划,并认真思考我们在项目中包含的每个依赖项。即便是最小的组件,在失去时也可能带来巨大的麻烦。
总结
在当今的数字环境中,供应链安全不仅是一个“可有可无”的选项,它是一个必需品。通过主动管理供应链的安全性,您可以保护您的组织免受与第三方关系相关的风险,并保持客户和利益相关者的信任。
通过这些,您已经掌握了如何通过实践最小权限原则来加固云环境。这为您提供了减少过度授权用户相关风险的工具,并确保您对谁能访问关键资源有更严格的控制。
在本章中,我们回顾并理解了以下内容:
-
最小权限原则的应用
-
安全中的持续合规性
-
安全的积极监控
-
共享责任模型
-
供应链安全的重要性
在下一章,我们将继续讨论构成您应用程序的业务逻辑以及一些常见的软件开发反模式。
第三部分:将其转化为行动
最后一部分将接着前一部分,描述常见的反模式、如何避免它们以及如何过渡到良好的习惯。我们将探讨的领域包括应用程序、数据、网络、可观察性、操作、迁移和测试。本部分将总结如何为成功的云采纳之旅做好准备,如何识别反模式,以及如何定义最佳结果。最后,我们将讨论如何实现良好的利益相关者对齐、增强我们的路线图,并为组织建立持续改进的基础。
本部分包含以下章节:
-
第七章**,在应用代码中表达您的业务目标
-
第八章**,不要迷失在数据丛林中
-
第九章**,将一切联系起来
-
第十章**,观察我们的架构
-
第十一章**,如何运行而不破坏它
-
第十二章**,从遗留系统迁移到云原生解决方案
-
第十三章**,你怎么知道一切都能正常工作?
-
第十四章**,如何开始您的云原生改进之旅
-
第十五章**,过渡到云原生的好习惯
第七章:将业务目标表达为应用代码
使我们公司技术独特并提供竞争优势的业务逻辑通常是我们采用的业务逻辑。将我们的业务规则表现为应用代码可以推动自动化、减少周期时间并提高生产效率。然而,当我们将这些逻辑迁移到云端时,我们可能会被一些反模式所困扰,这些反模式在我们过去的单体化本地架构中通常能被忽略。
在本章中,我们将涵盖以下主要主题:
-
搬迁转移
-
有状态应用程序
-
紧密耦合,低内聚性
-
完整的“完成”定义
-
其他陷阱
搬迁转移
当我们将应用程序迁移到云端时,我们需要转变思维方式,从将应用程序作为独立单元部署转变为将应用程序视为各种服务交互的涌现行为。在本节中,我们将探讨将应用程序迁移到云端的典型过程、我们可以使用的策略,以及如何提高我们云原生解决方案的成熟度。
在云中构建与为云构建
当我们将应用程序迁移到云端时,最简单的方法是将现有的部署打包成一个虚拟机(VM),然后将其部署到云端,并称之为云原生。这种思维方式将云的实际使用局限于简单地反映我们在本地环境中已有的拓扑结构。但我们实现了什么呢?我们仍然面临着刚刚迁移过来的系统的相同限制,但却没有享受到云的任何优势。我们只不过是把代码从我们的服务器转移到别人的服务器。我们可能在可维护性、组织复杂性和入职时间上获得了一些效率。然而,这种做法并非云大规模服务商所特有的,我们也可以通过大多数其他虚拟机托管平台实现相同的结果。这个搬迁转移思维方式使我们进入了云,但未能充分利用云的潜力。这种思维方式的区别在于:在云中构建与为云构建。一旦通过这种搬迁转移方法将应用程序迁移到云端,我们不仅可以对应用程序本身进行改进和优化,还可以优化其周围的基础设施和架构。
我曾经在一家公司工作,该公司有一个现有的本地解决方案。这个本地解决方案通过远程部署分发给客户。客户提供一台机器,特定的入驻团队登录到该机器上,并运行一个脚本来设置应用程序。这样的迁移思维一直延续到了他们提供的云原生托管产品中。入驻团队在云中配置了一个新的实例和数据库,然后有人安装了应用程序,客户访问云实例。这一过程是该公司在云中提供服务的首次尝试。然而,手动流程一直存在,且难以改变。这些流程是经典的“在云中构建”与“为云构建”之间的区别。放弃对这些业务流程的控制,交给自动化,可能是一个挑战。然而,除非我们利用云所提供的优势,否则就无法真正认识到这一转变的实际效率。一个能够更快速地推进周期并降低新客户进入门槛的好方法是转向自助、按需入驻,采用云工厂方法,正如我们在本章稍后的部分会详细介绍的那样。在他们未来构建的云原生应用中,也采纳了类似的技术,且这些应用是从零开始构建的。然而,这也引出了一个新的反模式,即持有“这次我们要把它做对”的心态。
“这次我们要把它做对”的迷思
我们经常看到的一个反模式是软件团队希望摧毁一切并从头开始,以便变得云原生。这种非黑即白的方法不仅将你的业务分割成遗留系统(你的原始应用)和全新领域(你全新的应用)开发,还意味着你忽视了客户正在使用的产品,而投入到一个可能在至少达到与本地解决方案相当的功能前,不会有用户的产品上。这些项目的时间表通常被严重低估,并且需要重新培训和重新配备资源,以获得你所需的云原生技能。这种非黑即白的方法通常意味着在你组织最缺乏云经验的时刻,围绕你的应用程序及其架构的关键决策会在前期做出!
在转向云时,AWS 提供了 7 种迁移策略,如我们在第二章中讨论的那样。为了帮助你回忆,这些策略包括:重构、重新平台、重新购买、重新托管、重新迁移、保留和退休。
你会注意到,重建并不是其中的一个选项。为了在现有应用中充分利用云原生服务,我们必须选择一个最终将我们引导到重构路径的选项。开始的最简单方法是为我们的现有应用构建一个云工厂。
云工厂
云迁移的搬迁和移位是不可避免的。在云中运行现有应用是将其迁移到云原生的第一步。在部署本地应用程序时,由于涉及客户提供的硬件,客户控制的访问以及手动步骤的部署,这会有显著的前置时间。正如我们之前的例子中所讨论的,这个领域中的一个常见反模式反映了云环境中的这一过程。客户在本地环境中使用不同的防火墙、虚拟化程序、硬件和安全。部署过程通常需要手动干预,以处理特定客户的独特性。
在云环境中部署时,我们可以自行指定这些选项。我们可以决定我们的虚拟机的大小、如何配置防火墙和网络,或者使用哪种操作系统。与多个独特的客户环境不同,我们多次部署相同的云环境,这意味着所有的怪癖对每个实施案例都是相同的。现在我们可以确信地自动化提供工作流程,从可能需要多个客户联系几周的过程,减少到可以在管道中运行并可能需要 30 分钟的过程。为您的应用程序创建一个云工厂是将本地应用程序迁移到云端的关键第一步,而无需重新设计为多租户模型。我们将在第十二章中深入探讨这一点。当我们开始将应用程序转移到云上时,一个问题仍然存在:我们如何在保留最终功能的同时重构它?答案是通过使用攀缘榕模式。
通过吸收枯死树上的养分,攀援榕树的云原生
攀缘榕是一种生长在宿主树上的植物。有时,宿主树会死去,只留下攀缘榕。由马丁·福勒提出的攀缘榕模式类似。它让我们逐步将现有的应用程序变成云原生,最终完全替代我们的传统解决方案。通过这种行动机制,我们还允许将系统范围的架构决策推迟到后续阶段,一旦我们组织的云成熟度得到改善。云迁移的第一阶段是将现有应用程序带入云端 - 也就是说,重新托管。您也可以在没有重新托管阶段的情况下技术上采取这种方法,而是将流量重定向到我们的本地实例,尽管这需要额外的网络设置和可靠的授权策略。这种简单的过渡在图 7**.1中有所体现。我们从一个本地实例开始,然后用云实例替换它。这个切换对最终用户是透明的。

图 7.1 – 从本地到云的初始应用迁移
通过完成这个阶段,我们已经实现了一些效率;通过消除对物理硬件的依赖并利用云工厂,部署速度变得更快,合租成本消失了,我们也减少了分散系统的操作负担。然而,我们并非云原生;操作系统补丁和数据库维护等负担仍然存在,我们仍在以一种将基础设施拓扑与客户群体匹配的方式进行操作。
我们迁移的下一个阶段是一个简单但关键的阶段,支持我们应用程序的未来版本。我们需要添加一个API 代理层。所有的大型云服务商都有提供这种功能的托管服务;在 AWS 中,它是API Gateway,Azure 有API Management,而 GCP 有Apigee和API Gateway。一些开源项目也为特定环境提供类似的功能,例如Kubernetes。这里的关键是,我们在终端用户和我们的应用程序之间引入了一个层,它可以执行 OSI 模型中定义的第七层路由。该模型将允许我们检查传入的流量,并根据 HTTP 请求属性决定操作。与图 7.1中的架构相比,我们现在增加了一个架构元素,即 API 代理,它对终端用户仍然是透明的。

图 7.2 – 向云实例添加 API 代理
从功能上讲,我们还没有充分利用 API 层的能力,但我们已经通过这次变更实现了一些操作效率。如果我们使用传输层安全性(TLS),我们可能会有一个预配的 TLS 证书。切换到完全托管的代理允许 TLS 终止在代理层进行,从而使我们摆脱了通过手动或半自动化过程管理 TLS 的操作负担。关键在于我们的应用程序不再与已部署的实例绑定。通常,我们使用单体架构构建本地应用程序,因为这些应用程序的部署与我们部署它们的硬件拓扑密切耦合。在云环境中,这些限制不再约束我们。这对开发团队在这种环境中的操作能力是有害的。使用单体架构通常会导致组件之间的高内聚,使得在不了解其在整个应用中的使用范围的情况下,很难预测某个变更的影响范围。
解决方案是使用 API 代理的第七层路由功能,将我们的应用解构为新的云原生实现。例如,许多应用都拥有一个用户管理系统,供用户登录应用。传统上,有人可能通过将密码存储在数据库中来实现这一点,理想情况下是经过哈希处理和加盐的。这种方法对大多数公司来说是一个明确的风险来源。不安全的哈希算法、时序泄漏和密码数据库安全,在这种模型下,都是贵公司直接负责的事项。通过将其迁移到托管服务,我们显著降低了运营风险。我们还可以在此阶段进行更改,通过将一些较为简单的迁移(例如数据库)重新平台化到兼容的托管数据库服务中,从而使我们的解决方案更加云原生。继续我们的架构演进,我们将单体应用拆解为下图所示的组件:

图 7.3 – 开始将单体应用解构为领域驱动的微服务
在这个新架构下,我们将用户管理和我们重新平台化的应用单体进行了分离。我们的用户服务通过 API 代理提供一个抽象层,用于执行如重置密码、更新电子邮件地址以及其他以用户为中心的功能。同时,我们原本的单体应用仍然包含所有用户外部的功能。我们已经成功地将应用的一个部分重构为真正的云原生,并使用了托管服务。最重要的是,我们不需要了解整个应用的架构设计就能实现这一点。我们只需要理解这个特定领域以及可用的服务来加速它的实现。我们还打破了用户服务和应用中不相关部分之间可能存在的耦合。在这种新模型下,对用户服务的变更只会影响服务本身,而不会对应用的其余部分产生意外副作用。
在一些简单的情况下,我们可能只有两个 API 代理目标:新的云原生服务和旧的遗留服务。然而,在执行这种替代或迁移功能的方法时,同样值得重新评估您的架构,看看您是否可以减少应用内的耦合,或通过拆分不同的服务来增加特定领域的内聚性。很少情况下,要求进行重构以成为云原生的完美解决方案是构建一个云原生的单体应用。
渐进地,我们可以继续将服务分解为其新兴领域。我们在应用程序内建立了有界上下文,代表了我们业务上高度内聚的部分。关于有界上下文和领域驱动设计的更多信息,我推荐阅读《领域驱动设计》,作者是埃里克·埃文斯。然后我们将我们的架构分解为这些领域,并尽可能利用云原生服务。作为这一转变的一部分,如果我们的应用程序支持多个客户,我们还可以将多租户性能构建到这些服务中。最终,我们将达到一个整合了整个应用程序的一系列云原生服务的阶段,这些服务由提供等效或改进功能的托管服务支持。作为我们架构演变的最后一步,我们已经移除了单体,并且只留下了新的应用程序服务。这在图 7**.4中有所体现。

图 7.4 – 原始的单体应用程序已被弃用,真正实现了云原生
通过使用 API 代理来缓慢而系统地分解单体,我们有效地实现了期望的结果:移除遗留的单体并采用云原生服务。在这一点上,可以移除 API 代理;然而,在大多数情况下,应用程序代理仍然通过作为应用程序的中心入口点提供好处。
我们已经审查了初始云迁移中的典型反模式,包括一次性迁移或退役重建等低效迁移策略。我们还探讨了榕树模式如何允许我们在现代化应用程序的同时继续为当前客户提供服务。现在,我们有了一条通往云原生的路径,不需要一次性广泛的解决方案,而是可以作为长期数字转型的一部分,重点放在客户结果上,而不是技术上的纯主义。
现在我们已经深入研究了现有应用程序的迁移,我们可以开始看看应用程序本身如何构建成为云原生。这个旅程的第一站是解决我们应用程序状态存储的位置。
有状态应用程序
大多数应用程序的核心是一系列有状态进程。这些状态可能是短暂的 – 也就是说,它们可能不是具有长期上下文的数据,例如用户会话仅在用户访问网站时处于活动状态。在其他情况下,我们可能会将这些状态持久化以供长期存储。例如,网上商店可能需要维护购物车状态,收集付款并发货商品的状态。这些都是需要在我们的架构中某处持久化的状态。在单服务器模型中,混合系统的本地和外部状态是微不足道的。在本节中,我们将研究这些模式的可伸缩性和健壮性,以查看如何以云原生方式管理状态。
无状态服务器
构建云原生应用程序时,一个常见的反模式是将状态存储在服务器本地。大多数云服务提供选项,如会话亲和性,使您可以将应用程序迁移到云中,并在本地存储状态。然而,我们应该避免在新的或重构的云原生应用程序中使用这些模式。两种主要模式可以帮助我们在云中实现这一目标。
在状态声明模式中,客户端向后端服务器呈现可验证的状态表示。我们通常使用这种模式来处理短暂状态,其典型示例是替换用户会话令牌,我们可以将其与存储在机器上的短暂状态匹配,并使用用户会话声明,如JSON Web Token(JWT)或安全声明标记语言(SAML)响应。在这两种情况下,客户端存储他们的状态,并且我们可以通过加密安全的签名来验证客户端的状态未被篡改。此模式有一些注意事项,例如,除非加密,否则这些令牌对最终用户是透明的,因此我们绝不应在声明中包含我们不希望用户看到的秘密信息。它们也是令牌窃取的主要目标,因此在使用此模式时,令牌生命周期、TLS 和令牌存储在客户端设备上的良好实践至关重要。
第二种模式是使用外部状态存储。如果我们处理的数据不是短暂的,并且需要由多个方使用,那么我们必须将状态持久化到服务器外部的存储中。存储的数据类型决定了我们如何在后端存储它。关键在于将状态移出我们的应用程序,这在云计算世界中提供了诸多好处。
我们通常会遇到三种类型的状态数据。当然,总会有例外和边界情况,但作为一般规则,我们可以选择适合我们用例的外部状态存储。
瞬态状态数据是指在某一时刻表示系统子状态的数据,但如果数据被删除,它不会带来不良后果。这可能是因为数据本身是其他数据源的缓存,可以重新构建,或者因为数据本身的性质是短暂的,例如短生命周期会话令牌。通常,我们存储这些数据是因为我们需要它在短时间内可用。可以把它想象成你的短期记忆,它存储着你当前正在积极使用的值,但随时可能被替换。云服务提供了专门针对高性能工作负载的解决方案,可以用于更具成本效益的方案。对于高性能工作负载,我们可以使用 AWS 的 ElastiCache、GCP 的 Memorystore 或 Azure 的 Azure Cache 等服务;这些服务都体现了传统部署缓存服务的概念。该领域的其他新兴解决方案,如 Momento,提供了缓存即服务。如果延迟不是关键因素,其他专有解决方案可能在成本效益和可扩展性方面更具优势,仅对延迟造成最小影响,例如 DynamoDB(AWS 的 NoSQL 服务)表中的 TTL,甚至像 Momento 这样的完全 SaaS 解决方案。与自管理范式的关键区别在于,这些服务是受管的,并且都提供自动可扩展的选项,使我们可以专注于应用程序中带来价值的部分,即我们的领域逻辑。
持久状态数据是指系统需要在语义模型的上下文中持久化引用的数据。这些数据可能是我们希望记录的订单,或者是我们希望保持余额的银行账户。我们存储这些数据的方式可能有不同的模式,比如关系型与非关系型、规范化与反规范化,或者结构化与非结构化。通常,这些状态的表示可以看作是类似于我们长期记忆的记录。在写作本文时,这是一个令人兴奋的领域,因为关系数据库的无服务器服务,如 AWS 的 Aurora Serverless 或 GCP 的 Cloud Spanner,正在取得巨大进展。对于非关系型数据库,大多数云提供商都拥有真正的无服务器服务(在它们能够扩展到零的方式上)。AWS 提供了 DynamoDB,Azure 提供了 Cosmos DB,而 GCP 提供了 Cloud Firestore。
支持数据通常是指没有持久化数据上下文的情况下几乎没有意义的数据。这些可能是像照片、PDF 文档或其他类型的文件,我们希望存储它们,因为它们提供了附加的信息。持久化数据和支持数据的区别在于,支持数据可以被视为对象,而不是记录。这一区别也反映在服务命名的方式上,通常称为 Blob 或应用程序存储。AWS 有S3,GCP 有Cloud Storage,Azure 有Azure Blob Storage。再一次,这些都是托管服务,它们的吞吐量和容量会随着我们的需求进行扩展。
问题是,我们什么时候需要将状态提交到外部服务?一般的经验法则是,任何需要在一次事务之外持久化的状态都应该提交到外部状态管理系统。局部状态在事务处理过程中是可以接受的,但对于任何突破这一边界的情况,外部状态是必需的。我们可以举一个大家可能都曾遇到过的例子,那就是多页网页表单,每次提交一个错误的值时,它会忘记之前的页面并把你带回第一页。这就是我们在使用跨越转换边界的本地状态时所面临的风险。
这些数据类型在处理在线事务处理(OLTP)工作负载时最为常见。在处理分析型(OLAP)工作负载时,存储和消费模式有所不同。当需要分析功能时,通常建议将数据持久化到一个专为你的使用场景构建的分析存储中,例如数据仓库。每个超大规模云服务商在这一领域有稍微不同的方法:GCP 有完全托管的无服务器解决方案BigQuery,AWS 有Redshift,Azure 有Azure Synapse。在这些超大规模云服务商之外,也有一些重要的竞争者,如Snowflake和Databricks。
现在我们已经讨论了如何从本地服务器中移除状态,接下来让我们探索在云原生环境中,这种变化为我们带来的弹性和可扩展性的全新可能性。
无状态服务器范式中的弹性和可扩展性
AWS 的首席技术官沃纳·福格尔斯曾提到过“一切都会失败,永远都会失败。”如果我们将状态保存在本地服务器上,那么该状态的持久性就与单一服务器的可靠性一样。像超大规模公司这样的企业,雇佣了大量工程师来确保他们的应用程序具备持久性、可用性,并且没有漏洞。而大多数进行云原生转型的人无法获得这些大公司所拥有的资源。这就是无状态云范式发挥作用的地方,它使我们能够通过使用托管服务来存储状态,从而在边际上进行交易。这些托管服务背后有大量工程师。如果我们将状态持久化到应用程序外部,突然之间,应用程序的容错能力变得不那么重要了。
服务器崩溃了?启动另一个服务器并调查原因。我们的状态不在服务器上,所以服务器是否宕机不再重要。我们的新服务器会从上一个服务器停止的地方继续运行。更好的是,在自我修复组中运行多个无状态实例的服务器。云服务还允许我们自动化这部分系统。AWS 使用自动扩展组和弹性负载均衡。GCP 为虚拟机提供了托管实例组,或者为容器提供了Cloud Run/Google Kubernetes Engine,以及负载均衡器来分配流量。Azure 使用虚拟机规模集和Azure 应用服务来实现类似效果。所有这些服务都使我们能够减轻单点故障的风险,尤其是在我们负责的云端部分,这些部分通常包含最多的漏洞。需要注意的是,管理状态甚至不需要是我们自己代码中的一个过程;我们可以更进一步,使用完全托管的状态作为服务。
状态即服务
通常,我们构建状态机来复制业务流程。例如,我们可能会在分布式微服务架构系统中为新租户进行注册。过去,我曾见过一些人以复杂且通常脆弱的方式编写代码,且文档不足。例如,一个名为中央租户服务的服务调用每个微服务进行编排,但这个租户服务会被每个需要执行入驻操作的团队触及。结果是无穷无尽的状态和容易出错的入驻流程,导致出现大量边缘案例,没有人能够轻松掌握系统的全部复杂性。
我们希望有一个状态机,告诉我们请求的操作是否已完成。这里,托管服务也可以带来好处。像AWS Step Functions、Google Workflows或Azure Logic Apps这样的解决方案可以将状态的维护外包给云端自身。这是当需要集中式编排时的一个优秀解决方案。在我们之前的示例中,我们希望为一个租户进行入驻,因此我们创建一个状态机,在租户服务中创建一个新租户,在用户服务中为该租户创建一个新的管理员用户,并向该用户发送一封电子邮件,邀请其登录。一旦用户接受邀请,可能会有更多的阶段,例如为租户配置新的数据,提示管理员添加其他用户,或为用户文件设置保留策略。
我们可以通过事件和特定服务的状态以分布式方式进行管理,但通常这会导致没有适当监管的无边界、未记录的行为。将状态机作为服务的方法还可以让我们在一个单一的界面中查看状态机结构,以及各个状态实例如何在其中进展。当租户入驻系统出现故障时,我们可以通过查看定义良好的状态机立即看到错误发生的位置。
我们在这个系统中通常看到的反模式是人们将状态机用于那些不跨越边界上下文的系统(即它们不需要编排)。在这些情况下,我们应该依赖于边界上下文内部的状态表示,例如将订单项从“已订购”更新为“已打包”,然后到“已发货”。在这种情况下,状态转换简单、线性且位于边界上下文内。因此,不需要外部状态编排。状态谜题的最后一部分是配置我们的应用程序。
将应用配置视为状态
从根本上讲,我们的应用行为是应用状态通过业务逻辑过滤后的一个自发属性。这里的反模式是将应用配置定义在我们用来定义业务逻辑的相同代码中。应用配置只是另一种形式的状态,通常在不同的部署环境中有所不同。我们的代码应该对其部署的环境保持中立,相反,配置应通过部署本身进行管理。我们通常会将应用配置存储在两个地方:
-
在外部的键值存储或密钥管理器中。我们在第五章中提到了这种方法,用于特性标志。
-
在用于创建我们应用程序新实例的模板内部,如通过环境变量。这通常用于引导值,比如服务发现端点或数据库连接字符串。
配置域中的本地状态与事务域中的本地状态之间的区别在于,配置域中的状态必须满足两个标准才能生效:
-
它必须是不可变的;配置不能由于外部因素变化,除非是服务的重新部署。
-
它必须是通用的;所有应用的副本必须提供相同的本地状态副本。
这两种范式确保我们的事务与完成请求的实际后端服务无关。在外部情况下,我们有更多的灵活性,但需要小心轮换和缓存失效的影响。
状态允许我们的应用通过业务逻辑的视角提供意义。然而,不当处理的状态可能会导致弹性和可扩展性问题。幸运的是,在云环境中,有许多经过验证的工具可以帮助我们存储应用状态。我们甚至可以将我们的状态机完全迁移到云端,利用云原生服务,同时将运营复杂度降到最低。尽管状态是我们应用的命脉,但我们代码的健康性和可变性通常通过另外两个属性来衡量:耦合性和内聚性。
紧密耦合,低内聚
在软件设计中,两个常用的衡量相互关联性的指标常作为健全系统设计的试金石。这些是耦合和内聚。耦合指的是不同服务之间互相调用以完成任务。高耦合意味着服务之间高度依赖,且在没有担心依赖关系或副作用的情况下,单独操作这些服务会变得很困难。内聚正好相反。耦合衡量服务之间的关系,而内聚关注的是服务内部的关系。如果一个服务的内聚性差,它会试图同时做许多不同的事情。我们常常看到在云原生软件开发中,低内聚和高耦合作为一种反模式。在本节中,我们将探讨这些反模式如何在云环境中体现,并讨论如何避免它们。
Lambdalith 与单一功能函数
在已部署的基础设施中,我们经常看到的一个反模式是低内聚度。通常,这种反模式是通过孤立的基础设施团队引入的;有关为什么这可能是一个糟糕的想法,请参阅第五章。让我们假设我们在 AWS 上有一个无服务器函数,一个Lambda 函数,每次我们想要一个新的函数时,我们都需要基础设施团队的批准来为我们创建一个新的函数,而不是让我们有权自己创建一个新的 Lambda 函数。然后,我们得到了一个本应只需要一天时间来实现的功能,但实际上应该是一个无服务器函数。与其等待基础设施团队处理他们的工单积压,并为我们提供我们的函数,我们看到了一个非常诱人的现有 Lambda 函数,只需添加一些额外的路由,也可以处理这个其他功能。将这种效果复合到许多功能中,突然间,我们得到了一个庞大的单体无服务器函数。因此有了“Lambdalith”这个别名。问题在于这些无服务器函数具有低内聚度。这意味着通过修改我们的函数,由于流程效率低下和独立所有权,我们可能会对完全不相关的功能产生很大的影响。
我之前曾与一个将架构团队与基础设施和开发团队分开的组织合作过。创建一个服务需要三个团队的互动,并且按照每月的节奏进行。这个特定的组织将团队与业务域对齐;每个业务域通常管理几个服务。虽然功能开发非常迅速,但支持这些功能的新服务的添加事件却非常罕见。这些容器在应用程序部分之间的内聚性低下中显著复杂化。康威定律依然活跃,架构紧密地遵循团队拓扑,甚至过度遵循。
在任何过程中,无论是在线销售还是供应新基础设施,这个过程越困难,完成的可能性就越小。通常,人们会问适当的摩擦力是多少,以确保我们仍然能够生成安全的、可部署的工件。几乎总是答案是尽可能少。我们应该通过为他们提供一个安全的平台来使团队能够负责其自己的输出。基础设施和架构资源应该在任何时候都可用以支持它们。然而,如果开发团队无法推动这个过程,你会发现这个过程将会被极大地浪费。
Lambdalith 的真正云原生对立面是单一功能的无服务器函数。在这种模式中,每个函数只做一件事,并且做到最好。例如,特定 API 端点上的 POST 方法。这并不意味着它不能与其他单一功能的函数共享代码。通常,将这些函数分组到具有高内部凝聚力的伪服务中是有意义的。然而,每个部署的函数应该对其伪服务组中的其他函数完全独立。这种分组可能是通过从同一代码库(如果使用单一仓库的话,甚至是同一个父文件夹)部署多个单一功能的函数来实现的。这种模式为我们提供了高凝聚力的部署单元。每个单元只关心满足单一请求类型的需求。我们应当注意,不要将这些单元拆解得过于细化。也就是说,它们不应该被拆解到需要多个函数链式调用的程度。
链式无服务器函数
另一个我们常见的反模式是无服务器函数在调用栈中的链式调用。这种形式的耦合会对解决方案的性能和成本效益产生极其负面的影响。例如,考虑一个无服务器函数,它使用典型的同步 前端后端(BFF)方法调用另一个查询数据库的无服务器函数中的业务逻辑。此情况在下图中有所展示。

图 7.5 – 无服务器函数的链式调用
如图所示,每个前置调用在等待后续调用完成的同时运行。在这种调用模式下,我们实际上是在加倍计算资源的消耗。在容器化或虚拟机环境中,这并不是问题,因为我们的计算资源可以在等待链式调用完成时处理其他请求。然而,在无服务器函数环境中,我们的函数一次只能处理一个调用。这意味着,在等待链中的第二个无服务器函数完成时,第一个 Lambda 函数无法处理其他请求。因此,我们实际上是在没有任何实质性好处的情况下,增加了计算成本和资源消耗。一些云服务提供商,如 GCP,正在构建允许更好利用这些未使用计算资源的平台。然而,大多数默认实现仍然限制为一次只能处理一个请求。链式函数是耦合的典型例子,它可以在单一函数内部转换为高凝聚力。我们更常见的需求是执行反操作,将耦合的服务解耦。
解耦耦合服务
当我们从另一个服务调用服务作为依赖项时,我们会增加对被依赖服务的更改爆炸范围,涵盖我们的依赖服务。这是一种紧耦合形式,可能对应用程序的性能造成很大影响。我们将服务链接在一起的数量越多,我们的服务就越不可靠,因为我们现在处理的是每个服务在链中的可靠性乘积。假设每个服务的可靠性为 95%。如果我们将 4 个服务组合在一次调用中,我们的可靠性将下降到 81.4%(0.95⁴)。通常,这个问题出现是因为它非常符合我们对服务的心理模型。作为程序员,当我们需要在应用程序内部执行某些工作时,我们调用一个函数并等待结果。将这个模型扩展到多服务架构时,我们调用另一个服务并等待结果。
幸运的是,云服务提供商有一种云原生方式来解决这种紧耦合问题。正确实现这一点需要两种思维方式的转变:
-
我们需要打破同步反馈的观念。发送一个 HTTP
202返回代码并异步执行工作,和同步响应 HTTP200返回代码的单次调用一样有效,甚至可能更有效。 -
我们需要停止将每个需要运行的服务视为依赖项,而是开始将它们看作是需要完成的独立工作单元。
在云原生环境中实施这些解决方案的关键是通过在中间放置一个托管服务来解耦这些服务。AWS 提供了简单队列服务(Simple Queue Service)和EventBridge,GCP 提供了Google Pub/Sub,而 Azure 则有Azure Event Grid和Azure Service Bus。
这些托管服务提供了类似的功能。它们充当我们的服务之间的消息代理,这样我们的服务就不需要同步通信来传递信息。它们在操作方式上略有不同。有些是简单消息队列,而有些是带有发布和订阅功能的完整事件总线实现。
使用这些服务的结果是类似的。我们的可靠性不再是由一系列产品的结果,而是通过解耦服务来将服务的可靠性交由托管服务负责。我们来看看四个不可靠的服务并将它们连接到托管服务上,实现异步执行。假设我们的托管服务具有四个 9 的正常运行时间(99.99% 的正常运行时间),那么我们的结果是四个服务,每个服务具有 95.98% 的可靠性。如果其中任何一个服务出现故障,其他服务仍将继续运行。
实施死信队列(DLQs)可以进一步提高这些服务的可靠性。如果我们的某个服务无法处理消息,我们可以将消息积压发送到 DLQ 中等待处理。一旦我们修复了我们的服务并且一切正常运行,我们可以自动从 DLQ 中重放事件并完成未完成的工作。这意味着不是一个服务故障会影响所有系统,而是一个系统的影响范围仅限于该系统本身。系统最终会在重播所有未处理消息后保持一致。当我们需要最终通过我们的系统跟踪这些事件,也许是为了排查它们为什么会进入我们的 DLQ,我们需要关联它们的路径,这引出了分布式系统的一个重要部分:遥测和事件关联。
遥测和事件关联
你无法提高你无法测量的内容。准确理解已部署应用程序中的耦合度可能具有挑战性。通常情况下,我们会遇到一种反模式,即使用传统的日志系统与分布式系统。传统的日志系统无法提供所需的粒度(详细级别)和可追溯性(与其他消息的关联性),以便调试和改进分布式系统。通常情况下,当我们调试分布式系统时,我们试图拼凑出在多个部署单元中执行操作的结果。这就是健壮的遥测系统发挥作用的地方。我们可以在进入分布式系统时标记所有请求、消息和调用的关联 ID,然后使用此关联 ID 跟踪该操作的影响,跨所有部署单元和托管服务。我们将在第十章中更详细地介绍遥测系统。然而,我们可以利用现代遥测系统的关联方面来帮助我们解耦应用程序。通过跟踪我们的迹象,我们可以揭示系统之间的依赖关系,这些依赖关系以前可能需要查看源代码或环境配置来找到。一旦我们识别出应用程序内的依赖关系,我们可以逐步从紧密耦合的依赖关系(一个服务调用另一个服务)转向松散耦合的依赖关系(通过共享的托管消息总线或队列连接的两个或多个服务)。
紧耦合和低内聚是我们通常在本地环境中避开的一些反模式。在云环境中,这些模式变得不再有效,导致应用程序性能差和意外副作用。解决这些反模式的关键是,首先能够衡量耦合度和内聚度,其次是努力解耦紧耦合的服务,并提高内部的内聚性。通常,建模内聚性和耦合度应成为特性架构规划的一部分,并构成“完成”定义的一部分。让我们探讨一些常见的陷阱,并深入了解完整的“完成”定义。
完整的“完成”定义
在创建隔离发布模型的软件时,正如在第五章中讨论的那样,我们探讨了如何赋能团队从构思到部署,再到运维,完全拥有交付结果。然而,这要求开发团队也要承担(在其他团队的支持下)之前被隔离发布管道隐藏的功能和责任,直到产品上线。因此,我们需要重新审视软件团队的完成定义(在某些情况下,还需要重新审视准备好定义)。之前我们探讨过为实现这一目标所需的文化和业务转型,而在本节中,我们将讨论如何将这些要求内建于你的“完成”定义中。
忽视安全
安全是交付管道中的一个关键因素。忽视安全实践可能导致公司风险逐渐积累,通常在发生安全漏洞之前不会被注意到。这种遗漏可能导致相互指责并带来严重后果。为了开发安全的应用程序,将多种安全实践整合到软件交付生命周期(SDLC)中至关重要。这些实践应成为任何工作完成定义的一部分,其审查应该像部署前的代码审查一样严格。
忽视开源或外部依赖是一种反模式。在软件领域,许多开源包提供了基础功能,我们在其基础上构建业务逻辑。然而,每个我们从外部源拉取的包都代表着可能将恶意代码添加到应用程序中的潜在途径。维护并监控软件物料清单(SBoM)能帮助你了解项目的健康状况。许多工具可以帮助你管理所使用的软件包的版本。管理依赖关系的典型模式是在语言层面使用一个可读的私有工件库,并通过这个工件库填充内部包供使用,同时允许它拉取并缓存上游包。这个库将使你能够拥有一个包含所有依赖关系和版本的统一视图,GCP、AWS、Azure 以及许多小型平台都可以从各自的工件库服务中导出和监控 SBoM。拉取请求应进行工具化,确保它们添加的包不会引入任何新漏洞,且应该定期进行维护,依据 SBoM 来解决任何新发现的漏洞。
没有威胁模型或构建后忽视它是一种反模式。通常,当我们看到从专门的安全团队转向支持并赋能的开发团队时,开发团队会利用安全团队来生成威胁模型,但在整个软件开发生命周期(SDLC)中未能充分考虑它。初步的威胁模型应作为团队“准备好”定义的一部分。威胁模型在决定如何解决问题时应是基础,且必须经过验证,确保所构建的解决方案能有效缓解已识别的风险。因此,威胁模型应是一个动态文档,随着变更的实施,提供有关如何缓解风险的详细信息,以便可以自信地合并这些变更。应用程序投入生产后,应通过云原生应用保护平台(CNAPP)进行监控,以捕捉任何可能未被威胁模型解决的风险或配置错误。有效的威胁建模的关键是选择合适的粒度。如果你是一个股票市场,正在对结算引擎进行修改,那么合适的粒度可能是每次合并。而其他低风险环境可能只需要在较低粒度层面进行威胁建模。其核心理念是找到适当的摩擦度,在不妥协必要的安全级别的前提下,合理地降低风险。
最后一种忽视安全反模式是源自云计算所提供的更大灵活性,即未能解决深度防御问题。在本地环境中,网络内部与外部的划分是显而易见的。你有一根物理电缆连接到防火墙,防火墙作为所有流量的入口点。你的解决方案可能在下游有一些软件定义的网络,但依然有明显的隔离。在云环境中,突然间,不同的服务运行在虚拟私有云(VPCs)内部或外部。端点可以通过互联网或通过端点投影进入你的网络进行访问。一些服务存在于云服务提供商管理的网络中,并需要额外的网络配置。所有这些都意味着流量流动的路径变得不那么明确。虽然有工具可以帮助解决这个问题,但从根本上讲,云环境的高度可配置性意味着配置错误可能会导致更大的风险面。受管云服务已经具备强大的身份与访问管理(IAM)工具。你应该在代码中补充强大的零信任认证与授权工具,并在每个应用层面进行验证。许多组织在实施零信任架构的过程中仍处于早期阶段。因此,这应该被视为一种北极星原则,而不是绝对要求。关键在于问自己:“如果我们不小心直接将此服务暴露到互联网,会发生什么?” 这有助于限制云配置错误的影响范围,并确保即使一个内部服务意外暴露给公众,它仍能授权进入的流量。这个影响范围的考量也需要从 CI/CD 的角度来考虑。我曾与一个客户合作,他们的所有基础设施都在一个单一的代码库和项目中。这导致了权限非常高的 CI/CD 账户,且它们的影响范围跨越多个独立的系统。拥有强大的深度防御策略意味着,随着应用架构向更自助的模式转变,开发者构建的基础平台足够安全,能够容忍每个层级的失败。正如我们必须确保开发者构建安全的平台一样,我们也必须确保我们构建的是可观测的平台。
忽视可观测性
在单体应用中,将日志输出到控制台足以调试我们的应用程序。这之所以有效,是因为应用程序只是一个简单结构(基础设施)上的复杂对象(我们的代码)。在云原生世界中,我们将很多复杂性转移到基础设施中,构成了一个复杂的结构(基础设施)上的简单对象(我们的代码)。这需要比单纯将日志输出到控制台更加健壮的日志记录和遥测实践。我们将在第十章中更详细地探讨这个话题,但在本节中,我们将介绍一些内容,这些内容应该构成完成定义的基础。
第一个反模式是忽略跨度,只使用日志记录。日志记录为我们提供了关于应用程序状态的时间点信息,而跨度则不同。跨度为我们提供了应用程序执行期间的上下文信息。作为完成定义的一部分,我们应该增加能提供有关我们代码执行子部分有意义信息的跨度。在跨度执行的过程中,我们还应该确保我们添加足够丰富的数据,以便通过我们的可观察性平台更容易地诊断问题。对于任何超出单个实例范围的部署,我们还必须考虑关联性,以便将跨度组合在一起并追踪它们在分布式应用程序中的路径。从多个服务的日志条目中拼凑请求的执行上下文比阅读相关联的跨度火焰图要困难得多。
第二种反模式是收集没有功能输出的度量指标。我们经常看到某些公司收集了很多度量指标,但没有警报或偏差监控。我们有数据来检查我们的应用程序是否按预期运行。然而,我们缺少一个关键步骤,那就是在出现问题时能够及时告知我们。通过全面的监控、警报和整改流程,我们可以确保系统的非功能性要求,如延迟和错误百分比,保持在可接受的范围内。因此,作为完成定义的一部分,我们应该确保两件事:
-
首先,我们必须确保所做的更改已经设置了监控。这可以通过合成流量、应用性能监控(APM)、可观察性工具和传统日志记录来实现。
-
其次,我们必须确保在工具检测到问题时,能够通知到正确的人。这可以通过自动在您的工单系统中创建工单、在消息通道中通知用户或其他方式来实现。关键是要识别回归问题,并且确保相关人员知道需要进行整改。
通过将这两个要素纳入我们“完成定义”的范畴,我们可以确保在新增或修改功能时,不会违反系统的非功能性要求。这种可观察性水平还使我们能够深入了解哪些部分的应用程序是我们持续改进过程中优化的候选项。以前,对于那些用户抱怨应用程序速度慢的客户,我们过滤了指标,将请求按照两个因素进行排序:请求的频率和典型事务的耗时。我们发现有三个端点被频繁调用且响应较慢。通过一些查询优化,我们将响应时间减少了两个数量级。这项改动总共花了三天时间,最终用户的满意度大大提高。如果没有收集这些指标并利用它们的输出,我们将需要在生产环境中进行大量测试,才能获得相同程度的洞察力。可观察性在发现事件原因(即问题发生时)时非常有用,但那么如何从一开始就避免事件的发生呢?
忽视可靠性
本节的最后部分讨论了忽视可靠性。这是我们在云迁移中常见的反模式。团队往往只关心功能是否能正常工作,而忽视了其持续运行的能力。正是在这种情况下,你构建它,你运维它的心态就显得尤为重要。那些同时负责其输出运维的开发团队,更有可能考虑到可靠性,因为他们有投资在其中,且希望避免在夜间或周末接到紧急电话。云原生服务提供了强大的工具,确保可靠性和服务的连续性。然而,利用这些服务可能意味着一次几秒钟的中断和几天的中断之间的区别。任何希望符合内部或外部服务水平目标(SLOs)或拥有合同服务水平协议(SLA)的公司,必须确保将可靠性视为“完成定义”中的一个关键方面。
我们将要讨论的第一个反模式是部署过程的一个方面。正如我们在第五章中所讨论的那样,开发团队应该负责自己变更的部署和运营。我们在这一领域经常看到的反模式是,在我们的环境中使用相同的部署策略。在开发或测试环境中,通常我们会使用全有或全无的部署策略。当我们想要保证所调用的代码版本是最新的,并且保持部署与测试周期之间的快速反馈时,这种策略是合理的。将这一方法应用于生产环境意味着,如果我们的变更导致功能故障,那么变更要么会完全崩溃,要么什么都不发生。即便是成功的部署,也可能会出现可避免的停机时间,因为新的服务可能需要时间才能上线。对于生产系统,我们关心的两件事是:早期反馈和快速修复问题。许多云原生的部署方法允许我们进行增量更新或快速回滚变更,以确保系统的正常运行,尤其是在使用像 API 网关或函数即服务这样的高度托管服务时。这些策略通常会以部署时间的增加或额外的资源配置为代价。同时,它们通常需要外部的状态管理,因为任何内部状态都会在部署时丢失。我们可以使用的部分方法包括:
-
滚动部署:这些部署将一组运行相同应用程序的资源(比如一组三个容器,可能都在运行我们的用户服务)进行逐步更新,直到所有服务都运行新版本,并且在开始部署下一个服务之前,等待每个服务变得健康。这使我们能够缓解在全有或全无的方式中,等待服务准备好处理流量时出现的可避免的停机时间,但它没有为我们在发生仅在运行时出现的故障时提供可靠的选项来恢复应用程序的正常状态。
-
蓝绿部署:在这种策略中,您有两组独立的资源。一组资源使用应用程序的最新稳定生产版本(蓝色)来处理生产流量,而另一组资源正在进行部署(绿色)。在确保新部署的系统正常工作后,您可以切换到新系统,这可以通过别名或内部 DNS来实现。然后,您可以停用旧的蓝色目标资源。如果发生故障,可以轻松地将引用、DNS 或其他方式指向旧的应用程序部署。
-
金丝雀发布:在这种策略中,你采用与蓝绿发布策略相同的部署方法。关键的区别在于从蓝色资源切换到绿色资源的过程。我们不会立即切换,而是将部分流量慢慢重定向到新的实例。这成为我们在煤矿中的金丝雀;我们可以使用一部分生产数据来测试服务,如果发生问题,只有少量请求会受到影响,而不是所有请求。否则,如果一切顺利,我们就会将所有流量切换到新资源,旧资源可以被退役。
这些方法论不仅仅适用于你的应用程序代码;这种模式可以在任何需要昂贵发布过程的地方使用。我曾与一位客户合作,该客户的数据库每个月都需要更新。每个月,用于构建数据库的数据都会被修改或追加。新数据的摄取和验证其正确性需要 15 分钟,而客户无法容忍 15 分钟的停机时间。因此,我们创建了两个表:一个存储最新数据,另一个存储上个月的数据。每次需要摄取新数据时,我们会将包含最旧数据的表填充为最新数据。然后,我们会将该表与当前使用的表进行对比。如果一切正常,我们将更新最终用户使用的视图,指向包含新数据的表。这使得数据集之间可以无缝过渡,不需要将系统下线,并且如果出现问题,可以迅速回退到最后已知的良好配置。理解哪种部署策略适合你的需求至关重要,选择合适的部署策略应成为“完成定义”的一部分。
我们将要讨论的第二个可靠性反模式是未正确处理灾难恢复。云服务有合理的默认设置来防止数据丢失事件,例如将对象存储在多个区域或自动化数据库备份过程。此过程通常是可调的,以满足你的恢复点目标(RPO)——即我们能够容忍丢失多少数据。尽管云服务对于数据丢失事件提供了很好的保护,但对于服务丧失事件的保护通常在很大程度上依赖于你的架构。数据丢失预防所未能解决的关键指标是恢复时间目标(RTO)。从备份恢复数据库可能需要相当长的时间。同样,搭建新的基础设施实例可能不是一个快速的过程。如果你的应用程序发生灾难性故障,那么制定一个恢复服务的计划对于你的终端用户来说非常重要。团队在这一领域通常犯的第一个错误是只创建一个基础设施副本,完成后就不再关注,然后继续开发新功能。在这种情况下,灾难恢复完全被忽视了。如果发生灾难性故障,团队不仅会忙于重新创建他们的服务,而且没有明确的过程来执行此操作。我们常见的第二种情况是,人们拥有一个理论上的灾难恢复策略。他们列出了发生故障时需要采取的步骤,但如果策略是理论性的,那么它实际上能否有效就难以保证。未经测试的策略毫无意义。任何灾难恢复策略都需要定期模拟测试。第一次测试的时间(而且通常是团队中的大部分人第一次看到该策略的时间)不应该是在发生严重故障时。通常,灾难恢复有几种选择;关键是所有选项都必须经过测试。我们通常考虑的恢复可能性如下:
-
冷恢复:该策略适用于非关键服务。冷恢复假设你从零开始,重新配置应用程序的新实例,并从备份中恢复以恢复服务。需要注意的是,没有灾难恢复计划并不等同于拥有冷恢复计划。像所有计划一样,冷恢复必须被记录并定期测试,以确保过程满足你的 RPO(恢复点目标)和 RTO(恢复时间目标)。
-
热备份:该策略涉及在不同位置运行您应用程序的第二个(或更多)最小副本,若服务发生故障,可以快速扩展以接管服务。理想情况下,故障转移和扩展应自动化,但在自动化尚未完成时,手动故障转移是完全可以接受的。一种替代热备用架构,采用相同的原则,涉及保持您应用程序的支持结构运行,但仅在需要故障转移时才启动应用程序。这种策略的变体通常被称为试点轻量策略。
-
热恢复:该策略涉及在多活架构中运行您的应用程序。就像我们可以运行多个服务器以确保能够容忍任何单个服务器的故障一样,这种模式采用相同的方法,但应用于整个架构。任何一个活跃部署的故障意味着流量可以被重定向到健康的区域。
混沌工程的概念在这里非常重要。记住 Werner Vogels 的名言,“一切都会失败,永远都会失败。”混沌工程通过故意将故障引入系统来加强这一点,确保系统具有容错能力。另一种好的策略是使用“游戏日”的概念,尤其是对于手动过程。这些模拟事件与责任团队一起执行灾难恢复策略,确保每个人都熟悉该过程。因此,每当完成一个功能或服务时,灾难恢复策略必须更新,以包括新更改的需求,并作为“完成定义”的一部分。
安全性、可观察性和可靠性是我们系统变化的内在部分,通常被忽视。通过将这些内在部分作为我们“完成定义”的一部分进行解决,我们确保我们的开发团队不仅仅是在构建展示他们所创建功能的应用程序,还在提供一个我们的最终用户可以信任的平台。这些系统部分构成了云原生可操作性的基础基准,但我们可能会掉入许多其他陷阱。
其他陷阱
在云原生应用程序开发中,有几种常见的反模式。本节将解析这些反模式,它们从传统软件开发中衍生而来,如何识别它们,以及避免这些反模式所需的主动思维转变。在我们的场景中,云原生应用程序具有扩展到任何我们选择的规模的能力,激发了我们的软件与潜在问题解决方案之间的有趣互动。通过理解这些反模式并采用主动的思维方式,我们可以赋予自己做出明智决策的能力,避免潜在的陷阱。
没有云原生经验的情况下解决云原生问题
我正在与一个客户合作,尝试将他们现有的数据结构迁移到OpenSearch集群中。我们有明确的模式,数据必须按照这些模式进行整理。然而,问题在于,客户尝试直接将他们的关系型数据结构迁移到 OpenSearch 中,而没有进行任何反规范化处理。这意味着,为了整理数据,我们需要执行多个查找操作来获取相关的数据结构。这些查找操作导致了一个情况:对于一个模型的单一请求,可能会膨胀为成千上万的下游请求,用于获取所有关联的数据。尽管我们一再反对,认为数据结构需要进行反规范化,或迁移到高性能、只读的关系型数据库副本中,但客户坚持要通过保留原始关系型结构在非关系型数据存储中来保持系统的灵活性。我们实施了许多改进措施,尽可能推动模型的性能,包括批量请求和针对重复值的本地缓存。然而,一些请求太过深度嵌套,无法进行优化。客户最初提出的解决方案是扩展集群,于是客户扩展了集群,直到再次遇到性能瓶颈,然后客户再次扩展了集群。我们与云服务提供商进行了有趣的电话会议,他们告知客户,他们提供的基础设施已经超出了云服务商为某些子服务预留的资源。这是我们想要解决的第一个反模式。几乎无限的云资源的易得性伴随着用更多资源解决性能问题的诱惑,结果是,云账单也会同样迅速膨胀。我们应该更多地从应用程序内部入手,而不是仅仅从其运行的基础设施来解决性能问题。垂直扩展我们的基础设施来解决性能问题,只会让我们走得更远。这个问题表明,可能需要一种替代的专业解决方案,或者您的服务耦合度较低,或者您的应用程序优化不良。
这引出了第二种反模式,它也可能导致第一种反模式。这种模式通常从一个负责云原生服务的人开始,他在网上看到一个有很多漂亮图标和框的分阶段架构,然后试图将这种架构强行套用到自己的用例中。我们的架构应该由我们需要编写的应用程序代码的要求来指导,而不是由我们编写的代码来适应某种架构。造成这种情况的原因可能是多方面的。一个常见的驱动因素是我们通常所说的简历驱动开发(resume-driven development)。当一个人更关心通过某种技术获得经验,而不是该技术解决问题的潜力时,就会发生这种情况。分阶段架构可以成为潜在解决方案的良好起点,并且通常能展示最佳实践。然而,我们必须谨慎对待这些架构,考虑它们在各种因素下的适用性。通常,在照搬一个分阶段架构之前,我们应该问自己一些问题,比如:
-
我们是否在这个分阶段架构解决问题的规模下运行?
-
我们是否拥有实施和维护它所需的内部技能?
-
这个模型是否符合我们的标准架构实践,还是它会是一个独特的架构?
-
我们能做哪些改动来确保这个架构更准确地解决我们的难题?
我们要讨论的第三个反模式是手动更改部署的基础设施或代码库,绕过我们的 CI/CD 流程。一个典型的例子可能是,我们的应用在生产环境中运行一个查询,完成需要一些时间。于是,开发者登录生产环境,快速在查找列上添加一个索引,问题就解决了。尽管需要一系列错误发生,以允许开发者进行这种修改,但从根本上说,我们正在给应用引入不稳定性。这个概念被称为环境漂移。我们的代码和部署管道定义了一个与实际部署不一致的模型。在我们的例子中,我们看到开发者对生产环境进行修改,这意味着所有后续更改的第一次测试,实际上是在这些更改进入生产环境时才会遇到环境漂移的问题。当我们需要重建基础设施时,这也会成为一个问题;通过绕过我们的源模型,每当我们尝试创建新的基础设施实例时,就会再次遇到同样的问题。解决这个问题的方法相对简单:开发团队不应在不遵循 CI/CD 流程的情况下更改非临时环境。如果他们想要快速原型修复或进行技术性突破,而这些工作会因对环境有写权限而加速,那么可以创建一个可以在工作完成后销毁的沙箱环境。这样,你就能避免在任何环境中积累测试和快速修复,避免影响生产环境的稳定性。理想情况下,这些低环境应尽可能与生产环境保持一致。关于生产环境,我们必须小心如何根据现实世界事件来扩展我们的代码。
成功的痛苦——无限规模的负面影响
在使用本地基础设施时,我们的应用程序吞吐量有一个上限。最终,我们将耗尽系统资源来处理请求。在云环境中,我们常常看到相同的思维方式发挥作用——一种忽视速率限制和服务限制的反模式。忽视速率限制、服务限制或节流的后果在云环境中显著更为严重。与基础设施限制不同,云环境中我们几乎拥有无限的资源池来进行扩展。假设我们将这种缺乏物理限制与无状态的服务器结合起来,这些服务器可以互换地处理任何请求,而不考虑我们可能有的任何服务级别分区。在这种情况下,我们可以非常快速且几乎无限地扩展以满足客户的需求。在这种情形下,我们必须对使用我们的服务设定人工上限。这些限制如何分配(例如按用户、租户、客户等)由实施者决定。我们设定合理的限制,以控制理论上无限的服务使用,避免成本失控,并确保不影响其他客户的服务。许多云原生托管服务已经内建了我们可以使用的功能,用于执行速率限制、使用监控和许可应用程序。通常,这些功能应用于API 聚合层,例如在 AWS API Gateway、Azure APIM 或 GCP API Gateway 中。幸运的是,这些相同的 API 密钥可以作为我们认证策略的一部分使用,例如,将请求与客户端绑定,以启用深度防御检查,确保我们的 API 密钥与我们正在调用的租户匹配。随着应用程序复杂度的增加,我们可能需要在 API 上实现自定义授权和速率限制逻辑。例如,AWS 允许通过 Lambda 函数向 API Gateway 添加自定义授权。其他一些小众的 API 代理平台,如Apigee(现已被 Google 收购)和Kong,允许通过全面的策略语言实现复杂的逻辑。
在传统的本地单体架构中,系统故障往往是一起发生的。我们的服务器是否超载了?这是一个相对简单的问题。在云原生世界中,我们的服务由多个组件构成,故障通常是零散发生的。我们需要对这些故障保持容忍,但也需要意识到,云所能支持的规模可能会导致一些有趣的行为。接下来我们要讨论的反模式是使用不良的超时和重试实践,尤其是在并发执行的背景下。假设我们有一个需要将 CSV 文件加载到数据库中的过程,并且有一个服务负责处理这些文件桶中单个文件的上传。当我们的上游客户——那些将文件上传到 S3 桶供我们使用的客户——意识到他们的系统出现了错误,过去三天内没有上传文件时,这并不算问题;他们已经补充了所有文件。假设我们有一个简单的架构,它通过 S3 事件和 SNS 请求 HTTP 端点来拉取文件进行处理。如果我们忽视了并发执行的后果,我们可能会突然开始同时摄取大量数据。这会对我们加载文件的数据库造成巨大的负载。如果我们没有为这些进程配置超时,那么我们可能最终会完全超载数据库。因此,我们应用程序中的所有调用必须设置超时,并且必须优雅地处理这些超时的到期,清理它们所请求的任何正在进行的工作。
那么,如果超时失败,接下来该怎么办?一个天真的回答可能是我们只需要重试请求。如果失败是由于系统过载以外的因素造成的,而且这些错误很少发生,那么我们可能可以采取这种方法。然而,需要注意的是,重试实际上是在加剧问题;我们正在请求更多的服务器时间来解决问题。如果系统已经超载,那么这种做法就会加重影响,因为旧的请求在重试时将与新的请求竞争资源。一个常见的策略是使用指数退避算法,尽管建议对最大重试周期和重试次数进行限制。这样做是可行的;然而,一旦服务器过载,大量调用将会失败,如果所有这些调用都按照同样的算法重试,那么我们所做的只是将问题推迟,最终在下次重试时我们将再次让服务器过载。
重试行为的另一个重要方面是抖动的概念。我们在重试行为中引入随机性,以防止发生踩踏式的拥挤情况。我们还需要注意重试的乘法效应。假设我们的服务发起了三层深的调用,并且每个服务都重试了五次。在这种情况下,下游系统将收到 53 次重试或 125 个请求,这正是我们不希望看到的行为,尤其是在下游服务过载时。幸运的是,有三种简单的方法可以避免这种情况:
-
使用消息队列解耦突发性和高成本的流量,然后根据队列深度扩展下游服务
-
尽可能使用云服务提供商的 SDK,因为这些 SDK 已经内置了重试行为
-
使用托管服务,因为这些服务通常更易于扩展,并且内置了重试和速率限制功能,您无需自己构建这些功能
这带我们进入最后一个反模式,即使用短暂资源的隐式属性进行硬编码的依赖映射。
避免隐式的短暂资源规范
在编写代码时,特别是基础设施即代码(IaC),我们很容易陷入使用直接规范来处理部分短暂资源的反模式。例如,短暂资源规范可能是应用一个 IaC 配置,输出实例的 IP 地址,然后在另一个 IaC 配置中直接使用该 IP 地址引用第一个配置实例。如果我们更改第一个配置,IP 地址可能会发生变化,但我们的短暂资源规范已在它们之间创建了硬依赖关系。相反,我们应该使用那些不是短暂的资源,例如可以更新的 DNS 条目。这是最简单的服务发现形式。还有一些功能强大的服务发现平台,可以为各种云提供商和部署配置扩展这一功能。理想情况下,我们基础设施之间的任何依赖关系应该是显式的,而不是通过硬编码的值隐式存在,这样可以确保我们的部署真正与已部署环境的状态无关。
总结
我们现在已经探讨了一些常见的反模式,这些反模式出现在我们将应用逻辑迁移到云端时。我们的应用代码通常是我们业务中的价值区分因素或竞争优势,因此我们可以将其迁移到云端,从而提高其可用性、弹性和性能。现在我们已经了解了在云端运行应用代码的影响,接下来我们该如何存储所有数据呢?这就是我们将在下一章深入探讨的内容。
第八章:别迷失在数据丛林中
数据是我们所做一切的核心。云原生应用程序的大多数操作都涉及以各种形式生成、消费和修改数据。选择合适的地方存储数据,了解如何摄取数据,并保持数据的完整性至关重要。虽然我们生产的应用程序的许多价值存在于业务逻辑中,但从根本上来说,这些业务逻辑是在数据上运行的。因此,我们存储数据的方式对应用程序的操作至关重要。与传统的本地服务不同,云原生服务提供了新的、令人兴奋的机会,可以显著降低我们的运营和维护成本。然而,如果使用不当,这些服务也能通过一些阴险的反模式迅速妨碍我们的努力。
在本章中,我们将讨论以下在云中持久化数据时常见的反模式:
-
选择错误的数据库或存储
-
从生产到开发的数据复制
-
备份和恢复应该在理论上是可行的
-
手动数据摄取
-
数据传输错误没有可观察性
在本章结束时,你将对云原生数据存储选项有一个扎实的理解,特别是它们在操作目的中的应用以及它们之间的权衡。
选择错误的数据库或存储
“当你只有一把锤子时,一切看起来都像钉子”是一个常用的说法,用来描述过度依赖同一工具处理所有问题的现象。有偏好是可以接受的,但当团队选择数据库或存储解决方案时,我们经常看到相同的开发者一次又一次地选择相同的工具。虽然熟悉特定工具集可能有助于快速上手和开发,但这可能导致次优的解决方案和反模式。云原生应用程序有着丰富的数据库和存储方式,因此一个全面的云应用程序应该考虑所有可用选项。在我们深入了解这些选项之前,先来看看一些必要的背景知识,以便更好地框定我们的讨论。
框定讨论
在讨论数据库时,首先需要探索一致性、可用性和分区容忍性(CAP)定理、规范化形式和时间复杂度。这三个概念解释了为多种解决方案设计数据模型时的权衡和方法。
CAP 定理
如前所述,CAP 定理代表一致性、可用性和分区容忍性,专门针对分布式数据存储。共识是,分布式数据库解决方案只能真正同时解决这三者中的两个能力:
-
一致性确保当数据库读取发生时,它将返回由所有在我们请求读取之前提交的操作所导致的数据库状态。强一致性的数据库维持这一范式,而最终一致性的数据库将返回一个可能没有传播所有已应用写入的状态;它表示数据库在某个过去时刻的状态。
-
可用性意味着每个有效数据库节点接收到的请求必须返回一个非错误响应。在分布式数据存储的上下文中,这可能与一致性保障发生冲突。我们如何确保系统已经接收到来自其他所有节点的所有事务,特别是在可能发生网络分区或延迟的情况下?这就引出了分区容忍性。
-
分区容忍性保证系统会继续运行,即使节点之间的消息传递不可靠或延迟。如果其中一个节点发生了灾难性的网络故障,我们的数据存储应继续运行。这在具有多主配置的分布式数据库中尤为突出,例如本章稍后讨论的一些高可用选项。
在理想的世界里,我们选择的数据存储会具备这三种属性,而且一些最近的技术进展推动了这种排他性的极限。然而,这种模式通常在现实中得到密切体现。

图 8.1 – CAP 定理元素的欧拉图
范式
范式是指我们在数据库系统中如何构建数据。从根本上说,范式是衡量我们数据库规范化程度的标准。我们将快速回顾范式,并通过一个共同的主题为每个范式提供示例。在这个过程中需要记住的一点是,尽管表面上看,范式越高,数据库设计越好,但在大多数情况下,我们还需要考虑数据的性能、查询以及访问模式。我们这里只讨论前三个范式,因为通常情况下,这也是云原生数据库之间差异的主要所在:
- 数据的第一范式(1NF)定义每个单元格为只包含一个单一值的单位,且数据存储中的列名应该是唯一的。许多支持嵌套或非结构化数据的存储解决方案已经不符合这一标准。下表展示了一个订单信息的第一范式数据集:
| 发票项 |
|---|
| 发票 ID(键) |
| 123 |
| 123 |
| 456 |
| 789 |
表 8.1 – 发票、项目和销售人员存储在单个表中
- 第二范式(
Salesperson列在第一个表中)。在这种情况下,我们的结果仅依赖于键的一部分,即发票 ID。
| 发票项 |
|---|
| InvoiceId (主键) |
| 123 |
| 123 |
| 456 |
| 789 |
表 8.2 – 发票和项目;请注意我们在此表中移除了两列
我们来添加一个新表,通过存储销售人员与发票 ID 的对应关系来满足第二范式:
| InvoiceSalesperson |
|---|
| InvoiceId (主键) |
| 123 |
| 456 |
| 789 |
表 8.3 – 发票及其与销售人员的关系;请注意,我们现在存储的数据较少,但仍能重建相同的细节
- 第三范式(
InvoiceSalesperson表基于InvoiceId主键。然而,销售人员的姓名依赖于SalespersonID,这是一种传递依赖。为了解决这个问题,让我们添加一个销售人员表(表 8.5):
| InvoiceItems |
|---|
| InvoiceId (主键) |
| 123 |
| 123 |
| 456 |
| 789 |
表 8.4 – 发票和项目;此场景与我们之前的示例没有变化
然后我们有相同的发票销售人员映射;不过,我们使用标识符而不是销售人员的姓名。
| InvoiceSalesperson |
|---|
| InvoiceId (主键) |
| 123 |
| 456 |
| 789 |
表 8.5 – 发票及其与销售人员的关系;然而,我们已经移除了传递依赖
最后,我们添加一个包含每个销售人员的表:
| 销售人员 |
|---|
| SalespersonID (主键) |
| 10 |
| 8 |
表 8.6 – 将销售人员 ID 映射到其姓名;这再次减少了我们存储的数据,但仍可以通过正确的访问模式重建
我们的解决方案现在已经发展到符合第三范式。如你所见,高级别的规范化要求越来越依赖于关系,但能提供更高的一致性。
时间复杂度
最后,我们需要讨论时间复杂度和大 O 表示法。大 O 表示法描述了系统执行时间相对于处理的数据集大小的上界。一个具有恒定查找时间的系统,不管数据集大小,都是 O(1)。一个随着数据集项目数量线性扩展查找时间的系统是 O(n)。
一个好的例子是一个天真的数据库实现,它检查数据库中的每一行,看看它是否符合我们的选择标准。在这种情况下,实施将是 O(n) 复杂度;随着记录数量的增加,我们需要对每一行查找进行线性检查。实际上,大多数数据库解决方案将位于这些值之间。复杂度可以以大于 O(n) 的速率扩展,但如果一个数据库提供这样的复杂度,你应该寻找另一种方案。
适合的数据库用于适合的目的
我们在云原生系统中看到四种关键类型的数据库用于大规模数据存储:关系型、NoSQL、键值型和图形型(还有许多其他解决方案,如分类账/区块链数据库、层次型数据库和向量数据库,但它们超出了本节的讨论范围)。每种数据库都有其优点,并且适用于不同的数据类型,但它们需要不同的处理方法。一个常见的反模式是开发人员为他们的应用程序选择了不合适的云数据库。
关系型数据库
关系型数据库是经过验证的传统数据库解决方案。它们允许您建立记录并建模它们之间的关系。在这种解决方案中,数据库通常符合严格的、预定义的一组关系和结构,这些关系和结构作为其模式的一部分进行定义。然而,越来越多的关系型数据库引擎提供了存储半结构化和非结构化数据的能力。由于其高度结构化的数据模型,关系型数据库使得维护数据的一致性和完整性变得非常容易。其内建的关系支持使得查询规范化数据变得简单。在云计算领域,这些数据库通常作为服务提供,甚至可能有“无服务器”的服务(稍后会详细解释为何要加上引号);然而,当我们尝试扩展这些系统时,就会遇到问题。通常,扩展模型是通过垂直扩展向这些服务添加额外的容量。
一些较新的解决方案提供了自动化、透明的分片能力,并且价格较高。在大规模数据集的情况下,这可能会引发问题,导致更高的云账单。还必须注意,在这些系统中,我们通常只能使用某些类型的索引,如二叉树,二叉树的时间复杂度为 O(log(n))。当我们在关系型数据库中查询数据时,一个典型的模式是连接记录并进行聚合,以返回我们想要的结果。这种模式在您知道要存储的数据结构,但不确定如何查询这些数据的访问模式时非常有用。灵活的访问模式使您能够在不对底层数据库进行重大更改的情况下扩展您的服务。您可以通过新的查询提供新的洞察。
提供关系型数据库的超大规模服务商涵盖了所有常见的 SQL 类型,例如 MySQL、PostgreSQL 和 SQL Server。通常,这些解决方案专注于一致性和分区容忍性。然而,许多超大规模服务商的新服务也提供高可用性。
NoSQL 数据库
NoSQL 数据库为传统的关系型数据库提供了一种替代方案。它们在一定程度上是非规范化的,并且它们依赖于内置于数据模型本身的访问模式,而不是允许灵活的访问模式。
所有的超大规模云服务商在这一领域都有产品:Azure 提供 Cosmos DB,GCP 提供 Firestore,AWS 提供 DynamoDB。与我们严格格式化的 SQL 表不同,NoSQL 数据库没有强制的模式。列可以混合数据类型,数据可以深度嵌套。有一些有力的论据支持你放弃单独的表,而将所有数据放入一个大表中。这些服务在低价格下提供极高的可扩展性和性能。然而,它们要求从传统关系数据库模型转变思维方式。
我们必须在前期设计好访问模式,以便从我们的 NoSQL 数据库解决方案中获得最佳价值。这个要求可能使开发稍微复杂一些,因为添加新的访问模式不仅仅是编写一个新查询的问题。我们可能需要对数据库设计进行重大修改。一些 NoSQL 领域的数据库解决方案(如 DynamoDB、Firestore 和 Cosmos DB)可以实现接近 O(1) 复杂度的正确结构化访问模式,但对于结构不当的访问模式,则会面临 O(n) 复杂度的惩罚。许多这些解决方案允许你优先考虑可用性和分区容忍性,或者一致性和分区容忍性。
键值存储
键值存储是一种简单的数据库类型。本质上,我们提供了一种方法来通过键(key)访问存储的数据(value)。NoSQL 数据库仍然允许复杂的访问模式。我们的键值存储只有一种访问模式:使用键获取存储在某个地址上的值。这些通常是高性能的内存数据库,可能会提供或不提供某种形式的持久化。此类数据存储的典型使用场景是复杂查询或来自其他系统的计算输出的缓存。当我们有低基数的复杂请求时,它们可以在云端武器库中提供帮助。
图形数据库
我们将讨论的最后一种数据库类型是 OrderID 字段,它在订单记录、运输清单和支付记录中都有引用。运输清单和支付记录包含指向订单记录的外键;然而,实际的关系存储在这些记录本身中。在图形数据库中,关系是一级对象。我们有对象(顶点)和关系(边),数据模型优化了关系的极快遍历,使我们能够高效地在数据集之间跟踪路径。当对象之间以任意方式进行交互时,这种特性尤其有优势,例如社交媒体网站上的用户与其他用户、帖子、社区等的互动。
其他数据库类型
探索其他支持服务或非标准数据库类型也可能是有利的。一个常被忽视的关键数据库类型是时间序列数据库。这些可以作为独立产品或之前数据库类型的扩展实现。这些数据库优化了按时间顺序访问模式和存储,而不是前面提到的结构。另一种常见的数据库或数据库扩展是空间数据库,专门研究查询中的几何和地理属性。关键在于不仅限制于前述数据库结构,还要探索适用于你边缘案例的选项。
我曾经处理过的一个例子中,客户使用 Postgres 数据库存储客户地址和标识列表。然而,该系统的访问模式不适合关系数据库。首先,数据不是关系型的;每条记录完全独立,其次,在数据库查询模式中显著使用 Postgres 关键字LIKE。客户的快速解决方案是在每一列上放置一个广义倒排索引(GIN)。这使得可以在任意字符串上进行搜索,但使得修改数据库变得笨拙。使用诸如 OpenSearch 之类的搜索服务来存储可查询文档可能更为简单,很可能会导致更低的云账单和更好的性能。
手动、托管、无服务器和真正无服务器数据库
在选择数据库时,我们必须确定之前讨论的数据库类型的需求以及我们将如何在云中使用数据库。
从传统思维方式出发的幼稚方法可能是我们只需提供一个云虚拟机,安装一个数据库,然后一切就搞定了。虽然这种手动方法可以行得通,但必须提供一个引人注目的价值主张。在这种情况下,你需要完全负责备份、更新数据库版本和操作系统,并且提供新的机器。如何安装、运行和维护数据库不太可能成为你业务的价值差异化因素。因此,通常认为这种手动选择是一种反模式,除非你需要特定功能或配置,而这些功能或配置在托管服务中不可用。相反,数据库的基线部署通常作为托管服务。
大多数公司在开始采用云数据库时采用了这种部署方法,因为这些托管服务为他们提供了一种使用熟悉工具(如 Postgres、MySQL 和 SQL Server)的方式,同时允许云提供商负责备份、更新和维护,采用经过实战检验和弹性的方法。许多公司从未找到离开这个层面的充分理由,这是完全可以接受的。我们还可以在这种开发模式下开始设置具有读取副本、自动故障转移和多主配置的弹性架构。
在管理型系统中,我们通常看到具有一致性和可预测模式的应用程序。然而,一些企业的流量和使用情况是不可预测的,因此你应该转向一个更具扩展性的解决方案。这种情况就是“无服务器”解决方案发挥作用的地方。我在这个场景中使用引号,因为它们是无服务器的(即它们会自动扩展)。不过,它们并不会扩展到零,许多人认为这才是真正的无服务器。我们在这一领域常见的反模式是,人们在迁移到这些“无服务器”解决方案时,未考虑非关系型数据模型。
最后,我们有了真正的无服务器数据库。这些通常是 NoSQL 或文档型数据库(例如在主要云提供商中的 DynamoDB、Firestore 和 Cosmos DB,属于在线事务处理(OLTP)领域),它们在极端可扩展性、成本效益和性能方面做出了使用便利性上的妥协。我们在这一领域常看到的反模式是,团队看到这一选项,并将其视为成就的巅峰,建立一个利用这种云原生独特选项的系统,而没有考虑其缺点。也就是说,你的数据更难以迁移,招聘也更困难,而且需要事先了解你的访问模式。这种组合可能导致初期糟糕的体验,促使团队回到熟悉的关系型数据库领域,而没有考虑这些数据库在一些适合的场景中的应用。
忽视存储需求
一个常见的反模式是,在云中使用传统的存储机制,而没有考虑其他选择。传统的文件系统是出于对设备内存储需求的演变而产生的,并提供了相当大的功能。网络文件系统,如 FTP 和 NFS,成为这些服务在多机器环境中的事实标准。这些系统的核心原则是,中央服务器负责协调对底层存储的访问。本书的一个常见主题是,集中化通常是一个反模式。
当我们开始设计一个利用云存储的系统时,我们应该首先问的第一个问题是,“我们可以使用 Blob 存储吗?” Blob 存储是去中心化的,能够水平扩展,且比传统的网络文件系统具有更高的弹性和持久性。在 Azure 中,这项服务是 Azure Blob 存储,GCP 提供 Cloud Storage,而 AWS 提供 S3。
你可以将 Blob 存储视为一个键值存储,它可以存储巨大的数据值。对于大多数云原生使用案例来说,这已经足够提供所需的能力。你还需要元数据吗?放到数据库里。需要锁吗?使用数据库。需要备份吗?使用版本历史记录。Blob 存储很可能是你存储需求的答案。有些情况下,专门的或传统的文件系统仍然能提供好处,例如在高性能计算、低延迟应用程序和传统文件系统迁移中。因此,记住没有一种工具可以解决所有问题。
忽略生命周期和归档策略
存储数据很容易。我们向选择的存储提供商发送请求,然后忘记它,直到需要使用它为止。问题就在这里:未能适当维护数据的生命周期可能会导致严重后果。
然而,我们可能希望节省一些费用,因为我们不一定需要访问这些数据;我们只需要将其保存档案。这时,存储层的概念就派上用场了。
让我们举个例子:我们在一家大型公司工作,负责内部税务功能。在一年中,人们会上传收据。在税务期间,我们需要反复访问这些收据,因为各种职能需要执行各自的职责。然后,在税务期过后,我们只需要保留一份副本,以防出现差异。在所有云服务提供商中,我们可以将他们的存储层分为三大类:
-
热存储是指需要定期访问并且能够随时获取的数据。通常,这个层级在存储成本和检索成本之间取得了很好的平衡。可以考虑将收据存储在此层级,以便在税务期间使用。
-
冷存储是指需要随时访问但不太可能经常访问的数据。我们在访问这个层级中的数据时需要付出更多费用,但通过较低的存储成本,享受不频繁访问的好处。这个层级可能是我们在一年中提交所有收据时存储的地方。
-
归档是指我们想要保留但没有特定访问速度要求的数据。这个层级提供最具成本效益的存储解决方案,但其访问成本最高,检索时间最慢(这可能是几个小时而不是毫秒级)。当我们完成一年的所有收据,并且只需要保留记录以备后用时,我们会将其移到这个层级。
一些数据可能需要保留,以符合监管要求,而其他数据可能只需要短期存储,因为其有效性会迅速降低。我们通过数据生命周期来实现这些使用案例。生命周期策略和管理工具使我们能够自动化这一过程。
通常,我们在生命周期策略中采取两种行动:要么改变数据的存储层,要么删除数据。一个生命周期策略可能会将这两种操作结合起来。例如,假设我们为一家公司工作,这家公司创建详细的财务报告。每个月,我们发布一份新报告,开始时频繁访问,然后逐渐不常访问,最后需要存档六年。我们的生命周期策略可能如下所示:
-
在热存储层创建一个文件。
-
等待 31 天(报告周期)。
-
将文件移动到冷存储层。
-
等待 334 天。
-
将文件移动到归档存储层。
-
等待六年。
-
删除文件。
如果我们将文件保持在热存储层,我们将支付频繁访问的便利费用,但实际上并未真正访问文件。因此,我们的生命周期策略使我们能够优化云存储开支。
从生产环境到开发环境的数据复制
我们都需要数据来确保我们在开发环境中构建的系统能够匹配用户在生产环境中生成的各种奇怪和有趣的数据类型。
这一部分是为数不多的几个反模式之一,反模式的严重性足以让整个部分以此命名。在任何情况下,都不应将用户生成的数据从生产环境复制到开发环境。虽然从生产环境获取真实的用例数据可能看起来很容易,但低环境通常具有更宽松的安全控制,并且开发人员的访问权限更广。最近的几起数据泄露直接涉及这一反模式;真实的用户数据出现在测试系统上,而这些测试系统被攻破。相反,在本节中,我们将讨论一些替代方案,以避免在生产数据上进行测试,以及在为测试环境创建数据时常见的反模式。
但我们会对生产数据进行掩码处理
我们将讨论的第一个反模式是使用来自生产系统的掩码数据进行测试环境中的测试。这种做法仅比直接使用生产数据稍微好一些。这个场景中的谬误在于,我们从一个不安全的位置(未掩码的生产数据)开始,应用一个转换(我们的掩码过程),并假设输出是安全的(掩码数据)。为了说明这是一个问题,让我们看一个类比的例子,它基于 FaaS。我曾与一个客户合作,该客户为 Lambda 函数开发了一个身份验证和日志包装器。这个包装器应用了一些功能,这些功能可以通过 Lambda 函数代码中的标志启用。一个标志启用了身份验证。这个模式意味着,从根本上说,任何创建的 Lambda 函数都是不安全的函数,然后必须选择启用安全性。相反,我们颠倒了这种依赖关系。我们默认让所有函数都是安全的,然后可以使用标志来关闭身份验证,以便使某些函数不进行身份验证。这一变化使得不安全成为一种有意识的选择,而不是无意识的错误。当我们掩码数据时,我们有可能犯无意识的错误,因为我们从一个不安全的位置开始。解决方案是从一个安全的位置开始,并明确地对我们的数据选择做出任何不安全的添加。因此,我们必须从一个安全的位置开始,这意味着我们需要了解我们的模式,并生成测试其极限的数据。
开始使用合成数据
正如我们之前讨论的,确保你使用的数据在低环境中是安全的最简单方法是确保它不来自生产系统。因此,我们需要一种可靠的方法来为我们的系统生成虚假数据。幸运的是,我们不是第一个遇到这个问题的人!已经有许多开源库专门用于生成完全虚假的数据。通常,对于云项目,JavaScript 在开发周期的某个阶段会被使用,无论是用于前端应用程序,还是后端服务器使用像 Node.js、Bun 或 Deno 这样的运行时,因此它通常是一个很好的基础语言。在这种情况下,Faker.js(fakerjs.dev)库提供了一整套生成器,用于为测试生成虚假数据。另一个常见的语言是 Python,它也有自己的 Faker 库(faker.readthedocs.io/en/master/)。
这些库构成了一个极好的基础,我们可以在此基础上进行建设。这些允许我们创建大量数据,以查看我们的系统在负载较重时的处理情况。我们可以使用生产系统的利用率指标来开发合成数据。合成数据保留了生产数据的模式和结构,但记录内容纯属虚构,非常适合功能测试。这种方法允许我们在较低的环境中加载与生产环境中相似数量的数据,确保我们在较低环境下测试的条件与在较高环境下的条件相似。我们在这里经常看到的一个反模式是试图在低环境中仅使用小数据集。这种反模式是一个问题,因为你首次在生产规模下部署系统时才测试系统。在这种范式下,仅在生产系统规模下才会出现的场景和边缘行为在测试期间仍然隐藏。这些问题可能是 SQL 查询优化不良或列上缺少索引。在这些场景中,小数据集不太可能暴露出这些问题。
完美的合成数据
在创建合成数据时,很容易陷入开发完美合成数据的反模式中。这种反模式只注入我们在生产系统中预期看到的数据、格式和使用模式。虽然这可能测试我们系统的顺畅路径,但不幸的是,用户往往会以我们从未预料到的方式来测试我们的系统。如果用户注册时使用一个地址,然后该地址被删除或分割成 A/B 区块或其他各种问题会发生什么呢?在这里,我们可以借鉴混沌工程的领域。与其创建完美数据,不如制造一定程度上有损坏的数据,通常表现为总合成数据的百分比。完美数据只适用于完全同质化用户的使用,而我们都知道我们的用户群体由大量不同的个体组成。
有一些简单的指导原则用于创建合成数据,我喜欢遵循这些原则。通常我将其分为两层:一层用于结构化数据(SQL 和 Parquet),另一层用于非结构化/半结构化数据(NoSQL、CSV、JSON 和 TXT)。非结构化数据损坏应视为结构化损坏的延伸。
结构化数据可以通过以下方式进行损坏:
-
缺失记录:如果我们在请求服务时收到了部分对象会发生什么?如果一个依赖项缺失会怎样?如果在创建记录时依赖项存在,但之后被手动删除了呢?
-
不可达状态:从代码的角度来看,我们可能有一些不可达的传递依赖关系,但从数据库的角度来看是允许的。如果我们达到了这种状态会发生什么呢?
-
损坏的记录:这是指在系统允许的情况下,数据本质上不合理的情况。如果用户不小心将信用卡号码输入到持卡人姓名字段中会怎样?如果我们的 CSV 文件中某一行的字符串中包含未转义的逗号,会发生什么?
-
大记录:当一个用户将无数只猴子和无尽数量的打字机连接到你的脏话过滤器时,会发生什么?
非结构化数据还可能以以下额外的方式受到损坏:
-
重复记录:当我们尝试插入重复记录或多个表示相同对象的记录时,会发生什么情况?
-
多余字段:当我们的系统收到来自客户端的额外数据时,会发生什么情况?
-
缺失字段:当我们的系统未收到来自客户端的预期数据时,会发生什么情况?
-
语法错误的数据:这是指与正在使用的数据媒介规则不一致的数据(例如,CSV 或 JSON 格式无效)。缺少列?忘记了大括号?
从这点来看,我们可以得出结论,完美的测试数据应当是设计上不完美的。这样可以帮助我们发现系统的边界行为。我们的测试数据应该在生产环境中遇到问题之前就能识别出可能遇到的问题。然而,对于我们在生产环境中可能遇到的数据问题,完全准确的预见是不可能的。最好的损坏数据类型是当我们在生产环境中发现某个问题时。在这种情况下,将损坏数据的方法(而非数据本身!)复制到你的合成数据生成工具中。这一过程可以帮助我们发现这种数据可能对生产产生的其他影响。例如,如果我们遇到一个无效的卡号输入问题,客户可以纠正卡号,一切恢复正常。如果我们将这一模式添加到合成数据中,我们就能看到如果该数据流入我们的账单系统或其他应用程序区域,如何影响我们的系统。
备份和恢复理论上应该能够正常工作
“鼠和人的最佳计划常常会失败,”这句名言出自罗伯特·彭斯的《致一只鼠》。其中的智慧是,无论我们如何小心地为每个可能的情况做好计划,直到我们执行它之前,我们都无法确信它会成功。我们在第七章中提到过忽视可靠性这个话题。接下来我们将更详细地讨论这个话题,并探索如何专门针对数据来解决这一反模式。如前所述,不测试数据的韧性将导致在你最不期待的时刻出现意外停机。让我们深入探讨一些缓解方法。
制定计划
拥有一个计划是构建弹性数据架构的第一步,而这个计划的关键在于理解共享责任模型。如果你按照本章第一部分的建议,在云中自托管自己的数据解决方案,那么你需要对一切负责。我们经常会遇到人们在转向托管服务时的断层。不可避免地,有人会在他们的托管云数据库实例中找到一个选项框,标记为启用备份,然后看到它已被勾选。接着,他们就会安然入睡,认为他们的数据是安全的,因为它被模糊地“由云处理”。如果这听起来很熟悉(即使不熟悉),你可能需要考虑制定一个恢复行动计划。
制定该计划时需要考虑的一些关键因素如下:
-
定义你的恢复时间目标(RTO)和恢复点目标(RPO)。这两个指标分别是以下问题的答案:
-
我能接受服务停机多长时间?
-
服务停机时,我能承受丢失多少数据?
一个常见的反模式是回答“没有”和“没有”。实际上,维持这样的策略的成本与现实不符。通常,这个问题的回答是按量级的,如秒、分钟、小时或天。
-
-
一旦你概述了恢复计划的参数,你必须设计一个架构解决方案来实现这些目标。假设我们关注的尺度涉及秒级或分钟级粒度,那么你可能需要考虑使用实时只读副本,这样在发生故障时可以接管作为主数据库,或者甚至考虑为超低停机时间的应用部署多主数据库配置。如果我们考虑的是小时或天级别的粒度(在第一个场景下,我们仍然需要这种深度恢复能力),那么一个稳健的增量备份系统就足够了。我们可以通过详细列出系统可能遭遇的压力点来测试我们的弹性架构,比如数据库实例的故障或整个云区域的宕机。接着,我们制定在这些压力点发生时系统的响应,并根据需要对架构进行调整。这里有一个有趣的平行之处,在于我们选择模拟的压力点和我们系统实际的弹性之间。例如,在巴里·奥赖利(Barry O'Reilly)的研究及其随后的著作《Residues: Time, Change, and Uncertainty in Software Architecture》中,他指出,往往我们的压力点并非相互独立;比如,网络故障和海啸摧毁数据中心在架构响应上可能会有相似之处。因此,我们的压力点列表并不需要详尽无遗。我们只需要列出并模拟这些压力点,直到最终的架构不再需要任何变更来支持从这些压力点恢复。
-
一旦我们设计了弹性架构,我们可以开始审查行动计划。行动计划是恢复服务的详细逐步手册;可以将其视为你的弹性架构的用户指南。识别完成操作所需的所有功能性和非功能性要求是至关重要的。以下是一些你可以问自己的好问题:
-
谁将执行操作?
-
他们将从哪里获取凭证?
-
他们将操作的资源标识符是什么?
-
这将对客户产生什么影响?
-
他们需要执行哪些步骤?
-
-
最后的步骤是执行你的行动计划。这个模拟操作可以在较低环境中进行,或者是在生产环境的副本上进行。不过,执行行动计划中的操作以识别文档中任何遗漏是至关重要的。理想情况下,你应该与没有参与设计行动计划的团队成员一起进行此操作。这个过程可以防止团队根据意图而非文档本身来执行操作。你可以根据需要多次进行此操作,以便完善行动计划,直到每个人都感到舒适为止。
演练日
当士兵训练备战时,他们不会仅仅在课堂上或者通过阅读大量可能已经过时的文档来进行。准备工作的核心部分来自模拟真实世界场景的训练活动。这个制度意味着,当他们响应情况时,他们不仅知道该做什么,理论上能知道如何应对;他们还具备了实际的知识。你的团队也应该类似地练习应对事件,使用接近真实世界场景的条件。
任何演练日的第一阶段都是规划。开始时,演练日应该有明确定义的范围和边界,以确保场景的安全性。你最不希望看到的就是假设的事件响应变成实际事件!规划应包括测试特定行动计划的场景。这些场景可以尽可能真实或虚拟,而你在设计架构时的压力测试列表可能是一个很好的起点。以下是我最喜欢的一些:
-
一位权限过多的高级工程师(这是不是让你想起了第六章?)有生产数据库的访问权限。他们不小心删除了我们的一个表。我们如何恢复数据?
-
你的数据库需要进行关键的安全更新,这需要重新启动数据库。你如何确保持续性?
-
有人计划删除 Blob 存储加密密钥。我们发现了吗?我们如何防止它?
即使这些场景可能是虚拟的,使用的工具和流程也应该与我们在实际事件中使用的相同。响应应该尽可能接近真实世界所需的响应。
记得我们在制定计划时定义的那些 RTO 和 RPO 目标吗?比赛日是检验这些目标的完美试金石。在活动开始之前,每个人都应该清楚这些目标,截止日期应该得到执行,理想情况下,达成目标应该有激励措施。
比赛日是促进团队间沟通并打破业务内部壁垒的好方法。要让所有受影响的团队参与,甚至是非技术团队。销售团队在缺少数据的情况下如何操作?市场营销团队需要发布声明吗?实际事件的影响往往超出了技术团队的范围,为什么不利用模拟事件来管理整个响应过程呢?你的技术团队可能需要更多仅限技术的比赛日,但全方位的比赛日对于测试整个业务的韧性非常有帮助。
执行比赛日是有趣的:设置你的模拟场景,告知运营团队当前的情况,然后观察他们执行恢复策略。在他们开始执行之前,确保团队了解比赛日的范围和边界,以避免我们之前提到的后果。在测试事件响应时,应该记录团队的行动。这个过程可以帮助你发现现有行动计划中的空白,并为未来的比赛日或实际事件进行优化。
这个过程之后应该进行一次健康且无责备的事后总结,既包括模拟事件(例如,这个理论事件最初是如何发生的?我们如何防止它在现实中发生?),也包括实际响应本身(例如,我们是否达到了 RTO 和 RPO 目标?我们的流程是否高效?)。
我们将在活动后使用执行阶段生成的文档进行赛后回顾。这次回顾可以按照标准的敏捷回顾格式进行:
-
什么地方做得好?
-
什么地方出了问题?
-
我们学到了什么?
-
下一次我们可以做出哪些改进?
我们通常可以将通过回顾提到的要点分为两类:
-
关于恢复计划执行的要点
-
关于比赛日执行本身的要点
两者都很重要,但使用第一组数据来改进你的恢复计划,第二组数据则帮助你在下次举办更好的比赛日!
真实的情况
如果你在实际事件发生时遵循前述建议,响应应该是一个运转良好的机器顺利启动。但这并不意味着你可以免除周围的责任。你仍然需要做以下事项:
-
按照流程执行
-
记录所有采取的行动
-
尝试达到 RTO 和 RPO 目标
-
进行事后总结和回顾
你将(希望!)很少有机会真正执行恢复计划,因此,这将是你获得最有价值数据的时刻。
手动数据摄取
当与其他工程师讨论他们在编写代码时遇到的问题时,他们经常会说计算机没有按照他们的意愿执行。我的答案通常是相同的:“计算机将会按照你告诉它的方式执行。”有一个古老的笑话很好地说明了这一点。一个程序员的伴侣要求他们去商店买一条面包,如果他们有鸡蛋,就拿一打。程序员带着一打面包回来。当被问及原因时,他们回答说:“噢,他们有鸡蛋。”计算机是字面的,但是当你最终让计算机表现出你想要的行为时,好消息是它将无限精确地执行这些动作,除非有外部影响。不利之处在于计算机在我们未预测到的行动方面表现不佳。另一方面,人类已经进化到擅长在我们未预料到的情况下表现出色。然而,你失去了计算机的完美执行标准。
这与数据有什么关系?如果我们希望我们的数据每次都以相同的方式被摄入,你会选择什么?一个可能能够即时处理边缘情况的不可靠人类,还是一个在相同输入情况下始终产生相同输出的远不那么容易出错的自动化系统?
第一个数据摄入管道
转向自动化数据摄入系统的第一阶段是定义顺利路径。我们在讨论合成数据时讨论过这个概念。如果你的所有数据都是完美的,你希望系统如何运行?这允许您将完美的数据输入系统并获得完美的结果。在理想的世界中,我们永远不需要超越这个状态。根据我的经验,我从未遇到过符合完美标准的数据源。因此,让我们开始推送数据通过我们的管道,如果我们的数据不符合我们的完美标准,我们可以在问题出现时处理这些问题。这可能涉及从源数据集中删除无效记录或操作数据以满足我们的完美数据标准。
这使我们能够兼顾两者的优势。我们的自动化系统处理所有格式良好的数据以生成确定性结果,而当计算机系统无法处理记录时,我们的人类操作员可以介入。这允许人类成员在需要时行使判断力,以确保所有记录都被正确摄入。然而,这种设置仍然存在一个关键问题:云服务可以快速摄入我们的数据,每秒处理数百万条记录。另一方面,虽然更为灵活,但人类的操作速度则极为缓慢。
失败的粒度
在数据摄入时,我们希望确保选择适合我们数据摄入管道的正确失败粒度。一种简单的方法是在遇到错误时立即失败管道。随着数据集的增长和摄入管道变得更加复杂,管道不经历故障的可能性迅速接近零。根据我的经验,数据管道通过全有或全无的方法提供价值的情况很少见。
通常,即使是不完整的数据集也比没有数据具有更大的价值,这就是这种简单方法的局限所在。在这里至关重要的是考虑你的失败粒度。这意味着我们需要找出数据的最小单元,在发生错误时变得不可用。这可能意味着我们在数据集中失败了单个文件、行/列或单元格。通过将失败限制在最小的非功能数据单元上,我们仍然可以利用数据集进行其他目的,收集失败的数据单元,然后异步处理这些故障,通过人类判断处理这些边缘情况,随着时间的推移增强数据集。
这可能包括一个自动预过滤阶段,用于确定数据是否符合我们的规范。符合规范的记录将被传递到我们的数据摄入管道,而不符合规范的记录将被传递到死信队列进行后续分析。
扩展管道
人力进行平凡任务的成本始终是最昂贵的。与时间、成本和培训新资源的需求相关联。随着云原生服务的采用,我们甚至几乎不需要动一根手指来增加我们的吞吐量。事实上,通过自动扩展,甚至那些少数的鼠标点击和键盘敲击也可能是多余的!
一旦初始管道建立完成,死信队列就成为一个宝贵的资源。随着我们修复死信队列中的数据问题,我们了解到我们预期在数据中看到的问题类型。通过分析我们的具有领域知识的人类专家如何纠正这个问题,我们可以开始为这些情况提供边缘案例的自动化,将他们的知识编码成指令,供我们的管道执行。随着管道的扩展,这种自动化使其提高了韧性,允许我们适应新问题,并需要他们的专业知识。
自动化这些情况还允许我们增加数据的实时性。我们不再需要等待人类在检测到错误后来修正这些错误,我们已经扩展了我们的规范,包括这些类型的数据。
转向流式处理
随着我们的管道变得越来越自动化,如果我们的上游数据源支持,我们可以增加数据摄取的频率,使其更接近实时。与每周一次的人工摄取过程(由于人力限制)不同,我们可以将管道的运行频率提高得多。我们已经看到客户通过这个过程实现了从每月数据摄取到每小时数据摄取的转变。
最终阶段不再是一个按计划驱动的过程,按计划提取一段时间内所有发生的数据,而是转向流式模型,在新数据出现时启动数据摄取管道。在这个领域使用云原生服务的优势在于,通常你已经创建的定时管道可以以最小的修改作为流式管道运行。
数据传输错误无可观察性
我会重复这本书中无数次提到的箴言:“你无法修复你无法衡量的东西。” 同样适用于数据传输。你需要能够查看数据传输的状态,以便根据已有的数据做出明智的决策。可观察性方法由用户决定,但重要的是要注意,单纯获取可观察性数据只是成功的一半。另一半是将数据展示给那些最能影响你数据管道质量的人。
数据完整性依赖性
让我举一个我们在客户中常常看到的假设场景。你有一个成功的应用程序,并且有一个出色的开发团队。为了更好地了解你的客户,你成立了一个新的数据团队来追踪用户如何与应用互动。为此,你的开发人员迅速将一些云原生数据管道工具拼凑在一起,供数据团队使用。然而,数据团队由于数据质量差,进展缓慢,花费过多时间将数据整理到可用状态。这导致数据团队因缺乏时间和优质数据而效率低下。开发团队只是把数据“扔”给数据团队,让他们应对后果。开发团队是数据的受益者,因为他们将是使用数据团队生产的数据信息来更好地理解他们所构建内容的人。在这里,我们看到了一种二分法:数据团队很少是数据的受益者,但他们却需要确保数据是正确的,以证明他们在做他们的工作。
反转依赖关系
我之前为一位客户工作,这家公司有一个非常庞大的(非软件)工程职能。这些工程师的任务是确保特定的安全参数得以满足。其中一部分工作包括从现场获取传感器数据。一名数据工程师负责维护数据管道。这种配置在静态环境下没有问题,但正如我们所有人通过沃尔纳·福格尔所知,“一切都会不断失败。” 发生的情况是,一些传感器、数据记录器甚至网络设备会出现故障并被替换,改变数据的拓扑结构。然后,数据会显示为未被识别,数据工程师会去找负责的工程师,以获取正确的参数来正确地获取数据。在这种情况下,数据工程师并未从数据中受益,而是负责反应性地修复数据。与该客户合作时,我们设计了一个解决方案来监控管道的健康状况,发现不一致之处,并通知负责的工程师数据未能被正确获取。然后,他们可以登录到一个用户界面修复数据拓扑,以便在下次运行时正确获取数据。由于这部分数据的责任由工程师承担,我们注意到,他们不仅反应性地修复了自己负责的数据,还主动去更新拓扑,防止未来的管道故障。我们反转了依赖关系!
这就是在观察性数据上拥有正确视角并授权受益者自行维护的力量。这让我们的数据工程师能够专注于更大的图景,处理数据领域的问题,而不是忙于追赶其他领域的进度。
维护依赖关系
现在,我们已经反转了生产者和消费者之间的数据依赖关系,我们可以开始研究如何保持链路的完整性。随着开发人员的推进,他们很少停下来思考自己所做的更改对更广泛数据生态系统的影响,而他们的数据只是其中的一小部分。应对这一难题的关键通常是通过数据契约。数据契约是一种规范,定义了应用程序将要生成的数据格式。这些规范代表了数据生产者和消费者之间对基础架构的共同理解。如果我们使用一个通用的规范框架,如 JSON Schema,我们可以为数据的一致性添加测试,作为完成定义的一部分。这个定义可以帮助我们识别何时会造成破坏性更改,并提前通知下游用户该架构正在发生变化。
该领域的成熟操作还允许采用更现代的工具,如数据目录。这些目录将使我们能够注册数据及其架构,以便组织中需要的人可以使用它。同样,随着这些新依赖关系的增长,集中跟踪它们是至关重要的,这样我们就能知道在数据合同需要重大变更时,应该通知谁。
因此,现在我们已经清楚地理解了数据可观察性在应对管道故障、预防性行动和将数据服务视为我们应用堆栈中的一等公民方面的重要性。
摘要
云计算为我们管理最重要的资产之一——我们的数据——提供了全新的方式!然而,陷入本章中的反模式不仅可能对你的盈利造成影响,还可能影响数据的持久性、可用性和安全性。通过理解本章中的概念,你将能够顺利导航云原生数据的丛林并构建有效的架构。接下来,我们将看看如何将我们架构的各个部分连接起来。
第九章:连接一切
在云原生环境中,网络在确保应用程序的性能、可扩展性和安全性方面起着关键作用。然而,随着组织接纳云计算,它们常常遇到源自不对称战略和过时实践的挑战。这些挑战表现为反模式——反复出现的问题,破坏了云原生解决方案的有效性。
本章深入探讨了最常见的云原生网络反模式,分析它们的影响,并提供切实可行的见解,以避免它们。通过理解并解决这些问题,组织可以设计出适用于云环境的韧性强、高效且安全的网络架构。
本章涵盖的反模式包括以下内容:
-
忽视延迟和带宽
-
缺乏 DNS 策略
-
单体连接性
-
忽视云原生网络功能
-
零信任应用模式
本章通过探讨这些话题,使您具备识别和减轻这些反模式的知识,从而促进健壮的云原生网络实践。
忽视延迟和带宽
当组织迁移到云端时,网络的角色发生了重大变化。在传统的本地部署中,网络工程师和管理员管理物理硬件、交换机、路由器,以及确保低延迟、冗余和安全所需的精细规划。这种精心编排对于优化性能至关重要。然而,随着公司迁移到云端,网络的焦点从物理基础设施管理转向虚拟化基础设施。这种转变可能导致人们误以为网络变成了次要问题,但实际上,它在云原生环境中仍然至关重要,只是形式不同。这正是忽视延迟和带宽的常见云原生反模式的根源。
焦点从物理硬件转向虚拟化基础设施,要求工程师管理组件,如虚拟专用云(VPCs)、子网、安全组、负载均衡器和服务间通信。尽管物理限制有所减少,但管理跨分布式系统的高效、安全和冗余通信的复杂性依然存在。延迟和带宽问题可能加剧,尤其是在由多个微服务构建的应用程序中,这些服务必须在分布式环境中无缝通信。
在接下来的部分中,我们将探讨如何有效地规划和管理对互联网、本地系统以及第三方服务的连接。这将包括设计稳健、安全的网络架构的见解,以促进无缝集成和可靠通信,无论是将云资源连接到遗留基础设施、外部合作伙伴还是更广泛的公共互联网。
云原生延迟
在 Azure、AWS 和 Google Cloud Platform(GCP)等云环境中,网络延迟指的是数据请求从一个点到另一个点所需的时间。
例如,假设托管在 AWS 上的应用需要从 S3 存储桶中检索数据,那么网络延迟就是请求穿越网络、被处理并返回响应时所产生的延迟。类似地,在 Azure 中,如果你的服务跨越多个区域,例如从东美国到西欧,网络延迟将影响数据在这些区域之间传输所需的时间。让我们以 S3 示例为主,因这是我们最近在一个项目中遇到的延迟问题。我们将以下图示作为该场景的参考:

图 9.1 - AWS 网络架构图
云原生延迟与服务
在一次咨询项目中,一家中型电商公司最近将大量业务迁移到了云端。作为其架构的一部分,他们将大量产品图片、用户生成的内容和交易数据存储在 Amazon S3 中。然而,他们并没有使用 S3 网关端点直接在 VPC 内访问存储,而是将所有 S3 流量通过托管在另一个账户中的出口 VPC 路由。S3 网关端点是 VPC 内的私有连接,允许直接、安全地访问 Amazon S3,而无需经过公共互联网,从而减少延迟并提高安全性。
最初,一切运行良好。网络团队熟悉从本地部署时期的出口 VPC,其中通过特定网络出口路由流量可以实现集中控制和监控。他们认为在云端采用类似的设置也会有所帮助,从而确保对互联网流量有更严格的控制。然而,随着时间的推移,他们开始注意到性能下降。以下是详细描述这些问题的清单:
-
延迟问题变得显而易见,特别是在高峰流量时段
-
用户在浏览大量产品图片时体验到延迟
-
大量数据上传进一步加剧了响应时间问题
-
客户面临图片加载缓慢和事务处理延迟的问题
-
团队没有考虑到应用 VPC 和出口 VPC 之间额外网络跳数的成本
-
每次向 S3 的请求都必须穿越两个 VPC 之间的网络,增加了不必要的延迟
-
数据在到达 S3 之前通过多个网络层路由,增加了延迟
-
由于缺乏网关选项,向 AWS 服务(如 S3)发出的 API 调用被定向到互联网
如果没有 S3 网关端点,它本应允许在 VPC 内部直接与 S3 进行高速连接,那么每次请求都需要绕远路。解决方案简单但有效。通过在其应用程序 VPC 内启用 S3 网关端点,他们可以建立一条直接通向 S3 的路径,消除跨 VPC 流量,且流量将保持在 AWS 账户内,而不是通过互联网。这几乎立刻降低了延迟,性能问题也随之消失。客户体验变得更加流畅和快速,而工程团队也从中学到了云原生网络的复杂性。下图展示了网关端点的使用情况:

图 9.2 - S3 网关端点与 DynamoDB
这是一个代价高昂的疏忽,如果他们考虑到云环境中可用的原生工具,本可以避免。相反,他们无意中引入了一种反模式,依赖于过时的本地网络实践。
跨可用区延迟
向云原生迁移的典型模式出现在连接跨多个云环境或同一云提供商内的可用区(AZs)的资源时,例如 AWS、Azure 区域或 GCP 区。虽然云平台提供分布式基础设施并承诺高可用性,但组织往往低估了当资源在地理上分布时,所面临的延迟和带宽挑战。请注意,地理分布也意味着跨区域内的多个可用区。
以 AWS 中的典型区域为例。你可能有 3-5 个不同的 AZ(可用区),每个 AZ 都是跨不同位置的数据中心的组合。这提高了容错性,但这些区域之间的延迟比同一区域内的服务/应用之间的延迟要高。
此外,当服务跨区域或可用区进行通信时,数据传输成本可能迅速上升,导致意外的财务负担。这个反模式反映了云原生架构中的一个根本性疏忽,即组织在关注多可用区冗余或跨云集成时,没有考虑到网络的性能和成本影响。

图 9.3 - AWS 可用区示例
在设计跨多个可用区或区域的架构时,考虑带宽限制并优化低延迟交互至关重要。区域内网络已经逻辑上进行了优化,以确保效率和性能,但由于地理分布支持本地化的高可用性,它始终面临固有的物理限制。你可以采取以下措施来解决此问题:
-
在相同的冗余平面上构建你的私有、数据和公共网络层。如果数据资源位于 AZ A,那么与其交互的其他层也应位于同一可用区。
-
在构建时考虑到高可用性(HA)时,要考虑跨可用区的延迟。
-
考虑高性能计算的延迟权衡,因为 高可用性 并不意味着高性能。
云原生带宽
在云原生环境中,带宽限制可能会显著影响应用程序的性能,尤其是当服务扩展或分布在多个区域时。尽管云服务对基础设施进行了抽象化,但带宽限制仍然存在。忽视这些限制可能会导致性能瓶颈,尤其是在高流量或数据密集型场景中。
带宽限制在扩展应用程序或管理大量数据时必须谨慎处理。例如,在三大云服务提供商(AWS、GCP 和 Azure)中,像 EC2 和 RDS 这样的服务根据实例类型存在带宽限制。较小的 EC2 实例,如 t2.micro 或 t3.small,相比于较大的实例如 m6a.large 或 c6a.xlarge,提供的网络带宽显著较低。跨区域或甚至跨 AZ 的数据传输可能会加剧延迟并引入额外的带宽瓶颈。
在 Azure 和 GCP 中也存在类似的带宽限制。
模糊性 - 导致延迟和带宽问题的原因
正如我们之前探讨的那样,在云环境中选择实例类型比传统的本地环境更为关键。云中可用的灵活性和种类繁多的选项既是福祉也是挑战。例如,选择 AWS 上适用于 Kubernetes 节点的实例类型,该节点需要四个核心和八个 gigabytes 的内存。乍一看,似乎我们有太多的选择。
快速查看 AWS 定价计算器可以看到至少有 10 种潜在的实例类型,每种实例提供不同的网络速度、内存分配和定价组合。以下是其中的一个示例:

图 9.4 - 来自 AWS 定价计算器的摘录
然而,真正的挑战在于确定哪个实例最适合您的具体使用案例。是选择 c6g.xlarge,它成本效益高并且仍能提供最多 10 Gbps 的网络吞吐量?还是选择更强大的 c7g.xlarge?这不仅仅是衡量性能与成本的问题。更深层次的考虑是您的应用程序是否能够在 ARM 处理器上运行,后者都采用了 AWS 的 Graviton ARM 芯片,尽管它们提供了令人印象深刻的性能提升,但可能并不适用于所有工作负载。
除了处理器兼容性,其他技术规格,如网络带宽和 CPU 架构,也需要深思熟虑。这些细节不仅仅是抽象的数字,它们直接影响应用程序的性能和可扩展性。
随着我们从本地基础设施迁移到云端,选择合适实例类型的艺术变得至关重要,这种计算选择也扩展到其他云服务。
超越虚拟机 - 容器和无服务器的带宽限制
必须认识到,带宽限制不仅仅局限于虚拟机。容器化服务和无服务器架构也可能遭遇带宽瓶颈,严重影响云原生环境中的应用程序性能。尽管基础设施管理被抽象化,像 AWS Fargate 和 Google Cloud Run 这样的服务仍然会对网络带宽施加限制,开发人员在设计可扩展的分布式系统时必须考虑这一点。
例如,AWS Lambda 是一个无服务器计算服务,也面临着可能影响应用程序的带宽限制。虽然 Lambda 抽象了服务器基础设施,但它的网络仍然面临吞吐量限制,尤其是在处理像 S3、DynamoDB 或外部 API 之间的大量数据传输时。如果忽略这些限制,可能会导致无服务器应用程序的性能下降,这类应用程序高度依赖服务之间快速、无缝的通信。以下是一些需要考虑的具体要点:
-
Lambda 中的 VPC 网络:当 Lambda 函数配置为在 VPC 内运行时,由于 VPC 的网络配置和吞吐量限制,它可能会面临增加的延迟和带宽限制。Lambda 的独特之处在于,内存分配越高,后台 CPU 的数量和网络带宽也越高。具体而言,CPU 越多,可用的弹性网络接口的完整带宽也越大。
-
冷启动延迟:尽管冷启动与带宽直接无关,但 Lambda 冷启动可能间接影响应用程序处理请求的速度,尤其是在高负载下,可能会加剧初次调用时的带宽瓶颈。
-
S3 和 Lambda 的数据传输:S3 和 Lambda 之间的大规模数据传输可能会遇到带宽限制,尤其是在处理大文件或高并发时,可能导致执行时间变慢或限制。还需要注意 Lambda 的无服务器限制,包括 6MB 的同步限制和 20MB 的响应大小限制。
-
外部 API 的出站带宽:当 Lambda 函数与 AWS 生态系统外的外部 API 或服务进行交互时,如果数据传输速率超过限制,带宽约束可能会增加响应时间,甚至导致超时。
随着云原生架构变得越来越复杂和分布式,带宽问题不能被忽视。从虚拟机到容器再到无服务器函数,云基础设施的所有层级都面临带宽限制,这些限制可能会引发意想不到的瓶颈。忽视这些限制是一个常见的反模式,可能会显著降低性能,并导致无法预见的成本,特别是在高流量环境或处理大量数据的应用程序中。通过主动解决带宽约束,并在设计架构时考虑这些限制,组织可以确保其云原生解决方案在性能和可扩展性方面得到优化。
在三大云服务提供商中,未考虑这些限制条件设计的应用可能会面临高延迟、数据瓶颈和成本增加的问题。云原生架构必须考虑这些因素,以避免与带宽和延迟相关的常见反模式。接下来的部分将向我们展示如何避免忽视延迟和带宽的陷阱。我们的下一节将深入探讨缺乏 DNS 策略的问题。
缺乏 DNS 策略
“问题不在于 DNS,
绝对不是 DNS 问题,
问题的根源是 DNS。”
这首现在非常著名的俳句完美地捕捉了现代网络中最被忽视的一个方面的沮丧与讽刺:DNS。DNS 常被视为一项简单的服务,但它是那些在出问题时才引起关注的关键组件之一。在云原生环境中,服务、系统和应用依赖动态和分布式架构,DNS 问题很快会演变成重大的停机、性能瓶颈或安全漏洞。然而,许多组织将 DNS 视为事后的考虑。
不一致的 DNS 管理反模式是一种无声的破坏者。向云原生架构转型的组织,往往会继承一种碎片化的 DNS 处理方式。由于存在遗留系统、混合环境和第三方服务,DNS 策略变得支离破碎,难以协调。这导致了不可预测的问题:解析时间慢、延迟增加、以及系统在不同基础设施间连接时产生的间歇性故障。
在云原生领域,这是一种灾难性的设计。不论服务是托管在本地还是云中,缺乏统一的 DNS 策略都可能使即便是设计良好的应用程序也变得不稳定。问题会在涉及外部服务时变得更加复杂,形成一张错综复杂的 DNS 解析路径网络,可能会延迟通信、引入安全风险,或导致服务故障。
本节将探讨缺乏 DNS 策略的原因及其后果,并提供制定统一且具弹性的 DNS 策略的指南。我们将讨论以下内容:
-
云原生 DNS 管理
-
混合环境
-
第三方集成
-
削弱流量隔离(QoS)
-
为高性能主链路配置低性能备份链路:备份链路上 QoS 的考虑
云原生 DNS 管理
在云原生架构中,DNS 不再仅仅是将域名映射到 IP 地址,它变得至关重要,关系到服务如何发现彼此、流量如何高效路由,以及如何在网络中构建弹性。然而,云原生环境的复杂性以及快速部署新服务的便利,如果管理不当,DNS 很快就会变成一团乱麻。
在云原生环境中,诸如 Amazon Route 53、Azure DNS 和 GCP Cloud DNS 等服务提供了专为云原生用例设计的高可扩展性 DNS 服务。这些服务使得 VM 实例、负载均衡器、API 网关和外部端点的路由更加快速、可靠。当管理得当时,它们能够确保服务的低延迟访问、无缝故障转移以及跨区域的冗余。然而,当 DNS 配置出现碎片化时,即使在云原生环境中,也可能导致严重的性能和连接问题。这些问题及其最终解决方案将在以下示例中讨论。
云原生和本地 DNS
我们在与一位金融科技客户合作时遇到了类似的情况,该客户使用 Amazon Route 53 来管理他们的云原生微服务的 DNS。最初,一切运作顺利,但随着他们的基础设施扩展,他们开始整合需要协调云环境和本地系统之间的服务。这家金融科技公司为管理内部域名实施了独立的 DNS 区域,Route 53 负责云原生服务,Active Directory (AD) DNS 管理他们的本地资源。然而,未能制定统一的 DNS 策略,导致两者系统之间的 DNS 记录不一致。
随着流量的增加,这些冲突的 DNS 配置成为了问题。服务开始失败,不是因为应用程序问题,而是因为冲突的 DNS 设置无法处理云环境和本地环境之间的正确流量路由。缺乏集中化的 DNS 策略导致了解决内部服务时的延迟,造成超时并降低了用户体验。碎片化的 DNS 管理方法导致了流量错误路由和不必要的延迟,影响了关键的金融操作。
在 AD 和 Route 53 之间的碎片化 DNS 管理导致了查询延迟、不一致的路由和连接中断。服务变慢,造成延迟峰值和中断,且需要花费大量时间进行故障排除。问题的根源?环境中的 DNS 设置不稳定且缺乏协调。
克服冲突的 DNS
最终,组织通过使用 Route 53 Resolver 解决了这个问题,这是一项旨在弥合本地和云原生 DNS 环境之间的服务。Route 53 Resolver 使他们能够将 DNS 查询从 AWS 环境转发到他们的本地 AD DNS 服务器。DNS 转发规则创建了一个无缝的 DNS 查询流,使得云服务可以解析本地域名,反之亦然。这种方法消除了需要并行 DNS 系统的需求,将 DNS 解析集中在一个统一的架构下。
Route 53 Resolver 的引入将他们的 DNS 设置转变为一个统一的系统,利用了适当的混合模型。内部应用现在可以解析云原生和本地域名,而不再受到管理分散带来的延迟或冲突的影响。通过整合 DNS 策略、将 AWS 目录服务与 Route 53 集成,并利用 Route 53 Resolver,他们确保了 DNS 解析在所有环境中都是一致、快速和可靠的。解决方案的简化版如下所示:

图 9.5 - 混合 DNS 解析器
下一部分将扩展讨论这一点,重点关注混合环境和 QoS。
基于应用/数据关键性的流量隔离(QoS)被削弱
云原生架构中一个被忽视的重要方面是根据应用和数据的关键性进行流量隔离。并非系统中的所有流量都是相同的;有些工作负载需要高优先级、低延迟的通信,而其他则可以容忍较慢的处理时间。这个概念是服务质量(QoS)的基础,它根据流量对业务操作的重要性来进行优先级排序。不幸的是,在云原生部署中,一个常见的反模式就是没有实施足够的流量隔离,导致性能下降、未能满足服务水平协议(SLA)以及不必要的资源消耗。
在传统网络中,QoS 策略通常根据流量的类型和重要性进行优先级排序。例如,关键应用(如实时金融交易、视频会议或数据库复制)会被优先处理。与此同时,非关键任务(如备份、大批量文件传输或常规更新)则被分配较低的优先级。然而,在云原生环境中,这种做法常常被忽视。如果没有适当的 QoS 实施,所有流量将被视为平等,这会导致当高优先级服务必须与低优先级服务争夺带宽和计算资源时,出现严重问题。
忽视流量隔离的成本——一个金融科技案例研究
在与一家大型金融科技公司进行咨询时,我们遇到了一个典型的例子,展示了在云环境中未能实施适当流量隔离的陷阱。该公司将实时交易处理和夜间数据备份一起运行,且都使用相同的共享云基础设施。最初,一切似乎运转正常,但随着交易量的增加,网络压力也随之增大。
缺乏结构化流量优先级策略意味着他们的备份操作(安排在高峰时段)消耗了大量可用带宽。这种干扰导致实时财务交易的延迟,导致未能达成服务水平协议(SLA),并引发客户不满。在此情境下,强有力的 QoS 策略的必要性变得显而易见。通过适当的流量隔离和优先级排序,我们确保了关键服务,例如实时交易处理,总是优先于不那么紧急的任务(如夜间备份)。通过隔离带宽占用大的操作,并根据服务的关键性分配资源,我们帮助他们完全避免了这些延迟。
未能根据关键性隔离流量的风险
当忽视基于应用或数据关键性进行流量隔离时,组织面临多个风险,包括以下几点:
-
关键应用的性能下降:业务关键型应用,如实时财务交易或敏感数据传输,如果不得不与非关键流量争夺带宽,可能会遇到延迟或性能问题。
-
错失 SLA:在以正常运行时间、速度和可靠性为关键绩效指标的环境中,未能隔离流量可能导致错失 SLA,从而导致处罚或声誉损害。
-
资源争用:对所有流量进行平等处理可能导致资源争用,关键进程可能因带宽或计算能力不足而无法获得足够的资源,而不重要的任务却占用不必要的资源。
-
安全风险:某些数据流,如涉及敏感财务或个人信息的流量,不仅因为性能原因需要隔离,也为了安全考虑。未能隔离这些流量可能会使关键数据暴露于漏洞之中。
最佳实践:流量隔离和 QoS
为避免削弱流量隔离的反模式,组织应实施适合其云原生基础设施的结构化 QoS 策略:
| 最佳实践 | 描述 |
|---|---|
| 根据关键性优先处理流量 | 根据流量对业务运营的重要性进行定义和分类。对延迟敏感或关键任务的流量应优先于不紧急的进程。 |
| 使用网络分段 | 实施虚拟网络分段(例如,VPC 或子网)以按优先级隔离流量,确保高优先级流量不与低优先级流量争用带宽。 |
| 利用云原生 QoS 工具 | 使用云服务提供商的工具,如亚马逊流量镜像、带宽控制、Azure 流量管理器和谷歌云网络服务层,来管理和优化流量流动。 |
| 监控并调整 QoS 策略 | 定期监控 QoS 策略的性能,并根据工作负载变化进行调整,以保持最佳性能。 |
| 考虑多云和混合架构 | 确保在多云或混合环境中实施一致的 QoS 策略,以防止瓶颈并保持本地和云基础设施之间的性能。 |
表 9.1 - QoS 最佳实践
云原生架构中的一个常见反模式是依赖低性能的备份链路来支持高性能的主链路,而没有考虑在故障切换过程中 QoS(服务质量)如何运行。许多设置中备份链路作为一种节省成本的措施实施,通常设计时带有较低的带宽和减少的功能。
然而,如果主高性能链路出现故障,关键应用和数据流将被迫切换到这些较慢的链路上,这可能导致严重的性能下降、延迟增加和服务中断。如果没有为这些备份链路配置适当的 QoS 策略,问题可能会加剧,因为在故障切换期间,关键流量可能不会被优先处理,进一步降低用户体验。
备份链路 QoS 的关键考虑因素
为了减轻这些风险,至关重要的是像主链路一样仔细规划备份链路,确保它们在发生故障切换时能够处理最关键的流量。适当配置的 QoS 可以确保在容量减少的情况下,重要服务保持优先级,并以最小的干扰运行。为了确保一致性,定期检查和通过备份链路进行测试的应用程序至关重要。未经测试的备份链路应视为不活动,直到经过某种周期性的测试。以下几点强调了如何处理备份链路:
-
在故障切换期间优先处理关键流量:实施 QoS 策略,确保高优先级流量(如事务数据或实时服务)在备份链路上优先于不太关键的流量。
-
定期测试备份链路的容量:定期测试备份链路的性能,确保它们能够在故障切换场景中处理关键流量负载而不会出现显著的性能下降。
-
根据需求扩展备份链路:确保备份链路可以适当扩展,以处理最关键的工作负载,即使它们无法与主链路的完整容量匹配。
-
监控链路性能:持续监控主链路和备份链路,确保 QoS 策略按预期工作,并在故障切换事件期间高效地路由流量。
-
评估成本与性能的权衡:在节省成本与关键应用性能要求之间找到平衡。备份链路配置不足可能会减少成本,但在停机期间可能会对业务连续性造成不可接受的风险。
通过适当规划和仔细配置备份链路及其 QoS 策略,可以帮助确保故障切换时的平稳过渡,保持关键应用的性能,并维持业务连续性。
在云原生环境中,未能根据应用和数据的关键性实现流量隔离是一种严重的反模式,可能会削弱系统性能、增加延迟,并危及关键服务的可靠性。通过建立强健的 QoS 策略,优先考虑高价值工作负载,组织可以确保其云原生应用具有弹性、响应能力,并能够满足最苛刻的业务需求。
单体式连接
我们简要讨论了网络工程师和系统管理员在管理本地硬件(如交换机、路由器等)方面的角色;伴随这种思维模式而来的是传统数据中心的网络规划方式。个别硬件组件成为整个网络的单点故障,如果核心交换机发生故障,整个网络堆栈也会崩溃。云原生模型的网络设置与传统组织数据中心的网络设置有很大不同;传统数据中心模型可能会在以下几方面设置其子网和网络层:
-
核心:网络的主干部分,负责核心交换机
-
分发层:位于核心层之间,负责处理网络策略/安全性
-
接入层:服务器、存储阵列以及从管理员视角看见的典型网络
附图提供了更详细的说明,帮助更清楚地理解这一概念。

图 9.6 - 三层传统网络
子网划分在三个网络层中管理方式不同,以下表格详细说明了这一点:
| 网络层 | 子网划分方法 | 功能 和焦点 |
|---|---|---|
| 核心层 | 最小子网划分 | 作为其他层之间的高速互联,优先考虑性能而非分段 |
| 分发层 | 大规模子网划分以支持多样化需求 | 处理光纤通道、防火墙和层间流量监控,需要灵活性和控制 |
| 接入层 | 传统子网划分方法 | 支持日常网络设置,根据用户和设备定制子网划分 |
表 9.2 - 跨网络层的子网划分
单体式云原生摩擦
虽然核心层依然专注于高速互联,但它可能会利用虚拟化网络解决方案,减少对物理基础设施的依赖,使得子网划分更加简化和灵活。在云原生环境下,分发层变得高度动态,子网划分用于管理 VPC、安防组和服务网格,控制跨多个区域或可用区之间的服务、存储和防火墙流量。同时,接入层则转向整合可扩展的资源,如容器化工作负载,传统的子网划分方法被自动化的、软件定义的网络解决方案所取代,能够根据工作负载需求动态调整。
在理想的情况下,过渡到云原生环境的组织应该摒弃老旧数据中心的限制。然而,实际上,常常发生的情况是,传统的网络模型仅仅是被直接迁移到云中。这就导致了一个常见的反模式,即将过时的做法应用于现代架构。结果就是,系统受限于这些限制,无法释放云原生基础设施的真正潜力。
本节将探讨云原生环境如何从单体连接模式过渡到 OSI 层级的分层故障转移策略。我们将重点关注同步流量与异步流量的挑战、减少单点故障以及配置数据包检查,以满足云原生架构的独特需求。
从单体到分层网络
单体连接,是遗留系统中的一个常见反模式,依赖于紧密耦合的单层网络设计,在这种设计中,所有应用组件都在内部进行通信,通常没有清晰的分离或隔离。虽然这种模型可能适用于较小的自包含应用程序,但它难以满足现代云原生环境的需求,这些环境优先考虑扩展性、灵活性和弹性。
过渡到云原生架构的组织采用分层网络模型,将服务和组件分开。这种方法与微服务密切对接,其中每个服务独立运行并通过明确定义的网络层进行通信。通过摆脱单体连接,转向更模块化、分层的结构,组织能够解决常见问题,如扩展性不足、故障隔离困难以及安全漏洞等。图 9.1 展示了一个完美的模块化分层网络结构示例,多个私有子网在 VPC 内被隔离开来。
分层网络
云原生环境中的分层网络引入了不同的层级,每个层级都有特定的目的。这种分层增强了控制力,根据功能、优先级或安全需求将服务隔离。例如,前端服务可以放置在一个网络层中,而后端服务(如数据库或内部 API)则位于另一个层级中。通过这种分层方法,可以通过限制对关键服务的直接访问来提高扩展性和安全性。通过应用网络策略,组织可以确保只有授权的服务可以跨层进行通信,从而减少在安全漏洞发生时横向移动的风险。
此外,分层网络支持服务的独立扩展。在单体架构中,扩展通常意味着复制整个应用程序,这可能会消耗大量资源并且效率低下。相比之下,分层架构允许根据流量和性能需求独立扩展各个服务。这种灵活性确保了资源的有效利用,并允许组织迅速适应不断变化的工作负载。以下表格详细描述了分层网络方法的好处:
| 方面 | 单体连接性 | 分层网络(云原生)** |
|---|---|---|
| 可伸缩性 | 扩展需要复制整个单体应用 | 独立服务可以单独扩展,减少资源使用 |
| 安全性 | 所有组件在同一网络层内自由通信,存在潜在的安全风险 | 服务有明确的分离,有助于更好的安全策略和隔离 |
| 弹性 | 一个系统部分的失败可能会导致整个应用崩溃 | 隔离的服务减少了故障的影响范围,增强了弹性 |
| 灵活性 | 很难修改或添加服务而不影响整个系统 | 可以添加、修改或替换服务,而不影响整体架构 |
| 网络流量控制 | 没有明确的流量分割;所有流量在组件之间自由流动 | 基于服务层次进行流量分割,有助于更好地管理和监控流量 |
| 开发速度 | 更改需要完整的应用程序测试和部署 | 可以独立更新和部署各个服务 |
表 9.3 - 分层网络的好处
单体到微服务 - 以网络为重点的示例
在与政府客户的咨询中,我们被委托解决他们从单体架构向云原生环境过渡的重要网络挑战。公司的原始网络设计缺乏分割,所有服务、前端应用程序、数据库和内部 API 都驻留在一个单一的扁平网络中。这种设置导致了许多问题,包括流量流动效率低下、安全漏洞以及由于子网范围有限而产生的 IP 分配挑战。
他们的单体网络架构使得基于功能或安全需求隔离服务变得困难。所有流量都通过同一网络流动,暴露了关键的后端服务(如数据库)面临不必要的风险。没有适当的网络分割,系统中的任何漏洞都可能迅速横向扩散,可能会危及敏感数据。此外,随着对其平台的流量增加,扩展需要复制整个系统,包括不需要扩展的组件。这种方法既消耗资源又低效。
方法 - 三层网络
我们在 AWS 上引入了分层网络模型,遵循三层能力,以规范和控制其云原生基础设施。该模型的部署如下:
-
展示 层(前端):
-
目的:处理用户请求和公共流量,主要涉及面向用户的组件,如 Web 服务器或 API。
-
实施:将前端服务放置在 AWS VPC 的公共子网中,可以从互联网访问。
-
安全性:使用安全组和Web 应用防火墙(WAFs)保护系统免受外部威胁,同时允许进入的 Web 流量或负载均衡器流量。
-
-
应用层(业务逻辑):
-
目的:处理业务逻辑,前端与后端之间的通信。此层托管内部服务、API 或微服务。
-
实施:将应用服务部署在私有子网中,将其与互联网直接访问隔离,同时允许它们与前端和后端层进行通信。
-
安全性:使用安全组控制哪些前端服务可以与应用层通信,确保只有授权流量在这些层之间流动。通过安全组引用限制了 Kubernetes Pod 之间的访问,消除了 IP 欺骗作为攻击向量。
-
-
数据 层(后端):
-
目的:存储和管理数据,如数据库和内部 API,这些数据必须安全并且隔离。
-
实施:将数据库和其他后端服务放置在一个独立的私有子网中,并实施严格的访问控制,确保只有应用层可以访问它。
-
安全性:实施 VPC 网关端点来限制访问,并配置网络访问控制列表(NACLs)进一步限制来自其他子网的未经授权访问。
-
在这里的三层架构基础上,我们将所有三层分布到多个可用区(AZ);这一架构显著提高了系统的韧性和可扩展性,使得即使某个区域完全离线,应用也能继续运行。当创建一个 AZ 时,应用会扩展到其他区域,流量会自动导向新的节点。可用区(AZs)是 AWS 区域内独立的地理位置,每个区域都有独立的电力、网络和冷却系统。与传统的两个数据中心相比,它们提供了更高的韧性,因为它们地理位置分离但紧密互联;这还包括完全冗余的专用光纤线路。这确保了即使某个区域因局部问题发生故障,其他区域也能继续运行,不会影响性能。在解决同步和异步流量时,这种多 AZ 设计的优势得到了最佳发挥。
同步与异步流量
云原生架构从根本上改变了服务之间的流量和通信处理方式。传统环境中的一个重大挑战是管理同步与异步流量,随着系统复杂度和需求的增长,这可能会成为瓶颈。传统组织的服务通常依赖于同步通信,意味着一个服务必须等待另一个服务的响应才能继续。这种方法可能导致低效、高延迟以及潜在的故障点,尤其是在分布式环境中,网络问题或服务延迟可能会导致整个流程停止。
相比之下,云原生架构设计上更倾向于采用异步通信。这一转变解决了传统架构中常见的反模式,即系统紧密耦合并依赖于实时的同步响应。这些传统系统在高负载或服务出现延迟时容易发生故障,导致超时、失败和弹性下降。让我们来看看云原生环境中异步流量的好处。
云原生中的异步流量关键优势
以下优势突出了异步流量对云原生应用至关重要的原因:
-
增强的弹性:即使系统的某个部分发生延迟或不可用,服务仍然可以继续运行。
-
改进的可扩展性:异步系统可以承载更高的负载,因为它们不要求立即响应,从而减少了高峰流量期间对服务的压力。
-
解耦服务:云原生系统提倡松耦合,使得服务可以独立运行,从而降低级联故障的风险。
-
容错性:通过使用队列和事件驱动模型,系统可以自动重试失败的操作,而不阻塞其他进程。
从强一致性到最终一致性
这一转变的一个关键方面是从强一致性到最终一致性系统的过渡,这使得云原生应用能够优先考虑可用性和容错性,而非即时一致性。通过采用最终一致性,云原生系统可以更有效地处理大规模的分布式工作负载,因为它们不再依赖于整个系统的完美同步。这种方法提高了可扩展性和弹性,即使组件暂时不同步,系统也能平稳运行——这是在高流量、全球分布环境中不可或缺的权衡。
云原生架构通过利用异步通信模型,如消息队列、事件驱动架构和无服务器组件来解决这一挑战。在这些系统中,服务发布事件或发送消息时不等待即时响应。例如,当用户在电子商务平台下订单时,订单可能通过消息队列(例如 Amazon SQS 或 Kafka)异步处理,从而允许前端继续与用户交互,同时后台处理订单。这种解耦提高了应用的韧性,因为一个服务的失败或延迟不会影响整个系统对用户响应或继续运行的能力。
解决单体连接问题
在传统系统中,依赖同步通信会产生紧密耦合的反模式,服务之间过度依赖彼此,必须实时可用才能保证系统正常运行。这引入了脆弱性,因为任何一个组件的延迟或故障都可能影响整个系统。
云原生架构通过推广异步通信来解决这一问题,在这种方式下,服务之间的交互不需要等待即时响应。通过这种方式,反模式被打破,系统变得更加弹性、可扩展,并且能够适应变化。随着组织向云原生迁移,它们能够享受独立扩展单个服务、优雅处理故障以及更高效地处理大量流量的灵活性。这一转变不仅提高了系统的整体性能,还为更加敏捷、适应性强的基础设施奠定了基础,能够随着业务需求的发展而进化。
从单体连接到分层网络的转变中,云原生架构显著提升了可扩展性、安全性和韧性。通过采用分层模型,组织可以摆脱紧密耦合、容易发生单点故障的同步系统。相反,服务被隔离并具备可扩展性,从而提供了更大的灵活性和控制力。通过适当的分段,即使是最复杂的基础设施也能保持高可用性,并且在安全漏洞发生时,横向移动的风险被最小化。这些优势使得云原生方法远远优于传统模型,确保它们在应用扩展时依然保持强健和高效。
接下来,我们将探讨另一个被严重忽视的反模式:忽视云原生网络特性。我们将分析忽视利用内置云功能如何限制性能和安全性,以及如何正确使用这些功能来最大化云原生基础设施的优势。
忽视云原生网络特性
在向云原生架构过渡时,一个最常见的陷阱就是忽视了云平台内置的强大网络功能。在传统的本地环境中,网络通常是以硬件为中心,依赖于物理交换机、路由器和防火墙。这导致在处理更加动态、由软件驱动的云原生网络时,出现了误解和不对称的期望。
本节将探讨在云中未能充分采用软件定义网络(SDN)如何导致性能和弹性问题。我们还将强调通过基础设施即代码(IaC)将网络配置视为代码的重要性,这是成功实施云原生网络的关键实践。还将讨论与不充分的网络边界防护相关的风险,特别是在管理生产环境与非生产环境之间的访问时。
这些领域每个都带来独特的挑战,如果未能妥善应对,可能会限制云原生基础设施的潜力,使组织面临安全漏洞和运营效率低下的风险。
云中的 SDN —— 来自本地环境的风险
SDN 并非仅限于云原生环境;这个概念已经存在一段时间。可以说,像 VMware 这样的公司通过其 VMware NSX 产品将这一概念普及开来,该产品于 2013 年发布,是 SDN 的早期实例,允许对网络基础设施进行虚拟化,从而通过软件而非传统硬件创建、管理和自动化复杂的网络。与从头开始搭建整个服务器机架的硬件不同,像 VMware NSX 这样的 SDN 工具为管理员提供了一个更快的方式,将其网络部署并扩展到新硬件上;云服务商采用这一概念来实现相同目标,而无需硬件组件。传统环境中的 SDN 仍然需要硬件来部署;它只是使模板化变得更加容易。
SDN 在云中蓬勃发展,将控制权从物理硬件转移到基于软件的解决方案。这一转变使得 AWS、Azure 和 GCP 等云提供商能够提供灵活、可扩展且动态的网络解决方案,以适应现代应用程序的需求。以下是 SDN 如何在这些平台上应用的一些关键示例:
-
AWS:Amazon VPC 使得隔离网络成为可能,并提供对路由、防火墙和访问的控制。
-
Azure:Azure VNet 使用 SDN,配合 NSG 和 Azure 防火墙等工具进行流量分段和网络策略自动化。
-
GCP:Google Cloud VPC 使用 SDN 实现可自定义的 IP 范围、防火墙规则和路由,配合 Cloud Armor 和 VPC 对等连接等工具提供安全性和连接性。
在所有三个平台中,SDN 提供了灵活性,可以以编程方式扩展、自动化和管理网络基础设施,使用户能够构建安全、优化的云环境,而无需传统硬件的限制。
云原生网络思维的变化
最常见的云原生反模式之一是,缺乏对云环境中 SDN 的理解,相较于传统的本地硬件设置。对这一点的理解差距常常导致对性能、弹性和整体网络行为的非现实期望,从而导致配置错误,影响系统的可靠性和可扩展性。
在云服务供应商中,常见的误解是,用户期待云网络像传统的硬件基础设施那样运行,其中专用的物理设备决定网络性能和容量。在本地环境中,网络的可靠性直接与硬件的稳健性相关,比如交换机和路由器。然而,AWS 网络,如 Amazon VPC,是完全虚拟化的。性能和弹性取决于子网、安全组和多可用区设置的配置质量。在这个虚拟环境中,配置错误可能导致较差的容错性和性能瓶颈,这与物理硬件环境的期望截然不同。
传统遗留网络迁移到云原生网络——一个案例研究
我们在与银行客户的网络提升合作中遇到了一个典型的配置不当的 AWS 网络设置。然而,当我们提到“配置不当”时,需要认识到,曾经被认为是最佳实践的方案,随着时间的推移和技术的进步,可能会演变成一个次优的解决方案。这个客户在 3-4 年内从本地基础设施迁移到 AWS。最初,他们的网络架构师认为三层 AWS 网络设计过于简单,并认为它为跨域通信和变更管理引入了过多的开销。
与其为每个环境或工作负载设计单独的 VPC,架构师们实现了一种将网络集中到一个共享 VPC 的设计,该 VPC 跨多个账户共享。在这个设计中,子网在不同账户之间共享,从传统网络的角度来看,这似乎是合理的。它类似于集中式核心网络在多个 AWS 账户之间共享访问层的概念。然而,这种方法并没有解决开销问题,反而引入了巨大的复杂性。当需要进行更改或灵活性调整时,任何对 VPC 结构或路由表规则的修改都会影响共享网络中的所有账户。与其构建一个容错、分层的云网络,他们无意中创建了一个伪装成简易的单点故障。这个设计类似于以下内容:

图 9.7 - 共享 VPC 设计
在像银行这样的风险厌恶行业中,这一设计缺陷被加剧了,因为即便是微小的变更也会在变更咨询委员会会议中受到严格审查。结果是一个僵化且脆弱的网络架构,限制了敏捷性并带来了相当大的风险。
我们的解决方案是将共享子网过渡到为每个账户分配独立的 VPC,通过 AWS Transit Gateway 互联。为了保留共享子网设置的优势,我们重新设计了网络,如图 9.1所示。所有外部流量,如互联网和第三方请求,都通过出口 VPC 进行路由,在那里一个安全设备(如 FortiGate 防火墙)会扫描所有外部流量。这消除了使用多个 NAT 网关或实例的需要。每个 VPC 都配置了特定的子网,根据用例启用或限制云原生功能。例如,数据/私有子网仅限于访问 DynamoDB 网关端点,从而确保更严格的安全性,减少不必要的服务访问。
这个重新架构的解决方案的附加好处是更具弹性和分布式的网络设计。现在的变更是账户特定的,显著减少了任何失败修改的影响范围。这个模块化设计确保了任何影响都仅限于单一环境,从而增强了敏捷性和容错性。
正如我们已经提到的变更,这引出了下一节关于网络访问审查不充分和缺失边界保护措施的问题。
网络访问审查不充分和缺失边界保护措施
与传统数据中心不同,传统数据中心的物理边界自然限制了访问,而云基础设施则是动态的,允许更容易的甚至潜在危险的访问升级。如果没有定期和彻底的访问权限审查,用户或系统可能会从非生产或开发系统获得意外访问关键生产环境的权限。这种缺乏监督的情况使得组织容易受到未授权的横向移动攻击,暴露敏感数据和核心系统,带来重大威胁。
缺乏坚实的网络边界防护措施进一步加剧了这些风险。像安全组、防火墙规则和路由表策略等防护措施,对于保持访问在预期环境内至关重要。如果没有这些控制,网络将变得扁平化,允许在各个环境之间无限制地流动,从而增加了数据泄露和不符合行业规定的风险。为了有效地保护云原生环境,组织必须实施严格的访问审查,并执行严格的边界控制,以防止未经授权的访问和权限提升。一种常识性的方法是将资源按环境(例如,对于 AWS)在其所属的组内进行隔离,将生产账户仅用于包含生产网络资源,并且通过任何方式与非生产或测试环境没有连接。以下表格列出了通常发现的风险:
| 风险 | 描述 |
|---|---|
| 访问升级 | 用户从非生产环境获得对生产系统的未经授权的访问 |
| 安全态势薄弱 | 缺乏边界防护措施导致网络结构扁平化,允许未经授权的环境间流动 |
| 增加的攻击面 | 定义不清的边界会创造漏洞,使攻击者可以在网络内横向移动 |
| 合规性违规 | 控制和监督不足可能导致不符合安全和监管标准 |
| 操作风险 | 重叠或配置错误的访问权限可能导致停机、服务中断,最重要的是,破坏合规措施 |
表 9.4 - 网络访问审查不足和缺失边界防护的关键风险
组织可以通过持续的访问审查和强有力的边界防护措施来更好地保护他们的云基础设施,从而确保安全和合规的操作。为了更好地实现之前提到的 IaC(基础设施即代码)和自动化,这些是关键。
IaC 和自动化——网络视角
每个云原生组织的核心是 IaC。你选择的具体工具(Terraform、CloudFormation 或 Azure 资源管理器)比你如何设计和实现它更为重要。每个 IaC 工具既有其不足之处,也有其优点,但真正定义成功方法的是其背后的架构和最佳实践。标准化对跨云原生环境高效的基础设施部署至关重要,尤其是在云网络方面,一致性对于管理多个环境(如开发、测试和生产)至关重要。
如果没有适当的标准化和最佳实践,云基础设施很快就会变得混乱。不同的团队可能以各种方式部署相似的资源,导致低效率、不一致和不必要的复杂性。结果就是一个难以管理且容易出错的系统。标准化不仅仅是保持整洁;它是确保每次部署都遵循可预测、高效的模式,且能够重复和扩展。那么,什么是有效的标准化和最佳实践呢?请考虑以下最佳实践:
-
{environment}-{app}-{resource}-{name}– 例如,prod-banking-aks-node– 帮助保持清晰并避免混淆。 -
可重复的模式:对于重复部署,如在多个环境中设置 Azure 中的 VNet,使用可重用的模块(例如 Terraform 模块或 CDK 函数)。这确保了基础设施部署的一致性,使管理变得更加容易。
-
在部署前进行规划:特别是在网络资源方面,确保基础设施更改可以在不干扰运行环境的情况下进行。一些更改,比如重命名资源,可能会触发替换,进而在更改窗口期间导致关键系统停机,幂等性可以防范此类风险。
-
版本控制:使用 Git 来存储和管理你的 IaC。版本控制可以轻松跟踪更改和回滚,并促进团队间的协作,确保基础设施部署的一致性和可追溯性。
-
自动化部署管道:实施 CI/CD 管道进行基础设施部署,而不是依赖手动、局部的流程。这样可以减少人为错误,确保一致性,并能更好地与版本控制系统集成,便于管理。
通过遵守这些原则,组织可以在云部署的复杂性中带来秩序,确保基础设施具有可扩展性、可维护性和高效性。标准化不仅仅是最佳实践,它是云计算长期成功的基础。以下图示展示了在使用 CI/CD 进行部署时,自动化和标准化管道的简单示例:

图 9.8 - 简单的 IaC 更改、检查和部署管道
在一个高度自动化、IaC 驱动的云原生网络中,路由规则或安全策略的更改是通过脚本化、版本控制并统一部署到各个环境的。这确保了每个环境(无论是开发、测试还是生产)都有一致的网络配置,减少了服务间误通信的风险,并确保了严格的安全控制。相反,在手动管理网络的环境中,任何更改都容易受到人为错误的影响,造成环境之间的差异,可能导致停机或数据泄露。
除了配置错误的风险外,忽视网络自动化会减缓组织的扩展能力。云原生环境要求灵活性,如果没有自动化的网络部署,提供新环境或扩展现有环境将变得耗时且容易出错。团队不得不手动复制网络配置,常常引入不一致性,可能导致服务中断。
零信任应用模式
随着组织从本地部署环境向云原生架构过渡,零信任模型成为他们必须采纳的最关键的安全转变之一。在传统的本地环境中,安全性通常依赖于边界防御;如果你在网络内部,你就被信任。然而,云原生应用程序运行在更为动态、分布式并且可能暴露的环境中。在云中,透明的网络边界不再存在,服务跨越多个区域、多个 VPC,且通常涉及不同的云提供商。正是在这种情况下,零信任作为一个基本的安全框架应运而生,其核心理念是“永不信任, 始终验证”。
从最简单的角度来看,零信任拒绝基于位置或网络所有权的隐式信任概念。相反,它假设每个用户、设备和应用程序在访问资源之前必须持续证明其合法性。零信任的核心原则要求安全性不仅关注外部威胁,还要监控和控制网络内部的访问,防止未经授权的横向移动,并减少攻击面。这在云原生环境中尤其重要,因为工作负载和用户的动态特性需要在每个访问点不断进行验证。
云原生环境与本地部署环境中的零信任
在传统的本地部署环境中,应用程序通常依赖于网络分段和防火墙来定义安全区域,这些区域有时被称为 DMZ(隔离区)。如果应用程序或用户位于企业网络内部,他们通常会被授予对资源的广泛访问权限,且很少受到审查。这种方法被称为隐式信任,存在着很大的漏洞。一旦攻击者获得网络访问权限,他们可以在系统间横向移动,而不会遇到实质性的障碍。传统的本地安全模型往往侧重于防止外部威胁,而不是审查每一个内部交互。
相比之下,云原生环境将每个组件视为不可信实体,无论它是内部微服务、用户还是外部客户端。对于云原生应用,零信任模型与云服务的分布式特性更为契合,因为云环境没有明确的内外边界。应用程序必须验证每一个请求,无论是内部微服务之间的请求、API 调用还是用户访问。
以 AWS 和其最小特权原则的实施为例。其核心原则与零信任一致,确保用户和服务仅获得完成任务所需的权限,绝不多于此。这意味着使用像 AWS 身份与访问管理 (IAM) 这样的服务,精确的策略控制每一项操作。在单个账户或 VPC 中,没有服务或用户是天生可信的。每一项操作都必须经过身份验证和授权,从而最大限度地减少权限提升或滥用的风险。
在 Azure 中,条件访问策略和 Azure Active Directory (AAD) 扮演类似角色,基于动态条件(如用户位置、设备健康状况和行为分析)验证每个访问请求。只有当这些因素与预定义的安全策略一致时,才会授予访问权限。同时,Azure VNet 和 网络安全组 (NSG) 能够实现流量的细粒度分段,确保应用和服务的隔离,并基于严格定义的安全规则控制访问。
在 GCP 中,BeyondCorp 模型通过完全去除隐性信任来实现零信任。Google Cloud 的 身份感知代理 (IAP) 确保每个请求在访问应用时都经过基于用户和设备身份的身份验证、授权和加密。无论流量来自网络的哪个部分,都不假定其可信。
| 原则 | 描述 | 云原生应用示例 |
|---|---|---|
| 永不信任,总是验证 | 每个请求必须进行身份验证、授权和加密,无论来源如何。网络的任何部分都不默认可信,且访问会持续验证。 | 使用 AWS IAM 策略和 AWS Secrets Manager 验证 API 请求、用户登录和服务间通信,确保安全通信 |
| 最小特权 | 强制实施最小访问权限,只授予用户和服务完成任务所需的权限,不多也不少。这限制了被攻破账户或服务可能带来的潜在损害。 | Azure 基于角色的访问控制 (RBAC) 确保云原生应用的最小特权访问,保持内部系统的隔离 |
| 微分段 | 将网络划分为安全的分段,以限制横向移动。在云原生环境中,这通过虚拟网络构件实现,默认情况下会隔离工作负载。 | AWS VPC、Azure VNet 和 Google Cloud VPC 隔离资源,而安全组和 NSG 控制授权流量 |
| 持续监控与审计 | 实时监控和审计环境中的所有交互,检测异常并响应威胁 | AWS CloudTrail、Azure Monitor 和 Google Cloud Operations Suite 提供关于访问模式的实时洞察 |
表 9.5 - 零信任的关键原则
零信任实践 - 一个云原生示例
在与一家金融服务公司进行咨询合作时,我们的任务是为一款部署在多个 AWS 可用区(AZ)上的云原生微服务应用实施零信任架构。每个微服务都作为 AWS Lambda 函数进行部署,API Gateway 作为服务之间的通信层。为了确保强有力的安全性,我们为每次服务调用实现了基于 IAM 的授权,并使用 AWS 签名版本 4 签名为 HTTP 请求添加身份验证详细信息。这种方法确保了对每个 API 的访问得到严格控制,仅限于授权的 IAM 角色进行通信。
我们利用 Amazon Cognito 强制实施用户访问身份验证,为特定数据和应用功能的访问应用细粒度权限。此外,通过使用独立的 VPC 隔离生产和预发布环境之间的网络流量,防止在没有明确授权的情况下直接通信。通过 CloudWatch Logs 和 VPC Flow Logs 进行实时监控,使我们能够追踪网络活动,并迅速标记任何未授权的访问尝试。最后,为了确保微分段,我们使用 PrivateLink 和 VPC 网关端点为客户端提供访问权限。这种全面的方法确保了系统内的所有交互都经过身份验证、授权并进行监控,遵循了云原生架构中至关重要的零信任原则。

图 9.9 - AWS 中零信任应用示例
在这个零信任框架中,应用不仅安全,而且具有适应性,能够在不妥协安全性的情况下进行扩展或部署新服务。这种方法与传统的本地网络模型形成鲜明对比,后者通常假设网络内的信任,在攻击者突破外围后便会产生漏洞。
随着云原生架构在复杂性和规模上的增长,采用零信任应用模式不再是可选项,而是必需的。通过确保默认不信任任何用户、服务或设备,并且每次交互都经过身份验证和授权,组织可以保护其云基础设施免受不断变化的威胁。零信任模型由 AWS、Azure 和 GCP 等云原生工具支持,有助于保护现代应用的分布式和动态特性,确保在不妥协云提供的灵活性和创新性的情况下实现安全性。下一部分将超越零信任,探讨在云原生环境中的权衡平衡。
深度防御网络与平面网络 – 安全性与可操作性的平衡
网络深度防御与扁平网络的辩论至关重要。当权衡不足时,往往会暴露出架构设计中的反模式。一方面,深度防御(即安全的分层方法)优先保护多个层级的资源,从防火墙、网络分割到访问控制和加密。另一方面,扁平网络提供最少的分割和更简化的连接方式,通过减少复杂性并简化服务间的通信,从而提高可操作性。
深度防御是一种经过验证的安全模型,适用于云原生环境,能够通过多层保护来确保安全。通过在 AWS、Azure 虚拟网络(VNets)或 Google Cloud VPC 中对工作负载进行分割,服务被逻辑上分离,并受到严格的安全组、防火墙和访问控制策略的保护。此模型确保即使攻击者突破了某一层,其他屏障(如 Azure NSG、Google Cloud 防火墙规则或 AWS 安全组)也能防止横向移动和进一步的损害。虽然这种分层方法加强了安全性,但它也增加了操作负担。然而,这一权衡的代价是增加了复杂性。更多的分割意味着更多的配置、潜在的失败点以及在管理不同层的策略时更大的操作开销。
相反,扁平网络通过提供最少的服务间分割,简化了操作负担。在扁平网络中,通信限制较少,使得服务的部署和扩展变得更加容易。连接的简便性减少了开发和部署周期中的摩擦,因为开发人员无需穿越一层又一层的安全防护和访问规则。然而,尽管扁平网络可以提高速度和灵活性,但它牺牲了安全性。由于服务之间的屏障较少,一旦攻击者进入网络的任何一部分,就可能以最小的阻力横向移动,从而可能危及整个系统。
选择网络深度防御与扁平网络之间的关键在于评估组织的具体需求,以及所管理数据和服务的关键性。安全性与可操作性并非一个二元决策,而是一种平衡。关键应用在某些情况下可能需要更严格的安全措施,而对于不那么敏感的服务,则可能容忍更扁平、更加高效的架构。
例如,当我们被要求在一个云原生环境中的 EKS 集群上构建微服务来处理金融交易时,深度防御可能是最好的方法,确保每个处理敏感数据的微服务都得到了严格的安全保障和隔离。除了常规的 AWS 工具外,为了确保每次调用都是安全的,我们还实现了服务网格以支持双向 TLS 和 Open Policy Agent 来细化访问控制策略。同样,安全性与可操作性之间的权衡必须始终被考虑,并且需要理解的是,云原生环境中的灵活性永远不能以牺牲真正重要的安全性为代价。由于任何处理金融交易的公司都需要遵守 PCI-DSS 和其他合规标准,我们确保在实现的每一层面都应用了最佳实践。
总结
忽视如延迟和带宽等基本因素可能会导致显著的性能瓶颈,而缺乏 DNS 策略则会引入操作效率低下和服务发现的不一致性。依赖单体连接方式会造成脆弱的网络结构,难以扩展和保护,而忽视云原生网络功能则会忽略为优化和保护现代基础设施而设计的内建能力。最后,未能采纳零信任应用模式会让云环境变得脆弱,因为传统的基于边界的安全措施无法应对云原生系统的动态和分布式特性。为了构建具有弹性、可扩展且安全的云原生应用程序,必须正视这些反模式,确保网络架构是根据云环境的独特需求设计的。
下一章将介绍如何在云原生领域中进行可观察性操作。
第十章:观察我们的架构
在云原生领域,可观测性和事件管理通常被视为次要问题,直到它们变得不再如此。组织常常只有在意外的停机或性能问题使一切停顿时,才意识到正确的监控和响应流程的重要性。到那时,损害通常已经发生:信任受到动摇,财务损失累积,团队则忙于修复系统和声誉。本章深入探讨云原生组织在扩展架构时,忽视可观测性所面临的常见陷阱或反模式。
在今天复杂的生态系统中,仅仅知道哪里出了问题是不够的。我们需要了解问题发生的位置,它如何影响我们的服务,以及可能的下游影响。此外,可观测性不再仅仅是被动响应;随着由机器学习(ML)和人工智能(AI)驱动的先进服务的出现,组织现在可以在事件发生前预测它们,并在问题演变成严重问题之前识别异常。对于那些在混合工作负载、微服务架构和多云环境中航行的组织来说,这种主动方法至关重要。
本章将探讨云原生可观测性和事件管理中的几个反模式,以及可以帮助克服这些挑战的实际补救措施。这些挑战包括:
-
分布式追踪的可观测性覆盖不完整
-
缺乏实时监控
-
忽视开箱即用的机器学习功能
-
未能为分布式追踪实施全面视图
-
未区分影响和诊断指标
在接下来的章节中,我们将详细介绍这些反模式,提供可操作的策略和补救措施,帮助组织建立一个强健的可观测性框架。解决这些常见的陷阱将为您提供保持运营卓越的清晰思路,并避免在即使是最复杂的云原生环境中出现潜在问题。
让我们在日志聚合器中捕获所有内容
本节首先探讨分布式追踪的可观测性覆盖不完整的风险,接着是实时监控的关键需求,以确保及时检测和响应。对于许多新接触云原生架构的组织来说,首要的本能反应是收集尽可能多的数据。
“让我们记录一切,”他们说,好像日志的庞大数量能神奇地让一切变得清晰。然而,不幸的是,这种思维方式通常会导致操作混乱,而非清晰。在捕获日志时,日志聚合工具可以是强大的助手,但前提是要有目的地使用它们。将每个系统、服务和应用的每一条日志都捕获到一个统一的、全面的聚合器中,听起来可能是理想的,但很快就会变得难以管理。最初为增强可视性而进行的高尚尝试,最终却演变成一堆无关紧要的数据,在一山无实际价值的日志下埋藏了需要解决问题的关键信号。
以 fluentbit 或 fluentd 为例,这些都是很棒的日志捕获工具,但如果不对日志进行过滤,那么成千上万甚至百万条日志将变得难以理解。
为什么不加区分的日志记录会失败
不加区分的日志记录假设所有数据都同等重要,但并非所有日志都是平等的。有些数据对诊断系统健康或调试问题至关重要,而其他日志则只是噪音。在服务的每次心跳都记录下来似乎有帮助,但在问题诊断过程中要浏览成千上万的心跳日志却适得其反。
以在应用中记录 OK 状态与 WARN/FAIL 状态为例。大量的 OK 状态对于某些人来说可能被视为噪音,它在云存储上的成本可能超过其实际价值。这种做法抬高了运营成本,因为云存储和处理不是免费的,记录一切很快就会成为财务负担。更多的数据意味着需要更多的处理能力来分析它,导致成本上升并且回报递减。
智能日志记录:一种更有效的方法
组织需要有意识地决定记录哪些内容,而不是捕获一切。日志保留应该是重中之重;然而,关键是专注于与业务关键操作相关的、具有实际价值的可操作数据日志,或者提供系统健康状况的见解。适当设置日志级别(如 DEBUG、INFO、WARN、ERROR)有助于过滤掉不必要的数据,确保仅捕获有意义的信息。
上下文同样至关重要:日志应当结构化,以便追踪不同服务和环境中的问题。捕获请求 ID、用户会话或事务 ID 等元数据有助于将日志串联成一条连贯的叙事线。像 AWS CloudWatch Logs Insights 或 Datadog 这样的工具可以用于集中日志管理和可视化,减少噪音并优先处理关键问题。这使得组织能够保持运营效率并快速解决事件。
智能日志记录:一个例子
假设有一个托管在 AWS 上的云原生电商应用。系统由多个微服务组成:一个用于处理认证的用户服务,一个用于管理库存的产品服务,一个用于处理交易的支付服务,以及一个配送服务。该应用每天处理数百万个请求,因此有效的日志记录对保持性能和快速排查问题至关重要。以下是如何应用智能日志记录:
-
DEBUG:在开发过程中,工程团队启用DEBUG日志以捕获用户认证的详细信息,例如调用 AWS Cognito 的 API。在生产环境中,DEBUG日志被禁用,以避免不必要的杂乱信息。 -
INFO:在产品服务中,INFO日志记录诸如用户将商品添加到购物车或完成订单等成功操作。例如:``` WARN: 当出现临时问题时,例如在向 AWS RDS 发起支付请求时发生超时,将生成 WARN 日志:ERROR: If the payment service encounters a failure due to insufficient funds, an ERROR log is recorded, triggering an alert:
user_id`, `session_id`, `transaction_id`, 和 `request_id`。例如,支付服务的日志可能包括:session_id
andtransaction_id`, engineers can trace a user’s actions across different microservices, from logging in, adding items to the cart, processing the payment, and arranging delivery.For example, if a delivery fails, the error logs from the delivery service can be correlated with the initial payment logs using thetransaction_id:ERROR: 投递失败 - transaction_id=txn001, delivery_id=delv789, error_code=DELIV_ERRORte,
In this scenario, smart logging helps reduce unnecessary noise by focusing on logs that provide actionable insights (e.g., ERROR logs for failed transactions). Each log entry includes context that enables tracing of user actions across services, allowing engineers to quickly diagnose and resolve issues.
Additionally, centralized log aggregation ensures that logs are easily accessible for analysis, providing a clear, end-to-end view of system behavior without overwhelming the team with irrelevant data. While smart logging helps streamline observability, it’s important to recognize that logs alone may not be enough. Without full visibility across all system layers, particularly in hybrid environments, blind spots can emerge. Next, we will explore how incomplete observability creates these gaps and what can be done to overcome them.
The Blind Spots of Incomplete Observability and the Importance of End-to-End Distributed Tracing
Observability in cloud native environments is more than just collecting logs; it’s about understanding your systems comprehensively by correlating metrics, traces, and logs across services. Many organizations fall into the trap of incomplete observability by focusing solely on specific layers, such as applications or infrastructure, while neglecting other critical components like data pipelines. This selective approach creates blind spots that obscure the true source of issues, making troubleshooting time-consuming and frustrating. For instance, a smoothly running application may actually be suffering from bottlenecks in its data pipeline. Still, if observability is focused only on the application layer, the problem may go unnoticed until it visibly impacts performance or availability.
To address these blind spots, organizations need to adopt comprehensive end-to-end distributed tracing. Distributed tracing follows the flow of requests across different services, applications, and hybrid environments, providing a detailed view of how systems interact and where potential bottlenecks or failures occur. This is especially crucial in microservices architectures, where a single user request may touch dozens of services before completion. Distributed tracing becomes even more critical for organizations running hybrid workloads, where cloud and on-premises systems must work together. Without it, latency issues, transaction failures, or inconsistencies between cloud native and legacy systems can go undetected until they cause significant disruptions.
Each of the major cloud providers offers unique tools to implement end-to-end distributed tracing:
| Cloud Provider | Distributed Tracing Tool | Key Features |
| AWS | AWS X-Ray | Trace requests across AWS services likeLambda, API Gateway, and DynamoDB.Provides detailed visibility into system performance and failures. Supports hybrid workloads by tracing requests across on-premises and cloud-based systems. |
| GCP | Cloud Trace (Google Cloud Operations Suite) | Tracks latency and performance across services such as Google Kubernetes Engine(GKE), Cloud Run and Cloud Functions.Identifies bottlenecks and supports hybrid workloads with OpenTelemetry integration for tracing requests between cloud and on-premises environments. |
| Azure | Azure Monitor (Application Insights) | Tracks request flows across services likeAzure App Services, Azure Functions, and Azure Kubernetes Service (AKS) offer deep visibility into microservice interactions and integrate with on-premises environments through SDKs and Azure Hybrid Cloud services for end-to-end traceability. |
Table 10.1 - Cloud providers and tracing tools
By leveraging these tools, organizations can gain a holistic view of how their systems perform, tracing errors and latency across multiple services and addressing issues before they cause significant disruptions. End-to-end distributed tracing is essential for diagnosing problems in complex cloud-native architectures. Nonetheless, it is crucial in optimizing performance and ensuring seamless interaction across hybrid environments.
The ability to trace requests across all layers of your infrastructure provides deep insights into where failures may occur, allowing for proactive adjustments. This enhances system reliability, reduces downtime, and improves user experiences across increasingly complex architectures.
Hybrid Workload Integration and Unified Observability
To ensure complete observability, organizations must adopt tools that handle hybrid workloads, providing visibility across boundaries between cloud native and on-premises environments. A unified approach to observability brings together logs, metrics, and traces into a cohesive framework, offering comprehensive insights across the entire infrastructure. The key components of hybrid observability include:
- Cross-Environment Tracing: Tools like OpenTelemetry standardize tracing across cloud and on-premises systems, following requests across boundaries for a complete view.
- Unified Metrics Collection: Metrics should be consistently collected across environments using tools like AWS CloudWatch or Prometheus and centralized for real-time analysis.
- Log Aggregation and Correlation: Logs from cloud and on-premises systems must be aggregated into a single repository (e.g., Splunk, Datadog) for analysis and event correlation.
- Unified Monitoring Dashboards: A single dashboard (e.g., Datadog, Grafana) should provide real-time insights across cloud native and on-premises systems, simplifying management.
- Alerting and Incident Management: Alerts must trigger real-time notifications across both environments, ensuring consistent incident response with tools like PagerDuty or Opsgenie.
While hybrid workloads provide flexibility and scalability, they also introduce challenges like inconsistent data formats, latency, and monitoring gaps, which can lead to data silos. However, adopting a unified observability approach improves visibility, speeds up troubleshooting, and enhances system reliability across hybrid environments.
Real-Time Monitoring: A Necessity for Transactional Systems
In industries like financial services, where real-time transactions are crucial, monitoring must be as close to real-time as possible. Delays of even a few minutes can have severe consequences, including financial losses, compliance failures, and damage to customer trust. Take for example SaaS providers, these organizations have Terms And Conditions with their API responses to meet specific customer requirements. In the case of Payment providers, response time needs to be within a specific period of time, otherwise, payments drop. Event-based alerting systems that trigger notifications when critical events occur (e.g., transaction failures, latency spikes, or security breaches) allow teams to respond swiftly, preventing minor issues from escalating into more significant incidents.
However, the effectiveness of real-time alerting is often diminished by alert fatigue, a common challenge in cloud native environments. Alert fatigue occurs when operations teams are overwhelmed by the sheer volume of alerts generated by monitoring systems, often leading to desensitization and missed critical signals. As teams struggle to keep up, they may begin ignoring or dismissing notifications, increasing the risk of missing real threats. To combat this, smarter alerting strategies are essential, such as leveraging AI to prioritize critical issues, reduce noise, and ensure that alerts are both meaningful and actionable.
Real-time monitoring is also essential for security. It allows teams to detect anomalies (e.g., unauthorized access attempts or unusual transaction behavior) and respond proactively. When paired with real-time logging, event-based alerts help teams maintain system performance and security without being overwhelmed by unnecessary notifications. The table below details which cloud native services from the big three cloud providers can help execute a proper real-time monitoring setup.
| Category | AWS | Azure | Google Cloud Platform (GCP) |
| Real-Time Metrics | CloudWatch: Monitors transaction latency, error rates, and throughput in real-time.Detects spikes in failed transactions instantly. | Azure Monitor: Tracks real-time metrics across microservices, including transaction completion times and error rates. | Cloud Monitoring: Observes latency, error rates, and transaction metrics in real-time.Flags abnormal spikes for investigation. |
| Instant Alerts | SNS: Triggers notifications via SMS, email, or Slack when alarms are raised. | Azure Action Groups: Sends notifications through email, SMS, push notifications, or Microsoft Teams. | Pub/Sub: Triggers alerts, notifying teams via email, SMS, or Google Chat. |
| Automated Responses | Lambda: Automatically reroutes traffic to backup services during failures. | Azure Functions: Automates responses like scaling instances or handling increased load. | Cloud Functions: Automates failover responses, redirecting traffic to alternate regions for high availability. |
| Security Monitoring | CloudTrail: Tracks and analyzes API activity for suspicious behavior. | Azure Security Center: Monitors and analyzes API activities for unauthorized access attempts. | Security Command Center: Tracks and analyzes suspicious API activities and logs. |
| Anomaly Detection | CloudWatch Anomaly Detection: Identifies unusual patterns in transactions, triggering alerts. | Azure Monitor: Uses ML-based anomaly detection for irregular transaction patterns. | Cloud Monitoring: Leverages anomaly detection to flag abnormal transaction behavior. |
| Automated Security Protocols | AWS Systems Manager: Automates security responses like disabling accounts. | Azure Logic Apps: Automates responses to security threats, such as flagging suspicious transactions. | Cloud Automation: Automatically triggers actions like quarantining suspicious transactions or disabling accounts. |
| Real-Time Logging for Deep Visibility | CloudWatch Logs: Collects real-time logs from allmicroservices and infrastructure components for deep analysis. | Azure Monitor Logs: Collects real-time logs from all services, offering detailed visibility into vstem events. | Cloud Logging: Provides realtime logging across services, enabling forensic analysis and event tracing. |
Table 10.2 - Cloud Vendors and monitoring services
Implementation Checkpoints and Guardrails for a Corporate Strategy
A solid corporate strategy backed by crucial implementation checkpoints is needed for cloud native observability to be effective. These should ensure observability practices are applied consistently across the organization. Key elements include:
- Defining Critical Events: Identify which events (e.g., transaction failures, security incidents) are most critical to the business and prioritize them in monitoring and alerting systems.
- Regular Audits of Observability Gaps: Conduct audits to identify and address gaps in observability, especially as new services and architecture changes are introduced.
- Automated Guardrails for Enforcement: Automated guardrails enforce consistent logging, tracing, and monitoring standards across all systems, ensuring every deployment adheres to best practices.
Automating these best practices reduces human error, ensures consistency across the organization, and reduces operational overhead. Instead of manually configuring observability for every new service or deployment, guardrails take care of this automatically, freeing engineers to focus on higher-level work.
For instance, when deploying new applications through a CI/CD pipeline with integrated guardrails, these guardrails actively enforce compliance by blocking any deployment that fails to meet the established requirements.
Cloud native observability is critical for maintaining control over increasingly complex systems. By avoiding the pitfalls of overlogging and incomplete observability, adopting real-time monitoring, and enforcing consistency through automated guardrails, organizations can gain the visibility they need to prevent disruptions and improve their operational resilience. Success in cloud native environments depends not on capturing everything but on capturing the right insights at the right time and ensuring that these insights drive actionable outcomes. However, beyond traditional observability methods, organizations can unlock even greater potential by leveraging the built-in machine learning (ML) and artificial intelligence (AI) capabilities offered by modern observability platforms to proactively detect anomalies and predict incidents before they escalate. The prior will be discussed in the next section, Ignoring ML and AI capabilities.
Ignoring ML and AI capabilities
In the previous section, Let’s Capture Everything in the Log Aggregator; we explored the common cloud native anti-pattern of overwhelming logging systems by collecting every possible data point without a strategic approach to filtering or prioritizing valuable insights. This scattershot method often results in data overload, making it difficult to extract actionable information when it’s most needed.
Building on that concept, another critical oversight in cloud native architectures is the tendency to ignore the out-of-the-box machine learning (ML) and artificial intelligence (AI) capabilities offered by leading cloud providers like AWS, Azure, and GCP. These platforms provide potent tools such as AWS’s Anomaly Detection in CloudWatch, GuardDuty, Azure Monitor’s AI-powered insights, and GCP’s Cloud Operations suite, which includes advanced log analysis and anomaly detection features.
This section will go over:
- Leveraging Cloud AI/ML for Anomaly Detection
- Improving Log Aggregation with AI Insights
- Centralized Monitoring with Automated Intelligence
- Reducing Operational Complexity through ML Automation
Leveraging Cloud AI/ML for Anomaly Detection
While real-time alerting and monitoring have become essential components of cloud native operations, they are no longer enough to keep pace with the growing complexity of modern systems. Traditional monitoring techniques often rely on static thresholds and manual rule-setting, which can result in missed critical events or unnecessary noise from false positives. In an environment where applications are increasingly distributed and dynamic, organizations need more intelligent solutions to detect subtle issues before they become full-blown problems. This is where anomaly detection, powered by AI and machine learning, becomes indispensable. Anomaly detection provides proactive insights that allow teams to address issues early, often before users even notice a degradation in service, shifting from reactive monitoring to intelligent, predictive observability.
Cloud providers like AWS, Azure, and GCP offer advanced AI/ML capabilities that transform traditional monitoring and observability. In AWS CloudWatch, for example, Anomaly Detection uses machine learning models to detect deviations from expected performance patterns automatically. Azure Monitor incorporates AI-driven insights to predict issues before they arise, while GCP’s Cloud Operations provides anomaly detection to pinpoint unusual behavior across logs and metrics. By utilizing these capabilities, organizations can gain a proactive edge in detecting potential issues before they become full-blown incidents, enabling teams to address problems in real-time.
However, despite the availability of these tools mentioned prior, many organizations fail to adopt them fully, sticking to manual monitoring methods that often fall short. Ignoring AI/ML-powered anomaly detection means missing out on a layer of protection that traditional rule-based alerting simply cannot provide. The power of machine learning lies in its ability to identify subtle patterns in massive data streams, patterns that may be missed by even the most experienced operators. By leveraging these cloud native AI/ML tools, organizations can enhance their monitoring efforts, reducing downtime and improving system resilience. The following example of Leveraging Cloud AI/ML for Anomaly Detection provides strong context on why its a tool that should not be ignored.
Anomaly Detection: An example
An example of AI/ML anomaly detection can be found in AWS CloudWatch Anomaly Detection. This feature uses machine learning to automatically establish a metrics baseline and detect deviations from this expected behavior.
For instance, in a web application, CloudWatch Anomaly Detection could monitor the number of requests to the server and establish an expected pattern based on historical data. Suppose the traffic suddenly spikes or drops outside the expected range, such as a sudden flood of requests indicative of a DDoS attack or a sudden drop in traffic suggesting a failure. In that case, it flags this as an anomaly and triggers an alert. The image below illustrates what that would look like:

Figure 10.1 - Typical Flow of Anomaly detection (Redraw please)
This flowchart outlines a monitoring process that begins with data collection and baseline establishment, continuously checks for traffic anomalies, flags and triggers alerts for anomalies detected, and loops back to ongoing monitoring if no anomalies are found.
As we progress, we must understand that effective monitoring doesn’t stop at anomaly detection. The next layer of observability involves Improving Log Aggregation with AI Insights, where machine learning continues to enhance how we filter and interpret vast amounts of log data.
Improving Log Aggregation with AI Insights
Log aggregation is critical to any observability strategy but is not enough to collect data. The true challenge lies in filtering through the immense volume of logs to extract actionable insights. AI and ML capabilities embedded in cloud platforms like AWS, Azure, and GCP are invaluable here. These tools offer smart filtering and categorization, enabling organizations to focus on the most relevant data.
For instance, AWS CloudWatch Logs Insights and Azure Log Analytics use machine learning to identify patterns and anomalies, helping teams make sense of vast amounts of log data more efficiently.
While many organizations are content to rely on manual searches and predefined queries, these methods often result in information overload or missed signals. AI-enhanced log aggregation helps reduce noise, highlights critical issues, and predicts future system behavior. By integrating these capabilities into the log aggregation pipeline, companies can improve their troubleshooting efficiency and prevent potential incidents by acting on predictive insights. This approach brings a level of sophistication to logging that manual methods simply cannot match. By integrating AI and ML capabilities into log aggregation, cloud native environments can significantly improve how logs are processed, analyzed, and acted upon. Below are some key ways in which AI enhances log aggregation:
- Smart Filtering and Categorization: AI models automatically sort logs based on relevance, reducing the time spent manually filtering through non-essential data.
- Pattern Recognition in Large Data Sets: Machine learning identifies patterns in logs that would be too subtle or complex for manual detection, enabling teams to uncover hidden issues or trends.
- Anomaly Detection in Log Data: AI detects anomalies within logs that indicate potential failures, security threats, or performance bottlenecks, allowing teams to act before problems escalate.
- Predictive Insights for Future Behavior: Machine learning analyzes historical log data to predict future behavior, offering teams proactive recommendations for avoiding incidents or optimizing system performance.
- Noise Reduction: AI-enhanced log aggregation reduces the noise by filtering out irrelevant or duplicate entries, making it easier to focus on critical log events and streamline incident response.
- Automated Insights and Recommendations: AI tools directly provide actionable insights and recommendations from log data, helping teams prioritize their efforts and resolve issues faster with data-backed guidance.
Looking ahead, it becomes clear that centralized monitoring is the backbone of enhanced observability, bringing together vast data streams for intelligent analysis at scale. In the next section, Centralized Monitoring with Automated Intelligence, we’ll uncover how AI and ML are the catalysts that elevate this approach from routine oversight to predictive power.
Centralized Monitoring with Automated Intelligence
Centralized monitoring has become the foundation of modern observability, allowing organizations to manage complex systems more easily. However, with the advent of AI and ML, centralized monitoring has evolved beyond merely consolidating data into dashboards.
Today, cloud providers like AWS, Azure, and GCP offer sophisticated monitoring platforms that do more than aggregate metrics; they:
- Analyze data in real time to deliver intelligent alerts and recommendations powered by machine learning.
- Visualize the performance of distributed systems to simplify the management of cloud native workloads.
- Centralize logging across all resources, enhancing visibility and enabling more efficient monitoring.
These platforms, such as AWS CloudWatch, Azure Monitor, and GCP Cloud Operations, allow teams to visualize the performance of distributed systems and reduce the complexity of managing cloud-native workloads, making monitoring more efficient and actionable.
In addition to performance metrics, all major cloud vendors now offer solutions to centralize logging across all resources, further enhancing observability. For instance, AWS provides AWS CloudWatch Logs and AWS Organizations, which enable centralized log aggregation and policy management across multiple accounts. This ensures that data from various services and resources, whether distributed or complex, is collected and accessible in one unified location.
Similarly, Azure Log Analytics and Google Cloud’s Logging offer comparable capabilities, aggregating logs from across regions and services while incorporating AI/ML-driven analytics to highlight significant trends, anomalies, and potential issues before they escalate.
Centralized Monitoring: An AI Example
These AI and ML-driven tools go beyond traditional monitoring by moving from reactive to proactive observability. Instead of simply responding to events as they occur, these platforms provide predictive insights that help teams identify issues before they manifest.
For example, AWS GuardDuty integrates with AWS Organizations and uses anomaly detection powered by machine learning to flag suspicious activity, such as unusual network traffic or unauthorized access attempts. Similarly, machine learning models across these cloud platforms can detect emerging patterns that indicate impending resource constraints or application bottlenecks, enabling operators to take preemptive action. The result is a more intelligent, responsive monitoring system that lightens the load on operations teams while ensuring better performance, security, and overall reliability of cloud workloads.
Reducing Operational Complexity through ML Automation
In cloud native environments, operational complexity can quickly spiral out of control. The sheer scale of data, distributed architectures, and dynamic infrastructure create monitoring challenges that are difficult to manage manually.
Fortunately, machine learning automation offers a solution by simplifying tasks like anomaly detection, alerting, and capacity planning. Cloud platforms like AWS, Azure, and GCP provide ML automation tools to handle these repetitive and time-consuming tasks, allowing operations teams to focus on higher-value activities.
For example, Azure offers a suite of machine learning automation tools specifically designed to streamline operational complexity. Azure Monitor’s Autoscale feature dynamically adjusts resources based on real-time demand, automatically increasing or decreasing capacity without manual intervention. With Azure Machine Learning’s anomaly detection capabilities, organizations can proactively address potential performance bottlenecks and resource constraints before they impact the end-user experience. Azure Automation, another powerful tool, automates routine operational tasks such as patch management, compliance checks, and system backups. These automated processes ensure that operations teams are no longer bogged down by repetitive tasks, allowing them to focus on strategic initiatives that drive business value.
ML Automation: Working Example
In a recent consulting engagement, clients facing growing operational complexity are often overwhelmed by the sheer volume of alerts and manual tasks that consume their team’s time. In these situations, leveraging Azure’s ML-driven automation tools can significantly transform their operations. For example, during a recent engagement, we worked with a client struggling with frequent scaling issues due to their fluctuating user base. By implementing Azure Monitor’s Autoscale and integrating predictive analytics from Azure Machine Learning, the client was able to reduce manual oversight, optimize resource allocation, and prevent costly downtime. The shift to ML automation enabled their team to reclaim time spent on firefighting and instead focus on innovation and growth.
By embracing ML automation, organizations can reduce the need for constant manual intervention, ensuring faster response times and more reliable systems. Automation increases efficiency and reduces the potential for human error, often the source of operational failures. In this way, AI and ML-driven automation act as a force multiplier, enabling operations teams to do more with less effort while maintaining robust system performance. As cloud native architectures evolve, ML automation will only grow in importance, becoming an essential component of successful observability strategies.
To get to the point where a traditional organization can utilize ML automation when moving to cloud-native, the table below provides a set of considerations:
| Step | Description |
| Assess Your Current Operational Processes | Identify repetitive, time-consuming tasks that can benefit from automation (e.g., anomaly detection, scaling, system maintenance). |
| Set Clear Objectives | Define specific goals for ML automation, such as reducing manual intervention, improving response times, or enhancing resource optimization. |
| Evaluate Existing Cloud Automation Tools | Review ML automation features in your cloud platform (e.g., AWS GuardDuty, Azure Monitor, and GCP Operations) for potential integration. |
| Prioritize Use Cases | Select the most impactful areas to automate first, like auto-scaling during peak loads or automating patch management. |
| Integrate Machine Learning Models | Implement cloud native or custom ML models for anomaly detection, predictive analytics, and resource optimization. |
| Develop Automation Pipelines | Build pipelines that integrate ML models with operations, triggering actions like resource scaling or issue resolution based on ML insights. |
| Test and Monitor Automation | Run simulations and monitor performance to ensure ML automation meets objectives, refining models and workflows as needed. |
| Scale Automation Across Operations | Expand ML automation to additional processes once initial use cases are successful, incorporating more complex workflows and models. |
| Implement Feedback Loops | Continuously gather data from automated processes to improve models and automation strategies, ensuring continual learning and refinement. |
| Train Your Teams | Ensure teams receive effective training to manage and optimize ML automation, maintaining performance and adaptability. |
Table 10.3 - ML Automation Considerations
As we’ve seen, AI/ML-driven anomaly detection in cloud native environments is not just an enhancement to observability; it’s a critical tool for maintaining system resilience. Whether it’s identifying unusual traffic spikes, unexpected performance drops, or subtle patterns that could indicate emerging issues, these capabilities give organizations a proactive edge in managing complex, distributed systems. By failing to leverage the intelligent, automated insights provided by AWS, Azure, and GCP, many companies are unnecessarily exposing themselves to more significant operational risks and inefficiencies. Embracing these tools is not just about reducing downtime; and it’s about building a more intelligent, adaptive infrastructure.
Yet anomaly detection is only one piece of the observability puzzle. As systems grow more distributed, tracking issues across multiple services and microservices becomes even more challenging. This is where distributed tracing is a critical technique for following a request’s journey across different components and identifying performance bottlenecks or errors in complex, interconnected systems.
In the next section, we’ll explore how Neglecting Distributed Tracing can leave gaps in your observability strategy, making it harder to diagnose issues and optimize performance in cloud native architectures.
Neglecting Distributed Tracing
Neglecting distributed tracing is a classic cloud native anti-pattern. It undermines one of the core principles of cloud native architecture: end-to-end observability. When tracing is overlooked, it disrupts the flow of visibility across distributed systems, leading to hidden performance bottlenecks, misdiagnosed issues, and a loss of accountability in critical pathways. This anti-pattern breaks the promise of transparency and agility that cloud native environments are supposed to deliver, leaving teams scrambling to diagnose issues without the whole picture.
This section will explore the importance of cloud native log aggregation within a security data lake and highlight how failing to integrate logs across distributed systems compromises security insights and operational awareness. Additionally, we will explain why splitting impact metrics from diagnostic metrics is not just a best practice but a necessity for precise, actionable insights.
Here’s what to expect:
- The Fragmentation Problem: How overlooking distributed tracing leaves gaps in visibility across microservices.
- Metrics that Matter: The importance of distinguishing impact metrics from diagnostic metrics for better incident response.
- Real-World Consequences: Case studies of what can go wrong when distributed tracing is neglected.
- Best Practices for End-to-End Tracing: A guide to implementing comprehensive tracing across complex systems
The Fragmentation Problem
Cloud native architectures thrive on the promise of agility, resilience, and scalability. By decoupling applications into independently deployable microservices, businesses gain flexibility and speed. However, as these systems grow in scale, so does the complexity of managing them effectively. When distributed tracing, the key to visibility within microservices, is neglected or improperly implemented, a dangerous anti-pattern known as fragmentation emerges.
Fragmentation occurs when tracing is applied inconsistently or only in parts of the system, leaving critical gaps in visibility. Instead of a clear, end-to-end view of transactions, teams are left with a disjointed mess, akin to navigating through a fog of partial data.
Distributed tracing exists to provide transparency throughout a system, capturing the full journey of requests as they flow between microservices, databases, and third-party APIs. When applied correctly, it offers a holistic view, enabling teams to pinpoint bottlenecks, identify errors, and optimize performance. However, when tracing is not implemented consistently across the entire architecture, teams are forced to rely on fragmented data, piecing together logs from disparate services without seeing the whole picture. This lack of cohesion doesn’t just compromise visibility, it introduces significant operational risks.
Fragmentation: An Example
Consider the case of an e-commerce retailer grappling with slow checkout times during high-traffic sales events. Their logs from individual microservices appeared normal without a unified tracing system, suggesting everything was running smoothly. Yet the customer experience told a different story: lagging transactions and failed checkouts, causing customer frustration and lost revenue. The real culprit, a third-party payment processor throttling requests, remained hidden from view, only uncovered after hours of expensive investigation. Had comprehensive distributed tracing been in place, the issue could have been identified in minutes, preventing financial loss and safeguarding customer trust.
Fragmentation as a cloud native anti-pattern breaks one of the core tenets of microservices: the ability to maintain observability across the entire system while still managing services independently. The tension between autonomy and operational oversight becomes unsustainable without distributed tracing. The solution is straightforward:
- Treat Distributed Tracing as a Foundational Element: Integrate distributed tracing into the architecture from the outset, ensuring it is a core part of the design rather than an afterthought.
- Implement End-to-End Tracing: To avoid blind spots, ensure every transaction is fully traced across all microservices, third-party APIs, databases, and other system components.
- Avoid Fragmented Visibility: Consistently apply tracing across the entire system to prevent teams from compiling incomplete data from isolated logs.
- Monitor All Critical Paths: Focus on critical user journeys, such as checkout processes or key transactions, to immediately detect and resolve bottlenecks, errors, or latency.
- Foster a Proactive Approach: Address potential risks before they become problems by continuously monitoring and tracing critical services, ensuring the system remains resilient under pressure.
- Enhance Observability: Integrate tracing with logging and metrics to provide a comprehensive observability stack, enabling faster diagnostics and incident response.
This approach builds a more reliable, agile, and resilient system that can scale effectively while maintaining operational visibility.
Metrics that Matter
Not all metrics are created equal in effective distributed tracing. To ensure a robust incident response and maintain a high-performing cloud native system, it is crucial to distinguish between impact metrics and diagnostic metrics. This distinction allows operations teams to prioritize alerts based on an issue’s severity while offering deeper insights for troubleshooting and resolution. The table below goes into further detail as to what the metrics types are:
| Metric Type | Description | Examples | Purpose |
| Impact Metrics | Focus on user experience and overall system health. Measure the direct impact on customers or business outcomes. | Latency, Error Rates, Request Failures | Quickly detect and address issues that affect end users,such as slow response times or failed transactions. |
| Diagnostic Metrics | Dive deeper into system internals to uncover the root cause of issues. Provide detailed technical information for troubleshooting. | CPU Usage, Memory Consumption, Network Traffic, Database Query Performance | Diagnose and resolve issues identified by impact metrics by analyzing system performance and resource |
Table 10.4 - Metric split
It is one thing to know the metrics types, but to utilize them is another. In the example below, we use OpenTelemtry to pull useful metrics from an application here using the OpenTelemtry SDK, directly tying to the code itself, instead of relying on an agent:
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader
# 设置 MeterProvider 和 Metric Exporter
provider = MeterProvider()
metrics.set_meter_provider(provider)
exporter = ConsoleMetricExporter()
reader = PeriodicExportingMetricReader(exporter)
provider.add_metric_reader(reader)
# 创建用于记录指标的计量器
meter = metrics.get_meter(__name__)
# 定义指标:影响和诊断
impact_latency = meter.create_histogram("impact_latency", unit="ms", description="请求延迟")
diagnostic_cpu_usage = meter.create_observable_gauge("diagnostic_cpu_usage", description="CPU 使用率")
# 模拟记录影响指标的函数
def record_impact_metrics(latency_value):
impact_latency.record(latency_value)
print(f"记录的影响延迟: {latency_value}ms")
# 观察诊断指标的函数
def observe_diagnostic_metrics():
import psutil
return psutil.cpu_percent(interval=None)
# 注册诊断指标回调
meter.create_observable_gauge("diagnostic_cpu_usage", callbacks=[observe_diagnostic_metrics])
# 模拟指标记录
record_impact_metrics(120) # 模拟 120ms 的延迟
代码中需要观察的关键点有:
-
impact_latency histogram追踪请求的时长,这是用户体验的一个关键指标。在这个例子中,我们记录了 120ms 的延迟。 -
diagnostic_cpu_usage可观察计量器监控 CPU 使用率。我们使用psutil库来收集 CPU 统计信息,这是一种在事故发生时了解系统资源使用情况的适当诊断指标。
通过收集和分析影响和诊断指标,团队可以迅速检测性能问题,并收集必要的信息以诊断和解决根本原因。这种综合方法确保了云原生系统在高压下仍能保持弹性和性能。
正确的指标决定了结果的相关性;下一部分将进入一个真实场景,讨论当我们忽视分布式追踪时会发生什么。
真实世界的后果
在与一家领先的电子商务零售商进行的最近一次合作中,我们受邀解决在高流量促销期间出现的重大性能问题。该零售商的微服务架构管理着库存管理和支付处理等关键操作,但其可观察性是碎片化的。仅依赖单个服务的日志和指标,他们无法追踪端到端的事务,导致在结账时间开始因负载增加而变慢时,无法迅速识别延迟的来源。事故发生几个小时后,我们实施了分布式追踪,立即揭示了一个第三方支付 API 作为导致延迟的瓶颈。
引入分布式追踪为零售商提供了实时的整个事务流的可视化,跨所有微服务。此追踪的集成使得运营团队能够更快地定位并解决问题,避免了本可以在几分钟内识别出来的长期停机。我们的干预减少了停机时间,并通过确保未来的高峰流量期间能更好地进行性能监控和更快的响应时间,恢复了客户的信任。下图展示了一个简单的 Kubernetes 微服务,后面列出了我们发现的问题。

图 10.2 - 简单的 Kubernetes 微服务
我们识别出的关键问题包括:
-
缺乏端到端的事务可视化:系统无法追踪客户在微服务中的整个旅程。
-
日志和指标孤立:指标仅限于单个服务,无法洞察它们在事务中如何交互。
-
未监控的第三方依赖:导致延迟的第三方 API 没有得到充分监控,直到实施了分布式追踪才被发现。
-
慢响应的事故处理时间:没有分布式追踪,团队依赖手动排查故障,延长了关键问题的解决时间。
为了解决这些挑战,组织需要一个全面的可观察性策略,整合分布式追踪、集中日志记录和强大的监控,涵盖所有系统组件。以下列表提供了 更多的背景信息:
-
实施分布式追踪:我们部署了 OpenTelemetry 作为我们的追踪解决方案,为微服务架构中的事务提供了端到端的可视化。这使团队能够立即检测到瓶颈,包括导致结账延迟的第三方 API。保持一致性的关键是将 OpenTelemetry SDK(在此案例中为 Python)与所有代码打包在一起。
-
增强日志聚合:我们将追踪系统与 CloudWatch 集成,进行集中式日志聚合,确保来自不同微服务的所有日志都能集中收集并进行检索。这提高了团队将日志与追踪数据关联的能力,使得事故检测和诊断更快速、更准确。
-
实时监控与警报:我们使用 Prometheus 和 Grafana 设置了监控仪表板和实时警报,配置它们以显示系统健康状况、性能指标和追踪信息。这为运维团队提供了系统性能的主动洞察,减少了他们在高流量事件中对被动故障排除的依赖。
-
第三方依赖监控:我们为第三方 API 建立了特定的监控系统,包括设置延迟阈值和故障率警报。这确保了外部依赖持续被监控,以防它们在未来默默成为瓶颈。
通过利用这些工具和策略,我们提高了零售商系统的可视化,并减少了他们对关键事件响应的时间。这些解决方案可以通过主要云服务提供商的等效服务复制,例如 AWS XRay + CloudWatch、Azure Application Insights 和 Google Cloud Operations Suite。
接下来,我们将讨论最佳实践以及在构建分布式追踪时需要考虑的因素,以便将我们迄今所学的知识结合起来。
解决追踪忽视的最佳实践
忽视分布式追踪就像在没有完整地图的情况下尝试在复杂的城市中导航;最终,你会迷路。端到端追踪就像你的 GPS,连接微服务之间的点,识别瓶颈,并照亮那些可能隐藏在分散日志阴影中的路径。分布式追踪必须作为基础实践,而不是事后的思考,以确保云原生系统保持敏捷、可扩展和响应迅速。
在应用构建追踪时,请考虑以下因素:
-
尽早开始并保持一致性:最关键的最佳实践之一是从一开始就实施追踪。事后为现有架构添加追踪就像为一艘正在下沉的船打补丁;效率低下且容易留下漏洞。一致性至关重要;每个微服务、依赖项和请求在系统中路径的每个环节都应覆盖追踪。这确保系统的任何部分都不会置于黑暗中。
-
跟踪整个过程:成功的跟踪不仅仅停留在表面。它需要覆盖整个请求生命周期,从面向用户的前端到后台服务,再到外部依赖,如第三方 API。这种全面的可见性确保了任何延迟或故障都可以追溯到根本原因,无论它是发生在系统内部还是外部。结果是更快的诊断、更快的解决方案,以及在事件发生时更少的头疼。
-
与指标和日志集成:跟踪功能强大,但与指标和日志结合时,它的作用更为显著。使用影响指标来识别用户体验何时下降,使用诊断指标来找出原因。将可观察性的三大支柱——跟踪、指标和日志进行整合,可以创建一个全面的系统视图,使团队能够获得他们所需的洞察,保持主动而非被动。
-
自动化并设置保护措施:手动为每个服务进行跟踪仪器化可能令人望而生畏,尤其是在动态的云原生环境中。像 OpenTelemetry 这样的自动化工具和框架简化了这个过程,确保每个新的微服务或部署默认都内置了跟踪功能。设置自动化保护措施,如延迟阈值、错误率和关键服务性能,可以在事件失控之前触发警报。
-
监控最重要的内容:并非每个跟踪、日志或指标都需要同等对待。优先跟踪系统中的关键路径,例如用户交易、支付流程,或任何直接影响客户体验的服务。这种聚焦确保团队的注意力集中在最重要的内容上,同时仍然关注整个系统的健康状况。
遵循这些最佳实践可以帮助传统组织在向云原生转型时,将分布式跟踪从一个反应式工具转变为一个主动的资产。当跟踪是全面且集成时,结果是一个云原生架构,它具有弹性、透明性,并能够满足现代应用的需求。虽然跟踪是一个运作良好的云原生系统的支柱,但真正的弹性考验在于组织在问题发生时的应对能力。即使采用最佳的跟踪实践,系统的恢复能力和维持稳定性也会受到影响,如果没有成熟的警报和事件处理流程。
本章的最后一节,我们将探讨警报和事件处理流程不成熟如何破坏即使是最强大的架构,以及如何解决这些不足是维持云原生环境中运营卓越的关键。
警报和事件处理流程不成熟
虽然提供了灵活性和可扩展性,但云原生组织在处理警报和事件时往往会遭遇不成熟的流程。在管理数千个微服务的环境中,冗余警报、观察性设置不完整以及无效的事件响应协议所带来的噪声可能会让团队不堪重负。当组织现代化其基础设施时,他们往往会忽略一个基本真理:警报和事件管理的关键不在于收集所有可用的指标,而是专注于正确的指标,响应正确的信号,并确保这些过程在所有环境中顺畅运行,而不仅仅是在生产环境中。
许多云原生失败的核心问题是“收集一切”的心态,收集所有可能的指标,并为每一个异常发送警报。这种做法通常会导致混乱,使工程和运维团队淹没在没有可操作洞察的数据中。问题不是指标的缺乏,而是缺乏有目的且良好对齐的指标和警报。通过理解指标倾倒的危险,我们可以变得更加谨慎和警觉,确保每个警报都有明确的目的,每个收集的指标都应该解决一个与业务和技术目标相关的具体用例。
本节将指导如何构建一个成熟、有效的警报和事件响应系统,重点介绍常见的陷阱以及克服这些陷阱的策略。
本节将涵盖:
-
目标驱动的指标和警报
-
指标倾倒的陷阱
-
在可观察性上向左移动
-
警报疲劳
-
事件响应成熟度
这些主题将帮助我们培养一种韧性强、主动的警报和事件管理方法,使团队在挑战出现时能够迅速且智能地响应。
目标驱动的指标和警报
可用的指标数量庞大,可能令人不知所措。然而,并不是每个指标都是有用的,收集所有数据而没有明确目标,会导致噪声、警报疲劳和低效。目标驱动的指标专注于收集与特定业务或技术目标直接相关的数据,确保每个指标都有实际目的。
指标应该根据它们提供可操作洞察的能力来选择,而不仅仅是因为它们易于收集。例如,除了收集所有实例的 CPU 使用率外,考虑:“我们通过监控这个想要实现什么目标?我们是在了解负载下的性能吗?预测基础设施扩展需求吗?优化资源利用吗?” 一旦目标明确,我们可以设计与之对齐的指标和警报。
目标驱动的指标和警报:一个示例
例如,假设我们考虑一个基于微服务的电子商务平台。一个关键的业务目标是确保顺畅的客户结账体验。在这种情况下,目标驱动的指标可能包括:
-
结账服务的延迟:这个指标跟踪完成结账过程所需的时间,直接影响用户体验。业务目标是确保客户不会因性能问题而放弃购物车。相关警报可能会在延迟超过定义的阈值时触发,提醒工程师在影响大量用户之前调查性能下降问题。
-
支付处理中的错误率:监控这个指标有助于确保支付失败的交易不会干扰销售。不是针对每一笔失败的交易都发送警报,而是当错误率在特定时间窗口内超过某个百分比时,触发警报,让团队能够区分小的波动和真正的问题。
-
库存更新延迟:如果销售后库存更新延迟,可能会导致超卖,影响收入和客户满意度。围绕订单完成后库存同步所需时间的目标指标,服务于业务目标的运营准确性。如果这些延迟超过可接受的限制,则触发警报。
通过定义像这样的指标,我们并不是仅仅为了收集数据而收集数据。相反,我们确保每个指标都有一个明确的目的,使团队能够专注于对业务真正重要的事项。现在我们已经看到了目标驱动的指标的价值,我们必须避免相反的方法,这就是我们所说的“指标倾倒”陷阱。
接下来,我们将探讨指标倾倒的陷阱,以及它是如何破坏即便是最有意图的云原生监控策略的。
指标倾倒的陷阱
在急于采用监控工具和收集洞察的过程中,许多组织陷入了指标倾倒的陷阱。这种情况发生在收集所有可能的指标时,没有考虑其价值或目的。表面上看,这似乎是一种确保完全可视化的方法。然而,这会导致数据过载、警报疲劳和系统性能下降,使得团队更难及时应对关键问题。指标倾倒是指收集所有可用的指标,无论是 CPU 使用率、内存、网络延迟还是磁盘 I/O,都没有考虑这些指标将如何使用,或者它们是否有助于实现业务目标。团队可能认为,收集更多的数据能给他们更多的控制权和洞察力。
指标倾倒:一个例子
例如,假设一个组织监控每个实例的 CPU 使用率,跨越数百个微服务,无论 CPU 使用率是否与服务性能相关。他们以非常精细的粒度(每秒)收集这些数据,即使该服务没有历史的与 CPU 相关的性能问题。随着时间的推移,这种方法会产生大量的数据,堵塞仪表板,增加存储成本,并创建一个警报系统,持续触发无关紧要的警告。这是典型的指标倾倒,收集了超出必要或可操作的数据。
指标倾倒会带来两个显著的问题,导致操作变慢:操作低效性和警报疲劳。以下是这些问题的体现方式:
-
操作低效性:
-
不必要的指标洪流减慢了监控系统,因为每个指标都必须被处理、存储和分析。
-
这会导致庞大的数据管道,消耗超过所需的资源。
-
工程师和运维团队必须从无关的数据中筛选信息,这使得找到重要见解变得更加困难。
-
关键警报可能会被延迟、淹没或遗漏,从而可能导致问题升级为停机故障。
-
-
警报疲劳:
-
监控过多的指标会导致过多的警报,压倒团队,造成非关键通知的流入。
-
随着时间的推移,团队变得麻木,增加了错过或忽略真正重要警报的风险。
-
这降低了团队的效率,增加了系统停机、恢复时间延长以及对客户体验产生负面影响的可能性。
-
以下是如何摆脱指标倾倒,朝着更专注、更高效的监控策略转变的方法:
| 行动 | 描述 |
|---|---|
| 定义明确的业务和 技术目标 | 确保每个指标都有明确的目的。首先要问:“我们要解决的业务或操作问题是什么?”收集支持这些目标的指标。 |
| 优先关注 可操作指标 | 聚焦于那些能提供可操作见解的指标。避免仅仅因为数据可用就收集它。确保这些指标能帮助团队做出决策或采取行动。 |
| 定期审查和 修剪指标 | 定期审计正在收集的指标。淘汰那些不再相关的指标,减少噪声,保持监控系统的高效性。 |
| 创建 基于阈值的警报 | 设计仅在关键阈值被突破时触发的警报。这减少了不必要的警报,帮助团队专注于最重要的问题。 |
| 使用 聚合指标 | 聚合指标以获得高层次的视图,避免过度细化。监控时间段内的平均值,以识别有意义的模式并减少噪声。 |
| 专注于关键绩效 指标 (KPI) | 将指标与衡量关键系统健康状况和性能的 KPI 对齐,如用户体验、交易成功率和服务延迟。 |
表 10.5 - 指标倾倒解决表
通过遵循这些步骤,你可以消除指标倾倒的低效,创建一个简化的监控系统,提供清晰、可操作的洞察力。这将改善响应时间,减少警报疲劳,并使团队能够集中精力处理云原生环境中最关键的方面。接下来的部分将通过讨论在可观察性中向左转来深入探讨。
在可观察性中向左转
云原生可观察性中最常被忽视的一个方面是未能将监控和警报延伸到软件开发生命周期(SDLC)的早期阶段。这种忽视导致了一种反模式,将完整的可观察性仅视为生产环境的关注点。在云原生环境中,微服务分布广泛且部署速度快,等到生产环境才发现问题就像是让炸弹的引线慢慢燃烧一样。这就是“向左转”实践的关键所在。
在可观察性中向左转意味着将监控、警报和诊断嵌入到开发、测试和UAT(用户验收测试)等早期环境中,而不是等到代码达到生产环境才进行监控。通过这种方式,组织可以更早发现性能瓶颈、扩展问题或配置错误,远在它们破坏生产服务或更糟的情况——影响客户之前。
想象一个场景,一个云原生电商应用正在部署。在生产环境中,公司使用像 Prometheus 和 Grafana 这样的强大可观察性平台来监控和警报系统健康。然而,在预生产环境中,如临时环境或 UAT,只有基本的设置:可能只有一些日志或简单的正常运行时间监控。
这意味着虽然应用程序经历了各种测试阶段,但像 API 延迟或资源饱和度等关键性能指标并没有被监控。开发团队不知道,在负载下,某个特定的微服务在特定数量的并发用户下会开始表现出高延迟。这个问题只在应用程序上线后在生产环境中暴露出来,延迟的激增影响了真实用户,导致在实际事件压力下急忙处理问题。
如果可观察性向左转,这个问题本可以更早地被识别出来。通过正确的指标,开发人员会发现,在负载测试阶段,随着负载的增加,API 延迟逐渐增加,这使得他们能够在生产部署前解决该问题。
在可观察性中向左转的关键是意识到监控在所有环境中都至关重要,而不仅仅是生产环境。以下是如何开始的方法:
| 行动 | 描述 | 向左转的好处 |
|---|---|---|
| 提前部署监控 | 从一开始就加入监控和追踪,确保每个功能或服务在开发过程中(开发、CI、预发布)都有可观察性。 | - 早期问题检测 - 提升开发者责任感 |
| 监控 负载测试 | 将预生产环境的负载测试视作生产环境一样对待。使用像 Grafana 或 New Relic 这样的工具监控 API 性能、内存和吞吐量,以便尽早发现瓶颈。 | - 早期问题检测 - 降低失败成本 |
| 在 低环境中设置警报 | 在测试阶段实施关键问题的警报(例如:错误率上升、延迟异常),以便在问题进入生产之前解决它们。 | - 更快的解决时间 - 降低失败成本 |
| 使用 分布式追踪 | 在非生产环境中应用分布式追踪,以识别低效路径和瓶颈,为开发者提供修复问题的见解,防止问题升级。 | - 更快的解决时间 - 提升开发者责任感 |
表 10.6 - 从监控开始
总结来说,将可观察性向左推进,将其从一种被动、以生产为中心的实践转变为一种主动、全面的方式,保护整个云原生应用生命周期。通过提前投资于可观察性,你可以显著减少生产环境中出现意外情况的可能性,确保你的云原生架构能够在任何条件下可靠地扩展和运行。
警报疲劳与事件响应成熟度
在云原生环境中,警报疲劳是潜在的敌人,当团队被源源不断的通知淹没时,这种情况悄然发生,其中许多警报只是小问题或虚假警报。持续的噪声让即使是最警觉的工程师也会产生麻木感,导致关键警报被忽视或延迟。在最糟糕的情况下,团队可能会对低优先级的警报习以为常,以至于错过了最重要的警报。另一方面,事件响应成熟度则是解药,反映了团队高效管理警报、有效分类并精准迅速解决问题的能力。
但如何避免淹没在无休止的警报中呢?更重要的是,如何将警报混乱转化为一个精简且成熟的事件响应过程?
如何应对警报疲劳
-
优先处理关键警报:只关注真正重要的警报,即那些直接影响系统性能和用户体验的警报。如果某个警报不需要立即处理,那它只是噪声。保持信号的清晰。
-
设定合理阈值:警报应该只在超过关键阈值时触发。CPU 使用的小幅波动不应该让你的团队陷入慌乱。设计触发规则时,应该捕捉到显著变化,并过滤掉微小波动。
-
关联警报:当多个警报触发同一个潜在问题时,很容易让人感到不知所措。通过将相关警报组合成一个可操作的通知,你可以减少杂乱无章的干扰,为团队提供更清晰的问题概貌。
-
调整和再调整:警报规则不是“一劳永逸”的。定期回顾并调整它们,以跟上系统行为的变化。六个月前重要的事情,现在可能已经不再相关。去除无效的部分。
-
自动化重复性工作:对于已知的、重复出现的问题,进行自动化解决。如果问题可以通过脚本修复,就没有必要在凌晨三点把人叫醒。自动化可以减少警报量,并让团队专注于真正重要的事项。
-
事后回顾:事件发生后,分析哪些警报有帮助,哪些警报增加了噪音。利用这些经验教训进一步优化你的系统,确保下一次警报更加精准和高效。
通过聚焦于真正重要的事情,并持续优化警报流程,你可以从反应式的应急处理转变为主动且深思熟虑的事件管理。这是事件响应成熟度的路径:每个警报都有其目的,每次响应都迅速,系统也变得更加韧性。当警报疲劳逐渐消失时,剩下的是一台精细调优的机器,它平稳、高效地运行,并且在发生问题时,你能够及时了解并知道如何修复。
摘要
在本章中,我们剖析了常见的云原生反模式——无差别地记录所有日志、忽视机器学习和人工智能的潜力、忽略分布式追踪的重要性,以及在不成熟的警报和事件响应流程中磕磕绊绊。每一个这些错误都会削弱云原生架构的稳定性和效率,使团队在噪音、盲点和不必要的火灾救援中挣扎。然而,通过优化我们的做法——使用有针对性的日志聚合、利用人工智能驱动的洞察、拥抱分布式追踪以提高可视性,并且完善我们的事件响应流程——我们为更具韧性和灵活性的系统奠定了基础。通过规避这些反模式,我们从反应式的危机管理过渡到主动的运营卓越。
现在我们已经解决了潜在的隐患,是时候确保系统在压力下运行平稳了。在下一章中,我们将深入探讨随着云原生工作负载的扩展和演变,如何保持稳定性和性能。
第十一章:在不破坏它的情况下运行
在本章中,我们将探讨管理云环境所带来的操作挑战,以及如何保持系统平稳运行,不论发生什么。我们将涵盖从理解云服务商 SLA 到通过多区域部署、故障切换架构和自动化扩展构建弹性等各个方面。我们将深入讨论主动规划、冗余和自动化的重要性,以最小化停机时间并确保业务连续性。无论是准备应对云服务商的故障、更新运行手册和文档,还是适应成功云操作所需的文化转变,本章将为我们提供必要的策略和工具,帮助我们保持云基础设施的稳定与可靠。
我们将在以下主题中讨论这一点:
-
假设云计算只是“日常业务”
-
不足的灾难恢复和备份计划
-
过时的运行手册和文档
-
忽视文化转变
-
围绕 CSP SLA 进行开发
假设云计算只是“日常业务”
当企业迁移到云端时,常常忽视了随之而来的复杂性和陡峭的学习曲线。云操作需要与传统 IT 截然不同的技能组合,如果没有合适的规划,团队很容易陷入困境。
在本节中,我们将深入了解云计算采纳所带来的复杂性,并学习如何为即将到来的挑战做好团队准备。我们将深入探讨云基础设施、自动化、扩展性和成本管理的方方面面,以便进行规划并避免常见的陷阱。
理解云计算的复杂性
当我们做出迁移到云端的决策时,通常都有一个非常充分的理由。我们希望:
-
避免替换昂贵的本地遗留硬件
-
使我们的产品现代化,使用更先进的技术
-
利用不同技术中的灵活性
-
无限扩展我们的存储解决方案
-
拥有离线备份
这个清单既不全面也不局限,但无论出于何种原因决定迁移到云端,我们都可以预期将会有一个学习曲线。
当企业迁移到云端时,通常认为这只是一次常规的 IT 升级。但事实是,这完全是另一个全新的领域。我们来分析一些容易让团队措手不及的事情。
-
基础设施即代码(IaC):在传统 IT 中,设置基础设施可能涉及到物理安装服务器或通过 UI 点击来配置资源。 在云中,我们可能要处理的是基础设施即代码(IaC)。 这意味着我们编写脚本——使用像 AWS CloudFormation、Terraform 或 Azure ARM 模板这样的工具——来定义整个环境。 如果我们的团队不习惯将基础设施视为可以像软件一样进行版本控制和管理的内容,那么我们就已经落后了。 IaC 提供的灵活性非常强大,但也要求开发人员和运维团队在同一页面上,理解每一行影响环境的代码。
-
自动化和 CI/CD 流水线:另一个经常被低估的领域是自动化和持续集成/持续部署(CI/CD)流水线的作用。 在云中,手动部署是不可扩展的。 我们需要能够自动构建、测试和部署应用程序的流水线。 没有自动化工作流经验的团队很快就会发现自己被手动流程淹没,面临延迟,并且在不同环境之间存在不一致的风险。 看似快速的部署,如果是手动操作,最终可能变成一个故障排除马拉松。
-
多区域冗余和可扩展性:云环境使我们能够在多个区域运行应用程序,即使一个位置发生故障也能确保正常运行。 但设置这一点并不像按一下开关那么简单。 它需要精心规划,并深刻理解我们的应用程序和数据如何在各个区域之间进行复制。 如果我们的团队没有经验或没有正确考虑设计问题,我们可能会在停机期间处于脆弱状态,数据不一致或难以恢复。
-
成本管理:云服务是按需付费的,这可能是双刃剑。 虽然我们不需要为硬件预先付款,但糟糕的资源管理可能迅速导致意外成本失控。 不习惯考虑成本优化的团队——比如在不需要时缩减非核心服务——可能会在月底时收到巨额账单。 这不仅仅是关于构建一个解决方案;而是要从一开始就构建一个具有成本效益的解决方案。
简而言之,云操作与传统 IT 相比是完全不同的。 如果我们的团队没有能力应对这种复杂性,我们就会陷入困境。 适当的规划、培训以及对可用工具的深刻理解不仅仅是“锦上添花”——如果我们想在云环境中取得成功,它们是至关重要的。
培训与技能提升
当一个企业计划迁移到云时,这并不像按一下开关那么简单。 我们需要一个覆盖所有内容的可靠计划,从技术层面到让整个组织都参与进来。 这是我们的做法:
-
从云准备性检查开始:在我们深入实施之前,必须弄清楚我们目前的情况。云准备性检查的核心是了解当前的配置——哪些可以轻松迁移,哪些可能需要一些工作,潜在的成本和风险是什么。而且,不仅仅是 IT 部门应该参与。业务领导者需要理解这一举措如何影响他们的部门——运营、预算,一切。
示例:当我们进行云准备性检查时,发现一些旧系统需要大幅重构,才能考虑迁移到云中。但另一方面,我们的数据库?它们几乎迫切需要提升和迁移,这从一开始就为我们节省了时间和金钱。
-
面向所有人的教育与培训:在云计算方面,技能差距是一个现实问题。我们的 IT 员工确实需要获得云认证,但不要仅仅停留在此。财务、市场营销、风险团队,甚至法律团队都需要理解云计算对他们意味着什么——成本结构、合规性、安全性等等。投资工作坊、培训项目和外部顾问,确保每个人都在同一页面上。
示例:我们不仅仅对 IT 进行了培训。财务部门学习了云计费的真正运作方式,并设置了警报,以避免月底的“意外惊喜”。同时,市场营销部门也接受了云合规性的速成课程,确保他们在我们的全新环境中不会因数据隐私问题而犯错。
-
设定明确、可衡量的目标:我们需要知道为什么要做这个决策。是为了减少资本支出吗?提高可扩展性吗?改善灾难恢复计划吗?无论我们的目标是什么,都要确保它们是可衡量的,并与我们的业务优先事项对齐。这样,我们就能知道是否按计划进行,并且我们的团队也有了明确的目标。
示例:我们的一个大目标?在一年内将基础设施成本减少 30%。我们确保它与业务相关,并且每个季度跟踪进展,确保云计算能有效地发挥作用。
-
构建一个稳固的迁移策略:一旦我们确定了目标,就需要一个策略来规划如何实现这些目标。采取什么方法——提升迁移、重新平台化,还是其他什么?谁负责什么?我们选择单一云、多云还是混合云模型?这些都是决定迁移方式的关键。确保我们的策略考虑到供应商锁定、互操作性和安全性等因素。
示例:我们的迁移策略并不是“一刀切”。我们从分阶段的方法开始,先将非关键应用进行提升和迁移,同时将核心服务重新平台化,以便利用云原生特性,如自动扩展。我们还通过规划多云策略来避免供应商锁定,保持对未来的关注。
-
沟通至关重要:这不仅仅是一个 IT 项目——它是整个业务的转变。我们需要让每个人都了解情况。解释我们为什么要迁移到云端以及它将如何惠及业务。定期更新有助于避免抵制,并确保每个人都知道接下来会发生什么,以及它将如何影响他们。
例如:每两周,我们都会进行公司范围的更新,解释迁移的进展以及接下来会发生什么。这种开放的对话有助于减少抵抗,并让每个人保持同步,避免惊讶,只有进展。
-
早期建立治理和合规性:云端为我们提供了灵活性,但如果没有正确的治理,事情可能会失控。从一开始就设立政策,定义谁可以访问资源,数据如何处理,以及如何进行监控。尽早让我们的法律、合规和安全团队参与进来,以确保一切符合规定。
例如:我们早早让法律团队参与进来,与 IT 团队并肩工作,制定访问政策,并确保数据处理符合客户要求的标准。定期的审计被纳入流程中,从而在扩展过程中将合规性内建。
-
测试一切:在我们切换之前,确保我们已经测试了所有内容——性能、安全性、备份和恢复流程。运行试点或概念验证项目,在全面迁移前解决任何问题。这是我们发现潜在问题的机会,千万不要跳过。
例如:在我们决定迁移面向客户的应用之前,我们将其与本地系统并行运行了一个月。这段时间让我们有机会解决一些延迟问题,并确保一切稳定后再切换用户。
-
迁移后的支持:我们迁移了数据或应用后,工作并没有结束。我们需要为持续支持做好规划——监控、成本优化和故障排除。确保我们有团队或合作伙伴准备好处理日常的云管理工作,并保持一切顺利运行。
例如:迁移后,我们有一支云运营团队准备就绪,负责监控和故障排除。自动化的成本预警系统被设置,以便捕捉到任何成本激增,且每周的回顾帮助我们保持检查,确保环境保持优化。
简而言之,迁移到云端不仅仅需要技术规划。更重要的是让整个业务都参与进来,设定明确的目标,并制定坚实的战略。如果我们全面覆盖各个方面,迁移将会顺利进行,避免未来的意外。
协作学习至关重要
总结来说,鼓励协作是弥合技能差距并保持团队敏锐的关键。组织内部培训,投资云认证,确保文档易于访问并且是最新的。当每个人共享知识并合作时,我们将避免由于孤立作业而产生的瓶颈和困惑。确保整个团队在同一理解下前进——这在长期来看将大有裨益。
在接下来的章节中,我们将讨论你的团队应该如何共同合作,制定适当的灾难恢复计划,并确保你的数据安全备份。
不足的灾难恢复和备份计划
灾难恢复(DR)通常在云操作中被推到次要位置,许多企业认为他们的云提供商会处理所有问题。但这是一个危险的假设。虽然云提供商提供了一些内建冗余,但灾难恢复的责任在于你。没有一个经过定期测试的可靠灾难恢复计划,我们就等于打开了大规模停机和潜在数据丢失的大门。我们不能只是希望云设置在故障后会自动恢复,我们需要一个清晰、经过测试的策略。
我们将讲解构建全面的灾难恢复和备份计划的关键组成部分,恢复点目标(RPO)与恢复时间目标(RTO)之间的关键区别,以及应对数据丢失、实例故障和可用区故障的策略。目标是确保我们的系统即使在出现问题时,也能更快地恢复并继续运行。
构建全面的备份计划
我们的灾难恢复(DR)策略不仅仅是一个可有可无的选项;它对于确保我们的业务在出现问题时继续运行至关重要。我们需要超越基本的备份,开始在多个区域构建冗余。使用像 AWS Elastic Disaster Recovery、Azure Site Recovery 或 GCP Backup & Restore 这样的云原生工具,确保如果一个区域发生故障,我们的服务能够无缝切换到另一个区域。考虑故障转移机制、自动扩展,以及我们如何尽快将关键系统恢复上线。
制定全面备份计划时需要考虑的因素有很多。
RPO 与 RTO
首先,让我们从两个术语的定义开始:
-
恢复点目标(RPO):这是在发生某种故障时我们能够承受的最大数据丢失量。问问自己:“我的业务能承受多少数据丢失?”。
零售商店可能能够承受较高的 RPO。也就是说,在发生故障时,它们可以支持数据丢失回溯到前一天的营业结束时。
另一方面,金融机构不能承受数据丢失,需要将 RPO 保持在尽可能低的水平,甚至在某些情况下为零。
-
恢复时间目标(RTO):这是在恢复环境时所能容忍的最长时间。
问问自己:“在发生故障时,我愿意失去多少业务?”实际上,我们并不希望失去任何业务,但在故障发生时,时间是一个关键因素。
回顾我们上面的两个例子,一个零售商店可能在周一至周五,早上 9 点到下午 5 点营业,可能能够承受 24 到 48 小时(大约 2 天)的恢复时间目标(RTO)。毕竟,系统故障总是在周五下午发生,对吧?就在我们准备去度过一个轻松的周末时发生?开个玩笑,在我们的零售例子中,较大的 RTO 是可以接受的。
另一方面,我们的金融机构需要一个非常低的 RTO,在某些情况下,甚至低于一小时。
我们可以通过许多方式来完善我们的 RPO 和 RTO 策略:
-
客户服务水平协议(SLA)/服务水平目标(SLO)
-
技术目标和约束
-
行业级别的合规性和监管要求
然而,仅仅根据这些因素之一来决定我们的灾难恢复计划并不可取。确保这三大因素都在协作的框架下进行考虑非常重要。
-
客户的 SLA / SLO 是由高层决定的,并由高管和销售代表写入合同。然而,如果技术目标没有对齐,这些协议就无法得到履行。
-
技术团队可以制定灾难恢复计划并配置备份计划,然而,没有明确的目标,这些措施是无法有效的。也许有些技术约束会限制技术团队交付正确结果的能力。
-
技术团队和高层管理团队还需要了解行业级别的要求,以防止遭受商业处罚或失去某些认证。
协作是构建全面、清晰、简明灾难恢复计划的关键。
灾难恢复策略
拥有灾难恢复(DR)计划只是战斗的一半,测试它才是实际工作的开始。我们不能仅仅设置好然后就忘记它。需要定期进行灾难恢复演练,模拟停机情况,看看我们的团队和基础设施如何响应。测试我们的备份,进行故障切换场景演练,确保一切按预期工作。现在发现问题总比在真正的灾难发生时才知道要好。如果我们的备份过时或损坏,那么当我们最需要它们时,将会迎来一个可怕的惊喜。
确保我们已经针对一些最常见的场景进行了计划和演练是非常重要的。测试灾难恢复策略对于确保我们的工作负载在出现问题时能够恢复至关重要。这不仅仅是拥有一个计划——它还关乎减少停机时间,并在问题发生时更快地恢复正常。请考虑以下三种主要场景,并在制定策略时,问问自己这个反问句:“我该如何从中恢复?”:
意外数据丢失
如果有人在数据库中删除了错误的表或生产环境中的客户记录损坏了,我们如何恢复数据?数据丢失不仅限于数据库。考虑亚马逊 S3、Azure BLOB 存储或 Google Cloud 存储中的对象存储。以及像亚马逊 EBS、Azure 磁盘存储或 Google 持久磁盘这样的服务器附加卷上的文件存储。
对于数据库,我们需要考虑一定程度的时间点恢复(PITR)。这可以帮助防止数据库上的意外、删除或写入,使我们能够恢复到特定时间点,精确到分钟级。PITR 使用数据库技术中的事务日志等数据库特性来实现这一点。
在我们的数据库上启用 PITR 可以将我们的 RPO 降低到尽可能小的范围,范围为 0 - 15 分钟,具体取决于数据库引擎的选择。
对于对象存储,防止数据的意外删除或写入具有简单而强大的设置。在对象存储上启用版本控制,并在删除对象时启用多因素身份验证,只是保护数据的两种方法。如果有人意外覆盖了我们对象的副本,我们可以恢复到之前的版本。这与数据库的 PITR 具有非常相似的效果,将我们对象存储的 RPO 降低到几乎为零。
块存储比对象或数据库更难保护。因为它是基于时间快照的块系统,我们只能使用最后一个时间快照中可用的内容。因此,建议将持久数据转移到托管共享数据服务,例如亚马逊 EFS 或 FSX、Azure Files 或 Google Cloud 文件存储。这些服务类似于附加到我们服务器的 NAS 设备,可以使用更精细的备份策略单独进行备份。块存储应仅用于短暂的应用程序。
实例丢失
在您的架构中,您可能有多个计算或数据库实例。本节适用于以下任何实例,但不限于:
-
亚马逊网络服务
-
EC2 实例
-
ECS 容器
-
EKS 节点
-
Lambda 函数
-
RDS 实例
-
-
Microsoft Azure
-
虚拟机
-
Kubernetes 服务(AKS)
-
容器实例(ACI)
-
Azure 函数
-
Azure 数据库
-
-
Google 云平台
-
计算引擎实例
-
Kubernetes 引擎(GKE)节点
-
Cloud Run 容器
-
云函数
-
Google 云 SQL
-
考虑在我们的架构中,当这些项目中的任何一个关闭时会发生什么。
始终详细规划是个好主意。在图表中绘制架构,并开始考虑如果我们取出单一资源会发生什么。我们的架构会受到什么影响?我们是否有单一故障点?

图 11.1 - 检查单点故障的架构
对于大多数计算级服务,有几种简单而有效的方法可以防止实例丢失。
-
负载均衡: 通过在工作负载前面放置负载均衡器,我们可以利用许多功能来帮助保护我们的工作负载。
-
将负载分配到多个实例上。
-
SSL 卸载
-
边缘级网络保护(WAF、DDoS 保护等)
即使在单实例情况下,通过使用负载均衡器,我们也能将实例与直接的互联网流量隔离,应用层次化的保护。
-
-
自动扩展组: 如果我们的服务设计上是短暂的,那么将其放入自动扩展组可以大大帮助我们的灾难恢复工作。一个自动扩展组(由 Amazon EC2 自动扩展、Azure 虚拟机规模集、Google 计算引擎自动扩展器提供)可以在我们的实例负载过重时按需添加额外实例。它还可以在实例启动时监控其健康状况,并在认为实例不健康时,用新的实例替换它,提供一定的自动修复功能。
像负载均衡器一样,即使在单实例环境中,使用自动扩展组也能提供必要的保护。
将这两项服务结合起来,可以提供一种策略,将我们的工作负载跨多个网络子网或可用区进行分配。
对于数据库实例,这应该不会太复杂。大多数托管数据库实例都可以进行保护:
-
AWS RDS: 使用多可用区(multi-AZ)配置,将我们的数据库自动复制到多个可用区,以实现高可用性和自动故障转移。
-
Azure SQL 数据库: 提供跨可用区的数据复制的区冗余配置,以确保弹性和高可用性。对于更复杂的配置,我们提供了地理复制和故障转移组功能,适用于 Azure SQL 托管实例以及 Azure MySQL/PostgreSQL 数据库。
-
Google Cloud SQL: 通过将我们的数据库跨区域内的多个可用区进行复制,提供高可用性配置。如果某个可用区出现故障,故障转移将自动启动。对于分布式工作负载,Cloud Spanner 和 Bigtable 提供了内建的跨可用区,甚至跨区域的复制,以实现全球弹性。
每个云服务提供商在多可用区和多区域设置方面有不同的方案,但目标是一样的:即使遇到问题也能保持数据库运行。
可用区故障
需要考虑的第三种也是最后一种情况是没有本地数据中心或提供商的重大故障。
全球云基础设施解读
Amazon Web Services (AWS): AWS 有多个区域(Regions),这些区域是地理上独立的,每个区域都有多个可用区(AZ)。这些 AZ 是独立的数据中心,能为我们提供高可用性和冗余性。
Google Cloud (GCP): GCP 采用与 AWS 类似的架构,拥有地理上独立的区域(Regions),在这些区域内部,我们有多个可用区(Zones),其作用与 AWS 的 AZ 相似。每个可用区都是一个独立的故障转移和冗余位置。
Microsoft Azure:Azure 与 AWS 和 GCP 一样,也有区域(Regions)和可用区(Availability Zones,AZs),以确保我们的工作负载保持弹性。但 Azure 还增加了称为可用性集(Availability Sets)的功能。这些功能帮助我们将虚拟机(VM)分布在数据中心内的不同硬件集群上,为我们提供额外的保护,以防局部故障。
在构建我们的架构时,我们需要考虑如何在不同位置之间分配工作负载。确保我们至少能够切换到另一个可用区(Zone / AZ)是非常重要的,某些服务在其功能集中已考虑到了这一点。
数据库服务允许进行多可用区(Multi-AZ)或冗余区配置。这意味着,如果某个可用区出现故障,我们的数据库将在最短的时间内进行故障转移。这是一个可选配置,通常会有成本影响,但成本是用来覆盖后台配置的额外实例,并且实时进行数据复制。在大多数情况下,这是一种透明的配置,一旦选择了该选项,它就会自动发生,通常我们容易理所当然地认为它是默认开启的,甚至可能会考虑禁用以节省成本。这就是我们不知道需要但有时会被充分利用的保险政策,因为有很多理由使用多可用区配置。
-
可用区的自动故障转移
-
通过先将配置应用于备用实例,再进行切换,减少配置更改期间的停机时间
-
通过从备用实例进行备份,避免对主节点性能的影响
其他可考虑的数据库选项可能是使用只读副本实例。这是我们有意配置并作为只读数据源使用的实例,适用于商业智能报告、备份,甚至可能是客户访问。这些副本实例在故障发生时可以提升为主节点,因此也有必要将我们的只读副本部署在另一个可用区。
对于计算实例类型,实例丢失中讨论的方法通常与可用区(AZ)/区域(Zone)故障时相同。只需确保我们将负载均衡器和扩展组配置为跨 2 个或更多可用区,这样可以确保它们高度可用,并且不会形成单点故障。
总结灾难恢复与备份
简而言之,灾难恢复是我们不能忽视的内容,它不能没有计划或未经过测试。这不仅仅是关于数据备份,还确保当发生故障时,我们的服务能够迅速且无缝地恢复。通过专注于覆盖 RPO、RTO 和多区域冗余的全面策略,我们将能够更好地应对任何突发灾难。
虽然灾难恢复计划很重要,但同样重要的是确保你在合适的时间为团队提供最新的运行手册和文档。我们将在下一节中详细讨论这一点。
过时的运行手册和文档
云环境以惊人的速度发展。基础设施发生变化,新增服务,实时扩展,安全更新频繁推出。在如此多的变动中,文档和操作手册容易过时。一旦发生这种情况,我们就会打开通向运营低效、沟通不畅和关键时刻发生错误的大门。过时的文档会导致团队在故障排除时走错路,浪费时间,甚至可能造成更大的问题。保持操作手册和文档的更新,对于维持顺畅的运营至关重要,确保在问题出现时每个人都能达成共识。
通过这一部分,我们将回顾一些最佳实践,以确保通过关注我们的文档和操作手册来保持最大运营效率。我们将回顾这一概念,并提出一些实际步骤,帮助我们保持文档的完整。
维护更新的文档
文档不是我们写完就忘记的东西,它是一个需要定期维护的活文档。随着基础设施的变化,无论是新部署、扩展,还是架构变化,我们的操作手册和文档应立即反映这些更新。当文档与当前环境不同步时,团队更容易遵循过时的程序,这可能导致响应时间缓慢,或者更糟,发生操作失败。
管理此过程的最佳方法之一是建立文档审查计划,直接与关键操作事件挂钩。在每次重大基础设施更新后,团队应审查相关的操作手册和技术文档,确保它们与当前的设置一致。这个审查过程可以融入变更管理程序,确保我们的基础设施更新自动触发文档审查。这是关于建立持续审查和对齐的习惯,以避免将来出现混乱。
另一种更具互动性的方法是通过“游戏日”来确保文档的质量。这可以被视为一种桌面演习,甚至是通过虚拟场景在安全的环境中进行的模拟。第八章对此有更详细的描述。
重要说明
实施 ISO 9001 可以极大地提高在云环境中保持操作手册、标准操作程序(SOP)和文档最新的过程。通过关注文档控制、定期审查和通过计划-执行-检查-行动(PDCA)循环进行持续改进,ISO 9001 确保了一致性和问责制。它强调基于风险的思维和审计,有助于减少过时文档的风险,并与 AWS CloudFormation 和 Azure ARM 模板等自动化工具协同工作,以简化更新并保持准确性。
ISO 9001 是质量管理体系(QMS)的国际标准。它为组织提供了一个框架,确保其流程始终符合客户和监管要求。ISO 9001 侧重于提高效率和保持高质量标准,强调客户导向、领导力、基于风险的思维、持续改进和文档控制等原则,使其成为确保各行业可靠、可重复结果的宝贵工具。
自动化文档
手动更新文档?那是通往灾难的快速通道。在快速变化的云环境中,手动更新根本无法满足需求。当有人来处理一个紧急事件时,他们需要在修复可能让问题更糟的地方之前,了解当前架构为何处于这种状态。这时,自动化工具发挥了作用。像 AWS CloudFormation、Azure ARM 模板和 GCP 部署管理器等工具可以自动将我们的文档与基础设施变更保持同步,减少人为错误,确保我们始终在使用最新的信息。
以 AWS CloudFormation 为例。当我们使用 CloudFormation 模板管理基础设施时,这些模板本身就作为文档的一种形式,准确展示了我们的资源配置情况。同样,Azure ARM 模板和 GCP 部署管理器也具有相同的功能。这些工具生成实时的基础设施更新,通过使用它们,我们确保文档永远不会滞后。
自动化文档也减少了手动更新时出现的人为错误。随着我们的云基础设施日益复杂,手动跟踪每个变更变得难以管理。自动化工具帮助我们简化这个过程,确保文档准确、最新,并与当前基础设施保持一致。
标准操作程序(SOP)
我们的标准操作程序(SOP)对于保持云环境高效运行至关重要,但它们只有在保持相关性时才有价值。像运行手册一样,SOP 不应该一写了之,而是需要随基础设施和工作流程的变化不断演进。在云环境中,架构或服务的快速变化可能使旧有的程序变得过时,这一点尤其重要。
定期审查标准操作程序(SOP)至关重要。每当我们的云架构发生变化,无论是部署新服务还是进行扩展调整,我们都应该重新审视 SOP,以确保它们仍然适用。当我们管理较小的基础设施时有效的程序,在扩展后可能不再适用。定期审查和更新 SOP 能确保我们的团队始终使用最当前的信息,快速高效地执行任务。
此外,在更新 SOP 时,务必包含从事故或停机事件中学到的任何经验教训。如果因程序缺口或疏忽导致故障发生,请更新我们的 SOP 以防止类似问题的再次发生。SOP 不仅仅是处理日常操作,它们反映了我们组织持续改进的过程。
重要提示
AWS Well-Architected 框架源自一次大规模停机事件的经验教训,当时早期的云计算采用者在设计具有弹性和可扩展架构时面临重大挑战。
AWS Well-Architected 框架由一系列文档化的最佳实践(或 SOP)构成,帮助我们最大化云架构的效益。
让我们更实际地看待这个问题。
实际操作中的文档和操作手册
所以,我们讨论了关于文档和 SOP 的常见原则,但我们可以采取哪些实际步骤来确保遵循文档最佳实践?我们可以遵循哪些技术指南?
-
实现基础设施即代码(IaC)
-
工具:使用 AWS CloudFormation、Azure ARM 模板和 Google Cloud 部署管理器等工具,将我们的基础设施定义和管理为代码。这些工具会自动创建模板,作为我们环境的实时文档。
-
版本控制:将这些模板存储在 Git 等版本控制系统中,以跟踪所有基础设施更改,便于必要时进行回滚,并提供准确的变更记录。
-
好处:基础设施即代码确保我们的文档与当前的基础设施状态保持一致,避免了手动更新的需求。
-
-
自动化文档更新
-
工具:集成 Terraform Cloud 或 CloudFormation Drift Detection 等工具,自动检测基础设施的变化并实时更新文档。
-
脚本:设置自动化脚本,从基础设施中提取更改并在 Confluence 或 SharePoint 等平台上更新文档。
-
好处:自动化确保我们的文档始终保持最新,而无需依赖手动流程,减少过时信息导致错误的可能性。
-
-
使用监控和警报系统
-
工具:利用 AWS CloudWatch、Azure Monitor 或 Google Cloud Operations Suite 来监控基础设施的健康状况和变化。
-
自动化:当基础设施发生变化或检测到警报时,自动触发文档审核。这可以与我们的 IT 服务管理(ITSM)工具(如 ServiceNow 或 Jira)集成。
-
好处:持续监控确保团队及时了解基础设施中的关键变化,提供主动更新文档或标准操作程序(SOP)的机会。
-
-
集中式知识管理
-
工具:实施集中式文档工具,如 Confluence、Notion 或 Azure DevOps Wiki,将所有操作手册、SOP 和技术文档存储并组织在一个地方。
-
可搜索的数据库:确保所有文档都易于搜索并且团队能够轻松访问。
-
好处:集中管理文档确保所有团队都能参考相同的最新信息,这样可以减少操作中的混乱和沟通不畅。
-
-
将文档嵌入到变更管理中
-
变更管理:确保每次基础设施变更都包含相关文档的审查,这样更新成为变更过程的一部分。这也有助于确保没有偏离原始设计的意图。
-
责任划分:指定具体团队成员负责文档更新,以形成问责制。
-
好处:将文档嵌入到变更管理中,确保每次变更都伴随必要的运行手册和 SOP 更新,从而避免基础设施和文档之间的不同步。
-
保持运行手册、文档和标准操作程序(SOP)最新,不仅仅是遵循最佳实践。这关乎避免代价高昂的错误、减少停机时间,并确保我们的团队在问题发生时能够有效地实时响应。在云环境中,随着变化迅速,过时的文档就像一颗定时炸弹,可能导致响应缓慢、混乱,甚至无法解决关键问题。
通过定期审查并自动化更新我们的文档,我们不仅在提高运营效率,还确保我们的团队在最需要的时候能够快速访问正确的信息。这是对韧性、敏捷性和长期云成功的投资。
随着向云端转型,运行手册和文档应当成为你文化的一部分,忽视这一点可能会对你的云采纳工作造成毁灭性影响。我们将在下一节讨论文化转型的问题。
忽视文化转型
在云端运营不仅仅是采纳闪亮的新技术——更是让团队以全新的方式共同工作。许多组织匆忙投入云项目,认为一切都围绕工具,但真正的挑战在于改变团队协作的方式。如果我们没有鼓励跨职能的团队合作,我们的云战略很快就会碰壁。云成功不仅依赖于基础设施,还依赖于团队如何互动、共享知识以及将他们的努力对准共同目标。
在本节中,我们将清晰地理解为什么协作对于云的成功至关重要。我们将了解如何打破信息孤岛,促使开发、运维和安全团队合作,从而避免错误并加快工作进度。我们还将深入探讨为什么跨职能团队和 DevSecOps 思维对提高效率和安全性至关重要。此外,我们还将讨论知识共享的重要性,以及在云环境逐步发展的过程中,如何确保每个人都保持同步。最后,我们将探讨如何管理对变革的抵制,确保我们向云转型的过程顺利而有效。
鼓励协作
云环境在团队之间沟通时能够蓬勃发展。在传统 IT 设置中,开发、运维和安全常常各自为政。开发人员推动代码,运维负责基础设施,安全团队则关注漏洞——每个团队都处在自己的“气泡”中。但在云环境中,我们不能承受这种分隔。开发、运维和安全必须始终保持同步。要打通沟通渠道,确保这些团队从一开始就紧密合作。
为什么这如此重要?云环境是动态的,变化迅速。代码部署更快,资源扩展或收缩,安全威胁不断演化。如果我们的团队没有协作,一个团队的变动可能会无意中对另一个团队造成问题。开发人员可能会引入新代码,从而无意中削弱安全性。运维团队可能在不知情的情况下推出变更,导致整体基础设施受到影响。当团队之间相互孤立时,这些变更可能会漏网,导致效率低下、停机,甚至更严重的安全漏洞。
协作不仅仅是“锦上添花”。它是有效云操作的支柱。团队需要打破障碍,作为一个整体围绕共同目标工作。促进这种协作的最有效方式之一是定期检查、跨团队会议和协作式问题解决会话。通过建立这些开放的沟通渠道,我们为团队提供了早期讨论问题、分享知识、并在问题成为大麻烦之前发现它们的空间。
打破信息孤岛
组织内部的信息孤岛是协作的主要障碍。在传统的 IT 环境中,团队通常有着严格定义的角色和职责。开发团队专注于编写代码,运维团队负责基础设施的部署和维护,安全团队则监控威胁和漏洞。虽然这种劳动分工在传统本地基础设施时代是合理的,但它与云环境的灵活性和速度并不匹配。
在云环境中,我们需要每个人在项目的整个生命周期中通力合作。开发团队不能仅仅把代码丢给运维然后就走开。安全团队不能等到最后才参与进来。云环境需要持续的协调。云所提供的灵活性和规模是很棒的,但它们也增加了复杂性——而复杂性带来了风险。孤立的部门只会加剧这些风险,因为它们导致了沟通不畅、工作流程割裂以及重复劳动。
那么,如何打破这些孤岛呢?从培养 DevSecOps 文化开始,让开发、安全和运维从第一天起就共同协作。这里的关键是共享责任。每个团队都应该理解他们的工作如何影响更广泛的系统,并且如何为共同目标作出贡献。我们还可以实施更正式的流程,例如集成的项目管理系统和定期的跨职能团队会议。打破孤岛需要时间,但一旦团队开始更紧密地协作,我们将看到更少的瓶颈、更快的问题解决,以及更加顺畅的云操作。
回顾一下 - 康威定律
在我们深入打破孤岛并推动团队间更多合作的同时,值得时刻记住康威定律(我们在第一章中已经讨论过)。这个观点提醒我们,团队间的沟通方式将直接影响系统的最终结果。如果我们没有作为一个整体协同工作,那么我们的云架构就会反映出这些沟通上的漏洞。因此,让开发、运维和安全团队保持一致,不仅仅是锦上添花,而是构建真正具有弹性系统的必要条件。
跨职能团队
创建跨职能团队是推动云操作中合作的最有效方式之一。这些团队将开发、运维和安全的成员聚集在一起,确保项目从一开始就涵盖所有方面。再也不需要等到最后一刻才让安全团队介入漏洞评估,或者等运维团队搞清楚如何扩展新的部署。从第一天起,每个人都参与其中,这促使了更好的对齐、更快的决策制定,以及更少的意外情况。
跨职能团队不仅仅是为了更快地完成任务——它们更重要的是提升工作质量。每个团队成员都带来了他们独特的专业知识,通过共同合作,他们能够更全面地解决挑战。例如,开发人员了解代码,但他们可能不了解基础设施的限制;运维人员知道如何扩展,但他们可能不了解某些配置的安全影响;安全人员了解漏洞,但可能不了解最新的开发框架。通过将这些不同的视角结合起来,我们可以打造一个更加弹性和全面的云操作。
这种方法还培养了 DevSecOps 思维,这是云成功的关键。DevSecOps 注重持续集成和持续交付(CI/CD),开发与运维携手合作,自动化并简化部署过程。这种思维方式消除了开发与部署之间的摩擦,使更新发布变得更加轻松,并减少了停机时间。安全性需要从一开始就融入到这个过程中,因此,DevSecOps 方法—将安全性融入开发和运维—对于保护我们的云环境至关重要。
知识共享
云技术始终在发展,要跟上变化,感觉像是一场永无止境的竞赛。如果我们的团队不共享知识,我们很快就会落后。每一个新工具、每一次基础设施的更新和每一个安全威胁,都需要所有相关人员了解。这就是知识共享的意义所在。
仅靠一个人或一个团队成为专家是不够的。信息需要在团队之间自由流动,以确保每个人都能及时了解发生了什么。这可以通过正式渠道如培训课程来实现,但更有效的方法是创建一种非正式知识共享的文化。定期的团队会议,可以让人们讨论他们面临的挑战、发现的新工具或他们学到的经验教训,这些都非常宝贵。
云计算是复杂的,没人能知道所有的事情。但通过鼓励团队分享所知道的,我们可以建立更强大、更有凝聚力的运作。当一个团队学到新知识时,确保他们将这些知识传递给其他团队。这不仅有助于团队的成长,还能确保知识孤岛的形成。我们团队分享得越多,云运作就会变得越具韧性。
推广 DevSecOps 思维
DevSecOps 思维注重打破开发和运维之间的障碍。在传统的 IT 架构中,这两个团队往往孤立工作,这可能导致延迟、沟通不畅和效率低下。然而,在云环境中,开发和运维需要持续合作。这种方法促进了协作,提高了效率,并且允许更快速、更可靠的部署。
在 DevSecOps 的世界里,开发人员不仅仅是编写代码并交给运维—他们还负责代码在生产环境中的表现。运维人员也不只是维持基础设施—他们参与开发过程,确保一旦部署,系统能够平稳运行。这种共同的责任有助于及早发现问题,并确保整个团队在项目目标上达成一致。
自动化在这里发挥着巨大的作用。通过自动化重复性任务——如测试、部署和监控——我们可以解放我们的团队,使其能够专注于更高层次的问题。自动化还减少了人为错误的风险,这在快速变化的云环境中至关重要。当一切都被自动化时,我们可以更快地行动,更频繁地部署更新,而不必担心遗漏任何细节。
克服对变革的抵制
即使我们知道协作至关重要,实施起来也并不总是容易的。习惯于孤立工作的团队可能会抵制转向协作。他们可能觉得这会增加工作量,或者他们的专业知识得不到尊重。这种抵制是自然的,但如果我们的云战略要成功,就需要解决这个问题。
要克服对变革的抵制,我们需要的不仅仅是空话——我们需要实时展示变革的好处。做到这一点的最有效方式之一就是推出一个试点项目。试点项目让我们在较小的范围内测试水域,同时向大家展示跨职能团队如何推动实际结果。通过选择一个关键项目,我们从第一天起就将开发、运营和安全团队聚集在一起,打破孤岛,展示协作如何带来更快的部署和更少的麻烦。
随着我们看到问题解决速度的提升和操作的顺畅,获得组织其他成员的支持变得更加容易。试点项目的魅力在于它具有低风险但高影响——为我们提供了所需的证据,证明协作不仅更高效,而且对于构建韧性系统至关重要。一旦试点成功,我们就可以将这种方法扩展到更多团队,使协作成为新的标准。
领导力在这里也扮演着关键角色。领导者需要为协作定下基调,表明它不仅仅是一个短暂的趋势,而是组织运作的一个重要部分。他们需要鼓励开放的沟通,提供必要的工具和支持,并在团队适应新的工作方式时保持耐心。文化转型不是一蹴而就的,但通过正确的方法,它可以改变我们团队的工作方式。
忽视文化转型是迁移到云端时组织可能犯下的最大错误之一。仅仅拥有合适的工具是不够的,我们需要我们的团队无缝协作,才能在云端取得成功。协作、跨职能团队、持续学习和 DevSecOps 思维方式对于构建韧性的云端运营至关重要。打破孤岛,促进沟通,并确保每个人在相同目标上保持一致。只有这样,我们才能释放云计算的真正潜力,确保长期成功。
当我们接近本章的结束时,我们最后要看看云服务提供商的服务水平协议的陷阱和误解,以及为什么它们不应该成为我们依赖的首要工具。
围绕 CSP SLA 进行开发
云服务提供商(CSP)的 SLA 可能承诺高可用性,但仅仅依赖这些保证可能让我们变得脆弱。开发超越 SLA 提供的弹性架构对于维持正常运行时间和确保业务连续性至关重要。
本节将深入探讨为什么仅仅依赖云服务提供商 SLA 对于实现真正的韧性是不够的。我们将分析如何通过多区域部署、故障转移系统和负载均衡来构建冗余,以保持一切平稳运行,即使提供商遇到问题。我们将学习如何通过多云策略、第三方冗余和异地备份来保护我们的系统,确保数据安全并保持业务运转。最后,我们将探讨如何通过自动化故障转移、负载均衡和自动扩展来提高效率,减少停机时间,并在不依赖人工修复的情况下保持基础设施的响应能力。
什么是 CSP SLA?
云服务提供商(CSP)SLA 本质上是我们与云服务提供商之间的合同,列出了我们可以期待其服务在性能、可用性和正常运行时间方面的表现。这是提供商告诉我们:“这是我们保证的内容”,但合同中通常包含大量细则。这些协议通常涵盖正常运行时间保证,比如 99.9%的可用性,并界定了提供商的责任范围。理解 SLA 中的具体内容非常重要,因为任何超出这些范围的部分将由我们来负责,而不是他们。因此,如果出现问题,我们需要知道它们的责任与我们需要承担的责任之间的界限。
超越 SLA 构建冗余
仅仅依赖我们的云服务提供商(CSP)SLA 是不够的,如果我们想要真正的韧性。没错,他们承诺高可用性,但即便是 99.9%的正常运行时间保证,实际上每年依然可能会有超过八小时的停机时间。对于关键任务系统,我们不能只依赖这个。我们需要在云服务提供商的保证基础上,构建我们自己的冗余层。这意味着我们需要准备备份计划,以应对那些不可避免的问题,因为问题不是发生与否,而是何时发生。冗余确保我们的系统保持运行,即便云服务提供商的服务没有达到他们的承诺。
以下是我们如何构建真正的冗余并确保我们的系统保持运行,即使在云服务提供商的 SLA 未能兑现时:
-
跨多个可用区部署:首先将我们的资源分布在同一区域内的多个可用区。这可以保护我们免受区域级故障的影响,比如硬件问题或局部停机。
-
跨多个区域部署:更进一步,通过跨多个区域进行部署。如果某个区域出现故障,我们的服务可以自动故障转移到另一个区域,确保我们的全球业务平稳运行。
-
设置故障转移架构:实现像热备或冷备的故障转移系统。这些系统在发生故障时会自动启动,从而避免我们浪费宝贵的时间手动修复问题。
-
使用负载均衡器:通过负载均衡器将流量分配到多个实例上,避免任何单个服务器超负荷。如果某个实例出现故障,负载均衡器会将流量转移到健康的实例上,保持服务的可用性。
-
实施自动扩展:使用自动扩展确保我们始终拥有足够的资源。当需求激增或系统发生故障时,自动扩展机制会自动增加实例或资源,确保系统稳定运行。
-
利用备份保护关键数据:定期备份数据,并将备份存储在不同的区域。如果主存储发生故障或数据损坏,我们可以迅速从其他位置恢复数据,而不会丢失重要信息。
-
主动监控与告警:使用像 CloudWatch 或 Azure Monitor 这样的工具来监控系统。设置告警以便在问题发生时立刻通知我们,从而提高响应速度。
-
测试故障转移和冗余计划:定期测试故障转移和冗余设置。不要等到实际停机发生时才验证系统是否有效,进行演练确保在故障发生时一切如预期工作。
在构建可靠的云系统时,我们不能仅仅依赖服务提供商的 SLA 并期望一切顺利。真正的弹性意味着我们要加设自己的冗余,部署多个可用区,设置故障转移系统,并确保我们的基础设施能够应对故障而不间断运行。通过采取这些实际措施,例如负载均衡、自动扩展、多区域部署等,我们不仅仅是在应对问题,而是在主动构建一个能够承受问题的架构。关键在于预测故障,并在故障发生前做好准备。这就是我们如何确保云环境始终平稳运行的方式,无论发生什么。
准备应对服务提供商停机
即使是最大的云服务提供商,也难免会遇到停机问题,而当这种情况发生时,我们不想被措手不及。准备停机并不是等待问题发生,而是构建一种能够应对故障并持续运行的架构。这就是多云架构、第三方冗余和异地备份发挥作用的地方。这些策略有助于确保,当我们的服务提供商遇到停机时,我们的业务不会受到影响。
多云架构
仅依赖一个云服务提供商虽然方便,但在需要高可用性条件的情况下,有时会被视为风险。采用多云架构时,我们将资源分布在多个云服务提供商之间,比如 AWS、Azure 和 GCP。如果一个供应商出现故障,其他供应商可以接管,保持我们的服务在线。关键在于不仅仅是将一切复制到不同的云中,而是要设计云无关的应用程序,这样它们就可以在任何可用平台上平稳运行。这并不是“一刀切”的方法,但对于关键任务服务来说,这是我们无法忽视的保障。
多云技术
在考虑采用多云架构时,我们需要考虑构建在不会被供应商锁定的框架和技术上,比如:
计算:Terraform/OpenToFu,Docker,Kubernetes
监控:Grafana,Prometheus,ELK Stack
Devops:Github actions,Gitlab,Jenkins
身份认证:Auth0,Okta
大多数数据库技术在云提供商之间是可迁移的,尤其是那些使用更开放标准的数据库,如 MySQL 和 PostgreSQL,这些数据库不受许可证限制。
第三方冗余
保护免受供应商停机的另一种方式是集成第三方冗余。这意味着使用外部服务或供应商来备份关键功能。例如,如果我们的主要云服务提供商管理数据库,可以考虑使用第三方服务来处理备份或关键基础设施部分。这样,即使供应商发生故障,数据仍然可以安全访问。目标是减少对任何单一供应商的依赖,以便从多个角度保障所有关键操作。
异地备份于其他云 / 混合解决方案
为了获得最终的安心,超越仅依赖一个云服务供应商,评估在另一个云或混合解决方案中实施异地备份的可行性。这是最后一道防线,将数据或重要资源存储在完全不同的环境中。通过将备份保存在不同的云提供商或甚至本地设施中,我们确保如果主要供应商发生重大故障或丢失,我们的数据和系统仍然可以从其他位置恢复。混合解决方案也可以在这里发挥作用,提供本地和云资源的混合使用。
关键要点是什么?永远不要依赖一个供应商来维持一切运行。通过实施多云策略,集成第三方冗余,并保持异地备份,我们正在为云可用性中不可避免的波动做准备。这样,当供应商出现停机时,我们的系统就不会受到影响。
权衡取舍
与任何解决方案或策略一样,运行高可用的多云架构也有一些优缺点:
| 优点 | 缺点 |
|---|---|
| 提高弹性和可用性通过利用多个云供应商,我们降低了停机的风险,因为一个供应商的故障可以通过另一个供应商的资源来缓解。 | 增加的复杂性跨多个供应商管理工作负载增加了复杂性,尤其是在架构、监控和安全方面。 |
| 避免供应商锁定使用多个云平台可以防止我们过度依赖单一供应商,从而提供更多灵活性以切换服务或谈判定价。 | 更高的学习曲线团队需要熟练掌握多个云平台,这意味着需要额外的培训和专业知识。 |
| 优化性能我们可以根据每个平台的优势选择最适合特定任务的供应商,优化速度、延迟或其他性能指标。 | 挑战性集成集成不同平台之间的服务并确保无缝通信可能是困难的,尤其是在使用不兼容的云原生工具时。 |
| 成本管理不同的供应商可能会提供针对特定服务的更具竞争力的定价,使我们能够通过根据定价模型分配工作负载来优化成本。 | 更高的运营成本虽然多云可以在某些领域减少成本,但增加的复杂性会提高运营开销,要求更多的工具、人员和管理。 |
| 合规性和地理灵活性多云使我们能够通过在多个地理位置和供应商之间分配数据和服务,满足区域合规要求。 | 延迟和性能波动在多个云中运行应用程序可能会引入延迟或性能问题,尤其是当来自不同供应商的服务需要实时通信时。 |
表 11.1 - 高可用多云架构的优缺点
真实案例
例如,一家受严格监管的澳大利亚金融机构尝试将其架构平衡在两个云供应商之间,结果成本是单一云环境的 10.4 倍,并且还造成了延迟问题,影响了其 RPO 和 RTO。
在这些情况下,评估权衡是非常重要的。
弹性自动化
云中的弹性不仅仅是为最坏的情况做准备,它还包括自动化关键流程,以便我们的系统能够预防潜在问题。通过将故障切换、负载均衡和自动伸缩集成到我们的架构中,我们确保服务在无需人工干预的情况下持续运行。以下是我们如何将自动化与智能架构选择结合起来,以构建一个真正有弹性的云环境。
自动化故障切换
当服务或实例出现故障时,我们最不想做的就是慌乱寻找解决办法。自动化故障切换可以让流量无缝重定向,最小化停机时间并保持系统平稳运行。
-
健康检查用于主动监控:AWS Route 53 健康检查、Azure Traffic Manager 和 Google Cloud Load Balancer 等服务持续监控关键端点的健康状态。
这些工具能检测服务是否宕机,并自动将流量重定向到健康实例。这种即时故障切换意味着服务不会中断,而人工干预是无法保证这一点的。
我们应该为所有关键任务服务设置健康检查。例如,在 AWS 中配置 Route 53,当主实例失败时将流量重定向到备份实例。定期测试这些检查可以确保它们按预期工作。
-
自动化 DNS 故障切换:利用 DNS 故障切换可以确保在出现问题时,流量会自动切换到备份区域或资源。
自动故障切换确保即使整个区域离线,流量仍然能够流动。与其在故障期间手动切换 DNS 记录,自动化可以立即重定向流量。
设置 DNS 故障切换策略,当需要时将流量切换到备份资源。在 AWS 中,我们可以配置 Route 53 中的加权路由策略,将流量均匀分配到主资源和次要资源之间。
负载均衡与自动扩展
自动平衡流量和自动扩展资源对于防止过载并在需求激增时维持性能至关重要。让我们逐一分析每个选项:
-
负载均衡用于无缝流量分配:负载均衡器,如 AWS 中的 Elastic Load Balancing (ELB)、Azure Load Balancer 和 Google Cloud Load Balancer,将流量分配到多个实例,确保没有单个实例被压垮。
通过分配流量,负载均衡器即使在高流量时期也能确保系统平稳运行。它们防止瓶颈,确保通过将请求路由到健康实例来提高可用性。
我们应该在云架构中实现负载均衡器。例如,在 AWS 中配置 ELB 将流量分配到多个可用区。这样,如果某个实例宕机,流量会自动路由到另一个实例。
-
自动扩展用于动态资源管理:自动扩展确保资源根据需求进行调整,在流量高峰时扩展,安静时缩减。
自动扩展优化了性能和成本效益。当需求增加时,它会自动添加资源以处理负载。当需求减少时,它会缩减以避免不必要的成本。
根据流量或资源阈值设置自动扩展规则。在 AWS 中,当 CPU 使用率超过某个百分比时,配置 Auto Scaling Groups 来增加实例。定期审查这些阈值确保它们与我们的实际需求相符。
为什么自动化对弹性至关重要
自动化为我们提供了前瞻性优势。通过提前设置故障切换和自动扩展,我们确保系统能够立即响应问题,最大程度地减少停机时间。
自动化系统能够检测问题并立即重新分配流量或扩展资源。这不仅减少了人为错误的风险,还确保响应时间比任何人工修复都要快。
自动扩展通过只使用所需资源来帮助管理成本,而负载均衡通过均匀分配流量来防止性能问题。
通过自动化故障转移、负载均衡和自动扩展,我们构建了一个具有弹性的云架构,能够实时应对挑战。主动监控、自动流量分配和动态资源管理的结合,确保我们的系统无论发生什么,都能保持响应和高效。
总结
在本章中,我们深入探讨了管理云环境的操作挑战,学习了如何在压力下保持系统平稳运行。我们涵盖了从拆解云服务提供商的服务水平协议(SLA)到通过多区域部署、故障转移设置和自动扩展来构建弹性的一切内容。我们还讨论了主动规划、冗余和自动化在减少停机时间和保持业务运转方面的价值。过程中,我们探索了如何应对服务提供商的故障、保持文档更新以及适应云操作所需的文化变革。现在,我们已经具备了保持云基础设施弹性和可靠性的策略和工具。
在下一章,我们将探讨从本地架构迁移到云端的策略,甚至是从一个云服务提供商迁移到另一个云服务提供商的过程,以及未以云原生方式处理云安全所带来的风险。
第十二章:从传统系统迁移到云原生解决方案
本章将深入探讨云迁移为何可能偏离轨道,更重要的是,如何避免这些陷阱。我们将分析导致云采用失败的最常见错误,比如在没有坚实战略的情况下贸然开始、缺乏关键利益相关者的支持,以及试图将过时的传统安全实践强行套用到云中。
以下是我们将讨论的内容:
-
如何制定清晰的迁移战略,使其与业务目标一致,这样你不仅仅是在迁移工作负载,而是确实在创造价值。
-
在整个云迁移过程中,利益相关者的参与至关重要,确保所有人保持一致,且都致力于迁移的成功。
-
为什么传统的安全实践无法适用于云环境,以及如何转向适应当今动态环境的云原生安全模型。
-
如何识别并弥补技能差距,确保你的团队为顺利高效的迁移做好充分准备。
本章结束时,你将拥有一份避免破坏云迁移的陷阱的路线图,并为顺利迁移到云做好更充分的准备。
规划有效的迁移
云迁移遇到障碍或完全失败的最大原因之一就是缺乏清晰的战略和适当的规划。许多企业未充分考虑全局,贸然开始迁移,导致混乱、意外的费用和低效问题。成功的迁移需要从一开始就进行深思熟虑,并与业务目标保持一致。
在本节中,我们将首先讨论为什么一个完善的迁移计划对于确保进度至关重要。我们将探讨如何通过为应用程序设定明确的优先级、选择合适的云平台以及决定迁移策略——无论是“提升迁移”(lift-and-shift)还是完全重构——来做出关键的决策。通过了解这些基础要素,我们可以以更清晰的思路、更专注的态度来进行迁移,从而提高成功的可能性。
没有计划地跳入:为何规划如此重要
一种反复出现的常见错误是将云迁移视为老旧基础设施的快速修复。团队通常匆忙推进这一过程,认为只需将应用程序或整个服务器迁移到云上,而不加深思。这种缺乏规划的做法会导致:
-
应用程序没有针对云环境进行优化。
-
工作负载与云服务不匹配。
-
由于资源扩展不当,导致的意外成本。
-
因未充分利用云原生服务而导致的投资回报未能实现。
-
早期未能解决合规性和安全要求。
-
这些问题中的每一个都可能是导致运营成本上升、迁移和云采用延误,甚至工作负载性能下降的根本原因。
-
如果没有适当的规划,我们可能会陷入混乱,形成一个效率低下、成本高昂且易于失败的拼凑式云环境。这正是“仓促行事,事后悔 慢慢感受”的经典案例。
制定清晰的迁移策略
成功的云迁移的关键在于一个坚实的策略。迁移到云端不仅仅是移动工作负载;它是一个重大转变,需要精心规划和明确的方向。如果没有强有力的计划,过程可能迅速演变为意外的成本、延误和不必要的复杂性。本节将深入探讨如何制定一个与业务目标对齐并使团队保持专注的迁移策略。从评估当前环境到选择正确的云模型,我们将覆盖一系列基础步骤,帮助您顺利进行未来准备的迁移。
评估当前环境
在开始之前,首先要清楚自己在处理什么。识别关键应用程序、依赖关系和集成。弄清楚哪些可以退休,哪些需要重大重构。别忘了查看网络依赖关系和延迟需求。
为了正确评估我们当前的环境,我们需要利用云服务提供商或第三方的云迁移评估工具。例如:
-
AWS 迁移评估工具可以帮助我们通过映射工作负载、依赖关系和集成来分析本地基础设施。它将提供详细的成本分析,并展示在 AWS 环境中的效果。
-
类似地,Azure Migrate 可以绘制出依赖关系和网络交互,展示哪些内容适合迁移到云端以及可能出现的延迟问题。
-
Google Cloud 的 Migrate for Compute Engine 以类似的方式工作,提供对虚拟机、应用程序和基础设施的洞察,确保我们为每个工作负载有清晰的迁移路径。
使用这些工具之一可以详细列出关键应用程序、它们如何交互,以及任何网络或延迟需求。这种可见性使我们能够做出更明智的决策,了解哪些可以退休、哪些需要重构或保留不变,帮助避免常见的导致迁移失败的陷阱。
在上述每个案例中,输出应该为您提供一个有用的迁移资产清单,以及它们可能需要的资源。以下是此数据的示例,但不局限于此,也不全面:
| 主机名 | CPU 核心数 | 操作系统 | 操作系统版本 | 总内存 |
|---|---|---|---|---|
| app-server01.local | 4 | Windows Server 2019 | 1809 | 8192 |
| linux-db01.local | 4 | Ubuntu 20.04 | Focal Fossa | 16384 |
| mssql-db01.local | 8 | Windows Server 2016 | 1607 | 32768 |
| app-server02.local | 2 | Windows Server 2019 | 1809 | 8192 |
| backup-server.local | 4 | Windows Server 2012 R2 | 9600 | 8192 |
| web-server01.local | 2 | RHEL 8 | Ootpa | 4096 |
| dev-server.local | 4 | Windows 10 Pro | 21H1 | 16384 |
| linux-app01.local | 2 | CentOS 7 | Core | 8192 |
| storage-server.local | 16 | Windows Server 2019 | 1809 | 65536 |
| dns-server.local | 1 | Ubuntu 18.04 | Bionic Beaver | 2048 |
| mail-server.local | 4 | Windows Server 2016 | 1607 | 8192 |
| log-server.local | 8 | Ubuntu 22.04 | Jammy Jellyfish | 16384 |
表 12.1 - 迁移评估数据
优先排序应用:使用灯塔应用
我们不需要一次性迁移所有内容。明智的做法是根据应用的业务影响、迁移的难易程度以及能够从云中获得最大收益的因素来优先处理应用。我们从那些较简单的应用开始,逐步提升,随着我们变得更加熟练,再处理更复杂的应用。我们有时将这一概念称为“灯塔”。
选择一个灯塔应用
灯塔应用是证明云采用价值的第一步。它是一个小型、低风险的应用,设定了其他一切的基调。选择时,要选一个足够重要以展示实际影响,但又不至于复杂到让团队陷入困境的应用。理想的灯塔应用易于迁移,能够明显从云原生功能(如自动扩展或无服务器架构)中受益,并且为您带来一个快速的成功,积累动力。关键是聪明地开始,为后续更大、更复杂的迁移奠定基础。
并非所有工作负载都需要相同的处理方式,按大小将它们分为“小型”、“中型”和“大型”——有助于我们简化规划和资源分配。T 恤尺寸法为我们提供了一种快速、实用的方式,根据复杂性和迁移工作量对工作负载进行分类。
-
小型工作负载
这些是简单、低影响的应用,可以轻松进行迁移,适合早期的迁移,几乎不需要更改,并且能帮助我们迅速积累动力。
-
中等工作负载
这些应用可能需要一些平台迁移或调整,以便在云中获得最佳性能。它们通常有特定的延迟或集成要求,需要更多的规划。
-
大型工作负载
大型、关键任务应用通常需要进行大规模重构,以充分利用云的优势。它们的迁移是分阶段进行的,并涉及详细的规划,以确保与业务需求保持一致。
通过提前为工作负载确定大小,我们可以清楚地了解资源、时间表和依赖关系,从而专注于快速成功,并以可管理的方式为更复杂的迁移做好准备。
通过利用像 AWS 应用发现服务或 Azure Migrate 的评估等工具,我们可以自动化确定哪些工作负载已经准备好迁移到云端,哪些则需要更多工作。这些工具为我们提供了清晰的视图,帮助我们决定从哪里开始以及哪些工作负载可以延后处理。
这种分阶段的方法帮助我们降低风险,避免团队感到不堪重负,并且在过程中保持动力。首先从较简单的迁移开始,可以确保更平稳的过渡,并为处理更关键的应用奠定长期成功的基础。
定义您的云模型
在我们开始迁移之前,最重要的决策之一是选择哪种云模型最适合我们的需求:单云、多云或混合云。每种模式都有其优缺点,因此我们需要根据每个工作负载的目标明智选择。
单云
如果我们坚持使用单一的云服务提供商,无论是 AWS、Azure 还是 GCP,这样可以简化操作。管理一个环境可以让团队更轻松,因为我们只需要专注于一套工具、API 和服务。对于不太复杂或内部应用来说,这种方法通常能提供所需的可靠性和性能。
然而,我们必须考虑供应商锁定的风险以及停机的潜在影响。如果我们的整个操作都依赖于一个供应商,他们任何一次停机都可能对我们造成严重影响。这就是权衡,简单性与灵活性和风险缓解之间的取舍。
云服务提供商的全球基础设施
在决定我们的云模型时,评估我们所考虑的云服务提供商(CSP)的全球基础设施非常重要。这包括了解他们的接入点数量以及他们确保高可用性的能力。
选择单一的云服务提供商并不意味着要牺牲高可用性,因为大多数云服务提供商都提供多个可用区和区域,可以用于冗余和故障转移。
关于如何实现高可用性的更多信息,请参考第十一章,我们将在其中深入探讨这个话题。
多云
对于关键任务应用程序,多云策略为我们提供了额外的韧性。通过将工作负载分布在多个云服务提供商之间,我们减少了受单一故障点影响的风险。
例如,我们可能会将主应用程序部署在 AWS 上,同时在 Azure 上有一个备用副本,随时准备接管以防万一。这样,如果某个服务提供商发生故障,我们的业务不会受到影响。多云策略还可以帮助我们跨不同区域或行业应对合规要求。然而,我们需要为管理多个平台上的不同工具、API 和配置所增加的复杂性做好准备。这要求我们的团队熟练掌握所有使用的平台,并且需要跟上各个平台的更新和变化。
混合云
混合模式让我们能够结合两者的优势,将本地基础设施与云资源相结合,甚至将多个云服务提供商混合使用。如果因为遗留应用、数据驻留法或严格的监管要求,我们无法完全迁移到云端,这种方式尤其有用。
在混合环境中,我们可能将敏感数据保留在本地,而将不太关键的工作负载迁移到云中。像 AWS Outposts、Azure Arc 和 Google Anthos 这样的工具帮助我们缩小本地环境和云环境之间的差距。挑战在于确保两种环境中的一切能够无缝协作,尤其是在网络、安全性和数据一致性方面。
混合云也可以看作是迁移过程中从两个云服务提供商之间或从本地迁移到云的一种过渡阶段。这种迁移通常需要几个月到几年时间,具体取决于规模或复杂性。
总结来说,我们选择的模型需要反映出我们所追求的技术和商业目标。对于关键任务应用,可能需要多云的冗余和可用性,而较简单的应用则可以单云环境中运行。如果我们需要考虑遗留系统或特定的合规要求,混合模型可能是最好的选择。最终,我们做出的选择必须与我们的运营能力和长期目标相一致。
使用迁移处理计划
在这里要问的第一个问题是:“在云原生迁移的背景下,什么是处理计划?”简而言之,处理计划是一个框架或模型,帮助组织做出关于如何迁移每个工作负载的重要决策。它可以被视为一种决策工具,用于对工作负载进行分类和优先级排序,以确定将基础设施、应用程序和数据迁移到云的最佳方法。
当我们做出工作负载决策时,使用正确的框架至关重要,无论是 AWS 的 7 个 R、Azure 的云采用框架,还是 GCP 的 6 个 R。这些框架帮助我们与目标保持一致,并确保我们为每个应用选择最佳的迁移方法。
虽然不同的云服务提供商(CSP)对它们的处理计划有不同的命名,但它们都围绕着相同的基本原则,具体如下:
-
重新托管(提升与迁移):将工作负载迁移到云中,所需的变更最少。这是我们在时间紧迫或需要保持简单时的首选方法,适用于 AWS、Azure 和 GCP。
-
重新平台化:进行小范围的调整以优化云环境,而不是进行全面的改造。我们可能会使用 AWS Elastic Beanstalk、Azure App Services 或 GCP App Engine 为我们的应用提供更好的平台,同时保持熟悉的操作环境。
-
回购(SaaS):在合适的情况下,将本地软件替换为 SaaS 解决方案。比如 Microsoft 365 或 GCP 的 Workspace,管理减少,效率提高,而且由他人处理繁重的工作。
-
重构:当我们需要重新设计一个应用,使其真正云原生时,我们会使用像 AWS Lambda、Azure Functions 或 Google Cloud Functions 这样的工具进行无服务器处理,或者将应用拆分为微服务并使用 Kubernetes。
-
淘汰:这涉及到剔除我们不再需要的应用程序。无论是为了简化复杂性还是节省成本,关闭过时的系统对于保持我们的云环境精简至关重要。
-
保留:有时候,最好将某些应用保留在本地,尤其是它们不适合云环境或合规要求需要这样做。我们可以通过 AWS Outposts、Azure Arc 或 Google Anthos 等混合解决方案来管理这些应用。
-
迁移:根据需要在不同云之间迁移工作负载。灵活性至关重要,云之间的切换使我们能够根据业务发展优化性能、成本或合规性。
注意事项
我们也在第七章第一部分中简要讨论了 7R 理论,特别是提升与迁移。
选择你的云平台
无论我们是在使用 AWS、Azure、GCP,还是它们的混合组合,确保平台符合我们的业务和技术需求是至关重要的。每个云服务提供商都有其优势,因此了解我们真正需要什么是关键,以避免可能限制性能或增加成本的不匹配情况。以下是在选择云平台之前需要考虑的一些因素。
服务和功能评估
我们需要从审视每个提供商提供的核心服务开始,特别是在对我们业务至关重要的领域。例如:
-
AWS 以其广泛而成熟的生态系统而著称,尤其是在计算(EC2)、无服务器计算(Lambda)和数据湖(S3)等领域。
-
另一方面,如果我们已经在 Microsoft 生态系统中,Azure 可能是更好的选择,因为它与 Active Directory、Office 365 和 Windows Server 等工具的无缝集成。
-
GCP 在其 AI/ML 能力、Kubernetes(GKE)和大数据解决方案(如 BigQuery)方面通常表现出色。
决定选择哪个提供商适合我们的需求,需要评估这些核心服务如何与我们当前和未来的工作负载相匹配。
成本考虑
虽然云服务提供商通常采用按需付费模式,但各个平台的定价模型差异巨大。我们不仅需要评估服务的前期成本,还需要根据可扩展性、存储和数据传输费用来评估长期的财务影响。AWS、Azure 和 GCP 在计算、网络和存储层级等方面有独特的定价结构。
在多云环境中,定价变得更加复杂。我们需要考虑不同提供商之间的数据外流成本,确保平台间的数据传输不会导致意外的费用。
另外需要注意的是,混合云策略可能会带来不同的费用,例如从私有数据中心到云服务提供商的直接连接费用、VPN 成本和额外的数据传输费用。
定价工具
工具如 AWS 价格计算器、Azure 价格计算器或 Google Cloud 价格计算器可以帮助我们根据使用模式估算这些费用。
合规性与安全
如果合规性是一个主要因素(例如 GDPR、HIPAA、PCI-DSS 等),我们需要确保所选平台具备必要的认证和数据驻留选项。AWS、Azure 和 GCP 都提供强大的安全性和合规性服务,但这些服务的深度和地区可用性可能有所不同。
例如,如果我们在欧洲处理敏感数据,AWS 和 Azure 提供了与 GDPR 更加符合的特定区域。如果我们专注于具备隐私要求的 AI/ML 工作负载,Google Cloud 可能会更具吸引力。
注意事项
正如在 第六章 中讨论的,合规性和认证是云服务提供商与客户之间的共享责任。
多云与混合云策略
如果我们计划采用多云战略,我们需要仔细评估互操作性。AWS、Azure 和 GCP 之间的服务能否轻松协同工作?我们需要决定是否使用像 Terraform 这样的云中立工具进行基础设施即代码管理,或使用 Kubernetes 进行容器编排来标准化。这可以确保我们不会被锁定在某一平台上,从而在云之间迁移工作负载或扩展操作时具有更大的灵活性。
对于混合云设置,AWS Outposts、Azure Stack 和 Google Anthos 等解决方案使我们能够将云延伸到本地数据中心,从而无缝管理跨环境的工作负载。选择哪种解决方案取决于我们如何管理本地与云之间的连接,以及我们所运行的特定工作负载。
延迟和区域布局
我们决策过程中的另一个关键因素是云服务提供商的地理覆盖范围。如果低延迟对用户体验至关重要,我们需要选择一个在客户群附近有强大区域布局的平台。AWS 拥有最广泛的全球基础设施,但 Azure 和 GCP 也提供了强大的覆盖范围。我们需要分析每个提供商的可用区域和可用性区域,并确定它们与我们地理需求的契合度。
最终,选择合适的云平台归根结底在于理解技术需求和更广泛的商业目标。无论我们是全力投入单一云服务提供商,还是将工作负载分散到多个云服务提供商之间,每个决策都应通过对服务、成本、合规性和可扩展性选项的深入评估来支持。
确定明确的时间表和里程碑
在规划云迁移时,设定现实的时间表和明确的里程碑是确保项目按计划推进、避免遗漏任何步骤的关键。我们可以这样分解任务,添加必要的技术深度,以保持流程紧凑且可预测。
评估阶段(发现与规划)
在我们迁移任何工作负载之前,我们需要为当前环境的深入评估分配足够的时间。这意味着需要使用像 AWS 迁移评估工具、Azure Migrate 或 Google Cloud Migrate 这样的发现工具,来绘制出我们所有的依赖关系、应用连接性和性能指标。这些工具为我们提供了一个完整的视图,避免后续出现意外情况。
如果我们回顾一下“评估当前环境”章节中的表格,我们可以看到这为我们设定了明确的要求,以确保我们可以开始规划我们的实例类型或需求。
| 主机名 | CPU 核心数 | 操作系统 | 操作系统版本 | 总内存 |
|---|---|---|---|---|
| app-server01.local | 4 | Windows Server 2019 | 1809 | 8192 |
| linux-db01.local | 4 | Ubuntu 20.04 | Focal Fossa | 16384 |
| mssql-db01.local | 8 | Windows Server 2016 | 1607 | 32768 |
| app-server02.local | 2 | Windows Server 2019 | 1809 | 8192 |
| backup-server.local | 4 | Windows Server 2012 R2 | 9600 | 8192 |
| web-server01.local | 2 | RHEL 8 | Ootpa | 4096 |
| dev-server.local | 4 | Windows 10 Pro | 21H1 | 16384 |
| linux-app01.local | 2 | CentOS 7 | Core | 8192 |
| storage-server.local | 16 | Windows Server 2019 | 1809 | 65536 |
| dns-server.local | 1 | Ubuntu 18.04 | Bionic Beaver | 2048 |
| mail-server.local | 4 | Windows Server 2016 | 1607 | 8192 |
| log-server.local | 8 | Ubuntu 22.04 | Jammy Jellyfish | 16384 |
表格 12.2 - 迁移评估数据
在这一阶段,技术审计至关重要。我们需要识别可能会受到迁移影响的网络配置、数据库、安全策略和存储设置。设定一个里程碑来完成这一发现阶段,确保我们在做出任何决策之前,手中有所有关键数据。可以把它当作为设定一个两周的窗口期,用来运行迁移评估,并在数据收集完毕后与关键利益相关者进行审查。
概念验证(PoC)/ 试点测试
在我们完成评估后,不能直接跳入全面迁移。我们需要一个概念验证(PoC)或试点测试。在这里,我们将选择一个或两个非关键应用,并将其作为试验进行迁移过程。例如,我们可能会使用 AWS 应用迁移服务将一个小型应用提升并迁移,或者尝试在 Azure 或 GCP 上使用 Kubernetes 重构某个组件。
这里的关键里程碑是成功完成 PoC。这可以帮助我们验证所选择的工具和流程是否能够在大规模环境下工作。根据我们测试应用的复杂性,迁移测试大概需要 2 到 4 周的时间。在这个过程中,定期检查非常重要,以跟踪迁移的效果,并在规模扩展之前解决任何问题。
全面迁移
一旦 PoC 得到批准并运行顺利,我们就进入全面迁移阶段。这是技术性迅速发展的时候。我们会设立检查点,例如确保我们的 IAM 角色、网络设置和安全组在我们开始迁移任何内容之前得到正确配置。像 AWS 数据库迁移服务、Azure 数据库迁移或 GCP 的数据传输这样的工具在处理数据库迁移时起到关键作用。
在这个阶段,我们的里程碑应涉及分批迁移。我们不会一次性将所有内容都转移到云端。相反,我们会设定目标,比如在 4-6 周内迁移我们应用的 20%,然后重新评估、回顾性能,并在推进之前进行微调。
优化和微调
当应用程序在云端时,工作并没有结束。这个阶段涉及回顾性能,合理调整资源大小,并实施自动缩放以有效满足需求。像 CloudWatch(AWS)、Azure Monitor 或 GCP Operations Suite 这样的监控工具在这里至关重要,用于跟踪性能并识别我们设置中的任何低效性。
我们将为这个阶段设定里程碑,以确保我们的云架构在性能和成本上都得到了优化。这意味着定期性能审查和关注资源利用率,以便我们可以根据需要进行调整。与所有利益相关者进行的迁移后审查让我们评估什么有效、什么不行,以及我们如何优化未来的迁移。
定期的利益相关者检查
在整个过程中,与利益相关者(无论技术性或非技术性)的定期沟通至关重要。我们将安排每周或每两周更新,以确保一切与更广泛的业务目标保持一致,并确保技术团队达到其关键的里程碑。详细的迁移运行手册、架构图表和定期的进展更新让所有人都保持在同一页面上,并且允许我们在需要时进行调整。
通过为每个阶段设定清晰的里程碑,评估、PoC、迁移和优化,我们保持组织性,避免问题变成更大的问题,并确保整个过程按计划进行。定期与利益相关者的沟通意味着没有人被置于黑暗中,我们可以调整时间表或流程,以确保从头到尾的平稳迁移。
没有战略的云迁移是在找麻烦。一个扎实、深思熟虑的计划确保你不只是把一切都扔到云端然后指望一切都顺利。优先考虑你的应用程序,使用像 AWS 的 7 个 R 框架,并选择正确的云模型,为成功奠定基础。有了清晰的计划,你将避免不必要的延迟、低效以及因为毫无准备就潜水而来的昂贵错误。
策略的另一部分是确保业务各个方面的利益相关者都对迁移活动有所了解。我们将在下一节更详细地介绍这一点。
最低利益相关者承诺
在云采纳方面,普遍存在一种误解,认为这仅仅是一个技术性的工作,IT 团队可以独立完成。然而,现实情况远非如此。云迁移不仅仅是另一个技术项目,它是业务运作方式的根本转变。为了成功,它需要各级利益相关者的全程参与,从 C-suite 高层到部门负责人,再到技术负责人。
注意事项
第五章更详细地介绍了文化转变。
但我们常常看到的是最小利益相关者承诺,这是一种不干预的方法,决策者只有在问题出现时才会参与。他们可能在开始时提供高层次的支持,但随后逐渐淡出背景,假设技术团队能处理一切。这种脱节导致了延迟、目标不一致、预算超支,最坏的情况是迁移失败。如果利益相关者从一开始就没有积极参与,整个项目就可能失去方向,直到你意识到,迁移已经偏离了原定轨道。
让我们来分析一下为什么这是一种反模式,以及利益相关者应如何承担云采纳的责任。
了解反模式:最小利益相关者承诺
了解在这些情况中,什么可能出错与什么可能正确一样重要。下面我们回顾一些关于最小利益相关者承诺的关键要点。
被动利益相关者参与的问题
问题在于,如果利益相关者没有充分参与,就会带来各种麻烦。IT 团队可能专注于运营效率或成本节约,而业务方可能更关注可扩展性或客户体验。如果没有利益相关者的定期参与,这些目标最终可能会发生冲突。
当关键决策者未参与时,延迟开始悄然出现。关于工作负载优先级、资源分配或迁移范围变更的决策往往会被拖延。这是因为没有人积极地掌舵。
那么会发生什么呢?项目拖延,挑战出现时,没人感到有责任去解决。这种缺乏责任感导致了缓慢的反应和糟糕的问责制。
被动而非主动的方法
利益相关者的最低参与度导致了一种被动的做法,只有当某些问题出现时才做决策。
结果如何?你最终会得到匆忙的“搬迁与转换”迁移,即将工作负载迁移到云端,而没有进行优化。这是一次错失的机会,最终你会为一个比原来环境差不多的云环境支付更多费用。
如果没有主动规划,迁移工作往往集中在短期收益上,比如迁移工作负载以避免硬件更新费用,或者为了满足监管截止日期。但这种做法忽略了更大的图景,忽视了优化、可扩展性和长期的云效益。这样我们就错失了云原生功能的全部潜力,最终云架构可能和我们遗弃的旧架构一样低效和昂贵。
这两种做法在许多失败的迁移中已经是常见做法,导致了成本增加、延误,以及企业因缺乏方向而重新回到传统技术。
利益相关者应如何参与云采用
为了让云迁移真正成功,光是让利益相关者站在旁边是不够的。积极、持续的参与才是关键。以下是利益相关者从一开始就能在推动云采用成功中发挥关键作用的方式。
谁是“利益相关者”
在云迁移中,利益相关者是对迁移成功具有切身利益的个人或团体。这些可以是高层领导团队、IT 管理层和架构师、应用程序所有者或开发人员、运营团队、财务团队或最终用户。这份名单既不详尽也不最终,任何与应用、数据或基础设施有接触的人都可以是利益相关者。
清晰和定期的沟通渠道
从一开始,利益相关者就需要参与其中。我们说的是建立定期会议,让技术和业务团队共同讨论进展、挑战和即将做出的决策。通过这种方式,大家保持一致,避免了阻碍项目进展的隔离式沟通。
尝试以下做法:
-
指导委员会:成立一个由技术和业务团队成员组成的指导委员会。这样,决策可以通过合作方式做出,确保迁移既符合运营目标,又符合业务目标。
-
检查会议:每周或每两周的检查会议有助于推动迁移进程。这些会议不仅仅是进度更新,更是调整战略的机会,帮助在问题变得更严重之前解决潜在的障碍。
定义业务目标
云采用需要被视为一种业务转型,而不仅仅是技术迁移。利益相关者应定义与迁移相关的明确、可衡量的业务目标,无论是提高敏捷性、降低成本,还是实现更快速的产品发布。
利益相关者需要负责这些业务目标,确保在整个迁移过程中定期回顾这些目标,以确认项目仍然在正确的轨道上。一些实用的步骤可能包括:
-
目标对齐:确保云迁移与更广泛的业务目标紧密相连,比如改善客户体验或简化运营。
-
关键绩效指标(KPIs):设立可衡量的成功指标,无论是减少停机时间、更快速的部署,还是成本节省。这些指标应在整个迁移过程中指导决策。
资源分配与优先排序
资源分配是利益相关者真正需要亲自参与的地方。延误和预算问题通常是因为对资源流向缺乏足够的监督。利益相关者需要参与工作负载的优先排序,确保关键应用程序获得所需的关注。这里的关键步骤可能包括:
-
预算监督:利益相关者应积极管理迁移预算,确保财务资源得到恰当分配,特别是对于关键工作负载和迁移后的云优化。
-
工作负载优先排序:让利益相关者参与决定优先迁移哪些工作负载。这有助于技术团队集中精力处理对业务带来即时价值的高影响应用程序。
定期审查与灵活性
云迁移不是一条直线,而是一个迭代过程。利益相关者需要定期审查进展,并准备根据需要做出调整。这不是一个“设定然后忘记”的情况。会有挑战,利益相关者需要保持参与,迅速做出调整。可以帮助的实际步骤有:
-
季度战略审查:除了定期的检查,利益相关者应举行季度审查,以评估迁移是否达到了预期的业务成果。
-
迁移后优化:迁移完成后,工作并未结束。利益相关者应该继续参与迁移后的优化,确保云设置在性能和成本效率上得到微调。
通过这种方式的参与,我们终于能够将云项目与真正的商业目标对齐,带来我们在传统、不干预方式中失去的灵活性和创新。
利益相关者的技术考虑因素
当涉及到利益相关者的参与时,需要在利益相关者层面考虑一些问题。
使用云原生治理工具
治理在云环境中至关重要。利益相关者应推动使用云原生工具来执行政策、管理多个账户,并确保安全性和合规性始终得到保障。例如:
-
AWS 控制塔或 Azure 蓝图:这些工具帮助在不同环境中管理账户并应用治理政策,确保我们始终保持合规和安全。
-
GCP 组织策略:这确保了对资源的集中控制,使得在多云环境中治理变得更加容易。
设定安全与合规基准
云迁移带来了新的安全挑战,利益相关者需要关注这一点。从第一天起,像 IAM、加密和日志记录等安全功能应该就开始实施,合规基准也需要作为迁移计划的一部分。可以考虑应用:
-
定期合规审计:通过定期审计,确保云环境符合行业标准。
-
安全评审:安全应该融入到迁移过程中,而不是事后的考虑。利益相关者应该确保在迁移的每个阶段都进行安全评审。
无论你采取什么方法,积极的利益相关者承诺对成功至关重要。
最小化利益相关者的参与是导致延误、预算超支和错失机会的根源。为了确保云迁移成功,必须从头到尾让利益相关者参与其中,确保决策与业务目标一致,资源分配有效,并根据需要进行调整。通过保持参与和积极主动,利益相关者能够确保云采用发挥其全部价值,并为企业的长期成功奠定基础。
如果利益相关者没有参与并保持信息通畅,由于缺乏明确的方向或仓促的决策,很容易在云中复制本地的概念。
复制本地安全控制
组织在云迁移过程中犯的最大错误之一就是试图将旧的本地安全控制移植到云中。这看起来可能是一个安全的选择,毕竟这些控制措施在旧环境中运作良好,那为什么还要重新发明轮子呢?
但现实是,云的运作方式完全不同,拖着那些传统的控制措施走上云端,可能弊大于利。这不仅会造成安全漏洞,还会增加运营负担,拖慢团队的效率并消耗资源。
本地安全模型基于静态环境、固定的网络边界以及需要手动配置的工具。但云环境是动态的,随着资源的增加和减少而不断变化,以满足需求。安全必须像云本身一样灵活和可扩展,这就是云原生工具的作用所在。坚持使用熟悉的做法可能看起来像是安全的选择,但它是一种反模式,可能在安全性、效率和运营复杂性上带来代价。
让我们深入探讨为什么复制本地安全控制是一个糟糕的主意,并探讨如何调整你的安全策略,以充分利用云原生解决方案的强大功能。
了解反模式:复制本地安全控制
在迁移到云时,容易回归我们熟悉的做法,使用多年在本地环境中依赖的相同安全控制。但现实是,在传统环境中有效的做法并不适用于以云为优先的世界。试图在云中复制这些旧的控制措施通常会导致低效、漏洞和运营上的头痛问题。我们不仅没有增强安全性,反而最终得到了一堆过时的控制措施,未能充分发挥云的优势。
在这一部分,我们将分析这种方法为何不足,并探讨转向云原生安全实践的真正价值。
本地安全在云中的问题
在传统的本地安全中,假设很简单,一旦进入网络,便被信任。网络边界内的所有内容都被认为是安全的。但在云中,这种模式不再适用。随着工作负载分布在各个地区,资源按需扩展和收缩,旧的思维方式很快就崩溃了。这时,零信任理念应运而生。
在云环境中,我们不能仅仅因为用户、设备或应用程序的网络位置就信任它们。零信任颠覆了这种假设,要求每次都进行验证,无论是用户、设备还是工作负载。所有事物都必须证明自己是安全的,才能获得访问权限。转向零信任模型对于拥抱真正的云原生安全至关重要。
零信任的关键支柱包括:
-
身份验证:始终确认请求访问的是谁或什么。
-
最小权限访问:仅限每个用户或服务所必需的访问权限。
-
持续监控:实时跟踪活动,检测威胁并在风险出现时加以缓解。
-
微分段:将网络划分为更小的部分,以隔离资源并限制攻击面。
-
设备安全:确保所有设备在授权访问之前符合严格的安全标准。
通过采用这些核心原则,我们摒弃了“网络边界内的任何东西都是安全的”这一过时的观念。零信任确保云环境中的每个组件都被持续验证,从而提供对内部威胁、配置错误和可能在传统本地部署中遗漏的安全漏洞的更强保护。这是我们在日益复杂的云环境中保持安全所需的思维方式转变。
尝试在云中应用传统的安全控制往往意味着错失云所提供的灵活性和可扩展性。传统工具无法跟上云环境变化的步伐,通常需要手动调整,导致操作变慢。更糟糕的是,如果这些工具与云原生服务集成不良,可能会使你的云基础设施暴露于风险之中。
例如,虽然本地环境高度依赖防火墙来阻止未经授权的流量,但云环境要求更加细粒度的安全控制。这时,身份和访问管理(IAM)发挥作用。在云中,不仅仅是阻止不良流量;而是确保只有正确的用户、服务和应用程序才能访问它们所需的资源——没有多余,也没有不足。仅依赖传统的基于网络的安全工具可能会在访问管理上留下危险的漏洞。
常被忽视和误解的共享责任模型。
迁移到云时,最重要的概念之一是共享责任模型。在传统的本地环境中,你控制一切,从物理硬件到其上运行的应用程序。但在云中,安全责任由你和云服务提供商共同承担。提供商负责基础设施,如数据中心的物理安全和它们之间的网络,而你则负责保护构建在其上的应用程序、数据和身份管理。
未能理解这一区别通常会导致安全配置薄弱。例如,认为云服务提供商会为你处理加密或访问控制,可能会导致数据泄露或未经授权的访问。传统的本地安全模型没有考虑到这种共享责任,试图将其直接复制到云中,往往会导致安全防护存在严重漏洞。
如何从本地安全转向云原生安全
在云中复制传统的本地安全方法是行不通的。为了充分利用云基础设施,我们需要调整思路,采用云原生的方法。在本节中,我们将详细阐述如何摆脱这些过时的安全模型,并开始全面利用云原生工具和实践。
在审查你的云原生安全实施时,请考虑以下提示
-
拥抱基于身份的安全模型:在云中,安全围绕身份展开,无论是用户、应用程序还是服务。IAM(身份和访问管理)是你的第一道防线。通过为每个用户和资源分配特定的角色和权限,你可以控制谁可以访问什么资源,以及在什么条件下访问。你可以考虑的实际步骤包括:
-
采纳最小权限原则:确保用户和服务仅拥有其绝对需要的权限。在 AWS 中,这意味着定义细粒度的 IAM 策略。在 Azure 和 GCP 中,类似的基于身份的控制允许你在粒度级别上管理访问权限。
-
实施多因素认证(MFA):MFA 应当对所有访问敏感资源的行为强制执行。这一额外的安全层确保即使凭据被泄露,攻击者也无法在没有第二因素的情况下获得访问权限。
-
定期审计:定期检查权限。云环境变化迅速,上个月合理的角色今天可能已经过于宽松。定期审计帮助你保持对访问权限的掌控。
-
注意
有关更多信息,请查看第六章以及临时凭证的使用
-
使用云原生安全工具:与其强行让本地安全工具在云中工作,不如利用专为云环境构建的云原生工具。每个主要的云提供商都提供了一整套安全服务,旨在监控、保护和扩展你的基础设施。
以下工具可以帮助你实施良好的云原生安全基础。
-
AWS Shield 和 AWS WAF:使用 AWS Shield 和 AWS Web Application Firewall (WAF) 保护你的应用免受 DDoS 攻击和其他恶意流量的影响。Azure 和 GCP 提供类似的服务,如 Azure DDoS Protection 和 GCP Cloud Armor。
-
集中式安全仪表板:使用像 Azure Security Center 或 Google Cloud Security Command Center 这样的集中平台来全面了解你的安全态势,并迅速识别任何漏洞或配置错误。
-
自动化威胁检测:像 AWS GuardDuty、Azure Advanced Threat Protection 和 Google Cloud Security Scanner 这样的工具持续监控可疑活动,并可以在威胁升级前提醒你。
-
-
自动化安全管理与监控:云环境不断发展变化,这使得手动的安全管理变得不切实际。幸运的是,云为我们提供了以下工具,自动化了许多安全监控和事件响应的方面,从而减少了运营负担,并确保对潜在威胁能够更快响应。
-
CloudTrail/CloudWatch:在 AWS 中,使用 CloudTrail 和 CloudWatch 来记录和监控云环境中的所有活动。类似地,Azure Monitor 和 GCP 的 Operations Suite 提供实时的云原生洞察和警报。
-
自动化响应威胁:为威胁响应配置自动化工作流。例如,如果 AWS GuardDuty 标记出可疑活动,你可以自动撤销凭证或触发安全组更改以阻止未授权访问。
-
安全审计与合规性:使用像 AWS Config、Azure Policy 和 GCP Policy Intelligence 这样的工具安排定期的自动化安全审计。这可以确保你的环境始终符合安全政策和行业法规。
-
-
通过云原生解决方案减少运营负担:坚持使用本地安全工具不仅限制了你的安全能力,还增加了大量的运营负担。在云环境中手动配置防火墙、管理静态 IP 地址或不断调整 VPN 设置既费时又容易出错。云原生解决方案减少了对手动干预的需求,自动化了许多安全管理过程。在规划迁移时,请牢记以下几点:
-
减少手动配置:用动态的基于身份的访问控制替换手动的防火墙和 VPN 设置。这减少了不断更新和监控的需求。
-
集中式治理:使用云原生治理工具,如 AWS Control Tower、Azure Blueprints 或 Google Cloud 组织策略,来管理多个账户中的策略,执行最佳实践,并自动化合规性管理。
-
自动化事件响应:通过云原生自动化工具,您可以消除应对安全事件中大部分的人工工作。自动撤销被盗的凭证、调整防火墙规则,或者根据需要启动备份实例——这一切无需人工干预。
-
总结来说,您需要拥抱云原生安全以消除传统的负担。在云中复制本地的安全控制不仅效率低下,而且充满风险。传统工具和手动流程无法跟上云环境快速变化的节奏,导致安全漏洞和操作效率低下。
通过采用云原生安全模型、自动化关键流程,并利用 AWS、Azure 或 GCP 提供的完整工具套件,您可以建立一个比以往更强大、更具可扩展性和更高效的安全态势。
关键点是:云安全不仅仅是一个复制粘贴的工作。它需要思维方式的根本转变。通过正确的方法,相关方和技术团队可以顺利地从过时、劳动密集型的安全模型过渡到一个云原生环境,从而最大化安全性和操作效率。
在本章的最后部分,我们将回顾教育和知识传递对成功迁移的重要性。
低估技能差距
在向云端迁移时,最关键且常被忽视的因素之一是团队内部的技能差距。许多组织在采用云技术时,认为现有的技术团队能够顺利适应新的环境。然而,云基础设施的运作原理与传统 IT 不同,假设原有技能能够直接迁移,往往会导致延误、效率低下,甚至失败。低估技能差距可能会导致诸如配置错误、错失优化机会,或最严重的安全漏洞等问题,直到为时已晚才被发现。
云迁移不仅仅是技术上的转变,更是思维方式的转变。如果没有适当的培训、支持和对所需技能的现实理解,组织往往会发现自己难以充分利用云的能力。让我们更深入地探讨这一反模式,并探索有效弥补技能差距的实际策略。
理解反模式:低估技能差距
在云技术采用方面,许多企业认为,如果某人在传统 IT 或数据中心管理中非常熟练,那么他们自然能够处理云操作。然而,不同的云服务提供商(CSP)有着完全不同的运作范式。
基础设施即代码、无服务器和容器编排等术语不仅仅是流行词;它们需要对新工具和方法有深入理解。没有正确的技能,云迁移很容易偏离轨道。让我们更详细地分析一下传统技能与云技能,以及它们对云采用的影响。
传统技能集与云技能集
在传统的本地环境中,管理基础设施意味着物理部署硬件、安装软件并手动管理一切。另一方面,云环境需要精通自动化、动态扩展和对云原生服务的深入理解。弹性、自动扩展和安全模型等概念对许多技术团队来说通常是新的,没有专注的培训,技能缺口很快就会显现。
对云采用的影响
未能解决技能差距不仅会导致迁移时间线延长;它还会直接影响云采用的成功。缺乏必要技能的团队可能复制旧的本地流程,这些流程并未针对云进行优化,导致工作流程低效和配置错误。更糟糕的是,糟糕的安全实践可能会开放漏洞,从而危及整个云环境的完整性。
如何弥补技能差距
承认存在技能差距是第一步,但这还不够。你需要一个坚实的计划来弥补它。以下是我们的做法。
投资于云培训和认证
最快弥补技能差距的方式是通过结构化培训和认证。每个主要云服务提供商都提供一系列认证,旨在为团队提供处理云架构、运营和安全所需的知识。AWS、Azure 和 GCP 都有针对不同角色(从架构师到开发人员再到 DevOps 工程师)的学习路径。
-
确定关键培训领域:不要仅仅送团队参加通用的云培训。确定团队需要提升的具体领域。是自动化?安全?容器管理?专注于能为组织带来最大价值的领域。
-
鼓励认证:推动进行正式的云认证。AWS 认证解决方案架构师、Azure 管理员和 Google Cloud 工程师认证为团队提供基础和高级知识。这些认证不仅验证技能,还能使你的团队始终掌握云最佳实践。
-
持续学习:云平台发展迅速。使学习成为持续过程,鼓励团队定期参与网络研讨会、动手实验室和新的认证考试。
培养跨职能协作的文化
低估技能差距通常源于将技术团队孤立在各自的领域中。当开发人员、运营和安全团队朝着共同目标合作时,云操作能够蓬勃发展。创建跨职能协作的文化不仅能弥补技能差距,还能确保整体云操作的顺利进行。请考虑以下几点。
-
跨培训:鼓励跨职能培训,让开发人员了解基础设施,运营人员了解更多关于代码和自动化的内容。这有助于在团队内创建 DevOps 甚至 DevSecOps 的思维方式。
-
协作项目:开展跨职能团队共同合作解决现实问题的项目。例如,从零开始构建一个基于云的应用程序可能需要开发、安全和运营团队齐心协力。这种方式促进了团队合作,同时也能实时提升技能。
-
导师制度:将熟悉云环境的资深工程师与那些仍在适应的工程师配对。导师制度加速学习,同时促进跨部门的协作。
平衡技术技能与软技能
这不仅仅是技术知识的问题。团队还需要具备在云环境中进行沟通、协作和解决问题的能力。云采用是一个全公司范围的举措,而不仅仅是一个技术项目,它要求业务和技术团队密切合作。弥合技能差距往往需要在这些团队之间促进更好的沟通。以下的指导对于确保平衡技术与软技能至关重要:
在整个组织中培养云流畅度
云采用影响着整个组织,而不仅仅是 IT 部门。为了最大化云迁移的效益,整个业务的利益相关者需要对云原则有基本了解。无论是财务跟踪云成本,安全管理合规性,还是法律处理云合同,确保各部门具备云流畅度是关键。请记住以下几点:
-
利益相关者工作坊:为非技术团队设立云基础知识工作坊,帮助他们理解云如何影响他们的角色,以及为什么云对业务至关重要。
-
云特定 KPI:为不同部门定义云特定的关键绩效指标(KPI)。这有助于确保所有业务单位理解云采用的影响和好处,并保持所有人对迁移目标的统一认识。
确立明确的责任归属
技能差距的最大来源之一是云项目中缺乏明确的责任归属。当角色和责任不明确时,人们往往会依赖他们熟悉的方式,这可能导致技术债务和运营低效。为确保责任和专业技能在需要的地方得以发展,必须明确云项目的责任归属。为了实现明确的责任归属:
-
定义角色:在云迁移过程中,明确谁负责什么。无论是基础设施、安全性,还是部署,都要明确责任,以确保没有遗漏。
-
创建云技术冠军:在组织内指定云技术冠军——那些负责特定云技术领域并推动跨团队最佳实践的人。
弥合知识差距是云成功的关键
低估云采纳中的技能差距是常见的反模式,但它也是最容易解决的。通过投资于针对性的云培训,培养协作文化,并在整个组织内建立云技能流利度,你可以弥补这些差距,确保顺利的迁移。云采纳不仅仅是技术问题,它关乎建立一支具备技能和心态的团队,以便在快速发展的环境中取得成功。
总结
云迁移远不止是迁移工作负载,它是一次完整的转型,需要精心规划、强有力的利益相关者参与,以及向现代化、云原生实践的转变。在这一章中,我们探讨了阻碍进展的一些常见反模式,从规划不足、利益相关者参与不力到从本地环境延续下来的过时安全实践。
使用像 AWS 的 7Rs 框架或 Azure 和 GCP 的等效选项,我们可以就每个工作负载做出更聪明的决策,确保每一步都符合技术和业务目标。通过战略性地优先考虑应用程序,并选择合适的云模型——无论是单一云、多云还是混合云——我们可以减少风险并制定出能够创造实际价值的迁移路线图。解决技能差距同样至关重要,因为它使团队能够接受成功在云端所需的工具和方法。
这不仅仅是迁移系统;它是为灵活性、可扩展性和创新奠定基础。有了清晰的战略、协作的团队精神和现代化的方法,我们不仅可以顺利迁移到云端,还能在那里茁壮成长。
第十三章:你怎么知道一切都能正常工作?
测试我们的代码是确保我们的更改既符合预期功能,又不会回归已有功能的方式。在云原生环境中,我们的复杂性越来越多地存在于超出我们代码范围的区域,因此以有意义的方式测试我们的应用程序变得复杂。让我们探讨如何以既高效又有意义的方式测试云原生代码,同时避免一些常见的反模式。
在本章中,我们将讨论以下主要内容:
-
常见的测试反模式
-
缺乏契约测试
-
手动测试
-
试图重现云环境
-
结构不良的代码
常见的测试反模式
在我们探讨云原生应用程序中常用的测试类型之前,我们首先需要了解一些我们必须避免的常见测试反模式。这些反模式通常是由于应用程序的测试策略在迁移到云端时演变而来。虽然大多数这些反模式适用于单元测试,但在测试其他模式时,也需要注意它们。
首先,我们将看看一些测试反模式,以及它们如何在云原生环境中显现。我们将探讨的具体反模式如下:
-
从未失败的测试
-
覆盖率徽章测试
-
测试实现细节
-
间歇性失败的测试
-
具有副作用的测试或耦合测试
-
多阶段测试
从未失败的测试
当我们考虑测试时,可能会认为从未失败的测试是好的。这意味着我们的代码和更改一直符合我们的预期行为,对吧?如果没有失败的测试,我们怎么能确保当合同被违反时,测试会失败呢?
为了说明这种情况,我将用我在之前角色中与一些团队的经验。那些团队刚刚完成了功能的编写,并且正在编写测试。他们在一个基于 Node.js 的异步代码库中工作,而 Node.js 中异步编程的一个特点是,当调用一个异步函数并且其中包含异步代码时,如果在测试中的函数调用上没有顶层的 await,测试将在异步代码执行之前退出。这意味着异步代码中的任何断言都只会在测试后抛出错误,因为在测试执行过程中没有抛出断言,所以测试通过。从一个未经训练的角度看,测试似乎验证了预期的功能。然而,实际上,测试是无效的。毫不奇怪,当我们加入了一些 async 和 await 的语法糖后,许多测试开始失败。
在这个例子中,缺乏对异步编程原则的理解导致了功能上无用的测试,这些测试给人一种一切正常的假象。
这种反模式在云计算中很容易陷入。随着系统变得异步、解耦并最终一致,我们的测试策略必须与系统的复杂性相匹配。你会注意到,如果团队遵循了测试驱动开发(TDD),整个情况是可以避免的。我喜欢使用的常见 TDD 方法是红色、绿色和重构:
-
红色:首先,创建支持你测试所需的最小结构。这可能是一个空的函数块、方法或对象。其次,编写你认为能够测试期望行为的测试(或多个测试)。当你运行测试时,它们应该失败,显示为红色。
-
绿色:用逻辑填充你的空占位符,使你的测试通过,显示为绿色。
-
重构:创建新的测试和功能来处理边缘情况。在这些情况下,最好创建正面和负面测试用例,并故意打破测试几次,以确保它按预期行为。
在云原生世界中,这些测试通常是我们自动化集成管道的一部分,例如 AWS CodePipeline、GCP Cloud Build 或 Azure DevOps Pipelines。
覆盖率徽章测试
另一个常见的反模式是,200 状态码可能给你带来很好的测试覆盖率,但这算是一个好的测试吗?数据的语义结构呢?输出是否与预期输入匹配?在这种情况下,端点的行为完全没有经过测试。我们没有确保任何未来的更改不会导致意外的行为,只保证它们会返回 200 状态码。
激励孤立的代码覆盖率并不会增加你对应用程序突现行为的确定性。相反,你必须激励编写经过同行评审的适当测试,以描述系统的预期行为。一个简单的测试标准是,测试是否确保系统的突现行为与我们对系统的心理模型更为一致。
测试实现细节
要求开发人员达到过高的代码覆盖率阈值,也可能导致另一个反模式:测试实现细节。在云原生领域,这种反模式尤其隐蔽,因为我们更关注结果和系统的突现行为,而不是实现这些行为的方法。随着我们利用新的架构和技术模式,实施细节可能非常流动。例如,如果我们需要对一个数组进行排序,我们可能首先检查输入是否为数字数组,如果是,则调用冒泡排序函数。假设我们在这里编写了两个测试:
-
检查当数组不是数字数组时,冒泡排序函数不会被调用,并且结果是一个错误
-
检查当数组是数字数组时,冒泡排序函数会被调用,并且结果是一个排序后的数组
后来,有人移除了最初的检查,来判断数组是否为数字数组,并将冒泡排序替换为已经内建类型检查的归并排序函数。我们的测试发生了如下变化:
-
我们的第一个测试通过了,尽管我们现在在每次执行时都会调用排序函数,因为我们的归并排序函数与冒泡排序函数不同
-
我们的第二个测试失败了,因为我们没有调用冒泡排序函数
在这种情况下,我们并没有改变系统的突现行为;我们只是更改了实现细节。相反,我们可以将测试设计成如下方式:
-
检查我们是否会在除数字数组以外的任何情况中出现错误
-
检查我们是否正确地对数字数组进行排序
这些测试仅检查所展示的行为,而不是我们是如何实现的。在这个新的测试框架下,当我们进行重构时,两个测试都会通过。
间歇性失败的测试
我常常询问客户有关失败的测试管道,结果常常得到这样的回答:“是的,它有时会这样。只要重新运行就行了。” 间歇性失败的测试会引发模糊性。
当测试管道失败时,我们的第一反应是重新运行它。这种模糊性意味着,我们识别管道失败的平均时间急剧增加,因为我们不知道问题是出在一个失败的测试,还是管道本身出了问题。我们不仅要对通过的测试充满信心,对失败的测试同样也要有信心。
让我们假设有一系列间歇性失败的测试。这些测试将阻碍生产部署、PR 审查和本地测试。它总是通过下次运行自行修复,每年只发生几次,且它是一个更新不频繁的微前端,那么为什么还要费力去修复呢?
在对问题进行初步诊断后,我们很快找到了罪魁祸首:有人在测试中断言当前的 UTC 分钟数小于 59,而不是小于或等于 59。这个符合概率的更改已经被成功推送并合并。这个期望深藏在一个代码块中,阻止了初步检查从测试输出中诊断出问题。这也为冗长且格式良好的测试输出提供了有力的论据。正如你可以想象的那样,有人在本地运行正常的情况下,某个管道失败了;他们决定重新运行,结果通过了。大家知道这个特定的管道是易出问题的,我们可以通过重新运行来修复它。你觉得这对开发人员有什么影响?
当我在工作中遇到这种情况时,我们发现,由于对基础管道失败的信心不足,失败的重新运行次数大大超过了不稳定的实际运行次数。云原生交付使我们能够快速推送代码库的增量更改。这一过程意味着,高效的团队每天会多次运行这些管道。
因此,在云原生环境中,对你的管道保持信任,无论成功或失败,都是至关重要的。测试变得不稳定的另一种常见方式是依赖于测试副作用或耦合测试。
具有副作用或耦合的测试
依赖副作用或耦合测试是一个容易陷入的陷阱,特别是在我们重构代码并添加现有测试时,因为其他测试可能已经引起副作用,而我们的新测试可能会不知不觉地依赖于这些副作用。
为了举例说明,让我们考虑确保用户行为的测试。我们有两个端点:一个用于创建用户,另一个用于删除用户。我们有一个测试,它生成一个随机的电子邮件,使用该电子邮件创建一个用户,并将其作为全局变量保存在测试文件中。然后,另一个测试读取该全局变量并删除该用户,检查用户是否正确删除。我们在这里违反了两个规则。我们不仅通过修改全局状态产生了副作用,而且还通过这个副作用耦合了两个测试。理解我们在这里失去了什么是至关重要的:
-
隔离测试:由于耦合问题,如果我们只想运行用户删除测试,它总是会失败,因为它需要与用户创建测试一起运行。现在我们只能运行整个测试文件。
-
重构能力:如果我们将测试移动到不同的文件或改变其执行顺序,它们将失败。这使得重构变得更加困难,因为我们现在需要理解它的耦合测试,以便重构我们感兴趣的功能的测试。
-
并行执行:随着我们的测试基础逐渐增长,优化管道执行变得愈加明显。人们通常首先会选择并行执行工具。当我们耦合测试时,并行执行可能导致失去测试套件的确定性执行。这种缺乏确定性意味着测试可能会间歇性地失败,从而导致管道变得“不稳定”,因为测试可能会或可能不会按照正确的顺序执行。
我们如何去除示例中的耦合和副作用?对于单个测试,一个简单的指示器是将测试单独运行,并检查它是否仍然通过。这个检查确保我们的测试没有上游耦合;它不会测试副作用或下游耦合。
下一步是重构我们的测试文件。理想情况下,应该没有全局变量。这个概念可能会引起争议,因为许多测试实现会在全局变量中有静态数据。然而,严格控制的生成数据总是比静态数据更好。
其背后的驱动因素很简单:生成数据意味着你在更大程度上测试了系统的边界。这可能会导致测试管道间歇性地失败,但如果你遇到间歇性失败,请将其视为一种祝福,而非诅咒。出现间歇性失败意味着你生成的数据与预期的生产数据不符!如果你使用静态数据,就永远无法在生产环境之前发现这个边缘案例。
使用静态数据的另一个问题是团队往往会变得懒惰。常见的罪魁祸首是 UUID。我见过生产系统崩溃的案例,原因是有人用了相同的 UUID 去索引两个不同的值,并在代码中创建了一个在生产数据中并不存在的关联。问题在于,开发者并没有生成一个新的 UUID,而是看到另一个实体的 UUID 已经生成,决定复制这个已经合规的 UUID,从而节省了大约 20 秒的开发时间。正如你所想,节省这 20 秒的时间远不及最终停机带来的影响。
大多数测试库都提供了预测试和后测试的钩子,用于设置数据和应用组件。通常也会提供一定的粒度,你可以在所有测试之前和之后运行,或者在每个测试之前和之后运行。决定何时使用它们的因素通常取决于应用组件。
如果组件有一个由测试修改的内部状态,那么该组件应在每个测试之前和之后创建和销毁。例如,局部缓存和持久化层。如果组件没有内部状态,通常可以通过为所有测试设置一次并在所有测试完成后销毁来进行优化。
示例可能包括认证层(除非你在该层存储会话!)、请求路由层或实用组件。当我们考虑避免副作用和测试顺序时,我们可能会想到将整个流程放入一个单一的测试中。这样,我们就没有打破测试之间的边界!然而,这会引出下一个非功能性反模式:多阶段测试。
多阶段测试
多阶段测试往往是因为我们将动作视为相关的。然而,我们需要记住,测试的目的是通常是测试一个行为单元,即使在集成测试中,我们也有一个更广泛的行为单元定义。为了理解为什么这是一个反模式,我们需要看看我们的失败模式。当我们有许多原子测试时,我们可以轻松看到哪个功能被破坏了。通过更少的多阶段测试,我们可能覆盖了相同的行为,但我们失去了报告的精确性。
多阶段测试中的早期错误也可能导致测试提前失败,从而掩盖后期多阶段测试中的错误。这可能是一个逻辑谬误,但如果我们用一个大型的多阶段测试替代所有的测试,我们就只能得到整个系统的通过或失败,这样一旦失败,问题的范围就非常广泛。在另一个极端情况下,如果我们将测试做到尽可能原子化,就能获得极高的精度,准确知道哪个行为单元出现了问题。这个领域中的一个模式是使用安排、操作和 断言(AAA):
-
安排:设置测试运行所需的所有内容(数据、认证、应用实例等)。
-
操作:执行待测试的行为。这一操作可能是调用某个端点或方法,或者执行集成流程。
-
断言:检查行为的结果是否符合预期。
关键在于,这个模式在一个测试中应该只出现一次。例如,未遵循这个模式的测试可能是这样:安排、操作、断言、操作、断言、操作、断言。后续断言的失败会掩盖第一次断言之后的所有操作。因此,我们的测试应该具有正确的原子性,以提供尽可能多的细节。
到目前为止,我们主要关注了单元测试,但我们不应当仅仅进行单元测试,忽略其他所有测试。接下来,我们将讨论另一个关键的测试类型,来确保语义正确性:契约测试。
缺少契约测试
在云原生环境中,我们通常会看到组件之间的松耦合,功能通过 API 和事件的组合进行暴露,并由其他微服务、用户界面、第三方及各种组合和排列来消费。在开发系统组件时,单单关注应用程序的即时需求已经不够了。我们需要为服务之间的通信提供信心。这就是契约测试发挥作用的地方。
契约测试
契约测试的核心概念是契约。契约是一种规范,明确解释数据如何在服务之间共享及其格式,甚至可能对非功能性需求做出一些保证。这个契约可以以 OpenAPI 规范、JSON Schema、Protobuf 定义、Smithy 接口或任何类似的接口定义语言(IDL)的形式存在。
数据契约的另一部分是它应该传达被传输数据的语义含义。关键在于为消费者提供清晰的定义,告诉他们预期会得到什么。现在我们已经有了契约,可以检查应用程序的输出,并确保它与已发布的架构一致。换句话说,我们是根据契约来测试我们的应用程序。
我们现在可以解耦应用程序的不同部分开发。通过提前定义我们的通信模式,并定义测试来检查我们是否遵守该模式,我们可以在达成合同一致的前提下,构建应用程序的多个部分。随着团队的扩展以及功能开发超出单个开发者的范围,这类测试变得越来越重要。如果一个开发者在处理应用功能的垂直切片时,可能会根据进度逐步设计组件间的通信模式。这允许敏捷开发;然而,当该开发者需要与其他方协作时,问题就出现了。他们在头脑中保持的迭代变化,突然成为系统整体进展的障碍,因为这些频繁的变化需要进行沟通。
尽管提前定义通信模式可能听起来有些像瀑布式开发,但需要注意的是,前期规划的程度是最小的。我们在这里操作的是功能的最小单元,一次处理一两个 API 端点,而不是系统的整体定义。提前投入时间建立共享的通信模型理解,将在未来带来回报,因为与其进行数据交换模型的迭代性快速变更,我们现在只会根据双方的功能需求和协议对模型进行必要的修改。
超越初步合同
当我们为数据交换方法构建这些合同时,我们可以开始发布这些文档供其他方使用。通过合同测试确保我们始终遵循数据合同,我们确保当前和未来的消费者可以继续享受其依赖项的稳定运行。新用户可以轻松地作为系统的消费者加入,因为系统已经有了文档说明。
那么问题来了,当我们需要更改合同时,会发生什么?这时,另外两种反模式就会出现。第一个反模式是没有维护服务依赖图。服务依赖图准确地告诉我们哪些服务从我们构建的服务中消费功能,并遵循合同规范。
这使我们能够评估我们正在对其进行合同更改的服务的影响范围,并确保我们对合同所做的任何更改与其他使用该服务的服务兼容。许多云服务提供商通过内置的可观察工具提供分布式事务追踪,或者我们可以通过任何提供类似服务的第三方工具来构建一个。如果没有服务依赖图,我们就无法了解我们计划做出的更改的影响范围。让我们来看一个简单的服务图示例。

图 13.1 - 一个简单的用户服务示例,通过 API 网关暴露,并被两个上游服务调用
在这个例子中,我们有一个用户端点,同时被消息服务和前端后端服务调用。
从前面的例子中,我们可以看到,用户服务的/user契约的更改将影响到两个上游服务,它们可能也需要更新,以确保服务的连续性。当我们定义新的契约时,可以用它来测试上游服务,如果它们都通过了,就可以安全地进行更改。那么,当我们更改契约时,如何避免破坏上游服务呢?
这引出了我们的第二个反模式,它直接操作现有的数据契约。我们可以扩展数据契约来包括新的功能,而不是修改现有字段或功能的语义含义。考虑一个由前述消息服务使用的对象,该对象从/user端点返回一个name字段。我们的数据契约规定该字段表示人的名字,例如Alice。消息服务可能还想提供一个称呼,例如Ms. Alice。在不修改消息服务的情况下,我们可以改变/user端点数据契约的语义,使得name现在表示称呼加名字。然而,这可能会对服务的其他消费者产生意想不到的影响。假设前端后端(BFF)服务获取多个用户的信息并按字母顺序排序他们的名字。现在,我们按称呼排序,而不是按名字排序。通过改变语义含义,我们无意中修改了行为。
这个牵强的例子看起来似乎很容易避免;然而,即使是对数据契约的小变动,也可能会带来意想不到的后果。这里有两种选择:要么我们修改数据契约并处理后果(通常很难预测、发现和修复),要么我们扩展数据契约。当我们扩展数据契约时,我们依赖那些未参与变更的服务忽略这些扩展。例如,我们可以不改变name字段的语义含义,而是新增一个叫做salutation的字段。消息服务可以使用这个字段来提供所需的功能,而 BFF 服务则可以继续使用name字段,忽略salutation字段。
如果我们真的必须改变数据契约的底层语义,我们仍然可以遵循不修改其他系统期望行为的原则。这可能看起来不符合直觉。然而,通过利用 API 版本控制,我们可以通过增加 API 的 v2 版本,根本性地改变数据契约的结构和语义。这保留了我们旧系统之间的数据契约,同时允许我们做出显著更改以支持新功能。我们可以通过契约测试使依赖服务与新数据契约对齐,从而追溯更新它们。最终,我们可以在没有实质性影响的情况下废弃原始端点,这样我们就基本上将数据契约的修改与新数据契约的采用解耦,从而将一个高度同步的部署过程和可能的停机时间,转变为一个可以根据业务需求异步进行的过程。
契约执行
定义我们在服务之间使用的数据契约是好的,但下一步是契约执行。仅仅定义我们服务之间传递的契约是不够的。理想情况下,在两个端点,我们应该检查我们传输的数据是否与我们对契约的理解一致。这里的一个重要方面是验证我们知道的内容并丢弃我们不知道的内容;这给我们提供了扩展契约的选项,正如我们之前讨论的那样。运行时的契约验证可以帮助我们避免意外的数据行为,并提醒我们契约之间的匹配问题。
一个好的实践是将我们的契约测试与模糊测试结合,注入损坏或无效的数据,以确保我们的应用程序能够拒绝这些数据。在云环境中,拒绝错误的数据与接受正确的数据同样重要!
为了提供良好的用户体验,在将数据发送到我们的服务之前,在应用层强制执行数据契约通常是有用的。这样不仅能为用户提供更快的反馈,而且每个我们在应用程序中捕获的错误,都是我们不需要处理的请求,从而减少了底层资源的负载。你能用的最便宜的计算机通常是离用户最近的边缘设备。
然而,另一方面,我们希望在接收到数据时进行验证,以确保其正确性和安全性。任何人都可以向我们的端点发送任何数据,我们有责任处理它。如果我们在后端和前端都执行契约,我们的数据契约就需要是可移植的。
可移植性
在这些场景中,不言而喻,数据契约的格式应尽量保持技术中立。框架和语言特定的库往往具有有价值的功能。然而,将我们锁定在某个框架中可能会使得跨技术操作变得困难。在类似的执行环境中,比如前端使用 React,后端使用 Node.js,它们都在底层运行 JavaScript,因此可能会有诱惑去使用专门的解决方案。但是,如果你的公司收购了一个代码库为 C# 的产品呢?他们将如何访问契约并确保数据完整性?因此,前面章节提到的所有格式的可移植性要求应始终牢记于心。
一个成熟的标准(如果你使用 JSON,这几乎是事实上的云原生标准,除了 GCP 中的 Protobuf!)是 JSON Schema。它由互联网工程任务组(IETF)维护,通过简单的网络搜索,你会发现他们是我们今天理所当然接受的许多标准的管理者。你通常可以找到非常成熟的库来生成、验证和测试 JSON 架构,支持你选择的语言和框架。它还允许通过标准如 OpenAPI 或 AsyncAPI,明确区分用于测试的数据架构(JSON Schema)和接口定义。如果架构是数据的定义,接口定义则是定义我们架构与服务端点之间关系的元结构。
代码生成
如果我们已经预定义了架构和接口定义,那么有多个开源项目可以利用这些信息来生成代码。通常,这种代码生成包括三个独立的组件:
-
类型生成:从我们的架构中生成类型,以供代码中使用。这种生成通常是其他两种类型的先决条件。
-
客户端生成:根据我们的接口定义和生成的类型,我们可以自动构建 SDK 来与我们的服务进行交互,无需担心需要进行 API 请求、编组和解组数据等问题。
-
服务器存根生成:根据我们的接口定义,我们可以生成服务器存根,使我们能够遵循接口定义,只需要构建业务逻辑。
当我们看三大云服务提供商时,他们使用这种方法来维护他们为各种语言提供的 SDK。AWS 使用 Smithy IDL 2.0,这是专门为 AWS 定义接口和代码生成而定制的,但它是开源的。Azure 使用 OpenAPI 规范,这是我们已经深入讨论过的内容。最后,GCP 使用 Protobuf 定义其所有服务,可以以 JSON 或自定义的紧凑二进制格式进行编码。通过使用代码生成,他们可以对底层契约进行更改,并通过重新生成所有后续客户端 SDK 来应用这些更改。
所以,契约测试确保我们不会破坏上游服务的功能和语义,并确保我们在调用下游服务时有信心。但我们如何确保用户界面的连续性呢?这就是一个反模式如此普遍,以至于值得单独开一节来讲解:手动测试。
手动测试
在开始这一部分时,一个出处争议的名言浮现在脑海:“我没有时间给你写一封简短的信,所以我写了封长信。” 虽然这看起来有些反直觉,但人们通常对手动测试持有相同的心态。他们常常沉迷于手动测试的过程,以至于没有停下来考虑自动化的可能性。这种反模式通常深深根植于组织结构中,直到团队层级。本部分将探讨在云原生环境中转向测试自动化的理由,以及你可以使用的实践,将手动测试流程迁移到自动化测试。
典型的公司测试类型
通常,公司会确信单元测试能够提供实际的好处,并同意这些测试可以自动化。如果你是一个手动执行单元测试的公司,那么你的工程师必须具备无限的耐心。
集成测试处于中间地带,公司对此有不同的处理方式。有些公司认为,如果他们编写足够的单元测试,那么集成测试是可选的(下一部分会详细讨论这个问题)。有些公司进行一些集成测试,但这些测试并不成为部署流水线的一部分,或者只是偶尔手动运行一次。
最后,我们有那些已经进行集成测试、将其自动化并将其纳入部署流水线的公司。还有其他的处理方法和成熟度层次,但这些是我们常见的集成测试类型。在最后的层级,我们有端到端测试,这些测试可能是自动化的,并成为部署过程的一部分;如果你的公司就是这种情况,那么这一部分可能已经是在对合唱团宣讲。然而,这些测试更有可能以专门的质量保证(QA)职能的形式存在,点击用户界面,按照电子表格或文档中的步骤操作,然后反馈结果,无论是在部署前还是部署后。
所以,关键在于,我们在观察三种不同类型的测试:
-
单元测试:测试单个服务或组件中的原子功能单元
-
集成测试:测试组件之间的交互
-
端到端测试:从最终用户的角度测试系统的功能
测试自动化的理由
在考虑这三种测试形式时,我还想回顾一下你工作记忆中的 DORA 指标:
-
部署频率
-
变更的交付时间
-
变更失败率
-
恢复服务时间
测试涉及优化一个指标:变更失败率。我们在部署变更之前进行的测试越多,变更失败率就越低。需要注意的是,这消除了我们在本小节早些时候讨论过的所有测试类型。
如果你的测试没有在部署路径上进行,那么你就没有保护你的变更失败率!虽然通过部署后测试,你可能会更早发现错误或其来源,从而可能有更快的恢复服务时间,但这实际上属于完全不同的专业领域(请参见第十章,关于观察已部署架构的内容)。因此,我们已经设定了一个要求:为了让测试对软件团队的性能产生有意义的影响,测试必须是部署到生产环境的关键路径上的一部分。
当我们使用手动流程时,我们最终会将变更批量处理,以便跟上代码库中的变更节奏。这有助于保护变更失败率。然而,实际上,将变更批量处理会增加我们的变更失败率,因为我们将这些变更合并在一起的情况下,任何单一变更对应用程序产生重大负面影响的概率比我们单独部署这些变更时要大得多。
假设我们在单独部署 100 个变更时,5 个变更失败。那么,我们的变更失败率是 5%。如果我们将这些变更分成 10 组,每组 10 个,进行 10 次部署,可能会运气好,把那 5 个失败分布在 100 个变更中,并且都集中在 1 个组内,但这仍然是 10%的变更失败率。更有可能的是,这 5 个失败分散在 10 个组中,导致多达一半的组失败,变更失败率高达 50%。如果我们只做一次重大变更,那么最终结果就是每个变更都会失败。这只不过是规模的问题,因此,即使测试在我们的关键路径上,批量处理变更仍然可能导致变更失败率的问题。
所以,我们已经确定批量操作对我们的变更失败率有不良影响。现在让我们看看其他指标:我们的部署频率和变更的交付时间。这两个功能都依赖于我们整个流水线的时间。向流水线中引入手动阶段会显著增加完成所需的时间。较长的流水线周期意味着开发人员不太可能部署小的增量变更;相反,他们更有可能将变更批量处理,导致我们之前讨论的将变更批量测试的问题。这会影响我们的部署频率。
我们的另一个指标,变更交付时间,是指在变更部署到生产环境之前,必须完成的所有线性步骤的总和。通过增加流水线时间,即使我们保持变更原子化并频繁部署,变更交付时间仍然会变得更长,因为其中某个环节需要较长时间才能完成。所以,手动测试对我们的变更失败率有破坏性,也影响我们的其他指标,变更交付时间和部署频率。我们在本书早些时候讨论过,部署路径中引入具有长周期时间的阶段或增加部署时间,意味着我们不太可能在服务受到严重影响时执行相同的检查,因此那些紧急修复或旨在解决生产中紧急问题的变更,通常没有像最初导致问题的代码那样经过严格测试。
所以,如果我们严格按照流程操作,我们会发现恢复服务的时间也会受到负面影响。我们只能通过变通方法和标准操作程序之外的途径来改善恢复服务的时间。这也抵消了通过在生产环境中测试或在关键部署路径之外早期发现问题所可能带来的任何好处。
一旦我们将人类引入我们的流程中,就会引入变数。人类非常擅长处理未知的问题,运用他们的知识和启发式方法,解决他们之前没有遇到过的问题。测试恰恰与这个过程相反。我们知道我们要测试的问题以及如何进行测试。因此,人类并不适合从事手动测试工作。通过自动化,我们可以显著加速这个过程。一旦我们将人类从方程式中移除,并引入自动化而非手动流程,我们能够进行多少测试的问题就不再是人力资源的问题,而是计算资源的问题。随着云计算的出现,可以根据需要快速配置和释放按需计算资源来执行测试。这个过程加速了我们的反馈周期,不仅使我们有信心确保所做的更改不会导致失败,还使所有开发人员能够在将代码推送到生产环境时,充分测试所有代码。
现在,这听起来好像人类在测试过程中没有任何价值;然而,我想提出一个假设:人类在定义和构想测试套件方面可以提供独特的价值,而不仅仅是执行这些测试套件。测试套件的定义和创建是一项独特的技能;它们是可变且微妙的,而人类在这方面非常擅长。一个很棒的笑话是这样的:一位开发者走进酒吧点了一杯啤酒;一位测试人员走进酒吧点了一杯啤酒、10,000 杯啤酒、负 1 杯啤酒、一张沙发,等等。尽管如此,我们重视的测试部分是创造性方面,理解问题空间,并提出独特的边界情况来确保行为一致性。实际上,执行这些测试是测试人员不应承担的任务。本节内容并不会告诉你让整个测试团队冗余。本节的目的是通过允许测试团队发挥创造力,最大限度地发挥他们的作用。
迁移手动测试流程
如前所述,手动测试流程通常存在于端到端的过程中。手动集成测试的迁移过程将其置于关键路径上,因为它们可能已经作为代码驱动的测试存在。如果没有,它们可以利用开发团队现有的技能集来创建集成测试。另一方面,手动端到端测试可能看起来是一个更加艰巨的迁移任务。我们的测试团队可能没有编码技能。然而,这并不意味着我们必须重构整个测试部门。相反,我们可以采取三个关键行动:
-
倚赖我们的开发职能
-
利用工具加速迁移
-
提升我们测试团队的技能
正如我之前所说,人类能够应对变化。我们的开发团队可能并非恶意地利用这一点,而是无意中依赖视觉提示来引导进行手动测试。当我们迁移到自动化测试时,通常必须依赖用户界面中对测试人员不可见但对测试框架可见的属性。例如,当我们将界面中的按钮改为超链接但保持相同的样式时,测试人员不太可能察觉到变化。然而,对于一个寻找按钮元素的自动化测试套件来说,这却是一个重大的变化。
因此,我们的开发团队需要改进工作方法,以确保其产生的工件是可测试的。在 Web 世界中,这可能表现为利用 ARIA 标签为特定元素提供意义。通过这种方式,共享 ARIA 标签的超链接和按钮可以被类似对待。关于 ARIA 标签,不仅测试人员会感谢你让 UI 更具可测试性,适当的 ARIA 标签还会使你的网站更具可访问性。因此,这是你应该做的事情。我们的开发团队已经很熟练地将测试集成到生产流程中。所以,我们可以依赖开发团队帮助将这套新的测试套件集成到生产路径中,从而免去测试团队对这项能力的需求。
我们仍然需要帮助编写测试。然而,开发团队不太可能愿意逐一查看过去手动测试团队所产生的所有文档,并将其转换为自动化测试。这也无法适应未来;我们想要添加的任何新测试都将依赖于开发团队。这时我们可以利用工具来加速迁移。许多用于端到端测试的测试套件都包括允许我们直接从浏览器录制测试的功能。使用这个功能,我们可以最后一次手动执行测试,录制下来,然后保存到我们的自动化测试框架中使用。
我们的真实依据不再是大量的文档,而是没有歧义的编码化测试。这个过程使我们大大接近于实现无需开发团队参与的自动化端到端测试。对于这次初始迁移,可能需要与开发团队进行接口对接,帮助项目启动。然而,从长远来看,测试团队必须独立完成这一过程。
我们必须提升测试团队在创建测试时使用的框架技能。这并不意味着每个测试员都需要成为开发人员。然而,每个测试员都需要具备独立定义、记录和将测试集成到测试套件中的能力。这个过程要求较小,但通过利用工具并依赖开发功能,我们可以避免改变团队结构。我推荐唯一改变团队结构的情况是朝着书中早些时候提到的结构转型,使团队能够自给自足。
如果你的测试功能是你业务中的独立单元,考虑将它们融入到交付团队中,使其能够完全自主。这不仅会打破独立测试功能和开发功能之间的对立关系,还会让团队能够完全拥有交付结果的端到端责任。这种更紧密的对齐意味着测试员可以依赖他们团队中的开发资源,在提升技能以实现完全自给自足的过程中获得支持。
尝试重建云环境
在上一节中,我们讨论了通过过度使用单元测试来弥补集成测试的缺乏。良好的编码实践能推动良好的测试。我们的业务逻辑,即驱动价值的代码部分,应该进行单元测试。然而,对这部分代码进行单元测试时,不应涉及过多模拟其运行环境。我们在这一领域中常见的反模式是,人们尝试通过第三方工具、广泛模拟或其他方法在本地环境中重建云环境。
为了剖析这种反模式,我们将审视传统的测试范式、云原生世界中的测试样式,以及我们如何最好地利用云服务来测试我们的代码。之前,我们集中讨论了端到端测试、契约测试和单元测试,因此这一节将重点讨论集成测试。
传统的测试范式
传统的测试范式通常包含大量的单元测试,因为它们成本低,少量集成测试,因为它们编写起来稍微有点难度,执行起来也有些难度,只有少数几个端到端测试,因为如前所述,这通常是一个手动功能。这通常为我们提供了一个被称为测试金字塔的模式。

图 13.2 - 测试金字塔
在本节的初始前提中,我提到我们的单元测试应该专注于测试那些与我们业务相关的代码部分:我们的业务逻辑。在云端环境中,资源便宜,许多以前存在于应用程序中的复杂性现在可以委托给云服务提供商本身。这就提出了一个有趣的问题:如果我们的逻辑被推送到云服务提供商,那么通过单元测试能够测试的功能将越来越少。通常情况下,我们看到开发者在这种情况下开始依赖大量的模拟。进入客户的代码库时,看到为测试一段业务逻辑而模拟了八个或更多云服务并不罕见。第三方工具也应运而生,并承诺在你的测试流水线或本地环境中提供类似云的功能。
如果我们继续以传统的单元测试优先思维方式,这些看起来都是很有吸引力的提议。当我们看到测试金字塔时,可能会觉得依赖集成测试是开发者的失败:“我没有足够好,无法为此编写单元测试。”我们可能认为集成测试仅仅用于非常复杂的跨服务行为,但这会将我们带入集成测试的领域,而非集成测试的领域。就像一部受欢迎的自然纪录片的制作人一样,我们希望观察系统在其自然栖息地中的行为。在我们的例子中,它的自然栖息地恰好是云端。
测试蜂巢模型
Spotify 研发在 2018 年发布了一篇优秀的文章,探讨了测试的蜂巢模型(engineering.atspotify.com/2018/01/testing-of-microservices/)。在这个蜂巢模型中,我们减少了对单元测试的过度依赖,作为测试的基础层,转而依赖集成测试或服务测试。Spotify 特别提到了集成测试的移除,即跨多个服务的测试。然而,我们认为,即使跨越多个服务,端到端的测试仍然可以产生价值。它们不应该作为单个服务健康状况的指示,而应该作为部署前的整体系统健康检查。

图 13.3 - 测试蜂巢模型
使用集成测试,我们比单元测试更准确地代表了实际部署环境。我们不是对云的模拟进行测试,而是将我们的服务部署到云端,然后在它们的自然栖息地中进行测试。在传统模型中,这种方式是可行的,因为我们的功能大部分存在于应用程序的上下文中。
然而,正如我们所说,我们应用程序中越来越多的常见部分正被外包到云端托管服务中。因此,很容易在云服务和我们想要测试的逻辑之间产生紧密耦合。在接下来的部分中,我们将更详细地讨论如何构建我们的代码,但现在,让我们专注于集成测试。
在云中测试与为云测试
在本书的早些章节中,我们讨论了在短暂环境中的开发。相同的概念可以用于我们的测试管道。利用测试蜂窝的结构,我们有许多集成测试来指定我们的应用程序如何与云环境交互。这些测试可以在临时的云环境中运行。这使我们能够在云中测试代码,使用真实的云服务而不是模拟它们。当我们模拟云服务时,我们是在将代码与我们脑海中对云的模型进行测试。而当我们使用实际的云服务时,代码不需要通过任何过渡的心智模型来进行测试。
有一些核心概念,我们需要实现这些概念才能在短暂环境中测试我们的代码:
-
我们必须拥有坚实的基础设施即代码(IaC)基础,以便根据需要快速启动和销毁环境。
-
我们需要了解我们基础设施中哪些部分需要更长时间来配置,并为测试目的提供预配置资源,以保持较低的周期时间。
-
我们的测试管道必须能够访问云环境。
在讨论坚实的 IaC 基础时,我们指的是在实现 IaC 时遵循良好的实践。为了有效地测试我们的应用程序,我们只需启动测试所需的基础设施部分,而不是整个应用程序。通常,我们需要在不同应用领域之间设置明确的域边界,以便有效地在与其他应用组件隔离的云中测试我们的系统。有关提供应用组件之间坚实边界以及应用组件内部强凝聚力的更多信息,我们建议查阅紧密耦合,低 内聚性部分。
IaC(基础设施即代码)中另一个通常通过这一实践暴露出的有趣部分是具体 IaC 属性的固化和编码。当我们需要部署多个副本来运行测试时,有时需要同时运行多个副本,我们可以迅速发现基础设施中那些围绕单一部署固化的区域。因此,这种测试方式还可以突出我们弹性计划中的漏洞,以及我们启动新应用实例的能力。
一些基础设施即代码(IaC)配置的某些部分可以非常快速地进行配置。例如,无服务器函数或 API 网关可以在最短的时间内进行配置。另一方面,更传统的资源,如关系型数据库实例或虚拟机,可能需要更多的时间来创建。通常,我们可以在测试环境之间使用共享资源,并通过命名空间或任何其他支持的分区方法进行划分。例如,假设我们有一个关系型数据库服务。在这种情况下,每个测试环境可能使用相同的数据库实例,这需要较长的时间来配置。然而,可以在该实例内创建一个单独的数据库来执行测试,然后在完成后将其删除。内存中的键存储可能使用一个实例,并且每个键的前缀使用测试套件执行时独特的命名空间。这个过程确保我们保持较低的周期时间,能够为开发人员提供快速反馈,同时还允许我们维持高频率的部署和较短的更改前置时间。
所有这些的基础是,我们的测试环境需要是真实的云环境。这个要求可能意味着将我们的测试管道与云凭证、基础设施管道和 CI/CD 流程连接起来。这增加了复杂性;然而,它的好处是增加了部署的确定性。将书中描述的其他最佳云实践应用到用于测试的云环境中也是至关重要的。我们仍然可以应用良好的云治理、FinOps、DevSecOps 和平台工程的实践,使这个云环境在我们的云资产中成为一等公民。通过在这个云环境中保持良好的操作习惯,我们不仅能让需要在该环境中运行测试的开发人员更加轻松,也能提高我们所运行测试的确定性,避免管道不稳定、长时间管道运行和较长的更改前置时间等问题。
测试非功能性需求
现在我们在真实的云环境中进行测试,并且已经拥有成熟的集成测试,我们还可以测试以前无法测试的属性。在这个领域中,以下是一些非常重要的测试属性:
-
延迟:这确保我们的请求能够在合理的时间内完成
-
一致性:许多云系统遵循最终一致性的原则,但我们可能对一致性时间有非功能性需求
-
可扩展性:我们可能希望进行负载测试,以确保我们的服务能够处理预期的流量模式
-
弹性:假设我们已经有了弹性策略,我们将根据书中早期讨论的原因进行测试
在这一点上,你需要发挥自己的判断力。之前我们讨论过,测试需要在关键路径上进行,才有意义。对非功能性需求进行测试并不总是能在关键路径上进行,通常这类测试涉及到我们应用程序的缓慢变化特性。因此,出于其复杂性,定期执行这类测试有时可能会更好。通常,这些测试用于检查先前执行中的回归。我们也可以将同样的严谨性应用于检查其他测试中的非功能性需求回归。
我们当然可以检查关键路径上的回归测试执行时间。在最近的一例中,一次手动发现的回归揭示了 XZ(一个流行的压缩工具)中的一个漏洞。一位开发人员注意到 SSH 执行时间的回归,随后通过调查发现了一个持续了多年的复杂阴谋,旨在为该工具留下后门。整个故事听起来像是一部间谍电影,任何感兴趣的读者都值得进一步研究。
尽管这些回归是手动发现的,但如果没有被发现,它们可能会对许多基于这些工具构建的项目造成灾难性的影响。
结构不良的代码
我们在编写云原生软件时常见的一个关键反模式是将 100%代码覆盖率与代码质量等同起来。重要的是要记住,高质量的代码和良好的编码实践应当自然地产生足够的代码覆盖率,以保证我们想要测试的行为。作为专业人士,我们必须确保遵循这些实践。编写良好测试的主要障碍之一是结构不良的代码,换句话说,就是低质量的代码。因此,在本节中,我们将探讨在编写云原生软件时可能出现的一些常见反模式,以及它们如何影响我们进行测试的能力。
关键术语
在讨论代码结构之前,我们需要定义一些关键术语,以便理解当前话题:
-
业务逻辑是指我们应用程序中将用户与持久化层之间的信息进行转换的所有操作。业务逻辑可能包括评估自定义规则,以确定客户是否有资格购买某个产品,或者将库存分配给刚刚进入采购系统的新订单。从根本上说,业务逻辑是我们应用程序中呈现我们独特商业主张的部分。如果我们将用户直接连接到持久化层,那么我们为客户增加了什么价值呢?公司中的其他非业务逻辑领域仍然通过提供良好的用户体验、可靠性和履行等内容而产生价值。但从软件的角度看,通过业务逻辑对过程进行编码和重复性的执行,通常是我们获得价值的核心元素之一。
-
副作用是指我们的应用程序执行的任何影响系统其他部分并依赖于定义函数之外行为的操作。例如,副作用可能是创建数据库中的新记录或向用户的手机发送通知。任何我们的函数执行的操作,除了根据其参数返回一个值,都是副作用。副作用本身并不是错误的。相反,它们是我们应用程序的一个重要组成部分,使我们能够执行诸如持久化、演变和事件处理等操作。
单体架构
仅仅因为我们通过微服务或无服务器函数逃离了单体应用程序,并不意味着我们在代码中已经逃离了单体的概念。我定义了前面两个术语,因为它们代表了应用程序必须执行的两个重要但非常不同的操作。关键的区别是,纯函数通常可以代表我们的业务逻辑。这个函数没有副作用,仅仅依赖其参数来生成返回值。为了保持这个函数的结果,我们必须依赖副作用与系统的其他部分进行通信,例如我们的数据库。
这就是我们再次可能陷入单体陷阱的地方。将业务逻辑与副作用交织在一起以满足需求是很有诱惑力的。从逻辑角度来看,这似乎很合理,在构建代码时,我们在需要的地方添加副作用。但这将导致高耦合和低内聚性,正如我们在单体结构中曾经遇到的那样。相反,我们应该做的是将关注点从业务逻辑中分离出来。定义我们如何操作的规则应该写成纯函数。它们不应有任何副作用,使得我们公司的独特价值主张可以直接进行测试。
当我们开始将副作用直接与业务逻辑放在一起时,我们突然需要提供模拟这些副作用的功能,仅仅为了测试我们运行业务的规则。这可能将测试业务逻辑的过程从一个测试纯函数的 10 分钟练习,变成一个多小时的练习,其中大部分时间都用来设置环境,模拟副作用以便运行测试。回想上一节的测试蜂巢,我们可以通过另一种类型的测试来测试副作用。在这种情况下,我们应该使用集成测试,在云中测试我们的代码,而不是大量的模拟和单元测试。这一逻辑的延伸是将业务逻辑编写为纯函数,并只测试业务逻辑,以确保其符合我们的业务规则和期望。然后,当我们想测试系统的副作用时,我们可以开始对已部署的服务进行集成测试。
所以,现在我们已经成功地将业务逻辑与实现其有用性的副作用分离开来。尽管如此,仍然有许多功能性代码将业务逻辑与副作用绑定在一起。虽然这可以通过集成测试进行验证,但其他替代方案使我们能够在不在单元测试中复制云环境的情况下提高代码覆盖率。这是有利的,因为单元测试的复杂度较低,执行速度更快,反馈周期也比集成测试更短。
六边形架构
2005 年,阿里斯泰尔·科克本(Alistair Cockburn)提出了六边形架构的概念。广义上来说,六边形架构为我们提供了一种方法论,用于将副作用的实现与其使用解耦。我将提供一张六边形架构的示意图,之后我们可以更详细地讨论。

图 13.4 - 六边形架构模型的概念图
在我们应用的核心中,我们有将副作用和业务逻辑结合在一起的应用代码;这个组合就是我们的实体。副作用通过标准接口暴露,这些接口被称为端口。例如,我们可能有持久化端口或通知端口。重要的是,实体对这些端口的实现是透明的。它只知道通过何种接口暴露这些功能。适配器实现这些接口或端口。适配器包含与外部系统交互所需的所有知识。例如,我们的数据库端口可能连接到一个提供 PostgreSQL 兼容服务的适配器。我们的实体并不知道 Postgres;它可以是 DynamoDB、SQL Server、MySQL 或任何其他数据库引擎。重要的是,它暴露了实体所期望的功能,并且这些功能在端口中有定义。同样,我们的通知端口可以使用 SMS、电子邮件推送通知或信鸽;这对实体来说并不重要。
类似地,我们有由外部适配器驱动的端口,用于接收来自外部的流量。无论我们的实体是由事件队列中的事件触发,还是由直接的 HTTP 请求触发,我们都有端口代表请求的接口,然后通过适配器将这些端口连接到我们的实体。这是一个至关重要的区别:我们有驱动端口,它们是作用于实体的外部力量;还有被驱动端口,这是我们的实体用于作用于外部系统的端口。
这可能看起来与测试无关;然而,这种架构模式的一个关键好处是,它使我们的实体和应用代码与运行环境无关。与实际服务进行交互的复杂性被隐藏在适配器中。通过我们端口提供的简化接口,模拟副作用变得更加容易,因为我们可以创建一个新的适配器来实现预期的行为,而不是尝试模拟云原生服务。这也防止了我们将单元测试和应用代码与特定的库或 SDK 绑定,因为所有这些都在适配器中处理,并最终通过我们的集成测试进行测试。
因此,在这里,我们不仅能获得代码可测试性的好处,还能在需要更改与外部系统的集成时获得代码的可移植性;这只是编写一个新的适配器来匹配现有端口的接口问题。这样就消除了反对编写云原生软件的一个关键论点:它会导致供应商锁定。通过利用六边形架构,我们可以确保我们编写的代码与运行环境无关,从而增加了如果我们决定迁移云提供商时代码库中可用的部分。
从第一天开始就正确构建你的代码结构
我们在本章的几个部分已经涵盖了测试驱动开发(TDD),但我想从不同的角度来讨论它。当我们谈论如何构建可测试的代码以及良好的结构时,TDD 可以帮助我们实现这个目标。如果我们在代码库中为新功能编写的第一件事是一个测试,那么,默认情况下,我们为实现这个测试而编写的代码将会是隐式可测试的。
我将使用 Java 来描述可测试代码与不可测试代码的区别,因为它有一些隐蔽的反模式。假设我们正在测试一些业务逻辑,并且我们有一个类,其中包含了运行我们功能所需的一切。我们可能会被诱导将业务逻辑实现为这个类中的一个私有方法,并从对外公开的应用逻辑的公共方法中调用它。如果我们已经遵循了本节中的一些实践,我们可能还会将我们的私有业务逻辑方法标记为静态,以表示它不依赖于该类的内部状态。
现在,到了测试我们的代码的时候;当然,我们想要测试的主要功能是我们的业务逻辑,以确保我们在代码中固化的业务规则得到了正确实现。然而,由于我们类的结构,这部分代码是最难测试的,因为它是私有的,只能在类的内部暴露。
在这种情况下,开发人员可能会被诱导去做以下事情之一:
-
使方法成为公共方法
-
以一种测试所有业务逻辑边界的方式测试应用代码
第一个方法不太可取,因为我们为了测试目的而改变了类内部的可见性。其他依赖该业务逻辑的人可能会直接从这个类中调用它,而这并不是它的主要目的,从而违反了单一职责原则。
第二个方法也不太可取,因为我们通过代理测试代码,这使得测试对应用程序的变更非常脆弱。它还增加了测试方面的工作量,因为我们必须模拟应用程序代码运行所需的所有内容。
现在,考虑一下如果我们编写了一个测试,期望某个方法能够实现我们的业务逻辑,那么在这种情况下我们的代码可能会是什么样的呢?我们摆脱了应用程序的约束,因此不太可能通过应用程序代码来测试它。我们可以创建一个公共方法,但也很可能我们的应用程序代码还不存在,因为我们希望完善业务逻辑。所以,我们不将它添加到应用程序代码中的类里,而是创建一个仅实现我们业务逻辑的静态类,该类是直接可测试的,具有单一责任,并且可以在应用程序代码中使用。
因此,TDD 不仅仅是编写高效测试的工具,它还帮助我们推动代码的良好结构化。这并不意味着你需要在开始编写代码之前编写每个测试,而是提前定义你希望实现的核心行为。
摘要
测试是我们在云原生工具箱中最强大的工具之一。它防止回归,确保兼容性,并让我们更有信心地认为系统的行为与我们心中的模型一致。希望你已经获得了一些关于如何在不拖延开发进度的情况下构建有意义测试的技巧。良好的测试实践对于扩展云原生应用至关重要,通过避免本章中的反模式,你将能更快、更有信心地部署应用。到目前为止,我们已经覆盖了很多内容。接下来,我们将探讨如何开始你的云原生之旅。
第十四章:如何开始你的云原生改进之旅
到现在为止,你已经吸收了很多信息。我们已经讨论了许多反模式和关注领域。在接下来的两个章节中,我们希望帮助你准备好开始你的云端改进之旅,并过渡到最佳实践。
在本章节中,我们将专注于第一部分:开始你的云原生改进之旅。我们将涵盖以下领域:
-
如何识别反模式
-
定义目标状态
-
进行差距分析
-
结构化商业案例
看起来我们又有一个信息量很大的章节要面对,接下来让我们开始识别反模式吧。
识别反模式
在之前的章节中,我们已经详细讨论了识别反模式的过程。现在,我们希望从更高层次进行,识别出需要警惕的行为。我们将按照领域对反模式进行分类,这将帮助我们保持专注,而不会迷失在细节中。
一旦我们知道什么行为或观察可能是一个警示信号,我们就可以回到各个章节,查找关于反模式识别的详细信息、它带来的风险以及如何修复它。让我们来看看如何识别反模式,我们将依照问题领域进行分类。
一般性指标
识别反模式有一些普遍的迹象。以下错误通常会影响多个领域:
-
我们遇到困难的一个非常明显的迹象是,如果我们必须为了赶上截止日期而偷工减料。我们将会生产出平均水平或低于平均水平的质量,并积累技术债务。如果之后没有时间去修复这些技术债务,我们将会陷入运营复杂性的困境。
-
低估云原生和 DevSecOps 转型的文化影响及学习曲线,也是一个可能影响所有领域的陷阱,从战略到安全、合规、数据质量、运营复杂性等。一个常见的迹象是缺乏培训预算和分配的培训时间。缺乏与外部顾问的合作也表明知识没有在组织中深入嵌入。
-
构建模块和操作流程的标准化缺失是一个容易发现的红旗。缺乏一致性将增加技术债务和运营复杂性,降低弹性,并妨碍自助服务体验,从而影响我们实现快速发布周期的目标。此反模式的迹象包括缺乏服务目录或偏向的 CI/CD 管道、小变动却需要大量时间,以及从未达成一致、过时或没有明确界限的运营模型。
-
如果我们在软件开发生命周期(SDLC)中跳过某些阶段,我们的结果将会存在缺陷。例如,如果我们不先确定需求而直接开始设计,那么我们的解决方案中就会缺少需求。通常,这些需求包括操作、安保、弹性、测试、数据一致性以及非功能性需求。如果我们在没有设计的情况下直接开始实施,也是一样的情况。这并不妨碍我们使用敏捷实践,我们只需要考虑整个 SDLC 的全局视角。
在概述了这些通用指标后,我们将开始深入探讨特定的问题领域,首先是与文化和自动化相关的反模式。
DevSecOps 文化与自动化
我们将在这里检查几个关键指标,并引用详细描述这些指标的章节:
-
如果开发人员不小心删除实例、容器或数据库,或者手动创建证书或密钥,这表明我们拥有一个不成熟的 CI/CD 管道,且没有足够的防护措施。这也意味着我们没有强制执行最小权限原则,必须设置所需的权限扫描,以相应地缩减权限。我们在第五章和第六章中讨论了这些内容。
-
如果我们在上线前过度依赖渗透测试,并且在审核中发现严重问题,那么我们缺乏一个持续保障的过程,我们在第六章中讨论了这一点。
-
如果我们没有良好的测试覆盖率,我们要么会出现停机,要么在试图实现快速发布周期时,测试人员将成为瓶颈。为了充分利用云的所有优势,我们需要在我们的管道中嵌入功能性和非功能性的测试。这包括契约测试、性能测试以及安全性测试,如密钥扫描和漏洞扫描。我们在第十三章中探讨了这些测试类型。
我们可以看到,某些描述的反模式,例如采取捷径,可能与一些通用指标相关联。接下来,我们将总结与战略和云采纳相关的指标。
与战略和云采纳相关的反模式
这一组反模式似乎尤其难以被集中式架构团队的成员发现,而且其后果对我们的转型之旅会产生长期的负面影响。我们现在来深入探讨这些问题:
-
如果我们的云战略已经超过一年没有更新,或者我们的行动与战略中阐明的目标不一致,那么我们就有问题了。这意味着我们要么朝着错误的方向前进,要么甚至不知道我们的组织应该朝哪个方向前进。如果在冲刺过程中优先级经常变化,那也是反应性行为的信号,我们在第二章中探讨了这种反模式的修正方法。
-
如果我们依赖一个非常分散的治理模型,无法为团队提供足够的自主权,我们将无法充分扩展我们的业务,可能难以满足客户需求。另一方面,如果我们没有任何治理措施,我们将面临合规性、可靠性、自助体验和其他挑战。如果我们的实施没有反映安全政策和合规要求,这是一个警示信号。我们需要在防护框架、文化转型和培训之间找到正确的平衡,正如我们在第三章中探讨的那样。
-
如果我们缺乏成本责任感,且没有建立成熟的费用返还模式,那么产品团队将没有动力优化他们的云价值。结果将是资源的低效利用、缺乏与成本相关的架构决策以及经常性的云超支。我们在第四章中讨论了这一点。
-
当我们进行云迁移,却没有重新平台化或重构应用程序以充分利用云原生的好处时,我们将面临增加的运维复杂性和安全程序。最小的利益相关者承诺以及缺乏迁移计划是显现的因素,我们在第十二章中调查了这一点。
当然,这些反模式会对其他问题领域产生连锁反应。其中之一就是运维和可观察性,我们将接下来探讨这个问题。
运维和可观察性反模式
这一类问题将影响我们应用程序的可靠性,并可能导致团队的挫败感和潜在的 SLA 处罚:
-
如果用户报告了一个事件,但事件团队没有收到任何警报,我们就知道我们的日志记录和监控覆盖范围不如预期。日志记录和监控必须覆盖整个技术栈,从网络到操作系统、应用程序逻辑和数据库,正如在第十章中讨论的那样。
-
如果我们收到过多的警报,就会导致警报疲劳。结果是会有警报出现,但没人会回应,因为这些警报不断发生。我们必须确保使用正确的日志严重性级别,而不是在高环境中使用信息或调试级别,正如我们在第十章中讨论的那样。
-
如果我们因响应时间过慢而违反了性能服务水平协议(SLA),我们需要找出瓶颈所在。如果没有追踪和跨度,我们将无法获得改进架构的洞察力,正如我们在第十章中探讨的那样。
-
如果我们没有灾难恢复(DR)策略,并且长时间没有进行恢复测试,那么我们知道在实际恢复场景下,我们的准备工作不足。仅仅进行备份并不意味着我们能恢复。备份可能已损坏,部署可能不像我们想象的那样自动化,运行手册也可能过时。我们在第十一章中讨论了这一点。
现在,我们已经总结了操作和可观察性指标,准备进入最后一组:技术指标。
技术反模式
在与技术相关的指标中,我们将重点关注应用、数据和网络领域:
-
有状态的应用通常表明我们已经背负了一段时间的技术债务,并且没有刷新架构。这可能是由于定制现成(COTS)产品的技术限制,或者因为我们没有持续为改进架构分配足够的时间。有状态的应用在采用云原生功能(如 FaaS、蓝绿部署和自动扩展)时会拖慢进度。我们在第七章中探讨了这一点。
-
当我们在应用中使用紧耦合时,会导致长时间的等待,并且由于增加的 CPU、内存或函数调用时间,也会消耗大量计算和数据开销。像异步调用和使用队列这样的机制可以帮助我们解耦架构,提升扩展效率。我们在第七章中讨论了这一点。
-
如果我们为每一个用例都只使用关系型数据库,那我们很可能走错了方向。专用数据库,如 NoSQL 或时序数据库,是有其存在的理由的。它们为特定用例提供快速查找,同时也提供关系型数据库所没有的功能,比如事件流或基于时间的分析,这些我们在第八章中进行了探讨。
-
如果我们没有使用主动-主动或故障切换路由,我们的网络链接就是单点故障。我们在第九章中讨论的云原生网络构造可以避免这种情况,并增强系统的弹性。
反模式可能出现在多个领域,从文化到 CI/CD、战略、云采用、操作和可观察性等方面。识别这些反模式并不总是容易的,尤其是当我们已经使用它们一段时间后。内化反模式后,就该开始定义我们想要达到的目标,并识别当前状态与目标状态之间的差距。
定义最佳结果并识别差距
一旦我们识别出在云原生采纳过程中遇到的痛点,我们必须找出根本原因。在整本书中,我们深入研究了这些原因,并对可能的问题领域有了很好的了解,例如文化方面、缺乏战略或运营卓越等。到目前为止,我们也知道一些修复措施可能需要重大努力。通常,存在依赖关系,这意味着我们需要先解决其他问题,才能处理我们希望解决的问题。例如,如果我们想改进 CI/CD 管道以建立更好的安全性姿态并加快上市时间,我们可能首先需要建立成熟的 DevSecOps 文化。在本章中,我们将频繁使用“当前状态”、“目标状态”和“差距”这几个术语。我们的定义与 TOGAF 有所偏离,更加贴合云原生的背景。
定义 – 当前状态、目标状态和差距
当前状态是我们目前的情况。它可以指我们的当前架构、工作方式、运营模式、安全性或合规性姿态。一些架构框架假设这是已经正式批准的规范,但根据我们的经验,这不一定反映现实。
目标状态是我们所追求的情况或架构的描述。由于我们处理的是项目管理三角形中描述的约束,它不一定与所有最佳实践完全一致。
差距是“两个状态之间差异的陈述。它用于差距分析的背景,其中识别了当前状态与目标状态之间的差异。” [来源:TOGAF – www.opengroup.org/togaf]。
现在我们将探讨我们的当前状态,以及目标状态应该是什么样子。
定义当前状态
我们希望建立一个关于我们应处理的所有事务的整体视图,以便在合理利用时间和预算的同时,获得全貌。这并不意味着我们可以处理所有事务,因为我们将面临约束,因此我们必须做出权衡决策。约束条件在下面的项目管理三角形图中有所展示。

图 14.1 – 项目管理三角形(来源:en.wikipedia.org/wiki/Project_management_triangle)
三角形代表了影响项目成功的关键因素:范围、时间和成本。它表明,一个约束的变化将会影响其他约束。例如,增加项目的范围可能会需要更多的时间和资金。我们必须平衡这些约束,以在保持质量的同时实现项目目标。这个三角形强调了同时优化这三个方面的挑战,这也就需要做出权衡。这些步骤将帮助我们阐明整体视图:
-
定义 重点领域:
研究每一个我们能够快速解决的问题,最终会变得让人不知所措。因此,我们需要选择一些重点领域来开始。这将有助于我们在后续阶段限制范围,以应对成本和时间的约束。内部和外部因素可以驱动我们重点领域的优先级。内部因素的例子包括不可靠的环境或不成熟的 DevSecOps 实践。外部因素可能是我们必须应对的新法规框架,或是最近的数据泄露。根据驱动因素的严重程度,我们需要选择我们的重点领域。我们可能还需要在战略提升和快速见效之间找到平衡,以此获得动力。
-
评估 现有文档:
我们将拥有能够帮助我们更清晰了解当前状态的文档。理论上这听起来很不错,但实际上,文档往往不完整或过时。过时的文档可能具有误导性,因为它不能反映实际的当前状态。因此,验证文档的准确性与关键利益相关者一起将是一个很好的做法,这也将引导我们进入下一步。假设我们很难找到相应的文档,因为它们分散在 Google Drive 和多个 Confluence 空间中,包括个人空间。那么,我们可能会将文档标准化纳入我们的目标状态。
-
识别利益相关者:
我们需要从各个业务单元中识别我们的利益相关者,例如客户互动、战略、运营、安全、开发和测试等。利益相关者是主题专家(SMEs)。产品或服务负责人会知道应用程序的功能及其所需的增强,以便在市场上更具竞争力。参与运营的人能够告诉我们运营中的不足之处,例如不稳定的运行时、缺乏补丁或可观察性,这使得事件管理变得具有挑战性。利益相关者矩阵有不同的变体,其中一些展示了利益相关者的权力和兴趣。至少,我们希望创建一个清单,展示业务单元、职位功能和代表的姓名。
-
规划 我们的研讨会:
与已识别的利益相关者开展研讨会将帮助我们提供有关问题领域的更多细节。此时,我们要考虑到利益相关者宝贵的时间。我们没有资金来推动我们的变革计划,而利益相关者必须完成他们的工作。因此,我们需要在谁需要参与什么对话上保持谨慎。最好有一个简短的启动会议,这样每个人都能听到关于我们想要实现的目标的相同信息。假设我们想要提高网络可靠性。那么,我们必须让网络、安全和云平台的主题专家参与其中。我们可以组织两场 1.5 小时的研讨会,第一场将探讨当前状态:
-
当前状态 发现研讨会:
第一个研讨会将捕获当前状态及其所面临的所有挑战。我们需要确保创建一个安全的环境,让每个人都能提出自己的观点和问题。我们还应该带上相关的文档,因为这将帮助我们开始讨论。记录以往的事件非常有助于洞察问题所在。
例如,在之前的一个事件中,由于我们的主动-被动拓扑无法工作,我们无法进行故障转移,或者我们无法进行故障排除,因为日志记录没有捕获我们所需的所有信息。理想情况下,这是一个高度互动的环节,结果可能是高层次的网络和数据流图、当前的响应服务水平协议(SLA)和吞吐量要求。我们还希望涵盖领域专家提出的任何修复建议。我们必须记录所有信息并详细记笔记。此外,在每个人同意后,我们还应录制会议,以便在后续分析发现时查阅细节。
我们现在已经收集了关于当前状态的所有信息。我们现在可以分析这些发现,并准备目标状态提案,这将是我们接下来要讨论的内容。
定义目标状态
拥有一个全面且经过验证的当前状态图像以及所有痛点将帮助我们明确目标状态和差距。这是我们如何开始的:
-
目标状态草案:
在当前状态发现研讨会后,我们需要分析我们的发现。我们记录了很好的会议笔记。对于每个发现,我们应该记录问题陈述、影响、差距、修复步骤或选项、业务收益和优先推荐。
修复选项是简短的陈述,说明可以采取哪些措施来弥合差距,并将我们从当前状态带到目标状态。如果我们识别出依赖关系,需要明确指出。在此阶段,我们只需要高层次的陈述。根据我们在研讨会期间覆盖的领域数量,我们可能会在多个问题领域中发现问题。如果是这种情况,将这些发现进行分组是值得的。这样,我们可以更好地结构化后续的研讨会,这将有助于我们后续定义工作包。
-
目标状态 发现研讨会:
我们需要为这个研讨会准备一份简短而精炼的视觉展示。可以是电子表格、幻灯片或在绘图软件中(如 Lucidchart 或 Miro)制作的图表。
例如,可以使用电子表格记录事实,并结合图表来展示解决方案建议。保持研讨会的结构化非常重要,收集每个人的反馈,并根据需要提供澄清。在研讨会结束时,我们应该验证我们的提案。这包括识别的差距以及对提出的解决方案和优先事项达成一致。由于工作量估算是我们的下一步,因此我们必须为每个修复分配合适的 SME。到目前为止,应该很明显谁是每个修复的合适 SME。必须提醒 SME 两件事:
-
首先,不要假设他们不一定是执行更改的个人。如果这个人是最有经验的,估算的时间会相对较短,但他们可能无法执行更改。
-
第二个重点考虑了组织的复杂性,尤其是对于受监管行业。现在我们已为每个修复分配了两个估算人员,我们准备开始活动了。
-
-
任务列描述了所需的操作,后面跟着说明注释列。我们可能希望将操作与我们所涉及的收益或风险类别对齐,这是我们在下一个列中所做的。剩下的四列记录了第一轮工作量估算(EE-1)和第一轮信心度(CL-1),然后是第二位 SME 的相同估算。
| ID | 任务 | 备注 | 收益 | 风险 | EE-1 | CL-1 | EE-2 | CL-2 |
|---|---|---|---|---|---|---|---|---|
| S-01 | 移除测试、UAT 和生产环境的人为访问 | 更新 IAM 角色和/或服务控制策略 | 提升安全性和合规性,推动自动化最佳实践 | CI/CD 知识差距可能会延迟开发者,CI/CD 流水线需要为遗留应用创建,可能需要培训 | 7 | 80% | 5 | 90% |
| S-02 | 强制启用静态加密 | 更新服务控制策略 | 提升安全性和合规性 | 对某些加密密钥的额外成本,延迟开销 | 15 | 90% | 12 | 80% |
| S-03 | 为第三方集成启用数据包检查 | 在所有账户中部署网络防火墙并更新路由 | 提升安全性 | 增加新的监控和警报范围,增加新功能的成本 | 120 | 60% | 100 | 50% |
| T-01 | 启用自助式 DNS 创建 | 为业务单元启用子域创建 | 改进用户体验和市场反应时间 | 除非建立保护措施,否则 DNS 记录可能与内部标准不一致 | 20 | 80% | 15 | 60% |
表 14.1 – 修复行动和工作量估算
-
确定时间估算:
接下来,我们将每个修复项的两个单独努力估算值取平均值。然后,我们会查看置信度水平。根据置信度水平,我们将向平均时间估算中添加适当的应急百分比。对于高置信度水平(超过 90%),我们将添加 5%;对于低置信度水平(50%),我们可以添加 25%,置信度越低,添加的百分比就越高。当然,这些数字是可以调整的;最重要的是保持一致性。我们可以按项目逐项估算应急,或者按整体百分比估算。
-
准备好 商业案例:
作为下一步,我们需要与之前两个工作坊中参与的主题专家(SMEs)验证努力估算。主题专家不会质疑自己的努力估算,但如果我们能将每个人带入整体图景,这将有助于增强他们的认同感。这是一个极好的机会,展示我们作为团队共同努力的成果。我们知道,对于个人来说,变革是具有挑战性的,特别是当它影响工作方式并需要采用新技能或放弃职责时。这是一个感谢每个人的奉献、投入和开放心态的好时机,感谢他们帮助我们将组织提升到更好的状态。
现在,我们已经对当前状态、目标状态、差距以及弥补这些差距所需的修复措施有了清晰的认识。我们还为修复措施分配了优先级,并按问题领域将它们分组。我们处于一个知识丰富的位置。 “知识就是力量”是一个众所周知的名言,在这种情况下,它使我们处于一个坚实的位置,可以启动一个能够改善我们组织的商业案例。让我们现在深入探讨。
定义最佳结果并识别差距
到目前为止,我们已经创建了一个坚实的框架,帮助我们阐明我们想要提议的倡议的高层设计、收益和粗略的努力估算。但在我们可以启动商业案例并使其具备信心以获得批准之前,还有几个步骤需要完成。我们还需要为不同的目标群体提供不同的视角,更重要的是,我们需要补充更多有关商业收益的细节。在本章的最后部分,我们将重点关注以下几个领域:
-
在整个组织中传播我们的计划倡议
-
进入更详细的层次
-
创建工作分解结构
-
制作商业案例文档
-
在组织中进行导航以获取支持
对于这些领域中的每一项,我们将解释它为何至关重要,以及我们必须考虑哪些因素,以确保顺利开始我们的最佳实践之旅。让我们从吸引更广泛的团队开始。
与更广泛的团队分享高层次的计划
我们知道人类对变化有抗拒心理。因此,我们需要尽早提供可见性,并让他们了解我们想要达成的目标。这样,其他人可以更长时间地思考可能影响他们的变化。这为他们提供了更多的思考时间,他们甚至可能提供有价值的反馈,从而导致更好的结果。不断与更广泛的群体互动还将帮助我们赢得信任。我们不仅需要这一信任来获得商业案例的批准,还需要它来推动实施。当别人相信我们的行动时,他们会准备好提供帮助。这些是我们在此阶段需要采取的行动:
| 1 | 持续与核心利益相关者的互动: |
|---|---|
-
保持与我们之前两次工作坊中涉及的利益相关者的持续对话,以便与不断变化的需求保持一致。
-
使用现有的节奏会议来进行更新,或者根据利益相关者的个性安排定期的一对一会议。有些人在群体面前不愿表达关切。
-
我们需要解决所有的洞察,以将我们的提案转化为成功。
|
| 2 | 确定更广泛的利益相关者群体: |
|---|---|
-
使用现有的治理论坛来支持新的提案。
-
例如,架构工作组、工程工作组、架构审查委员会、变更批准委员会、技术审查委员会和战略治理论坛等。
-
大型组织通常有层级结构。例如,架构适配可能需要先经过一个论坛的批准,才能由另一个论坛支持其成本和风险。
|
| 3 | 与更广泛的利益相关者群体互动: |
|---|---|
-
我们希望首先将我们的提案提交给所需的论坛,并且需要确保它们拥有适当的目标群体代表。
-
治理结构因公司而异。
-
如果我们是新加入某个组织,我们需要有人帮助我们导航治理流程,例如我们的经理或同事。
-
当我们展示我们的提案时,我们需要关注两个方面:
-
并非每个人都具备我们长期关注的领域的深度知识。因此,我们必须调整语言,并考虑目标群体,使用可视化工具,如架构图。
-
我们必须关注肢体语言的语气,并积极倾听反馈。观察房间的动态将帮助我们识别关切,并与个别利益相关者安排后续跟进。
-
|
表 14.2 – 社交化高层计划
我们刚刚探讨的活动将帮助我们进入下一个更详细的层次,接下来我们将讨论这一点。
添加组织特定的细节
我们希望进入下一个更详细的层次,并将从多个角度来解决这个问题。我们将从影响成本和时间表的内部因素开始。我们需要多详细将取决于组织的性质,接下来我们将讨论这一点:
-
合适的详细程度:
启动新项目对于刚获得种子资金的初创公司通常更容易。对于受监管行业和政府组织,我们必须证明一个强有力的尽职调查过程,概述其优缺点,并提供一个中立的供应商选择过程。
后者可能需要询价请求(RFQ)或提案请求(RFP),采购部门可以提供模板和指南。如果多个业务单元争夺预算,我们必须做好准备。这包括良好的视觉效果、支持我们提案的可靠数据、实际的实施估算、持续的许可证费用以及其他运营费用。所需的详细程度将根据组织的具体情况而有所不同,我们需要将其纳入我们创建的文档中。
-
创建新视图:
我们必须为不同的利益相关者创建不同的视图,例如架构视图、流程流或 RACI 矩阵。我们将为企业架构师提供高层次的视图,并描述好处、机会、风险、可靠性等内容。我们还需要为网络团队提供详细的网络图,说明数据流动和网络路由。
安全团队将希望看到我们实施的安全控制措施,例如流量检查、网络访问控制列表、DDoS 防护、密钥管理等。风险团队可能需要一个风险矩阵。根据我们之前讨论的组织背景,清单将会变得更长。
-
识别技能差距:
由于我们已经进行了更详细的工作量估算,现在对所需技能有了更清晰的了解。如果存在技能差距,我们需要在成本和时间估算中解决这些差距。提升技能通常是通过多种渠道进行的。这些渠道可以是课堂课程,只要团队成员不频繁查看电子邮件、Slack 或 Teams 频道,就能减少他们被临时请求分散注意力的可能性。
课堂课程提供更多灵活性,因为它们可以随时随地进行。除了课程外,我们还应使用团队扩展的方法。通过这种方式,我们引入来自咨询公司的专家,与我们的团队一起完成工作。但最重要的是,我们必须确保知识传递到我们的团队。我们需要在时间估算中考虑这一点。我们会记录所有与培训相关的费用,因为这些费用对我们的商业案例至关重要。
-
识别文化和变革管理差距:
如果我们的提案涉及文化转型,我们需要解决这个问题。我们可能需要雇佣一名变革经理,并与人力资源(HR)部门进行对话,更新职位描述。
我们还需要考虑在过渡阶段生产力较低的问题,这段时间我们的团队需要适应新的工作方式,并投入时间进行培训。改变组织文化所需的时间通常被低估。在此阶段,与人力资源部门进行对话将非常有帮助。如果公司内有变更经理,他们可以提供高层次的估算。人力资源和变更管理部门可以提供更多有关组织特定活动的见解,以及我们需要在路线图中考虑的通知期。
-
运营模式:
我们当前的运营模式是否支持新计划的各个方面?我们是否引入了任何新的组件或第三方解决方案?如果有新的供应商需要我们引入,谁将负责此事?谁将管理许可证并监控许可证的使用限制?是否需要新的维护活动,例如打补丁或创建需要频繁推出的新容器镜像?如果存在空白,我们需要定义谁对这些空白负责,谁是相关责任人,谁需要被告知或咨询。如果我们已有 RACI 矩阵,可以将这些新活动添加进去。如果没有,我们应当开始创建一个,并邀请相关方参与,以完善当前的运营模式。
既然我们已经探讨了组织背景及其综合影响,我们可以继续讨论外部因素和技术影响。
处理外部因素和技术影响
外部因素将取决于我们所处的行业、市场、技能市场和经济周期。架构变化或规模增加将推动技术影响,我们将首先研究这一类别:
-
架构和规模 增加影响:
当我们修改架构时,需要考虑是否需要扩大任何下游系统。如果我们扩展到多区域部署,我们的应用将生成更多日志,如审计日志。我们需要处理这些日志,可能会涉及许可证问题,或者我们可能需要升级存储。日志的成本通常被低估,因此值得调查当前的日志量。多区域部署还会产生跨区域的数据传输费用,这需要我们加以考虑。我们还将需要更多的 TLS 证书。如果我们从第三方获取证书,费用将会增加。如果我们的新解决方案成功,它可能会导致流量增加,我们的基础设施需要进一步扩展。这将导致数据传输费用增加以及我们基础设施资源的额外成本,这些我们在第四章中有讨论。
-
现有技术债务和 战略提升:
总是存在技术债务,它会拖慢我们的进度。作为新计划的一部分,我们需要考虑可以修复哪些问题以实现更好的结果。我们需要考虑我们 CI/CD 环境中的空白。我们是否已实现代码扫描和自动化测试?我们是否为我们的 CI/CD 工具链和云平台设置了所有的保护措施?我们的Landing Zone是否需要改进,因为它在安全性或合规性隔离方面考虑得不够?这些空白会阻碍我们前进,它们要么会拖慢交付进度,要么会增加整体风险。因此,我们应该修复这些问题,正如我们在第四章中讨论的那样,我们还需要对本地应用程序进行重新架构,以便进行云迁移,关于这一点我们在第十二章中进行了探讨。
-
监管考量:
如果我们的新解决方案需要满足监管要求,我们需要确保将其纳入复杂性、交付时间表和所涉及的工作量中。我们必须实施所需的控制措施并进行验证。我们还必须考虑由于监管要求所带来的审计工作量。像 PCI 这样的合规框架要求对最小权限执行、数据保护、加密、防火墙规则、关键事件日志记录、访问日志记录、漏洞扫描等进行彻底的证据收集。这个工作将需要几个月的时间,我们必须为这些审计分配资源。我们在第三章中讨论了监管要求。
-
市场变化和 技术趋势:
市场趋势的变化可能会影响我们的解决方案思路。消费者网站提供更多的照片,有时还有产品的 3D 渲染图和视频,我们需要考虑这些变化,以保持竞争力。技术也在不断变化。越来越多的服务产品变得商品化,FaaS 和无服务器存储解决方案就是其中的例子。我们希望确保利用这些商品化服务,以减少我们的操作工作量。我们在第二章中讨论了 Wardley Mapping。
-
技术 和合作伙伴关系:
新的技术趋势和标准也需要考虑。如果一个新标准,例如 OpenTelemetry,有助于减少供应商锁定,我们应该考虑它并评估其影响。如果我们正在选择新的软件,例如部署工具,那么我们应该评估生态系统,例如我们所在地区的用户组和合作伙伴,并看看如果我们建立良好的合作伙伴关系是否能够获得免费的培训。我们在第二章中详细讨论了这一点。
-
其他 外部因素:
其他因素包括法律和合同方面的考虑。我们将审查相关的服务水平协议(SLA),包括恢复时间目标(RTO)和恢复点目标(RPO),并确保我们的架构和流程与之对齐。地缘政治因素,如贸易限制和地区政治稳定性,可能会影响我们计划的成功,尤其是当我们在全球范围内运营时。我们在第九章讨论了与网络相关的方面,在第八章讨论了 RPO 和 RTO。
在这个阶段,我们对我们的组织背景以及需要考虑的内部和外部因素有了清晰的理解。凭借这些知识,我们已经准备好重新审视我们的工作量估算,并构建我们的路线图。
构建路线图并保持利益相关者的知情
在这个阶段,我们将参考敏捷术语,这些术语将用于构建我们的路线图。为此,请使用敏捷联盟的定义(www.agilealliance.org/agile101/agile-glossary/)。
定义 – 敏捷术语
史诗:史诗是一个大型用户故事,无法在单个迭代内完成,或其规模足够大,可以拆分成更小的用户故事。
用户故事:在与客户或产品负责人协商后,团队将要完成的工作分解为称为“用户故事”的功能增量。
产品待办事项:产品待办事项是一个列出新特性、现有特性的变更、错误修复、基础设施变更或其他活动的列表,这些是团队为实现特定目标而可能交付的。
产品负责人:产品负责人是产品开发团队中的一个角色,负责管理产品待办事项,以实现产品开发团队希望完成的目标。
上述术语经常使用,但由于存在不同的敏捷交付框架,我们在使用这些术语时指的是相同的内容。
我们之前做出了一个高层次的工作量估算。在评估了内部和外部因素之后,是时候验证这些估算并推进到下一个更详细的层次:
-
评估之前的 工作量估算:
根据获得的见解,我们必须验证之前捕捉到的工作量估算是否涵盖了所有必要的活动。如果有遗漏的步骤,我们需要将其添加进去。最好保留初步估算的版本,以便以后进行比较。我们可以请提供初步估算的相同领域专家重新验证工作量估算。我们可以通过一个会议开始这次重新验证,会上我们会提供所有相关背景。这将是对该计划的简短回顾,包括以前的估算和自最初工作量估算以来的新发现。我们将需要花一些时间讨论这些发现,因为任何新的内部或外部发现都可能影响工作量估算。团队随后可以返回初步估算并将其补充完整。现在是时候在初步时间估算中添加一列,记录应该执行某项任务的职位职能。这将帮助我们验证是否具备所有必要的技能和资源。最终结果将是更新后的时间估算和新增的责任。
-
创建 待办事项列表:
基于更新后的时间估算,我们将创建一个待办事项列表。理想情况下,这可以在敏捷管理解决方案中完成,如 Jira 或 Wrike。如果我们没有许可证,我们可以使用如 Trello 之类的免费层级工具,但我们需要确保我们的组织认可该软件,以避免出现影子 IT。商业解决方案具有有用的规划功能,例如管理任务之间的依赖关系、创建总体史诗、将故事映射到史诗中,并将其分组到冲刺中。一旦这个结构创建完成,我们就可以生成一个路线图。
以下截图展示了 Atlassian 公司在 Jira 中的路线图示例。Jira 使用issues而不是stories,使用timeline而不是roadmap,但概念是相同的,正如我们所见:

图 14.2 – Jira 中的路线图(来源:https://www.atlassian.com/software/jira/guides/basic-roadmaps/tutorials#filter-and-view-settings)
-
保持 利益相关者的参与:
在我们进行规划活动的同时,必须保持利益相关者的知情。我们之前已经提供了可见性,并在架构和工程论坛上做了展示。我们获得了新的见解,范围或方法可能已经发生了变化,自我们最初的高层次提案以来。现在我们可以再次向这些论坛展示,并提供更多细节。保持每个人的知情将减少抵触情绪,因为大家都已经被纳入讨论,并有机会提出关切。
到目前为止,我们已经收集了许多数据点,并保持了与利益相关者的沟通。我们有许多输入可以在商业案例中重复使用,接下来我们可以开始记录这些输入。
商业案例文档
我们需要了解目标受众,以确保文档使用正确的术语。CSP 特定的术语,如 Lambda、Apigee 或 Azure Blob Storage,可能对需要批准商业案例的利益相关者没有意义。因此,我们应避免使用技术术语,如果必须使用技术术语,则需要解释它们及其带来的好处。如果我们为一个较大的组织工作,我们可能会有一个可供使用的商业案例模板。
通常,战略和架构团队会维护此部分。如果我们没有模板,也没关系,因为我们将使用一种可以采用的结构:
| # | 章节标题 & 描述 |
|---|---|
| 1 | 执行摘要 |
| 本节将简要概述云转型计划。到目前为止,我们已经制作了不同的视图,我们可以在本节中利用其中一个高层次的视图。我们需要解释战略目标和预期的商业成果。我们还将记录一个高层次的成本摘要、收益以及我们之前制作的路线图的高层次视图。 | |
| 2 | 商业驱动因素与战略对齐 |
| 在这里,我们可以描述当前的业务和技术挑战。我们将指出痛点和现有的低效之处。我们还可以参考与我们组织相关的市场、行业和技术趋势。我们需要概述我们的计划如何与公司战略对齐,以及我们的解决方案如何帮助获得竞争优势,例如更快的产品发布周期。 | |
| 3 | 愿景与目标 |
| 在本节中,我们将描述我们云计划的长期愿景,并捕捉关键目标和指标,如 KPI 和成功标准。例子包括提升市场上市时间、提高安全性或合规性以降低整体风险,或者提升韧性,减少停机次数。 | |
| 4 | 当前状态 |
| 我们将在此处提供当前挑战的概述,包括基础设施、应用程序、数据、挑战和限制,包括技术债务、性能、可扩展性和安全性挑战。我们必须解决所有差距领域,包括技能、资源、文化、运营、治理、安全、合规性、变更管理、CI/CD、缺乏护栏以及技术债务,这些应在之前的工作坊中已有记录。 | |
| 5 | 目标状态 |
| 本节将描述提议的计划。我们将涵盖与当前状态相同的领域,并指出目标状态与之的不同之处。如果我们保持与前一节相同的结构,利益相关者将更容易看到差异。工作坊文档应该提供我们在此处所需的所有输入。 | |
| 6 | 财务分析 |
| 在这里,我们将提供成本明细,展示初始投资、迁移成本和运营费用。我们还将涵盖所需的额外人员或外部顾问。如果我们从本地部署迁移到云端,将会从资本支出(CapEx)转向运营支出(OpEx)。我们计划这个倡议是因为我们的组织将从中受益,我们需要在投资回报率(ROI)计算中展示这一点。我们将说明预期的 ROI、回报周期和长期节省。收益包括减少运营工作量、加快新解决方案交付速度和减少服务水平协议(SLA)违约,从而减少罚款支付。除非我们已经 100%使用云端,否则我们将解释云定价模式(例如按需付费)和承诺支出计划。 | |
| 7 | 价值主张与收益 |
| 在这里,我们将描述定量的收益,例如成本节约和提高的业务敏捷性,并概述定性的收益,如提升的创新能力、客户满意度、员工体验和竞争优势。 | |
| 8 | 风险评估与缓解 |
| 本节在受监管行业中尤其重要。我们将描述涉及运营、技术、交付和财务义务的关键风险。我们还将概述风险缓解策略和应急计划,例如分阶段部署、小规模变更增量、员工技能提升、实施保护措施、管理超支等。 | |
| 9 | 实施计划 |
| 在这里,我们将提供之前制作的路线图。我们需要概述关键的里程碑、阶段和时间表。本节还将包括一份资源计划,显示内部团队、顾问和来自我们云服务提供商(CSP)的专家。我们还将描述我们的利益相关者,包括变更管理和治理。此信息将在即将进行的利益相关者对话中使用,包括共享业务案例文档。 | |
| 10 | 组织影响 |
| 在本节中,我们将描述技能和劳动力转型,包括培训、招聘和技能提升的需求。我们还将描述流程变化,例如从手动测试转向自动化测试,以及文化方面的内容,例如建立 DevSecOps 文化并向跨职能团队方法转型。 | |
| 11 | 合作伙伴与供应商策略 |
| 如果我们购买新的 SaaS 解决方案,我们将概述它如何与我们当前的生态系统集成,并描述我们的合作伙伴策略。SaaS 供应商是否能够指定关键客户经理和专家?他们是否能够提供针对我们组织的定制培训? | |
| 12 | 合规性、安全性和法律考虑 |
| 在这里,我们将描述第三方是否满足所有合规要求,如 SOC-2、HIPAA 或 PCI。我们还需要描述供应商是否符合数据保护和隐私要求。我们还将描述服务水平协议(SLA),包括可用性和性能 SLA,供应商是否能够提供这些信息。 | |
| 13 | 摘要与建议 |
| 在本节中,我们将总结主要发现和结论,提出最终建议,并概述所需的行动。此节概述了文档内容。有些利益相关者只会阅读文档的第一部分、最后一部分,以及他们直接相关的部分,如法律部分或财务分析部分。因此,我们需要在文档的第一部分和最后一部分使用清晰的商业语言。 |
表 14.3 – 商业案例文档
文档必须由各个团队成员和参与研讨会的利益相关者进行评审。如果时间有限,我们可以在利益相关者之间分配评审任务。如果我们犯了明显的错误,例如财务计算错误,我们将失去可信度,而我们要尽力避免这种情况。
我们需要为文档找到正确的平衡,以便提供足够的信息传达必要的内容,而不会进入不必要的细节,导致难以阅读。文档评审将有助于找到这一平衡。在编写文档的过程中,我们会继续与更广泛的利益相关者群体进行互动,并沟通下一步的时间安排,我们将在接下来讨论。
下一步与其他考虑事项
我们正在接近商业案例过程的尾声。唯一缺少的“微小”环节就是在转向最佳实践之前获得批准。那么,如何实现这一最后一步,这对启动实施至关重要且必要呢?让我们来看看我们需要考虑的一些方面以及需要采取的行动:
-
完美的时机来 申请预算:
是否有一个完美的时机来申请预算?大型组织有财务周期,预算申请必须在新财年开始前的几个月提交。对于这一请求,我们不需要最终确认和批准的商业案例,但至少需要高层次的利益。大多数时候,云架构师可以通过与关键利益相关者或供应商联系,获取一些成本信息。如果我们刚刚经历了一个事件,比如数据泄露,获取安全提升的资金将不成问题,甚至可以超出财务周期,除非泄露事件让我们无法继续运营。
-
完美的时机来提出 商业案例:
商业案例是否有完美的时机?如果我们之前已经请求了预算,我们必须确保商业案例的批准时间与我们计划的实施启动时间一致。我们需要考虑到一些未计划的延迟,例如利益相关者无法参与或紧急项目优先,导致我们在下次治理会议中无法立即安排展示。有些公司会进行季度或半年一次的优先级评估。如果是这种情况,那么准备好商业案例将非常有帮助,特别是我们能提出有力的观点,让组织处于更好的状态。关于是否存在完美时机的问题,简短的回答是取决于情况,但最好的做法是做好准备,并与利益相关者保持良好的联系。
-
审批流程:
审批流程非常依赖于组织的具体情况。如果我们之前没有提出过商业案例,并且对流程不完全了解,我们需要与经理或曾经做过此事的同事联系。他们可以提供一些指导,并引导我们找到负责治理论坛并批准商业案例的人员。我们必须询问他们需要注意哪些事项,以及获得批准的关键领域。可能是安全、合规性或采购,这取决于行业和组织。我们还需要准备一个总结我们商业案例的展示,接下来我们将讨论这个问题。
-
展示:
我们需要一个展示,使用合适的工具为治理论坛中的利益相关者提供支持我们的解决方案。根据组织的规模,我们可能需要在多个论坛上获得批准。例如,一个论坛会挑战所有架构和工程方面的问题。一旦我们获得支持,就可以在一个挑战风险并提供组织效益的论坛上展示。在这种情况下,我们需要准备两场展示:一场技术性展示和一场专注于业务和风险的展示。我们花在准备这些展示上的时间,和我们花在实际商业文件上的时间一样宝贵。展示就像是我们认为将成为成功故事的产品的销售宣传册。
在这一点上,我们祝你在展示中好运,并总结本章的关键要点。
摘要
我们首先探讨了如何识别反模式以及我们需要留意的迹象。这包括了一般性指标和具体的关注领域,如文化、自动化、战略、运营、可观察性和技术。接着,我们开始定义当前状态和目标状态,并探讨了我们需要弥补的差距,以及保持利益相关者参与的重要性。我们还探讨了如何加入组织背景,考虑可能影响我们解决方案的内部和外部因素。我们探索了如何制定路线图、商业案例文档,以及支持我们商业案例的演示文稿,同时保持利益相关者的参与。到目前为止,我们应该已经得到了认可的商业案例,并准备开始我们的转型,接下来我们将在最后一章中讨论这一过程。
第十五章:向云原生良好习惯过渡
向云原生架构过渡不仅仅是一个技术任务;它是一个战略转型,涉及到组织的各个方面。它包括从传统思维方式和流程转变为优先考虑敏捷性、韧性和创新的现代方法。本章不仅仅讨论云采用的技术步骤,还深入探讨了使转型成功的关键要素:对齐利益相关者、定义战略性和灵活的路线图,以及建立持续改进的文化。这不仅仅是利用最新的技术;它是将这些技术整合到一个支持并为未来目标做准备的整体战略中。
在我们应对这一转型过程中,我们必须确保每一部分都无缝衔接,从利益相关者参与到执行。我们将探讨如何争取支持,并将团队凝聚在一个共同的愿景下,将认同转化为动力。本章旨在作为制定详细而灵活的路线图的指南,帮助我们精准且有目的地推动组织向前发展。最后,我们将强调建立反馈循环并培育持续改进文化的重要性,确保组织不仅适应变化,而且在不断发展的云环境中蓬勃发展。以下是本章将涵盖的内容:
-
利益相关者对齐
-
你的路线图
-
持续改进
让我们从探索利益相关者对齐这一关键步骤开始,这是成功云原生转型的基础。
利益相关者对齐
在我们在第十四章中建立的利益相关者对齐基础上,向云原生组织过渡不仅仅是技术上的变革;它还需要改变人们和团队如何合作、做决策,并与整体愿景对齐。在这一部分,我们将探讨利益相关者对齐的关键方面,强调吸引正确人员、管理依赖关系,以及确保团队为成功而构建的重要性。本节基于第二章的见解,战略化你的云原生转型,专注于有效对齐利益相关者的实用策略。
利益相关者管理考虑事项
成功的云原生转型依赖于有效的利益相关者管理。如果没有这一点,偏离目标、冲突和失败的项目将是可能的结果。为了应对这些挑战,理解各个利益相关者群体的需求和期望,并据此进行管理是至关重要的。
| 利益相关者群体 | 考虑事项 |
|---|---|
| 高层领导 | 如第十四章所讨论,提前参与以确保获得赞助和资源。展示投资回报和战略优势。 |
| 技术团队 | 包括架构师、开发人员和 SRE,确保技术决策和实施得到认可。 |
| 运维和安全 | 整合运维和安全团队,与 DevSecOps 实践保持一致,促进协作。 |
| 商业利益相关者 | 确保商业领导者理解云原生解决方案如何与目标和指标保持一致。这不仅仅涉及高级领导层,还涵盖了变革管理和人力资源领域,以应对文化变革。 |
表 15.1 - 利益相关者及考虑事项
建立一致的沟通对于成功的利益相关者参与至关重要。通过各种渠道定期更新信息,如会议、新闻通讯、仪表盘或项目管理工具,确保利益相关者在整个转型过程中保持知情和参与。透明的云原生计划进展、挑战和成就的洞察促进了信任,并创造了共享所有权的感觉,使利益相关者感到他们是这一过程的核心。通过建立这种参与度,我们鼓励一种协作氛围,利益相关者提供有价值的见解和反馈,这对于完善策略和克服障碍至关重要。
此外,互动式研讨会和培训课程对于构建对云原生原则的共同理解至关重要,特别是对于那些可能对其中的复杂性不太了解的非技术相关方。这些课程旨在解开云原生概念的神秘面纱,例如微服务、容器化和 CI/CD,同时以实际的商业价值为例,如在第七章中所述,将您的商业目标表达为应用程序代码。研讨会还专注于围绕共同目标使不同部门保持一致,推动早期的跨职能协作。进一步支持这种一致性需要通过 RACI 框架(即 责任人、被问责人、咨询人、知情人)明确角色和职责,通过明确责任和决策权来管理期望。提前建立这些边界有助于减少模糊性,增强协调性,确保努力朝着统一目标有序推进,并建立坚实的信任基础。清晰的沟通和相互理解的基础为下一步奠定了基础:确定合适的人选来推动转型。
确定所需人员
构建一个有效的云原生团队不仅仅是填补角色;它需要组建具备必要技能、思维方式和协作精神的个人,以应对转型过程中的复杂性。这个过程包括创建一个技术专家、战略思考者和跨职能合作者的平衡,他们能够无缝地合作。每个角色都应由具备技术专长且能够随着组织的发展不断学习和成长的人员担任,以下是一些例子:
-
云架构师和平台工程师:对于设计和管理符合业务需求的云原生架构至关重要,正如在第七章中讨论的那样。
-
安全工程师:在整个生命周期中嵌入安全措施,发挥着至关重要的作用,正如在第五章中强调的那样。
-
产品负责人和商业分析师:确保实施与业务目标一致并交付可衡量的成果,详细内容见第三章**.。
理解这些具体技能和职责对于组建一个能够应对转型挑战的团队至关重要。以下是云原生旅程中所需的关键角色和组织所需的技能:
| 角色 | 描述 | 关键技能 |
|---|---|---|
| 云架构师 | 设计云架构并确保其符合云原生最佳实践 | 解决方案设计、云平台和自动化 |
| 平台工程师 | 管理云基础设施,专注于自动化和基础设施即代码 (laC) 实践 | laC(Terraform、CloudFormation/CDK、ARM/Bicep)、自动化和脚本编写 |
| 开发人员/SRE | 构建、部署和维护云原生应用程序,重点关注可扩展性和可靠性 | CI/CD、容器化和微服务 |
| 安全工程师 | 实施持续的安全控制并监控云原生环境中的威胁和漏洞 | DevSecOps、自动化和威胁检测 |
| 产品负责人 | 确保技术实施与业务目标一致,弥合差距 | 商业分析和利益相关者管理 |
表 15.2 - 云原生旅程中的关键角色
一旦这些角色确立,就需要预见和管理可能在有效对齐这些利益相关者时出现的潜在挑战。
利益相关者对齐中的常见挑战
即使采用了结构化方法,云原生转型通常在与利益相关者的对齐方面面临重大挑战。这些挑战通常源于对云原生技术的熟悉程度不同、对变革的抵制或部门目标的冲突。第二章强调了将战略与业务目标对齐的重要性。在此基础上,我们探讨了在汇集利益相关者时出现的具体挑战,并提供了克服这些挑战的策略。
变革的阻力
在云原生转型中,经常面对抵制,尤其是在利益相关者对新方法不熟悉或持怀疑态度时。这些关切通常源于对现有工作流程干扰或与云原生实践相关风险的认知。为了解决这一问题,可以利用基于证据的案例研究和数据,展示诸如改善上市时间、增强敏捷性和整体业务价值等实际好处。通过将这些成功案例与组织的战略目标对齐,如第二章所强调的,我们可以减少抵制并在利益相关者中建立信心。
冲突的优先事项
通常存在冲突的优先事项,特别是在具有不同目标的部门之间。开发团队可能优先考虑快速发布,而运维团队则强调系统稳定性。这些冲突可能导致摩擦和进展缓慢。解决方案是促进合作研讨会,让利益相关者在平衡技术和业务需求的方法上达成一致。以下表格详细描述了旨在对齐这些优先事项的研讨会:
| 研讨会 | 重点 | 成果 |
|---|---|---|
| 目标与关键结果 (OKR) 对齐研讨会 | 使开发和运维团队围绕共享的目标和指标达成一致 | 一组统一的 OKR,平衡速度和稳定性,为明确可衡量的前进路径提供支持 |
| 跨职能规划会议 | 汇集开发、运维、安全和业务单位代表,规划云原生路线图 | 一个协商一致的行动计划,整合技术和业务需求,以实现更顺畅的实施 |
| 发布策略和部署研讨会 | 建立对部署实践的共识,包括蓝绿部署、持续集成/持续部署和自动化技术 | 一个能够对开发和运维实现高效、可靠和安全部署的部署策略 |
| 风险管理和稳定性研讨会 | 制定减轻与快速部署相关风险、确保运营稳定性的策略 | 一个平衡速度需求和减少中断焦点的风险缓解框架 |
| 文化整合与协作工作坊 | 解决开发与运维团队之间的文化差异,促进沟通、共享责任和协作 | 提高团队凝聚力,培养支持跨职能协作的文化,助力云原生成功 |
| 技术与业务对齐会议 | 吸引技术和业务利益相关者讨论云原生实践如何满足业务和技术需求 | 确保技术效率的平衡策略,同时为各部门提供业务价值 |
表格 15.3 - 协作工作坊
没有高层支持,云原生项目可能会因资源不足或方向不明确而停滞不前。正如在第二章中概述的那样,尽早获得高层赞助是成功的关键因素之一。强调云原生采纳的战略价值,并展示其如何与业务目标对齐,如提高可扩展性、弹性和成本效率。以高层领导易于理解的方式呈现这些优势,以确保获得必要的支持和资源。
招聘策略的角色依赖关系和影响
成功的云原生转型需要组建合适的团队,并理解角色之间的依赖关系,以确保协调一致。本节探讨了招聘策略、技能差距和团队组织对构建凝聚力和适应性结构的影响。我们从评估技能差距开始。在启动转型之前,评估团队的技能是至关重要的,以识别任何技能差距。这有助于确定是否需要提升技能或招聘。关键领域包括以下内容:
-
云架构:
-
当前评估:评估团队是否熟悉云原生架构模式(例如微服务、无服务器架构和测试自动化的 CI/CD 技能)
-
所需行动:提供培训项目和认证,如 AWS 认证解决方案架构师或 Kubernetes、无服务器等领域特定技术
-
-
安全专业知识:
-
当前评估:评估安全团队是否了解云原生安全实践(例如零信任和自动化威胁检测)
-
所需行动:招聘 DevSecOps 专家或提供针对性的培训课程,以培养内部专业知识
-
-
协作技能:
-
当前评估:审查团队在 DevOps 和平台工程模型下进行跨职能工作的准备情况
-
所需行动:实施工作坊和团队建设活动,鼓励协作行为
-
理解角色和团队之间的依赖关系对于确保云原生转型的协调和顺利进行至关重要。以下是关键的依赖关系及其对团队结构的影响:
-
跨职能协作:正如在第二章中强调的,有效的开发、运营和安全团队之间的协作至关重要。组织面向产品的小组,以减少孤岛效应并促进效率。
-
去中心化治理:去中心化治理,详见第三章,使团队能够快速、有效地做出决策,同时与目标保持一致并最小化瓶颈。
-
共享责任模型:明确云服务提供商与内部团队之间的责任,以有效管理安全、合规性和运营。有关更多信息,请参见第一章,云原生的好处和 常见误解。
对招聘和组织结构的影响
向云原生转型往往需要重新思考组织结构和招聘策略。从传统的孤岛式结构转向产品导向的模型,可以优化云原生最佳实践。
为了与云原生最佳实践保持一致,组织应摒弃传统的孤岛结构,转而采用产品导向的团队。这些团队负责产品或服务的整个生命周期,从而增强责任感和响应能力。以下是这种转变对组织结构的影响:
| 传统模型 | 产品导向模型 |
|---|---|
| 狭隘的部门划分(例如开发、运营和安全) | 跨职能团队共享产品所有权 |
| 专业技能聚焦 | 适应变化需求的通才技能 |
| 较长的决策周期 | 去中心化、更快的决策 |
表 15.4 - 模型比较
以下是产品团队的优势:
-
增强的所有权:团队负责整个生命周期,从而加快决策速度
-
与目标的一致性:与商业目标和客户成果紧密对齐
-
协作文化:促进持续学习和创新
招聘考虑因素
向产品导向、云原生环境的转型通常需要招聘新人才或培养现有员工。以下策略可以指导这一过程:
技能多样性:招聘云原生角色时,应注重多样化的技能组合。具有网络工程、安全性、数据管理和自动化背景的候选人能够提供至关重要的专业知识,增强团队的能力。
文化契合度:云原生环境强调协作、敏捷和鼓励持续学习的心态。优先考虑能够接受这些价值观的候选人,确保他们能够适应云原生实践快速变化的节奏。
平衡专家与通才:虽然通才因其适应能力和广泛的知识面而具有价值,但在安全、FinOps 和平台工程等关键领域拥有专家,确保在需要时能提供深入的专业知识。
提升技能和培训项目
当外部招聘不可行时,提升现有团队成员的技能是一种非常有效的策略。开发一个全面的培训计划,既培养技术技能,又培养软技能,是关键:
-
认证项目:提供认证路径,例如来自三大云服务提供商的认证,帮助团队成员获得必要的云原生技能。这些项目为员工提供了一种结构化的方式,帮助他们在关键领域发展专业技能。
-
内部云学院:建立内部学院,由经验丰富的云工程师指导其他团队成员,通过实践经验分享知识。这种方式促进了学习文化,并确保了组织内部的知识传递。
-
实践工作坊和实验室:组织实践工作坊和实验室,在这里团队可以在模拟的云原生场景中应用知识,构建 CI/CD 流水线或部署无服务器应用程序。这些环节巩固了学习,并提高了团队的信心和能力。
实现利益相关者的一致性是任何云原生转型的基础。组织可以通过有效地管理利益相关者、组建合适的团队、解决招聘影响和人员依赖关系来实现平稳过渡。借鉴自第二章和第七章的策略,本节提供了构建支持联盟所需的工具,确保组织各级之间的统一方法。在这些基础工作到位后,组织为云原生转型的下一阶段做好了充分准备。接下来,我们将探讨如何建立路线图以及如何应对这些挑战。
你的路线图
成功的云原生转型不是偶然发生的,它是通过精心策划和细致设计的路线图实现的。就像建筑物在开始建设前需要蓝图一样,云原生转型也需要一个详细的计划,将技术举措与战略业务目标对齐。扩展自第十四章,这份路线图是一个指南,帮助我们在复杂的变革中导航,同时确保每一步都是有目的的,并与我们组织的目标一致。
本节将概述构建一个推动我们云原生转型的实际路线图。我们将探讨成功计划的关键组成部分,包括以下内容:
-
迁移规划
-
过渡架构
-
交付举措
这些都是将战略转化为现实所必需的。到本节结束时,我们将清楚地理解如何创建一个支持并加速我们成为云原生组织的路线图。
了解迁移路径
每一次云原生转型都始于迁移计划。这个计划不仅仅是一个简单的清单,而是一个动态的策略,依据业务需求、技术要求和组织的变革意愿而不断发展。迁移计划应当明确哪些工作负载和应用将被迁移到云端,并说明如何调整这些应用以适应云原生架构。本节基于前几章的内容,强调了结构化迁移方法的重要性。
为了制定成功的迁移计划,遵循以下步骤:
-
评估并分类应用:全面评估现有的应用和系统。确定哪些最适合云原生环境,并将其分类为以下几种:
-
重托管(提升并转移):针对可以通过最小更改进行迁移的应用
-
重构/重新平台化:针对那些需要修改才能高效运行在云中的应用
-
重建:针对可能需要使用云原生技术进行重大重新开发的遗留系统
-
停用或替换:针对那些已过时或可以被 SaaS 或 PaaS 解决方案替代的应用
-
第二章对此进行了更详细的讨论。
-
定义优先级标准:并非所有应用都需要同时迁移到云端。根据业务影响、技术复杂性、监管要求和当前系统依赖性,制定一个优先级框架。那些在风险最小的情况下能提供最大价值的应用应该在迁移初期优先考虑。AWS 的云采用框架(CAF)、微软 Azure 云采用框架和谷歌自己的 CAF 都是很好的参考框架。
-
建立分阶段方法:采用分阶段的迁移策略,可以在进入下一阶段之前管理风险并从每个阶段中汲取经验,具体如下:
-
第 1 阶段:迁移非关键应用,以熟悉云原生流程
-
第 2 阶段:迁移需要中度重构的关键应用
-
第 3 阶段:处理需要大规模重构或替换的复杂遗留系统
-
通过将迁移分阶段进行,组织可以积累动力,优化流程,并系统地管理变革。这种分阶段的方法与前面章节中讨论的云原生采用的增量特性相一致,确保了灵活性和受控的风险管理。
一个可靠的迁移计划必须有过渡架构的支持,这些架构可以指导组织通过每个迁移阶段。过渡架构充当当前状态与目标云原生状态之间的中介状态,确保每个迁移阶段都得到控制和管理。这与第十七章,在应用代码中表达业务目标中强调的内容一致,即强调如何将应用程序适应云原生环境。
这些是过渡架构的关键要素:
| 元素 | 描述 |
|---|---|
| 临时状态设计 | 为每个迁移阶段制定架构蓝图,展示应用程序和系统在最终云原生状态之前的临时功能 |
| 临时服务 | 利用临时服务或混合架构(例如,混合本地和云资源)以确保过渡期间的连续性 |
| 集成点 | 在传统系统和云原生组件之间建立集成点,如 API 网关或数据同步工具,以保持一致性并最小化中断 |
表 15.5 - 过渡架构
如果我们不能通过一次发布从当前状态过渡到目标状态架构,则需要过渡架构。它们可以帮助我们在规划过程中降低风险并解决技术依赖。过渡架构应根据每个迁移阶段的具体需求量身定制。例如,在早期阶段,混合云模型可能会维持传统系统的运行,同时测试新的云原生功能。随着应用程序逐渐完全迁移到云原生,它们可以淘汰这些临时设置。
构建灵活性和敏捷性
迁移计划和过渡架构的关键方面是确保灵活性和敏捷性。云原生环境是动态的,因此路线图必须允许根据新的需求、技术和洞察进行调整。采纳以下实践来创建一个具有韧性的路线图:
-
模块化规划:将迁移任务分解为可以独立执行的模块化组件。此方法最小化了中断,并使团队能够并行工作,从而加速整体迁移进度。
-
反馈回路:建立反馈回路,让团队回顾每个迁移阶段的进展和成果。定期的回顾和绩效评估有助于改进计划,并根据经验教训调整未来的阶段。
-
自动化与编排:使用基础设施即代码(IaC)和编排工具来自动化部署和过渡。自动化关键元素可以减少手动操作、降低风险,并加速迁移活动,确保每个过渡都高效且一致。
规划迁移不仅要考虑技术方面,还必须提前考虑交付举措。
规划交付举措
就像我们在第十四章开始时所做的那样,制定一个全面的迁移计划和过渡架构,下一步是定义和执行交付举措。这些举措将战略转化为行动,确保云原生原则和实践融入组织的运营和文化。这一步是路线图从规划转向执行,与前几章中讨论的交付策略保持一致。
交付举措应结构化,涵盖云原生转型的各个方面,包括开发、基础设施、安全性和操作。为确保全面的解决方案,请考虑以下交付举措:
-
基础设施现代化:
-
目标:从传统基础设施过渡到完全自动化和可扩展的云原生环境,如第七章中所讨论
-
行动:
-
使用 Terraform、AWS CloudFormation、ARM 模板或 Azure Bicep 等工具实现基础设施即代码(IaC)
-
构建 CI/CD 管道以自动化基础设施组件的部署和扩展
-
引入容器编排平台(如 Kubernetes)来管理大规模的微服务和工作负载
-
-
-
开发 实践提升:
-
目标:建立云原生开发实践,以提高敏捷性并减少市场时间,如第五章中所讨论
-
行动:
-
采用微服务架构来分解单体应用
-
实施 CI/CD 实践,实现自动化测试、集成和部署
-
在适当的情况下利用无服务器计算来加快开发速度并减少运维开销
-
-
-
安全 集成 (DevSecOps):
-
目标:将安全实践嵌入整个开发生命周期,以最小化漏洞,如第十一章《不破坏它地运行》和第五章中所讨论
-
行动:
-
在 CI/CD 管道中自动化安全扫描和合规检查
-
实施零信任架构来保护云原生应用程序和基础设施;第九章,《忽略延迟和带宽》提供了零信任架构的深入概述
-
使用云原生威胁检测和响应工具开发安全监控策略
-
-
通过结构化这些举措,我们可以确保云原生原则的实施和操作,为强大且有韧性的云环境奠定基础。
分阶段交付——将举措与迁移阶段对齐
为了确保迁移计划和交付举措之间的一致性,举措必须与迁移的各个阶段对齐。这种方法确保每个阶段都迁移系统,并构建必要的能力以支持云原生操作。通过将每个交付举措与特定阶段对齐,我们创造了一个结构化的、系统化的进程,从而最小化风险、最大化效率,并支持迭代学习和适应。这种分阶段交付方法呼应了早期章节中讨论的增量策略,确保平稳的转型旅程。以下是向云原生迁移的分阶段详细参考表:
| 阶段 | 关键活动 | 细节 和行动 | 成果 |
|---|---|---|---|
| 阶段 1 | 建立基础云基础设施 | IaC 实施:使用 IaC 工具(如 Terraform)部署基础设施,自动化网络设置、安全组和 VPC 配置CI/CD 流水线设置:构建 CI/CD 流水线,自动化基础设施组件的部署,确保一致性和可重复性容器编排:设置容器编排平台(例如,Kubernetes),用于管理工作负载,支持微服务并提供可扩展性安全控制:集成基本的安全控制,如防火墙和身份管理,以建立安全的基础环境。 | 一个可扩展的自动化环境,使用 IaC 和 CI/CD 流水线,为部署应用程序和高效扩展资源提供基础 |
| 阶段 2 | 重构并部署业务关键应用 | 应用重构:将关键应用适配到云原生环境,适当时将单体应用拆分为微服务平台重设计:针对合适的工作负载,实施云原生架构,以减少运维开销并增强可扩展性增强安全性:集成先进的安全实践,如零信任架构,并在 CI/CD 流水线中自动化安全扫描(参见 第五章)可观察性设置:部署监控和日志工具(例如,Prometheus 或 Grafana),确保应用性能和健康状态的可视性及实时跟踪 | 改进敏捷性的云原生应用,通过自动化流水线部署并安全监控,提供对系统性能和稳定性的即时洞察 |
| 阶段 3 | 完全重建或替换遗留系统 | 系统重建:对于不适合简单重构的遗留系统,考虑在云中重新托管或使用托管/SaaS 服务(例如,使用 DocumentDB for AWS——一种托管的类似 MongoDB 的数据库——而不是自行托管 MongoDB)数据迁移:将数据库迁移到托管的云服务,如 Amazon RDS 或 Google Cloud 数据库,确保数据一致性和可用性基础设施优化:使用自动扩展组、负载均衡器和缓存机制优化基础设施使用,确保资源高效利用和成本管理(基于 第四章 的洞察,如何避免账单惊讶) | 完全集成的云原生系统,利用微服务、无服务器计算和云原生安全,达到增强的性能、可扩展性和成本效率 |
| 阶段 4 | 优化和自动化云原生操作 | 完全自动化:使用像 Helm for Kubernetes 等高级编排工具自动化应用管理和扩展,实现零操作管理DevSecOps 集成:扩展 DevSecOps 实践,将安全控制深入嵌入 CI/CD 流水线,并自动化合规性检查云成本优化:实施 FinOps 实践,通过使用 AWS 成本探查器等工具,识别节省机会并建立成本保护措施,持续优化云支出,如在 第四章中所讨论的性能调优:执行应用性能调优,利用监控工具的洞察动态调整资源,确保最佳应用性能 | 高度自动化的云原生操作,聚焦于效率、安全性和成本优化,使得业务需求下的持续交付和快速扩展成为可能 |
表 15.6 - 分阶段交付示例
为确保从当前状态系统到目标架构的无缝演变,必须在交付计划中嵌入结构化的过渡策略。
将过渡架构融入交付计划
过渡架构在交付计划的执行中发挥着重要作用。通过将过渡设计整合进交付过程中,我们能够管理依赖关系并减少中断。以下是如何有效融入这些架构:
-
临时集成层:使用 API 网关或中间件解决方案作为旧系统和新云原生组件之间的临时层。这种方法确保了在系统逐步迁移和重构时,服务的连续性。马丁·福勒(Martin Fowler)的外观模式或缠绕无花果模式非常适用。第七章提供了更多的见解。
-
混合部署模型:对于无法立即迁移的工作负载,实施混合部署模型,使组件在本地和云环境中协同工作。这些模型允许逐步迁移而不影响关键系统的可用性。
-
迭代发布:与其同时迁移所有内容,不如实施迭代发布,将组件或服务分批次控制迁移。我们可以根据每次发布阶段的性能和监控反馈调整后续阶段,并捕捉关键指标。
过渡架构应视为临时解决方案,在迁移进程中逐步演变,最终在组织达到其云原生目标状态时逐渐淘汰。
衡量成功与调整路线图
我们的路线图成功与否,取决于衡量进展、捕捉重要指标并做出必要调整的能力。建立与我们组织业务目标对齐的可衡量成果是我们交付举措的一部分。常见的指标包括以下内容:
-
部署频率:新功能或更新多久可以部署一次?部署频率的增加表明成功过渡到云原生实践。
-
恢复时间(TTR):衡量从事故中恢复服务所需的时间。恢复时间越短,表明弹性和云原生成熟度提高。
-
应用性能:监控应用的响应时间、吞吐量和资源使用情况,以评估云原生重构是否优化了性能。
通过跟踪这些指标,我们可以识别改进领域,优化我们的路线图,并确保每个阶段和举措都能提供可衡量的价值。
由于云原生环境是动态的,我们的路线图应纳入持续反馈循环,以适应变化、创新和经验教训。这些循环包括定期评估每个阶段和举措的结果,确保能够根据实际表现数据进行调整。
持续反馈的良好习惯
以下是一些良好的习惯,可以帮助您获得持续的反馈:
-
回顾会议:在每个阶段后举行回顾会议,回顾成功、挑战和改进领域。利用这些反馈优化即将到来的阶段,并根据需要调整路线图。
-
自动化监控和警报:实施自动化监控系统,提供有关应用性能、安全事件和基础设施健康的实时数据。自动化警报帮助团队迅速响应并根据新兴趋势或问题调整策略。
-
跨职能评审委员会:建立由开发、运营、业务和安全团队代表组成的评审委员会。这些委员会提供全方位的见解,确保技术目标和业务目标在整个转型过程中保持一致。
构建云原生路线图需要精心规划、战略对齐以及灵活的适应能力。通过制定全面的迁移计划、设计有效的过渡架构以及构建交付举措,我们创造了一条支持并加速我们云原生旅程的道路。本节内容阐述了制定一个系统且高效转型路线图所需的基础要素。
既然路线图已经确定,接下来的重点是确保在整个云原生旅程中持续改进。以下部分将深入探讨创建持续演进和精炼文化的策略,以最大化转型的收益。
持续改进
成为云原生组织的旅程并不以迁移或完善的路线图为终点;它是对持续改进的持续承诺。在动态的云环境中,流程、技术和组织目标不断演变,要求团队迅速适应。持续改进是保持云原生环境优化、弹性并与操作需求和业务目标保持一致的机制。通过嵌入持续改进,云原生组织可以持续创新,并应对变化的需求,确保在云原生领域的持续成功。
本节最后探讨如何将持续改进的文化嵌入云原生实践中。我们将讨论以下内容:
-
新的或修改过的构建模块:支持持续优化和云原生成功的关键技术和操作组件
-
文化对团队和工作方式的影响:为了促进持续改进文化,团队动态和思维方式的转变是必需的
-
技术依赖关系:理解和管理相互依赖关系,以维持一个可适应、高性能的云环境
这些组件创造了一个生态系统,在这个系统中,云原生实践可以成熟和演化,使组织保持竞争力和灵活性。
建立新的或修改过的构建模块
一个云原生环境的强大程度取决于其构建的基础模块。在组织过渡过程中,可能需要修改现有的构建模块或引入新的模块,以有效支持持续改进。构建模块指的是技术和操作组件,如工具、基础设施、流程和治理框架,这些都是实现云原生成功的关键。
在初期迁移阶段,必不可少的工具和基础设施可能需要调整或更换,以满足成熟、持续改进的云原生环境的需求。可能需要引入新工具来解决自动化、可观察性或安全性方面的缺口。
以下是持续改进的关键构建模块的示例:
-
增强的 CI/CD 管道:如在第五章中讨论的那样,随着云原生环境的扩展,CI/CD 管道需要发展,以支持更高的部署频率、集成测试和改进的回滚能力。先进的自动化和编排工具,如 Argo CD 和 Flux for Kubernetes,可以帮助使管道更加高效、安全和有弹性,同时支持 GitOps 原生方法。有关 GitOps 策略的更多内容,请参见第三章。
-
可观察性和监控工具:实时可观察性至关重要。升级或实施像 Prometheus、Grafana 和 New Relic 这样的工具,使团队能够监控指标、跨分布式系统跟踪请求并捕获日志,从而提供系统健康的全面视图。第十章,观察你的架构,提供了构建有效可观察性策略的更深入见解。
-
自动化政策执行:政策执行确保持续遵守安全、成本管理和运营标准。像 AWS Config 和 Kubernetes OPA Gatekeeper 这样的工具可以简化此过程,最大程度减少人工干预的需求。第四章 和 第二章 更详细地探讨了预防性护栏,突出展示了如何主动保持合规性。
每一个新的或增强的构建模块都在减少摩擦和提高迭代速度方面发挥着作用。这种适应性确保了环境能够无缝处理新的应用、服务和工作负载。
创建和修改治理框架
一个治理框架提供了监督和结构,确保云原生实践与组织目标一致。然而,随着云原生环境的发展,治理框架必须适应不断变化的需求。早期的治理工作可能集中在建立合规性和安全标准上;而现在,它们应该转向支持创新和灵活性。在一个持续发展的环境中,根据新工具、流程和服务调整治理实践的能力至关重要。调整治理框架使团队能够自主工作、做出敏捷决策,并利用创新解决方案,而不受约束。
此外,适应性治理框架创造了一个更加包容的环境,在这里,团队反馈被纳入治理调整。通过鼓励定期的反馈循环,团队可以突出政策改进的差距或机会,从而提升治理实践的相关性和影响力。为了促进一个与持续改进相一致的治理框架,考虑以下关键实践,每一项都旨在提升灵活性、自主性和响应能力,特别是在云原生环境不断成熟的过程中:
| 考虑因素 | 描述 |
|---|---|
| 动态护栏 | 利用灵活的护栏,正如在 第五章 中所讨论的那样,这些护栏能够适应新的工具、流程和服务,使团队能够在组织边界内创新,而不受限制性政策的约束 |
| 分散化决策 | 鼓励在定义的框架内进行自主决策,减少瓶颈,加速创新周期,正如在 第三章 中所讨论的那样 |
| 基于反馈的调整 | 定期收集团队对治理政策的反馈,并相应地完善框架,确保与不断变化的需求保持一致,促进持续改进 |
表 15.7 - 治理框架实践
适应持续改进的治理框架不仅能促进运营效率,还能支持创新和实验的文化。
接受持续改进的文化
成功的云原生转型在技术和文化上同等重要。如果没有持续改进的思维方式,团队可能难以跟上云原生环境所要求的变化速度。嵌入持续改进的文化有助于确保团队积极主动、参与其中,并致力于改进流程和技术栈。
云原生组织依赖于跨职能合作,这有助于加快决策并更好地与业务目标对齐。在一个持续改进的环境中,开发、安全和运营(DevSecOps)的协作变得更加关键。
以下是构建协作文化的策略:
-
跨职能小组:创建以产品为导向的小组,成员来自开发、运营和安全团队。这些小组实现了责任共享,促进了团队紧密合作,解决挑战并交付价值。更多内容请参见第一章。
-
定期回顾:定期进行回顾,评估成功并找出改进的领域。回顾为团队成员提供了一个安全的空间,表达关切、庆祝成果,并产生改进流程的想法。
-
知识共享会议:通过举办内部研讨会、午餐学习会或技术交流会来鼓励知识共享。这些会议帮助建立集体知识库,确保团队了解新工具、最佳实践和不断发展的云原生概念。
培养协作文化有助于减少部门壁垒,支持持续学习和创新。这一协作基础不仅加速了决策过程,简化了工作流程,还培养了团队成员有权提出创意和改进建议的文化,进一步推动了组织内的创新和适应性。
赋能团队实现自主性和责任感
在云原生的旅程中,赋能团队做出决策并承担领域责任变得至关重要。自主性不仅能加快流程,还能促进责任感,因为团队成员会直接对项目的成功负责。以下方法可以用来促进团队的自主性:
-
分散决策:允许团队在其领域内做出决策,无需等待集中审批。例如,团队可以拥有 CI/CD 流水线,选择最符合组织需求的工具和流程。另一个方法可以在第二章中找到,它通过自上而下和自下而上的方式探讨决策制定。
-
明确的所有权模型:为云环境中的应用程序、服务或组件分配明确的所有权。所有权可扩展到维护、更新和改进,确保每个系统都有专门的团队负责监控和提升其性能。
-
定义成功指标:为每个团队制定具体的成功指标,如 DORA 指标(部署频率、变更失败率和恢复服务时间),这些指标应与业务目标对齐。通过指标,团队可以不断改进流程,以达到或超越预期,并尽可能识别瓶颈。
创建一个自主且负责的环境,减少对其他团队的依赖,并推动从根本上持续改进。
解决技术依赖问题
在不断发展的云原生环境中,技术依赖关系是一个关键因素。工具、平台和服务之间的依赖关系可能影响性能、可扩展性和灵活性。有效管理这些依赖关系对于实现无缝改进至关重要,并确保云原生系统保持敏捷。
随着云原生环境的成熟,服务、数据库和基础设施组件之间的依赖关系变得更加复杂。清楚地了解这些依赖关系有助于避免在更新或引入新元素时出现问题。以下步骤可用于管理依赖关系:
-
依赖关系映射:创建服务、数据库、API 和第三方工具之间依赖关系的可视化地图。可以使用依赖关系映射工具,如服务发现工具(例如,AWS Cloud Map、GCP 服务发现或 Azure API 中心)。
-
定期依赖关系审计:定期进行审计,识别过时、未支持或性能不佳的组件。与云原生架构不再兼容的依赖关系应升级或替换。
-
建立依赖关系负责人:为关键依赖关系(如数据库或外部 API)指定负责人。拥有负责人可以确保依赖关系得到定期监控、更新和优化,从而最大限度减少性能下降的风险。
通过映射和管理依赖关系,我们可以减少意外故障、提高系统的弹性,并简化环境中的更新。
积极管理第三方集成
许多云原生环境依赖于第三方服务,如 SaaS 应用程序或数据提供商。有效管理这些集成对于保持系统性能、确保数据一致性以及避免中断至关重要。以下是第三方依赖关系的重要考虑事项:
-
服务水平协议(SLA):审查第三方服务的 SLA,了解其性能保证、可用性和支持水平。确保 SLA 与运营要求一致,特别是对于关键任务的集成。
-
主动监控:实现监控工具,跟踪第三方服务的性能和可用性。如果集成开始出现性能问题,自动化警报可以帮助团队在用户受到影响之前做出响应。
-
后备机制:对于关键服务,建立后备机制,如故障切换实例或备用提供商,以确保在故障期间的连续性。这对于支持高可用性应用程序或关键功能的服务尤为重要。
主动管理第三方集成可以确保依赖关系不会成为故障点,支持性能和可靠性的持续改进。
嵌入反馈循环以实现持续改进
反馈循环对于持续改进至关重要,它提供了基于数据的洞察,帮助做出决策并推动增强。通过在各个过程、基础设施和应用程序中嵌入反馈机制,团队能够获得实时调整的洞察。
持续监控对于捕捉系统性能、安全性和用户体验的实时反馈至关重要。一个可观察性堆栈,包括监控、日志记录和追踪,提供了对云原生环境的完整视图,使团队能够主动检测和解决问题。以下是可观察性堆栈的关键组件:
-
实时监控:使用像 Prometheus 和 Datadog 这样的工具来监控基础设施和应用程序健康状况。实时监控提供即时警报,处理如延迟增加或 CPU 使用率等问题。
-
集中式日志记录:实现集中式日志记录解决方案,如Loki、Grafana、Tempo 和 Mimir(LGTM)堆栈(一个流行的开源监控堆栈),以聚合和分析日志。集中式日志记录使团队能够识别模式、排查错误并获得环境中的洞察。这也扩展到大三云服务提供商,他们有自己的云原生解决方案,如 Amazon CloudWatch、Azure Monitor 和 GCP 操作套件。
-
分布式追踪:如 Jaeger 或 OpenTelemetry 等工具可以实现跨微服务的端到端追踪。追踪提供了请求流的可见性,帮助团队识别瓶颈并优化应用程序性能。
实时可观察性增强了反馈过程,为团队提供了可操作的洞察,以维持高可用性和性能标准。
利用 DORA 指标获取性能洞察。
DevOps 研究与评估(DORA)指标在衡量持续改进成果方面具有不可或缺的价值,因为它们提供了关于软件交付和运营性能的量化洞察。这些指标包括:
-
部署频率:衡量代码部署的频率,反映敏捷性和响应能力。
-
变更的交付时间:跟踪从代码提交到部署的时间,反映流水线的效率。
-
变更失败率:表示导致生产环境故障的变更百分比,反映测试和验证的质量。
-
恢复的平均时间(MTTR):衡量从生产环境故障恢复的时间,体现系统的韧性。
以下是如何使用 DORA 指标来推动改进:
-
设定性能基准:使用 DORA 指标来建立性能基准,并跟踪随时间的改进。
-
识别优化领域:例如,较高的变更失败率可能表明需要更强的测试或代码审查流程。
-
庆祝成功:当指标显示改进时,庆祝这些里程碑,以强化持续改进的文化,并激励团队。
云原生技术领域发展迅速,新的工具、框架和方法不断涌现。作为持续改进的一部分,定期评估和优化技术栈,以利用技术进步,确保环境保持高效和具有竞争力。以下策略可以用于技术栈优化:
-
评估新工具:定期审查最新的工具和技术,看看哪些能提高生产力或性能。例如,像 Linkerd 这样的服务网格或更新的 CI/CD 工具可能提供改进的功能,支持持续改进。
-
优化资源分配:定期分析资源使用情况,找出可以节省成本的领域。利用自动扩展、预留实例或竞价实例可以在不影响性能的情况下减少云支出。
-
优化 CI/CD 流水线:随着流水线的演进,寻找优化的方式,例如集成新的测试框架或添加质量门控,减少人工干预的需求。
通过在技术栈中实施持续改进,我们可以确保环境保持敏捷、高效,并能够满足业务需求。
总结
在云原生组织中执行持续改进是一个持续的、迭代的过程,需要致力于提升技术和文化实践。通过建立新的或修改过的构建模块,拥抱协作和自治的文化,管理技术依赖关系,并嵌入反馈循环,组织可以创造一个环境,使云原生实践与业务需求共同发展。
当持续改进融入到组织的基因中时,我们的云原生之旅将保持灵活、韧性强,并能够推动持续的增长和创新。本章总结了构建、执行和优化云原生转型的基础策略和洞察,赋能团队在不断变化的数字化环境中以敏捷和自信引领前行。


浙公网安备 33010602011771号