原文:
annas-archive.org/md5/ec641f51414ac10506c7857d2f65c8f4译者:飞龙
前言
欢迎来到 架构师的云平台工程!平台工程是创建环境的实践,能够以安全且高效的方式构建、测试、验证、部署和运营软件。 平台工程关注自动化,并使平台的用户、开发人员和运维人员能够专注于价值创造。 平台通常被定义为 内部开发平台 或 内部开发者门户 (IDP),它抽象了基础设施的复杂性以及支持软件生命周期所需的所有活动组件,从其设置到上线到生产环境。 但平台工程不仅仅是让技术和组件能良好协同工作。 它需要开放的心态和整体性的方法来定义平台的目标,并在决策过程中遵循原则,推动变革文化 和创新。
在 架构师的云平台工程中,我们将引导你建立产品思维,构建一个随着时间推移而逐步老化和成熟,但始终保持年轻活力的解决方案。 一步步地,我们将确定战略方向,并为平台定义目标架构。 这将成为你和与你一起工作的人们的活文档。 在本书中,我们将覆盖平台的四个不同支柱,以及你需要做出的相关决策:由 Kubernetes 表示的基础设施、自动化、自服务能力,以及内置的可观察性和安全性。 到书的最后,你将掌握处理成本的工具,包括实际的基础设施成本和技术债务。 如果两者都管理得当,它们甚至可以成为你克服组织障碍 和政治斗争的最佳盟友。
对于本书中讨论的每个方面和主题,我们还提供了额外的资源,涵盖了完整的技术细节。 我们的目标是为你提供一个参考框架和方法,用于定义可以随着时间成熟的平臺架构,而不依赖于特定的技术或版本。 我们深知生活中唯一不变的就是变化,而这一点同样适用于平台工程。 这就是为什么我们鼓励你作为平台工程师和架构师,保持对这些变化的敏感,并将产品思维带给你的用户 和利益相关者。
本书适合谁阅读
本书适合平台工程师和架构师、DevOps 工程师以及云架构师,他们希望通过将平台作为 产品来转变实现云原生平台的方式。
本书还面向 IT 领导者、决策者和 IT 战略家,他们正在寻找改善其系统架构和软件交付的新方法,书中通过一种全面的方法,超越了简单的“你构建它,你 运行它。”
本书内容
第一章, 平台工程与平台构建的艺术, 介绍了平台和 IDP(内部开发平台)。 本章涵盖了产品思维的重要性,以及构建用户所期望的系统的雄心。
第二章, 理解平台架构以构建产品化平台, 将引导您完成创建平台架构的所有相关基础工作和方法。 您将发现平台作为产品的价值,最小可行平台的首次实现,以及如何观察和衡量其成功 和采用情况。
第三章, 为支持平台功能构建基础, 本章将引导您完成定义平台坚实基础的必要步骤和过程,帮助平台从初始功能集向支持企业的关键 平台功能发展。
第四章, 架构平台核心——Kubernetes 作为统一层, 本章提供了关于 Kubernetes 为何成为平台工程师首选平台的见解。 您将了解核心集成和我们在集中关注 额外增强功能之前必须做出的相关决策。
第五章, 集成、交付和部署——自动化无处不在, 本章为您提供了关于构建、部署、测试、验证、安全、操作、发布和扩展软件的复杂性以及如何通过 自助服务功能集中化和自动化这些体验的稳定理解。
第六章, 为开发者及其自助服务构建,回顾了 IDP 集成的概念,并分享了构建具有弹性、灵活性以及 以用户为中心的平台的最佳实践。
第七章, 构建安全和合规的产品,详细讲解了安全标准框架及趋势;如何利用软件物料清单;并定义了确保平台安全而不限制能力的正确行动。 此外,我们还展示了如何确保应用交付过程提供加固和安全的软件/容器包,并展示如何使用策略 引擎技术。
第八章, 成本管理与最佳实践,解释了平台成本增加元素的概念以及如何优化这些成本。 你将了解标签策略、一般的成本优化场景、如何利用可观察性来识别优化潜力,以及如何将最佳实践 付诸实践。
第九章, 选择技术债务以修复平台问题,为你提供了工具、框架和方法来积极管理你的技术债务。 与成本类似,技术债务可以不断增长,并且如果不加以处理,会对平台造成负面影响。 。
第十章, 为未来打造平台产品,强调了变革的必要性,以及我们作为平台工程师在以可控方式促进变革中的角色,平衡可靠性 和创新。
为了充分利用本书 |
你应该了解云计算的基础知识、Kubernetes、平台工程的理念,以及如何定义 这些架构方面的内容。
| 本书涵盖的软件 内容 |
|---|
| Kubernetes |
| Backstage |
| CI/CD 解决方案,如 GitHub Actions |
| Keptn |
| Argo CD |
| Crossplane |
| Prometheus |
| OpenTelemetry |
| Harbor |
| OpenFeature |
| Renovate Bot |
下载示例代码文件 |
你可以从 GitHub 下载本书的示例代码文件,链接是 https://github.com/PacktPublishing/Platform-Engineering-for-Architects。如果代码有更新,将在 GitHub 仓库中更新。
我们还有其他的代码包,来自我们丰富的图书和视频目录,您可以在 https://github.com/PacktPublishing/ 找到。快来查看一下!
使用的约定
本书中使用了多种文本约定。
文本中的代码:表示文本中的代码词汇、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter/X 用户名。 举个例子:“目录路径嵌套在图表中,使用这个名为 crds/ 的目录允许 Helm 在将 CRD 添加到集群中后暂停,继续执行 图表执行。”
代码块如下所示:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
version: v1
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct
任何命令行输入或输出如下所示:
$ kubectl label nodes platform-worker2 reserved=reserved
node/platform-worker2 labeled
粗体:表示新术语、重要词汇或屏幕上显示的词汇。 例如,菜单或对话框中的词汇会以 粗体显示。举个例子:“这些平台日志应尽可能不包含任何 个人身份信息 (PII) 。”
提示或重要说明
显示如下。
保持联系
我们欢迎读者的反馈。
常规反馈:如果你对本书的任何内容有疑问,请通过电子邮件联系我们,地址是 customercare@packtpub.com 并在邮件主题中提及书名。
勘误:尽管我们已尽一切努力确保内容的准确性,但仍可能出现错误。 如果你在本书中发现错误,我们将非常感激你能报告给我们。 请访问 www.packtpub.com/support/errata 并填写表单。
盗版:如果您在互联网上遇到任何我们作品的非法复制品,任何形式的,我们将非常感激您提供相关的网址或网站名称。 请通过 copyright@packt.com 与我们联系,附上 该材料的链接。
如果您有兴趣成为作者:如果您对某个主题有专业知识,并且有意撰写或贡献书籍,请访问 authors.packtpub.com。分享 您的想法
分享您的想法
一旦您读完 平台工程师的架构师指南,我们期待听到您的想法! 请 点击这里直接进入 Amazon 评论页面 为这本书分享 您的反馈。
您的评论对我们和技术社区非常重要,将帮助我们确保提供优质的 内容。
下载这本书的免费 PDF 副本
感谢您购买 这本书!
您喜欢在移动中阅读,但无法随身携带您的纸质书籍吗? 您的纸质书带不走吗?
您的电子书购买无法在您选择的设备上使用吗? 选择的设备是否不兼容?
别担心,现在每本 Packt 书籍都会附赠无 DRM 保护的 PDF 版本 完全免费。
随时随地,在任何设备上阅读。 直接从您最喜欢的技术书籍中搜索、复制并粘贴代码到您的应用程序中。
优惠不止如此,您还可以每天通过电子邮件获得独家折扣、新闻简报以及精彩的免费内容。 您的收件箱。
按照这些简单步骤获取 奖励:
- 扫描二维码或访问下面的链接
https://packt.link/free-ebook/978-1-83620-359-9
-
提交您的购买凭证 以获得奖励
-
就是这样! 我们会直接将您的免费 PDF 和其他福利发送到您的 电子邮件。
第一部分 – 平台工程与架构概述
在第一部分中,您将进一步了解平台工程和平台架构的基础。 我们将帮助您深入理解平台产品思维,向您展示平台工程不仅仅是构建系统。 然后,我们将引导您完成创建平台架构的过程,从定义平台的目标到最简可行的平台,并讲解如何衡量平台的成功和接受度。 在 第三章中,我们将重点设计平台的基础,以提升用户体验并避免 技术复杂性。
本部分包含以下章节:
-
第一章,平台工程与平台打造的艺术
-
第二章,理解平台架构,以将平台构建为产品
-
第三章,为支持平台能力打下基础
第一章:平台工程学与平台打造的艺术
在本章中,我们将学习如何判断我们的组织是否处于适合规划平台的状态。 为此,我们将澄清为什么平台成为如此重要的话题,产品思维如何融入其中,以及判断我们是否准备好构建平台的检查点是什么。 我们将了解平台之间的差异以及最常构建的哪些平台类型。 常见的平台类型。
接下来,我们将深入探讨平台的三个核心元素:普及的云、开发者体验和平台的主要特性。 总体而言,我们将看到云原生工程中的一些常见元素。 这引出了一个问题:我们是否真的需要另一个抽象层。 我们还将考虑,平台是否能帮助我们克服由于过度工程化复杂系统和开发流程所带来的高认知负担,还是最终只是成为又一层抽象层。 我们将反思一些这些层,以找到答案 为我们自己。
最后,我们将讨论超越技术和平台实现的方面。 理解社会技术层面的内容并将人类,我们的实际利益相关者,置于中心是至关重要的。 这使我们能够定义更好的平台产品,并为紧密合作找到方法。 紧密合作。
在本章中,我们将讨论以下 主要话题:
-
作为产品的需求 平台作为产品
-
实现以开发者和 产品为中心的解决方案
-
我们是否需要另一个 抽象层?
-
社会技术层面
作为产品的需求
在 云原生环境中,近年来几乎没有其他话题像“平台”这一术语一样,给人留下如此深刻的印象,平台 以及平台工程师的角色也随之而来。 就像第一个可用的 CI/CD 流水线的引入一样,这场淘金热导致了快速适应,往往没有明确的目的或理性。 现在我们已经进入知识的谷底,可以深入思考一个问题:你需要一个平台吗?如果需要,如何设计和实施它,确保它能够持续发展到 未来?
为了回答这个问题 我们应该首先看看构成这样一个平台的要素。 平台是不同能力的组合,这些能力是掌握传统和云原生环境所必需的,以便它能够在应用程序的开发、交付和运营中支持最终用户。 平台可以作为推动力,将非云原生基础设施转化为有价值的资源。 然而,今天大多数计算平台提供某种形式的 API,可用于自动化部署和工具化可用资源,并构建平台的基础。 平台为最终用户提供任何类型资源的一致性,并通过自服务 API、模板、CLI 或其他解决方案授予其功能访问权限。 以下示例还突出了平台由许多组件组成: 许多组件:
图 1.1:平台/IDP 示例
我们通常会看到 平台的主题出现在云原生的背景下,但为什么会这样呢? 云原生技术使组织能够在公共云、私有云和混合云中构建和运行可扩展的应用程序。 这种方法通过容器、标准化服务提供、不可变基础设施和声明式 API 等功能得到了最好的体现。 这些功能实现了松耦合的系统,这些系统具有弹性、可管理和可观察性。 这些功能使开发者能够以最小的努力进行频繁的更改。 简而言之,平台是云原生计算的推动力,并利用其工具将其 工具化。
公司和开发者从平台中获益是平等的
软件工程师在云原生平台上的体验不同于在云服务提供商上本地开发软件。 专注于构建面向某一 云服务提供商 (云服务提供商)(CSP)会将你绑定到该封闭生态系统的逻辑中。 当你在云原生平台上构建时,必然会有类似的效果,因为这些平台通常是以 Kubernetes 为中心,利用 Kubernetes API 的高度集成统一性。 然而,问题在于,云原生平台提供相同的体验,而你并不意识到底层基础设施的存在。 由于大多数公司至少有两个到三个云或类似云的服务提供商,而且已经在适应这些服务时遇到困难,云原生平台无疑是一个颠覆性的游戏改变者 [1]。 在云原生平台上开发软件改变了思维方式和架构。 然而,如果不采纳这种思维方式,失败的概率 会很高。
然而,有更多方面需要考虑,平台不仅仅是统一的基础设施管理。 平台必须是为了某个特定的目的而创建的。 平台必须有明确的用途。 关于平台面向谁构建,以及平台工程师的利益相关者是谁,通常的定义认为这些仅限于开发人员。 这些定义忽略了一个事实,那就是整个组织、运维团队和其他专业团队同样从平台中受益。 平台为软件工程师提供了一个简便的入口,来构建、测试、部署、发布和运营他们的软件。 它深入提供使用情况的洞察,并允许看护者和管理员无所畏惧地维护基础设施、平台和集成。 用商业术语来翻译,平台可以提供更快的市场进入时间,并且具备更大的灵活性来改变和调整其组件,同时保持高可靠性和 强大的稳健性。
这对现在的公司意味着什么? 由于市场上 IT 专业人员的短缺、IT 变化的快速节奏,以及培训团队在云技术和云服务提供商方面的超负荷工作,平台为能力引入了合适的断点。 我们需要这些断点,以避免将多个学科合并到一个角色中的趋势,例如 DevOps。 此外,利用 DevOps 方法论的平台工程师并不是 DevOps。 我们需要积极保护这个角色,避免重蹈 DevOps 角色的覆辙,并在定义上保持敏锐。 平台工程师整合专家提供的能力,通过他们的平台简化这些能力的使用,帮助开发人员使用,并为工程师提供自助服务。 然而,开发人员不需要成为多个领域的专家,例如安全性、可观测性、基础设施配置和自动化等。 这与常见的 DevOps 角色有所不同,DevOps 需要成为自己领域内所有必要方面的专家,以确保其应用的正常运行。 未来我们仍然需要 DevOps 来处理更高级的应用管理,但我们也必须让他们的工作 更轻松。
该平台为需要专业知识的自下而上的能力提供集成层,例如安全性、数据库,甚至是虚拟机或裸金属服务器的部署,同时也提供开发人员和 DevOps 的自上而下使用。 如下面的图所示,平台工程团队负责提供 这一层。
图 1.2:平台驱动型组织中的能力与责任
当然,这也 意味着必须培养和教育另一个专家团队。 然而,相比之下,平台工程师的小团队通常能够构建并运行庞大的环境。 理想情况下,平台减少了公司内其他团队的认知负担,让他们能够专注于核心价值,通过简化开发过程中的机制来帮助他们。 这个平台有助于减轻压力并提高透明度。 来自世界各地的公司常常分享他们在平台和平台团队方面的经验,通常的调子是讲述他们如何解决之前无法应对的问题,或者这种方法如何提高了他们产品 和服务的质量。
这些平台通常被 称为 内部开发者平台 (IDP),因为它们通常是为企业的内部开发团队而构建的。 在本书中,我们将交替使用平台、IDP、平台产品和云原生平台这些术语。 然而,我们首先会稍微强调一些方面:
-
平台:统一服务的跨技术层的通用术语,允许开发者使用。 这些平台通常被称为
-
IDP:强调开发者、 软件开发生命周期 (SDLC),以及 开发软件所需的工具
-
平台产品或平台即产品:强调专门的团队负责平台演进能力及其长期承诺,同时建立一种 不同的思维方式
-
云原生平台:专注于抽象和使能使用标准化 API 以及集成 的能力
这种视角 可能感觉很细致,但平台这一术语本身往往会导致更多的混淆。 云平台也是一种平台,对吧? 一个 软件即服务 (SaaS) 也可以视为平台。 提到云原生平台或 IDP 可以引导我们走向正确的方向并获得更准确的理解。 根据您组织的成熟度,明确这些术语并建立共同的理解、语言和 共享知识也是至关重要的。
平台案例研究和成功故事
为了 突出平台的积极影响,我们可以通过三个完全不同的公司及其使用 IDP 后的结果来进行展示。 所有这些案例主要集中在 Backstage 作为开发者门户和进入点的角色, 以及 IDP。
作为 Backstage 的发明者和 IDP 运动的发源地,Spotify 声称以下说法适用于其内部的 Backstage 用户:
-
GitHub 上活跃度高出 2.3 倍 更多
-
代码更改多出 2 倍 部署更改次数
-
部署次数增加了 2 倍
-
新开发者的入职时间从 60 天缩短至 20 天
Expedia 集团报告 了不同的数据:
-
平均而言,创建一个新组件 或应用程序需要四分钟
-
超过 4,000 名用户每天至少使用 IDP 20 分钟 以上
-
技术文档每月被查看超过 50,000 次 每月
-
超过 15%的内部开发工具已与 Backstage 集成 从而减少了上下文切换
现在,最后一个 我们应该关注的公司是丰田:
-
项目现在每周交付一次工件 而不是每月
-
每个团队节省了 8-12 周的额外工作,从而减少了超过 500 万美元的成本或用于 价值创造的时间和预算
-
标准化部署模板减少了失败并加速了部署 部署速度
这些数据对于了解数字原生公司、旅游科技公司以及世界上最大的汽车制造商之一的背景非常有趣。 这些数据中的任何一项都能清晰地展现出正面 效果 [2]。
项目与产品
谈到 组织,引入新解决方案通常作为一个项目来进行。 因此,在某个时间点,有人决定投资建立自己的平台。 这种方法面临一个根本性的问题:截止日期。 项目需要在规定的时间和预算框架内达成目标。 如果项目耗尽时间或资金,它将专注于其运维。 生命周期的这两个部分被当作不同的事情来处理,造成了朝阳与夕阳的时间段。 简单来说,在实施阶段,你会看到大量的投资、沟通和兴奋。 然而,在达到截止日期后,项目变成了一个需要维护的死物。 DevOps 并没有改变这种行为;它只是常常有了新的名称、新的角色和不同的流程。 然而,最终,预算、人力和注意力被转移到下一个项目,而仅有一小部分原有的预算得以保留。 这对于那些在实施过程中辛勤工作的工程师来说是令人沮丧的,随着纯粹运维成本的不断增加,这对于组织来说也将变得令人沮丧。 然而,构建该平台的人可能会离开或加入其他项目。 这种短期视角的系统实施方式,慢慢地扼杀了许多优秀的项目和团队精神。 更重要的是,它显示了解决方案的商业价值并不明确。 当一个实施方案(如平台)能够提供明确的价值时,就不应该有理由转移注意力并导致 它的夕阳。
尽管将许多实现作为项目来进行是一种有效的方式,但对于平台实现而言,这却是它的死刑。 常规实现是功能完整的;完成后它们可以存在。 但是,平台总是在不断发展、不断升级,并且总是实现新的功能。 在与开源和云服务提供商合作时,你将会早早了解到它们在自身开发周期中的工具和软件的更新速度。 功能、修复和安全补丁会持续发布。 这对大公司来说是一个重大挑战,因为它们仍然习惯于远远慢于此的发布周期。 保持与这种快速发展的速度同步的好处在于,作为一个组织,你可以频繁地从新的功能和能力中获利。 它是创新的驱动力和使能器,使你能够以其他方式实现系统,并解决你可能没有意识到的问题。 对于你来说,不痛苦的问题,真的算是个问题吗? 组织通常不会将这类问题视为问题,因为它们习惯于只识别痛苦的过程 和方法。
让我们看一个例子。 在当前年份(2024 年),欧盟发布了一项法律,旨在改善企业的碳排放报告。 从高层次来看,这也包括 IT 资源。 此外,在过去的几年里,多个开源基金会和项目已开始致力于为软件的能源消耗提供透明度。 一年前,我们只能报告非常粗略、估算的数字,关于数据中心、服务器的能源消耗,以及经过一些人工处理后,某个软件的能源消耗。 今天,我们可以为在裸金属、虚拟机管理程序或 Kubernetes 容器中运行的任何应用获取细粒度的信息,因为工具已经发展到可以提供这些数据。 公共 CSPs 提供越来越多的关于其自身能源消耗的见解。 我们可以期待来年会发生什么? 我们可以期待更好的数字,包括能源的区域性碳混合,以及这些数字的端到端可见性和透明度。 对于平台和平台工程团队来说,这种透明度将随着时间的推移自然到来。 它不需要一个项目来彻底颠覆 IT。 提出这一需求将促使平台工程团队将这些功能实现到平台的核心中,惠及所有使用该平台进行构建、部署、发布和 运营软件的人。
这被称为产品思维方式,对于平台来说,适应其环境的需求是自然而然的。 他们 的 环境。
平台作为一个产品
作为产品的 平台是以用户为中心,倾听并积极研究最终用户的需求,不断改进其服务。 一个产品也意识到它的价值。 类似于你手机上的任何应用,它利用自身的价值来为进一步的开发和新功能提供资金。 在这里,没有截止日期,也没有结束。 目标仅仅是通过每次发布变得更好。 这给组织带来的是一个专家团队,持续致力于为业务提供有价值的平台的核心能力。 价值创造。
将平台设计和开发作为一个产品,超越了单纯的工程学层面。 它面临着组织方面的挑战,这些挑战应当在你决定积极构建平台时考虑进去。 事实上,你需要提供有效的数据来证明你的平台带来了好处,并且展示出平台能够覆盖其自身的成本。 这必须在产品负责人和平台工程师的思维方式中。 这里的想法不是要成为商业人士,而是要能够清楚地传达存在的理由,更重要的是,成为一个没有 截止日期的产品。
现在,你可以找到三种不同类型的作为产品的平台:
-
IDP 平台:
-
为 软件工程师提供最佳体验
-
为开发和运营团队提供端到端支持和可视化, 支持他们的软件
-
引入治理、合规性 和安全性
-
为开发团队建立自助服务,并简化 部署过程
-
-
数据科学和机器学习平台 :
-
与 IDP 平台类似,并且通常是从这些平台演变而来的 。 这些平台
-
利用其可扩展性进行数据的研究、分析和处理, 高效地降低数据成本
-
克服了复杂的实施过程,并使它们 普遍可用
-
提供直接、安全的访问相关的 数据源
-
-
低代码/商业平台:
-
强烈的趋势驱动着提供平台,这些平台能带来解决方案,使得可以在相对较少甚至几乎没有编码需求的情况下实现新特性。
-
我们将在未来几年中更多地看到它们。
-
在我们的书中,我们将专注于产品中心化的 IDP 架构视角。
你需要一个平台吗?
和任何其他复杂环境一样,我们首先要问:我们真的需要一个平台吗?我们知道我们将如何使用它吗?
尽管平台可以提供很多好处,但它们并不总是你组织问题的答案。以下是你还未准备好使用平台的迹象:
-
你只有单体应用程序。
-
你没有自己的开发团队。
-
你的 DevOps、SysAdmin 或基础设施团队工作过度,或者被孤立。
-
你有非常简单的应用程序,这些应用可以运行在任何地方。
-
你很难为培训提供预算,以帮助你的团队提升技能。
-
你通常运行商业化的、现成的解决方案。
另一方面,什么时候使用 IDP 对你来说有意义呢?以下标准是你准备好使用IDP的指示:
-
你有多个基础设施环境的需求,或者推动一个多云战略。
-
你需要对你的环境进行高级控制(安全性、合规性,以及对基础设施和应用行为的深度洞察)。
-
你的开发团队不断被无价值的任务所压垮。
-
你有一个好奇且感兴趣的 DevOps 或基础设施团队,他们已经迈出了向平台过渡的第一步,尽管他们并没有意识到这一点。
-
你的应用程序由于微服务架构需要某种类型的编排,因为许多组件或不同的集成需要良好地协同工作。
-
你希望让组织能够优化 IT,以降低成本、提高透明度、质量,或安全性。
在为你的组织定义一个平台产品之前,你应该回答清楚检查清单上的所有问题。 有多个点来说明你为什么需要它是有道理的。 例如,仅仅因为某个团队请求一个 IDP,或有人在会议上提到他们听说过它,并不足以作为做出此类决定的坚实基础。 平台的引入是一个过程,根据我们的经验,它可以在相对较短的时间内成为公司核心的焦点。 在这样的压力下,你仍然需要有明确的目的 和方向。
现在我们已经学会了如何定义平台的目的,接下来我们需要讨论一个问题:我们真的需要这个额外的 抽象层吗?
我们真的需要另一个抽象层吗?
让我们简要总结一下到目前为止的内容。 一个平台为你现有的基础设施和环境加上了一个括号,并在其上加了一层抽象。 该平台通过进一步的功能增强它,使得你的开发团队能够以自动化的 自助方式利用它。
从技术角度来看,这代表着下一个抽象层次。 因此,讨论我们放置在其上的这层新结构是有道理的。 从底部到顶部,我们可以看到裸机,接着是虚拟化的超监视器;其上是云服务提供商。 有些人可能会包括容器、Kubernetes 或无服务器组件——而现在,我们将添加我们的平台。 这些至少是四个层次,每一层都承诺让其下方的层次更简单,并通过 一个难以定义的元级脚本、 基础设施即代码 (IaC)、云库和自动化将它们粘合在一起。 那么,我们真的需要这一层额外的抽象层吗,还是我们只是在用它来让自己 忙碌 地建造东西?
简化抽象层
没有 简单的答案,但通过探讨每一层的目的,你或许能够更好地理解它 。
最初引入虚拟化技术的目的是简化主机供应,以便软件能够运行并更好地利用服务器。 今天,它们仍然具有同样的作用,但可以被 Kubernetes 和容器运行时所取代。 反对这种替代方案的一个关键论点是,虚拟机提供更好的隔离和更高的安全性。 在不深入讨论的情况下,也有提供非常坚固隔离的选择,比如 Kata 容器。 唯一令人头疼的组件是带有操作系统和其运行时的容器。 展望未来几年,WebAssembly (Wasm)可能会成为解决这一问题的一部分。 在容器中没有操作系统,只有纯裸二进制文件,几乎没有攻击门路。 然而,让我们再给它一些 时间。
基础设施即服务 (IaaS)提供商 和公共云提供商通过软件定义的存储和网络增强了这一能力,减少了构建自己数据中心及管理所有物理依赖的复杂性。 此外,它们还提供了常用场景的进一步功能,如数据库、负载均衡、用户管理、消息队列或者 ML 平台和预训练的 AI 模型。 这是一个非常有用的实施方案,推动了行业的快速发展,扩展了可能性。 然而,这也导致整个行业朝着一个问题导向发展。 技术的发展速度超过了人们和组织,尤其是它们能够适应的速度。 我们看到全球专业工程师的短缺,而企业每年都在考虑提供更多的数字服务。 因此,解决方案及其依赖关系都是本地化到云端。 这种努力的回报可能是显著的。 你可以用一个相对较小的全球团队管理任何类型的基础设施和服务。 然而,现实也表明,平均每家公司拥有两到三个 IaaS 和公共 CPS,加上(通常还有)自己的计算能力,以及大约 10 个 SaaS 提供商,大企业可能达到 50 个 [1]。CSPs 还提供 40 到 200 种不同的服务。 换句话说,今天我们能够取得很大成就,但这些环境的复杂性也 变得相当重要。
为了驯服这个 规模,IaC 和 云开发工具包 (CDKs)已经成为管理你的着陆区和软件集成的首选工具。 故事中有趣的部分是,像 DevOps 这样的实践经常被误解,已经使情况变得更糟。 这些误解现在已经导致开发人员也期望设置和维护他们 软件需求的基础设施。
最后但并非最不重要的是,我们有基于容器、Kubernetes 或无服务器的系统。 每种环境都有几十种选项可供部署代码和运行组件。 理解这些需要关注的层次太多了。 然而,它们的发展是合理的,因为你不希望像以前那样运行软件。 将代码推送到镜像,然后选择运行时简化了 配置过程。
总体而言,要表示复杂性水平,我们可以想象一个三维对象,比如一个由立方体构成的立方体。 下面的插图展示了不同的服务层,代表了抽象的不同成熟度,以及每一层如何组合形成一个 IT 环境。
图 1.3:计算抽象和简化的多维复杂性
现在,这个图表 过于简化,考虑到每个维度中你拥有的数百或数千个选项。 然而,它仍然给出了一个很好的提示:如果你需要一个平台,建立一个包装器围绕这个结构,并驯服它的巨大复杂性以利用它的力量。
对软件工程师和其他 IT 专业人员的认知负荷
为了管理所有这些层次,我们需要了解并使用许多工具,并遵循各种流程。 在花费大量时间处理那些本应简化我们工作的事情时,专注于实际工作并创造价值变得困难。 这就是所谓的 认知负荷 。最早由丹尼尔·布赖恩特(Daniel Bryant)提出,这个术语概括了许多开发者以及其他 IT 专家的工作过载和心理压力, 以及其他 IT 领域的专业人士。 减少认知负荷能带来更多的幸福感和满足感,同时也能提升工程师的效率和可靠性。 看一下下面的图示,可以简化我们在不同时代作为专业人士需要处理的事务的视角。 然而,往前看,我们必须减少这种负荷。 人工智能可能是其中的一部分,此外,还有运行计算过程的新概念,以及 平台,当然也在其中。
图 1.4:扩展的认知负荷及其对理想未来的预测
不仅仅是 技术随时间变化,它还会不断积累。 这意味着我们不仅要运行和维护遗留系统,还要改变架构风格,引入新的编程范式和新工具。 这也改变了职责范围,并且大大超出了几年前职位描述中的典型边界。 拆解这个问题可以揭示出是否需要一个平台来解决我们的难题,或者实施一个平台是否会再次增加 复杂性。
最终,每个组织都是不同的。 有些组织停留在 2000 年代初,而有些组织则不断尝试适应未来的变化。 即便在同一个组织内部,你也常常会发现巨大的差异。 一个部门可能仍然在自己的数据中心上运行所有虚拟机,而下一个部门可能将功能部署在全球 CDN 或边缘提供商上。 因此,如果你确实需要平台,制定一个愿景、战略和目标就落在了你身上。
我们所经历的复杂性以及对工程师施加压力的行为需要被面对,因为信息技术随着时间的推移往往变得更加复杂。 在接下来的章节中,我们将重点讨论为开发者实施正确的解决方案,以克服我们正在走向的那个麻烦方向,而这个方向甚至可能导致 职业倦怠。
实施面向开发者和产品的解决方案
在接下来的几年里,我们将见证云计算的发展。 在此背景下,平台将发挥至关重要的作用。 一方面,云将无处不在,成为基础设施的抽象。 无论它是边缘计算的形式,还是非常专业化的服务或产品,这都不重要。 另一方面,正如我们在上一节中所了解到的,我们必须专注于提供能够为开发者和其他角色带来最佳体验的环境,这样他们就可以专注于创造价值。 将这些元素实践性地结合起来是 IT 组织跟上市场步伐并为公司持续创造价值的关键能力。
普遍存在的云
普遍存在的云 并非 单一的解决方案。 它聚集了多种正在经历 转型性变革的云计算能力,以显著推动业务和创新。 关键的进展专注于将云技术整合到任何地方,从私有数据中心、分布式计算网络到边缘计算。 然而,普遍存在的云不仅限于此。 它遵循通过传感器、物联网组件、移动设备和其他智能连接解决方案来弥合物理间隙的概念。 因此,它也被称为 无处不在的计算、 环境智能、 或 无所不在。
Gartner,这家研究公司,认为以下六项技术将塑造普遍存在的云并定义其 特性 [3]:
-
增强型 FinOps:将 DevOps 方法与成本优化 和预算管理相结合
-
云开发环境 (CDEs):简化和统一开发 环境,减少人为错误并 确保可重现性
-
云可持续性:实现 环境、社会和经济效益,减少云计算技术快速增长带来的有害影响,并利用其力量 造福社会
-
云原生:实现之前定义的 云特性
-
云端扩展至边缘:CSP 能力扩展至 边缘
-
Wasm:一种潜在的无处不在的运行时和二进制格式,适用于各个地方,但不 一定适用于所有事物
然而,我们 需要问自己,为什么这些现在对我们作为平台工程师、架构师 和开发者有意义。
首先,你可以在这些定义和假设中找到我们已经在使用的许多技术。 云原生、FinOps、边缘计算和 CDE 已成为日常现实,而可持续 IT 和 Wasm 在近年来经历了大量开发。 这一切都与明确表明我们讨论的不是未来 100 年内无法实现的科幻技术相关。 它正在发生,且已准备好投入使用。 我们开发并创新了所有这些基础;它们可能不像 GenAI 那样显而易见和突出。
其次,为了从云投资中提取最大价值,企业必须采用自动化的运营扩展,利用云原生平台工具,并实施有效的治理。 这些平台集成了 SaaS 等关键服务, 平台即服务 (PaaS),以及 IaaS,以创造具有模块化功能的综合产品。 鼓励 IT 领导者利用这些平台的模块化特性,以保持在快速变化的市场环境中的适应性和灵活性。 想象一下,在没有一个能够驾驭这些广泛变化的的平台的情况下,环境会有多复杂。 尽管如此,面对所有这些复杂性,我们仍然需要保持产品思维,否则在未来提供可靠的 IT 服务和解决方案将变得困难。
图 1.5:云概念在普遍的云中无处不在
查看 前面的图示,你可以发现无处不在的云元素。 我们不应该把这张图看作是独立的项目。 一切都是相互连接的。 手机上的应用与云端或本地集线器中的服务进行通信,企业有多个网络将不同的计算环境连接在一起,而我们完全忽略了更进步的概念 例如 Web3 在这里。
重要提示
信息技术正经历着一场重大的变革,无论是可见的还是不可见的领域。 随着我们迈出的每一步,我们在增加其复杂性的同时,面临着人口压力和专业人才短缺的挑战。 迟早,大多数公司将需要拥有自己的平台。 如果他们 没有,他们将购买 作为服务。
专注于开发者体验
希望每个开发者都能在没有过度疲劳的情况下,涵盖广泛的工具和技术领域,是不可持续的。 因此,用户体验的质量在决定平台的采用和成功中至关重要。 一个设计良好的平台意味着它是直观的,易于导航,并与开发者的期望和工作流相一致。 提升体验包括简化互动、最小化摩擦点,并提供一个视觉、技术和功能上都令人愉悦的环境。 这不仅提高了用户满意度,还提升了生产力和参与度。 这不仅提升了用户满意度,还增强了生产力和参与度。 问题是如何 实现这一点。
我们必须考虑到每个开发者在设计平台时可能有不同的偏好。 这直接涉及到平台与用户之间的互动问题。 开发者可能会提出各种问题,例如: 我们需要设置一个门户吗? 在 Git 服务上推送代码就足够了吗? 我可以通过 CLI 与平台互动吗? 这些问题可能难以回答,但成功的平台提供了所有这些互动。 从 API 中心的方法开始,将使得任何其他路径可以同时进行。 强大的 API 是一个好平台的核心。 实际上,大多数平台仍然提供多种不同的接口。 快速发展的工具将统一这些接口,从而克服这些挑战。如果考虑到在全新环境下构建,它可以直接嵌入到 核心中。
这样一个核心的例子是 Kratix。 这个 Apache 2.0 许可的开源平台自称是一个“… 用于构建可组合 IDP 的平台框架。” 在下图中,你可以看到 Kratix 如何在我们今天使用的所有常见工具之间定位自己,并提供一个 入口点。
图 1.6:Kratix 作为中央集成组件的概述
Kratix 通过 Promises的概念实现这一点,它本质上是一个 YAML 文档,定义了平台与用户之间的契约。 每个团队都必须经历一个复杂的入职过程,这并非由于平台本身,而是由于其他依赖项,如 CI/CD、Git 仓库以及将一切连接在一起。 通过 Kratix Promises,你可以将所有这些步骤封装起来,或者将多个 Promises 合并为一个。
目前,Kratix 支持简化平台基础架构以提升开发者体验,但仍然缺少一些内容。 问题的另一面是开发者门户。 Backstage 是一个由 Spotify 开发的开源 Apache 2.0 许可证解决方案的示例。 Kratix 与 Backstage 配合得很好,且实现了无缝集成。 Backstage 是一个框架,旨在声明式地创建图形用户界面,统一基础设施工具、服务和文档,从而提供极佳的开发者体验。 Backstage 有三个核心特性:服务定义、Backstage 服务目录和插件系统,通过它你可以启用其他功能,例如文档。
图 1.7:Backstage 的三个核心特性
此时,我们 已经看到了需要解决的挑战,并且我们已经对解决方案空间有了初步了解。 这应该能让我们在深入探讨接下来的章节中的细节之前,感受到当前的可能性。 下一章将继续探讨具体内容。
平台的属性
一个平台 必须具备某些属性,并提供一些核心组件,使我们能够向最终用户提供功能。 到目前为止,我们已经了解了需要处理的所有复杂性、需要集成的内容以及在创建最佳体验和产品时如何专注于最终用户的思维方式。 所有这些都必须与技术、过程或方法论的方式相匹配,以形成属性。 对于你平台的理念开发,我们只能鼓励你先研究这些属性,然后决定最适合你的解决方案,而不是先选择一个解决方案并围绕它构建对你情况的适用性。
一些属性,比如减少认知负担、将平台视为产品或开发者/用户体验,已经得到了很好的覆盖。不过,仍然有更多需要考虑的:
-
灵活性、可调性和可组合性:平台应该提供灵活性,允许它们以不同的方式被使用和与其他系统集成。 通过支持模块化和可组合的设计,用户可以根据自己的具体需求自定义和扩展平台,添加可选功能,而不会被不必要的功能所困扰。 这种方法使平台能够为拥有多样化需求的广泛用户群体提供服务,同时 保持简洁性 和可管理性。
-
安全:安全是必须嵌入平台设计和架构的关键属性。 默认安全 意味着 平台在开箱即用时采用最佳安全实践和配置。 用户应该拥有强大的 安全措施,无需进行大量配置。 这包括数据加密、安全访问控制以及定期安全 更新以防范漏洞。
-
自助服务:启用自助服务功能使用户能够执行设置环境、部署应用程序和访问服务等任务,无需等待 IT 支持。 这种能力不仅加速了工作流程,还减少了平台团队的运营负担。 自助服务门户应用户友好,并提供所有必要的工具和权限,使 用户能够独立管理他们的 任务。
-
文档和支持:有效的文档和入职培训对于赋予用户权力和减少与平台相关的初始学习曲线至关重要。 全面、清晰和易于访问的文档确保用户能够自主解决问题并了解平台的能力,而无需外部帮助。 入职过程应该指导新用户了解平台的核心功能和功能,使他们从 一开始就感到能力和信心。
你可能已经意识到,这些属性在某种程度上符合本书的大纲,因此它们是我们设计和规划的灯塔 平台。
有时,这些 属性可能过于软化,无法作为实施的参考点。 这一问题的替代方案被内部开发者平台社区(https://internaldeveloperplatform.org/)描述为 IDP 的五个核心组件 [4],我们鼓励您查看作为 替代来源:
-
应用配置管理:以动态、可扩展和 可靠的方式管理应用配置
-
基础设施编排:根据上下文以动态和智能的方式编排基础设施 方式
-
环境管理:使开发者能够在需要时创建新的并且完全配置好的环境 。
-
部署管理:实施持续交付或甚至持续部署的交付流水线 。
-
基于角色的访问控制:以可扩展的方式管理谁可以做什么 。
在 第二章中,我们将详细讨论平台的组织和技术方面,以及制定一个可实施计划来将你的平台打造成一个 产品。
关注开发者视角意味着影响组织,从而影响为其工作的人们。 接下来,我们将探讨在 创建平台时需要考虑的社会技术因素。
理解社会技术方面
设计一个 成功的平台不仅仅涉及技术能力;它还需要深入理解用户的多样化需求,从早期阶段开始促进和激励协作,并创建一个欢迎平台文化的开放环境。 平台工程的这些社会技术方面是至关重要的视角,它们不仅强调平台的技术组成部分,还强调人类元素——个人和团队如何与系统互动,系统如何影响他们的工作和行为。 理解这一常常不可见的部分 在创建平台时至关重要。 它是将技术上强大的系统与深度整合的日常工作流和用户行为联系起来的粘合剂。 尊重这一几乎元层面的因素意味着通过高满意度提高生产力并推动采用。 我们必须承认,每一个技术决策都具有后果,既影响技术本身,也影响人类。 因此,设计能够与用户产生共鸣的平台,促进协作文化,推动创新,并让日常工作变得更加轻松是很重要的。 通过关注这些社会技术方面,平台工程师可以创建出更具适应性、可持续性和以用户为中心的系统,这些系统能够在不断发展的 云原生环境中经得起时间的考验。
然而,我们必须意识到,我们的互动是在一个社会技术系统中进行的。 挑战在于,我们在工作、个人和私人环境中不断发生摩擦和优化。 工作环境代表着你在专业领域中的所作所为。 个人环境是一种以“我”为中心的视角,分享着与任何与你接触的人的经历,可以是工作或私人方面的内容。 最后,私人环境是别人可以估计和观察到的内容,也就是发生在你关闭门后但可能对你的观点和视角产生影响的事。 这种不断的变动和调整发生在公司或项目结构、人员、技术以及他们的任务之间。 在此过程中,我们有不同的影响因素和激励驱动因素。 以下的表示应能可视化这一持续的运动。 子系统和系统本身有其自身的规则、活动, 和权力。
图 1.8:社会技术系统,Trancossi 等人。
当我们 在确定实施平台的最佳方法时,试图了解需求、建立社区,并倡导开放时,我们必须意识到这一切都受到并发生在一个社会技术系统内。 有时我们可能会被阻塞或被推向不同的方向,或者发现很难激励人们。 这是花些时间理解子系统和外部系统推动你的时机。 这些子系统和外部系统正在 推动你。
理解平台设计中的用户需求
平台 设计必须本质上具有灵活性,以容纳比开发人员更广泛的利益相关者。 我们不能说得太多,但实施一个平台是一个全员参与的决策。 软件工程师、产品负责人、业务利益相关者和操作团队都有独特的需求和挑战,他们期望平台能够应对。 开发人员可能寻求简便的部署和测试工具,而最终用户需要直观的界面和无缝的互动。 与此同时,业务利益相关者很可能主要关注 投资回报率 (ROI)、安全性、治理、合规性和可扩展性。 作为平台工程师和架构师,你有责任识别这些需求,并在平台生命周期中保持平衡。
因此,第一步 在以用户为导向的平台设计中,是准确识别和理解与平台互动的不同利益相关者群体。 在早期阶段,可以通过访谈和调查来获得清晰的了解。 考虑从 360 度角度来看,记住采访一个人多于采访太少的人通常更好。 在后期阶段,更加依赖数据是有帮助的,可以使用平台各个组件的使用数据。 服务请求和帮助台上的未解决问题将是衡量平台可用性的良好指标。 此时,将平台视为产品并拥有产品思维是至关重要的,因为你必须从开发的最早阶段到整个产品生命周期中都考虑用户反馈,确保平台具有可访问性、直观性和高效性。 虚荣心的错觉肯定会将你的努力引向错误的方向。 定义诸如透明性或简洁性等原则会很有帮助,它们能指导你通过开发和决策过程。 在接下来的章节中,我们将深入探讨这个话题 。
为了保持相关性和效率,平台必须不断发展。 记住,项目在遇到截止日期时就会结束;产品则随着每次发布和用户反馈不断发展。 建立健全的发布文档和反馈循环对于这一迭代改进过程至关重要。 哪个渠道最适合你的组织和用户是你需要决定的,但除了调查和访谈之外,还有许多其他方式。 例如,通过沟通工具的直接互动、用户论坛、支持解决方案,甚至是内部企业社交媒体,或者在极端情况下,平台本身内嵌的反馈机制。 由真实用户体验和挑战定义的定期更新和升级,确保平台始终与用户需求和行业标准保持一致,促进忠诚度并 保持持续的参与。
促进和增强协作
透明且开放的反馈循环问题在于,它们需要良好的协作架构。 否则,它会显得不自然,从某种意义上说,就像传统的需求工程方法。 作为平台工程师,我们必须将这些经典方法包装成一种更具个人化和欢迎感的方式。 有效的协作是任何成功平台的基石。 通过整合合适的沟通工具,通过定制提供卓越的用户体验,并倡导跨职能团队合作,平台不仅能成为技术解决方案——它们还能成为不同开发团队之间的合作场所,并推动组织 和创新。
为了促进 合作,你的团队和平台必须是开放和欢迎的。 减少任何形式的障碍,使新产品团队能够顺利加入,并为他们提供不同呈现方式的起始点。 必须清楚地说明如何以及在何处联系你的团队以解答各种问题。 这在新用户团队加入你的平台的初期尤为重要。 消除任何隐性期望,即大家清楚地知道如何以及在哪里找到你的团队,因为通常并非如此,尤其是在大型组织中。 这要求你和你的团队成为平台的倡导者,并通过内部公共文档和登陆页面进行宣传。 你必须走出去,与其他团队合作,倾听他们讨论挑战,展示你的解决方案。 在可能的情况下,你必须向你的组织传达新功能和使用场景,并 不断向他们展示如何轻松 开始使用。
培养开放的、以平台为中心的文化
培养 一种开放和以平台为中心的文化可能是最难的部分。 这需要来自你组织内其他预算管理角色的支持,除了你自己的参与之外。 培养依赖于培训、激励(可能会有激励措施)和与社区或用户群体的互动。 所有这些活动超出了你的 预算责任。
培训可能看起来是一个昂贵且耗时的活动,而且很快就会过时,但几乎没有比这更好的方式能与最终用户进行紧密且真正开放的接触。 综合培训项目结合了不同的方法 和来源:
-
专注于平台各个组件的面对面工作坊 你的平台
-
入职培训的实践环节,以及一个简单的首次项目或特定的集成,这些 不会太复杂
-
自助教程
-
在线/视频教程 用于通用内容
-
在线/视频教程用于 你的特定需求
如你 所见,你不必一切亲力亲为。 购买常见知识的课程和培训,并提供你自己的内容来深化这些知识,教授你的平台特性。 此外,考虑创建一个资源库和维基,包括常见问题解答、最佳实践指南、故障排除技巧、代码片段和示例、用例推荐以及事后分析等。 这可以帮助用户更有信心,并减少新 技术采纳的学习曲线。
为了保持动力,培训和平台使用可以结合激励措施。 有不同的激励策略,如游戏化、表彰计划和基于绩效的奖励,可以鼓励平台的积极使用。 对于大公司,我们甚至见过内部徽章计划和 云驾驶执照,这些通常可以与官方认证结合。 但同时,你需要小心不要设定过高的人工障碍。 那样反而会适得其反。 理想情况下,你的激励措施应该能够激发新用户的兴趣,并为专家提供挑战。 例如,它们可以与现有的绩效指标整合,强化一个重视持续改进和有效利用技术的文化。 通过这种方式,你还可以通过定义的 KPI(如成本降低、绩效提升、 和稳定性)影响企业目标。
最后,我们需要将所有这些方法结合起来。 最好的方法是创建一个社区。 我们可以通过用户小组、定期聚会和论坛来建立这样的社区,让用户分享知识、共同解决问题,并相互提供支持。 为了培养一个社区,我们强烈建议你寻求 C 级高管和市场团队的支持。 这听起来可能很简单,只要把人们聚集在一起,似乎一切都会顺利。 实际上,这是一门完整的学科,需要探索吸引社区成员的策略、促进富有成效的讨论,并培养用户之间的归属感和责任感。 在用户中。
没有人,且不尊重他们的需求,你的平台要么很快被放弃,要么从一开始就无法获得任何吸引力。 专注于培训、激励和繁荣社区的战略举措可以加速开放、以平台为中心的文化。 为了提高平台的有效性,你必须超越其纯粹的技术部署。 这种整体性的方法确保了平台成为组织的基础组成部分,推动创新和效率在各个层级和利益相关者之间流动,从开发者和运营到业务和 流程所有者。
总结
在本章开头,我们探讨了平台在现代软件开发中的作用,特别是在云原生环境中的作用。 我们已经确定,平台不仅仅是基础设施元素,它们是需要战略规划和持续改进的基本产品,以适应不断变化的技术和 业务需求。
你已经了解了平台的基础知识,并且意识到平台结合了软件开发、运营和部署,形成了一个紧密的环境,具有全面性。 在此基础上,你看到了平台作为产品思维方式为何是一个关键组成部分。 它包含了持续开发、用户参与以及对反馈的响应,以保持其相关性 和价值。
接下来,我们讨论了简化开发者与平台交互的重要性,显著减少了认知负荷和操作复杂性。 两个简短的工具示例应该激发你对后续章节的好奇心和兴趣,同时也向你展示了所有这些复杂性和挑战 都是可以解决的。
在最后部分,我们了解了社会技术层面的因素以及人类因素的显著相关性。 平台必须同时考虑技术能力和人类因素,确保它们支持用户的工作流程、协作和生产力。 为此,我们介绍了三个支柱:在设计解决方案之前理解用户需求、促进和增强协作,以及培养开放的、 以平台为中心的文化。
这些课程应该激励你深入了解平台架构以及如何构建它们,因为它们提高了运营效率,并在组织内促进了创新和敏捷性。 通过内化这些概念,平台工程师和架构师可以设计出既稳健、以用户为中心,又能适应变化的解决方案,同时为 他们的组织创造真正的价值。
从人力资源方面转向架构,我们将探讨如何定义平台的原则和目标,如何定义平台架构,以及如何衡量平台在下一章中的成功。
进一步阅读
-
[1] CNCF 年度调查 2023: https://www.cncf.io/reports/cncf-annual-survey-2023
-
[2] 关于 IDP 成功的案例研究:
-
[3] Gartner 2023 年新兴技术的炒作周期: https://www.gartner.com/en/articles/what-s-new-in-the-2023-gartner-hype-cycle-for-emerging-technologies
-
[4] 内部开发者平台的 5 个核心组件(**IDP): https://internaldeveloperplatform.org/core-components/
第二章:理解平台架构以构建平台作为产品
在这一章中,你将被引导完成所有相关的基础工作和创建平台架构的方法。 首先,你将学习到平台原则,以及它们如何成为你平台战略的引导部分。 这将帮助你保持正确的方向,专注于最重要的事情。 我们将通过定义你平台的目标来结束这部分内容。
从这里开始,我们将定义你的架构。 你将学习到平台的组成部分、平台的可组合性,以及如何处理依赖关系。 接下来,你将学习如何为你的需求创建参考架构。 为了给你带来新的视角,我们收集了几个平台作为产品的 用例。
最后,你将学习如何用 最简可行平台 (TVP) 开始你的平台之旅,以及如何通过相关的 关键绩效 指标 (KPIs) 使平台的采用变得可视化。
你将在 第二章 学习到以下内容:
-
理解平台原则并定义你的平台 和团队的目标
-
探索平台架构——层次、组件, 以及元依赖关系
-
探索平台作为产品——用例 和实现
-
理解 TVP(平台作为产品)
-
通过相关的 KPI 来使 采用过程透明化
理解平台原则并定义你的平台和团队的目标
你需要两样 主要的东西来为你的平台开发合适的架构并遵循它。 首先,你必须定义引导你前进的护栏,以及开发和运行 你的 内部开发平台 (IDP) 作为产品的步骤。 第二,你需要理解你的目标是什么。 这不仅仅是架构,更是支撑你平台的已识别和定义的目的。
将原则作为决策的护栏进行引入
原则 可能听起来像是来自被遗忘的企业架构师时代的老派方法,或者非常僵化的组织。 在一切变得敏捷的时代,原则是积极决策的基石。 它们有助于缩短讨论时间,并专注于平台交付。 原则与能力或属性有何不同? 平台的能力是 IDP 可以提供或提供的功能。 想象一下你需要文件存储,通过在平台内应用资源定义的规范,系统为你提供一个符合 S3 标准的存储桶。 属性是所提供能力的超集,可以主动或被动消费。 如果你定义了一个安全平台,那就是属性,那么这可能结合了节点的硬化 、 常见漏洞和暴露 (CVE) 扫描,以及网络加密和严格的 基于角色的访问控制 (RBAC) 规则等。 一个 原则帮助你决定如何实现这些能力和属性。 因此,你通常会遇到两种类型 的原则:
-
通用原则:这些 是面向全组织的计数方向点。 近年来的一个常见例子是: 数据是资产。这意味着: 以下含义:
所有数据对组织都具有价值。 它是一个可衡量的资源,我们采取措施保护并 使用它:
-
对于每个数据源,某人 负责
-
数据对每个人可用 。
-
我们将保护数据免受丢失和 安全威胁
-
-
具体原则:这些 是面向特定用例的原则,可能与其他人相关,但旨在针对少数人或专家。 来自安全领域的一个例子是: 任何活动都由身份定义。这可以解释为: 如下:
-
系统中的每个过程都会记录一个身份 。
-
未知身份应立即 报告
-
每个系统都需要 用户身份验证
-
牢记 这两个原则将在你设计场景架构时,引导你做出不同的决策。 你会发现,特定原则看似描述了一个部门的显而易见的期望。 但如果你想确保事情按照你期望的方式完成,绝不要假设或隐性地期望某些事情。 你想要它的样子。
重要提示
定义 明确 规则、指南和框架,如果你对某个人的活动结果有特定的期望。 隐性 要求对方能够读懂你的心思,并拥有与你相同的世界观 。
平台和平台工程原则示例
在帮助你定义自己原则之前,我们想给你提供一些关于 可能原则的 建议:
-
关注共性问题:识别并优先解决那些能够帮助你组织中多个部门或人员的问题。 通过消除共享问题和滚雪球效应的难题,防止他人重新发明轮子,这些问题如果没有处理,会逐渐变得更大 和更严重。
-
不要重新发明轮子:研究市场上能够满足你需求的潜在解决方案。 定期检查自制的解决方案,寻找标准化的替代品。 市场发展比我们快。 专注于创造价值,而不是 内部依赖。
-
每个客户都很重要:你平台上的每个用户都至关重要,从大型系统到小型产品。 平等地收集和评估每一条反馈。 以同样的方式满足每个人的需求和要求,并提供相同水平的服务。 将这些反馈视为定义你 发展路径的主要方式。
-
消除浪费:我们将构建一个尽可能高效利用资源的平台,并帮助我们的客户尽可能优化资源。 我们推动资源消耗的透明度,并提供扩展、减少和调整工作负载的选项。 我们共同开发最佳实践,帮助开发人员了解如何配置和使用先进技术以实现 更大的灵活性。
-
平台就是一种产品:每个决策都要保持产品思维。 关注为你的内部客户(如开发人员、运营人员、安全人员等)提供真正价值的内容。 确保功能能够快速发布,并且有短的反馈循环。 识别那些由非价值驱动的技术带来的干扰。 你最高的目标是让你的客户愿意使用你的平台,而不是 强迫他们。
-
内部源代码:你平台的每一行代码都对你的内部组织开放。 问题和故障会公开跟踪,并且它们的解决方案会 被记录。 在相关情况下,保持一个常见问题解答(FAQ)。 任何人都可以提出功能、修复漏洞、提交代码和文档,以改进你的平台。 推动社区活动,促进你与 所有用户之间的交流。
这些原则试图涵盖不同的观点和细节层次。 哪个适合你很难说。 如果你发现它们 不起作用,不要害怕随着时间调整措辞或原则。
产品思维作为核心原则
你的内部客户应该希望使用你的平台。 他们不应该被 强迫使用。
定义你自己的原则
一旦你 适应了原则的理念,所有原则看起来都不错,对吧? 现在,挑战是以团队能够采纳的方式定义并写出这些原则。 它们需要融入你的用词,并与公司内部定义 类似元素的方式相契合。
原则可以来源于你的公司价值观、客户反馈或团队的内部研讨会。 无论你做什么,关于原则的来源保持透明非常重要;否则,团队可能会感到被排除在外。 你还需要对它们进行几轮迭代,精炼措辞,并将其浓缩到最基本的内容。 与所有原则一样,它们不应过长,但也不应过短。 句子应简洁明了,不应包含嵌套或条件。 条件往往意味着你对原则不确定,或者说明它可以分成两个原则。 合适的长度是:你只处理一个主题,给出两到三句解释,也许还加上一些动机 或合理化。
我看到过两种非常高效的写作方式,它们在定义原则和寻找常见引用及适应性时非常有效,有时,这些原则出现在 Slack/Teams 的频道描述或 电子邮件 页脚中。
命令和合理化
命令和合理化方法通常适用于那些层级较强的组织,在这些组织中,平台团队可能刚刚成立,或者整个倡议会被持怀疑态度审视。 这要求在初始化时有更严格的指导。 然而,我认为这些原则应随着时间的推移进行调整,并应收集平台工程团队和最终用户的意见。
以下是一个大纲,展示如何 编写它:
-
标题:每个原则都有类似标题的内容,应该牢记在 脑海中。
标题后应跟随 命令列表:
-
初始命令设定了 方向。
-
接着,应说明为什么 这很重要。
-
之后,应该考虑一些更详细的操作 步骤。
-
然后,应再给出一个行动 或理由。
-
在这里,责任应交给 读者。
-
这是基于前述大纲的一个示例:
-
标题: 自服务优先:
-
每个平台功能必须能够由最终用户使用,而无需与平台 工程团队进行交互。
-
这使得用户能够自我决定,并减轻平台和 DevOps 团队的工作负担。
-
不要规定具体方法,而是通过 最佳实践进行引导。
-
打开最终用户部署完全透明的可能性,并允许对 操作数据进行细粒度的访问。
-
你提供的是一套极有价值的工具和自动化系统,简化了软件的开发 和运营。
-
正如你所见,这种风格告诉读者该做什么。 标题很有力地表达了, 无论你做什么,首先要考虑让它可自服务化。首先处理这样的数字风格命名。 如果每个原则都以“首先”,“首要”或 “总体”命名,这样的做法就行不通了。 然而,在这里,你可以看到,所有你写下的潜在原则中,这个原则永远是第一位的,并且很可能会凌驾于 其他原则之上。
第二至第四句详细说明并合理化了第一句。 它们提供了支持的论点和考虑的指导原则。 结束语和标题或第一句话一样重要。 这必须是一个交接语句。 它像是号召行动,但并不是要求别人做什么——这是前面句子所要表达的。 它必须以个人层面来表达,直接对读者说话。 请查看下面的示例列表,了解如何为原则做结尾的其他想法。 一个原则的结束语。
平台团队将随着时间的推移增长他们的内部信任和动力,这需要一种不同风格的 原则。
我们将…
成熟的平台工程团队 和年轻的组织需要能够触动他们 我们 情感的原则。 这几乎就像是兄弟姐妹般的誓言。 然而,你也需要充分了解你的团队,并谨慎处理。 并非每个人都喜欢这种定义原则的方式,因为它们呼吁强大的纽带和沟通。 这只是一个个人问题,没有负面影响,但如果忽视它,你可能会失去宝贵的团队成员。 这就是我如何定义 我们 将 的原则:
-
大纲:
标题:标题保持不变;简洁有力,简短精炼, 就是这样:
-
第一句话通常结合了原则的意图,并包括帮助说明,以 合理化它
-
接下来的 句子都在定义更多的目标 或方法
-
每个句子将以“我们”,“一起”,“作为一个团队”,“为了我们的客户”等开始, 以此类推
-
-
示例:
标题: 自服务优先:
-
我们将以自服务的方式为客户提供每一项平台功能,专注于他们的用户体验 (UX)并支持自主决定 软件开发
-
我们提供最佳实践,并在定义最有效的方法上进行合作。 这些方法最有效。
-
我们共同创造一个透明、创造价值的环境,促进自动化和以最终用户为中心的功能,以简化软件开发 和操作
-
你对这种方法有何看法? 我保持了相同的原则,这样你可以做一个并排对比。 你支持哪一个?
你可以看到, 我们将 更加简洁,但稍显复杂。 这是因为你需要直接面对团队,告诉他们需要关注什么,并用一句话解释背后的理由。 将其切割成短句会失去同样的效果,可能会传达错误的信息。
两种方法的结合可以很好地发挥作用,帮助你识别哪种方式更适合你的团队。 然而,平台团队对这种混合方式感到满意并不罕见。 如果你有四到六个原则都在呼唤你的 我们 的感受,这可能会感到沉重,但如果有一长串 命令,它可能会给你带来很大的压力。
以下是这部分内容的总结: 在下面的列表中: :
-
原则是你在架构和 工程决策中的有益护栏
-
四到六个原则 是最有效的
-
如果你不确定,可以从较少的原则开始,并与最终用户和平台工程师一起识别 接下来的原则
-
经常检查你的原则,看看它们是否仍然适合你的团队,但不要每几 个月就改变它们
将平台的目标发展成一种产品
要成功地 开始构建一个平台,我们需要定义其目标和方向,以及如何构建或重构平台工程团队。 这一步骤还帮助你对之前定义的原则进行首次迭代。 反思你自己的看法,并挑战你最初的定义。 这将帮助你学习如何整合两种不同的力量和 相互矛盾的目标。
一开始将平台作为产品看似简单。 改变思维方式、与客户沟通并提供一些良好的功能,这些就是你需要做的。 然而,这只是故事的一部分。 我们需要让你意识到,云原生平台有潜力成为你组织的软件开发、交付和运营的核心动力。 因此,我们将向你介绍一些不同的概念,这些概念你也能在其他组织理论和实践中找到,例如看板(Kanban)、精益起步(Lean Inception)或 团队拓扑学(Team Topologies)。
理解你自己的价值
如果人类 在某一方面确实非常糟糕,那就是做估算。 没有尺度或参考点时,我们很难做出正确的估算。 比如,我问你,平台对你组织的价值是什么? 你可能会提出这样的论点,比如更快的软件开发周期、更少的运营开销、以及减少招聘成本的快乐工程师。 这些说法都没有错,但也没有什么是精确的。 用商业术语来说,平台作为产品的价值在于它促进了市场时间的缩短,或者优化了延迟成本的灵活性。 换句话说:你将服务推向市场所需的时间越长,你创造的价值就越少。 一个好的平台将通过提供高度的灵活性和速度来帮助你优化这个价值, 从而为实施团队提供支持。
在 延迟成本 成本理论(cost of delay) [1]中,假设容量 是固定的。 如果你想实施三个项目,你需要决定从哪个项目开始。 每个项目带来的价值不同。 如果你同时启动所有三个项目,假设的情况是你能在同一时间完成所有项目,但无论是依次进行还是同时进行,你的速度都不会更快或更慢。 有了一个支持自助服务、高度自动化和自治、可靠性等的 IDP,你可以减少对可用容量的依赖,从而允许多个项目同时实施。 进一步思考,这也是为什么公共云服务提供商如此成功的原因之一。 然而,随着复杂性的增加和角色定义的错误,这些好处变成了障碍。
图 2.1:没有平台与有平台的延迟成本
前面的图展示了在没有平台和有平台的情况下实施项目的区别。 左侧我们可以看到至少有两个延迟,这意味着第二个项目在年末或某个期间开始提供价值。 这种延迟可能是由手动流程、对其他团队和团队成员的依赖,或者没有彼此集成的各种技术步骤所导致的。 右侧,项目的同时启动将由于非常好的平台带来显著的价值增长。 请记住,下面的区域代表的是 价值。
重要提示
云原生平台,如 IDP,正在打破延迟成本理论,使得快速且早期的价值生成成为可能。 平台越好,对能力的依赖越少,团队实现和运营产品的效率越高,你的组织能创造的价值就越多。
从系统到平台作为产品
最终,一个产品无非是由客户需求、你的 业务 利益、一些技术以及整体用户体验(UX)构成的服务对象。 如果缺少这些元素中的任何一个,你的产品将会失败。 在项目的世界里,我们有三个基石在不断拉扯着彼此:时间、金钱和范围。 这被称为 铁三角 。在这三个方向之间找到平衡需要仔细的调整。 但由于我们希望摆脱项目视角,我们将在这里介绍产品的铁三角。 它由可行性、可取性 和可行性组成。
图 2.2:产品的铁三角
我们可以在这种平衡中找到不同的力量在拉扯产品。 所以,我们必须问自己以下问题:
-
我们为客户 和用户解决了什么需求或任务?
-
我们的客户想要什么? (通常,他们 并不知道。)
-
我们如何使 它运作起来?
-
我们应该使用什么技术? 该使用什么技术?
-
我们如何才能从中建立一个可持续的业务 呢?
我们现在可以将这种产品视角与 平台视角结合起来。
“数字平台是一个由自服务 API、工具、服务、知识和支持组成的基础,这些要素被安排成一个引人注目的内部产品” 甚至 Bottcher 曾这样描述过一个平台 [2]。此外,他还说,“自主交付团队可以利用平台以更快的速度交付产品功能,同时 减少协调。”
平台和产品有很大的重叠。 两者都 具备以下特点:
-
他们必须倡导其有用性并将其推广到 内部团队
-
它们应该经过精心设计 并且准确
-
它们是以用户为中心设计的,或者更好的是,与用户/开发者共同设计(关注 UX/DevEx)。
-
他们随着时间推移不断发展提供的能力,并且需要一份 清晰的路线图。
在开发 平台作为产品的清晰愿景和目标时,应考虑并检查这些方面。 你会自然发现,对于产品铁三角,两个角色会被 立即分配。
平台的产品负责人将处理可行性,而平台工程师将处理可行性。 但几乎每个组织都缺少负责可取性的人。 这个 角色通常被称为 开发者 体验 (DevX)。
没有 DevX,一个平台工程团队 是不完整的。
重要提示
平台的产品负责人处理可行性。 平台工程师处理可行性。 DevX 负责可取性。 这些角色定义了平台作为一个产品的成功。
利益相关者及其对你的待办事项的影响
谈论 利益相关者和客户时,企业内部世界展开了一幅由许多有不同利益的人组成的景象。 为了聚焦重要内容,我建议将他们分为 三组:
-
用户:真正会使用你的平台/产品的一群人。 在我们的案例中,使用者将是开发者 或 DevOps 人员。
-
客户:具有预算决策权和/或为整个团队、部门做出决策的人, 或类似角色。
-
影响者:其他对你的平台感兴趣的人,如安全团队或 运维团队。
你正在 为那些利益相关者群体构建平台,而不是为了自己! 在定义平台的目标时,你应当从不同的角度来看待不同的利益相关者群体。 他们的需求可能会随着时间变化,你可以通过频繁的迭代和调查来了解这些变化。 当你为待办事项定义功能时,要明确这些需求来自哪些利益相关者。 如果已经过去一段时间,通常六个月是一个合适的时间框架,那么你应该与利益相关者一起重新优先排序功能请求。 另一方面,这也会影响平台的目标。 让我们看一个 例子。
不久前,我们被要求稳定客户的平台。 我们对工作负载了解不多,但整体系统不可靠,几乎无法作为一个有用的系统。 几周后,经过一段时间的工作,新利益相关者出现了。 他们对平台产生了兴趣,因为它可以自动调整大小以适应工作负载,并且人们普遍对快速且简便的入驻过程感到满意。 此外,在之前的实现过程中,提供了严格隔离的单租户部署。 这些新利益相关者来自数据科学部门,他们希望能够轻松运行自己的模型,而不必成为专家。 他们使用的云服务提供商已经过于复杂,因为他们只专注于机器学习。 平台所有者同意提供几周的资源,用于在平台上实施数据科学家所需的工具。 尽管离完美还很远,但实现和平台足够好,易于使用,成本低廉,并且确保了所有的数据保护法规。 再过一段时间,平台团队的主要目标是为数据科学团队提供隔离的环境,这些环境配备了一整套工具,并且在完成任务后被拆除。 此外,平台仍然可以运行任何其他工作负载,目前对此没有需求。 暂无需求。
这个现实世界的例子表明,有时外部影响力比你自己的推动力更强,但它能导致更高的接受度和整个组织的采纳。 该组织的采纳情况。
重要提示
最终,你建立了一个平台,作为一个面向利益相关者的产品,主要是面向用户,而不是 为了你自己。
挑战康威定律
Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations. (Melvin Conway, 1967.)
我认为平台的主要目标之一是比目前的状态做得更好。 为此,我们必须挑战组织的现状。 公司会不断进行重组,交换责任并调整结构。 但最终,组织结构保持不变。 这就是康威的定律——至少他描述了他对组织的观察。 平台的存在是为了颠覆和协调;一方面,运用 DevOps 方法学识别瓶颈并打破这些结构,另一方面,协调专业团队的努力,形成一个 统一的环境。
作为一个平台团队,你应该首先定义你的目标和你希望遵循的理念,以便在被迫遵循组织结构之前实现你的目标。 可惜的是,这往往导致政治游戏——如何获得更多权力,如何拥有最多用户,以及谁有最好的资源来推动决策。 但不要太天真,以为拥有一个不错的平台和一些出色的功能就足以 取得成功。
因此,你需要对团队的目标有清晰的定义,以便在风雨飘摇时保持方向,在一切都想拖住你时继续前进,或者在你过于迅速和具有牵引力时保持你在正轨上。 它旨在帮助你保持 平衡。
为了将这一切汇聚起来并为你的团队和未来保存,你可以使用 平台工程目标画布 作为起点。 你可以使用以下模板(https://miro.com/miroverse/platform-engineering-purpose-canvas-template/),或者自己创建一个。
图 2.3:平台工程目标画布 [3](此图仅作为视觉参考,文本信息并非关键内容。)
由于我们专注于 设计和创建一个作为产品的平台,我们将不会进一步探讨平台工程团队的详细信息,如何建立它们以及提供正确的变更管理方法。 还有其他专注于此的书籍和方法;因此,我们建议您查看 团队拓扑 如果您对团队 开发也感兴趣 [4]。
凭借您的平台目的,我们可以逐步接受创建您的平台架构的下一个挑战。 在接下来的部分,我们将为您创建一个参考架构和其他图表,以产品的形式呈现。
探索平台架构 – 层次结构、组件和元依赖关系
您的平台旅程的导航由参考架构定义,您可以根据这一架构来调整整体实施。 架构,特别是架构图,不是永恒的。 它们是 一个框架,一个蓝图,您必须根据它们进行定位,但是随着市场解决方案的演变,无论它们是开源的还是 闭源的,它们可以并且应该随时间变化。
为了使某些部分更易于理解,我们必须为您提供一些现成的工具和产品。 因此,我们 更倾向于突出开源解决方案而不是商业解决方案。 我们不希望给您任何偏见,因此请始终注意,对于我们提到的每件事情,至少有数种选择可供选择。 我们可能选择某些工具作为参考,因为我们更了解它们,或者因为我们看到它们在社区中更常用 比其他工具。
创建架构永远不应该只包括一个视角。 与以往每个主题一样,我们必须考虑各利益相关者从不同角度看待平台的情况。 我不想为您提供传统企业架构管理工具的完整集合,但我愿意为您提供一些相关的可视化和工具。
平台组件模型
Stephan Schneider 和 Mike Gatto 在 2023 年首次提出了 IDP 参考架构模型 [5],该模型经过社区多次改进。 不幸的是,该模型缺乏一些重要的视角,要么是由于命名问题,要么是因为缺少一个所谓的 plane。 因此,我们开发了一个更为全面的模型,其中包括以下几个 plane:
-
开发者体验 plane:这个 plane 涵盖了软件开发和基础设施工程所需的所有第一层组件
-
自动化与编排 plane:该 plane 集成了构建、测试、部署、存储和编排应用程序以及基础设施的工具 。
-
可观察性 plane:该 plane 包括任何需要的工具,以提供平台及其应用程序发生的透明性和可视化
-
安全与身份 plane:该 plane 包含安全执行和监控系统、用户与账户管理解决方案,以及密钥和证书管理工具
-
资源 plane:这是一个容器,包含所有可以用于平台的计算资源
-
能力 plane:该 plane 位于平台内或平台上方,例如 Kubernetes,提供面向用户的服务
图 2.4:平台参考组件
这个组件视角 表明,平台肯定不只是一个单一的服务器,我只是安装一些容器编排或开发者门户的地方。 通常,这些组件有多个可能的部署位置。 这是一种链接,将相关的元素联系在一起。 例如,为了加强安全性,我们将在资源 plane 中找到相关的元素来遵守合规性并提供加固的配置,比如收集数据并分析的外部系统,位于 Kubernetes 中的能力 plane 之上,扫描容器并保护网络,此外还会出现在 CI/CD 中,以便只交付加固过的容器。 你可以看到,单一的主题可以存在于平台的任何地方。
平台的可组合性
一个 平台由许多不断发展的部分组成。 随着这一发展,你的用户和组织可能也会发生变化。 我们经常发现的一个巨大问题是,平台的某些部分不愿意被替换。 虽然常常会有关于优先级或预算的争论,但最常见的问题是它无法轻易替换。 有时,这是因为平台和组件已经陈旧,实际上是相互紧密结合的;有时则是因为技术选择不当,引入了一系列依赖关系,使得替换变得困难。 但也有第三个原因:将自己做事的方式强行塞入 错误的工具中。
组件化是一项原则,也许是一种意识形态,肯定是一种平台构建的方式和决策。 当组件能够相互作用而无需在其间开发中介来进行翻译时,例如脚本或无服务器函数时,组件就是可组合的。 可组合的组件可以以最小的努力,且对平台功能影响最小甚至没有影响地被替换。 Kubernetes 是一个极力支持这种方法的环境,因此它成为了构建平台的事实标准。 然而,平台的组件是分布式的,并不是所有的组件都运行在 Kubernetes 上。 这使得找到 正确的工具 变得具有挑战性。
一个通用的、一刀切的平台听起来总是不错,但它是不现实的,并且增加了复杂性。 你需要将更多组件引入平台时,组件之间难以协作的可能性也会增大。 因此,能够为特定的使用场景提供调整,而无需改变整个架构,将提高其可用性。 组件化的另一个重要好处是关注点的分离。
在 第一章中,我们 强调了平台作为即插即用专用解决方案的抽象层的目的。 严格执行组件化将会给组织层面带来大量工作,但它将允许专业团队将其核心能力直接提供到 你的平台。
要评估平台的一个组件是否可组合,你需要寻找 四种能力:
-
可编排的:它可以在现代动态环境中运行,例如 Kubernetes,而不 受到影响
-
模块化:它不需要任何其他工具或技术前提条件,但可以利用这些工具来扩展 其功能
-
可发现的:它需要与其他组件进行交互,遵循标准化的 API,或遵循像 Kubernetes 的自定义资源定义这样的概念 。
-
自主的:它必须独立于其他外部输入并自主运行 。
现在,我们知道在设计平台和选择平台组件时应该关注什么。 在接下来的部分中,你将了解那些使组件之间保持联系的东西。
依赖关系和隐藏的胶水
无论平台的 组件多么可组合 ,总会存在依赖关系和一些 隐藏的胶水。这些隐藏的胶水是组件之间流动的信息,使它们相互响应。 作为架构师,我们的工作是确保这些信息不相互矛盾。 这些信息很重要,但并不 为人所充分理解。
管理和处理依赖关系
首先,让我们通过可视化组件之间的依赖关系来构建可组合性。 为此,我们可以使用一个简单的依赖矩阵。 这个工具可以帮助你做决策并规划未来的组件。 此外,它需要一些维护工作;许多平台依赖于单个工程师的知识,并且随着平台随着时间的推移变得更加复杂,文档也会变得更复杂。 因此,映射依赖关系是实现透明度的最短路径。
在下面的例子中,我们有 工具 A-C,例如 容器网络接口 (CNI) 1-3。现在,这些 工具可以是我们之前提到的参考组件列表中的任何工具。
在依赖关系中,我更倾向于明确指出我们拥有的依赖类型。 因此,你可以使用如下内容: 以下内容:
-
单向和双向依赖:你可以使用这些来描述 工具 B 是否依赖于工具 A,或者工具 C 是否依赖于工具 B,就像工具 B 依赖于 工具 C 一样。
-
增强依赖:增强依赖会解锁更多的能力和功能,如果建立了,但并非必须。 例如,如果你有一个手动用户管理的工具,现在你可以利用 单点登录 (SSO) 来减少你的 人工工作量。
-
冲突依赖:顾名思义,这两者无法 很好地协同工作。
图 2.5:依赖矩阵
你 看过了吗? 在双向依赖的示例中,工具 B 和 C 之间的关系没有正确 显示。 在工具 C 的列中,工具 B 的双向市场缺失。 当你实现依赖矩阵时,需要提供明确的指导,以跟踪这些关系。 我认为最有用的是为两个工具都设置标记。 然而,你必须明确阅读方向,或者引入更多的标记。 例如,你可以使用 (u) 来定义一个 传入依赖关系。
依赖管理是一个持续的任务。 随着时间的推移,你可能会忘记添加新工具。 因此,无论你使用什么方法来实现新功能,创建一个自动子任务来更新依赖矩阵可能是个好主意。 一个很大的好处是定期评估这个矩阵,这可能会发现潜在的 瓶颈或问题, 你可以着手解决。
应用 x 平台 – 相互影响
这个 相互影响 是 这样定义的:它们之间是相互关联的,以至于 一个补充另一个,或者等同于另一个。 在平台与用户应用之间,你有某种程度的相互影响。 例如,一个应用需要大幅扩展。 作为平台,你支持这种行为,但同时确保它不会影响到其他应用。 另一方面,该应用选择你的平台是因为你支持它的需求。 没有用户的平台是没用的。 为了作为应用发挥最佳效果,你应该在 该平台上运行。
然而,这个例子 非常通用。 相互影响也会影响到 YAML 文件中定义的层级之外的元素。 它也是没有被要求却自然而然产生的需求和要求;它是两个实施方之间的团队动态;它还体现了一个解决方案如何影响其他解决方案的方式 他们的工作。
因此, 依赖 这个词并不适合用来描述这种关系。 它是一种共存,一种协作,朝着相同的方向一起前进。 对于平台工程团队,尤其是作为架构师的你来说,在设计解决方案时,必须始终牢记这种相互影响。 要让这一点成为你的超能力,你需要教育平台工程师和用户了解这些影响,并专注于如何让他们从平台中获得最佳效果,同时不会感到 任何限制。
相互影响
相互影响是应用与平台之间的无形互动。 将其理解为一种共同的力量,使得平台和用户的应用能够比没有彼此时更好地融合在一起。 相互依赖。
另一个地方这种相互影响变得可见的是 在过程当中。 在过程中。
平台的过程定义机会
平台工程 借鉴了许多 DevOps 方法论中的做法。 在 DevOps 角色中,一些部分侧重于自动化。 这些自动化步骤转换为定义流程。 因此,我们也可以说,平台工程师为其创建技术流程,以便作为产品在用户导向的方式中实施。 然而,这些程序在明确的设计决策中并不常见。 流程的形式(或流程的样子)取决于某些组件的工作方式。 关于平台可组合性,这可能是一种固有的方法,但我们能否通过明确设计 流程来改善平台?
它不应该变成业务流程建模。 许多先进功能,诸如 GitOps 或 Kubernetes 上的操作员,支持的工具可能具有多个 基于决策路径的变量。 如果要将这些都绘制出来,那将是非常可笑的。 然而,文档化并设计流程对于理解平台是有帮助的。 困难之处在于多个入口点的流程,这些流程可以从以下开始:
-
基础设施配置
-
用户引导
-
应用部署
-
事件处理
每个都需要自己的 流程定义。
你有机会在关注用户友好性和操作性的基础上发现优化潜力。 利用流程视角可以将以用户为中心的平台开发与更常见的、纯粹的技术驱动特性定义区分开来。 不幸的是,目前我们无法为你提供更多的见解,因为这一领域仍然是新兴的,几乎没有相关的知识分享。 在 第三章中,我们将深入探讨 这个话题。
供应商锁定讨论
总结 关于依赖性的主题,我们必须触及关于供应商锁定的讨论。 这是战略和架构决策的一部分,并经常推动产生奇怪的结果。 此时,您应该充分意识到,您总是会有依赖性,而供应商锁定仅仅是其中之一。 正如开源为避免专有软件带来了良好的基础一样,它也被用作自行构建事物的论据。 要问的重要问题是:您希望为用户提供平台的速度和服务质量是多少? 您预期的运营成本是多少? 除此之外,您还必须考虑 团队的可用性、技能集以及您的 组织更倾向于的成本(运营费用 (OPEX)或 资本支出 **(CAPEX)。
有关供应商锁定的一些不同观点如下:
-
最好自己构建:完全自己构建某些能力可能会让您感到终极自由,避免任何类型的供应商。 事实上,您只是成为了自己的供应商。 在某些时候,您可能不想或无法再投资于您的开发(常见的项目行为)。 因此,您作为自己的供应商从自己的市场中退役,并且您害怕的一切都成为了现实。
-
选择每个问题中的最佳工具,而不是每个上下文中的最佳工具:在可观察性范围内,有许多选项可用于监控、日志记录和跟踪。 针对这个问题的常见方法是选择最适合的开源工具。 在此基础上,您需要实现日志收集器和代理来转发指标。 您所实现的是一个完全可组合的可观察性解决方案。 另一方面,与单一供应商解决方案相比,您可能会失去上下文意识、可扩展性或操作性等能力。 我不想说专有软件更好;然而,我见过许多组织使用 10-14 种不同版本的工具,运行在最大规模上,并拥有高昂的运营成本。 实际上,对于工具集来说,这种做法在处理事故时并不有益。 在这种情况下,我们不幸地倾向于回避真相,并为为何事情会变得这样找借口。 它更好。
-
专注于错误的事情:人们仍然关注部署 Kubernetes 的任务。 这被认为是一个挑战,并且变成了一个永无止境的故事。 考虑利用工具、有明确观点的平台或商业解决方案来完成容器编排,并专注于 你平台中创造价值的部分。
供应商锁定是架构师在定义目标时议程上的一个情感讨论点。 你必须保持眼界开阔,真正考虑什么是重要的,什么仅仅是满足自尊心的东西。 复杂且无法管理的解决方案并不会为你赢得奖项 。
到目前为止,你已经了解了依赖关系以及如何处理它们。 在接下来的章节中,我们将学习如何让 它们可见。
参考架构
参考架构 对平台工程团队、你的平台和相关用户来说是非常宝贵的 资产。 它们为讨论和决策过程奠定基础,并帮助通过前瞻性思维定义未来的工作。 不幸的是,许多平台 团队无法清晰地描绘出 他们的系统。
特定供应商的参考架构
现在,这些 参考架构可能会因你使用的不同供应商而有所变化。 平台工程社区 [6] 已经收集了一些可供构建的选项和模板。 一个好的起点是单一云提供商模板,这里以 AWS 为例。 然而,能力平面仍然缺失。 这里的重点是云服务提供商,因为它通常会为你的平台定义大量的组件。 正如你在下图中看到的, 云服务提供商 (CSP) 服务 可以在架构的任何部分找到。 你甚至可以绘制出一个更具观点的目标,利用 CSP 的 CI/CD、密钥管理和 云身份提供者(IDP)。
图 2.6:由 platformengineering.org 提供的 AWS 参考架构
与单一供应商平台相比,多供应商平台自带一定的复杂性。 除了每个供应商使用的资源外,我们还必须考虑存储和分发容器镜像的位置、如何提供可观察性,以及 如何跨供应商管理机密和证书。 你可以在以下的参考架构中看到,满足这些期望并不简单。 通过多云平台策略,你将面临大量需要处理的问题。 成本将急剧增加,实施和平台行为会随着每个云服务提供商(CSP)的不同而略有变化,而且很难定义一种完全合适的方法。 可用性、安全性、可扩展性和效率等方面会因构建在 多个环境上而产生冲突。
图 2.7:由 platformengineering.org 提供的多供应商参考架构
然而,并非每个平台都需要在云端运行。 可选择的方案是无穷无尽的。 我们在成熟企业中常见的是混合、私有云或扩展至云的环境,这些环境依赖于像 VMware Tanzu 或 Red Hat OpenShift 这样的成熟解决方案。 在以下图中,我们可以看到一个以 OpenShift 为核心的平台架构。
图 2.8:由 platformengineering.org 提供的 OpenShift 参考架构
调整 参考架构以适应其运行环境 非常重要。
重要提示
你为平台选择的环境会自动规定平台的一些部分,无论我们喜欢与否! 增加云和基础设施提供商的数量会呈指数级增加你平台设计的挑战。 这将显著增加你平台设计的挑战。
通过能力平面扩展参考架构
大多数参考架构的弱点在于它们缺乏对实际平台运行时上运行的组件所提供的能力的视图。 这种视角是必需的,因为没有它,用户无法使用平台的功能和特性。 没有它,用户将无法使用平台的功能和特性。
在下一个图中,我们 将提供一些关于 能力平面的参考:
-
用户空间:用户实际看到并可以用于托管其应用程序的环境
-
规模与调度:支持用户应用响应事件、缩小规模或提供自定义调度选项的能力
-
网络:处理进出流量,自动管理 DNS 条目或集群 负载均衡
-
重量级任务:通常更倾向于交由管理,而不是自己操作的事物,比如批处理框架或 消息流处理
-
资源集成:一个至关重要的组件,将实际的基础设施资源连接到平台运行时;存储或 GPU 集成,也包括资源控制,例如使用 Crossplane 工具
-
安全与合规:提供管理和存储机密、主动扫描集群和应用程序中的 CVE 漏洞的能力
-
可观察性:提供一个简单且快速的可观察性入口,统一数据收集,或帮助处理 成本
图 2.9:带有示例工具的能力平面
能力平面 对于实际的应用部署和运行至关重要。 它是你与技术互动最密切的空间,如果用户的应用在这里失败,所有其他的努力都将付诸东流。
平台架构超越了参考模型
总结参考架构,它们提供了一个易于理解的平台概念。 它们没有提供的是平台的实际架构。 源代码版本管理在哪里运行? CI/CD 管道组件在哪里? 容器注册中心在哪里? IDP 如何托管?
因此,作为平台架构师,我们必须提供一个实际的架构,展示这些组件的位置。 这为进一步的依赖关系、网络通信和需求、可用性以及平台的可扩展性提供了深刻的洞察,或者简单来说,是否平台中有太多其实并不帮助平台稳定性的组件。
以下图表展示了这种架构可能的样子。 你还会看到不同的组件和网络连接分布在各个位置。 然而,当谈到平台架构时,这就是它应该如何在技术上 被表示。
图 2.10:平台架构
很难找到合适的方法将基础设施和平台组件在一张图表中展示。 这不是最干净的方式,但它有必要突出所有的依赖关系和相互影响。 尽可能保持简单,但也要详细到足够的程度。 你甚至可以将其拆分成不同的图表,以突出某些信息。
拥有你的架构
看起来 管理和处理不同版本和变种的架构似乎需要大量文书工作。 然而,你可能已经体验过,平台变化的速度远快于图表的更新。 重要的是,图表作为你作为架构师工作的结果,不应拖慢平台的发展,而平台的发展也不应拖慢图表的更新。 我见过一些项目,架构师变成了一个杰出的等级制度。 所有这些项目都失败了,并且在做出正确决策时遇到了困难。 作为架构师,你并非无所不知,但你也不是平台工程团队。 共同合作,保持一致和同步是关键,几乎就像你希望构建的平台一样。 要建立的平台。
同样的道理适用于你的架构。 你必须拥有它们,但不是支配它们。 一个架构必须是一个思想的游乐场,是未来发展的沟通工具,是关于平台能力的真实来源。 这只有在你负责推动它,并且听取他人意见时 才是可能的。
在本书的后续章节中,我们会讨论一个相关的话题,关于拥有你的架构:如何应对技术债务。
有主见的平台与质量的成本
在构建平台时,会出现两个问题:有主见的工具和质量的成本。 这两者都有很强的论点需要 考虑,但它们也有强烈的反对理由。
有主见的工具和产品
有观点的 工具、产品和服务强调一个严格的概念,并且不提供替代方案。 几乎所有的东西都有其观点,但问题是它们的灵活性和可组合性如何。 对于如何做某件事的强烈观点使得后续的决策变得更容易,因为解决方案空间缩小了。 随着这种方法用户基础的增长,它可能会变得主导,最终成为事实上的标准。 我们必须在架构中仔细考虑这些因素,并澄清对它们潜在 未来影响的理解。
现在,严格执行一个概念可以带来很多好处。 例如,每个解决方案在提供 Kubernetes 集群的领域内都有其观点。 然而,它们提供的是一个一致且通常已经准备好投入生产的整体解决方案。 这样的工具在集成时也可能更快,因为它们覆盖了广泛的主题并预先集成了其他工具。 另一方面,这也可能是一个缺点,因为如果你想实现其他选项,会付出更多的努力。 然而,在某些情况下,这几乎是不可能的,或者成本 过于昂贵。
你还应该区分可见的大概念和那些更隐蔽的、隐藏的概念。 前者容易识别和评估。 它们附带大量的预定义集成,通常基于单一供应商的技术。 而那些小型和隐藏的有观点的工具则更难以识别, 因为你使用得越广泛,它们的缺点就越显现出来。
质量的成本
有一句话说: 与其频繁购买便宜的,不如一次性购买昂贵的。但在平台做得正确的情况下,这句话是错的。 采用产品思维意味着持续的投资。 这更像是你每天都要照料的花园,而不是你一次性投资的手表。
质量的成本是一个多维度的问题。 一个高质量的平台,很可能非常有偏见,对于某些用例来说,可能是完美的选择。 但质量不是免费的,它基于高投资或运营费用。 在大型公司中,你会遇到类似内部成本分摊的情况。 这也意味着你必须分担质量成本。 我们在最终用户社区中经常看到,像这样的平台往往会导致沮丧。 由于成本过高,入门门槛对托管简单应用程序来说太高,或者它的偏见性使得运行一个非常复杂的应用系统变得不可能。 这导致其他人开始从零开始为他们的应用程序构建自己的平台和解决方案。 如你所见,这是一个奇怪的问题。 由于平台的高成本,用户的运营成本也变得很高,而偏见性的解决方案并没有真正提供所需的功能。 这就是所谓的 质量的成本 成本。
然而,你也不能通过快速拼接一些随机工具来绕过这个问题,提供一个既便宜又尽可能开放的平台。 这可能会导致平台的项目初期快速上手,但我可以保证,这条路走得越快,用户离开你的解决方案的速度也越快。 记住,以产品思维方式看,你希望让用户能够自己做事,而你的平台则消除了所有繁重的工作。 理想情况下,你的用户也不需要成为所有 使用技术的专家。
从战略层面来看,质量成本的问题影响了许多决策。 我们见过一些平台经过多年开发,最终却因为其 性能/价格比 而遭遇挑战。
你需要为你的平台找到黄金路径。 然而,不要以为一个完美的平台就符合他人的需求。 如果你遇到这个问题,这显然是一个信号,说明 你已经失去了以产品为导向的思维方式,缺乏 用户导向的视角。
创建你自己的架构
行动的时候到了。 到目前为止,我们已经涵盖了所有相关的输入源、关注的主题和需要考虑的视角,现在可以开始构建架构了。 因此,我们准备了一个模板,你可以在本书的 GitHub 仓库中找到,或者作为一个 Miro 协作工作的 模板。
在这些模板中,你将通过不同的步骤和架构图来构建你的平台架构:
-
创建你的参考架构。
-
专注于能力层面及其组件。
-
定义平台的基础设施架构。
-
可视化平台的控制流。
由于架构是一个动态的产物,你需要反复修改它,遵循PLAN, DO, CHECK, ACT 循环。
花时间浏览这些模板:
-
GitHub: https://github.com/PacktPublishing/Platform-Engineering-for-Architects/tree/main/Chapter02
-
Miro: https://miro.com/miroverse/platform-architecture-workshop
创建你的参考架构
参考架构概述了你计划的组件,将其分类并将其作为平台实施的核心部分。这也是你在某个阶段定义依赖关系图的帮助来源。
为了给你的参考架构图注入活力,最好从已经确定的组件或给定的基础设施开始。这些固定组件可以是,比如 CI/CD 工具或安全解决方案。首先,基础设施变得重要,因为它影响所提供的资源。如果你选择使用公有云服务商,很多服务可以作为托管解决方案使用。在某些情况下,这也决定了你将使用基础设施即代码(IaC)工具,或者反过来,如果你仅选择基础设施即服务提供商,这意味着你需要考虑平台中其他地方可能运行的服务。它们很可能会最终出现在能力层面,这就引出了一个问题:我们是否需要为共享服务专门部署一个集群,还是采用服务部署在用户命名空间中的方法?
接下来,处理自动化和编排层面。 出于某种原因,这个层面相对较为确定,并为开发者体验层提供了坚实的决策基础。 你需要确保所选的解决方案是较新版本,并且能够与其他云原生服务集成,而无需任何脚本。
最后但同样重要的是,你需要考虑可观察性和安全性层面。 如前所述,可能你已经有了现成的解决方案。 但特别是对于那些平台工程和云原生之旅还比较新的组织来说,你可能会对现有的解决方案提出挑战。 安全工具需要能够理解云和 Kubernetes。 它们需要与这些平台集成,并能够应对它们非常动态的特性。 同样的理由也适用于可观察性和运营解决方案。 你不希望每次 pod 被终止或在集群中移动时都收到警报。 在集群中。
最重要的是,你最终将所有的视角汇集在一起:平台的原则和目标、关键用户、可组合性,以及这些移动组件之间的相互影响。 但是你的设计不需要完美。 在深入设计过程之前,请继续阅读,因为我们将在本章稍后讨论 TVP 的话题。
专注于能力层和组件
当 参考架构搭建完成后,我们需要在下一步中通过能力层来扩展它。 当然,这本身就是一个大步骤,因为实际上有数百种开源解决方案可用于能力层中的任何需求。 如果你从未见过 CNCF 景观,以下快照展示了大约三分之一的 CNCF 列出的开源 项目 [7]。
图 2.11:CNCF 景观(该图像仅作为视觉参考,文本信息并不重要。)
请注意, 至少还有一些其他开源组织也管理着数十个项目,你可以将它们算作云原生领域的一部分。
云原生宇宙的好处和坏处在于,对于每一个微小问题,你至少有三个±1 的选项来 解决它。
对于能力平面,建议从 底层向上工作:
-
我们需要哪些资源的集成?
-
我们如何将操作数据提供给可观察性解决方案? 我们需要在基础架构和应用空间之间拆分吗?如果需要,如何拆分?
-
确保安全和合规性措施正确地转移到 用户的领域。
-
我们如何处理网络流量? 我们需要在 集群内进行加密吗?
-
我们是暴露一个 API,还是将其与 云 API 集成?
-
扩展和调度可能需要什么? 是否有其他功能需要 提供?
预计大部分时间在能力平面上工作。 随着每个新用户和新产品的加入,会有新的需求出现。 每当新用户和新产品出现时,新的需求就会随之而来。 最棒的部分是当你能观察到产品的演变,并且要求更多 高级功能。
再次强调,首先关注核心要素。 正确整合网络管理和存储比提供机器学习工作台解决方案或新的容器运行时更为重要,例如 WebAssembly (Wasm) [8]。
为平台定义基础架构架构
在定义参考架构的有趣部分之后,我们必须直接进入严肃的架构定义。 听起来像笑话的部分往往被跳过,但许多平台无法提供这个视图。 事实上,这个图表比参考架构更相关,因为它涉及实现、架构讨论以及安全与合规性检查。 然而,它也更加复杂 理解。 。
如前所述,我们必须将一侧的基础架构架构与平台的相关组件结合起来。 这有助于我们理解系统中每个部分的位置以及所需的连接 。
该图必须突出显示计算基础设施使用的不同环境,消耗的托管服务,它们之间的连接方式,以及存在的外部连接。 每个组织都有自己绘制此类图表的方式,遵循特定的标准,或者做得更简化。 我们的模板尝试提供一个 中间方案。
你也可以在架构图中对突出部分进行不同的调整。 我们经常看到,在可视化精确的网络连接、网络隔离或协议方面具有巨大的相关性。 将一个隔离环境与相应的控制流结合,并展示如何将更新导入其中,将利用两种图表类型来 最大化理解。
记得在图表中包含诸如管理环境/集群、集成测试的暂存环境,甚至是开发环境之前的一个步骤。 为了保证连贯性,备份和恢复也可能是有帮助的。 你看,越是投入工作,更多的细节就会浮现出来。 当图表变得过于复杂时,你应该提供 不同的版本。
可视化平台的控制流
可能 对你来说比较新的可能是 控制流。它是 一个像流程一样的方法的第一步,旨在帮助我们澄清管理平台和用户交付物的相关路径。 平台内有多个流;其中这三个是 最为突出的:
-
基础设施提供:此流可视化了基础设施测试环境的重要性,以及在该层级上的变化如何影响它们,从在版本管理系统中提交 IaC 清单,到部署、测试,再到 最终发布。
-
从代码到部署:这对于平台用户最为相关。 一个人提交的代码是如何被拾取,构建、集成、扫描和测试的? 开发和生命周期设置程序 是什么样的?
-
平台能力管理:这对于负责 集群交付组件的平台注册工程师尤为重要。
有许多其他较小的控制流可以帮助我们理解平台,例如秘密和证书管理,或者 用户管理。
从纸面工作到实际使用案例,我们将看一些不同平台风格和实现的示例。 在下一部分,你将 把视角从通用平台扩展到 专门化解决方案。
探索平台作为产品——使用案例和实现
我们谈到了平台的目的,比如 优先考虑自服务。但是我们如何实现这一点, 我们希望提供哪些使用案例作为 自服务?
每个组织 的使用案例和平台实现都有些不同。 这是因为每个组织的技术栈不同,遗留/现有的工具和流程也各不相同,这些都是优化的候选项。
在这一部分,我们讨论了在我们多年来与组织合作中看到的使用案例。 我们可以假设其中一些案例将是你自己未来平台工程计划的好候选者。
寻找专家以及他们引起的瓶颈
有一篇 来自 Thoughtworks 的精彩博客文章,其中有一段引用,帮助我们开始寻找好的使用案例 案例 [9]。
是什么使某个东西成为平台?
平台是集中专业知识的手段,同时将创新下放到客户 或用户。
换句话说,在任何生产、运输和操作软件以支持其业务的 IT 组织中,我们可以找到诸如基础设施配置、访问控制、构建和部署工件、可观测性、质量工程、发布 管理、容量规划、 网站可靠性工程 (SRE)、事件响应、数据分析、自动化、业务洞察等方面的专家 等等。
我们的平台目标是识别使用案例以及它们所需的专业知识,然后以简单的方式将这些使用案例作为自服务提供给每个人使用,无需每次都去找专家 。
通过自服务来集中专业知识
允许每个人完成工作,而不必成为专家或在所有需要的领域请教专家来完成他们的 工作!
如果我们现在 查看整个 软件开发生命周期 (SDLC),并列出从新应用或功能的初步构想到它发布到最终用户所需的所有任务、专家和时间,我们将能够识别出许多阻碍 SDLC 进展的瓶颈。 这要么是因为某些任务是手动的,要么是因为这些任务需要某个专家来完成。 由于专家通常比较稀缺,他们成为了共享资源,团队在发布新功能时往往需要等待这些专家。 这会导致项目进度拖延。
在 第三章中,在 理解现有 SDLC 一节,我们将更详细地研究如何最好地理解当前的 SDLC 或组织中的 价值创造之旅 。 你将了解不同的方法来理解一个工件的生命周期、所涉及的任务、依赖关系,以及如何跟踪时间,以识别出那些适合自动化的任务,作为 平台服务的一部分。
现在让我们来探索一些我们曾与之合作过的组织中的这些用例和实施选项!
将专业知识集中作为自助服务用例
虽然 还有许多其他的用例,但以下是一些你可能会在平台中实施的自助服务功能示例。
提供合规的环境
根据行业的不同,数据存储、环境安全性以及所需的报告类型等方面都有一定的规定。 为了确保组织中任何团队请求的每个环境都符合所有这些规定,我们可以将其作为我们平台的自助服务功能来实施。
这是该用例的一个用户故事:“作为一名数据科学家,我希望将我的新数据模型与一个 类似生产的数据集进行验证!”
为了将这个故事分解成具体任务,有 一些细节需要解决,例如:这些数据集来自哪里? 数据科学家是否希望从多个可用的数据集里选择一个? 验证的输出是什么?它存储在哪里?谁可以访问它? 你如何选择数据模型? 这个验证运行多长时间?我们是否需要设置最大时间来关闭环境,以避免不必要的成本? 我们需要生成什么类型的审计数据,因为这涉及访问 生产数据?
另一个类似的用户故事可能是:“作为一名 QA 工程师,我希望使用与 80%终端用户相匹配的浏览器/操作系统组合,在连接到生产数据库的最新版本软件上运行我的手动测试!”
与前面的用户故事类似,我们需要提出一些额外的问题,例如:你想测试的软件产品是什么?它如何能够自动部署? 我们在哪里可以找到生产用户浏览器/操作系统使用的数据? 这个环境需要保持可用多长时间? 我们可以为这个配置的环境设置过期时间吗? 工程师可以看到哪些数据,哪些数据不能看到?因为我们正在处理访问 生产数据的问题。
这样的用例实现可能会有很大差异,但我们应该始终从终端用户的旅程开始考虑。 我们可能希望我们的数据科学家或质量工程师登录到我们的内部开发平台门户。 在那里,他们可以选择 配置符合要求的环境的用例。 然后,他们可以填写相关数据,以回答所有提出的问题。 这些输入可以用来创建该环境,并使其可供 请求该环境的团队使用。
进行性能和韧性测试
性能和韧性测试应该 成为每个软件版本发布的一部分,以确保新功能不会通过变得超级慢来影响用户体验(UX)。 我们还希望确保我们的新软件能够应对不可预见的情况,例如网络连接问题、缓慢或不可用的后端服务或数据,或者异常 高负载。
虽然有很多工具可以生成流量(负载测试工具)或模拟问题(混沌工程),但这些工具及其所需的环境往往需要大量专业知识来设置、配置、运行和后续分析
与其让我们的性能、站点可靠性或混沌工程师成为瓶颈,我们可以努力将这些专业知识集中化,并将其提供为我们工程团队的自助服务。 这里将是正确的用户故事:“作为开发团队,我们希望知道我们软件的最新版本是否存在任何性能或 可靠性下降!”
我们可以实现这种自助服务能力的多个迭代。 从提供包含相关工具的环境开始,所有开发人员需要做的就是执行测试并等待结果。 但理想情况下,我们希望最终达到这样的情况,即完全自动化甚至集成到我们的开发流程中。 我们应该朝着这样的目标努力:“作为开发团队,我们希望在主要拉取请求上获得性能和可靠性指标,以便知道最新的代码更改是否足够好,可以提升 到生产环境!”
就像在前面的例子中,我们可以从一个门户开始,团队可以请求性能测试环境。 要满足第二个完全自动化的用户故事,我们需要考虑提供一个可以从 CI/CD 流水线系统调用的 API,获取所有相关的输入参数,然后返回执行测试的实际结果。
新应用的入职
创建 新的应用程序或服务是开发团队的工作。 为此,他们通常必须经历许多不同的步骤,例如创建一个新的 Git 仓库,添加样板代码和元数据设置,配置构建(CI)流水线等等。 更多的步骤。
如果每个开发团队总是从头开始,我们不仅会出现多种本质上相同的做事方式,而且还会在所有开发团队中产生大量重复的工作,这会分散实际编码的时间。
一个适合平台自助功能的良好用户故事可能是这样的:“作为开发团队,我们希望基于一个完全配置的模板创建一个新的应用程序,这样我们就可以专注于编写代码,而不用担心如何构建、部署, 和运行!”
查看 整个 SDLC,我们的自服务甚至可以从产品团队使用诸如 Jira等工具创建的特性需求开始, 以下展示了作者曾与之合作的某个组织中新应用的端到端入职流程:
图 2.12:作为自服务的端到端应用入职(该图像仅作为视觉参考,文本信息并不重要。)
对于开发团队而言,旅程从 Jira 工单开始。 接着,他们前往该组织选择的 IDP——Backstage,在那里他们将走过自服务 应用程序入职 向导。 该向导会创建一个新的 Git 仓库,并预先加载好现成的代码模板、管道、部署说明、可观察性配置、所有权等内容。 一旦代码提交,管道会自动将构建物部署到开发代码空间,并自动连接到 Visual Studio Code!
访问可观察数据以应对事故响应
一旦新软件部署到生产环境,开发人员通常会将焦点转向下一个应用或功能。 然而,当灾难发生时,他们需要支持运维或 SRE 团队进行故障排除,以修复出现的任何问题。
在许多组织中,生产环境中的遥测或可观察数据仅限于由专门团队负责的生产环境访问。 还有合规性原因,毕竟不是每个人都应该访问可能敏感的数据。 但当身处所谓的 战情室时,快速访问相关的可观察数据非常重要,而不必填写太多请求表单、将数据从一个环境复制到另一个环境,或将生产可观察工具中的数据转换为开发人员常用的格式。
在 第三章,我们会更详细地讲解此用例,在这里我们简要描述用户故事:“作为开发团队,我们希望能轻松访问生产事故相关的可观察数据,以便快速解决 问题!”
现在我们有了几个用例,接下来让我们看看如何将这些想法转化为用户实际可以使用并从中受益的东西。
理解 TVP
在产品管理中,我们通常讨论的是一个 最小可行产品 (MVP)。 MVP 定义了你需要构建的产品最简单版本,以便将其推向市场。 MVP 的概念最初是由 精益创业 运动 引入的,这一运动由 埃里克·里斯 *[10]*推动。我鼓励大家阅读这本书或访问其优秀的博客文章,网址是 theleanstartup.com 网站。
MVP 中的 最小化 指的是一款帮助初创团队验证他们的想法是否真的解决了问题或痛点的产品版本。 所有这些精益创业的理念可以直接应用于平台工程 ,比如这样:
-
我们的团队是 初创公司
-
我们的平台是 产品
-
我们的目标市场是我们的 内部用户
-
我们的假设是它实现了 目标
在精益创业中, MVP 被定义为 一款足够好的产品的首个版本, 足够好 以至于可以发布。 它足够好,因为它已经解决了问题,尽管可能不是功能完整的。 它足够好,可以交到用户手中,验证我们的假设,并获得早期反馈,从而为后续迭代和改进提供基础。
现在,让我们深入探讨如何 应用所有这些精益创业的理念,定义我们自己的 MVP——或者,正如我们喜欢称之为的, 我们的 TVP!
寻找你的 TVP 用例
在 上一节中,我们已经探讨了我们可以通过平台提供哪些自助服务用例。 我们通过观察专家目前在哪些领域需要帮助以完成工作,或者在哪些地方涉及大量人工 工作,从而识别出了这些用例。
像任何新的软件产品一样,可能有很多我们想要实现的优秀功能。 问题是:我们应该从哪个开始做呢? 为了回答这个问题,最好根据几个维度来进行优先级排序。 其中一种方法是 ICE 评分 模型,但你也可以随意使用任何你熟悉的或已经在组织中使用的评分模型 [11]。 ICE 代表 影响力 (我们通过这个功能所能产生的影响), 信心 (我们有多大信心能够实现预期的影响),以及 容易程度 (实施这个功能所需的努力程度)。 我们为每个指标赋值 1-10,并将这些数值相乘。 如果我们对每个功能的想法都这么做,我们就能轻松地进行比较并得出首个优先级列表。 以下是我们之前讨论的四个用例的评分示例,使用一些虚构的数字作为 ICE 评分:
| 用例 | 影响力 | 信心 | 容易程度 | 分数 |
|---|---|---|---|---|
| 提供 合规环境 | 6(良好的影响) | 5(中等信心) | 2(不容易) | 60 |
| 性能测试和 弹性测试 | 6 | 5 | 5 | 150 |
| 新应用程序的 入职培训 | 8 | 7 | 3 | 168 |
| 访问 可观察性数据 | 8 | 8 | 3 | 172 |
表 2.1:ICE 评分示例
正如我们所说, 前面的表格中的 ICE 分数只是虚构的。 然而,这些例子应该能给你一些关于这个评分如何工作的指示。 它的另一种形式还包括范围,因此被称为 RICE。 RICE 就是简单地将范围、影响力和信心相乘,并将结果除以努力——从而得出一个 易于使用的分数。
根据前面的例子,我们可以辩称,应该先从 新应用程序的引导 或 访问可观测性数据 开始,因为这两者得分最高。 另一方面,我们也可以认为 运行性能和弹性测试 会是更好的候选项,因为它似乎是最容易 实施的。
无论你使用的是 ICE、RICE,还是其他模型,它都应该帮助你决定首先解决哪个用例,目标是迅速产生影响。 在开始实施之前,让我们谈谈第一次实施应该达到的效果 !!
足够好与完美做到了!
我们大概 都同意,一个产品几乎不可能是完美的或已经完成的! 总有一些我们希望看到的功能,或者那些烦人的 bug 我们希望有人能最终修复。 当我们开始一个新产品时,比如我们的平台,我们需要改变这种思维,并接受第一次发布的版本是 足够好 的。这并不意味着我们在走捷径;这只是意味着我们需要抛开完美主义心态,勇敢地说,“ 它已经足够好——让我们 发布它! ”
在《精益创业》中,提到了谷歌地图的发布 [12] 。看起来团队当时正在向谷歌高级管理团队展示他们的新动态网页(使用 AJAX)地图解决方案。 他们的做法是首创的。 尽管开发团队仍然认为这只是一个早期原型,但管理团队仍然印象深刻。 据传,拉里和谢尔盖仅仅说了,“ 它已经足够好了。 发布它。 ”尽管开发团队有一些保留和担忧,但他们还是按要求进行了发布。 其余的——我们都知道——就是历史:谷歌地图是并且仍然是一个巨大的成功。 这个成功的背后是因为这个解决方案只做了一件事——但是那件事做得极其出色,并且成为了与其他竞争对手区分开来的关键。 仅仅通过有限的功能集发布,正是这让他们的竞争对手措手不及,并给了他们 领先的机会。
这如何转化为我们的 TVP 呢? 与 Google 的例子不同,我们不必害怕竞争——或者我们真的有吗? 事实上,我们是有竞争的:我们的竞争对手是那些开发团队,要么浪费时间按旧有方式做事,要么启动自己的项目,构建工具和自动化来解决问题,但只是为自己服务,而不是考虑如何为整个组织规模化解决这个问题。 整个组织。
这意味着我们不必完美无缺地交付我们的 TVP 第一次实施,但它必须足够好,以帮助我们展示提供的价值。 我们需要在假设中明确指出,这个价值是什么,具体是为哪些用例 我们实施的。
TVP – 验证我们的假设
因此,我们 选择了我们的用例,我们知道我们的第一次交付必须足够好,以便最终用户可以使用并从中获得价值。 但是,那个价值是什么呢? 我们如何衡量并证明我们的平台功能确实有 影响呢?
这是我们的产品假设所在。 回顾之前提到的相同用例,我们可以提出以下我们希望达到的假设影响: 有:
| 用例 | 假设 |
|---|---|
| 提供 合规环境 | 验证新 数据模型 时合规违规减少 80% |
| 性能和 弹性测试 | 在生产环境中,识别并修复问题后,扩展性问题减少 50% |
| 新应用程序的 引导 | 新应用程序的交付时间减少 20% |
| 访问 可观察性数据 | 生产问题的故障排除时间减少 50% |
表 2.2:验证用例的产品假设
这个 假设也是一个很好的方式,可以向组织内需要为我们工作提供资金的人推介这个想法。 最终,我们是在做内部推销——我们需要充分论证为何我们要投资时间和金钱来建立一个新的内部开发平台。 我们所称之为假设的价值声明,很可能会与 你的领导层产生共鸣。
剩下的最后一个问题是:我们如何衡量和验证我们的假设? 对于一些人来说,假设我们有如 合规违规的工单数量, 与可扩展性相关的产品问题工单,或者 在事件响应工单上预定的开发时间,应该是很容易的。 更棘手的会是周转时间,因为一个组织如何定义周转时间,首先需要进行解释。 它是从创建初始功能请求开始,还是从开发者开始工作时算起? 此外,我们如何衡量完整的端到端流程? 虽然这一切都有可能,但我们必须确保知道如何衡量现状,以便在我们实施 TVP 后能与数字进行比较,从而验证 我们的假设。
构建、衡量并学习
我们知道我们想要构建什么,我们的假设是什么,以及如何衡量它。 现在,是时候将这些付诸实践了。 就像任何敏捷产品开发一样,我们要 构建、衡量并学习。 我们希望 尽早让终端用户参与进来。 最好的方式是,在我们仍处于原型阶段时,就将他们纳入并从中学习。 持续的反馈帮助我们及早做出重要决策,而不是等到我们有了最终版本,却因为错过了一些 显而易见的东西 而被用户拒绝。
该过程可以通过以下图示最佳地呈现,你也可以在许多受 Lean 创业运动启发的文献中找到:
图 2.13:构建、衡量并学习,以实现你的 TVP
这是一个持续的循环,旨在尽量减少构建、衡量和学习阶段之间的时间,以便在我们的测量反馈表明我们走错了 路径时,能够及时修正或调整。
在这一循环中,有几个里程碑是值得考虑的: 如下:
-
第一个原型:将其展示给有兴趣和潜在的个人重度用户。 他们会给你非常好的 早期反馈。
-
足够好:一旦你达到能够兑现用户故事承诺的阶段,扩大到一组早期采用者,以获取 更广泛的反馈。
-
假设已验证:一旦你通过首批早期采纳者验证了假设,便是时候向其他组织推广并宣传这个成果了。 利用你的早期采纳者为你推广这些新功能!
我们来了。 我们有了 我们的 TVP!
TVP
TVP 是我们平台的那个版本,它为最终用户提供价值。 它使平台工程团队能够验证我们的假设,即它实现了我们的使用案例的目的(例如,减少认知负担)。 它让我们以最少的努力收集最大量的验证性学习,为我们的下一个 产品迭代做准备。
当你开始引入一个平台时,追踪其采纳情况并判断是否走在正确的道路上是很重要的。 接下来,我们将帮助你定义 KPIs 以 做到这一点。
查看相关的 KPIs 以使采纳过程透明化
做正确的事情,并且谈论它。 (Georg Volkmar Earl of Zedtwitz-Arnim, 1978.)
一个常见的问题 我们在许多平台实施中看到的是缺乏其效益的证据。 理论上,这一切都说得通,但让我们用一些数字来支持它。 此外,它们有助于了解你是否朝着 正确的方向前进。
因此,定义不同的 KPIs 是有帮助的,通过这些 KPIs,可以了解平台采纳的进展情况。 第一步,你应该反思你已经衡量了什么。 通常,我们只需要以正确的方式组合现有的数字,就能够定义新的 绩效指标。
首先,我们需要理解度量标准、日志和追踪数据,定义我们如何获取它们所代表的值,以及它们的含义。 虽然它们都是相关的来源,但大多数对你平台的采用并不重要。 这只是代表了系统的一侧。 同时,应该明确的是,我们更关注的是用户及其 体验。 支持渠道、工单系统、开放的拉取请求、注册请求数量以及其他用户互动工具,对于理解适应情况非常有帮助。 这些数字的重要性会随着时间变化。 例如,申请访问平台的人数通常呈现出一个有两个平坦侧面的山丘形状。 在一侧,由于人们过于羞怯,不愿尝试新事物,因此采用初期会很慢。 而在山丘的另一侧,随着新项目较少地被加入平台,平台的采用增速变缓。 另一个例子可能是支持请求的数量。 这些通常会随着用户数量的增加而增加。 然而,随着平台转向自助服务,这些数字预计会随着时间的推移逐渐减少到最低水平,同时你的平台会变得更好,用户也会学会如何 使用它。
因此,第二点,你必须定义你平台当前 KPI 的上下文。 或许看起来显而易见,成熟平台可能会有不同的 KPI,或者你的利益相关者必须以不同的方式解读这些 KPI,但相信我,事实并非如此。 你需要让这一点变得透明、清晰并且易于理解 给每一个人。
重要提示
KPI 及其当前的成熟度背景需要被 明确指定。
举个例子,下面的图示展示了与平台集成不良的环境相比,KPI 可能会如何变化。 这些数字是基于从不同项目中收集的几个测量数据,并在此进行了概括。 在左侧,缺乏明显的改善方向,或者它们不断上下波动。 最明显的就是支持请求数量的增加。 将其放在较少应用使用平台的背景下来看,这是一种不良信号。 现在,在右侧,我们可以看到任何 KPI 都有所改善。 大多数数字不会降到零,但它们会保持稳定,无论是平台增长、最终用户增长,还是其他 长期影响。
图 2.14: 比较平台影响力(左:无平台,右:有平台)
这些数字 缺乏上下文。 当你通过平台的生命周期声明某个状态时,数字变得更加有意义。 在下一张图中,我们添加了一个 分段的示例。
随着首次采用支持请求的增加,每次变更的成本也在上升,而仅有少数应用程序被迁移。 在逐步推广阶段,可以看到新应用程序的数量迅速增加,同时,支持请求也在增加。 每次变更的成本趋于平稳。 在接下来的优化阶段,我们可以看到大规模的变更。 每次变更的成本和支持请求急剧下降。 新应用程序的数量已达到峰值,并且由于大多数能够使用平台的应用程序 已经迁移,所以数量开始缓慢下降。
在这三个阶段中,每个版本的发布时间逐渐减少。 这是自动化和自助服务的效果,并且在最后一个阶段开始趋于平稳。 这与几乎所有其他关键绩效指标(KPI)的稳定发展相似。 与其他图表相比,我们还改变了添加应用程序数量的表示方式。 现在,你可以看到每个季度迁移的应用程序数量以及总的 应用程序数量。
图 2.15:平台生命周期分段的示例 KPI
通常,当公司看到这些数字时,他们会停止在该领域的投资。 以产品思维来看,这些数字意味着你能够在固定的成本下提供持续的改进和创新,同时客户满意并能够进行 快速开发。。
定义平台采纳 KPI
我们 可以使用许多技术指标作为我们的 KPI 基础。 这些指标易于获取并且可以关联。 另一方面,这些数字的解读则取决于你。 服务请求的减少可能是因为你有出色的文档,但也可能是因为没有人使用这个平台。 如前所述,这就是为什么它需要提供完整的图景。 这可能变得复杂,因为每一个新的 KPI 可能会为数据添加更多的细节。 在某些时刻,你可能需要 删减这些内容。
对于开发人员和 DevOps 团队,已经有一些框架可以作为 基础使用。
DORA 指标
DevOps 研究和评估 (DORA) 是由 Gene Kim 和 Jez Humble 创立的初创公司,您可能从 *《DevOps 手册》*中了解到他们。 DORA 指标是一组四个关键绩效指标,可用于衡量 DevOps 团队的表现及其平台对用户的影响。 尽管它们并不总是完全适用,但它们被广泛采纳和使用,例如被诸如 GitLab *[13]*的系统所采纳。
DORA 指标如下:
-
部署频率:组织成功发布的频率 生产
-
变更的交付时间:从承诺到 进入生产
-
服务恢复时间:导致生产中失败的部署的百分比 时间
-
变更失败率:组织从失败中恢复所需的时间 时间
我经常看到组织将术语从 生产 更改为 发布 或 生产发布。这是因为大多数公司在发布面向最终用户之前都要经历多个阶段。 由于每个组织的具体情况不同,有多种解决方案来衡量这些数字,但最终通常会采用自己的方法 来实现。
要测量发布次数,您可以针对支持您发布的喜爱的源代码版本控制系统运行一个简单的 API 调用。 这些数字可以导入数据库并通过 Grafana 仪表盘进行可视化。
识别变更交付时间更为复杂。 为此,您必须跟踪提交并查看它们何时包含在发布中。 然而,这两个指标都很容易获取和计算。 另一方面,变更失败率变得更为棘手。 为此,您需要在整个部署和生产链中包含有关您的发布的信息,以便在发生故障时,您可以识别问题属于哪个发布的日志。 此外,您还必须确定是否真的是由发布引起的问题 还是其他原因。
恢复服务的时间与同样的过程一样。 你需要确定何时发生了事故,何时成功关闭,以及何时通过恢复解决。 你的事故管理系统可以提供这两个指标。 这些指标。
关于 DORA 指标的特殊之处在于,他们已经研究了成千上万家公司,为你提供了与其他公司相比的好坏概述。 [14]。
| 精英 | 高 | 中 | 低 | |
|---|---|---|---|---|
| 部署 频率 | 按需 | 每天一次到每周一次之间 一周 | 每周一次到每月一次之间 每月 | 每周一次到每月一次之间 每月 |
| 变更 交付时间 | 少于 一天 | 一天到 一周之间 | 一周到 一个月之间 | 一周到 一个月之间 |
| 变更 失败率 | 5% | 10% | 15% | 64% |
| 失败的部署 恢复时间 | 少于 一小时 | 少于 一天 | 一天到 一周之间 | 一个月到 六个月之间 |
| % 的受访者 | 18% | 31% | 33% | 17% |
表 2.3:不同成熟级别的 DORA 指标
DORA 指标的优点在于,大多数公司都能收集到这样的数据。 另一方面,作为平台工程师,我们缺少一些关于直接和个人反馈的方面。
下图是一个终端用户的 Grafana 仪表板,展示了实时数据。 在左上角,你可以看到部署到生产环境的应用程序数量为 105,总共的部署次数为 1.847\。 在右上角,显示了变更的周期时间(单位:小时),为 612.5,变更失败率为 0.522%,部署频率为 5.02,MTTR 为 199\。 底部的图表展示了每个应用程序的部署情况。
图 2.16:DORA 仪表板的实际示例(该图片仅供视觉参考,文本信息并非必需。)
如何开始使用 DORA? 一种方法 是利用 Keptn,一个 CNCF 孵化项目,提供自动化的可观察性,用于 Kubernetes 上的应用感知部署。 Keptn 可以通过命名空间级别的注释启用,并将创建 Prometheus 指标和 OpenTelemetry 追踪,便于观察部署。 这些指标包括部署的持续时间、部署成功和失败的情况,并为部署、应用、环境和版本提供维度。 开箱即用,这 为你提供了一些核心的 DORA 指标,你可以将它们展示在你的仪表板上,如下图所示:
图 2.17:Keptn 提供自动化的部署可观察性,报告一些 DORA 指标
Keptn 提供了额外的功能,比如基于 SLO 的部署成功验证,并且还会在多个阶段追踪部署,以识别额外的指标,例如,“部署在哪个环节停滞? 推广过程中遇到了什么问题?”
要了解更多信息,请查看 Keptn 网站和 DORA 教程 [15]。
SPACE 框架
SPACE 框架 结合了五个维度 用于评估开发团队的生产力。 GitHub、微软和维多利亚大学共同开发了这一方法。 它专注于团队协作的方式及其成果。 查看这五个维度 将使 这一点变得清晰:
-
满意度与福祉:收集有关整体满足感、幸福感以及与工作相关的心理健康的信息。
-
绩效:以输出为导向的指标,如已完成的任务或发布的版本
-
活动:关注如提交次数、合并请求或代码审查等活动
-
沟通与协作:我们将检查团队的沟通行为和对齐情况,以及使用审查和评论机制
-
效率与流动:开发和部署过程的顺畅程度
你可能会觉得可以使用部分或全部的 DORA 指标来回答性能、效率,甚至是活动,没错。
对于满意度和福祉,我们可以使用如下方法,如员工满意度得分(ESS)、员工净推荐值(eNPS)或员工参与指数(EEI)。在开始时,你可以通过简单的调查开始。
性能指标的想法包括交付时间、从事件到恢复的时间、发布次数和测试代码覆盖率。
要衡量活动,你可以参考以下内容:
-
部署频率
-
代码行数
-
提交次数
-
拉取请求数量
-
审查次数
-
完成的任务/问题
-
已解决的故事点
这些数字并不总是容易收集的。在一些国家,明确禁止评估个人的表现,且只允许对一定数量的人进行此类评估。这也常常使得 SPACE 受到批评。因此,如果你希望使用 SPACE,我们不得不承认,这些指标对于了解开发周期很有帮助,你的主要客户,你应该和负责数据保护的团队沟通,他们负责确保正确设置这些内容。
类似的问题 出现在沟通与协作维度上。 如果你不想查看通信工具的用户统计数据,合并请求、合并时间,或提交、合并请求或问题票中的评论数量,都是一个不错的开始。 你还可以通过征求反馈来评估会议的质量。
效率和流动性的最后一个维度可以再次基于 DORA 指标。 此外,评估开发周期中有多少次交接,开发人员真正专注的时间是多少,以及他们的 速度是多少,也是非常有帮助的。
SPACE 框架 可以在个人、团队和组织层面使用。 以下是迈克尔·考夫曼(Michael Kaufmann)书中的图示, 《通过 GitHub 加速 DevOps》,提供了进一步的 这些层级的示例。
图 2.18:迈克尔·考夫曼(Michael Kaufmann)提供的 SPACE 指标示例 [16]
通过 SPACE 框架,我们 现在可以深入洞察开发过程,这对我们作为平台工程师非常有帮助,并且它扩展了 DORA 指标。 我们可以将这些 指标相互叠加。 这使得产品负责人、架构师和平台工程师可以评估他们是否以正确的方式做正确的事情。 然而,我们缺少来自 开发者体验 (DevEx)专家的反馈。
DevEx 框架
SPACE 和 DORA 缺乏 DevEx 的视角。 此外,虽然 我们正在关注满意度和流动性,但它并没有给我们提供关于平台工程团队的完整画面。 这就是 DevEx 框架 发挥作用的地方 [17]。它将视角限制为仅仅三个维度。 它们共同构建了 DevEx 的基础,并能够扩展其 行动范围。
图 2.19:DevEx 的三个核心维度
从开发者的角度来看,流动状态是指他们 100%专注于编写代码,几乎忘记了时间、饥饿和其他需求。 流动状态越容易实现和维持, DevEx 就越好。
我们谈论了很多认知负担。 简而言之,一个良好的 DevEx 包含非常低的 认知负担。
最后,反馈循环衡量开发者在其行为上收到反馈的速度和质量。 反馈越好,开发者就能以最小的摩擦和损失,更加持续和可操作地做出反应。
要 衡量 这些是困难的,因为答案介于实际指标和 主观反馈之间:
-
心流状态:
-
指标:重新提交的提交记录,变更请求数量,每个 拉取请求的提交次数。
-
主观反馈:他们感到被打断的频率如何? 他们是否感到持续的压力或紧迫感? 他们的 决策自主权有多高?
-
-
认知负担:
-
指标:重新打开的缺陷数量,调试时间,组件的依赖项数量,以及解决 技术问题的时间
-
主观反馈:编码时间与其他任务的时间;他们组件的技术范围,以及他们需要多频繁地 切换上下文
-
-
反馈循环:
-
指标:周期时间,部署频率, 平均修复时间 (MTTR),缺陷数量,以及 测试自动化的水平
-
主观反馈:代码审查的有效性、内部团队沟通以及 反馈质量
-
正如你可以 从这些例子中看到的,解释的空间很大。 当你定义平台的 KPI 时,必须确保这些指标被清晰描述。 你需要特别准确地解释你如何解读哪些反馈和指标以及 如何解读。
重要提示
架构师必须理解这些 KPI 及其含义,以便能够有效地改进平台。
使用性能指标
通过 之前的框架,一些性能指标被突出了出来,例如关闭的问题数量或故事点。 这些指标在团队层面上运行良好,但也可能导致 许多误解。
然而,有一种方法并非抽象且不清晰,像故事点那样,而是一种万无一失的方式,用来与用户和利益相关者讨论平台及其效率:成本。 我知道这不是一个创新的 KPI,但许多团队往往做得不正确,产品负责人也对此感到畏惧。 我也并不意味着要报告团队的成本、基础设施或许可证。 你可以利用成本指标作为平台表现的证明,及其平台团队。
每次变更的成本
每次变更的成本 是一种 有效的方式,能够突出平台的改进和能力。 在云原生生态系统的最终用户社区中,我们可以看到这个 KPI 被用来讨论平台的运行情况。
让我们比较两种不同的每次变更成本: :
-
$500 每次变更:每月$15,000,或每年$180,000,基于每月 30 次变更
-
$80 每次变更:每月$2,400,或每年$28,800,基于每月 30 次变更
显然,两个数字之间有着巨大的差距。 但是你应该考虑到,最初你的成本会较高,而且变更次数很少。 理想情况下,平台团队和平台本身会随着时间的推移变得更好,从而稳定整体成本,但变更的次数会增加。 这将导致每次变更的成本降低。 下面的图表展示了这一点,便于更好地可视化。 虚线展示了整体成本的例子。 随着平台变得更加高效,整体成本略微增加。 深色实线表示每年的变更次数,虚线则表示每次变更的成本。 正如你所见,随着你能够进行的变更次数增多,每次变更的成本大幅下降。 这虽然是一个非常基础的数字,但它是你与平台及其平台工程团队沟通的有力工具。
图 2.20:每年总成本 示例
每个项目/产品的成本
相关的 成本每变更的成本是每个项目、产品或应用的成本。 我们可以从两个不同的方向来看这些成本:
-
总共享成本:仅关注团队成本、额外工作量或非因果关系成本等方面 不是因果关系基础的
-
平衡的因果关系成本:因果关系成本包括除共享成本外,项目所消耗的基础设施和服务的实际成本 项目
为了突出平台和团队的表现,我建议选择总共享成本。 这样的数字很容易获取,并且可以在项目之间进行分配,使得你能够在每月不费太多力气的情况下追踪它们。 另一种选择是 每个项目的引入成本。对于这个指标,你需要计算每个使用平台的项目在引导过程中的工作量。 然而,我个人不会在这些指标上花费太多精力。 它们更像是修辞数字,并不能提供关于平台性能的深入见解,而更多是关于你在引导过程中的效率 在 引导中的表现。
用户/产品的间接成本
间接成本的视角与每变更成本非常相似。 在这里,你将所有直接成本和共享成本相加,并仅减去消耗的资源。 因此,区分像代理、网络流量以及可能的与用户相关的个人成本与产品实际使用的资源是很重要的。 计算这一点比较复杂,但结果是平台及平台团队的性能指标。
这是一种分歧的指标。 一方面,它应该尽可能小,以便能在内部销售平台。 另一方面,这个数字代表了平台实际价值的成本。 因此,我认为我们需要隐藏一个既不太昂贵也不太便宜的中间地带。
总结
本章向你介绍了定义平台原则以及如何制定你的平台团队目标。 现在你手中拥有了文档化和设计平台架构的工具,接下来是针对不同平台的最终用户示例。 本章为你提供了关于平台能力的额外视角。 通过 TVP 的方法,你学会了如何专注于单一里程碑而非全局目标,并更快适应需求。 最后,我们向你介绍了几种衡量平台采用情况和 性能指标的方法。
在 第三章,我们将讨论为平台构建基础的细节。 首先,我们将向你介绍我们的参考公司和示例公司,并解释一些细节。 你将学习到基础设施基础、混合云以及 软件即服务 (SaaS)的挑战,以及创建基础架构的参考架构 。
进一步阅读
-
[1] 延迟成本:项目延迟的经济影响 交付: https://businessmap.io/lean-management/value-waste/cost-of-delay
-
[2] Evan Bottcher,关于平台的讨论: https://martinfowler.com/articles/talk-about-platforms.html
-
[3] Miro 模板,平台工程目标 画布: https://miro.com/miroverse/platform-engineering-purpose-canvas-template
-
[4] 团队 拓扑结构: https://teamtopologies.com/
-
[5] PlatformCon2023,平台即代码:通过参考架构简化开发者平台设计 架构: https://youtu.be/AimSwK8Mw-U?si=1CDAJb1gLtlCgeyH
-
[6] PlatformEngineering.ORG 工具: https://platformengineering.org/platform-tooling
-
[7] CNCF 景观: https://landscape.cncf.io/
-
[8] Wasm 示例源代码:
-
通用 页面: https://webassembly.org/
-
一个简单的 Kubernetes 运维程序用于运行 Wasm – kwasm: https://kwasm.sh/
-
一个企业级运维程序和开发工具包用于 Wasm: https://www.spinkube.dev/
-
-
[9] ThoughtWorks 平台技术战略 层次结构: https://www.thoughtworks.com/insights/blog/platform-tech-strategy-three-layers
-
[10] 精益 创业: https://theleanstartup.com
-
[11] ICE 打分模型 模型: https://www.productplan.com/glossary/ice-scoring-model/
-
[12] 谷歌创业课程 地图: https://www.startuplessonslearned.com/2010/09/good-enough-never-is-or-is-it.html
-
[13] GitLab DORA 指标: https://docs.gitlab.com/ee/user/analytics/dora_metrics.html
-
[14] DORA 报告 2023: https://cloud.google.com/devops/state-of-devops
-
[15] DORA 教程: https://keptn.sh/stable/docs/guides/dora/
-
[16] 迈克尔·考夫曼,《通过 GitHub 加速 DevOps》 GitHub: https://www.packtpub.com/product/accelerate-devops-with-github
-
[17] DevEx 框架: https://queue.acm.org/detail.cfm?id=3595878
第三章:构建支持 平台能力的基础
解决用户遇到的问题,设计良好的用户和开发者体验,避免技术复杂性,是成功产品和成功 平台工程的基础步骤。
实际上,许多项目失败的原因是忽视了这些基础原则:我们看到架构师迷失在技术细节中,忽略了他们需要解决的问题。 项目失败的一个常见原因是最终用户在新产品创建过程中的参与不够持续。 通常,架构决策是在没有考虑新产品如何适应现有生态系统、流程和组织技能的情况下做出的。 所有这些都导致了一个不稳定的基础,有限的成功潜力 。
在本章中,我们将详细讲解定义平台的坚实基础的必要步骤和流程,该平台可以从初始功能集成长为支持关键企业的 平台能力。
因此,我们将在本章中涵盖以下主要主题:
-
金融 One ACME——我们的 虚拟公司
-
通过找到 正确的视角 克服平台的复杂性
-
考虑现有流程并整合一个 新实施
-
设计 基础架构架构
-
探索多云、多 SaaS 以及能力的 碎片化
-
探索一个参考架构 用于我们平台
金融 One ACME——我们的虚构公司
在本节中,我们将学习 如何理解工程组织中用户的需求,如何平衡不同团队的需求,以及如何决定平台应该包含哪些能力,哪些 不应包含。
为了使这个更具应用性和实际性,我们将向您介绍 金融 One ACME。虽然它是一个虚构公司,但我们将在本书的其余部分中介绍并使用的历史、技术挑战和团队,都是我们过去几年在许多组织中看到过的。 拥有这样的组织可以帮助我们更好地解释如何将本书中所介绍的理论应用到 实际行动中。
让我们来看一些 关于 金融 One ACME的重要细节:
-
Financial One ACME 的简史:Financial One ACME 一直是金融服务市场软件解决方案的领导者。 公司成立于 2000 年代初期,采用经典的三层应用架构(Windows 富客户端、应用服务器和数据库),客户将其安装在自己的数据中心中,并且每年发布两次软件更新。 每年发布两次。
多年来,Windows 富客户端逐渐被 Web 客户端所替代。
-
提供自托管 SaaS 和本地部署的产品:2015 年,SaaS 托管版本的需求增加了。 与其重新设计产品以支持多租户的 SaaS 解决方案,决定是简单地为每个 SaaS 客户单独托管应用服务器和数据库,且所有服务都托管在现有的 Financial One ACME 数据中心中。 这解决了数据存储位置和数据访问的问题。 然而,这意味着随着 SaaS 客户数量的增长,运营开销也随之增加,因为每个客户(=租户)都在其 独立的虚拟机上部署了生产环境。
此外,IT 运维面临着不断扩展数据中心容量的挑战,以应对生产环境随业务增长而扩展的需求。 由于客户规模不同,他们还需要为每个租户进行单独的容量规划,以确保环境大小合适,避免 资源过度配置。
另一方面,开发团队负责预生产环境的管理。 这包括从开发工作站、构建服务器到预生产测试和 暂存环境的所有设施。
-
转向每月发布:从 2015 年到 2020 年,发布频率不断提升,最终形成了每月发布一次的周期。 这些发布由开发团队构建和测试,然后交给 IT 运维部门进行部署,既包括 SaaS 环境,也包括那些仍在本地部署软件的客户。 这种速度的变化导致了一个情况:并非每个客户都希望如此频繁地更新软件,因为更新必须与他们的内部变更请求流程对接。 一些客户的版本滞后了多达六个发布,这给开发团队增加了额外的负担,必须支持所有这些 较旧的版本。
-
迁移到云端:在 2020 年,业务扩展到新地区,随着扩展,要求也增加了,需要在新地区提供 SaaS 服务。 公司决定不再建设更多的数据中心,而是 将现有的生产架构迁移 到公共云提供商的计算服务上。
这一举措还包括了新的流程和指南,关于如何更新软件或访问这些云服务器上的数据——例如,如何访问属于 租户 Y 的 X 服务器日志!
-
被新兴金融科技公司超越:在疫情期间,涌现出了一些新兴的金融科技软件公司,这些公司是 为云端而生、为云端架构设计的!这给 Financial One ACME 带来了压力,因为这些新的仅 SaaS 公司的架构不需要维护一个支持 SaaS 和本地环境的传统架构。 它们的架构也是多租户和多云的,这使得它们比 Financial One ACME 的同类产品运行得更加高效和低成本。
领导层做出了 战略决策,重新架构他们的服务,同时提升开发、支持和运营现有平台的效率,直到每个客户都能迁移到未来的 仅 SaaS 服务。
现在我们到了 2024 年,是时候思考如何帮助这个组织实现现代化并重新创造自我。 Kubernetes 和云原生是未来的技术栈! 希望寄托在平台工程上,改善工程师们在未来技术栈上的工作,同时维护旧技术栈。 这就是我们发挥作用的地方——新成立的平台 工程团队!
现在,让我们了解一下我们未来的 内部开发平台(IDP)的潜在用户:
-
开发团队:管理所有预生产工具 和环境
-
IT 运维:谁在管理本地数据中心和云端 计算资源
-
DevOps:负责从应用层面部署和运营现有基于 SaaS 的生产环境的团队
-
质量工程师:专注于在软件推广到生产环境之前进行测试的团队 以保证质量
-
站点可靠性工程师(SRE):专注于弹性、可用性,帮助报告和执行服务水平协议(SLA) 和服务水平目标(SLO)
-
技术文档:负责准备面向最终用户的文档,配合每个发布版本,包括发布说明、新特性以及 使用指南
-
其他人:包括 数据库管理员, 项目经理, 产品负责人, ProdSec, 以及其他人
现在我们知道了团队是谁 我们 作为一个团队是谁以及 我们的 潜在用户是谁,接下来让我们看看 我们 需要如何构建一个平台来解决 他们的 痛点!
通过找到正确的视角来克服平台的复杂性
“我们花了几个月时间构建了我们的新平台。 开发人员讨厌它! 帮我 理解为什么!”
我们不想最终陷入 那种不得不在公共讨论论坛上发布这样的问题的情况。 这个标题——信不信由你——来自一篇真实的帖子。 如果你想了解更多关于这个故事的信息, 可以阅读 Reddit 上的帖子 [1] ,该帖子提供在 进一步 阅读 部分。
那么,为什么会发生这种情况呢? 许多平台工程项目失败的原因与其他产品开发项目失败的原因相同:有人有了一个好主意——建造了或者让别人建造了一个产品——但最终发现没有人看到这个新产品的好处,因为它没有解决任何人实际面临的问题。 人们所面临的问题。
许多人犯的错误是不通过潜在的最终用户来验证初步想法,这些用户可能会从该解决方案中受益。 如果你找不到一群具有需要的新产品能够解决的实际问题的用户,那么最好根本不构建产品,因为它注定会从 一开始就失败。
如果你曾从事过产品管理工作,你可能会想,“但这不就是产品管理 101 吗!” 完全同意! 然而,并非每个负责构建新平台的团队都拥有产品管理经验。 我们见过许多团队发现自己处于这样一种境地,他们可以开始构建一个平台,但并未意识到它与构建任何常规产品的相似之处。 在开始构建之前,构建产品的许多任务已经开始了 *产品。
应用基础的产品管理原则——“不要给用户更快的马”
成功的 平台工程方案应与过去成功的产品团队所做的相一致: 过去:
-
识别 一个拥有足够大用户群体的问题 基础
-
理解 为什么这是一个挑战以及目前它的负面影响是什么 现在
-
研究 为什么这个问题尚未 得到解决
-
如何 量化解决 这个问题 的好处
为了回答这些问题并超越基础,我们建议与你的潜在终端用户进行交谈。 让他们告诉你他们面临的实际问题,并给予他们自由,解释一种能使他们理想地完成工作的解决方案。
在倾听时,请确保你没有被当前知道的任何技术限制或挑战所局限。 有一句名言,归功于 亨利·福特 据说他曾说:“如果我问人们他们想要什么,他们会说更快的马。” 你会发现,用户通常能够轻松描述他们的问题。 然而,他们通常提出的解决方案受限于他们认为可能的范围,或者是当前意识到的技术限制。 。
现在,我们并不打算从一个需要数月或数年的革命性新软件工程方式开始。 然而,这种思维方式是重要的,因为它是朝着解决别人未能解决的问题迈进的一步,而这个解决方案 能够被广泛采用!
首先,我们来思考如何 解决这个问题 使用 最简单且最快速的 技术方案。 不要一开始就过度设计 试图提出最佳或最具革命性的技术实现方案。 虽然这是一个鼓舞人心的目标,但我们的初衷是 快速获取反馈并验证 我们提出的解决方案是否解决了潜在 最终用户的痛点。
为了获取这些快速反馈,你需要做 以下几件事:
-
快速交付 一个 解决方案
-
展示 给你的潜在 最终用户
-
获取 持续反馈
-
根据 反馈进行 优化
-
继续 通过这些步骤 进行迭代
这个过程 会一直持续,直到你能够证明用户愿意使用你的解决方案,因为它改善了他们完成 事情的方式。
避免“沉没成本谬误”
并非每个项目都会成功,不管你尝试和迭代多少次。 “ 沉没成本谬误 ”是一个在日常生活决策中经常见到的问题模式, 在软件工程中也同样存在。 它突出了一个问题,即组织在一个策略上继续投资,因为已经做出了投入,即使显然停止投资会更好,因为该策略不可能成功。 关于这一点有很多材料可以阅读,例如 沉没成本 的相关文章 [2]。
因此,明确何时停止迭代非常重要。 如果“用户喜欢这个解决方案”这一时刻在一定时间内没有发生,你必须准备好停止并终止这个项目。 为此,你需要为自己设定 达成这一 验证点 的里程碑。 记住,正如前面所提到的,你不希望最终出现类似“我们花了几个月时间构建这个平台。 开发者讨厌它! 帮我 理解为什么!”这样的结论。
构建用户需要的东西——一个实际的例子
让我们回到最初的步骤。 我们需要构建的是什么? 在产品管理中,有许多不同的思维方式(例如请参见 图 3*.1* ,这是其中一个例子),它们展示了构建的事物与用户需求之间的差异。 如果你搜索关于过度工程的思维方式,结果也是如此。 它们得出了相同的结论: 在没有先理解用户需求的情况下构建事物! 用户需求!
图 3.1:过度工程悖论
我们有可能避免一种情况 ,即最终构建出一个无法解决真正问题,或者以过于复杂的方式解决问题,并且没有投资回报的情况。 投资回报。
每个旅程中最难的步骤是第一步。 在我们的案例中,第一步是理解 谁 是我们潜在的平台注册用户,以及 平台可以解决的真正痛点是什么 。
为了看到这一点的实际应用, let’s walkthrough the several steps on how we would approach this for Financial One ACME!
第一步——理解用户的真正痛点
在走廊中的对话中,开发团队常常抱怨,分析软件中的问题,在生产环境中要比在预生产环境中容易得多。 他们可以完全访问构建服务器(Jenkins)和测试工具(Selenium 和 JMeter)的所有日志,以及他们部署软件的环境。 他们可以轻松增加日志级别,或者迅速部署一个包含更多日志输出的新版本,以更快地解决问题。 更快地解决问题。
当 生产环境中发现问题时,分析问题是完全不同的故事! 开发团队必须通过提交 Jira 工单来请求 IT 运维的许可,以便获取日志访问权限。 这有时需要几个小时,因为 IT 运维团队通常会被其他许多任务压得喘不过气。 IT 运维团队也没有关于软件记录日志的位置的内部知识,开发团队也不总是在初始工单中提供这些信息。 因此,通常需要多次迭代才能捕获到所需的日志,并将其上传到 IT 运维团队管理的工具,以便与其他团队共享生产相关数据。 更改日志级别也不是那么简单。 这种生产环境的更改必须遵循特别的变更审批流程。 作为软件变更,这由 DevOps 团队处理,这进一步拖慢了进程。 这使得事情变得更加缓慢!
对开发团队来说,这意味着他们不能像以前那样直接远程登录到服务器上即时访问和分析日志,而是必须通过 IT 运维的中央生产数据存储工具来分析这些日志。 然而,开发团队并不太熟悉这个工具,因为他们并不经常使用它。 该集中式工具还有自己独立的权限系统,最初是为了防止未授权的访问敏感数据而设置的。 由于该系统与开发团队使用的认证和访问控制系统并未集成,通常与当前团队的分配情况不同步。 这导致了个别工程师无法访问他们需要的日志,从而导致与 IT 运维和 DevOps 之间的额外沟通,或者通过一个未经批准的捷径,直接询问恰好有访问权限的开发同事来获取 日志!
如你所见,开发团队中充满了很多挫折和痛苦。 但正如你所想象的那样,IT 运维和 DevOps 团队也面临着大量的挫折。 他们在操作生产环境时,经常会被要求查找并提供生产数据访问权限,或批准日志级别的更改,这些任务不断打断他们的工作。 他们经常需要来回沟通,才能弄清楚请求的是什么数据,数据在哪里,谁应该有权访问 这些数据。
通常会有大量的讨论来理解完整的情况,理解双方的痛点,并且获取足够的细节,以便开始思考更好的解决方案。 当你在组织中应用这一方法时,计划足够的时间并提前通知你想要交流的人,以便他们可以整理思路来进行 这些对话!
为了开始提出解决方案,最好先组织各方痛点的概览,如下表所示: 在 以下表格中:
| 问题: 开发人员无法直接访问生产环境中的日志 日志 |
|---|
| 痛点: 开发团队 |
| 需要创建 Jira 工单来请求访问生产环境中的日志。 |
| 大量时间都花费在工单上,直到 IT 运维团队找到正确的日志 来捕获。 |
| 在生产环境中进行故障排除时,很难更改日志级别。 但仍然需要创建更多变更请求工单。 |
| 低效的日志分析。 开发人员更习惯于使用预生产环境中的工具。 生产环境中的工具对他们来说不够直观,反而降低了 效率。 |
| 处理生产日志中的权限问题 分析工具。 |
表格 3.1:将问题及其痛点组织成易于理解的表格
现在我们有了 双方的痛点列表,是时候考虑这些痛点的解决方案了,分析该解决方案的影响、成本,以及其 投资回报率 (ROI) 将会是什么!
步骤 2 – 量化解决这些痛点的收益
我们从 量化一个解决方案的影响开始。 这是必要的,以证明构建一个能解决这些痛点的平台所投入的时间和精力。 虽然之前解释的痛点是真实的,但我们需要理解这些问题是偶发的还是经常发生的。 我们需要回答的问题是,是否值得投入数周时间来构建一个解决 这个问题的平台?
回到相同的团队,现在是时候量化那些列出的痛点的成本,按时间花费或实际的美元来计算。 我们可以通过有根据的猜测或从他们当前的时间追踪中获得这些数字(最佳选项)。 由于团队目前正在使用工单,我们应该能够获得这些工单的总时间花费 在两方之间。
这里是一个修订后的表格,包含了额外的 成本影响!
| 痛点/每月花费的时间 | 开发团队 | IT 运维 | DevOps |
|---|---|---|---|
| 请求日志访问的缓慢过程 | 2 天 | 4 天 | |
| 更改 日志级别 | 0.5 天 | 0.5 天 | |
| 低效的 日志分析 | 2 天 | ||
| 解决权限问题的变通方法 | 0.5 天 | ||
| 总计 | 每月 5 天或每年 60 天 每年 | 每月 4 天或每年 48 天 每年 | 每月 0.5 天或每年 6 天 每年 |
表 3.2:量化每个痛点的收益,并提供一个简洁的概览
现在,这是一个 很好的概览,包含了一些有趣的统计数据,可以帮助我们更容易做出决策。 如果我们能够解决开发者目前面临的所有痛点,尤其是他们现在无法轻松访问生产环境中的必要日志文件,我们每年可以节省多达 114 个工程工作日。 这是一个很好的起点,也是一个强有力的理由,去投资提高团队效率,进而投资于 平台工程!
步骤 3 – 提出一个能改善开发者体验的解决方案
现在我们知道 我们每年最多可以节省 114 个 全职等效 (FTE) 工程师工作日,我们应该继续推进并提出一个解决方案,呈现给相关用户。 我们不能展示解决方案的技术细节,而是应该描述开发者将如何体验用户旅程。 开发者体验 是平台工程中经常讨论的 关键词。 所以,让我们提出一个能为开发者带来全新体验的解决方案,激发他们使用 我们的解决方案!
像产品工程一样,我们需要通过询问终端用户他们希望如何与未来的解决方案互动来让他们参与其中。 开发者通常偏好通过代码或简易使用的 命令行接口 (CLI) 来完成所有工作。 这里重要的一点是,我们希望提出一个适合当前工作流程和工具的解决方案,这样我们的用户就无需学习另一个工具或改变他们的工作方式。 。
在我们的场景中,提案采用了 代码化配置 的方法。 开发者可以在代码中指定日志级别、日志输出、所有权和通知渠道。 这可以是一个独立的 YAML 或 JSON 文件,也可以是 Kubernetes 部署定义的一部分。 开发者只需要将该文件提交到他们的 Git 仓库。 DevOps 和 IT 运维可以验证并批准 拉取请求 (PR), 确保所有数据准确无误。 如果有新的警报出现,或者有人请求日志,新的平台工程能力将获取该组件的正确日志文件。 然后,它使用所有权和通知信息联系开发团队,提供相关日志的链接或摘要,以便解决问题。 下图展示了提议的端到端工作流,并展示了它如何改善开发者、IT 运维和 DevOps 的体验:
图 3.2:通过代码化配置提升开发者、DevOps 和 IT 运维的体验
该 提议的解决方案解决了当前所有的痛点,同时确保只有拥有组件的团队可以查看他们的数据。 该解决方案还具有可扩展性,使其在生产和预生产环境中都能以相同的方式工作。 这是未来迭代的 这一能力!
步骤 4 – 你的第一个原型
如果提议的 解决方案被接受,就可以开始进行原型实现。 原型是获取快速反馈的好方法,虽然实现不必完美,但也能提供有效反馈! 就我们的目的而言,原型是最好的方法,因为我们需要验证用户想要解决的问题是否能够以他们愿意使用的方式解决 我们的解决方案。
原型的第一部分应聚焦于 接口 ,即我们正在构建的这一新功能的接口。 在我们的案例中,这就是我们之前讨论过的配置文件。 原型设计中的一个关键考量是决定解决方案是否应该在现有技术栈(云虚拟机上的三层应用)上解决问题,还是仅仅想在 Financial One ACME 将其新的云原生实现迁移时解决这一问题。 目标应该始终是提供相同的开发者体验,无论底层技术栈如何。 然而,在实施过程中,收益和投入的差异可能会 非常大。
为了验证这两个技术栈的原型,请参见以下的配置即代码文件:
https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/plat-engi-arch/img/Table_01.jpg
表 3.3:两种声明性方式实现提议的解决方案
两种 选项都允许开发团队提供所有相关信息,并允许 DevOps 和 IT 运维人员 验证这些信息:
-
服务详情:名称、版本、所属组件 。
-
所有权:团队标识符、选择的通知工具和选择的频道 。
-
日志:日志级别是什么,日志写入到哪里 。
在这个 Kubernetes 示例中,你还可以看到我们如何通过已经标准化的注解来传递一些信息,例如app.kubernetes.io/name、part-of和version。我们还可以看到像日志级别这样的信息可以传递给容器,因为在这个配置文件中改变日志级别也可以改变由已部署的容器产生的日志!
在进行任何实际实现之前,可以先获取关于该提议配置文件格式的早期反馈。 这给开发、DevOps 和 IT 运维团队提供了机会,他们可以提出额外的元数据需求,如 服务的优先级 。 这可以用来定义当生产环境出现问题警报时的升级流程,或用于发送更新邮件给 团队的备用邮箱地址。
我们提议的解决方案的核心不是配置文件,而是能够响应开发者请求的自动化过程,同时也可以由警报触发。 最简单的解决方案是一个简单的服务,它暴露一个 REST 端点,可以用于这两种使用场景的触发。 该服务需要在一个能够访问 以下内容的环境中运行:
-
持有“配置文件”的 Git 仓库或 K8s 集群
-
对目标环境中现有日志解决方案的 API 访问
-
访问 通知工具的 API
要开始 一个最小可行原型,我们可以定义只支持 K8s、只支持生产日志解决方案,并且只支持单一的通知工具,如 Slack。 这使我们能够通过原型证明其价值,并且有扩展到其他配置数据源、附加日志环境以及更多通知工具的选项。
剩下的就是 REST API 的定义。 在这里,我们应该与开发和 IT 运维团队进行咨询,因为他们是该 API 的主要使用者。 开发者使用它按需请求访问日志,而 IT 运维团队在问题被识别时调用该 API。 下表展示了适用于这两种使用场景的 REST API 定义示例:
| 请求数据 按需提供 | 通知 问题 |
|---|---|
GET https://logservice/request?service=fund-transfer-service&environment=prod-useast-01 | GET https://logservice/request?service=fund-transfer-service&environment=prod-useast-01&incident=PROD-1234 |
表 3.4:新提议服务的 REST API 示例
尽管两种实现方式都试图为这些服务找到正确的日志文件,并将其发送到正确的团队,Notify API 还接收一个事件参考,这使得我们的实现能够在发送给 开发团队的消息中包含该信息。
作为这个解决方案原型的一部分,我们还可以做很多事情: 例如:
-
确定当前的 SDLC 效率,并学习如何衡量我们打算 带来的积极影响
-
提供 CLI、聊天机器人或 网页 UI
-
为新服务创建一个模板 Git 仓库,包含 新的配置
-
创建审计日志以跟踪谁在 请求数据
-
暴露指标以跟踪 API 的使用情况和性能
-
实现适当的身份验证以调用 REST API
-
实现速率限制,以避免在调用后台 Git、K8s API 或日志 平台 API 时出现问题
这个列表可能 还可以继续。
并不 需要在一开始就实现所有这些功能,以验证原型并证明 这些能力的价值。
将基本的产品管理技能应用到您的平台项目中
到目前为止,我们学到了如何理解用户的真实痛点,如何量化为这些痛点构建解决方案的益处,如何提出解决方案,以及如何通过构建 原型来保持用户的反馈循环!
现在我们明白,在构建新平台时,我们需要一种产品思维方式,是时候扩展我们的需求收集了。 通过了解平台如何融入现有的端到端流程和工具,超越开发者的需求,将为我们未来的采用和能力增长打下基础!
考虑现有的流程并整合新的实现方案
我们刚才讨论了如何识别用户的真实痛点,以及如何选择合适的候选项为首批原型进行早期反馈。 然而,需求不能仅仅来自最终用户。 我们必须超越仅通过聊天机器人、模板库或新的 CLI 提供自助服务的做法。
我们需要审视并分析整个价值创造过程,看看新平台的功能在其中如何定位。 我们需要确保我们理解当前的 软件开发生命周期 (SDLC)——这是组织在开发、发布、运行和退役新软件时遵循的过程。 有几个问题我们需要能够 回答:
-
引入变更到现有的 SDLC 的标准和流程是什么? ?
-
当前 SDLC 效率是如何衡量的,我们如何衡量我们预期的积极影响? 。
-
是否有我们需要遵守的关于新工具的监管要求?
-
组织内需要被通知或批准新工具的人员是谁?
-
新工具是否与现有系统进行集成,满足认证、访问控制、审计、可观察性、安全性 和弹性等要求?
第一步是了解现有流程,如何证明我们想要实现的积极影响,扩展它的需求,以及谁是关键的 决策者。
了解现有的 SDLC——“工件的生命周期”
作为 平台工程 旨在提供能够改善和改变开发人员在 SDLC 过程中执行特定任务的能力,了解组织中当前的 SDLC 是非常重要的。 特别是在大型企业中,很可能并非只有一个过程,而是许多在多年来不断演化的过程。 同样,很可能没有多少人——如果有的话——能从第一个需求和工件创建开始,一直到新软件在生产环境中投入运行,再到其被替换 或退役。 我们非常重要的一点是,不能犯假设我们——或者某一个人——了解现有端到端过程的错误。 即使是那些在公司工作多年的工程师,通常也会生活在自己的信息泡沫中,只对从一个新想法的诞生到代码发布、运行,最终被 退役的全过程有一个有限的了解。
工件生命周期实验——从想法,到 git 提交,到生产环境!
学习端到端过程的一种简单方法是做一个 小实验。
作为孩子,我曾 像你一样对河流(无论大小)感到着迷。 我相信你一定也曾将一块木头或一根树枝投入水中,观察它被水流带走的过程。 你可能会沿着河流跑,观看那根树枝一路流向它的最终生命周期阶段:大海! 因为所有的水流最终都会汇入大海。 作为孩子,我们并没有机会将那根树枝一路追踪到大海。 然而,作为工程师,我们有机会追踪一个工件的完整生命周期:从想法的诞生(需求工程工具中的一个工单)到开发者的第一次 git 提交,直到该工件部署到生产环境中,或者被更新或替换 在生产环境中。
我们有两种方式来理解这个工件生命周期。 首先,我们可以选择一个现有的服务或功能,通过分析所有工单、git 提交、管道运行、测试报告、电子邮件、变更请求和事件报告,进行一些取证,从中了解相关的过程、工具和 人员!
另一种方法是让其中一个开发团队创建一个“演示”或“无影响”的功能。 随着特性标志的流行,这可以是一个简单的功能,通过标志改变工件的某些运行时方面。 这样做的好处是,它不会对生产环境造成风险,但它允许我们了解关于当前 SDLC 的所有信息,并由此推导出该组织当前的工件生命周期!
关于工件生命周期的洞察
我曾 举办过几次“让我们理解工件生命周期”工作坊,和世界各地的不同组织合作。 结果是收获了很多关于人、流程和工具的洞察和学习。 这包括 以下内容:
-
什么 任务 从需求到第一次 git 提交,再到 生产部署
-
谁 参与了——不同的团队,负责开发、测试、验证和推动从开发到生产的变更 到生产
-
过程中使用的 工具 以及是否在 不同环境中为相同任务使用了不同的工具
-
过程中哪些任务是 手动 的,哪些是 已经 自动化 的
-
依赖 于其他任务或团队,以保持变更推进 到生产
-
每个任务的 时间 、整体时间、任务之间的等待时间 等等
这些洞察 使你能够创建完整的软件开发生命周期(SDLC)或完整的工件生命周期的可视化。 一旦我们进入讨论我们的平台功能如何影响当前 现有的流程时,这样的可视化将非常有用:
图 3.3:理解软件工件的生命周期rtifact
工件生命周期不仅限于初始交付
虽然 平台工程的工作通常旨在改善软件组件的初始入职或交付方面,但我们不能局限于此。 这就是为什么术语 制品生命周期 是一个很好的替代方案,因为生命周期并不会在初始开发过程结束时停止。 制品的生命周期还包括运营、发布更新、维护,甚至是替换或淘汰 该制品。
在我们从 Financial One ACME 的第一个例子中,我们讨论了一个运营生命周期阶段。 这涵盖了开发团队获取生产日志文件以排查当前问题的繁琐过程。 下图展示了这个生命周期阶段 和过程!
图 3.4:访问日志时事件响应的生命周期
相关团队的需求和现有流程
在我们的 练习中,为了理解制品在生命周期中的流转过程,我们学到了很多关于涉及的团队、现有工具和流程的知识。 我们还了解了未来平台能力可能需要集成的工具,哪些团队需要合作,另外——如果我们最终要替换或与现有工具集成——需要做哪些工作,以确保不会破坏当前工具 实现提供的功能。
以下是一些 发现的例子:
-
单点登录 (SSO):每个工具都需要与 中央 SSO
-
安全性:每个工具都需要通过软件供应链的 安全指南
-
审计:每个工具都需要创建特定的 访问日志
-
服务水平协议 (SLAs):每个关键工具都需要遵守公司范围内定义的可用性 SLAs,以确保 关键服务
到目前为止,我们已经 了解到理解软件制品的完整过程和生命周期是多么重要。 了解哪些团队参与其中,介绍新工具时需要经过哪些现有流程,这一点也非常重要。 我们还了解到,平台工程能力可以在未来的某些领域为软件交付和制品 生命周期提供显著改进!
引入生命周期事件 – 测量和提升 SDLC 的效率
我们已经讨论过工件生命周期的概念。 一个工件通常会经历一系列阶段:需求接受、实施开始、拉取请求、工件构建、安全扫描完成、测试完成、构建验证、工件提升、部署完成、功能发布、问题检测、配置更改、问题 解决、工件退役。 虽然每个组织的生命周期阶段或环节可能有所不同,但我们可以通过 DevOps 无限循环很好地可视化这一过程。 为了追踪工件在生命周期中的进展,我们建议你在每个步骤中记录为生命周期事件。 下图展示了这些事件的示例,以及相关工具和团队应添加的一些元数据,以更好地理解工件从最初的需求 到操作的完整流动:
图 3.5:SDLC 及其工件生命周期事件
生命周期事件的 概念并不新鲜。 许多组织正在通过不同的方式实施这一概念, 例如,在其 CI/CD 流水线的开始和结束时,添加日志输出,包括元数据,如时间戳、Git 仓库、流水线、创建的工件和成功状态。 持续交付基金会一直在进行 关于 CDEvents [3] 规范的工作,该规范定义了一套事件词汇,允许工具以互操作的方式进行通信。 CDEvents 是一个很好的起点,可以扩展以覆盖工件的完整生命周期,正如 之前所提议的那样。
标准化此类事件有许多好处 :
-
每个工件都可以通过其生命周期追溯:这意味着它可以回答诸如谁参与了 工件的创建!
-
发布管理:哪个版本的发布工件已经部署, 何时 由 谁 在 哪个 环境中?
-
生命周期阶段可以被衡量,这为我们提供了 DORA 指标:从初始需求到首次部署需要多长时间(交付时间),我们有多少次部署(部署频率),有多少次部署导致了生产中的问题(部署失败率),以及修复生产问题需要多长时间(恢复服务时间)?
-
合规性:它使我们能够识别某些工件是否跳过了重要步骤,如安全扫描、韧性测试等。
-
互操作性:这指定了我们是使用 Jenkins 还是 GitHub Actions 来构建工件。 如果所有工具都生成相同类型的事件,我们就能控制整个 生命周期。
在 你 定义生命周期事件之前,先查看开源社区中的现有倡议,以及交付、可观测性和 应用生命周期管理 (ALM)领域中的供应商在做什么。 没有必要重新发明轮子,因为目前标准正在制定中!
呈现改善现有 SDLC/DORA 的价值主张
理解 现有的 SDLC 并使工件的生命周期可见,将为我们正在进行的平台工程项目提供宝贵的洞察。 这对于所有工程团队成员来说也是一种启示,因为他们中的许多人很可能从未得到过这种概览,无法看到当前流程中有哪些地方可以 改进。
获得的洞察力使我们能够在价值主张上进行工作,这将改善不仅是开发团队的日常生活,理想情况下还包括 SDLC 过程中许多其他团队的工作。 这就是为什么理解和衡量当前流程如此重要——它不仅能让我们提出新的解决方案,还能呈现有力的数据支持的改进,例如提高交付时间、部署频率、部署失败率或恢复服务的时间(我们钟爱的 DORA 指标)。
基于迄今为止学到的所有内容,这在我们为 Financial One ACME 的日志访问用例中会是什么样子? 我们的初始用例仅关注在生产环境中出现错误时如何改善日志访问。 在了解了完整的端到端流程后,所有相关团队以及现有的流程、工具和组织需求,我们可以提出以下解决方案和 价值主张:
| 建议:将可观察性自动化作为非功能性 软件需求 |
|---|
| 价值主张:提高 DORA 指标,减少认知负担,并扩展 最佳实践 |
| 关键绩效指标(KPI)和 受影响团队:通过自动将生产环境中的相关可观察性数据传递给开发团队,使服务恢复时间提高 50% 。这消除了 DevOps 和 IT 运维团队手动捕获和转发日志的需求。通过自动化捕获和分析早期生命周期阶段(开发、测试)的可观察性数据(日志、指标、追踪和事件),使交付时间缩短 50% 。分析将改善并自动验证新构建的工件,从而减少 质量工程师的手动工作量。通过自动捕获早期环境中的问题,并基于可观察性数据自动检测常见问题(新的关键日志、异常、应用程序缓慢等),使生产部署失败率降低 50% 。 |
| 高级用户旅程 和协作:作为一名 开发团队,我提交一个 可观察性即代码(Observability as Code) 配置文件,其中包含有关日志源(用于自动捕获)、所有权(用于自动路由)和重要日志模式(用于自动验证和 自动报警)的信息。作为一名 质量工程团队,我协作并扩展日志模式,以自动检测回归作为测试 结果分析的一部分。作为一名 DevOps 团队,我协作并基于其他 开发团队的经验和模式扩展日志模式检测规则。作为一名 IT 运维团队,我协作并验证正确的日志源,并基于开发 和 DevOps 定义的相关日志模式扩展生产问题检测。 |
表 3.5:以可展示的布局提出我们的解决方案建议
提出清晰的建议和价值主张
如果我们能够清晰地阐明 我们的平台的优势,成功的机会将更高。
现在我们已经 学会如何设计我们的提案,以包括所有参与软件交付和工件生命周期的人员,现在是时候考虑如何设计 拟议的解决方案。
设计基础架构体系
到 目前为止,我们已经推销了我们的提案。 一旦所有参与的团队和执行赞助商都同意,就是时候进入下一个阶段了:我们需要考虑如何设计解决方案以及如何与基础架构配合,以实现组织的所有非功能需求:弹性、可用性、审计能力、安全性、强制集成等等。
虽然我们在开始阶段不应过度设计,但了解对基础架构决策产生影响的所有要求至关重要。 以下是我们需要能够回答的几个问题:
-
我们如何、由谁以及在哪里部署、更新和运营 平台?
-
是否有组织要求在 特定基础设施上运行?
-
我们的解决方案是否需要在多个地理区域甚至多个 基础设施提供商之间运行?
-
是否有基础设施要求来访问和连接 其他系统?
-
我们的解决方案必须能够支持多少用户?
-
我们的基础架构以及 终端用户的 SLA 是什么?
-
我们如何进行 扩展和收缩?
在 第四章中,我们将 花更多时间深入探讨使用 Kubernetes 作为统一编排层来架构平台核心。 无论您最终决定使用 Kubernetes 还是其他工具作为底层抽象层,您都需要回答这些问题,因为它们将影响您的一些决策。 因此,让我们深入了解如何回答这些问题会影响我们的 架构决策!
避免象牙塔式的方法 – 我们拥有这个平台!
在回答影响基础架构的问题之前,让我们先回答基本的 所有权问题:
我们拥有这个平台!
平台工程团队负责整个平台的端到端产品!
由于我们的平台将提供使交付和操作软件组件更轻松的能力,我们的首要目标必须是遵循我们自己的最佳实践,并且最好能以相同的黄金路径和自助服务功能来部署平台,正如我们希望终端用户使用的那样。 一些组织称之为 做零号客户 或者 饮用自己的香槟。如果我们不遵循这一原则,只是建造一些东西,然后扔给别人希望他们操作,那我们就错失了现代产品思维在 平台工程中的真正意义。
我们需要感受到用户当前在软件交付和操作中所经历的痛苦。 这将成为我们构建平台能力的更大动力,使我们作为软件 团队的工作更轻松。
我们需要避免 象牙塔式的做法 ,这种做法是我们从上而下强迫最佳实践,而自己却没有遵循这些最佳实践。 如果我们这样做,可能会像本章开头提到的那个著名的 Reddit 帖子一样:“我们花了几个月建这个平台。 开发者讨厌它! 帮我 理解为什么!”
现在,让我们回过头来回答之前提到的一些基础设施问题,这些问题可能会影响我们的 架构决策。
组织约束——现有的基础设施要求?
我们需要 弄清楚是否有使用现有基础设施服务的限制。 对于企业来说,可能已经存在与基础设施或云服务提供商的合同。 如果存在这样的限制,它将影响我们的决策——例如,我们是否需要在本地运行和操作自己的 K8s 集群,还是可以利用供应商的托管服务? 如果我们被限制在某个云供应商,这也意味着我们可能只能使用他们的服务(存储、数据库、缓存, 等等)。
关于这一领域,我们还需要关注访问控制、流入和流出以及 成本约束!
在最终确定基础设施 和架构决策之前,了解所有此类组织约束是非常重要的!
连接性约束——互操作性要求?
我们的平台 功能将要求我们连接并与其他现有系统进行交互。 这包括访问 SSO、Git 仓库、CI/CD 管道、可观察性、编排层、云 API 等。
根据平台运行的位置——即本地部署与云部署——这将影响平台如何与所有这些工具连接,或者这些工具如何连接回 平台。
我们需要考虑防火墙、拉取与推送连接、API 限速和成本,因为我们需要确保所有系统之间具有弹性的互操作性。 这些系统。
在最终决定我们的平台基础设施及其与其他系统连接的位置之前,了解所有这些连接约束非常重要。 我们需要与之连接的系统。
弹性约束——SLA 和其他非功能性需求?
我们平台的 目标是改善各种内部用户(开发人员、DevOps、IT 运维、质量工程师、应用支持等)的日常工作。 这意味着我们的平台每次用户需要时都必须保持可用并正常工作。 在全球企业中,这可能意味着需要具备 24/7 的运营弹性和高可用性。 如果平台不可用,我们的工程师将无法进行关键工作,比如发布软件的新版本、修补安全漏洞或扩展工作负载以应对增加的最终 用户需求!
因此,我们需要了解平台上的非功能性需求,例如 以下内容:
-
可用性——例如,早上 9 点 到下午 5 点 在单一时区,或跨所有时区的周一至周五 时间段
-
用户体验——例如,必须保证系统的可接受的最终用户性能,支持最多 100 名并发工程师使用 平台功能
这些非功能性需求还意味着我们需要考虑如何进行横向和纵向扩展。 我们需要定义是否将平台集中提供,以便服务全球各个地区,还是需要将平台组件部署到不同地区,以更好地满足 可接受的性能的用户体验要求。
动态、水平或垂直扩展是我们将在本书后面详细探讨的话题,当我们深入研究如何使用 Kubernetes 作为统一层架构平台的核心时。
现在我们已经找到了所有这些问题的答案,我们将能够做出关于平台基础设施和架构选择的更明智决策,以及 它的能力!
探索多云、多 SaaS 和能力碎片化
当我们研究能力碎片化以及它如何与平台即服务和其可扩展性互操作时,有一件事是我们想到的一个关键功能,虽然一开始可能不太显眼:IDP 应该是多租户的,而不仅仅是多 用户。
作为我们平台能力之一的多租户和所有权
多租户通常是在生产应用程序的上下文中考虑的。 例如,我们的平台客户 Financial One ACME 正在寻求将其单租户产品转变为多租户产品。 这将帮助他们实现更高的利润率,减少运营开销,并带来一系列其他商业上的成功。 在高度监管的行业中,生产应用程序中存在的数据分离应该在应用程序生命周期的每个级别中都存在,包括 IDP。 这不仅是最佳实践,而且可能是获得某些安全性和 合规认证所必需的。
由于生产数据可能进入测试,确保平台上每个用户的默认访问级别尽可能限制,有助于确保如果数据最终被传送到不希望出现的地方,数据的暴露表面将尽可能小。 此外,多租户的完全隔离确保了每个团队可能需要的秘密彼此之间是隔离的,进一步降低了任何 风险表面。
我们将在 第七章中进一步探讨平台的安全性和多租户的优势。 然而,需要注意的是,多租户也有助于减少平台用户的认知负担。 我们将在 第六章中更详细地讨论这一点, 为开发者和 他们的自助服务构建。
多租户意味着我们做出的任何架构决策——我们在平台中包含的任何工具——也必须支持多租户。 以可观察性为例——如果我们捕获日志、度量、追踪和事件,既包括核心平台的,也包括用户部署的应用程序,我们需要确保这些可观察性数据能够“分离”到各个租户。 我们已经讨论过,在部署核心平台时,我们的平台必须包含所有权作为元数据,以及在为新应用提供自助服务模板时。 让我们考虑一个例子,部署定义中丰富了所有权元数据,如在 克服平台复杂性 一节中所讨论的。 这些所有权元数据 可以用来强制访问控制,限制对该部署所捕获的任何数据的访问,包括在查询度量或追踪时使用它作为过滤器: 或追踪:
| **service-abc.yaml (**Kubernetes 部署) | 使用所有权元数据 与可观察性结合使用! |
|---|
| apiVersion: apps/v1``kind: Deployment``metadata:``**name: fund-transfer-service** ****namespace: prod-useast-01**
**spec:
…
**template:**
****metadata:**
****annotations:**
****owner.team: dev-team-backend**
****app.kubernetes.io/name: fund-transfer-service**
****app.kubernetes.io/part-of: backend-services**
****app.kubernetes.io/version: 2.34**
**…
**spec:**
****containers:**
**- name: fund-transfer
**image: "financeoneacme/fund-transfer:2.34"**
…********************** | 注释可以作为 PromQL 查询中的过滤器使用, 例如:sum(rate(container_cpu_usage_seconds_total{annotation_name="owner.team", annotation_value="dev-team-backend"}[5m])) |
表 3.6:如何定义和使用所有权元数据
这些 所有权信息可用于向那些拥有该组件的团队授予可观察性数据的访问权限。 它允许我们将数据按租户进行划分,同时也允许我们平台的管理员或共享服务的所有者分析跨越单一租户的数据。 这也是一个重要的功能,因为我们很可能会遇到跨租户的问题。 因此,拥有适当上下文的全部可观察性数据将对于识别问题和 解决问题至关重要。
数据管道——无论是使用 OpenTelemetry Collectors 还是商业产品——也可以利用这些元数据将可观察性数据发送到不同的后端存储,甚至可以基于租户对这些数据的存储进行分离!
关于所有权和可观察性的话题将在后续章节中详细讨论,因为它是我们平台许多功能和属性的关键支持。
关于在多 X 环境中运行的考虑
在 组织约束 一节中,我们讨论了理解现有的任何约束, 例如我们是否有 业务或监管义务来运行多云、多 SaaS,或——正如一些人所称—— 混合云。
当金融公司 ACME 希望进入不同的全球市场时,可能需要将我们的软件从云服务商的最本地化区域运行——例如,EU-WEST 或 APAC-SOUTHEAST。 甚至可能需要跨多个区域或多个不同的供应商运行,以履行高可用性和弹性要求,同时遵守这些公司所需遵循的标准。 遵守这些标准。
出于竞争或监管原因,也有可能一些云服务商或 SaaS 供应商根本无法使用。 为什么会这样呢? 如果金融公司 ACME 的潜在客户将某个云服务商视为竞争对手,或者某个供应商不符合某些监管要求,他们将无法购买我们的 软件服务。
这听起来 像是有很多限制,几乎没有选择,不是吗? 幸运的是,有解决方案可以解决这个问题:在接下来的章节中,我们将深入讨论 Kubernetes 作为底层抽象层。 在这个抽象层之上构建将使我们更容易——但并非没有麻烦——将工作负载迁移到不同的区域和不同的 云服务商。
由于我们的平台及其所有组件不仅仅会运行在 Kubernetes 上,还将包括其他服务,因此创建一个全面的检查表是很重要的,以避免做出未来难以更改的架构决策。 例如,如果我们的平台需要一个文档存储服务,我们可以选择在 Kubernetes 上运行和操作 MongoDB 等文档数据库,或者从某个云服务供应商那里选择一个现有的 SaaS 服务。 选择托管服务将减少我们的工作量,但我们需要确保每个支持文档存储服务的潜在 SaaS 供应商提供相同的接口、类似的性能特征和类似的成本结构。 如果我们做出错误的架构决策,可能很难做出以下更改:
-
改变我们的实现方式,以便支持一个 不同的 API
-
对不同供应商的性能和可扩展性产生影响
-
增加我们软件的整体运营成本
集中式和分布式平台能力
在 接下来的章节中,我们将提供更多的例子,展示如何将我们的 IDP 及其组件作为一个中央服务、按环境、按区域,甚至按租户(如果有此需求)来运行。 关于组织需求的发现将影响这些决策,例如我们的客户是否要求他们在特定区域运行,或是否不允许使用某个 云服务提供商。
将组件集中化有一个很大的优势,那就是它们更容易管理。 想一想一个 集中式 持续集成 (CI) 系统,比如 Jenkins 或 GitLab,它通过拉取请求触发管道来构建新的工件。 这种 CI 系统的中央实例更容易操作、观察、安全性管理和维护。 另一方面,这意味着所有用户都共享同一个系统,这可能很容易导致瓶颈。 中央系统还需要 访问所有目标环境,这些环境可能位于不同的地理 区域,甚至是其他云服务提供商。 随着每个新团队接入他们的应用程序,或者每个新客户对 Financial One ACME 的需求都可能增加对这些云环境的依赖,尤其是当要求我们软件 特别部署时!
去中心化组件的优点在于能够自动封装数据捕获、存储和访问过程。 这些组件仅被特定区域或环境中的团队使用,这限制了诸如噪声邻居等模式的潜力,我们将在 第六章中详细讨论这一点。去中心化方法的缺点是,随着每个新环境的加入,组件数量的增加使得操作、监控、安全性和管理这些组件变得更加困难。 自动化可以在此提供帮助,但我们不能低估额外的复杂性。 想一想,如果我们的 CI 系统发现了漏洞。 我们需要在所有的去中心化服务中逐个修补,而不是在中央系统中修补一次!
现在我们已经了解了多重 X(包括多租户、云和 SaaS)将对我们的架构决策产生影响,因此,找到努力、收益和外部需求之间的良好平衡非常重要。 到目前为止,我们所获得的所有知识使我们能够提出一个好的平台参考架构,这是我们将在本章最后部分讨论的内容!
探索我们的平台参考架构
架构图是展示一个系统向最终用户提供什么功能及其内部工作原理的好方法。 在这一章中,我们讨论了构建未来平台基础的一些重要步骤以及 其能力:
-
我们平台的目的(解决最终用户的痛点):我们的最终用户是谁,我们需要解决什么问题?
-
用户界面/开发者体验:我们为最终用户提供的理想开发者体验,如何最好地融入他们的日常工作活动中?
-
核心平台组件:选择合适的组件,以适应现有的流程、工具、基础设施 和约束。
-
我们的平台作为产品:像任何软件产品一样,我们的平台必须具备可用性、韧性(即使在高负载下也能正常工作)和默认的安全性。
-
成功的关键绩效指标(KPI):利用可观察性来衡量并推动采纳、效率 和生产力。
一种不同的展示方式是 通过我们平台的高级架构图来呈现。 虽然以下图示并不完整,但它可以作为你将要构建的平台的一个很好的参考:
图 3.6:我们平台基础架构参考(该图像仅作为视觉参考;文本信息并非必需。)
我们的平台作为一个产品,必须有明确的目标!
在进入 技术细节之前,先可视化并阐明目标!
让我们一步步走过这张图,就像你向同事或终端用户展示时那样。 我们将从顶部开始,然后再深入探讨可观测性、可用性、弹性 以及 安全性。
目标——为终端用户提供自助服务
在 第二章中,我们举了一个平台原则的例子,我们称之为 自助服务优先。我们提供了详细的描述,声明:“我们将为客户提供每项平台功能作为自助服务,关注他们的用户体验,并支持自主决定的 软件开发。”
这正是前面图示顶部所反映的内容。 在这里,我们列出了我们了解到的所有潜在终端用户。 对于 Financial One ACME,我们的开发团队通过简化新应用程序的入驻过程或更便捷地访问生产中的遗留系统日志文件,支持他们的用例。 我们还通过提供自助服务功能,减少手动工作和认知负担,支持 DevOps、安全、 站点可靠性工程 (SRE) 和 应用支持团队。
像这样的高级架构图,空间有限。 我们可以通过文字添加不同终端用户自助服务功能的示例,或者——如果需要——为每个终端用户及其 自助服务功能提供这张图的更详细版本!
用户界面/开发体验
每个终端用户 群体都是不同的。 即使在终端用户群体内部,我们也可能会有不同的技能集,这在设计和实施平台的自助服务功能用户界面时需要考虑。 自助服务功能。
开发团队很可能更倾向于待在他们首选的集成开发环境(IDE)中,比如 Visual Studio Code 或 IntelliJ。 他们大概能接受编辑 YAML 文件来启用新的自助服务功能。 有些人可能会期待一个 IDE 插件,能够引导创建这些 YAML 文件,或者一个能提供代码补全和架构验证的插件,来减少像 拼写错误这类错误的发生。
另一方面,同一组织内的其他团队可能希望有一个漂亮的开发者门户 UI —— 比如 Backstage,它提供了很好的模板功能,便于创建 新组件。
然后是自动化工程师,他们既不习惯使用 IDE,也不愿意通过向导点击来创建新项目。 他们需要一个可以用来自动化任务的 API 或 CLI,因为这才是他们习惯的工作方式。 他们可能期待一些 Python 库来调用我们的 自助服务功能。
正如本章前面讨论的那样, 每个用户的技能不同,因此他们对良好的用户体验有不同的期望。 专注于提供良好的用户体验至关重要,因为这将是决定平台是否会被采纳的关键因素。 这就是为什么我们需要重点突出用户界面及其在我们参考架构中的样式,因为这将是用户与 平台互动的方式!
核心平台组件
虽然我们每个人 在选择工具和技术时都有自己的偏好,但选择核心平台组件的正确方法不应基于个人喜好。 它必须基于我们想要通过用户界面交付的自助服务用例(即我们平台的功能),这个界面要能提供良好的用户和 开发者体验。
在前面的图示中,我们将平台组件细分为以下几个领域: 以下几个领域:
-
交付服务:这些 是专注于软件交付的工具和服务,因为这是我们平台的主要用例。 CNCF 开源工具,如 Backstage、ArgoCD、Flux 和 OpenFeature,开源工具如 GitLab、Jenkins 和 K6,甚至商业工具如 Atlassian 的工具,都属于 这一类别。
-
平台服务:作为 一个关键的使用场景,将围绕交付和操作软件组件展开,我们的平台还应提供这些软件组件所需的核心平台服务。 这些服务可能包括缓存或数据库(Redis、MongoDB 或 Postgres)、消息传递和事件(Apache Kafka 或 RabbitMQ)、服务网格(Istio、Linkerd 或 Nginx),以及诸如机密管理、容器注册表、策略代理、自动扩展等核心服务 等等。
-
平台:虽然平台不一定要运行在 Kubernetes 上,但在本书的其余部分,我们将重点关注 K8s 作为基础平台编排层。 然而,Kubernetes 并不是解决所有平台工程问题的万能答案。 目标是选择合适的平台组件,以提供最终用户所需的自助服务。 这可能会导致你将平台运行在虚拟机上,甚至选择一个完全托管的现成 SaaS 解决方案!
-
X-as-Code:除了 优先自助服务外,我们还必须接受 一切皆代码 的理念。 无论 是定义部署、可观察性还是所有权,如 本章前面讨论过的,或者软件生命周期的任何其他方面,一切都应以某种形式的代码表达。 在这里,你应该选择像 Crossplane、Terraform 或 Ansible 这样的工具。 尤其是 Crossplane,它在云原生领域中逐渐成为在声明式方式下编排应用程序和基础设施的首选工具。 此外,确保根据工具在交付和平台服务中的 X-as-Code友好程度来验证你的工具选择,例如它们如何 定义 服务水平目标 (SLOs) 或使用所选 可观察性工具设置监控警报!
-
可观察性:你不会在没有任何遥测和关键指标(如速度、高度或燃油表)的情况下开车或飞行。 我们也不能在没有内置可观察性的情况下操作任何平台。 感谢像 OpenTelemetry 这样的标准以及 Prometheus 和 Fluent 等项目,我们在平台中使用的组件中有许多内置的可观察性信号。 无论是 Kubernetes 本身,还是像 Nginx、Reddis、Harbour、ArgoCD 或 Backstage 这样的工具,所有这些工具都会发出度量、日志、事件和/或追踪,我们可以收集这些数据并将其发送到我们的可观察性后端进行自动分析或警报! 虽然许多工具已经内置了这些功能,但并非每个我们选择的工具都会提供我们所需的所有数据。 因此,基于工具的可观察性状态验证你的工具选择非常重要。 对于某些工具,你可能需要从日志中提取度量。 对于其他工具,你可能需要一个扩展——例如,Jenkins 提供了一个 OpenTelemetry 插件,用于在每次 Jenkins 作业执行时发出追踪。 在其他情况下,你可能需要依赖基于代理的商业可观察性解决方案。
可观察性将在本书后续部分深入讨论,因为它是许多领域的关键基础,例如 SRE、自动扩展、事件响应 和故障排除。
一个可用、具备弹性且安全的平台
平台就是一种产品! 因此,一个我们希望内部用户使用的产品,必须在他们需要时可用,在大量用户同时使用时具备弹性,并且要确保安全,以便我们的用户信任 该产品。
为了确保我们的平台在用户需要时始终可用,我们需要应用与任何成功软件产品相同的架构原则。 对于我们的平台,这意味着所有关键组件也需要默认是可用的、具备弹性且安全的。 让我们来看看以下一些关于 这三个 支柱的示例和最佳实践。
可用性
我们的用户 认为我们的平台可用,当他们可以用它进行我们承诺的自助服务用例时。 还记得我们提议的 从生产环境自助请求日志 用例吗?来自 图 3*.2*?如果开发团队遵循这个自助服务用例,他们期望我们的平台在任何时候,无论是周二中午还是周五晚上 11 点,都能按时交付请求的日志。
该用例涉及许多不同的工具,例如 Git(存储配置为代码文件的位置)和我们自家的解决方案,该解决方案通过 REST API 提供特定日志的请求。 这两个系统都需要可用。 这两个系统还需要在规定的时间内响应请求,并提供有效的响应。
确保可用性的最佳方法是遵循 两个步骤:
-
端到端用例监控:就像我们对业务关键应用程序所做的那样,我们可以设置合成测试来模拟该用例的端到端用户旅程。 在这种情况下,我们将通过执行虚拟提交和 PR 并验证响应时间和响应代码来验证调用 Git API 的正常工作。 我们还会对我们的 REST API 调用请求日志做同样的操作。 然而,这种情况还需要等待请求的日志被发送回开发团队的通信渠道,以便我们可以测量完整的 端到端时间。
这两种情况都可以通过自定义脚本完成,我们将其作为定期作业运行,或者我们可以利用 现有的合成测试解决方案。 您应该验证您的可观察性平台是否已经提供了合成测试,因为许多供应商在其产品组合中都有此功能。 这也将使我们第二步更加容易,即监控和警报关键 质量指标!
-
监控并警报关键可用性指标:作为平台团队,我们希望在最终用户开始抱怨之前,能够在平台自助服务用例不再按预期工作时得到通知。 这就是监控和警报关键指标的作用所在。 我们的合成测试已经提供了一个良好的指标,但我们应该设置自动警报,以防 Git API 或我们的 REST API 开始变慢或开始响应错误。 此外,我们还可以对其他领先指标进行警报。 我们平台中的许多工具——包括我们的 Git 示例——将生成日志以及健康指示器指标。 如果我们看到 任何错误 日志,我们希望能够收到通知。 这些日志可能是早期警告指标。 大多数系统还具有内部队列,例如请求队列。 如果这些队列不断增长,我们希望能够收到通知,因为这意味着过多的传入请求正在积压,最终会导致性能和 可用性问题。
我们还需要做很多其他工作,以确保系统保持可用。 我们将在下一节讨论这些内容,届时我们将 讨论 系统的弹性。
弹性
我们刚才 讨论了我们产品的可用性。 对于我们的最终用户而言,平台必须始终可用,无论他们是系统中唯一的用户,还是有 1,000 个其他用户在尝试执行自助服务任务。 他们还期望平台始终可用,无论我们的内部基础设施或云服务是否出现任何问题。 这就是我们讨论系统弹性的时刻。 它意味着尽管发生了任何意外事件(高负载、组件故障、连接问题等),系统本身 依然保持可用。
从 架构角度来看,我们可以做很多事情来提高系统的弹性,从而实现高可用性。 让我们再次考虑 REST API 的示例。 从部署的角度来看,我们可以做以下几点:
-
负载均衡复制部署:我们可以使用 ReplicaSets 部署我们的实现,这样多个实际的 Pod 实例就需要处理传入的请求。 请求可以通过轮询或其他更 复杂的算法进行负载均衡。
-
实现地理多样性:为了服务全球用户,我们可以将我们的实施方案部署到用户所在的地区。这减少了网络延迟的影响,并根据用户的分布来分配负载。
-
提供自动扩展:**水平 Pod 自动扩展器(HPA)和Kubernetes 事件驱动自动扩展(KEDA)**允许我们基于指标(如 CPU、内存、传入请求量,甚至用户体验)来扩展我们的实施方案。这使得我们能够避免大多数资源限制导致的弹性问题。
-
执行自动备份和恢复:并非所有问题都能预防。如果发生灾难,拥有自动备份和恢复选项非常重要,这样我们可以尽快恢复正常运行。
从软件架构的角度来看,我们的 REST API 有以下几种选择:
-
API 请求速率限制:我们可以限制整体或特定用户/团队的请求数量。这可以避免因某些人不小心(或故意)向我们的系统发送过多请求而导致的问题。
-
排队传入请求:事件驱动架构允许我们将请求排队,并在有工作者可用时处理它们。工作者可以根据队列长度进行扩展。虽然像请求队列这样的额外层可能会影响请求延迟,但这种架构模式将提高系统的稳定性、弹性和可用性。
-
重试和退避机制至下游系统:由于我们还需要调用 Git 或日志监控等后端系统,我们希望确保不会受到它们端问题的影响。为此,我们可以实现 API 重试(当 API 调用超时或失败时)并结合退避机制(增加 API 调用之间的时间间隔)。这些策略将提高我们的弹性,并且有助于我们的下游系统。
安全性
如果我们的平台 随时可用,那是一个很好的开始。 但是像任何软件产品一样,它也必须是安全的。 对于平台来说,这一点尤为重要,因为它使我们的最终用户能够创建、部署和操作新的软件应用程序,而这些应用程序也必须是安全的。 如果我们的平台运行在具有已知漏洞或容易被黑客攻击的堆栈和工具上,我们就会面临攻击者利用这些漏洞进行软件供应链攻击,或获取机密信息的风险。 让我们再看看我们的 REST API。 如果我们允许每个人使用该 API 从生产环境请求日志,最终可能会把关键日志信息发送给 黑客。
这就是为什么对我们的平台、我们使用的每一个组件和工具,以及我们开发的每一行代码应用最严格的安全指南是如此重要。 在 第七章中,我们将更详细地讨论构建合规和安全产品的主题,因此在这里我们只是简要概述。 我们必须将我们的平台视为公司中最关键的软件。 因此,我们不能部署任何具有已知漏洞的组件。 我们必须在所有自定义开发的 API 中实施适当的访问控制。 我们必须使用所有安全扫描和警报工具来保护我们的平台,这些工具也是我们在生产环境中运行任何业务关键软件时会使用的。 生产环境中。
我们是平台工程团队,这意味着我们对平台的安全负责,就像我们对平台的 可用性 和韧性负责一样!
成功的 KPI 和优化
“我们花了几个月时间构建我们的新平台。 开发人员讨厌它! 帮我 理解为什么!”
根据 到目前为止我们所学的内容,我们应该能处于一个良好的位置,以避免我们在本章开始时想要避免的问题。 我们希望构建一些用户喜爱的产品,因为它能让他们的生活变得更轻松。 但我们不能仅凭直觉或个别证据就宣称成功。 我们需要通过 KPI 来衡量我们的影响力,并根据 KPI 报告我们的成功,同时我们还需要利用平台内可以观察到的所有数据, 不断优化这些成功的 KPI,以及平台的运营方面。
我们已经详细讨论了可观察性,作为我们平台的自助服务功能以及我们的最终用户,以及使用可观察性来理解我们平台的内部工作原理,以确保可用性和弹性。 观察我们的平台组件,如 Backstage、ArgoCD、Jenkins、OpenFeature、Git、Harbor、Redis、Istio 和 Kubernetes 本身,为我们提供了关于平台及其功能成功的许多见解。 让我们深入了解一些关键指标,如何捕获它们以及我们可以用它们来优化我们的平台采纳 和效率。
活跃用户
如果像 Backstage 这样的工具成为我们平台的开发者门户选择,我们需要测量有多少用户每天或每周登录 Backstage。 我们希望衡量通过 Backstage 模板引擎创建了多少新项目,以及这导致了多少新的或更新的 Git 仓库。
对于我们在财务一 ACME 上的日志分析用例,我们可以测量我们的 REST API 被调用的频率。 由于团队应该使用团队标识符或令牌来识别,我们可以测量有多少团队正在使用我们的功能,以及使用频率。
这些都是当前采纳的良好指标。 如果我们看到采纳速度缓慢,我们可以提供更多教育或利用更多一对一会议来使更多团队能够采纳。 我们还可以利用各个团队的现有采纳情况,并创建内部成功案例来推广平台的功能给 其他团队。
然而,重要的是开始测量平台上有多少活跃用户,并将其用作基准,以便我们可以设置额外的行动并增加采纳!
服务水平目标 (SLOs) / DORA
平台 是通过自助服务模板推广最佳实践的机会。 这就是服务水平目标 (SLOs) 的用武之地。 我们不仅可以为我们的平台组件定义 SLOs,如可用性,还可以将这作为一个机会,在我们的平台上通过任何新模板为我们的最终用户创建的新软件项目中包含 SLO 定义 - 我们希望他们的软件也具有高可用性、弹性 和安全性。
此外,我们可以通过我们的平台,衡量有多少新的软件项目和发布得以创建和发布。 我们可以查看 Jenkins 作业的执行次数,执行时间,ArgoCD 同步的频率,以及有多少部署最终进入生产环境并满足其 SLOs。 这些都是帮助我们将 DORA 指标反馈给工程团队的关键指标。 他们需要这些指标来展示他们的工作效率。 这也帮助我们作为平台团队,突出展示随着我们的平台的帮助,团队在效率上的提升,假设一些指标,如 部署频率 或 变更的交付时间 将会有所改善。 我们将在 第五章中详细讨论 DORA, 届时我们将深入探讨 CI/CD 自动化!
利用率/FinOps
让大量用户采用我们的平台是一个伟大的目标,我们已经学会了如何衡量它。 将更多的团队带入一个集中式平台,可以让我们集中执行最佳实践,围绕部署的正确大小和正确扩展进行管理,并优化底层基础设施的利用,从而实现平台和所有通过该平台部署的应用的成本优化。 通过它。
在 第一章中,我们提到了一项新的欧洲法规,旨在报告碳排放。 这也可以作为平台能力进行集中处理,报告平台、每个平台服务以及通过平台部署和运行的每个应用的实际资源利用、成本和计算的碳影响。
还有许多这样的使用案例帮助我们优化底层基础设施的利用,以控制我们的成本。 总的来说,这意味着我们的平台是一个 非常适合我们 FinOps 倡议的地方!
我们希望你能将类似的方法应用于为你的平台工程项目创建架构参考架构。 从一个高层次的概述开始,展示平台的目标,概述其功能和用户界面,提供核心平台组件的见解,并指出你如何衡量平台工程计划的成功。
总结
在本章中,我们学到了如何以产品思维接近平台工程:找出我们需要解决的真正问题,提供一个简单快速的解决方案来验证我们的实现,确定我们的平台如何融入现有流程和组织要求,提出具有价值主张的解决方案,且不仅仅关注开发团队,然后设计时注重灵活性,而不是走向 过度工程化的道路!
我们最终得到了一个高级参考架构,您可以使用它向终端用户及任何需要支持该项目的利益相关者展示平台的目的。
在 第四章中,我们将深入探讨平台的架构细节,Kubernetes 的作用,如何将其与现有服务集成,以及如何将平台的能力提供给你的应用程序和服务 开发团队!
进一步阅读
-
[1] Reddit 帖子: https://www.reddit.com/r/devops/comments/stuep4/weve_spent_months_building_this_platform_devs/
-
[2] 沉没 成本: https://developerexperience.io/articles/sunk-cost
-
[3] CDEvents: https://github.com/cdevents/spec
第二部分 – 设计与打造平台
在 第二部分中,我们将讨论平台的技术基础,并引导你在设计过程中走过相关的决策点。 为此,你将学习平台的四个主要部分 – 由 Kubernetes 代表的核心组件和基础设施、平台所需的自动化、面向自服务、开发者友好的平台相关组件,以及构建安全且 合规环境所需的步骤。
本部分包含以下章节:
-
第四章, 平台核心架构 – Kubernetes 作为统一层
-
第五章, 集成、交付与部署 – 自动化无处不在
-
第六章, 为开发者及其自服务打造平台
第四章:平台核心架构 – Kubernetes 作为统一层
作为一个平台工程团队,你需要做出一个关键决定,关于你核心平台的底层技术栈。 这个决定将对你的组织产生长期影响,因为它将决定你需要哪些技能和资源来构建一个支持当前和未来自服务 用例的平台。
Kubernetes — 或简称 K8s — 不是解决所有问题的方案,但在构建平台时,Kubernetes 可以构建 基础。
在本章中,你将深入了解是什么使得 Kubernetes 成为许多平台工程团队的首选。 我们将解释 Kubernetes 所基于的承诺理论概念,以及它的实现方式带来的好处。
你将更好地理解如何导航 云原生计算基金会 (CNCF) 生态系统 ,因为在实施你自己的 平台时,选择合适的项目对你至关重要。
一旦你熟悉了 Kubernetes 及其生态系统的优势,你将学习在定义平台核心层时需要考虑的事项,例如统一基础设施、应用和服务能力。 你将学习如何为与新平台之外的核心企业服务实现互操作性而设计,并如何设计平台的灵活性、可靠性 和健壮性。
因此,我们将在 本章中涵盖以下主要内容:
-
为什么 Kubernetes 扮演着至关重要的角色,以及它为什么(不)适合所有人
-
利用和管理 Kubernetes 基础设施能力
-
为灵活性、可靠性 和健壮性设计
为什么 Kubernetes 扮演着至关重要的角色,以及它为什么(不)适合所有人
目前,我们将专注于 Kubernetes,但也有 其他方式可以提供运行工作负载的平台。 除了 Kubernetes 的许多不同版本(如 OpenShift)外,还有一些替代方案,如 Nomad、CloudFoundry、Mesos 和 OpenNebula。 它们都有存在的理由,但只有一个几乎被无处不在地采纳:Kubernetes!
除了这些平台,你还可以使用公共云提供商的虚拟机或服务来实现无服务器、应用引擎和简单的容器服务。 在许多情况下,平台在需要时也会利用这些服务。 采用纯 Kubernetes 策略可能需要更长的时间,因为组织需要一段时间才能完全投入其中。 不过,你可以观察到两个最近的趋势:
-
从 Kubernetes 管理虚拟机
-
迁移到虚拟集群和由集群管理的虚拟机,以防止由于 虚拟化许可证 带来的成本激增。
Kubernetes 拥有一个重要的生态系统和社区,许多其他组织实现的广泛用例,以及高度积极的贡献者来解决随 Kubernetes 出现的下一个挑战。 与 Kubernetes相关。
Kubernetes – 一个起点,但不是终极目标!
“Kubernetes 是一个构建平台的工具。 这是一个开始,但不是最终目标” 这句话来自于 Kelsey Hightower,他曾在 2014 年 Kubernetes 推出时为 Google 工作。 然而,尽管 Kubernetes 在构建现代 云原生平台中发挥着至关重要的作用,但这并不意味着它适合每一个人。 还记得平台工程的产品导向方法吗? 它从理解用户的痛点开始。 一旦我们了解了痛点,就可以着手实现用例,并决定采用哪些技术方案。 来做出选择。
请回顾 第一章 中名为 *你真的需要一个平台吗?*的部分,我们提供了一份问卷帮助你决定平台的核心内容。 答案可能是 Kubernetes,但也不一定非得是。 让我们从查看 Financial One ACME 的示例用例开始。
Financial One ACME 会选择 Kubernetes 吗?
如果我们考虑 Financial One ACME 的用例,“在生产环境中更容易访问日志以进行问题诊断”,使用提议的解决方案并不一定需要 Kubernetes 作为 底层平台。
如果我们的组织尚未使用 Kubernetes,且我们仅需要一个集成到不同日志解决方案中的新自动化服务,那么我们可能不想将 Kubernetes 提出作为底层核心平台。 这是因为它会为尚未具备所需经验的组织带来新的复杂性。 我们可以使用所有现有的工具和团队来实现并操作该解决方案;也许我们可以将其与其他已经拥有的工具一起运行,遵循相同的部署、升级、监控等操作流程。
另一方面,如果已经存在相关知识,或者 Kubernetes 已经可用,那么使用 Kubernetes 作为核心平台来编排这个新服务将解决很多问题,例如提供 以下内容:
-
新服务容器 作为 Pods
-
针对 这些服务的自动化健康检查
-
通过 ReplicaSets 等概念提供的弹性和可扩展性 以及自动扩展
-
通过 Ingress 控制器和 网关 API 实现外部访问
-
通过 Prometheus 或 OpenTelemetry 对这些服务的基本可观测性
然而,当我们仅仅需要部署一个简单服务时,是否真的需要运行我们自己的 Kubernetes 集群呢? 答案是否定的! 有一些替代方案,例如使用你首选的 云服务商的能力来运行实现:
-
无服务器:该解决方案可以作为一组通过 API 网关暴露的无服务器函数来实现。 状态或配置可以存储在云存储服务中,并可以通过 API 轻松访问。
-
容器:如果该解决方案在容器中实现,该容器可以是轻量级的,并且其端点可以通过 API 网关轻松暴露。 无需一个完整的 Kubernetes 集群,且无需某人进行 维护。
这个仅仅是 Financial One ACME 的一个使用案例 可能不会促使我们选择 Kubernetes 作为核心平台。 然而,在做出这个关于未来平台核心的关键决策时,我们还必须超越第一个使用案例来看待问题。 平台工程将通过为内部工程团队提供许多自服务功能来解决更多的使用案例,从而提高他们的 日常工作效率。
这是一个棘手且影响深远的决策,需要在前瞻性和过度工程之间找到良好的平衡。 为了让这个决策更容易做出,让我们来看看选择 Kubernetes 作为 核心平台的好处。
选择 Kubernetes 作为核心平台的好处
为了让做出选择未来平台核心的关键决策变得更容易,让我们来看一下为什么其他组织选择 Kubernetes 作为核心构建块。 理解这些原因、好处以及挑战,应该能让架构师更容易做出这个 重要决策。
声明性期望状态——承诺理论
传统的 IT 运维 使用 义务模型,这是 当一个外部系统指示目标系统执行某些操作时的情况。 这种模型需要将大量的逻辑嵌入到外部系统中,例如自动化管道。 一个脚本化的管道,无论是基于 Jenkins、GitHub Actions 还是其他解决方案,不仅需要将更改应用于目标系统。 该管道还需要处理外部系统未预测的结果和错误。 例如,如果部署新软件版本在一定时间内未成功,我们该怎么办? 我们应该回滚吗? 管道该如何 处理这种情况?
在《Kubernetes 纪录片第一部分》(https://www.youtube.com/watch?v=BE77h7dmoQU)中,Kelsey Hightower 用一个很好的类比解释了 Kubernetes 遵循的承诺理论模型。 它大致是这样的: 它是这样的:
如果你写了一封信,把它放进信封里,并贴上目的地地址和正确的邮票,那么邮局承诺会在一定时间内将这封信送达目的地。 无论这个投递过程涉及卡车、火车、飞机或其他任何形式的运输,对写信的人来说都无关紧要。 邮政服务会尽一切努力履行投递承诺。 如果一辆卡车发生故障,另一辆卡车将继续前行,直到信件送达最终目的地。
同样的原则适用于 Kubernetes! 在我们的类比中,信件是我们放入信封中的容器镜像。 在 Kubernetes 世界中,信封是某个 自定义资源定义 (CRD)。 为了传递镜像,这可以是一个 Deployment 的定义,其中包括镜像的引用、副本数、该镜像应部署到的命名空间,以及该镜像运行所需的资源要求(CPU 和内存)。 Kubernetes 然后会尽其所能,履行部署该镜像的承诺,通过找到合适的 Kubernetes 节点,确保其满足所有要求,以运行指定副本数的容器镜像,并具备所需的 CPU 和内存。
另一个例子是 Ingress ,它将已部署的服务暴露到外部世界。 通过注解,可以控制某些对象的行为。 对于 Ingress,这可能是为应暴露的域自动创建 TLS 证书,使得匹配的服务可以通过 HTTPS 访问。 以下是一个 Ingress 对象示例,用于 fund-transfer-service 通过特定域将对象暴露到外部世界,使用证书管理器——一个 Kubernetes 核心生态系统工具——来创建有效的 TLS 证书 来自 LetsEncrypt:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: fund-transfer-service
namespace: prod-useast-01
annotations:
cert-manager.io/issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- fundtransfer-prod-useast-01.finone.acme
secretName: finone-acme-tls
rules:
- host: fundtransfer-prod-useast-01.finone.acme
http:
...
完全工作的 Ingress 对象描述比这个清单中展示的内容稍微复杂一些 [1] 示例。 然而,这个示例很好地解释了 Kubernetes 如何将定义转换为预期的实际操作——从而 实现 承诺。
现在,问题是:“这一切魔法是如何运作的?” 为了回答这个问题,我们将从探讨控制器 和操作符的概念开始。
Kubernetes 控制器和操作符
Kubernetes 控制器本质上是实现 Kubernetes 承诺理论的控制循环。 换句话说,控制器自动化了 IT 管理员通常手动执行的任务:持续观察系统的当前状态,将其与我们期望的系统状态进行比较,并执行纠正措施,以确保 系统运行!
因此,Kubernetes 控制器的一个核心任务是 持续对账。 这种持续活动使其能够强制执行期望的状态,例如确保 在先前的 Ingress 定义示例中 匹配的 期望状态 与 当前状态。 如果期望状态或当前状态发生变化,表示它们 不同步。 然后,控制器尝试通过对管理对象进行更改来同步两个状态,直到当前状态再次与期望 状态一致!
以下插图显示了控制器如何监视 期望状态 (通过清单表达并存储在 etcd 中),将其与 当前状态 (在 etcd 中持久化的状态)进行比较,并管理 管理对象 (例如 Ingress、部署、SSL 证书等):
图 4.1:通过 Kubernetes 控制器实现的对账和自愈设计
这个图表已经显示了控制器的核心 概念和能力,强调了自动对账循环如何通过设计自动实现自愈。 然而,控制器还有其他功能:观察集群和节点健康,强制资源限制,按计划运行作业,处理生命周期事件,并管理部署的推进 和回滚。
现在,让我们讨论 Kubernetes 操作员。 操作员是控制器的一个子类,通常专注于特定领域。 一个很好的例子是 OpenTelemetry 操作员,它管理 OpenTelemetry 收集器和工作负载的自动插装。 该操作员使用相同的对账循环来确保始终应用 OpenTelemetry 的期望配置。 如果配置更改或当前的 OpenTelemetry 收集器或插装存在问题,操作员将尽最大努力保持承诺,确保期望状态是实际状态。 要了解更多信息,请访问 OpenTelemetry 网站 在 https://opentelemetry.io/docs/kubernetes/operator/。
操作器的其他使用案例通常涉及管理和自动化核心服务和应用程序,如数据库、存储、服务网格、备份与恢复、CI/CD 以及消息传递系统。
如果你想了解更多关于控制器和操作器的信息,可以查看 CNCF 操作器工作组及其白皮书,网址为 github.com/cncf/tag-app-delivery/tree/main/operator-wg。另一个精彩的概述可以在 Kong Blog 上找到,标题为 What’s the Difference: Kubernetes Controllers vs Operators。这篇博客还列出了控制器和操作器的优秀示例:konghq.com/blog/learning-center/kubernetes-controllers-vs-operators
现在我们对控制器和操作器有了更多了解,接下来让我们看看它们是如何确保所有 Kubernetes 组件和部署具备内建弹性的!
由探针驱动的内建弹性
控制器持续验证我们的系统是否处于期望的状态,通过观察 Kubernetes 集群、节点和所有已部署的 Pod 的健康状况。如果其中某个组件不健康,系统会通过某些自动化操作将其恢复到健康状态。以 Pod 为例。如果 Pod 不再健康,它们最终会被重启,以确保整个系统的弹性。重启组件通常是 IT 管理员在“我们试试关掉再开看看会发生什么”方法下执行的默认操作。
就像 IT 管理员通常不会随意开关设备,Kubernetes 采取了更为复杂的方法来确保我们的 Kubernetes 集群、节点和工作负载的弹性。
Kubelet——Kubernetes 的核心组件之一——通过使用多种类型的探针(启动探针、就绪探针和存活探针)持续监控 Pod 的生命周期和健康状态。以下图示展示了根据启动、就绪和存活探针检查结果,Pod 可以处于的不同健康状态:
图 4.2:Kubelet 使用探针判断 Pod 健康状态
一旦 Pods 不再健康,Kubernetes 会尝试重新启动 Pods,并将 Pods 恢复到健康状态。 对于探针结果的评估和重启策略,有很多不同的设置,你必须熟悉这些设置,才能充分利用 Kubernetes 的内建弹性。 所有这些设置都在你的 Deployment 和 Pod 定义中声明。
如果你想了解 更多关于 Kubelet 如何管理不同的探针并查看一些最佳实践,我们建议查看一些博文,例如 Roman Belshevits 关于存活性 探针的文章: https://dev.to/otomato_io/liveness-probes-feel-the-pulse-of-the-app-133e
另一个很好的资源是官方 Kubernetes 文档,介绍如何配置存活性、就绪性和启动 探针: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
健康探针仅在 Kubernetes 内部有效
重要的是要理解,所有这些健康检查仅在 Kubernetes 集群内部进行,并不能告诉我们通过 Ingress 对外暴露的服务,从最终用户的角度是否也是健康的。 最佳实践是额外从“外到内”的角度进行健康检查和可用性检查,作为外部控制。 例如,你可以使用合成测试来验证所有暴露的端点是否可达并返回 成功响应。
现在我们已经了解了 Pod 的内建弹性,接下来讨论一些更复杂的构造,例如通常由多个不同的 Pods 和其他对象组成的应用程序,如 Ingress 和存储。
工作负载和应用生命周期编排
正如我们所学,Kubernetes 提供了 内建的 Pods 生命周期编排,如 前一节所述。 然而,我们在 Kubernetes 上部署的业务应用通常有多个依赖的 Pods 和工作负载,这些共同构成了应用。 以我们的 Financial One ACME 为例:支持客户的金融服务应用包含多个组件,如前端、后端、缓存、数据库和 Ingress。 不幸的是,Kubernetes 没有应用的概念。 尽管有多个倡议和工作组在定义应用,但我们目前必须依赖其他方法来管理应用,而这些应用是由 多个组件组成的。
在 批处理变更以应对依赖性 一节中, 第五章,我们将学习诸如 Crossplane 之类的工具。 Crossplane 允许你定义所谓的复合应用,这使得应用所有者能够轻松定义应用的单个组件,然后部署单独的实例,如 以下示例所示:
apiVersion: composites.financialone.acme/v1alpha1
kind: FinancialBackend
metadata:
name: tenantABC-eu-west
spec:
service-versions:
fund-transfer: 2.34.3
account-info: 1.17.0
redis-cache:
version: 7.4.2
name: transfer-cache
size: medium
database:
size: large
name: accounts-db
region: "eu-west"
ingress:
url: „https://tenantABC-eu-west.financialone.acme"
Crossplane 提供 应用程序 和基础设施编排,使用操作符模式持续确保每个应用程序实例——如在复合应用中定义——按预期运行 。
另一个我们将在 第五章 中深入了解的工具是 Keptn CNCF 项目。 Keptn 提供自动化的应用感知生命周期编排和可观察性。 它让你可以声明性地定义部署前后检查(验证依赖关系、运行测试、评估健康状况、强制基于 SLO 的质量门控等),而无需编写自己的 Kubernetes 操作符来实现这些操作。 Keptn 还提供自动化的部署可观察性,以更好地理解发生了多少次部署,成功了多少次,以及它们在哪些地方和为何失败,通过发出 OpenTelemetry 跟踪和指标,方便故障排除 和报告。
Kubernetes 提供了构建韧性系统的许多基础构件。 虽然你可以编写自己的操作员来扩展到你自己的问题领域,但你也可以使用现有的 CNCF 工具,例如 Crossplane 或 Keptn,因为它们提供了一种更简单的声明性方式,应用承诺理论的概念,来处理 更复杂的 应用程序和 基础设施组成。
重启组件是确保系统韧性的一种方式,但还有更多的方法。 让我们来看看自动扩展,它解决了动态环境中另一个关键的 问题!
自动扩展集群和工作负载
在大多数行业中,系统预期的负载在一年中的每一天分布不均。 总会有某种季节性波动:零售在黑色星期五和网络星期一有激增,税务服务在报税日有激增,金融服务通常在发放工资时会有激增。 我们的 Financial One ACME 客户也面临同样的情况。 作为一个金融服务组织,始终会有来自终端用户的基本流量,但在月初和月末 会有流量激增。
Kubernetes 提供了几种扩展应用 工作负载的方式:手动(例如,设置 ReplicaSets)或通过工具自动扩展,如 Horizontal Pod Autoscaler (HPA)、 Vertical Pod Autoscaler (VPA),或者 Kubernetes Event Driven Autoscaler (KEDA)。 这些 扩展选项允许你在工作负载的 CPU 或内存不足时、应用程序流量激增时,或者响应时间开始 增加时进行扩展!
除了工作负载,你还可以并且很可能需要通过工具来扩展你的集群和节点的规模, 例如 Cluster Autoscaler (CA) 或 Karpenter [2],或者通过你所使用的托管 Kubernetes 云服务提供的选项。
作为一个平台工程团队,你需要熟悉所有不同的选项,同时也要注意所有的 考虑因素:
-
设置限制:不要允许应用程序无限制地扩展。 您可以选择为每个应用程序、工作负载、命名空间等强制执行最大限制。
-
成本控制:自动扩展是很棒的,但也有其成本。 确保将成本报告给 应用程序所有者。
-
缩小规模:扩展很容易! 确保同时定义何时缩小规模的指标。 这样 可以保持成本 在可控范围内。
要了解更多信息,请查看以下 文档: https://kubernetes.io/docs/concepts/workloads/autoscaling/
现在我们已经了解了在 Kubernetes 环境中扩展的选项,那么如何扩展到其他Kubernetes 集群呢? 我们来看看这个问题。
一次声明——到处运行(理论上)
Kubernetes 作为开放标准的承诺是,任何声明的状态(Ingress、工作负载、机密、存储、网络等)无论是在单一集群中运行,还是在多个集群中运行以满足特定需求(如阶段分离:开发、预发布和生产,或区域分离:美国、欧洲, 亚洲等)都会表现相同。
无论是操作您自己的 Kubernetes 集群,使用 OpenShift,还是使用云供应商提供的托管 Kubernetes 服务,这一承诺在理论上都是成立的。 那么,在理论上是什么意思呢? 不同的服务之间确实有一些具体的技术差异,您需要加以考虑。 根据不同的服务,网络或存储可能会有所不同,因为底层实现依赖于云供应商。 某些服务还会提供核心 Kubernetes 服务、服务网格和运维工具的特定版本,这些都会随着托管安装一起提供。 一些服务要求您使用供应商特定的注释来配置某些服务的行为。 这就是为什么在不同供应商之间应用相同的声明式状态定义理论上是可行的——但实际上,您需要考虑一些小的差异,并进行一些 在理论上的调整,这些差异需要特定的供应商配置!
由于技术细节和差异不断变化,因此在本书中提供当前的对比并不合适。 您必须理解的是,尽管理论上您可以将任何 Kubernetes 对象部署到任何版本的 Kubernetes 上,但结果和行为可能会有所不同,具体取决于您部署的环境。 这就是为什么我们建议对所选的 Kubernetes 目标平台进行一些技术研究,并了解它与其他平台的差异,特别是当您想要进行多云/多 Kubernetes 部署时,因为相同的 Kubernetes 对象可能会有 细微的差异!
好消息是 全球社区正在通过提供更好的指导和工具来解决这个问题,使得 声明一次——随处运行 的承诺 成为现实。
我们已经看到了选择 Kubernetes 作为核心平台的许多好处。 然而,还有另一个重要的原因,解释了为什么 Kubernetes 在过去 10 年里自首次发布以来获得了如此广泛的采用:那就是全球社区和 CNCF!
全球社区和 CNCF
Kubernetes 于 2014 年 6 月由 Google 宣布,版本 1.0 于 2015 年 7 月 21 日发布。 随后,Google 与 Linux 基金会合作,并成立了 CNCF,将 Kubernetes 作为其初始项目! 自那时以来,社区和项目迅速席卷了全球!
十年后(在撰写本书时),CNCF 拥有 188 个项目,244,000 名贡献者,1660 万次贡献,成员遍布全球 193 个国家。 许多介绍 Kubernetes 和 CNCF 的演示文稿通常从展示 CNCF 的生态图开始: https://landscape.cncf.io/
虽然生态图令人印象深刻,但它也成为了许多关于如何在这个全球社区的所有项目中导航的艰难和复杂性的梗的来源。 然而,不要害怕。 全球 CNCF 社区是 Linux 基金会的一部分,其使命是为快速发展的云原生项目提供支持、监督和指导,包括 Kubernetes、Envoy、 和 Prometheus。
以下是您需要注意的一些事项,它们将帮助您在不断增长的 CNCF 项目列表中导航:
-
项目状态:CNCF 会积极跟踪每个项目的状态和活动。 贡献者和采纳者的数量,以及项目的开发活跃度,是你是否应该进一步关注某个项目的良好指标。 如果一个项目处于停滞状态,只有一个维护者,或者几乎没有采纳者,那么对于你选择长期支持的平台工具而言,可能并没有什么用处。 你的平台。
-
成熟度级别:CNCF 还指定了成熟度级别 ,包括沙箱、孵化、或已毕业,分别对应于《创新者的窄道》中的创新者、早期采纳者和早期多数这几个层级 的 跨越鸿沟 图表(https://en.wikipedia.org/wiki/Crossing_the_Chasm)。 已毕业的项目已经在多个行业广泛采纳,是其支持的用例的安全选择。 孵化中的项目已经从技术试验场跨越到获得良好采纳,并且维护者的数量也在不断增长,维护者的背景也日益多样化。 想了解更多关于 CNCF 成熟度的标准,并查看各项目处于哪个级别,可以访问官方站点 : https://www.cncf.io/project-metrics/。
-
ADOPTERS.md文件,几乎每个 CNCF 项目在其 GitHub 仓库中都有。 如果你决定采纳这些项目中的一个,我们鼓励你通过提交拉取请求将你的名字添加到采纳者名单中。 这不仅有助于项目,也有助于其他组织决定该项目是否 值得追求!
Kubernetes 至关重要,因为它有一个强大的社区
尽管 Kubernetes 拥有强大的技术基础,但正是过去 10 多年中建立起来的社区和生态系统使 Kubernetes 成为平台工程师将其作为 核心平台的可行选择。
我们现在已经更清楚地理解了 Kelsey Hightower 所说的:“Kubernetes 是一个用来构建平台的平台。 这是一个开始,但不是最终目标。”选择 Kubernetes 作为核心平台有很多好处,特别是因为它是基于 承诺理论的概念构建的。Kubernetes 提供了组件的自动化弹性、扩展性和生命周期管理。 不断壮大的社区通过数百个开源 CNCF 项目为许多常见问题提供了解决方案,任何组织 都可以使用。
虽然我们通常关注 Kubernetes 在部署和编排应用程序方面的好处,但让我们看看如何利用 Kubernetes 将我们的基础设施能力提升到未来平台!
利用和管理 Kubernetes 基础设施能力
回顾一下 第二章,你已经了解了平台参考组件模型和能力平面。 当我们谈论将基础设施能力提升到 Kubernetes 时,最终用户在使用该平台时会意识到这些能力。 我们必须区分需要与 Kubernetes 集成的资源和那些通过规范配置并部署到 Kubernetes 的资源,以及在集群外部操作或创建的新资源。 在下图中,您可以找到需要坚实集成的资源整合和网络部分的示例;否则,它们会主动阻碍平台的有用性和 功能。
图 4.3:带有示例工具的能力平面
集成基础设施资源
我们将讨论平台底层技术的基本组件和你必须做出的设计决策。 首先,由于 Kubernetes 的强大,你在工具选择上更加灵活,并可以根据需要进行扩展。 当你调整平台能力以适应不同 的使用案例时,这尤其有帮助。
容器存储接口
该 容器存储接口 (CSI) 提供 对附加到集群或运行集群的节点的存储技术的访问。 在 CSI 开发者文档中 [3],你可以找到几乎所有存储提供商的驱动程序。 该列表包含 云提供商的驱动程序,例如 AWS 弹性块存储 (EBS),软件定义存储如 Ceph,或者商用解决方案如 NetApp 的连接器。 此外,CSI 驱动程序还支持特定工具的驱动程序,如 cert-manager 和 HashiCorp Vault。 简而言之,CSI 对于任何需要存活时间超过其所属容器且未存储在数据库中的数据至关重要,或者对于 数据库存储是必需的。
驱动程序的安装依赖于基础设施和存储技术。 例如,对于云提供商,你通常需要 以下内容:
-
服务帐户或 权限策略
-
启动污点 和容忍配置
-
预安装的 外部快照工具
-
驱动程序 安装本身
由于其复杂性,这些组件通常通过 Helm 或其他软件包管理工具进行部署。 有时,它们需要更多的节点权限,这在平台设计时可能带来安全隐患。 你还需要考虑如何访问存储:
-
ReadWriteOnce (RWO):一个 Pod 声明了一部分可用存储,它可以进行读写操作,而其他 Pods 不能访问该存储,除非原 Pod 释放 该存储。
-
ReadWriteMany (RWM):多个 Pods 可以声明一部分可用存储。 它们可以进行读写操作,并与其他 Pods 共享该存储。
-
ReadOnlyMany (ROM):多个 Pods 可以声明一部分存储,但只能从中读取数据。 从中读取。
-
ReadWriteOncePod (RWOP):仅能被一个 Pod 声明;没有其他 Pod 可以占用它,并允许读写操作。
CSI 驱动程序的概述提供了更多关于哪些访问模式被支持的信息。 由于没有一刀切的解决方案,你需要将你的选项透明地展示给用户,并解释如何 使用它们。
用户需要了解和理解的核心元素是 StorageClass, PersistentVolume,以及 PersistentVolumeClaim。当一个 Pod/Deployment 需要一个卷时, StorageClass 将触发新卷的创建。 如果一个 Pod/Deployment 已经声明了一个卷,而且它没有被销毁,Kubernetes 控制平面将会重新分配该卷给 Pod/Deployment。
图 4.4:动态配置新的持久卷
你作为平台团队定义 StorageClass ,理想情况下,与存储专家合作。 以下示例突出显示了 StorageClass的常见定义。配置中有很多容易出错的地方;例如,未设置 reclaimPolicy 将默认删除后创建并附加的卷。 然而, StorageClass 支持你为用户请求的 PersistantVolumeClaim 动态创建卷,因此是自助服务的强大推动力:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ultra-fast
annotations:
storageclass.kubernetes.io/is-default-class: "false"
provisioner: csi-driver.example-vendor.example
reclaimPolicy: Retain # default value is Delete
allowVolumeExpansion: true
mountOptions:
- discard
volumeBindingMode: WaitForFirstConsumer
parameters:
guaranteedReadWriteLatency: "true" # provider-specific
这带来的缺点是你需要考虑人为错误,错误可能会导致存储被填满,从而使平台崩溃,直到 系统冻结。
CSI 挑战
CSI 的定义是 一种相对较新的方法,但存储管理和软件定义存储的底层技术比 Kubernetes 要早得多。 我们还可以在许多 CSI 驱动程序中发现这一点,它们不过是对传统代码的封装。 对于那些不太灵活且可扩展性较差的集群来说,这可能不是问题,但在你有大量活动的环境中,你可不想让 CSI 成为系统中的瓶颈。 一些 CSI 甚至有限制和约束,以防止它们在规模扩展时失败。 公平地说,我们通常会看到这种情况出现在本地安装和一些老旧的存储技术中。 对于这些,我们还可以考虑 逻辑单元号 (LUN) 的呈现和连接限制。 LUN 是 Pod 从存储空间请求并获取数据的方式。 物理服务器与存储之间的连接数量是有限制的。 同样,当您管理自己的存储 和 SAN 时,这一点尤为重要。
为什么有些 CSI 这么差劲? CSI 不仅仅是提供存储容量。 它与存储提供者进行通信,承诺提供所需的容量,并等待 RAID 控制器、备份和快照机制准备就绪。 在大规模存储系统中,我们还会看到更多:我们可以找到存储容量分配和 优化过程。
为了克服这些问题,您需要评估存储,特别是其云原生存储能力的存储驱动程序。 这将需要进行大规模的性能测试,并创建大量的卷。 CSI 驱动程序不应做任何削减或性能下降,创建的卷应处于 毫秒级别。
此外,确保驱动程序支持跨存储和跨云/基础设施迁移;提供不同基础设施之间的同步和异步复制;提供各站点之间的功能对等;并在需要时支持本地存储类型,例如 边缘场景。
一个好的 CSI 将使您的平台能够 在任何地方运行,并支持广泛的 使用场景。
容器网络接口
容器网络接口 (CNI) 可以成为平台最相关的组件,但它也是最被低估的组件。 在我们看到的许多项目中,一些平台团队并不关心他们使用什么作为 CNI,也不太利用网络策略、加密或细粒度的网络配置。 由于它对网络层的简单抽象,刚开始使用时并不会让人感到压倒性。 然而,另一方面,有许多用例中,最关键的组件就是 CNI。 我甚至见过因为 CNI 的动态特性与传统的网络实现方法不兼容而导致项目失败。
CNI 总是需要专门的实现,因为它是一套规范和库,用于编写插件来配置网络接口。 CNI 只关注 Linux 容器的网络连接,并在容器被删除时清除分配的资源。 由于这一点,CNI 有广泛的支持,并且其规范实现简单。 易于实现。
因此,我们作为架构师绝不应将 CNI 视为“Kubernetes 中的另一个对象。” 我们必须评估并引入它。 一些 CNI 旨在简化维护,提供一个坚固但简单的功能集。 例如,如果主要关注的是第 3 层,考虑使用 Flannel。 其他 CNI,如 Calico,是一个坚实的选择,功能丰富;Cilium 则引入了 eBPF 的使用,提供更快速、更安全的网络连接。 如果你因为可能有其他需求,如提供不同级别的网络,而仍然难以选择,可以选择社区为你提供的解决方案:Multus。 慢慢思考并探索你的选项。 有成百上千 种 CNI。
CNI 对 你的平台可能有重要影响:
-
安全性:CNI 可以提供不同的网络策略功能,以实现对网络的细粒度控制。 它们可以具备额外的加密功能,集成身份和访问管理系统,以及 详细的可观测性。
-
可扩展性:集群规模越大,网络中的通信就越频繁。 CNI 必须支持你的增长目标,即使在复杂的路由和数据传输下仍然保持高效。
-
性能:Pod 之间的通信有多快和直接? CNI 引入了多少复杂性? 它能多高效地处理通信? 它能处理很多复杂的 网络策略吗?
-
可操作性:高级 CNI 不是很侵入式,且易于维护。 强大的 CNI 理论上可以被替换,只要它们遵循 CNI 规范,但每个 CNI 都有自己的一套功能,这些功能往往是 无法替代的。
请注意,并非所有的 CNI 都支持这些功能。 例如,有些甚至不提供网络策略支持。 其他 CNI 是云提供商特定的,只与一个云提供商集成, 并且它们确实启用一些以云提供商为中心的功能。
架构挑战 – CNI 链式调用与多个 CNI
平台非常适合 CNI 链式调用。 CNI 链式调用 引入了多个 CNI 的顺序使用。 CNIs 的使用顺序及其目的在 /etc/cni/net.d 目录中定义,并由 kubelet 处理。 这允许平台团队处理网络的一部分,并提供一种受控的方法,而平台用户则可以在更高的层次上自由配置他们的网络。 例如,平台用户可以访问 Antrea 作为 CNI,以某种程度上配置他们的网络。 他们还可以应用网络策略和出口配置,以防止他们的应用与所有人进行通信。 在平台的另一侧,平台工程团队将通过 Cilium 管理全局跨集群通信以及网络加密,以执行安全最佳实践。 此外,Cilium 提供的可见网络数据将提供给运营和安全团队。 这些用例最适合与云提供商自己的 CNI 进行交互。 它们通常能够更好地将平台与云集成,但在另一面缺乏许多高级功能。 其他方面的功能则较少。
另一个待评估的方法是通过 Multus 或 CNI-Genie 为 Pod 分配多个网络接口。 通常,Pod 只有一个接口,但例如使用 Multus 时,这可以是多个网络接口。 什么时候这变得相关? 以下实例是它变得相关的示例: 变得相关:
-
将控制数据和操作数据与 应用数据分离
-
为极为 异构的工作负载提供灵活的网络选项
-
通过为每个租户分配完全不同的网络,将多租户架构提升到一个新水平
-
支持不寻常的网络协议和连接,例如在边缘场景或 电信环境中
-
网络功能虚拟化 (NFV),由于 其复杂性 ,需要多个网络
Multus CNI 是一种位于节点上的元插件,处于实际 CNI 和 Pod 网络接口之间,如下图所示。 它一方面将不同的网络接口连接到 Pod,另一方面处理与预期 CNI 的连接,以确保正确的网络接口。 的连接。
图 4.5:Multus 元 CNI 插件
这两种方法都必须进行充分评估。 它们对网络的复杂性、性能 和安全性有重大影响。
提供不同的 CPU 架构
Kubernetes 支持 多种 CPU 架构:AMD64、ARM64、386、ARM、ppc64le,甚至包括使用 s390x 的大型机。 目前许多集群运行在 AMD64 架构上,但在本文写作时,ARM64 正受到强烈关注,导致这一趋势的变化。 本讨论主要关于节省成本并获得一些额外性能,同时减少总体电力消耗。 至少在理论上,这是一个三赢的局面。 不仅 ARM64 是基础设施可能发生的变化,开源架构项目 RISC-V 也在加速发展,并且是第一个创建 RISC-V 服务 *[4]*的云服务提供商。
作为平台工程师,我们可以启用这些迁移和变化。 Kubernetes 集群可以同时运行多种架构——不是在同一个节点上,而是在不同的节点组中。 请记住,这一变化也需要容器构建方面的调整。 对于某些软件组件,你可以进行多架构构建;而对于其他组件,可能需要在为不同架构创建容器之前进行调整。 容器才可以创建。
要选择一个部署应该交付到的架构,你只需要在 nodeSelector 中像这样添加 Spec 部分到部署 YAML 文件:
nodeSelector:
kubernetes.io/arch: arm64
提供不同容器镜像的一个即将到来的替代方案是将软件编译为 WebAssembly (Wasm) 容器。
Wasm 运行时
作为一种替代容器格式,Wasm 的使用在过去一年中大幅增加。 Wasm 是一种面向栈式虚拟机的二进制指令格式。 可以把它看作是各种编程语言和多种不同执行环境之间的中间层。 你可以将用超过 30 种不同语言编写的代码编译成一个 *.wasm 文件,然后在任何 Wasm 运行时上执行该文件。
然而,名称 WebAssembly是具有误导性的。 最初设计是为了让代码在网页上快速运行,但今天它可以在任何地方运行。 我们为什么要使用它? Wasm 默认是安全且沙盒化的。 在一个 Wasm 容器中,除了经过编译的二进制代码外,没有操作系统或其他任何东西。 这意味着没有可以破坏或窃取上下文或服务帐户的东西。 Wasm 还具有极快的启动时间,其限制由运行时设置,而不是模块。 一些运行时声称启动速度可达到大约 50 毫秒。 相比之下,你的大脑需要超过 110 毫秒才能识别某物是否在你眼前经过。 此外,Wasm 容器的大小大约是 0.5 MB – 1.5 MB,而一个非常精简的容器可能约为 5 MB。 然而,我们在市场上看到的通常是 300 MB – 600 MB,1 GB – 3 GB,甚至有时超过 10 GB 的镜像大小。 通过减小镜像大小,Wasm 容器的存储占用也大大减少。 Wasm 还具有硬件独立性。 相同的镜像可以在任何地方运行,只要你有一个可用的 Wasm 运行时。
在 Kubernetes 环境中,OCI 和 CRI 运行时支持 Wasm。 这意味着你可以同时运行一个 Wasm 容器和一个常规容器。 如以下图所示,不需要做进一步的修改。 Wasm 应用镜像存储在节点级别,并由上层执行。
图 4.6:Wasm 在 Kubernetes 节点上
为了使 Wasm 可执行并在你的平台上可用,你需要指定一个运行时类并在部署/Pod 级别定义其使用。 在以下示例中,你可以看到左侧指定了 crun 作为 RuntimeClass,右侧则是一个 Pod 定义,其中 spec.runtimeClassName的值为 crun 。 对于 crun,我们还需要添加一个注释来告知 crun 该 Pod 具有一个 Wasm 镜像:
| apiVersion: node.k8s.io/v1``kind: RuntimeClass``metadata:``name: crun``scheduling:``nodeSelector:``runtime: crun``handler: crun | apiVersion: v1``kind: Pod``metadata:``**name: wasm-demo-app** ****annotations:**
****module.wasm.image/variant: compat**
**spec:
**runtimeClassName: crun**
****容器:**
****name: wasm-demo-app**
****image:**
**docker.io/cr7258/wasm-demo-app:v1************** |
表 4.1:定义一个将在 Wasm 运行时执行的 RuntimeClass 和 Pod
作为替代方案,像 SpinKube 这样的新开发 提供了一整套工具来以最佳方式利用 Kubernetes 资源 [5]。这种方法使得开发体验能够与 Wasm 容器化应用的部署和执行紧密集成。 下图展示了工作流以及不同组件如何协同工作。 它使开发过程变得简单直观,并为 平台带来了一个快速但稳定的新运行时环境。
图 4.7:SpinKube 概览 [6]
然而,Wasm 真的是业界已经采纳的技术吗? 以下是一些展示 其采用情况的示例和用例:
-
`互操作性:Figma 作为 Wasm 在 任何计算机上运行
-
插件系统:您可以为 Envoy 编写 Wasm 扩展
-
沙箱:Firefox 或 Chrome 浏览器可以在沙箱环境中运行 Wasm,以保护 您的系统
-
区块链:CosmWasm 或 ICP 使用 Wasm 的版本来 运行应用程序
-
容器:WasmCloud 执行容器的概念不同,或者是 SpinKube,一个具有 CLI 的 Wasm 运行时,提供简单的 开发流程
-
无服务器平台:Cloudflare Workers 或 Fermyon Cloud 运行您的 Wasm 应用
Wasm 目前还不能替代容器。 它是一个进化的步骤,非常适合一些特定的应用场景,但它尚未得到广泛采用,并且在调试过程中存在问题。 然而,这些障碍的解决只是时间问题。 它们会得到解决。
为 GPU 利用启用平台
类似于对不同 CPU 架构的支持,或者将容器运行时扩展到包括 Wasm,GPU 的支持 最近对用户变得极为相关。 必须安装特定于 GPU 类型的设备插件,如 AMD、Intel 或 Nvidia。 这将向 Kubernetes 及其用户暴露自定义可调度资源,如 nvidia.com/gpu 。 此外,我们不是 GPU 及其功能的专家;从平台工程的角度来看,不同的供应商为其插件开发了不同的功能集和扩展。
如果您的用户需要 GPU,我强烈建议开发或者寻找该领域的专家。 AI 和 LLM 的领域正在迅速扩展。 硬件和软件提供商每月都会推出新工具、新系统和新方法,以便充分利用这些技术。 任何场景都有其非常具体的需求。 训练一个模型需要大量的数据、GPU、存储和内存。 微调一个模型主要取决于您想训练的模型有多大。 一个七十亿参数的模型可以适应 14 GB 的 VRAM,但提高精度可能会轻松将其大小增加到 24 GB 或更多。 最后,为用户提供推理引擎以服务 LLM 需要大量的 网络通信。
重要提示
推理意味着向 LLM 发送一个提示。 大多数人认为 LLM 接着会像人类一样创建故事。 然而,实际上发生的是,在每个单词之后,LLM 必须将整个提示(包括新词)再次发送给 LLM,以便它能决定添加到句子中的下一个词。
作为经验法则,对于所需的 GPU VRAM(视频内存是 GPU 的内存),你需要将模型的大小翻倍。 以下是一些 更多的例子:
-
Llama-2-70b 需要 2 * 70 GB = 140 GB VRAM
-
Falcon-40b 需要 2 * 40 GB = 80 GB VRAM
-
MPT-30b 需要 2 * 30 GB = 60 GB VRAM
-
bigcode/starcoder 需要 2 * 15.5 = 31 GB VRAM
因此,需要平台与机器学习团队之间的合作。 根据他们想使用的模型,你选择的硬件可能不再符合 要求。
架构挑战
虽然 GPU 的集成非常简单,但它们有一些需要讨论的要素;你应该了解以下内容:
-
GPU 成本:便宜的 GPU,具有较低的 VRAM 和计算能力,可能不适合你的使用案例。 另外,你可能不会 24/7 使用 GPU,但你应该考虑更具动态性和灵活性的可能性。 然而,如果你的使用案例需要 GPU 计算能力,拥有 GPU 从长远来看可能比常规的 CPU 更便宜。
-
特权权限:许多机器学习工具需要进一步的定制和调整,特别是它们所要求的权限。
-
最终用户需求:除了模型大小外,数据科学家和机器学习工程师希望如何使用模型,很大程度上取决于他们想要实施的实际使用案例。 方法的任何小变化都可能使平台无法使用。 这必须在此类平台的架构中加以考虑,以提供最多的资源和最大的扩展 灵活性。
-
外部模型拉取到集群:与容器类似,从像 HuggingFace 这样的页面拉取模型是一种常见做法。 你可能会考虑在支持机器学习活动的平台网络中进行此操作。
为机器学习和大语言模型(LLM)操作创建适合的平台需要一种全新的优化层次。 未运行的 GPU 是浪费金钱。 使用不当的 GPU 是浪费金钱。 然而,从基础设施的角度来看,我们还必须确保更多:数据保护、平台安全性以及模型的专门可观察性。 在我看来,机器学习和大语言模型是一个令人兴奋的应用场景,提供了一个平台工程师的游乐场。
解决方案空间
为了优化 GPU 的使用,有一些 可用的方法:
-
多进程 服务器 (MPS)
-
多实例 GPU (MIG)
-
时间分片/共享
根据 GPU 驱动程序,您将会发现多种可能性,就像使用 Nvidia 一样。 其他 GPU 驱动程序可能还不够成熟或功能丰富,但 当然,您应该经常评估 这个问题。
时间分片是最差的选择。 虽然它比什么都没有好,但 MPS 至少会比时间分片方法高效两倍。 然而,MPS 有一个主要缺点:进程之间没有严格的隔离,这会导致切片之间出现相关故障。 这就是 MIG 的优势所在。 它提供了良好的进程隔离和 GPU 的静态分区。 在一个超级动态、可扩展且随时可调整的 Kubernetes 集群中,静态分区如何实现? 是的,因为机器学习训练不会仅仅运行几秒钟或 几分钟 [7]。
下图展示了 GPU 的内存分区,您可以将不同的工作负载分配到这些分区中。
图 4.8:将 GPU 拆分成三个 GPU 实例的示例
这些 GPU 实例可以由单个 Pod 使用,也可以由一个包含多个进程的 Pod(不理想)使用,或者通过使用 Nvidia 的 CUDA 等技术来使用。 CUDA 是一个 MPS,因此您可以结合不同的方法,如下图所示:
图 4.9:使用三个 GPU 实例并行的示例
从这里,我们可以看一下研究和实验部分,你可以结合 Kubernetes v1.26 ,并且它仍处于 Alpha 阶段,因此每个版本可能会有 API 的重大变动。 有一些有趣的文章和演讲讨论了它。 根据你阅读的时间,它可能已经过时了。 date [8].
启用集群可扩展性
如前所述,在本 章节中,Kubernetes 集群的伸缩能力对于不同需求是有益的,包括从弹性、随工作负载增长到回退重新初始化,再到在数据中心和可用区提供最高可用性。 从本质上讲,我们区分水平和垂直自动扩展器,后者针对 Pods,水平 CA 则调整节点数量。
与许多功能一样,Kubernetes 提供了规范,但期望其他人来实现它。 这至少适用于 VPA 和 CA,它们至少需要在 集群级别运行一个指标服务器。
然而,HPA 功能丰富,支持基于指标的伸缩。 请看以下 HPA 的例子。 使用 stabilizationWindowsSeconds,我们还可以告诉 Kubernetes 等待先前的操作,以防止抖动。 抖动的定义如下,根据 Kubernetes 文档: Kubernetes 文档:
在使用 HorizontalPodAutoscaler 管理一组副本的规模时,由于所评估的指标具有动态特性,副本数量可能会频繁波动。 这有时被称为抖动,或者说是振荡。 它类似于控制论中的滞后效应概念。
我们可以参考以下 HPA 的配置。 看起来很简单;你可以看到,根据策略,行为可以发生巨大变化。 例如,当在拥有数百个副本的大型部署中减少 10% 的 Pods 时,我们需要非常小心。 所示的缩小配置将防止同时删除超过两个 Pods:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
maxReplicas: 7 #maximum replicas to scale up to
minReplicas: 3 #expected minimum replicas
scaleTargetRef: ... targetCPUUtilizationPercentage: 75 #metric to react on
behavior:
scaleDown:
stabilizationWindowSeconds: 300 #wait 300 sec
policies:
- type: Percent
value: 10 #reducing 10% of Pods
periodSeconds: 60 #per minute
- type: Pods
value: 5 #reducing not more
periodSeconds: 60 #than 2 Pods per min
selectPolicy: Min
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 75 #increase the Pod by 75%
periodSeconds: 15 #every 15 seconds
selectPolicy: Max
VPA、HPA 和 CA 的问题
你需要考虑自动扩展器家族的一些约束:
-
HPA:
-
你 必须正确设置 Pods 的 CPU 和内存限制及请求,以防止资源浪费或频繁 终止的 Pods。
-
当 HPA 达到可用节点的限制时,它无法调度更多的 Pods。 然而,它可能会利用所有可用资源,这可能会导致 问题。
-
-
VPA:
-
VPA 和 HPA 不应基于相同的指标进行缩放。 例如,尽管两者都可以使用 CPU 利用率触发扩容,HPA 部署更多的 Pods,而 VPA 增加现有 Pods 上的 CPU 限制,这可能导致基于相同指标的过度扩展。 因此,如果同时使用 VPA 和 HPA,应将 CPU 用于其中一个,而将内存用于 另一个。
-
VPA 可能建议使用比集群或节点中可用资源更多的资源。 这会导致 Pod 变得不可调度。
-
-
CA:
-
CA 缩放基于 Pods 的请求和限制。 这可能导致许多未使用的资源、利用率低下以及 高成本。
-
当 CA 触发云提供商的缩放命令时,可能需要几分钟时间为集群提供新的节点。 在此期间,应用程序性能会下降。 最坏的情况是,它 变得无法服务。
-
解决方案空间
作为平台工程师,我们希望确保用户能够定义缩放行为,同时不会让平台面临风险。 利用 HPA、VPA 和 CA 需要完美的配置与控制,由策略引擎提供的保护措施以及密切的监控。 控制集群的扩展和缩减变得至关重要,同时要为 用户启用命名空间内的自动缩放。
在云提供商上管理 Kubernetes 集群的缩放需要你查看 CA 及其可用的各种云集成。 此外,如果你使用 Cluster API (CAPI),你 还可以利用其能力进行 集群 自动缩放。
网络能力和扩展
现在,让我们来看一下 Kubernetes 与底层基础设施的最终资源集成。 为此,我们将从集群的网络机制入手,逐步探讨 DNS 和负载均衡。 DNS 和负载均衡可以在集群内发生,并与 Kubernetes 运行的基础设施协同工作。
Ingress – 旧方式
Ingress 是旧版定义,描述了如何将外部集群的最终用户请求路由到系统中并传递给暴露的应用程序。 近十年来,它一直是定义传入网络流量的方式。 Ingress 通常由如 NGINX、HAProxy 或 Envoy 等 Ingress 控制器表示,举几个例子。 这些控制器本质上会采用 Kubernetes 定义的标准资源中的路由规则,并管理其余部分。 如下面的图所示,从那里开始,流量会被重定向到正确的服务,服务再将其转发到 Pod。 从物理层面上讲,流量将从网络接口流向 Ingress 控制器,再到 Pod,但正如 Kubernetes 是一位优秀的调度器一样,仍然有一些逻辑步骤 介于其中。
图 4.10:Ingress 控制器(来源:Kubernetes 文档)
虽然它具有可扩展性,适用于一些 最大规模的部署,但它也有 一些缺点:
-
Ingress API 仅支持 TLS 终止和简单的基于内容的 HTTP 流量请求路由
-
它的语法有限,保持 非常简单
-
它需要注解 以支持扩展性
-
它降低了可移植性,因为每个实现都有自己的方式来 执行此操作
构建多租户集群更加具有挑战性,因为 Ingress 通常是在集群级别,并且权限模型较弱。 此外,Ingress 支持命名空间配置,但不适合多团队和共享的 负载均衡基础设施。
Ingress 方法的优美之处在于它广泛的支持与其他工具的集成,例如用于证书管理的 cert-manager 和即将看到的外部 DNS 处理。 此外,Kubernetes 的维护者声称没有计划废弃 Ingress,因为它以一种简单的方式完美地支持简单的 web 流量。 方式。
Gateway API – 新方式
在 2023 年秋季,网关 API 正式发布。 网关 API 由多个资源类型组成,而不是单一资源,它遵循的模式在其他 关键集成中已被使用:
-
网关: 进入集群的入口点 流入的流量 -
GatewayClass: 定义将处理 网关的控制类型 -
*Route: 实现从网关到 服务的流量路由:-
HTTPRoute -
GRPCRoute -
TLSRoute -
TCPRoute -
UDPRoute
-
将下图与 Ingress 方法进行比较时,我们可以看到流入的流量通过网关并被重定向的两个步骤 通过 *Route。
图 4.11: 网关 API
它们如何比较? 如何比较?
| Ingress | 网关 API | |
|---|---|---|
| 协议 | 仅限 HTTP/HTTPS | L4 和 L7 协议 |
| 多租户 | 困难/自定义扩展 | 按设计支持多租户 设计 |
| 规范 | 基于注释,控制器特定 | 控制器独立,拥有 资源,标准化 |
| 定义/资源 | Ingress 资源 | 网关,GatewayClass,*Route 资源 |
| 路由 | 基于主机/路径 | 支持头部 |
| 流量管理 | 仅限于 供应商 | 内建/定义 |
表 4.2: 比较 Ingress 和网关 API
这一丰富的功能集对需要构建平台的人来说是一个游戏规则改变者。 此前,这些大多数功能必须通过商业购买,或通过一些变通办法和自开发工具强行集成到集群中。 然而,借助网关 API,支持广泛的协议,并且还附带了两个 有趣的额外 功能。
您可以使用网关 API 创建跨命名空间路由,可以使用 ReferenceGrant 或者 AllowedRoutes。允许的路由通过引用绑定实现,需要网关所有者定义来自哪些命名空间的流量。 在实践中,网关配置将会扩展 如下:
namespaces:
from: Selector
selector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- alpha
- omega
这将允许来自 alpha 和 omega 命名空间的流量。
或者,我们可以使用 ReferenceGrant,如下所述:
ReferenceGrant 可用于启用网关 API 内的跨命名空间引用。 具体来说,路由可以将流量转发到其他命名空间中的后端,或者网关可以引用另一个命名空间中的密钥。
它们听起来相似,但实际上不是。 让我们 来比较一下:
-
ReferenceGrant:在命名空间 A 中的网关和路由授予命名空间 B 中的服务 转发流量 -
AllowedRoutes:在命名空间 C 中配置了网关对命名空间 B 的路由。
除了这些跨命名空间的额外安全层外,网关 API 还具备自己的扩展能力。 通过它们,您可以定义自己的策略附加,如后端 TLS 策略,以验证正确的 TLS 使用方式 。
在我们继续之前的最后一件事。 网关 API 自带角色。 角色是预定义的角色,允许细粒度使用网关功能。 入口只有一个角色,即 用户,无论是管理员还是开发者。 以下表格显示了这些角色在 四层模型中的写权限:
图 4.12:高级四层模型的写权限
在这一点上, 网关 API 是解决无数夜晚正确处理入站流量并构建具有清晰和 透明方法的多租户平台的真正救星。。
ExternalDNS
该 ExternalDNS 项目由 Kubernetes 贡献者开发,是一个常在云提供的 Kubernetes 集群中使用的工具,但仍然没有作为一个重要实现被广泛强调。 然而,它弥合了集群中某些随机 IP 和一个公开或私有可访问的 DNS 之间的鸿沟,并将流量路由到平台内的应用程序。 ExternalDNS 支持几乎所有云环境以及类似云的环境,还支持如 CloudFlare 这样的流量和内容聚焦型服务。
然而,ExternalDNS 不是一个 DNS。 惊讶吧! 它从 Kubernetes API 读取资源,并配置外部 DNS 指向集群的公共端点。 你也可以说,ExternalDNS 让你能够通过 Kubernetes 资源以 DNS 提供商无关的方式动态控制 DNS 记录。
让我们来看看 ExternalDNS 如何与 Kubernetes 的 CoreDNS 和 Cloud DNS 服务一起工作。 在下图中,你可以看到左侧是托管的 Kubernetes。 在这种情况下,AWS EKS 和 CoreDNS 正在 Kubernetes 上运行,以解析内部 DNS 请求。 当部署了 ExternalDNS 后,它会观察网关、入口和服务资源。 当发生变化或有新服务 上线时,ExternalDNS 会更新云提供商或 DNS 服务提供商上的 DNS 记录。
图 4.13:ExternalDNS
然而,在寻找替代方案时,你通常只有两种备选方式:自己创建 DNS 条目(手动)或通过自定义控制器、函数,或者在基础设施 创建过程中实现自动化。
因此,看到 ExternalDNS 的限制令人非常痛苦:
-
缺少细粒度的控制;例如,ExternalDNS 会为来自 任何命名空间的所有服务和入口创建 DNS 记录
-
ExternalDNS 只提供 A 记录;如果你需要 TXT 或 CNAME 记录,你必须 手动完成
-
你将获得 DNS 名称的默认 DNS 配置;否则,你必须手动 定义它们
除此之外,你还可能会遇到更高的费用(由于其不合理的 DNS 记录创建行为)以及增加的复杂性或延迟。 我不能完全同意这些问题,因为这取决于你如何 处理它们。
仅当你已经掌握 Kubernetes 网络的其他部分,并能够进行精细化的网络策略和网关 API 管理,从而严格控制哪些服务可达及如何访问时,才考虑使用 ExternalDNS。 此外,考虑启用 DNSSEC 功能,并建立 DNS 监控。 监控。
负载均衡、EndpointSlices 和拓扑感知路由
最后,为了 总结 网络部分,我们将简要 讨论 负载均衡、 EndpointSlices,以及 拓扑感知路由。
负载均衡由 集群中的入口控制器或网关 API 处理。 这可以通过与云服务提供商结合,外包给外部负载均衡器。 所有主要的云服务提供商都有自己的方法,通常通过他们自己的控制器来管理托管服务的负载均衡器。 这些选项之间有什么区别? 在 Kubernetes 内部运行自己的负载均衡器意味着,首先,所有流量都会被路由到那个入口点。 通过正确的设置,这可以是多个节点,并且负载分配非常简单。 缺点是,如果某个节点由于某种原因超载,它仍然会处理并内部分配流量。 云负载均衡器会将负载分配到多个节点,并且根据集成方式,它会知道某个节点是否能够处理更多的负载,或者是否应将流量重定向到另一个节点。 一个 公共云负载均衡器的缺点是,你必须为此付费。 付费。
EndpointSlices 在大规模集群中变得至关重要。 Endpoint 是定义 IP 地址和端口列表的 API 对象。 这些地址属于动态分配给服务的 Pod。 当创建服务时,Kubernetes 会自动创建一个关联的 Endpoint 对象。 Endpoint 对象维护与服务选择器标准匹配的 Pod 的 IP 地址和端口号。 EndpointSlices 在 Kubernetes 1.16 中被引入。 它们提供了一种将网络端点分布到多个资源上的方式,减少了 Kubernetes API 服务器的负载,并提高了大规模集群的性能。 过去,单一的大型 Endpoint 对象会导致服务变慢,而现在创建了多个小型 EndpointSlice 对象,每个对象代表 一部分端点。
控制平面创建并管理 EndpointSlices,每个 slice 的端点数不得超过 100 个。 此限制可以调整,最大值为 1,000。 对于 kube-proxy 来说,EndpointSlice 是路由 内部流量的事实来源。
EndpointSlices 对于 拓扑感知路由也是必需的。 通过拓扑感知路由,你可以将流量保持在云提供商的 可用区 (AZ)内。 这有两个主要优点:它减少了 网络成本并提高了性能。 而不是让 AZ 1 中的 Pod 与 AZ 2 中的 Pod 通信并传输大量数据,AZ 1 中的 Pod 现在将与 AZ 1 中的一个副本(如果有)进行通信。 为了实现最佳效果,传入流量应通过外部负载均衡器均匀分配,并且每个区域应至少有三个端点。 否则,控制器将无法分配该端点,失败的概率约为 50%。
Kubernetes 作为平台控制平面的一部分
回顾第二章,我们可以在参考架构中看到,平台可以是高度分布式的,基于许多服务,从更高的角度来看,这些服务可能甚至不属于同一组。 我们讨论过,Kubernetes 很可能成为你平台的核心部分。 然而,它能变得有多核心呢? 如前所述,Kubernetes 不仅仅是用来运行工作负载的;它是一个平台(基于承诺理论和标准化模型及 API),用于构建平台。 这使得 Kubernetes 将一只脚迈入平台控制平面,并通过两种方式实现这一点:作为资源控制器和作为 平台或协调器。
从 Kubernetes 内部管理资源
开源的 Crossplane 项目是唯一一个不依赖于任何提供商的解决方案,可以在 Kubernetes 内部管理云资源。 最初为了在 Kubernetes 内部管理其他 Kubernetes 集群而创建,它迅速成为处理云资源的通用解决方案。 云资源作为 CRD 提供,可以通过规范文件将其定义为 Kubernetes 本地资源。 这使得用户可以选择定义他们所需的内容,并将资源创建交给 Kubernetes 的承诺理论来处理。 对于不同的云,有所谓的提供商可用,用于定义可用的资源。 用户可以创建单个资源或完整的组合,这些组合由多个资源组成,它们 属于同一组。
外部资源与内部定义资源的问题
管理资源的正确方法是什么? 是应该由基础设施团队定义,还是通过需求表单的输入来定义? 是否可以通过平台由用户来定义? 一切皆有可能,但没有简单的 答案。
让我们来看看这两种方法。 首先,让我们看看来自传统保守背景下的 Financial One ACME 的一个场景:基础设施团队在过去几年里一直在争取自动化和声明性方法。 虽然他们通过 Ansible 管理本地环境,但他们决定为云提供商使用更简单的工具:Terraform(或 OpenTofu)。 我们不会详细介绍整个技术栈,但直到我们进入 Kubernetes 平台之前,一切都通过经典的 CI/CD 推送原则和 IaC 通过 Terraform 来协调。
Financial One ACME 正在启动一个新项目,开发内部使用的定制软件。 团队将利用 ACME 平台并着手系统的基础架构工作。 他们已经确定需要某些文件存储、缓存、关系型数据库、通知服务和消息流服务。 由于平台提供了一些自助服务,团队可以将 Terraform 模块复制到他们的仓库中。 从这里开始,一个预定义的 CI/CD 管道将接管配置,并将资源部署到定义的环境中。 这些自定义的但仍然由外部管理的资源在某些方面是与系统的其余部分隔离的。 它们可能生活在同一个仓库或层级中,并由团队管理,但它们并没有 紧密集成。
另一方面,它们提供了一定程度的稳定性。 在平台用户空间内部,这些资源是不可见的,唯一存在的是一个发现服务。 当一个组织逐渐成熟时,管道可能会被定制,而无需通知所有者或用户。 然而,基础设施和应用程序是明确分离的,这是一个优势,因为它们的生命周期完全不同。 这些元素。
快进到现在,Financial One ACME 已经完成了云原生转型,最大限度地利用了平台工程和 IDP。 同样,他们计划开展一个新的内部项目,这个项目与之前的项目完全不同,但却有着完全相同的需求。 一些组织的行为永远不会改变。 这一次,项目团队在他们的开发者门户中创建了一个新项目。 所有基本需求会自动推送到一个新的 Git 仓库中。 所选的资源被选中并推送到平台,平台上的控制器决定在哪里部署这些资源。 一些资源最终成为云服务商的托管服务,另一些则由专门的团队放在共享服务账户中,还有一些则在项目的命名空间内。 过了一段时间,团队意识到他们选择了错误的配置,经过调整后,迁移到新服务的过程开始了。 这个场景与之前的场景一样真实,但具有 不同的影响。
团队需要更详细地了解他们的需求;另一方面,他们必须信任预定义的部署和配置。 平台工程团队与运营团队合作,定义了具有防护栏的最佳实践,确保可操作性,同时也几乎满足了用户的所有需求。 在集群用户空间内,团队可以找到所有部署的资源,并将它们视为平台内的服务,即使它们并未在其中运行。 然而,用户端的突然变化可能导致资源在其他地方突然增加或删除。 管理服务团队必须在没有警告的情况下处理这些变化。 总体而言,所有依赖资源都表现出极其不稳定和动态的特性,难以预测,也难以管理。 另一方面,项目可以完全专注于流程和进展,因为外部资源是通过集群内部处理的,而不是通过外部集群资源管理解决方案(如 IaC)。
两种方法都可以。 两者各有利弊,而对你的组织来说,最适合的方法往往更多地取决于人的因素,而不是技术因素。 然而,显而易见的是,内部定义的集群资源比外部定义的更加动态,并且更多地转移到了用户的责任范围内。 定义的资源。
最终,这变成了一场哲学讨论。 外部定义的资源更为传统,而内部定义的方法则是进步和面向未来的。 然而,我们没有太多选项来运行集群内的供应流程。 除了 Crossplane,我们还看到了许多元实现控制器,它们从集群中读取自定义资源并触发 CI/CD 流水线,例如。 如果有人问。
在本节中,我们研究了 Kubernetes 所需的基本能力,围绕它们的挑战,以及如何解决它们。 而且,它们不像你在会议上看到的那些疯狂的实现方式。 正确掌握这些基础知识将决定其他一切是否会带来愉快或痛苦。 接下来,我们将通过探讨找到合适的节点大小及其对灵活性 和 可靠性的影响来结束本章。
设计灵活性、可靠性和稳健性
在上一部分中,我们讨论了集群的可扩展性,以及 VPA、HPA 和 CA 如何协同工作。 这有助于创建一个灵活、可靠且强大的系统。 其中一个关键部分是允许定制,前提是不会对系统造成损害。 集群的各个组件必须无缝协作,但也必须在需要时能够互换。 这非常敏感:一方面,你有一个随着时间推移而不断扩展和收缩需求的集群;另一方面,你还需要集群周围的所有扩展功能,以便为你的使用案例提供最佳的功能集。 你还拥有一个不断发展的开源社区,该社区经常发布更新和新功能,这些更新和新功能应该集成并为你的用户提供。 正如我们之前所说的,这就是为什么你必须拥有产品思维——为你的用户构建最佳的平台。 扔掉不需要或过时的东西,但要保持整个系统作为 你的核心。
现在,出于某种原因,我们仍然看到关于是否应该将所有工作负载放在 Kubernetes 上,以及它是否可靠的讨论。 我们必须从两个角度来看这个讨论:从 Kubernetes 的基础设施和核心职责的底层视角来看,以及从用户可以看到并体验到的顶层视角来看。
优化资源消耗与留出足够的头部空间
正如我们在 第二章中学到的那样,Kubernetes 集群及其管理的工作负载之间有着一种有趣的关系,相互影响。 有些应用程序需要更多的 CPU 能力,其他应用程序则会扩展,而其余的则根据需求运行。 找到合适的匹配并不容易,但理想的目标是高资源消耗,因为它优化了可用资源的使用,从而降低 成本。
如何使集群达到合适的大小
评估集群的合适大小 始终是一个挑战。 找到合适的解决方案显然是一个 看情况而定的问题。让我们以 Financial One ACME 为例,它必须提供一个新的集群。 我们对预期的工作负载了解不多,只知道它需要一些内存,并且有几个不那么需要资源的活动组件。 因此,我们可以选择以下 选项之一:
-
1x 16 vCPU,64 GB 内存
-
2x 8 vCPU,32 GB 内存
-
4x 4 vCPU,16 GB 内存
-
8x 2vCPU,8 GB 内存
出于可用性原因,第一个选项会是个坏主意。 如果你在集群中进行更新,整个系统崩溃或你需要提供一个新的节点,你需要将所有应用程序迁移并关闭旧节点。 选项 4 包含许多节点。 由于其小巧的尺寸,这可能会导致资源短缺,因为一些基础组件将消耗部分 CPU 和内存。 此外,根据云提供商的不同,可能会有其他限制,比如可用的 IP 地址、带宽和存储容量。 另外,如果你有一个需要 1 vCPU 的应用程序,并且可能扩展到 1.5 – 2.0 vCPU,它可能会导致一个 完整节点崩溃。
然而,Kubernetes 每个节点使用多少资源呢? 默认情况下,对于 CPU,我们可以使用以下规则:
-
前 6% 核心
-
第二核心的 1% 核心
-
接下来 0.5% 两个核心
-
从第 5 个核心起的 0.25%
我们也有一些关于 内存的粗略规则:
-
前 25% 4 GB
-
以下内容的 20% 4 GB
-
接下来 10% 8 GB
-
接下来的 112 GB(最多 128 GB)的 6%
-
任何超过 128 GB 的 2%
-
如果节点内存小于 1GB,那么是 255 MiB
此外,每个 节点有一个 100 MB 的驱逐阈值。 如果资源完全利用且超出阈值,Kubernetes 将开始清理一些 Pods,以防止内存完全耗尽。 在 learnk8s,你可以找到一篇非常详细的博客 关于它(https://learnk8s.io/kubernetes-node-size)。
让我们可视化 这些数字:
| 2 vCPU 8 GB RAM | 4 vCPU 16 GB RAM | 8 vCPU 32 GB RAM | |
|---|---|---|---|
| Kubelet + 操作系统 vCPU | 70 m 或 0.07 vCPU | 80 m 或 0.08 vCPU | 90 m 或 0.09 vCPU |
| Kubelet + 操作系统内存 | 1.8 GB | 2.6 GB | 3.56 GB |
| 驱逐阈值 | 100 MB | 100 MB | 100 MB |
| 可用 vCPU | 1930 m 或 1.9 vCPU | 3920 m 或 3.9 vCPU | 7910n 或 7.9 vCPU |
| 可用内存 | 6.1 GB | 13.3 GB | 28.34 GB |
表 4.3:不同节点大小的资源消耗和可用资源
从这些可用的 资源中,你还需要减去任何用于集群的资源,例如 DaemonSet 用于日志记录和监控, kube-proxy,存储驱动,等等。
进行计算,如果有许多小节点,所使用的基础资源层比大节点的要大。 让我们来看一个例子。 两个 2vCPU 8 GB RAM 节点总共需要 140 m 的 CPU 和 3.6 GB 的 RAM,而一个 4vCPU 16 GB RAM 节点只需要 80 m 的 CPU 和 2.6 GB 的 RAM。 这些是为了提高可用性所付出的成本,但在仅对比可用资源时,单个节点需要分配给 Kubernetes 的资源较少。 然而,理想情况下,节点应该达到其最大使用率;我们并不是运行一个虚拟机,标准情况下有 80% 的未使用资源! 至少 80% 的节点利用率应该是实现最佳性能/价格比的目标。 这也是因为服务器的能源比例性。 CPU 所需的能源并不会与 工作负载呈线性比例增长。
假设一台服务器最多可以消耗 200 瓦特。 那么,大多数服务器在 CPU 利用率达到 50% 时需要消耗 150 到 180 瓦特之间的电量。 这意味着,服务器的利用率越高,能源/CPU 的利用率越好,这也是更加具有成本效益 和可持续的。
在选择集群节点大小时,我们必须考虑其他因素: 集群:
-
如果你提供的是少数几个大节点,但用户定义了反亲和性,使得每个节点上只能运行一个副本的 Pod,并且由于预期副本数过高导致节点不足,那么一些 Pod 将变得无法调度。
-
大节点往往资源利用率低,因此你会花更多的钱在一些你 并不使用的东西上。
-
如果你有太多小节点,并且不断遇到待处理的 Pods,每个集群都必须进行扩展,这可能会让用户不满,因为扩展新节点总是需要时间。 此外,如果应用程序持续运行在 资源限制下,也可能会影响其服务性。
-
许多节点会导致更高的网络通信量、容器镜像拉取和每个节点上重复的镜像存储。 否则,在最坏的情况下,你总是需要再次从注册表拉取镜像。 对于小型集群来说,这不是问题,但对于大量节点来说,这会变得 非常频繁。
-
节点越多,它们之间以及控制平面之间的通信就越频繁。 在某些请求量级下,这意味着需要增加 控制平面的节点大小。
找到合适的节点和集群大小本身就是一门科学。 极端的两端都不好。 首先,考虑一下你期望的工作负载类型。 如果不确定,可以从中等大小的节点开始,并根据需要调整节点大小。 此外,始终考虑预留一些额外的内存。 Kubernetes 每个节点的核心组件不需要大量的 CPU,但需要至少 2 到 3 GB 的内存,以及所有其他 默认组件。
解决方案空间
大多数公共云提供商都支持运行多种实例类型的 Kubernetes 节点。 这对于不同的使用场景非常有帮助,从隔离工作负载到优化利用率,或者从一种 CPU 架构迁移到另一种架构。 我们还讨论了 GPU 利用率,在这种场景下,你可以结合使用 CPU 节点运行非 GPU 工作负载,同时在 GPU 实例上进行模型训练。
为此,你必须正确管理和标记节点,并为用户提供透明的方法和支持,帮助定义他们的 亲和性设置。
为了确定合适的节点大小,learnk8s 还为你提供了一个实例计算器(https://learnk8s.io/kubernetes-instance-calculator),你可以在开始制作自己的 Excel 表格进行计算之前先考虑使用它。
此外,在定义集群规模时,尽管规模看似不那么相关,但通过选择合适的节点大小,你可以直接影响成本、利用率、应用可用性、用户体验,以及为弥补 潜在缺点所需做的额外实现。
总结
在这一章中,我们更深入地了解了 Kubernetes 的一些相关组件,它们构成了你平台的基石。 我们首先考察了 Kubernetes 是否是正确的选择,并且探讨了它为何通常是一个明智的选择。 Kubernetes 以承诺理论为核心,具有许多强大的功能来运行和扩展平台,因此它几乎是平台的完美基础。 从这里,我们探讨了 Kubernetes 的一些基本元素:存储、网络、CPU 架构和 GPU 支持。 在此背景下,我们了解了一些设计考量和在实现 Kubernetes 时可能遇到的问题。 尽管 Kubernetes 作为基础在不同环境下可能有所不同,但完全可以创建一个统一的体验。 然而,这将带来一些主要的缺点,比如失去某些云服务提供商的功能、灵活性, 以及可定制性。
接下来,我们讨论了如何在一个非常严格与高度灵活的系统之间找到平衡。 两者都可以被视为强大且可靠,但它们带来的是非常不同的挑战和问题。 因此,我们进行了一个简短的思维实验,以确定正确的集群大小和节点类型,然后我们通过讨论如何在用户空间实施保护措施来结束这一部分内容。 这帮助我们在用户空间内提供灵活性,但通过防止用户的不当行为和错误配置的服务,保护了平台。 我们在 这一章中学到了这些内容。
在下一章中,我们将重点关注平台的自动化。 除了基础设施,自动化是平台的关键组件,正如你稍后将看到的,它在长期中可能成为瓶颈和成本驱动因素。 你将学习如何设计一个适当的发布流程,如何在 CI/CD 和 GitOps 中实施该流程,并且如何使用这种组合来管理平台工件的生命周期。 我们还将向你展示如何有效地观察 这个过程。
进一步阅读
-
[1] Kubernetes 中的对象: https://kubernetes.io/docs/concepts/overview/working-with-objects/
-
[2] Karpenter: https://karpenter.sh/
-
[3] CSI 驱动程序 索引: https://kubernetes-csi.github.io/docs/drivers.html
-
[4] RISC-V Kubernetes 节点在 Scaleway 上: https://www.scaleway.com/en/docs/bare-metal/elastic-metal/how-to/kubernetes-on-riscv/
-
[5] SpinKube: https://www.spinkube.dev/
-
[6] SpinKube 概述: https://www.spinkube.dev/docs/overview/
-
[7] Nvidia – 改善 GPU 在 Kubernetes 中的利用率: https://developer.nvidia.com/blog/improving-gpu-utilization-in-kubernetes/
-
[8] DRA 与 GPU:
架构师的平台工程:Kubernetes 核心解析
4633

被折叠的 条评论
为什么被折叠?



