谷歌-Anthos-实战-全-
谷歌 Anthos 实战(全)
原文:Google Anthos in Action
译者:飞龙
前置内容
前言
写《Google Anthos 实战》的想法是在与数百位对在任何地方管理应用程序、更快交付软件和保护应用程序及软件供应链感兴趣的客户讨论后产生的。客户们希望更好地了解 Anthos 如何帮助他们管理在传统本地设置、边缘、云原生和多云环境中的应用程序部署。他们感兴趣的是实现容器、无服务器、基础设施即代码和服务网格的好处,以提高生产力和速度。他们希望了解如何通过自动化和透明的策略管理来保证并提高应用程序生命周期每个阶段的保障和安全。
《Google Anthos 实战》汇集了那些热衷于 Kubernetes、无服务器和 Anthos 的谷歌工程师们的集体专业知识,以及谷歌云认证高级专家,这是一群在设计和实施企业解决方案方面具有专业知识的精英级云架构师和技术领导者。
致谢
没有无数同行者的工作,《Google Anthos 实战》是无法实现的(en.wikipedia.org/wiki/Fellow_traveller)。
主要作者们想要感谢其他作者们的贡献;按字母顺序排列,我们感谢 Ameer Abbas、Amita Kapoor、Aparna Sinha、Eric Brewer、Giovanni Galloro、Jarosław Gajewski、Jason Quek、Kaslin Fields、Konrad Cłapa、Kyle Bassett、Melika Golkaram、Onofrio Petragallo、Patricia Florissi、Phand Phil Taylor。其中一些作者被选入了在 2021 年 Google Cloud Next 上发布的书籍预览版。在这本完整版出版物中,所有作者都包括在这本书的 17 章以及电子书和在线的额外 6 章中。
作者们感谢所有审稿人提供的深思熟虑的意见、讨论和审阅。按字母顺序,我们感谢 Ady Degany、Alex Mattson、Alon Pildus、Amina Mansur、Amr Abdelrazik、Anil Dhawan、Ankur Jain、Anna Beremberg、Antoine Larmanjat、Ashwin Perti、Barbara Stanley、Ben Good、Bhagvan Kommadi、Brian Grant、Brian Kaufman、Chen Goldberg、Christoph Bussler、Clifford Thurber、Conor Redmond、Eric Johnson、Fabrizio Pezzella、Gabriele Di Piazza、Ganesh Swaminathan、Gil Fidel、Glen Yu、Guy Ndjeng、Harish Yakumar、Haroon Chaudhry、Hugo Figueiredo、Issy Ben-Shaul、Jamie Duncan、Jason Polites、Jeff Reed、Jeffrey Chu、Jennifer Lin、Jerome Simms、John Abel、Jonathan Donaldson、Jose San Leandro、Kamesh Ganesan、Karthikeyarajan Rajendran、Kavitha Radhakrishnan、Kevin Shatzkamer、Krzysztof Kamyczek、Laura Cellerini、Leonid Vasetsky、Louis Ryan、Luke Kupka、Maluin Patel、Manu Batra、Marco Ferrari、Marcus Johansonn、Massimo Mascaro、Maulin Patel、Micah Baker、Michael Abd-El-Malek、Michael Bright、Michelle Au、Miguel de Luna、Mike Columbus、Mike Ensor、Nima Badiey、Nina Kozinska、Norman Johnson、Purvi Desai、Quan To、Raghu Nandan、Raja Jadeja、Rambabu Posa、Rich Rose、Roman Zhuzha、Ron Avnur、Scott Penberthy、Simone Sguazza、Sri Thuraisamy、Stanley Anozie、Stephen Muss、Steren Giannini、Sudeep Batra、Tariq Islam、Tim Hockin、Tony Savor、Vanna Stano、Vinay Anand、Yoav Reich、Zach Casper 和 Zach Seils。
没有作者、审稿人、编辑和营销团队的巨大合作,这本书是不可能完成的。我们特别感谢来自谷歌的 Arun Ananthampalayam、J. P. Schaengold、Maria Bledsoe、Richard Seroter、Eyal Manor 和 Yash Kamath;以及来自 Manning 的 Doug Rudder、Aleksandar Dragosavljević和 Gloria Lukos。感谢你们的持续支持和灵感。
特别感谢 Will Grannis,谷歌云首席技术官办公室创始人兼总经理,作为一位服务型领导者,始终激励他人。此外,特别感谢埃里克·布赖尔,加州大学伯克利分校计算机科学名誉教授和谷歌基础设施副总裁。没有他的支持和鼓励,这本书是无法写成的。
所有作者的版税将捐赠给慈善机构。
作者
-
阿米尔·阿巴斯,谷歌高级产品经理,专注于现代应用程序和平台
-
阿米塔·卡普尔,德里大学前副教授,现在是 NePeur 的创始人,热衷于利用 AI 做好事
-
安东尼奥·古利,谷歌工程总监,一生致力于搜索和云服务,是三个天使的父亲
-
阿帕尔纳·辛哈,产品管理和 DevRel 高级总监,建立了 Kubernetes 并领导了 PM 团队,使利润和损失增长了 100 倍
-
埃里克·布赖尔,加州大学伯克利分校计算机科学名誉教授和谷歌基础设施副总裁
-
乔瓦尼·加拉罗, 谷歌客户工程师,专注于 Kubernetes、云原生工具和开发者生产力
-
雅罗斯瓦夫·盖耶夫斯基, 全球首席架构师和 Atos 杰出专家,谷歌云认证研究员,热衷于云、Kubernetes 和整个 CNCF 框架
-
杰森·奎克, Devoteam 全球 CTO,G Cloud,最初是一名程序员,现在在谷歌云上构建,热衷于 Kubernetes 和 Anthos
-
卡斯林·菲尔德斯, 谷歌云 GKE 和开源 Kubernetes 开发者倡导者,CNCF 大使
-
康拉德·克拉帕, 谷歌云认证研究员#5,负责 Atos 托管 GCP 产品设计的首席云架构师
-
凯尔·贝塞特, 云原生社区成员和开源倡导者,与谷歌产品和工程团队合作,领导了 Anthos 的原始设计合作伙伴关系
-
梅丽卡·戈尔卡姆(谷歌员工), 谷歌云解决方案架构师,专注于 Kubernetes、Anthos 和谷歌分布式边缘云
-
迈克尔·马迪森, World Wide Technology 的云架构师,背景在软件开发和 IaC
-
奥诺弗里奥·佩特拉加洛(谷歌员工), 谷歌云客户工程师,专注于数据分析和人工智能
-
帕特里夏·弗洛里斯(谷歌员工), 技术总监,谷歌云 CTO 办公室,过去 10 年专注于联邦计算,这是联邦分析和联邦学习的一个超集
-
菲尔·泰勒, CDW Digital Velocity 的 CTO,13 岁开始编程,是一位不懈的企业家,有使用公共云和 Kubernetes 将产品推向市场的记录
-
斯科特·苏罗维奇, HSBC 银行全球容器工程负责人,谷歌研究员,Kubernetes 倡导者,以及《Kubernetes:企业指南》的合著者
关于这本书
Anthos (cloud.google.com/anthos) 是一个多云容器化产品,在本地、多个公共云平台、私有云和边缘工作。它也是一个托管应用程序平台,将谷歌云服务和工程实践扩展到许多环境,以便您可以更快地现代化应用程序并确保它们之间的操作一致性。
谁应该阅读这本书?
读者应该对分布式应用程序架构有一个一般性的了解,并对云技术有一个基础的了解。他们还应该对 Kubernetes 有一个基本的了解,包括常用资源、如何创建清单以及如何使用 kubectl CLI。
本书是为任何对深化其 Anthos 和 Kubernetes 知识感兴趣的人设计的。阅读本书后,读者对 GCP 和多云平台上的 Anthos 将有更深入的了解。
本书是如何组织的:路线图
-
第一章—介绍 Anthos 和现代应用如何帮助企业推动多个行业的转型,以及云原生微服务架构如何提供可扩展性和模块化,为企业在当今世界提供基础和竞争优势。
-
第二章—大多数组织可以轻松管理少量集群,但随着环境的扩展,通常会遇到支持问题,使得管理变得困难。在本章中,您将了解 Anthos 如何为运行在不同云提供商和本地集群上的 Kubernetes 集群提供单一视图。
-
第三章—Kubernetes 正成为“数据中心 API”,是 Anthos 背后的主要组件,为我们提供所需的计算环境,以支持便携式、云原生应用,以及在适当的使用案例中,单体应用。本章介绍了 Kubernetes 的组件、声明式和命令式部署模型之间的差异以及高级调度概念,以保持工作负载在基础设施的部分部分出现故障时仍然可用。
-
第四章—Anthos 提供完全支持版本的 Istio,这是一个开源的服务网格,为在 Anthos 集群中运行和在外部服务器(如虚拟机)上运行的工作负载提供多个功能。了解 ASM 的组件以及每个组件如何在网格中提供功能,以及如何使用相互 TLS 来保护流量,提供高级发布周期,如 A/B 测试或金丝雀测试,并使用 GCP 控制台提供网格流量的可见性。
-
第五章—深入了解使用 GCP 控制台管理集群和工作负载。了解不同的日志记录和监控考虑因素,如何使用 CLI 管理集群和工作负载,以及如何在混合环境中进行扩展和设计运营管理。
-
第六章—利用前几章的知识,了解 Anthos 组件,这些组件为开发者提供创建应用程序的工具,包括 IntelliJ、Visual Studio Code 和 Google 的 Cloud Shell 的 Cloud Code 插件,以及使用版本控制和 Cloud Build 来部署应用程序。
-
第七章—Anthos 允许组织在 Kubernetes 上实现标准化,提供统一的模式来开发、部署、扩展和确保便携性和高可用性。可以使用工作负载身份来保护工作负载,这为混合和多云环境中的多个集群提供了增强的安全性。了解如何使用负载均衡器将流量路由到集群,并使用 Google 的 Traffic Director 在多个集群之间路由流量,以及如何使用 VPC 服务控制来保护您的集群。
-
第八章—从电信示例中了解更多关于边缘 Anthos 的信息,以及他们如何实现 5G 来增强质量检查、自动驾驶汽车和库存跟踪。
-
第九章—无服务器消除了 Kubernetes 对开发人员的复杂性。在本章中,您将了解基于 Knative 的 Cloud Run,以及其组件如何用于解决不同的用例,包括事件、版本管理和流量管理。
-
第十章—Anthos 网络具有多层和多种选项。在本章中,您将了解云网络和混合连接,包括专用互连、Cloud VPC 以及使用标准公共互联网连接。深入了解 Anthos 网络选项,了解您如何连接运行 Anthos 或任何兼容 Kubernetes 版本的集群,无论是来自其他云服务提供商还是本地。
-
第十一章—随着组织的发展,管理和扩展多个集群的复杂性也随之增加。Anthos Config Management (ACM)通过门卫策略提供安全性,使用 Git 等标准工具进行配置管理,并使用分层命名空间控制器提供额外的命名空间控制。
-
第十二章—持续集成和持续交付是成为敏捷组织的主要组成部分之一。为了实现您的 CI/CD 目标,您将学习如何使用 Skaffold、Cloud Code、Cloud Source Repositories、Artifact Registry 等工具,使您的组织真正实现敏捷。
-
第十三章—在 Anthos Config Management 的基础上构建,以保护您的集群免受恶意或意外事件的影响。要了解如何保护一个系统,您需要了解它可能被破坏的方式,在本章中,您将学习一个人如何部署提升的 Pod 来接管主机或整个集群。然后,使用 ACM,学习如何通过攻击或错误(如镜像中的漏洞库)来保护各种组件。
-
第十四章—您可以在 Anthos 上运行数百万个镜像和产品,并且您的组织可能维护其自己的产品版本。Google 使您更容易使用由 Google 或其他行业领导者(如 NetApp、IBM、Red Hat 和 Microsoft)精选的工作负载集合。在本章中,您将了解 Google Marketplace 以及如何使用它轻松地为您的用户提供解决方案。
-
第十五章—说服开发人员或企业从运行在虚拟服务上的遗产应用程序迁移可能很困难且耗时。他们可能没有足够的员工或主题专家来协助工作,并倾向于保持现状。Anthos 包括一个实用工具来帮助这个过程,从识别迁移候选工作负载到实际将这些工作负载从虚拟机迁移到容器。
-
第十六章—要将工作负载从任何遗产技术迁移到容器,您需要了解最佳方法和迁移到微服务的益处。本章将通过实际案例和要避免的反模式,教您如何使用 Anthos 通过现代化您的应用程序。
-
第十七章——将更高级的工作负载迁移到 Kubernetes 变得越来越普遍,包括可能需要 GPU、PCI 卡或外部硬件组件的工作负载。尽管你可以在虚拟环境中完成这项任务,但这样做有其局限性,并且存在几个复杂性。在本章中,你将学习如何在裸金属上部署 Anthos,以提供一个平台来满足你可能在 VMware 上遇到限制的需求。
以下附加附录可在本书的 ePub 和 Kindle 版本中找到,你可以在 liveBook 上在线阅读:
- 附录 A 云是新的计算堆栈
菲尔·泰勒
- 附录 B 来自现场的经验教训
凯尔·巴塞特
- 附录 C 在 VMware 上运行的计算环境
约阿希姆·加耶夫斯基
- 附录 D 数据和分析
帕特里夏·弗洛里斯
- 附录 E ML 应用的端到端示例
阿米塔·卡波尔
- 附录 F 在 Windows 上运行的计算环境
卡斯林·菲尔德斯
liveBook 讨论论坛
购买 Google Anthos in Action 包括免费访问 liveBook,曼宁的在线阅读平台。使用 liveBook 的独特讨论功能,你可以在全球范围内或针对特定章节或段落附加评论。为自己做笔记、提出和回答技术问题,以及从作者和其他用户那里获得帮助都非常简单。要访问论坛,请访问 livebook.manning.com/book/google-anthos-in-action/discussion。你还可以在 livebook.manning.com/discussion 上了解更多关于曼宁论坛和行为准则的信息。
曼宁对读者的承诺是提供一个场所,让读者之间以及读者与作者之间可以进行有意义的对话。这不是对作者参与特定数量活动的承诺,作者对论坛的贡献仍然是自愿的(且未付费)。我们建议你尝试向他们提出一些挑战性的问题,以免他们的兴趣偏离!只要本书有售,论坛和以前讨论的存档将可通过出版社的网站访问。
关于主要作者
安东尼奥·古利对建立和管理全球技术人才以推动创新和执行充满热情。他的核心专长在于云计算、深度学习和搜索引擎。目前,他担任谷歌云首席技术官办公室的工程总监。此前,他曾担任谷歌华沙站点负责人,将工程站点的规模扩大了一倍。
到目前为止,Antonio 在欧洲四个国家获得了专业经验,并在欧洲、中东、亚洲和美国六个国家管理过团队;在阿姆斯特丹,作为 Elsevier(一家领先的科学出版商)的副总裁;在伦敦,作为微软 Bing 的工程站点负责人;在意大利和英国担任 CTO;在欧洲和英国担任 Ask.com 的 CTO;以及在几个共同创立的初创公司中,包括欧洲最早的网页搜索公司之一。
Antonio 共同发明了搜索、智能能源和 AI 领域的几项技术,拥有 20 多项已授权/申请的专利,他还撰写了关于编码和机器学习的几本书,这些书也被翻译成了日语、俄语、韩语和中国语。Antonio 会说西班牙语、英语和意大利语,目前正在学习波兰语和法语。Antonio 是两个男孩 Lorenzo(22 岁)和 Leonardo(17 岁)以及一个小公主 Aurora(13 岁)的骄傲的父亲,他们都有发明创造的激情。
Scott Surovich 在过去 20 年里一直是世界上最大银行之一 HSBC 的工程师。在那里,他担任过各种工程角色,包括与思杰、Windows、Linux 和虚拟化合作。在过去三年中,他一直是混合集成平台团队的负责人和 Kubernetes/Anthos 的产品负责人。
Scott 一直热衷于为任何愿意学习的人培训和撰写关于技术的文章。他多年来一直是一名认证培训师,为包括微软、思杰和 CompTIA 在内的多个供应商教授认证课程。2019 年,他共同撰写的第一本书《Kubernetes 和 Docker:企业指南》出版。该书受到了好评,在第一版成功之后,更新后的第二版于 2021 年 12 月 19 日发布,并在发布的第一周成为了畅销书。
他也是一个狂热的 3D 打印爱好者(几乎到了上瘾的地步),微控制器爱好者,以及热衷的曲棍球运动员。当 Scott 有空闲时间时,他更喜欢和妻子 Kim 以及他的狗 Belle 一起度过。
Scott 还想要感谢谷歌给他加入初始 Google Fellow 试点小组的机会,并信任他参与这本书的创建。
Michael Madison 喜欢探索新的云计算技术,并寻找利用计算进步来简化公司运营和为客户创造新价值的方法。他目前在 World Wide Technology 担任云平台架构师,这使他能够帮助公司和组织开始或继续他们的云之旅。
尽管迈克尔作为一名 IT 专业人士已有超过 15 年的经验,但他最初是在娱乐行业起步,为主题公园和邮轮公司工作。最终,他对编程的爱好变成了他的主要职业,并将他的领域扩展到基础设施和云计算。当机会来临时,他全身心投入到云计算项目中,将他在软件开发方面的十年经验应用于云计算和混合部署的挑战中。
迈克尔原籍德克萨斯州,他在乔治亚州、阿拉斯加和德克萨斯州生活和学习。他最终在密苏里州找到了工作,目前住在圣路易斯郊外。迈克尔和他的妻子拥有一辆房车,并计划在几年后带着他们的狗 Shenzi 环游全国。
关于封面插图
《Google Anthos in Action》封面上的插图标题为“Frascati 居民”,或“Frascati 居民”,摘自雅克·格拉塞·德·圣索沃尔(Jacques Grasset de Saint-Sauveur)于 1797 年出版的作品集。每一幅插图都是手工精心绘制和着色的。
在那些日子里,人们通过他们的服饰就能轻易地识别出他们居住的地方以及他们的职业或社会地位。曼宁通过基于几个世纪前丰富多样的地域文化的书封面来庆祝计算机行业的创新精神和主动性,这些文化通过如这一系列图片的图片被重新带回生活。
1 Anthos 概述
阿帕尔纳·辛哈
本章涵盖
-
现代应用程序的解剖结构
-
使用 Anthos 加速软件开发
-
使用 Anthos 在规模上标准化操作
-
谷歌的起源
-
如何阅读这本书
软件已经统治世界一段时间了。作为消费者,我们已经习惯了那些使叫车或存支票等事情变得更快、更智能、更高效的应用程序。日益增多的是,我们的健康、教育、娱乐、社交生活和就业都得到了现代软件应用程序的增强。在这些应用程序的另一端,是一系列大小企业,它们提供这些改进的体验、服务和产品。现代应用程序不仅部署在消费者手中,也部署在企业供应链的各个点上。许多传统行业(如零售、媒体、金融服务、教育和物流)的主要交易系统正在逐渐被频繁自动更新、高效扩展并融入更多实时智能的现代微服务所取代。新的以数字为先的初创公司正在利用这个机会颠覆传统商业模式,而企业老牌公司则急于现代化他们的系统,以便竞争并避免被颠覆。
本书将带您了解 Anthos 的解剖结构——平台、开发环境、自动化和扩展的元素,以及与谷歌适应的模式的连接,以在任何行业的现代软件开发中达到卓越。每一章都包括如何使用该平台的具体示例,其中几章还包括动手练习来实现这些技术。
1.1 现代应用程序的解剖结构
什么是现代应用程序?当你想到那些改善你生活的软件时,你可能想到的是那些交互性强、快速(低延迟)、连接性强、智能、具有情境感知、可靠、安全且在任何设备上易于使用的应用程序。随着技术的进步,现代应用程序的能力,如安全性、可靠性、感知能力和智能水平,也在不断提高。例如,新的开发框架如 React 和 Angular 极大地提高了应用程序的交互性水平,而新的运行时如 Node.js 则增加了功能。现代应用程序具有通过频繁更新不断改进的特性。在后台,这些应用程序通常由许多持续改进的服务组成。这种模块化是通过打破旧的“单体”应用程序编写模式实现的,在这种模式中,所有各种功能都紧密耦合在一起。
以模块或微服务形式编写的应用程序提供了多项优势:组成服务可以独立演进或随着时间的推移替换为其他更可扩展或更优越的服务。此外,现代微服务模式在分离关注点和在服务之间设置合同方面做得更好,这使得检查和修复问题变得更加容易。这种将应用程序作为微服务编写、更新和部署的方法,这些微服务可以一起使用,但也可以独立更新、扩展和调试,是现代软件开发的精髓。在这本书中,我们将这种模式称为“现代”或“云原生”应用程序开发。术语云原生适用于此处,因为微服务模式非常适合在分布式基础设施或云上运行。微服务可以逐步推出、扩展、修订、替换、调度、重新调度,并在分布式服务器上紧密打包,从而创建一个高效、可扩展、可靠的系统,该系统响应迅速且经常更新。
现代应用程序可以按照一系列架构和运营原则从头开始编写(greenfield)或通过重构现有的brownfield应用程序来实现。应用程序现代化的最终目标通常是加速收入,通常这涉及到 IT 部门之外的业务线(LOB)团队。大多数传统企业的 IT 部门在历史上一直专注于降低成本和优化运营。尽管降低成本和优化运营可能是应用程序现代化的副产品,但它们并不是最重要的好处。当然,现代化过程本身需要前期投资。Anthos 是谷歌云在混合和多云环境中进行应用程序现代化的平台。它提供了实现高投资回报率应用程序现代化所需的方法和技术基础。强调通过 API、微服务和云可移植性实现模块化的 IT 战略,结合一个能够自动化重用、实验和成本效益扩展以及安全可靠运营的开发者平台,是成功应用程序现代化的基本关键前提。
Anthos 的一个方面是现代开发者体验,它加速了业务线应用程序的开发。它针对重构棕色地带应用程序和编写基于微服务和 API 的应用程序进行了优化。它提供统一的本地、本地和云开发,从源到生产的自动化事件驱动。开发者可以使用现代语言和框架快速编写代码,并使用本地仿真和测试以及集成 CI/CD,Anthos 支持快速迭代、实验和高级部署策略。Anthos 开发者体验强调云 API、容器和函数,但企业平台团队也可以对其进行定制。Anthos 开发者体验的一个关键目标是让团队每天多次发布代码,从而提高速度和可靠性。Anthos 具有内置的速度和投资回报率指标,以帮助开发团队衡量和优化其性能。数据驱动的基准测试通过预先包装的最佳实践蓝图得到增强,团队可以部署这些蓝图以实现性能的下一个层次。
Anthos 的另一个方面是为中央 IT 提供的操作员体验。Anthos 以其独特可扩展、简化的方式在多个云中运行操作而脱颖而出。这一功能得益于谷歌在过去 20 年发明和磨练的非凡技术基础,该技术基础在相对低成本的基础设施上运行具有极高可靠性的服务。这是通过使用由 Kubernetes、Istio、Knative 和其他构建块组成的抽象层标准化基础设施来实现的,以及 Anthos 特定的扩展和集成,用于自动化配置、安全和操作。Anthos 的操作员体验提供高级安全性和策略控制、自动声明性配置、高度可扩展的服务可视化和操作,以及自动资源和成本管理。它具有广泛的自动化、测量和故障避免能力,用于高可用性、云、本地、边缘、虚拟化和裸机基础设施上的安全服务管理。
企业和小公司一样发现,多云和边缘计算是他们的新现实,无论是通过自然发展还是通过收购。许多国家的法规要求证明在云之间迁移应用程序的能力,并展示对主权支持的故障容忍度。未受监管的公司发现多云对于提供开发者的选择和访问创新服务是必要的。在边缘运行服务和提供更高智能的机会进一步扩大了基础设施的影响范围。一些 IT 组织自行开发跨云平台集成,但这项工作每天都在变得更加困难。以可扩展、可维护的方式构建跨云平台极为困难,更重要的是,这种方法会从宝贵的开发者时间中扣除用于产品创新的时间。
Anthos 提供了一个基于谷歌在软件开发和站点可靠性工程(SRE)操作多年经验和技术创新的解决方案,并辅以谷歌云管理数百万企业客户现代应用基础设施的经验。Anthos 的独特之处在于同时满足 LOB 开发者和中央 IT 的需求,在两个领域都具备高级功能。开发者和操作员在不同环境中的体验一致性使企业能够通过 Anthos 获得应用现代化带来的最大回报率。
1.1.1 加速软件开发
软件产品创新和新的客户体验是数字经济中新收入增长的引擎。但在创新过程中,只有少数想法能转化为成功的新产品;大多数失败并消失。随着每个行业过渡到软件驱动,新产品创新依赖于拥有高度敏捷和高效的软件开发流程。开发者是新国王的制造者。没有敏捷、高效的开发流程和平台,公司可能无法创新,或者以非常高的成本进行创新,甚至产生负的回报率。广泛的 DevOps 研究评估¹研究(DORA)在几年内对超过 30,000 名 IT 专业人士进行了调查,涉及各种 IT 职能。它表明,软件开发的高超是商业成功的标志。考虑到现代应用在推动经济中的重要性,这一点并不令人惊讶。
DORA 量化了这些好处,表明“精英”或表现最高的软件团队在实现收入和业务目标方面比低绩效团队高出两倍。精英团队的区别特征是频繁发布软件。DORA 发现以下四个关键指标提供了对软件开发卓越的准确测量:
-
部署频率
-
变更的领先时间
-
变更失败率
-
恢复服务时间
高效团队频繁发布软件,例如,每天发布几次。相比之下,表现不佳的团队每月发布次数不到一次。该研究还发现,频繁发布的团队软件缺陷率较低,并且比其他团队更快地从错误中恢复。因此,除了更具创新性和现代性之外,他们的软件更加可靠和安全。年复一年,DORA 结果也显示,越来越多的企业正在投资于能够实现精英表现的工具和实践。
为什么开发速度较快的团队有更好的业务成果?一般来说,更高的速度意味着开发者可以进行更多的实验和测试,因此在相同的时间内可以提出更好的答案。但还有一个原因。开发速度较快的团队通常已经将编写和部署代码变成了一种自动化、低成本的流程,这附带的效果是使更多的人成为开发者,特别是那些在业务方面比在工具方面更根深蒂固的人。因此,高速度的开发者团队有更多的业务线思维和更深入的用户需求理解。快速实验和关注用户的结合产生了更好的业务成果。Anthos 是跨云运行的共同基础层,为加速应用程序交付提供统一的开发者体验。
1.1.2 在规模上标准化运营
开发者可能是新的国王制造者,但运营团队是每天运营王国的团队。运营包括提供、升级、管理、故障排除和扩展服务、基础设施和云的各个方面。通常,网络、计算、存储、安全、身份、资产管理、计费和可靠性工程都是企业运营团队的一部分。传统的 IT 团队在 IT 运营方面的人员比例从 15%-30%不等。这个团队并不总是明显地参与与业务线的全新产品介绍,但它经常奠定基础,选择云服务、发布服务目录,并使服务符合业务使用。未能投资于运营自动化往往意味着这个团队成为瓶颈和固定成本来源。
反之,现代化运营对速度有巨大的积极影响。现代应用程序开发团队通常由一个非常精简的运营团队支持,其中 80%以上的员工从事软件开发而非运营。这种以开发者为中心的比例只有通过现代化的基础设施和可扩展的自动化运营才能实现。这意味着运营非常精简,并使用广泛的自动化来快速上线新服务。也许 Anthos 最大的价值在于在各个环境中一致地自动化运营,这是由一个独特的开放云方法实现的,该方法起源于谷歌自身的基础设施。
1.2 谷歌的起源
谷歌的软件开发流程经过多年的优化和微调,以最大化开发者的生产力和创新,这吸引了世界上最优秀的软件开发者,并导致了软件和软件开发及交付实践的创新良性循环。Anthos 开发堆栈从这些基础中发展而来,并建立在谷歌向行业引入的核心开源技术之上。
Anthos 的核心是 Kubernetes,这是一个通过容器抽象层管理基础设施的广泛编排和自动化模型。Kubernetes 上面的层基于谷歌的 SRE 或运营实践,这些实践标准化了大规模服务的控制、安全和管理工作。这一层的服务管理根植于基于 Google Istio 的云服务网格。企业策略和配置自动化通过 Anthos Config Management 构建在这一层,以提供大规模的自动化和安全保障。这个平台可以在多个云上运行,并抽象出下面的不同网络、存储和计算层(见图 1.1)。

图 1.1 Anthos 组件和功能
在 Anthos 堆栈之上是开发者体验和 DevOps 工具,包括使用 Knative 的部署环境以及与 Tekton 集成的 CICD。
摘要
-
现代软件应用程序提供了一系列商业优势,并在许多行业中推动了转型。
-
这些应用程序的后端通常基于云原生微服务架构模式,这允许极大的可扩展性、模块化,以及一系列适合在分布式基础设施上运行的运营和 DevOps 优势。
-
Anthos 是一个起源于 Google Cloud 的平台,用于托管云原生应用程序,提供开发和运营方面的优势。
^(1.)www.devops-research.com/research.xhtml.
2 一个单一视角
Melika Golkaram
本章涵盖
-
拥有一个单一视角及其组件的优势
-
不同角色如何使用和从这些组件中获益
-
获取一些实际经验来配置 UI 并将集群连接到 Anthos UI
我们生活在一个应用性能对成功至关重要的世界中。为了更好地服务其最终用户,许多组织已经推动将他们的工作负载从集中的数据中心分散出去。无论是为了更接近用户、增强灾难恢复还是利用云计算的好处,这种分散都给用于管理和支持这一策略的工具带来了额外的压力。在这种新范式下繁荣的工具是那些已经成熟、变得更加复杂和可扩展的工具。
没有一劳永逸的工具。同样,也没有哪个人能够管理甚至一个小型组织的整个基础设施。所有应用程序都需要工具来管理持续集成/持续部署(CI/CD)、监控、日志记录、编排、部署、存储、身份验证/授权等。除了前面提到的可扩展性和复杂性之外,这个领域的大多数工具还提供了一个信息丰富且用户友好的图形用户界面(GUI)。拥有一个易于理解的 GUI 可以帮助人们更有效地使用工具,因为它降低了学习软件的门槛,并增加了用户收到的相关信息量。
Anthos 本身具有支持数百个应用程序和数千个服务的容量,因此需要一个高质量的 GUI 和统一的用户体验,以充分利用生态系统并降低运营成本。为此,Google Cloud Platform 在 Google Cloud 控制台中提供了一套丰富的仪表板和集成工具,以帮助您监控、故障排除和与部署的 Anthos 集群交互,无论其位置或基础设施提供商如何。这个单一视角允许管理员、运维专业人员、开发人员和业务所有者查看其集群和应用工作负载的状态,同时受益于 Google Cloud 的标识和访问管理(IAM)框架以及每个集群提供的任何附加安全措施。
Anthos GUI 及其“单一视角”并不是第一个尝试集中管理集群舰队可见性和操作的产品,但它提供了对大量不同环境提供实时可见性的支持。为了全面了解 Anthos GUI 的好处,在本章中,我们将探讨一些可用于聚合和标准化与多个 Kubernetes 集群交互的选项。
2.1 单一视角
单一视角提供了以下三个在所有操作员、行业和操作规模中共享的特征:
-
集中化——正如其名所示,单视图应该为资源提供一个中心 UI,无论它们在哪里运行以及提供给谁。前者与集群运行的底层基础设施和云提供商相关,后者与本质上多租户服务相关,其中一位操作员集中管理多个客户的集群和工作负载。利用中心仪表板的优点,管理员将能够获得资源的高级视图,并深入到感兴趣的领域,而无需切换视图。
-
然而,中心环境可能会在隐私和安全领域引起一些担忧。并非每个管理员都需要连接到所有集群,并且并非所有管理员都应该能够访问 UI。中心环境应附带其自身的安全措施,以避免与行业标准有任何操作上的妥协。
-
一致性——让我们回到一个操作员在多云或混合架构中运行集群和客户的场景。大多数基础设施提供商,无论是提供专有服务还是基于开源,都试图为用户提供一个稳定的界面。然而,他们使用不同的术语,对优先级的看法也不一致。最后,根据他们的 UI 哲学和方法,他们设计视图和导航的方式也不同。记住,对于云提供商来说,集群和容器管理只是更大服务套件和预设计仪表板组件的一部分。虽然这可能在单一操作环境中是一个积极的因素(你可以在 Kubernetes 仪表板之外学习导航到其他云服务仪表板,而无需进行最小切换),但在多环境服务和仅关注 Kubernetes 的人看来,这会变成一个头疼的问题。
-
易用性——操作中单视图的吸引力之一在于来自不同来源的数据是如何聚合、规范化和可视化的。这为深入性能管理和分类提供了很多简便性,尤其是如果它结合了图形界面的话。
图形用户界面一直是任何在线应用的重要组成部分。首先,在应用管理周期中的某个时刻,团队可能既没有与远程调用工作的技能,也没有兴趣。他们期望有一个强大、易于导航且高度设备无关的 UI 来处理日常职责。
其次,无论团队的技术能力如何,一个聚合的仪表板在一个集中的视图中提供的功能远比逐个调用服务提供商和集群要多,因为 UI 提供了许多具有正确安装和可读性的数据字段。
2.2 非 Anthos 可见性和交互
Anthos 并非第一个通过比内置 API 更易于消化的形式来暴露 Kubernetes 集群信息的解决方案。尽管许多开发者和运维人员已经使用命令行界面 (CLI) kubectl 与集群交互,但呈现的信息可能非常技术性,并且通常不会以友好的方式显示潜在问题。Kubernetes 的扩展,如 Istio 或 Anthos Config Management,通常也附带自己的 CLI(例如 istioctl 和 nomos)。在所有不同的工具之间交叉引用信息可能是一项艰巨的任务,即使是经验最丰富的开发人员或运维人员也是如此。
2.2.1 Kubernetes 仪表板
解决此问题最早开发的工具之一是 Kubernetes 仪表板 (github.com/kubernetes/dashboard)。尽管这个实用程序默认情况下不会部署到新的 Kubernetes 集群,但它很容易部署到集群并开始使用它提供的信息。除了提供对 Kubernetes 集群大多数组件的整体视图外,仪表板还向用户提供了一个图形用户界面来将新工作负载部署到集群中。这使得仪表板成为查看状态和与新的集群交互的便捷且快速的方式。
然而,它只适用于一个集群。你当然可以将 Kubernetes 仪表板部署到每个集群中,但它们将保持相互独立,没有交叉连接。此外,由于仪表板位于集群本身上,远程访问它需要与使用 CLI 工具相似的努力,需要服务、负载均衡和入口规则来正确路由和验证传入流量。尽管仪表板对于概念验证或小型开发者集群来说可能非常强大,但多用户集群需要更强大的工具。
2.2.2 提供商特定的 UI
Kubernetes 从一开始就是一个开源项目。尽管基于 Google 内部工具,但 Kubernetes 的结构允许供应商和其他云服务提供商轻松创建他们自己的定制版本,无论是为了简化平台上的部署或管理,还是为了添加额外的功能。许多这些修改都为部署或管理操作定制了 UI。
对于云服务提供商来说,他们其他产品的许多用户界面已经存在,并遵循特定的风格。每个提供商都为其版本的 Kubernetes 开发了不同的 UI。尽管这些 UI 中有一部分处理集群的基础设施配置和维护,但每个 UI 中都有一些是专门用于集群操作和管理的。然而,每个 UI 的实现方式都不同,无法管理除该云提供商原生 Kubernetes 风味以外的集群。
2.2.3 定制软件
一些公司决定突破界限,开发自己的定制软件和 UI 来可视化和管理他们的 Kubernetes 安装和操作。尽管由于 Kubernetes API 的开放标准,这始终是一个选项,但任何定制开发都会带来维护任何定制操作软件所伴随的所有挑战:维护软件的新版本、修复错误、处理操作系统和软件包升级等等。对于最高程度的定制,没有比定制软件更好的选择,但对于大多数公司来说,成本与收益的计算并不划算。
2.3 Anthos UI
之前每种解决方案都有一个基本缺陷,阻止了大多数公司充分利用它。Kubernetes 仪表板没有多集群功能,且难以处理远程访问。供应商特定的 UI 对于其特定版本工作良好,但不能处理不在其网络或运行其版本 Kubernetes 的集群。而定制软件的开发和维护成本很高。这就是 Anthos 多集群单视图仪表板发挥作用的地方。这个单视图仪表板是 Google Cloud Platform 已广泛使用的云控制台的扩展和嵌入,允许用户查看、监控和管理他们整个云基础设施和工作负载。
谷歌为 Anthos 中的多集群可见性开发的解决方案依赖于一个名为 fleets(之前被称为 environs)的新概念,Connect 框架以及 Anthos 仪表板。Anthos 仪表板是谷歌为其已经提供多年的、针对其云中 GKE 集群的现有 GKE 仪表板的增强。Connect 框架是 Anthos 的新特性,简化了 Google Cloud 与世界各地集群之间的通信过程。Fleets 是一种聚合集群的方法,以简化它们之间的常见工作。让我们花点时间来更深入地讨论一下 Fleets。
2.3.1 Fleets
Fleets 是谷歌用于逻辑组织集群和其他资源的一个云概念,让您可以使用和管理多集群功能,并在您的系统中应用一致的政策。把它们想象成一个分组机制,它为单个项目内的资源应用了多个安全和操作边界。¹ 它们帮助管理员在 fleet 和其成员集群及资源之间建立一对一的关系,以减少单个安全性和访问规则的配置负担。属于同一 fleet 的集群之间也存在更高的信任关系。这使得管理集群之间的流量以及将它们的服务网格连接起来变得更加容易。
一个 Anthos 集群将只属于一个且仅属于一个舰队,并且不能在不离开第一个舰队的情况下加入另一个舰队。不幸的是,这种限制在复杂的服务通信中可能会带来一些小问题。例如,假设我们有一个 API 服务和一个数据处理服务,由于安全原因,它们需要运行在不同的舰队中,但两者都需要与一个定制的权限服务进行通信。权限服务可以放置在两个舰队中的任何一个,但任何不属于权限服务舰队的服务都需要通过集群外部的网络与该服务进行通信。然而,这个关于舰队的规则阻止了用户意外地将必须保持分离的集群合并,因为允许通用服务同时存在于两个舰队中会打开额外的攻击向量(见图 2.1)。

图 2.1 舰队合并导致的安全问题示例
当多个集群位于同一舰队中时,许多类型的资源必须具有唯一的名称,否则它们将被视为相同的资源。这显然包括集群本身,但也包括命名空间、服务和标识。Anthos 将其称为“相同性”。相同性强制在舰队中的所有集群之间保持一致的所有权,并且在一个集群上定义但在另一个集群上未定义的命名空间将被隐式保留。
在设计您服务的架构时,必须牢记这个相同的概念。例如,Anthos 服务网格通常将同一命名空间中具有相同名称的服务视为整个舰队中的相同服务,并自动在集群之间进行流量负载均衡。如果所涉及的命名空间和/或服务具有唯一名称,这不应引起任何混淆。然而,访问 Demo 命名空间中的 Webserver 服务可能会产生意外的结果。
最后,Anthos 允许所有服务在访问外部资源,如 Google Cloud 服务、对象存储等时使用一个共同的标识。这个共同的标识使得在舰队内部的服务一次访问外部资源成为可能,而不是每个集群分别访问。尽管这可以被覆盖并且可以定义多个标识,但如果资源没有精心设计和正确配置,可能会出现负面结果。
2.3.2 连接:它是如何工作的?
现在我们已经讨论了舰队,我们需要检查各个集群如何与 Google Cloud 进行通信。任何作为 Anthos 部分的一部分的集群,无论是附加² 还是 Anthos 管理的,都会在安装或注册过程中将 Connect 部署到集群。这种部署从集群到 Google Cloud 建立了一个持久的连接,该连接接受来自云的流量并为集群提供云侧操作的安全访问。由于初始连接是外出的,它不依赖于从云到集群的完全可路由连接。这种设置大大减少了安全考虑,并且不需要集群在公共互联网上被发现。
一旦建立了持久连接,Anthos 可以代理 Google Cloud 服务或用户通过 Google Cloud UI 向集群发起的请求,无论该集群位于 Google Cloud 内部、其他云服务提供商、边缘或本地。这些请求使用用户或服务的凭证,保持集群的安全性,并允许现有的基于角色的访问控制(RBAC)³ 规则跨越直接连接以及通过代理的连接。使用 Anthos UI 的请求可能看起来像图 2.2。

图 2.2 从 Google Cloud 到集群及返回的请求和响应流程
尽管从 Connect 代理到 Google Cloud 的隧道是持久的,但每个请求的每个阶段都使用各种机制进行身份验证,以验证请求者的身份并确认该层是否允许发起请求。跳过层是不允许的,并且无效请求将被接收下一层的层拒绝。请求-响应身份验证的概述可见于图 2.3。

图 2.3 从 Google Cloud 到集群的请求验证步骤
无论集群级别的任何授权措施如何,用户仍然必须允许查看集群附加的 Google Cloud 项目,以使用 Connect 功能。此方法使用给定项目的标准 IAM 流程,但拥有单独的权限允许安全团队通过直接连接(或某些其他隧道)授予用户对集群的访问权限,但不允许他们通过 Google Cloud 进行远程访问。
Connect 符合 Google 的访问透明度⁴,在以下两个领域为顾客提供透明度:
-
访问批准—客户可以授权 Google 支持人员对其服务的一部分进行工作。客户可以查看 Google 员工可能需要该访问的原因。
-
活动可见性—客户可以将访问日志导入其项目云日志中,以了解 Google 员工的操作和位置,并在必要时实时查询日志。
2.3.3 安装和注册
要使用 Connect 功能,我们显然需要在我们的集群上安装 Connect 代理。我们还需要通知谷歌我们的集群属于哪个项目,以及因此属于哪个舰队。幸运的是,谷歌已经通过 gcloud 命令行工具提供了一种简化的实用程序来完成此任务(见mng.bz/Op72)。此过程使用工作负载身份或谷歌云服务账户将集群注册到项目的 Connect 池,并在集群上安装和启动 Connect 代理。
虽然这些步骤将集群注册到谷歌并启用了大多数 Anthos 功能,但您仍然需要从谷歌控制台对集群进行身份验证,才能从谷歌云中查看和交互集群。Connect 允许通过云身份(当使用 Connect 网关时)、⁵载体令牌或如果集群上启用了 OIDC 进行身份验证。最简单且推荐的方法是使用云身份,但这需要为集群激活和配置 Connect 网关。有关 Connect 网关的更多信息,请参阅第五章关于 Anthos 的操作管理。
2.4 Anthos 云 UI
现在我们已经完成了管道安装,我们可以走一遍并展示 UI 界面。谷歌通过项目级别的云控制台提供 Anthos UI。由于 Anthos UI 仅在项目级别可见,因此只有注册到该项目舰队中的集群是可见的。Anthos UI 菜单包含多个子页面,每个页面都专注于集群管理的不同方面。在撰写本文时,这些部分包括仪表板、服务网格、配置管理、集群、功能、迁移到容器、安全、Anthos 的云运行和虚拟机。让我们逐一查看这些页面。
2.4.1 Anthos 仪表板
Anthos 菜单的默认页面,以及 UI 的中心枢纽是仪表板。仪表板旨在让管理员对当前舰队中的集群有一个宽视角,同时便于深入到特定组件的细节。首先,前往控制台左上角的三明治菜单(图 2.4)。从菜单中选择 Anthos 以进入 Anthos 功能页面。

图 2.4 导航到 Anthos 仪表板
图 2.5 显示了 Anthos 仪表板视图的示例。

图 2.5 Anthos 仪表板示例
尽管这个示例显示了当前的 Anthos 项目成本,但仪表板仍然使用谷歌的 IAM,并且只有查看用户具有适当的计费相关权限时,该信息才会出现。其余部分突出了 Anthos 该方面的关键错误或其他用户参与的问题。点击这些链接将带您到相应的子页面。
2.4.2 服务网格
服务网格页面显示了当前舰队中任何集群中注册的所有服务。初始列表显示了每个服务的名称、命名空间和集群,以及预定义阈值下的基本指标,如错误率和延迟。您还可以通过命名空间、集群名称、每秒请求数、错误率、延迟、请求大小和资源使用情况来过滤此列表,以便管理员可以轻松地深入特定任务。图 2.6 显示了针对默认命名空间中的服务进行过滤的服务网格屏幕。

图 2.6 带有过滤器的服务网格 UI
2.4.3 配置管理
在第十一章中深入探讨的 Anthos Config Management 是 Anthos 在 Kubernetes 集群上自动添加和维护资源的方法。这些资源可以包括大多数常见的 Kubernetes 核心对象(如 Pods、Services 和 Service Accounts)以及自定义实体,如策略和云配置对象。此选项卡显示了当前舰队中所有集群的列表、它们的同步状态以及当前在集群上强制执行的修订版本(图 2.7)。表格还显示是否已为集群启用了策略控制器⁶。

图 2.7 配置管理视图中的集群
选择特定的集群将打开配置管理集群详细视图,如图 2.8 所示。此详细视图提供了有关配置设置的更多信息,包括使用的仓库位置、同步周期以及集群上运行的 ACM 版本。

图 2.8 配置管理视图中的集群详细
2.4.4 集群
集群菜单列出了当前舰队中的所有集群,包括位置、类型、标签以及与每个集群关联的任何警告,如图 2.9 所示。通过在列表中选择一个集群,将在右侧边栏中显示集群的更详细视图,包括当前 Kubernetes 版本、可用的 CPU 和内存以及启用的功能,如图 2.10 所示。在侧边栏信息下方,一个管理功能按钮将带您进入该集群的功能选项卡。在图 2.9 中,以下集群在项目中创建:
-
GKE (cluster-gcp)
-
硬件(cluster-1)
-
Azure AKS (azure-cluster 和 externalazure)

图 2.9 集群菜单中的列表视图

图 2.10 集群菜单中的集群详细侧边栏
2.4.5 功能
Anthos 服务包含几个功能(在其他章节中更详细地介绍),包括:
-
配置管理
-
入口
-
二进制授权
-
Anthos 的 Cloud Run
-
服务网格
功能菜单提供了一个简单的方法来为整个舰队启用和禁用特定的服务。图 2.11 显示了每个集群现有功能的列表。

图 2.11 功能菜单
管理员还可以从界面禁用或启用这些功能中的大多数(某些功能是 Anthos 的基本组件,无法禁用)。同样,通过 gcloud 或舰队管理 API 也可以实现这种可能性,以实现更好的自动化。值得注意的是,如果无法通过可视化界面完全启用,控制台会生成管理员可以无缝输入 CLI 的正确命令。
2.4.6 迁移到容器
Anthos 的一大优势是自动将 Windows 和 Linux VM 迁移到容器,并将它们部署到兼容的 Anthos 集群。以前,这主要是通过 CLI 完成,并从源集群启动,但此菜单现在提供了一个方便的集中流程,用于将 VM 转移到容器,并进入不同的部署方案。该菜单包含用于查看和管理迁移、源和处理集群的标签页。有关将现有 VM 迁移到容器的过程的信息,请参阅第十五章,“迁移。”
2.4.7 安全
安全菜单是您找到与查看、启用和审计当前舰队中集群安全状态相关的多个工具的地方。图 2.12 显示了您首次选择安全菜单时的基本视图。

图 2.12 安全菜单
如您所见,我们目前尚未启用二进制授权⁷,但 Anthos 提供了一个快捷方式,可以快速将其启用。一旦我们启用,就会显示二进制授权的配置页面(图 2.13),使我们能够查看和编辑策略(如果需要的话)。

图 2.13 二进制授权策略详情
2.5 监控和日志
然而,GCP 控制台中的 Anthos 菜单只是解决方案的一部分。Google 还提供了操作套件,包括云监控和云日志,以帮助管理应用程序和基础设施的操作。Anthos 将应用程序数据的记录和指标简化为操作套件的一部分,作为默认部署的一部分。这可以使基于这些指标的 SLO 和 SLA 的添加变得容易。⁸ 此外,Anthos 菜单中的几个页面包括快捷方式和按钮,可以触发向导以引导方式创建 SLO。
2.6 GKE 仪表板
Google 已经提供了 GKE 仪表板多年,以帮助您在 GCP 中查看和管理 GKE 集群。随着 Anthos 的发布,GKE 仪表板已扩展以显示通过 GKE Connect 连接的 Kubernetes 集群的详细信息。尽管 Anthos 菜单专注于集群的高级功能和 Anthos 特定的功能,如服务网格和配置管理,但 GKE 仪表板允许管理员深入到特定的工作负载和服务。下一节将介绍如何将 Azure AKS 集群注册到 Anthos 仪表板中的教程。
2.7 连接到远程集群
在本例中,Azure Kubernetes Service (AKS)引擎中已经创建了一个集群。谷歌允许远程注册几种集群类型,称为附加集群(见mng.bz/Y6ne)。要附加这些集群,您需要执行以下步骤:
-
在可以访问要注册的集群的计算机上打开一个终端窗口。注意连接到集群使用的 kubeconfig 文件的完整路径。
-
在谷歌控制台中,在 IAM 部分下,创建一个具有 GKE Connect Agent 角色的 Google 服务帐户。生成一个账户密钥并保存。
-
在您的 Anthos 项目中确定集群的官方名称;这是成员名称。
-
使用以下命令注册您的集群,将
字段替换为适当的信息:⁹ gcloud container fleet memberships register <MEMBERSHIP_NAME> \ --context=<KUBECONFIG_CONTEXT> \ --kubeconfig=<KUBECONFIG_PATH> \ --service-account-key-file=<SERVICE_ACCOUNT_KEY_PATH>几分钟后,您的集群出现在 GCP 控制台中,如图 2.14 所示。
![02-14]()
图 2.14 已注册集群视图
-
验证已注册的集群。如图所示,最近创建的集群(externalazure)旁边出现了一个警告标志。这是正常的,也是提醒您登录到集群以执行更多操作。图 2.15 显示了集群注册状态的视图。

图 2.15 集群注册状态视图
通过点击集群的三点,您可以看到可用的操作。点击登录,您可以看到以下登录选项可用:
-
使用您的谷歌身份登录
-
令牌
-
基本认证
-
使用为集群配置的标识提供者进行认证
让我们继续使用令牌进行认证。为此,您需要一个具有正确权限的 Kubernetes 服务帐户(KSA)。如果您还没有,请在您的终端中键入以下内容来创建一个 KSA:
KSA_NAME=[KSA_NAME]
kubectl create serviceaccount ${KSA_NAME}
kubectl create clusterrolebinding [VIEW_BINDING_NAME] \
--clusterrole view --serviceaccount default:${KSA_NAME}
kubectl create clusterrolebinding [CLOUD_CONSOLE_READER_BINDING_NAME] \
--clusterrole cloud-console-reader --serviceaccount default:${KSA_NAME}
KSA 权限
所有登录到集群的帐户都需要在集群中至少持有以下 Kubernetes RBAC 角色:
-
view—Kubernetes 基本角色,允许以只读访问权限查看命名空间中的大多数对象。它不允许查看角色或角色绑定。
-
cloud-console-reader—希望查看控制台中集群资源的用户需要具有相应的权限。您通过在集群中创建一个 ClusterRole RBAC 资源,即 cloud-console-reader,来定义这一组权限。cloud-console-reader 授予其用户对集群节点、持久卷和存储类的 get、list 和 watch 权限,使他们能够查看这些资源的详细信息。
创建了 KSA 后,获取 KSA 的 Bearer 令牌:
SECRET_NAME=$(kubectl get serviceaccount [KSA_NAME] -o jsonpath=‘{$.secrets[0].name}’)
kubectl get secret ${SECRET_NAME} -o jsonpath=‘{$.data.token}’ | base64 --decode
在谷歌控制台中粘贴令牌到登录提示后,你立即会在你的 AKS 集群(externalazure)中看到与其他集群类型相同的视图。图 2.16 展示了该视图。

图 2.16 Anthos 附加集群已认证
图 2.17 通过仪表板显示了节点及其健康状态。

图 2.17 附加集群的节点视图
可以通过这种方式将几种不由 GCP 管理的 Kubernetes 集群附加到 Anthos 上。这样做可以简化操作并提供一致性,并允许管理员从单一平台访问安全权限。
摘要
-
为使用微服务的任何组织提供单一视角的混合和多云 Kubernetes 是成功和全球运营的基石。
-
单一视角的最大好处之一是管理员可以使用相同的界面来配置服务级别目标(SLO)和警报,以确保服务保证。
-
Anthos UI 提供了一些主要优势,包括以下这些:
-
服务和资源的集中操作
-
在多个服务提供商之间保持一致的运营体验
-
无需费力的导航和简单的员工培训
-
任何组织角色的窗口
-
-
Anthos UI 提供多种用法,包括集群管理、服务操作和可观察性,使用统一的界面。
^(1)Google Cloud Platform 项目是一组配置设置,它定义了您的应用程序如何与 Google 服务交互以及它使用哪些资源。
^(2)通过附加集群,您可以在 Google Cloud 控制台中查看现有的 Kubernetes 集群以及您的 Anthos 集群,并在它们上启用 Anthos 的一些功能子集,包括与 Anthos Config Management 的配置。更多详情请参阅 mng.bz/pdRE。
^(3)基于角色的访问控制(RBAC)是一组权限和授权组件,它允许或拒绝管理员或计算对象对一组请求资源的访问。
^(4)启用了访问透明度的服务允许客户通过 Google 人员控制对其组织数据的访问。它还提供了日志,记录 Google 人员在访问客户内容时采取的操作。
^(5)Google Cloud Identity and Access Management (IAM) 允许您授予对特定 Google Cloud 资源的更细粒度的访问权限,并防止对其他资源的未授权访问。
^(6)策略控制器是 Anthos Config Management 的一部分,允许管理员定义自定义规则,为安全、资源管理或操作原因设置护栏。
^(7)在第十二章“与 CI/CD 的集成”中进一步探讨了二进制授权。
^(8)有关 Anthos 的 SLIs、SLOs 和 SLAs 的详细信息,请参阅第四章。
^(9)--kubeconfig 行是存储包含要注册的集群条目的 kubeconfig 的本地文件路径。如果设置了该环境变量,则默认为 $KUBECONFIG;否则,默认为 $HOME/.kube/config。
基于 Kubernetes 构建的计算环境
Scott Surovich
本章涵盖
-
理解 Kubernetes 管理、架构、组件和资源
-
声明式应用程序管理
-
理解 Kubernetes 资源
-
控制 Pod 调度
-
例子和案例研究
就像许多新技术一样,Kubernetes 可能难以学习和实施。手动创建集群需要包括公钥基础设施、Kubernetes、Linux 和网络在内的广泛技能集。许多供应商认识到这个问题,并自动化了集群创建,允许你创建具有很少或没有 Kubernetes 背景的 Kubernetes 集群。虽然自动化允许任何人创建集群,但它也消除了很多可以帮助你解决作为集群管理员或平台开发者可能遇到的问题的 Kubernetes 知识。
经常出现的问题是,“你真的需要了解 Kubernetes 吗?”答案因你在集群中扮演的角色而异,但无论你将扮演什么角色,你都需要对 Kubernetes 的功能有一定的了解。例如,如果你是集群管理员,你应该了解所有集群组件如何交互。这种理解将帮助你排查集群和工作负载部署问题。作为开发者,你应该了解基本的 Kubernetes 操作和各种 Kubernetes 资源,也称为 Kubernetes 对象,这些资源可以用来部署你的工作负载。了解如何通过使用选择器、容忍度和亲和/反亲和规则等选项将部署强制推送到节点或一组节点也很重要。
在本章中,你将学习 Kubernetes 集群中每个组件如何与其他组件交互。一旦你理解了基本交互,你将了解最常用的 Kubernetes 资源。最后,为了结束本章,你将学习 Kubernetes 如何调度工作负载的细节,以及如何根据标签、选择器和亲和/反亲和规则来约束调度器放置工作负载。
3.1 为什么你需要了解 Kubernetes?
Anthos 的核心是 Kubernetes,它为在集群中运行的应用程序提供计算引擎。Kubernetes 是由 Google 创建的一个开源项目,已经存在多年。在撰写本文时,云原生计算基金会已经认证了 90 个 Kubernetes 产品。认证产品包括来自 IBM、Canonical、SUSE、Mirantis、VMware、Rancher、Amazon、Microsoft 以及当然,Google 的发行版。
听到常见的抱怨说部署 Kubernetes “太难了”,大多数供应商解决方案使其变得更容易。虽然使安装更容易对于大多数企业来说是必要的步骤,并且可以腾出时间专注于更重要的事情,但它也导致了一个问题:不了解集群中包含的基本组件和资源。
使用不同的服务示例,假设您有一个需要新数据库的应用程序。您可能不知道如何创建新的数据库模式或 SQL 查询,但您知道 Google 提供了 MySQL,并为应用程序创建了一个新实例。MySQL 实例将自动创建,一旦部署,您就可以使用 GCP 控制台创建数据库。
由于您可能没有强大的 SQL 背景,您可能会在数据库中创建一个具有多个字段的单个表,这些字段将与应用程序一起工作。数据库可能在几天或几周内表现良好,但随着其变大,性能将开始变慢。虽然单个表数据库易于实现,但并不是一个优化的解决方案。如果您有 SQL 背景,您会创建一个具有多个表和关系的数据库,使数据库更高效和可扩展。
这种场景类似于理解 Kubernetes 的工作原理以及系统提供的功能。为了充分发挥 Kubernetes 的潜力,您应该了解其底层架构和每个组件的作用。了解组件如何相互集成以及可以使用哪些资源将帮助您在部署集群或部署应用程序时做出良好的架构决策。
涵盖每个集群组件和 Kubernetes 包含的超过 60 种资源类型的详细信息可以填满一系列书籍。由于本章中的许多主题引用了包括 Pods 和 DaemonSets 在内的资源,因此它将从一个 Kubernetes 资源口袋指南开始,提供最常用 API 资源的简要定义。
在本章中,我们将提供 Kubernetes 组件、资源和常用附加组件的背景信息,这些组件为 Anthos 提供计算能力。如果您对 Kubernetes 比较陌生,市场上许多书籍都解释了如何构建集群以及如何使用 kubectl,并专门用整章内容介绍每个 Kubernetes 资源。本章应被视为资源介绍,深入关注如何在集群中控制部署的位置。
3.1.1 技术要求
本章的实践部分将要求您能够访问在 GCP 上运行的 Kubernetes 集群,并采用以下部署模式:
-
集群必须在同一区域的至少两个不同的区域中部署。本章中展示的示例将基于 us-east4 区域的 us-east4-a、us-east4-b 和 us-east4-c 区域,但您可以使用不同的区域来部署您的集群。
-
每个区域必须至少包含一个 Kubernetes 节点。
本章内容不仅限于 GCP 上的 Kubernetes;练习中所使用的资源和结构适用于任何 Kubernetes 集群。
3.1.2 历史和概述
由于本书的读者可能对 Kubernetes 较新或是有经验的 Kubernetes 管理员,我们在在线附录 A 中添加了一些关于从物理服务器到容器的历史和进化的信息。
3.1.3 管理 Kubernetes 集群
当一家公司决定在云中运行 Kubernetes 集群时,他们通常会使用云提供商的本地产品,例如以下这些:
-
谷歌 Kubernetes 引擎(GKE):
cloud.google.com/kubernetes-engine/ -
亚马逊弹性 Kubernetes 服务(EKS):
aws.amazon.com/eks/ -
微软 Azure Kubernetes 服务(AKS):
mng.bz/GR7V
使用本地产品是获取新集群并快速运行的最快和最简单的方法,因为提供商已经自动化了安装。要从零开始到运行集群,您只需要提供一些信息,如节点数量和大小、区域和地区。有了这些信息和点击或 API 调用,您可以在几分钟内拥有一个集群,准备好部署您的应用程序。
Google 是第一个提供其 Kubernetes 解决方案的云服务提供商,该解决方案既适用于云环境也适用于本地环境,而不需要任何专门的硬件解决方案。在 Google 这样做之前,其他提供的产品要求组织为每个云提供商及其本地集群部署不同的解决方案。为多个安装使用不同的解决方案通常会导致各种不同的问题,包括以下这些:
-
增加人员以支持每个部署
-
本地和远程部署应用程序的差异
-
不同的身份管理解决方案
-
不同的 Kubernetes 版本
-
不同的安全模型
-
标准化集群操作的困难
-
没有所有集群的单个视图
这些差异使得运行 Kubernetes 的工作更加困难,最终对组织来说成本更高。
Google 认识到这些问题,并创建了 Anthos,它通过提供一种 Kubernetes 安装和管理解决方案来解决本地和远程挑战,该解决方案不仅适用于 GCP 和本地集群,还适用于运行 Anthos 的其他云提供商,如 AWS 和 Azure。
使用 Anthos 无论部署在哪里都提供统一的平台。想象一下,您有一个单一的支持路径和一套通用的工具,用于 GCP、AWS、Azure 和本地环境中的所有集群。Anthos 为组织提供了许多优势,包括以下这些:
-
在 Anthos 控制台中查看集群的统一视图
-
一个通用的服务网格提供
-
使用 ACM 进行配置管理
-
Google 支持的所有选项:所有集群组件的单一点联系
最好的是,Anthos 基于上游 Kubernetes,因此您获得所有标准功能,但还增加了 Anthos 提供的工具和组件,这使得多云集群管理更加容易。
接下来,我们将深入了解构成 Kubernetes 集群的架构以及组件之间是如何相互通信的。
3.2 Kubernetes 架构
任何基础设施一样,Kubernetes 由多个组件组成,这些组件通过通信来创建集群。这些组件被分为两层:控制平面和工作节点。控制平面负责保持集群状态,接受传入请求,调度工作负载,并运行控制器,而工作节点则与控制平面通信,以报告可用资源,运行容器工作负载,并维护节点网络规则。
如果你正在 GCP 上运行 Anthos,你可能不熟悉控制平面或工作节点的组件,因为你不会像在本地安装中那样与之交互。本节将解释,Kubernetes 集群有一个名为控制平面的层,其中包含运行 Kubernetes 所需的组件。当集群在 GCP 上运行时,控制平面是在一个 Google 管理的项目中创建的,这限制了你对管理节点和 Kubernetes 组件的交互。
所有 GKE 集群都可以在 GCP 控制台中查看,位于 Kubernetes 引擎部分。对于每个集群,你可以通过在详情面板中点击集群,然后选择节点来查看节点的详细信息。节点详细信息将显示,如图 3.1 所示。

图 3.1 GKE 节点详细信息
与 GCP 上的 GKE 不同,本地安装的 GKE 提供了对控制平面节点和集群 Kubernetes 资源的访问。当然,Google 仍然支持本地控制平面,但你可能需要检查组件以排查任何问题或对集群进行配置更改。如果你只在 GCP 上部署了 GKE,你可能不了解控制平面的所有组件以及它们是如何交互的。理解这种交互对于故障排除和找到任何问题的根本原因至关重要。
注意:当你在本地部署 GKE 集群时,会创建三个 Kubernetes 配置文件。其中一个将以用户集群的名称加上 -kubeconfig 后缀命名,一个是 kubeconfig,最后一个叫做 internal-cluster-kubeconfig-debug。kubeconfig 文件配置为针对管理集群的负载均衡地址,而 internal-cluster-kubeconfig-debug 则配置为直接针对管理集群的 API 服务器。
要查看多个配置文件,请参阅图 3.2。

图 3.2 管理集群和用户集群配置文件
在理解系统的重要性之后,让我们继续了解集群中的每一层,从控制平面开始。
3.2.1 理解集群层
第一层,控制平面,包含五个或六个组件(实际上,两个控制器实际上包含多个组件)。控制平面包括提供集群管理、集群状态和调度功能的组件。我们将在下一节中详细说明每个组件,但现在,我们只想介绍这里所示的控制平面组件:
-
ETCD
-
Kubernetes API 服务器
-
Kubernetes 调度器
-
包含多个控制器的 Kubernetes 控制器管理器
-
节点控制器
-
端点控制器
-
副本控制器
-
服务帐户/令牌控制器
-
-
包含多个控制器的云控制器管理器
-
路由控制器
-
服务控制器
-
节点控制器
-
要查看控制平面的图形表示,请参阅图 3.3。在本节结束时,我们将提供一个完整的组件图,包括每个组件的通信方式。

图 3.3 控制平面组件
集群的第二层是由工作节点组成的集合,它们负责运行集群工作负载。每个工作节点有三个组件协同工作以运行应用程序,如图 3.4 所示。

图 3.4 工作节点组件
到目前为止,我们还没有解释每个组件如何与其他组件交互。在我们展示集群交互的完整图之前,我们需要了解集群中的每个组件。在下一节中,我们将解释每个集群组件,并在本节结束时,我们将结合两个图来展示所有组件之间的连接性。
3.2.2 控制平面组件
如前所述,控制平面包括多达六个组件。每个组件协同工作以提供集群服务。理解每个组件是提供强大、稳定的集群的关键。
etcd
集群中的每个资源和其状态都维护在 etcd 键值数据库中。整个集群状态都存储在这个数据库中,使得 etcd 成为集群中最重要的组件。如果没有一个正常工作的 etcd 数据库,你就没有了一个正常工作的集群。
由于 etcd 非常重要,你应该在集群中始终至少运行三个副本。根据集群的大小,你可能想要运行超过三个,但无论你决定运行多少,总是运行奇数个副本。运行奇数个 etcd 节点允许集群选举一个多数领导者,最小化 etcd 集群进入脑裂状态的机会。如果一个集群进入脑裂状态,多个节点声称自己是多数领导者,这会导致数据不一致和损坏。如果你发现自己处于脑裂状态,你需要从 etcd 备份中重新创建 etcd 集群。
虽然运行多个副本会使 etcd 高可用,但您还需要创建数据库的常规备份,并将其存储在集群外的一个安全位置。如果您丢失整个集群或 etcd 数据库损坏,您将能够恢复备份以恢复节点或整个集群。我们将在本章后面解释备份 etcd 的过程。
在使 etcd 高可用并创建常规备份之后,对 etcd 的最后一个考虑因素是安全性。etcd 数据库包含每个 Kubernetes 资源,因此它将包含敏感数据,如机密,这些机密可能包含密码等数据。如果有人获得了您的 etcd 数据库副本,他们可以轻松地拉取任何资源,因为默认情况下,它们以明文形式存储。
覆盖 etcd 可能需要整整一章。有关 etcd 的更多信息,请访问主 etcd 网站 etcd.io/docs/。Google 还提供了备份 GKE 本地集群的步骤和脚本。您可以在 mng.bz/zm1r 找到文档和脚本。
Kubernetes API 服务器
API 服务器是集群的大门。所有进入集群的请求都通过 API 服务器进入,它将与其他组件交互以完成请求。这些请求来自 kubectl CLI、Kubernetes Dashboard 或直接 JSON API 调用的用户和服务。
这实际上是一个事件驱动的中心辐射模型。API 服务器封装了 etcd。所有其他组件都与 API 服务器通信。API 服务器不会直接响应请求与控制器通信。相反,控制器会监视相关的更改事件。
Kubernetes 调度器
如果 API 服务器收到创建 Pod 的请求,它将与 Kubernetes 调度器通信,调度器将决定哪个工作节点将运行工作负载。
当工作负载尝试请求无法满足的资源或具有无法匹配的约束时,它将无法调度,Pod 也不会启动。如果发生这种情况,您需要找出调度失败的原因,或者更改您的部署代码,或者向您的节点添加资源以满足请求。
Kubernetes 控制器管理器
控制器管理器通常被称为控制循环。为了使 Kubernetes 保持所有资源处于请求的、期望的状态,必须将每个资源的状态与其请求状态进行比较。实现这一过程的过程被称为控制循环。
Kubernetes 控制器管理器由一个二进制文件组成,该文件为每个“逻辑”控制器运行单独的线程。包含的控制器及其角色在表 3.1 中显示。
表 3.1 包含的控制器及其角色
| 控制器 | 描述 |
|---|---|
| 节点 | 维护所有节点的状态 |
| 复制 | 维护复制控制器的 Pod 数量 |
| 端点 | 维护 Pod 到服务的映射,为服务创建端点 |
| 服务账户/令牌 | 为命名空间创建初始默认账户和 API 令牌 |
从表中可以得出的主要概念是,通过使用控制循环,管理器不断检查其控制的资源(资源),以保持它们处于声明状态。
Kubernetes 控制器管理器处理内部 Kubernetes 资源状态。如果你使用云服务提供商,你的集群将需要一个控制器来维护某些资源,这就是云控制器管理器的角色。
云控制器管理器
注意:你可能在每个你交互的集群中都不会看到这个控制器。一个集群只有在配置了与云服务提供商接口的情况下才会运行云控制器。
为了给云服务提供商提供灵活性,云控制器管理器与标准的 Kubernetes 控制器管理器是分开的。通过解耦这两个控制器,每个云服务提供商都可以向其服务中添加可能与其他提供商或基础 Kubernetes 组件不同的功能。
与 Kubernetes 控制器管理器类似,云控制器管理器使用控制循环来维护资源的期望状态。它也是一个运行多个控制器及其进程的单个二进制文件,如表 3.2 所示。
表 3.2 云控制器管理器运行的控制器
| 控制器 | 描述 |
|---|---|
| 节点 | 创建节点资源并维护位于云服务提供商中的节点状态 |
| 路由 | 维护网络路由以提供节点通信 |
| 服务 | 维护云服务提供商组件,如负载均衡器、网络过滤和 IP 地址 |
最后,当我们说“云服务提供商”时,我们并不是指你仅限于使用公共云服务提供商。在撰写本文时,Kubernetes 支持以下云服务提供商:
-
Amazon AWS
-
Microsoft Azure
-
Google Cloud Platform (GCP)
-
OpenStack
-
华为
-
vSphere
现在已经解释了控制平面,让我们继续讨论工作节点组件。
3.2.3 工作节点组件
从高层次来看,你应该对控制平面中的组件有一个基本的了解。它是负责集群交互和工作负载部署的层。单独的控制平面不能做很多事情——它需要一个目标,一旦调度,就可以运行实际的工作负载,这就是工作节点的作用所在。
kubelet
kubelet 是负责运行 Pod 并向 Kubernetes 调度器报告节点状态的组件。当调度器决定哪个节点将运行工作负载时,kubelet 从 API 服务器检索它,并根据拉取的规范创建 Pod。
kube-proxy
我们将在下一节讨论服务时详细介绍这一点,但到目前为止,你只需要了解 kube-proxy 的基本概述。kube-proxy 负责创建和删除网络规则,这些规则允许 Pod 进行网络连接。如果主机操作系统提供了数据包过滤器,kube-proxy 将使用它;如果没有提供,流量将由 kube-proxy 本身管理。
根据你为集群选择的网络提供商,你可能可以选择在无 kube-proxy 模式下运行你的集群。像 Cilium 这样的容器网络接口(CNI)使用 eBPF 提供与 kube-proxy 相同的功能,但无需在基本 CNI 部署之外添加额外的组件。
容器运行时
容器运行时是负责在主机上运行实际容器的组件。人们通常将容器运行时简称为 Docker。这是可以理解的,因为 Docker 确实将容器普及开来,但多年来,其他替代方案也被开发出来。其中两种最受欢迎的替代方案是 CRI-O 和 containerd。
曾经,容器运行时被集成到 kubelet 中,这使得添加新的运行时变得困难。随着 Kubernetes 的成熟,团队开发了容器运行时接口(CRI),它提供了简单“插入”容器运行时的能力。无论使用哪种运行时,其责任都是相同的:在节点上运行实际的容器。
现在我们已经回顾了每一层及其组件,让我们展示这两层之间的连接以及组件如何交互,如图 3.5 所示。

图 3.5 集群组件通信
这就完成了关于 Kubernetes 集群组件的部分。了解组件如何交互将帮助你诊断问题,并理解集群作为一个系统如何交互。
根据你的角色,了解集群组件及其交互可能不如了解集群资源那么重要。Kubernetes 资源被每个与集群交互的用户使用,用户至少应该了解最常用的资源。作为参考,你可以在 Kubernetes 网站上阅读有关 Kubernetes 资源的信息,网址为 mng.bz/0yRm。
要在 Kubernetes 上有效地部署应用程序,你需要了解基础设施的功能,从 Kubernetes 对象开始。接下来,我们将继续探讨 DevOps 范式和 Kubernetes 集群组件。
3.2.4 理解声明性和命令性
在 DevOps 中,自动化框架可以使用两种不同的实现方法,被称为 DevOps 范式。它们包括声明性模型和命令性模型。
本章将解释每个范式,但在深入探讨它们之间的差异之前,你应该了解控制循环的概念。
理解控制循环
为了维持您期望的状态,Kubernetes 实现了一套控制循环。控制循环是一个无限循环,它始终检查资源的声明状态是否与其当前状态相同。
如果您声明部署应该有三个 Pod 副本,并且意外删除了一个 Pod,Kubernetes 将创建一个新的 Pod 以保持状态同步。图 3.6 显示了 ReplicaSet 控制循环的图形表示以及它如何维持期望的副本计数。

图 3.6 控制循环示例
如您所见,控制循环不需要复杂就能维持期望状态。副本控制器简单地循环遍历集群中所有的 ReplicaSet 资源,比较当前可用的 Pod 数量与声明的期望 Pod 数量。Kubernetes 将添加或删除 Pod,以使当前副本计数等于在部署上设置的计数。
理解 Anthos 的功能以及 Kubernetes 如何维护部署的声明状态对于任何 Kubernetes 用户来说都很重要,但这只是开始。因为许多供应商已经使得部署集群变得非常简单,开发人员和管理员往往忽略了理解整个系统的优势。如前所述,为了设计一个有效的集群或应用程序,您应该了解集群组件的基本功能。在下一节中,将介绍 Kubernetes 架构,包括控制平面和工作节点组件以及它们之间的交互方式。
需要理解的第一批概念之一是声明性模型和命令性模型之间的区别。表 3.3 提供了每个模型的简要描述。
表 3.3 声明性和命令性模型
| 模型 | 描述 |
|---|---|
| 声明性 | 开发者声明他们希望系统执行的操作;无需告诉系统如何执行。声明性模型使用 Kubernetes 清单来声明应用程序的期望状态。 |
| 命令性 | 开发者负责创建实现所需最终状态所需的每个步骤。创建部署的步骤完全由开发者定义。命令性模型使用 kubectl 命令(如 create、run 和 delete)告诉 API 服务器要管理哪些资源。 |
在声明性模型中,您可以在单个文件中管理多个资源。例如,如果我们想部署一个包含新命名空间、部署和服务的新 NGINX 网络服务器,我们将创建一个包含所有资源的单个 YAML 文件。然后,使用 kubectl apply 命令部署该清单,该命令将创建每个资源并添加一个包含最后应用的配置的注释。因为 Kubernetes 跟踪资源,并且您在单个文件中拥有所有资源,所以管理部署和资源的变化更容易。
在 imperative 模型中,你必须运行多个命令来创建你的最终部署。使用之前的示例,其中你想要部署一个 NGINX 服务器、一个服务和一个 Ingress 规则,你需要执行以下三个 kubectl 命令:
kubectl create ns web-example
kubectl run ngnix-web --image=nginx:v1 -n web-example
kubectl create service clusterip nginx-web -tcp=80:80
虽然这会完成与我们的声明式示例相同的部署,但它有一些限制,在简单的示例中并不立即明显。一个限制是 kubectl 命令不允许你为每个资源配置所有可用的选项。在示例中,我们部署了一个运行 NGINX 的 Pod。如果我们需要添加第二个容器来执行专门的任务,如日志记录,我们就无法通过 imperative 方式添加它,因为 kubectl 命令没有在 Pod 中启动两个容器的选项。
避免使用 imperative 部署是一个好习惯,除非你试图快速解决问题。如果你出于任何原因使用了 imperative 命令,你应该跟踪你的更改,以便你可以修改你的声明式清单,以保持它们与任何更改同步。
要理解 Kubernetes 如何使用声明式模型,你需要了解系统如何通过使用控制循环来维护声明状态与当前运行状态之间的同步,以对部署进行管理。
3.2.5 理解 Kubernetes 资源
在本书的整个过程中,你会看到对多个 Kubernetes 资源的引用。如本章前面所述,一个新集群包含 60 多种资源类型,不包括可能通过 CRDs(自定义资源定义)添加的任何自定义资源。有多个 Kubernetes 书籍可供选择,因此本章将只提供每个资源的简介,以提供在大多数章节中都将使用的基礎知识。
记住所有基本资源是有挑战性的,你可能并不总是有口袋指南可用。幸运的是,你可以使用一些命令来查找资源以及每个资源可用的选项。第一个命令,如下所示,列出了集群上可用的所有 API 资源:
kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
输出提供了资源的名称——如果可以在命名空间级别使用,任何简短名称——以及资源的类型。如果你知道每个资源的作用,但忘记了名称或是否可以在命名空间级别设置,这将很有帮助。如果你需要任何资源的额外信息,Kubernetes 提供了下一个命令,它为每个资源提供详细信息:
kubectl explain <resource name>
explain 命令提供了资源及其在清单中可用的所有字段的简要描述。例如,接下来你会看到一个关于 Pod 的简要描述以及创建资源时可以使用的一些字段:
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata <Object>
Standard object’s metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
如你所见,每个字段都有详细的解释和链接,当适用时提供额外的详细信息。
您可能无法始终访问安装了 kubectl 的系统,因此表 3.4 提供了大多数您将在集群中使用的常见资源的简要描述。
表 3.4 集群中使用的资源
| Kubernetes 资源 | 描述 |
|---|---|
| ConfigMaps | 存储 Pod 的配置数据。 |
| EndpointSlice | 一组用作服务目标的 Pod。 |
| Namespace | 用于在多个开发人员或应用程序之间划分集群。 |
| Node | 为 Kubernetes 集群提供计算能力。 |
| PersistentVolumeClaim | 允许应用程序声明持久卷。 |
| PersistentVolume | 在集群层配置的存储资源。PersistentVolumeClaim 请求由 PersistentVolume 提供。 |
| Pod | 一个容器或一组容器。 |
| ResourceQuota | 设置配额限制,按命名空间强制执行。 |
| Secret | 存储特定类型的秘密数据。数据字段中值的总字节数必须小于 MaxSecretSize 配置值。 |
| ServiceAccount | 提供一个身份,可以对其进行身份验证和授权以访问集群中的资源。 |
| Service | 提供一个名为抽象的软件服务,由代理监听的本地端口和确定哪些 Pod 将响应用户通过代理发送的请求的选择器组成。 |
| CustomResourceDefinition | 表示应该在 API 服务器上公开的资源。 |
| DaemonSet | 用于将容器部署到集群中的所有节点或节点子集。这包括在初始部署之后可能添加的任何新节点。 |
| Deployment | 允许对 Pod 和 ReplicaSet 进行声明性更新。 |
| ReplicaSet | 确保在任何给定时间都有指定数量的 Pod 副本正在运行。 |
| StatefulSet | StatefulSet 代表一组具有一致标识和控制 Pod 启动和停止的 Pod。 |
| Ingress | 一组规则,用于将入站连接定向到 Pod 端点。 |
| NetworkPolicy | 定义了一组 Pod 允许的网络流量。 |
| PodSecurityPolicy | 控制对影响 Pod 和容器将应用的安全上下文产生影响的能力的请求。 |
| ClusterRole | 集群级别的 PolicyRules 逻辑分组,可以作为一个单元由 RoleBinding 或 ClusterRoleBinding 引用。 |
| ClusterRoleBinding | 将 ClusterRole 中定义的权限分配给用户、组或服务账户。ClusterRoleBinding 的作用域是集群范围的。 |
| Role | PolicyRules 的逻辑分组,可以作为一个单元由 RoleBinding 引用。 |
| RoleBinding | 将 Role 中定义的权限分配给用户、组或服务账户。它可以引用同一命名空间中的 Role 或全局命名空间中的 ClusterRole。RoleBinding 的作用域仅限于其定义的命名空间。 |
| StorageClass | 描述可以动态预配 PersistentVolumes 的存储类别的参数。 |
了解可用的资源是创建最佳应用程序部署和帮助解决集群或部署问题的关键之一。如果没有对这些资源的了解,如果 Ingress 规则没有按预期工作,你可能不知道该查看什么。使用表中的资源,你可以找到三个对于 Ingress 规则所必需的资源。第一个是 Ingress 本身,第二个是服务,最后一个是端点/端点切片。
观察 Ingress 资源之间的流程,一个进入的请求会被 Ingress 控制器评估,并找到匹配的 Ingress 资源。Ingress 规则根据 Ingress 规则中定义的服务名称路由流量,最后请求被发送到由服务创建的端点对应的 Pod。
3.2.6 Kubernetes 资源深入探讨
如果你对资源已经有了一定的了解,对资源和它们用途的简要概述是一个很好的复习。我们意识到并非每位读者都有与 Kubernetes 资源互动多年的经验,因此在本节中,你将找到一些最常用集群资源的额外细节。
所有 GKE Kubernetes 集群共有的一个特点是,无论是在本地还是远程,它们都是基于上游 Kubernetes 代码构建的,并且它们都包含 Kubernetes 资源的基本集合。与这些基本类型交互是你可能每天都会做的事情,对每个组件、其功能和用例示例有深入理解是很重要的。
命名空间
命名空间为名称提供范围。资源名称需要在命名空间内是唯一的,但不能跨命名空间。
命名空间在集群中的租户之间创建逻辑分离,为集群提供多租户功能。根据 Gartner 的定义,“多租户是指软件操作的模式,其中一个或多个应用程序的多个独立实例在共享环境中运行。实例(租户)在逻辑上是隔离的,但在物理上是集成的” (mng.bz/Kl74)。
在命名空间级别创建的 Kubernetes 资源被称为 namespaced。如果你看到某个资源是 namespaced 的,这意味着该资源是在命名空间级别而不是集群级别进行管理的。
在命名空间中,你可以创建提供安全和资源限制的资源。为了提供一个安全的多租户集群,你可以使用以下类别的 Kubernetes 资源:
-
RBAC
-
资源配额
-
网络策略
-
命名空间安全资源(以前称为 Pod 安全策略)
我们将在本节中更详细地讨论每个资源,但就目前而言,你需要理解的是,命名空间是集群的逻辑分区。
当你创建服务时,也会使用命名空间,我们将在服务部分中介绍。服务被分配一个 DNS 名称,包括服务名称和命名空间。例如,如果你在名为 sales 的命名空间中创建名为 myweb1 和 myweb2 的两个服务,在一个名为 cluster.local 的集群中,分配的 DNS 名称如下:
-
myweb1.sales.svc.cluster.local
-
myweb2.sales.svc.cluster.local
Pods
Pod 是 Kubernetes 可以管理的最小部署单元,可能包含一个或多个容器。如果一个 Pod 运行多个容器,它们都共享一个公共的网络堆栈,允许每个容器使用 localhost 或 127.0.0.1 与 Pod 中的其他容器通信。它们还共享挂载到 Pod 的任何卷,允许每个容器访问共享的文件位置。
当 Pod 创建时,它会分配一个 IP 地址,分配的地址应被视为短暂的。你不应该针对 Pod 的 IP 地址,因为它在 Pod 被替换时可能会在某个时刻发生变化。要针对在 Pod 中运行的应用程序,你应该针对服务名称,这将使用端点将流量导向运行应用程序的正确 Pod。我们将在本节的相关主题中讨论端点和服务。
虽然没有关于单个 Pod 中应该有多少容器的标准,但最佳实践是添加应该一起调度和管理的容器。在决定将多个容器添加到 Pod 时,应考虑扩展和 Pod 重启等操作。这些事件在 Pod 级别处理,而不是在容器级别,因此这些操作将影响 Pod 中的所有容器。
示例
你创建一个包含 Web 服务器和数据库的 Pod。你决定你需要扩展 Web 服务器以处理当前的流量负载。当你扩展 Pod 时,它将扩展两者:Web 服务器和数据库服务器。
如果只想扩展 Web 服务器,你应该部署一个包含 Web 服务器的 Pod 和一个包含数据库服务器的第二个 Pod,这将允许你独立扩展每个应用程序。
许多设计模式在 Pod 中使用多个容器。Pod 中多个容器的常见用例被称为边车。边车是与 Pod 中的主容器一起运行的容器,通常用于在不修改主容器的情况下添加一些功能。以下是一些使用边车处理任务的常见示例:
-
日志记录
-
监控
-
Istio 边车
-
备份边车(即 Veritas NetBackup)
你可以在 Kubernetes 网站上查看其他示例,网址为mng.bz/91Ja。
理解 Pod 是理解 Kubernetes 部署的关键点。它们将成为你将与之交互的最常见资源。
标签和选择器
Kubernetes 使用标签来识别、组织和链接资源,允许你识别属性。当你创建 Kubernetes 中的资源时,你可以提供一个或多个键值对标签,如 app:frontend-webserver 或 lob=sales。
选择器用于引用一组资源,允许你选择你想要链接或选择的资源(资源集),使用分配的标签。你可以将选择器视为一种动态分组机制——任何匹配选择器的标签都将被添加为目标。这将在下一节中展示,该节将介绍使用选择器将服务链接到运行应用程序的 Pod 的服务资源。
服务
我们可以使用许多之前提到的资源来全面了解它们如何连接以创建一个应用程序。拼图中的最后一部分是服务资源,它将应用程序暴露出来,允许它使用定义的 DNS 名称接受请求。
记住,当你创建一个包含你的应用程序的 Pod 时,它会被分配一个 IP 地址。当 Pod 被替换时,这个 IP 地址将会改变,这就是为什么你永远不希望使用 IP 地址来配置连接到 Pod 的原因。
与本质上短暂的 Pod 不同,一旦创建,服务就是稳定的,很少被删除和重新创建,提供稳定的 IP 地址和 DNS 名称。即使服务被删除和重新创建,DNS 名称也将保持不变,提供一个稳定的名称,你可以将其作为目标来访问应用程序。在 Kubernetes 中,你可以创建几种服务类型,如表 3.5 所示。
表 3.5 Kubernetes 中的服务
| 服务名称 | 描述 | 网络范围 |
|---|---|---|
| 集群 IP | 在集群内部暴露服务。 | 通过使用入口规则内部和外部暴露 |
| 节点端口 | 在集群内部暴露服务。使用分配的节点端口向外部客户端暴露服务。使用任何工作节点 DNS/IP 地址与节点端口结合将提供对 Pod(s)的连接。 | 内部和外部 |
| 负载均衡器 | 在集群内部暴露服务。使用外部负载均衡器服务在集群外部暴露服务。 | 内部和外部 |
现在我们用一个例子来解释 Kubernetes 如何使用服务在一个名为 sales 的命名空间和一个名为 cluster.local 的集群中暴露一个应用程序:
-
为 NGINX 服务器创建了一个部署。
-
部署的名称是 nginx-frontend。
-
部署已被标记为 app: frontend-web。
-
已创建了三个副本。
三个运行中的 Pod 已经被分配了 IP 地址 192.10.1.105、192.10.3.107 和 192.10.4.108。
-
-
为了提供对服务器的访问,部署了一个名为 frontend-web 的新服务。在创建服务的清单中,使用了一个标签 选择器来选择任何匹配 app: frontend-web 的 Pod。
-
Kubernetes 将使用服务请求和选择器来创建匹配的端点。
因为选择器匹配了用于 NGINX 服务器的部署中使用的标签,Kubernetes 将创建一个链接到三个 Pod IP(192.10.1.105、192.10.3.107 和 192.10.4.108)的端点。
-
服务将从集群的 Service IP 池中接收一个 IP 地址,以及使用
. .svc. 创建的 DNS 名称。 因为应用名称是 nginx-frontend,DNS 名称将是 nginx-frontend.sales.svc.cluster.local。
如果任何 Pod IP 由于重启而更改,kube-controller-manager 将更新端点,为您提供稳定的端点访问 Pods,即使 Pod IP 地址发生变化。
EndpointSlices
EndpointSlices 将 Kubernetes 服务映射到运行应用程序的 Pod(s),通过服务选择器和具有匹配标签的 Pod(s)之间的匹配标签进行链接。图 3.7 展示了其图形表示。

图 3.7 Kubernetes 端点
在此图中,在命名空间中创建了一个名为 nginx-service 的服务。该服务使用 key app 的选择器,其值等于 nginx-frontend。使用选择器,Kubernetes 将在命名空间中查找任何匹配的标签,标签等于 app=nginx-frontend。该命名空间有三个正在运行的 Pod,其中两个 Pod 已标记为 app=nginx-frontend。因为选择器匹配,所有匹配的 Pod IP 地址都被添加到 EndpointSlices。
Annotations
Annotations 在第一眼看起来可能类似于选择器。它们是键值对,就像标签一样,但与标签不同,它们不是由选择器用来创建服务集合的。
您可以使用 annotations 在资源中创建记录,如 Git 分支信息、图像散列、支持联系人等。
ConfigMaps
ConfigMaps 用于存储非机密的应用信息,与容器镜像分离。虽然您可以直接在容器镜像中存储配置,但这会使您的部署变得过于僵化——任何配置更改都需要您创建新的镜像。这将导致维护多个镜像,每个配置一个。
更好的方法是将配置存储在 ConfigMap 中,当 Pod 启动时读取。根据应用需求,ConfigMaps 可以作为文件挂载到容器中,或作为环境变量。使用不同配置部署镜像只需要不同的 ConfigMap,而不是整个镜像构建。
例如,假设你有一个需要根据部署位置不同配置不同的 Web 服务器镜像。你希望在容器运行的位置无关的情况下在整个组织中使用相同的镜像。为了实现这一点,你创建了一个配置为使用 ConfigMap 进行 Web 服务器配置的 Web 容器镜像。通过使用外部配置,你通过允许容器之外进行配置,使你的镜像具有可移植性。
机密
机密就像 ConfigMap 一样,因为它们包含 Pod 将使用的外部信息。与 ConfigMap 不同,机密不是以明文形式存储的;它们是使用 Base64 编码存储的。
如果你之前使用过 Base64 编码,你可能认为它与明文没有太大区别,或者没有更安全——你是对的。Kubernetes 中的机密不使用 Base64 编码来隐藏机密;它们是 Base64 编码的,以便机密可以存储二进制信息。如果有人有权查看机密,解码信息是微不足道的。因此,建议你使用像 Vault 或 Google Secret Manager 这样的外部机密管理器来加密你的机密。
注意
你也可以在存储在 etcd 中的机密时对其进行加密,但这仅加密数据库中的值,而不是 Kubernetes。如果你启用此功能,你只保护了 etcd 数据库中的机密。为了保护你的机密,你应该使用两种加密方法,因为这将保护你在集群和 etcd 中的机密。
etcd 在第 3.2.2 节“控制平面组件”中进行了讨论。
资源配额
记住,命名空间用于为应用程序或团队提供逻辑分离。因为集群可能被多个应用程序共享,我们需要有一种方法来控制单个命名空间可能对其他集群资源产生的影响。幸运的是,Kubernetes 包括资源配额来提供资源控制。
可以在任何命名空间的标准 Kubernetes 资源上设置配额;因此,资源配额是在命名空间级别设置的,并控制命名空间可以消耗的资源,包括以下内容:
-
CPU
-
内存
-
存储
-
Pods
-
服务
配额允许你控制命名空间可以消耗的资源,允许你与多个命名空间共享集群,同时为集群资源提供“保证”。
RBAC
基于角色的访问控制(RBAC)用于控制用户在集群内可以执行的操作。角色被创建并分配权限,然后这些权限被分配给用户或组,从而为集群提供权限。
为了提供基于角色的访问控制(RBAC),Kubernetes 使用角色和绑定资源。角色用于为资源或资源集创建一组权限,而绑定用于将权限集分配给用户或服务。
角色和集群角色
角色为资源或资源集创建一组权限。Kubernetes 中使用了两种不同类型的角色来定义权限的范围,如表 3.6 所示。
表 3.6 Kubernetes 中使用的角色
| 角色类型 | 范围 | 描述 |
|---|---|---|
| 角色 | 命名空间 | 角色中的权限只能在创建它的命名空间中使用。 |
| 集群角色 | 集群 | 集群角色中的权限可以在集群范围内使用。 |
对于 Kubernetes 新手来说,角色的范围可能会令人困惑。Role 资源比 ClusterRole 资源更直接。当您创建一个 Role 时,它必须包含一个命名空间值,这将在指定的命名空间中创建角色。因为角色仅存在于命名空间中,所以它只能用于在自身命名空间中分配权限——它不能用于集群中的其他任何地方。
ClusterRole 在集群级别创建,可以在集群的任何地方用于分配权限。当分配到集群级别时,ClusterRole 中授予的权限将被分配给集群中所有定义的资源。然而,如果您在命名空间级别使用 ClusterRole,权限将仅在指定的命名空间中可用。
两个最常见的 ClusterRole 是内置的 admin 和 view。Role 和 ClusterRole 本身并不将一组权限分配给任何用户。要将 Role 分配给用户,您需要使用 RoleBinding 或 ClusterRoleBinding 绑定 Role。
角色绑定和集群角色绑定
角色仅定义了允许资源使用的权限集;它们不会将授予的权限分配给任何用户或服务。要授予角色中定义的权限,您需要创建一个绑定。
与角色和 ClusterRole 类似,绑定有两个范围,如表 3.7 中所述。
表 3.7 绑定类型及其范围
| 绑定类型 | 范围 | 描述 |
|---|---|---|
| 角色绑定 | 命名空间 | 可以用于仅在其创建的命名空间中分配权限 |
| 集群角色绑定 | 集群 | 可以用于在集群范围内分配权限 |
既然我们已经讨论了 Kubernetes 资源,让我们继续讨论如何控制 Pod 将被调度到何处运行。
3.2.7 控制 Pod 调度
在本节中,我们将解释如何使用节点标签、亲和/反亲和规则、选择器、污点和容忍等特性来控制工作负载放置的位置。
随着 Kubernetes 的流行,用例已经增长并变得更加复杂。您可能会遇到需要特殊调度的部署,如下所示:
-
需要 GPU 或其他专用硬件的 Pod
-
强制 Pod 在同一个节点上运行
-
强制 Pod 在不同的节点上运行
-
特定的本地存储需求
-
使用本地安装的 NVMe 驱动器
如果你只是将清单部署到你的集群中,调度器在选择节点时不会考虑任何“特殊”的考虑因素。如果你部署了一个需要 CUDA 的 Pod,并且 Pod 被调度到一个没有 GPU 的节点上,应用程序将无法启动,因为所需的硬件将不可用给应用程序。
Kubernetes 提供了使用在节点级别和你的部署中设置的先进调度选项来强制 Pod 在特定节点或节点集上运行的能力。在节点级别,我们使用节点标签和节点污点来分组节点,在部署级别,我们使用节点选择器、亲和力/反亲和力规则以及污点/容忍度来决定 Pod 的放置。
使用节点标签和污点
在节点级别,你可以使用两种方法来控制将在节点或节点上调度的 Pod。第一种方法是标记节点,第二种是污点节点。尽管这两种方法都允许你控制 Pod 是否将在节点上调度,但它们有不同的使用场景——要么吸引 Pod,要么排斥 Pod。
吸引与排斥
你可以使用标签来分组你部署中要针对的一组节点,强制 Pod 在这些特定的节点上运行。当你标记一个节点时,你并没有拒绝任何工作负载。标签是一个可选值,如果部署中设置了使用标签的值,则可以由部署使用。这样,你为可能需要标签提供的某些要求的 Pod 设置了一个吸引力,例如,gpu=true。
要使用 kubectl 标记节点,你使用以下标签选项:
kubectl label nodes node1 gpu=true
如果一个部署需要 GPU,它将使用一个选择器告诉调度器它需要在具有标签 gpu=true 的节点上调度。调度器将寻找具有匹配标签的节点,然后将 Pod 调度到具有匹配标签的节点之一上。如果找不到匹配的标签,Pod 将无法被调度,并且不会启动。
使用标签是完全可选的。使用之前的示例标签,如果你创建的部署没有选择 gpu=true 标签,你的 Pod 不会被排除在包含该标签的节点之外。
污点(Taints)的工作方式不同:而不是创建一个邀请 Pod 在其上运行的键值,你使用污点来排斥任何无法容忍污点设置的值的调度请求。要创建一个污点,你需要提供一个键值和一个效果,这控制着 Pod 是否被调度。例如,如果你想控制具有 GPU 的节点,你可以使用 kubectl 在节点上设置一个污点,如下所示:
kubectl taint nodes node1 gpu=true:NoSchedule
这将使用键值对 gpu=true 和效果 NoSchedule 污点节点 1,这告诉调度器排斥所有不包含对 gpu=true 的容忍的调度请求。与标签不同,标签会允许未指定标签的 Pods 被调度,而具有 NoSchedule 效果的污点设置将拒绝任何不“容忍”gpu=true 的 Pod 被调度。
污点(Taints)有三个可以设置的效果:NoSchedule、PreferNoSchedule 和 NoExecute。每个效果都设置了对污点如何应用的控制:
-
NoSchedule—这是一个“硬”设置,将拒绝任何不耐受污点的调度请求。
-
PreferNoSchedule—这是一个“软”设置,将尝试避免调度一个不耐受污点的 Pod。
-
NoExecute—这影响节点上已经运行的 Pods;它不用于调度 Pod。
现在我们已经解释了如何在节点上创建标签和污点,我们需要了解部署是如何配置来控制 Pod 放置的。
使用节点选择器
当创建 Pod 时,你可以在你的清单中添加节点选择器来控制 Pod 将被调度到的节点。通过使用分配给节点的任何标签,你可以强制调度器在某个节点或一组节点上调度 Pod。
你可能不知道集群上所有可用的标签。如果你有权限,可以使用 kubectl 通过带有 —show-labels 选项的 get nodes 命令来获取节点和所有标签的列表,如下所示:
kubectl get nodes --show-labels
这将列出每个节点及其分配的标签,如下所示:

你还可以在 GCP 控制台中看到节点标签,如图 3.8 所示,通过点击节点的详细信息。

图 3.8 GCP 节点控制台视图
在镜像中使用集群中的标签,我们可以创建一个清单,通过使用节点选择器在第三个节点上部署 NGINX,如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
Labels:
run: nginx-test
name: nginx-test
spec:
replicas: 1
selector:
matchLabels:
run: nginx-test
template:
metadata:
creationTimestamp: null
labels:
run: nginx-test
spec:
containers:
- image: bitnami/nginx
name: nginx-test
nodeSelector:
kubernetes.io/hostname: gke-cluster-1-default-pool-ead436da-8j7k
使用节点选择器中的值 kubernetes.io/hostname:gke-cluster-1-default-pool-ead436da-8j7k,我们强制 Pod 在集群的第三个节点上运行。为了验证 Pod 是否在正确的节点上调度,我们可以使用 kubectl 使用 -o wide 选项获取 Pods,如下所示,如图 3.9 所示:
kubectl get pods -o wide

图 3.9 获取具有宽输出的 Pods
节点选择器选项允许你使用任何标签来控制将用于调度你的 Pods 的节点。如果节点选择器值与任何节点不匹配,Pod 将无法调度,并将保持挂起状态,直到它被删除或在节点上更新匹配选择器的标签。在下一个示例中,如图 3.10 所示,我们尝试将部署强制到具有集群中不存在的主机值的节点选择器。首先,我们可以使用 kubectl get pods 查看所有 Pods 的状态来检查状态。

图 3.10 get pods 输出
注意,nginx-test2 Pod 处于挂起状态。检查 Pod 为什么无法启动的下一步是描述 Pod:
kubectl describe pod nginx-test2-6dccc98749-xng5h
将显示 Pod 的描述,如图 3.11 所示,包括输出底部的当前状态。

图 3.11 kubectl describe 输出
在消息区域,状态显示 0/3 个节点可用:3 个节点未匹配节点选择器。因为我们的节点选择器没有匹配任何现有标签,Pod 无法启动。要解决这个问题,您应验证节点选择器是否正确,如果正确,请验证是否有节点具有相同的标签集。
使用亲和规则
节点亲和性是控制 Pod 在哪个节点上运行的另一种方式。与节点选择器不同,亲和规则可以执行以下操作:
-
包含比简单的匹配标签更复杂的语法。
-
根据亲和规则匹配进行调度,但如果找不到匹配项,Pod 将在任何节点上调度。
与只有一个值的节点选择器不同,节点亲和规则可以包含操作符,允许进行更复杂的选择。表 3.8 包含操作符列表及其评估描述。
表 3.8 操作符及其描述
| 操作符 | 描述 |
|---|---|
| In | 检查标签是否在列表中。如果列表中有任何值,则视为匹配。 |
| NotIn | 检查标签是否在列表中,如果值不在列表中,则视为匹配。 |
| Exists | 检查标签是否存在;如果存在,则视为匹配。注意:标签的值无关紧要,且在匹配中不进行评估。 |
| DoesNotExist | 检查标签是否存在;如果标签与列表中的任何标签不匹配,则视为匹配。注意:标签的值无关紧要,且在匹配中不进行评估。 |
| Gt | 用于比较标签中的数值;如果值大于(Gt)标签,则视为匹配。注意:此操作符仅与单个数字一起使用。 |
| Lt | 用于比较标签中的数值;如果值小于(Lt)标签,则视为匹配。注意:此操作符仅与单个数字一起使用。 |
使用节点亲和规则,您可以根据需求选择软亲和性或硬亲和性。您可以使用两个偏好创建亲和规则:RequiredDuringSchedulingIgnoredDuringExecution,也称为硬亲和性,和 preferredDuringSchedulingIgnoredDuringExecution,也称为软亲和性。如果您使用硬亲和性,亲和性必须匹配,否则 Pod 将无法调度。但是,如果您使用软亲和性,如果匹配,则将使用亲和规则。如果没有找到匹配项,Pod 将在集群中的任何节点上调度。
创建节点亲和规则
节点亲和性在 PodSpec 中的 manifest 中设置,在亲和性字段下,作为 nodeAffinity。为了更好地解释如何使用节点亲和规则,让我们使用一个示例集群创建一个使用亲和规则的 manifest。
该集群有三个节点,如表 3.9 所示。在规则中我们将使用的标签将以粗体显示。
表 3.9 集群中的节点
| 节点 | 节点标签 |
|---|---|
| 节点 1 | beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=e2-medium,beta.kubernetes.io/os=linux,cloud.google.com/gke-nodepool=default-pool,cloud.google.com/gke-os-distribution=cos,cloud.google.com/gke-preemptible=true,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/arch=amd64,kubernetes.io/hostname=gke-cluster-1-default-pool-77fd9484-7fd6,kubernetes.io/os=linux |
| 节点 2 | beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=e2-medium,beta.kubernetes.io/os=linux,cloud.google.com/gke-nodepool=default-pool,cloud.google.com/gke-os-distribution=cos,cloud.google.com/gke-preemptible=true,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/arch=amd64,kubernetes.io/hostname=gke-cluster-1-default-pool-ca0442ad-hqk5,kubernetes.io/os=linux |
| 节点 3 | beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=e2-medium,beta.kubernetes.io/os=linux,cloud.google.com/gke-nodepool=default-pool,cloud.google.com/gke-os-distribution=cos,cloud.google.com/gke-preemptible=true,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-c,kubernetes.io/arch=amd64,kubernetes.io/hostname=gke-cluster-1-default-pool-ead436da-8j7k,kubernetes.io/os=linux |
我们希望创建一个部署,在 us-central1-a 或 us-central1-c 区域中创建一个 NGINX 服务器。使用以下清单,我们可以使用基于 failure-domain.beta.kubernetes.io/zone 键的亲和力规则在任一区域创建 Pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: failure-domain.beta.kubernetes.io/zone
operator: In
values:
- us-central1-a
- us-central1-c
containers:
- name: nginx-affinity
image: bitnami/nginx
通过在 matchExpressions 中使用键 failure-domain.beta.kubernetes.io/zone,我们设置亲和力评估为 true,如果节点标签匹配 us-central1-a 或 us-central1-c。因为集群中的第二个节点具有标签值 us-central2-b,它将评估为 false,并且不会被选中来运行 Pod。
使用 Pod 亲和力和反亲和力规则
Pod 亲和力规则将确保已部署的 Pod 在具有匹配标签的同一组节点上运行,而反亲和力规则用于确保 Pod 不会在具有匹配标签的同一节点上运行。Pod 亲和力规则用于与节点亲和力规则不同的用例。节点亲和力允许您根据集群节点标签选择节点,而 Pod 亲和力和反亲和力规则使用已在集群中运行的 Pod 的标签。
创建 Pod 亲和力规则
当你创建一个亲和规则时,你是在告诉调度器将你的 Pod 放置在具有与亲和规则中选定的值匹配的现有 Pod 的节点上。Pod 亲和规则,就像节点亲和规则一样,可以创建为软亲和规则或硬亲和规则。它们也使用与节点亲和规则相同的运算符,包括 In、NotIn、Exists和 DoesNotExist,但它们不支持*Gt 或 Lt 运算符。
Pod 亲和规则在 PodSpec 中的亲和性和 podAffinity 字段中指定。它们需要一个节点亲和规则不使用的额外参数——topologyKey。topologyKey 被 Kubernetes 用来创建一个将用于检查亲和规则的节点列表。使用 topologyKey,你可以决定根据不同的过滤器(如区域或节点)来查找匹配项。
例如,假设你有一个按节点许可的软件包,每次运行软件一部分的 Pod 运行在另一个节点上时,你需要购买额外的许可证。为了降低成本,你决定创建一个亲和规则,强制 Pod 在现有已许可的 Pod 运行的地方运行。现有的 Pod 使用名为 license 的标签,其值为 widgets。以下是一个示例清单,它创建了一个在具有标签 license=widgets 的现有 Pod 的节点上的 Pod。由于我们需要在同一节点上运行以维护许可,我们将使用一个按 kubernetes.io/hostname 过滤的 topologyKey:
apiVersion: v1
kind: Pod
metadata:
name: widgets-license-example
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: license
operator: In
values:
- widgets
topologyKey: kubernetes.io/hostname
containers:
- name: nginx-widgets
image: nginx-widgets
清单告诉 Kubernetes 创建名为 nginx-widgets 的 Pod,在已经运行使用标签 license 且值为 widgets 的 Pod 的主机上运行名为 nginx-widgets 的镜像。
创建 Pod 反亲和规则
反亲和规则与亲和规则相反。亲和规则根据一组规则对 Pod 进行分组,而反亲和规则用于在不同的节点上运行 Pod。当你使用反亲和规则时,你是在告诉 Kubernetes 你不希望Pod 运行在另一个节点上,该节点上已经运行了一个具有规则中声明的值的现有 Pod。使用反亲和规则的一些常见用例包括强制 Pod 避免其他正在运行的 Pod 或跨可用区域分散 Pod。
Pod 反亲和规则在 PodSpec 中的亲和性和 podAntiAffinity 字段中指定。它们也需要 topologyKey 参数来过滤将用于比较亲和规则的节点列表。
在我们的亲和示例中,我们使用了一个使用节点主机名的 topologyKey。如果我们为部署使用相同的键,则不会考虑区域;它只会避免将 Pod 放置在另一个正在运行的 Pod 所在的同一节点上。尽管 Pod 会分散到各个节点,但选定的节点可能都在同一区域,这将无法跨区域分散 Pod。
为了将 Pod 分散到不同的区域,我们将使用标签 failure-domain.beta.kubernetes.io/zone,并且我们将使用操作符 In 来比较标签 app 的值为 nginx-frontend,如以下代码片段所示。我们还将使用软反亲和规则,而不是硬规则,允许 Kubernetes 在没有其他选择的情况下使用相同的区域:
apiVersion: v1
kind: Pod
metadata:
name: nginx-frontend-antiaffinity-example
spec:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx-frontend
topologyKey: failure-domain.beta.kubernetes.io/zone
containers:
- name: nginx-frontned
image: bitnami/nginx
通过使用 failure-domain.beta.kubernetes.io/zone 作为拓扑键,我们告诉 Kubernetes 我们希望避免将任何具有 app=nginx-frontend 标签的 Pod 放置在同一个区域。
使用污染和容忍度
虽然你可能更可能需要将 Pod 调度到特定的节点,但存在一些用例,你可能希望只为特定的工作负载保留特定的节点,从而基本上禁用默认调度。与 nodeSelector 和亲和规则不同,污染用于自动排斥,而不是吸引,Pod 到节点。当你想要节点默认拒绝任何调度尝试,除非部署明确指定了要在节点上调度的正确“容忍度”时,这很有用。例如,想象你有一个包含数百个节点和几个具有 GPU 可用性的节点的集群。因为 GPU 很昂贵,我们希望限制这些节点上的 Pod 只用于需要 GPU 的应用程序,拒绝任何标准调度请求。
使用如 nodeSelector 或亲和规则之类的控制项不会告诉 Kubernetes 调度器避免使用某个节点。这些提供了开发者控制 Pod 部署方式的能力,如果它们不提供这些中的任何一个,调度器将尝试使用集群中的任何节点。因为 GPU 很昂贵,我们希望拒绝任何在不需要使用 GPU 的节点上运行 Pod 的调度尝试。
创建节点污染
要停止调度器在节点上调度 Pod,你需要使用带有 taint 命令的 kubectl 和要污染的节点、键值以及效果。键值可以是任何你想要分配的值,效果可以是以下三个值之一:NoSchedule、PreferNoSchedule 或 NoExecute,如表 3.10中所述。
表 3.10 污染效果
| Effect | 描述 |
|---|---|
| NoSchedule | 如果 Pod 没有指定与节点污染匹配的容忍度,它将不会被调度到该节点上。 |
| PreferNoSchedule | 如果 Pod 没有指定与节点污染匹配的容忍度,调度器将尝试避免在节点上调度 Pod。 |
| NoExecute | 如果 Pod 已经在节点上运行并且添加了污染,如果 Pod 不匹配污染,它将被从节点上驱逐。 |
例如,如果我们有一个名为 node1 的节点上有一个 GPU,我们可以使用以下命令来污染该节点:
kubectl taint nodes node1 gpu=:NoSchedule
污点命令中的键告诉调度器必须匹配什么污点才能允许 Pod 在节点上调度。如果 Pod 请求没有使用容忍匹配污点,则基于 NoSchedule 的效果,调度器不会在节点上调度 Pod。
创建具有容忍的 Pod
默认情况下,一旦节点设置了污点,调度器将不会尝试在该受污节点上运行任何 Pod。按设计,您设置污点是为了告诉调度器避免在任何调度中使用该节点,除非部署明确请求在该节点上运行。要允许 Pod 在已设置污点的节点上运行,您需要在部署中提供一个容忍。容忍用于告诉调度器 Pod 可以“容忍”节点上的污点,这将允许调度器使用与容忍匹配并分配了污点的节点。
注意污点不会吸引 Pod 请求——它们只会拒绝任何没有设置容忍的 Pod。因此,要将 Pod 引导到具有污点的节点上运行,您需要设置一个容忍和一个节点选择,或者节点亲和性。选择器将告诉调度器使用具有匹配标签的节点,然后容忍告诉调度器 Pod 可以容忍节点上设置的污点。因为容忍告诉调度器“偏好”具有匹配污点的节点,如果找不到这样的节点,调度器将使用集群中具有匹配标签的任何节点。
关键要点容忍和节点选择器/亲和规则协同工作,以选择 Pod 将要运行的节点。
通过在您的清单的 pod.spec 部分分配一个或多个包含要匹配的键、操作符、可选值和污点效果的容忍来创建容忍。
该键必须分配给与您想要在节点上调度 Pod 的节点匹配的键。操作值告诉调度器简单地查找键(存在)或匹配键值(等于)。如果您使用等于操作符,您的容忍必须包含一个值字段。最后,必须匹配效果,Pod 才能在节点上调度。
要调度一个可以容忍 node1 的 GPU 污点的 Pod,您需要在 PodSpec 中添加以下内容:
spec:
tolerations:
- key: "gpu"
operator: "Exists"
effect: "NoSchedule"
添加容忍告诉调度器 Pod 应该被分配到具有 gpu 污点键和 NoSchedule 效果的节点。
控制 Pod 的调度位置是确保您的应用程序部署能够满足分配的 SLA/SLO 目标的关键点。
3.3 进阶主题
本节包含了一些我们希望在章节中包含的进阶主题。我们认为这些主题很重要,但它们不是理解章节主要主题所必需的。
3.3.1 聚合 ClusterRoles
当向集群添加新组件时,通常会创建一个新的 ClusterRole,并将其分配给用户以管理该服务。有时可能会创建一个角色,并且你可能注意到被分配了 ClusterRole 的 admin 用户默认具有对新组件的权限。在其他时候,你可能注意到新添加的组件,如 Istio,不允许内置的 admin 角色使用任何 Istio 资源。
看起来像 admin 这样的角色默认没有权限访问每个资源可能听起来有些奇怪。Kubernetes 包含两个 ClusterRoles,它们提供某种形式的 admin 访问权限:admin ClusterRole 和 cluster-admin ClusterRole。它们可能听起来很相似,但分配给它们的权限方式非常不同。
cluster-admin 角色很简单——它为所有权限分配了通配符,提供对每个资源的访问权限,包括新资源。admin 角色没有分配通配符权限。分配给 admin 角色的每个权限通常都是明确分配的。因为该角色不使用通配符,所以任何新的权限都需要为新资源分配。
为了使这个过程更容易,Kubernetes 有一个称为聚合 ClusterRoles 的概念。当创建一个新的 ClusterRole 时,可以通过分配一个 aggregationRule 来将其聚合到任何其他 ClusterRole。以下是一个帮助解释聚合如何工作的示例。默认的 admin ClusterRole 看起来与下一个示例类似:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin
...
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.k8s.io/aggregate-to-admin: "true"
在这个代码片段中,你可以看到 admin ClusterRole 有一个包含 rbac.authorization.k8s.io/aggregate-to-admin: 'true' 的 aggregationRule。当创建一个新的 ClusterRole 时,如果它使用相同的聚合规则,它可以自动与内置的 admin ClusterRole 聚合。例如,已经部署到集群中的新 CRD 创建了一个新的 ClusterRole。因为新 ClusterRole 的权限应该分配给管理员,所以它已经创建了一个与 rbac.authorization.k8s.io/aggregate-to-admin: "true" 匹配的聚合规则,如下所示:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: aggregate-example-admin
labels:
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rules:
- apiGroups: ["newapi"]
resources: ["newresource"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
这将创建一个名为 aggregated-example-admin 的新 ClusterRole,将 get、list、watch、create、patch 和 delete 等操作分配给 newapi apiGroup 中的资源 newresource。这个新的 ClusterRole 可以绑定到任何你想分配权限的用户,但由于权限是管理员所需的,它还分配了一个标签 rbac.authorization.k8s.io/aggregate-to-admin: "true",这与在 admin ClusterRole 中分配的聚合规则相匹配。标签匹配,因此 API 服务器上的控制器会注意到匹配的标签,并将新 ClusterRole 的权限与 admin ClusterRole 合并。
3.3.2 自定义调度器
在 Kubernetes 中,最被误解的概念之一是集群如何调度工作负载。你经常会听到在 Kubernetes 集群上部署的应用程序具有高可用性,当正确部署时,它们确实是。为了部署高可用性应用程序,了解 kube-scheduler 如何做出决策以及你的部署可以影响其决策的选项是有益的。
默认的 Kubernetes 调度器,kube-scheduler,负责根据一系列标准将 Pod 调度到工作节点,包括节点亲和性、污点和容忍度以及节点选择器。尽管 Kubernetes 包含了基础调度器,但你并不局限于只使用单个调度器来处理所有部署。如果你需要基础调度器不包括的特殊调度考虑因素,你可以通过在清单中指定调度器来创建自定义调度器,如果没有提供,则将使用默认调度器。创建自定义调度器超出了本书的范围,但你可以在 Kubernetes 网站上了解更多关于自定义调度器的信息:mng.bz/jm9y。
以下是一个将调度器设置为名为 custom-scheduler1 的自定义调度器的 Pod 的例子:
apiVersion: v1
kind: Pod
metadata:
name: nginx-web
spec:
containers:
- name: nginx
image: bitnami/nginx
schedulerName: custom-scheduler1
Kubernetes 调度器监视 API 服务器以查找需要调度的 Pod。一旦确定一个 Pod 需要被调度,它将通过一个多阶段决策过程来确定最合适的节点,这个过程将过滤掉节点,然后对未被过滤掉的节点进行评分。
3.4 例子和案例研究
使用本章的知识,解决接下来案例研究中提出的每个要求。记住,如果你在不同地区部署了你的 GKE 集群,请将练习中的示例区域替换为你的区域。为了节省任何潜在的成本,示例只需要每个区域一个节点。
3.4.1 FooWidgets Industries
你被要求协助 FooWidgets Industries 处理他们新部署的 GKE 集群。他们很快发现他们没有内部技能来完成部署,因此集群的当前状态是在三个 GCP 区域中的简单、新的集群。
集群概述和需求
FooWidgets Industries 有一个部署在三个区域(us-east4-a、us-east4-b 和 us-east4-c)的 GKE 集群。公司根据内部标准和专用硬件使用有不同的 Pod 放置要求。他们包括了期望的工作负载放置和应分配给节点的标签的分解,如表 3.11 所示。
表 3.11 工作负载放置
| 区域 | 所需工作负载 | 标签/污点 | 节点名称 |
|---|---|---|---|
| us-east4-a | 任何工作负载 | disk=fast | gke-cls1-pool1-1d704097-4361 |
| us-east4-b | 仅需要 GPU 的工作负载 | workload=gpu | gke-cls1-pool1-52bcec35-tf0q |
| us-east4-c | 任何工作负载 | gke-cls1-pool1-e327d1de-6ts3 |
工作说明书要求你在表中提供需求。集群尚未配置到初始部署阶段,需要你完成以下配置:
-
创建任何节点标签或污点,以根据表中记录的支持工作负载实现工作负载放置。
-
创建一个使用 NGINX 镜像的示例部署,以演示根据 FooWidgets Industries 提供的需求成功放置工作负载。
下一个部分包含解决 FooWidgets 需求的方案。你可以跟随方案进行操作,或者如果你感到舒适,配置你的集群以满足需求并使用方案来验证你的结果。
FooWidgets Industries 解决方案:标签和污点
第一项要求是创建可能需要的任何标签或污点。使用需求表,我们可以得知我们需要在 us-east4-a 中的节点上添加 disk=fast 的标签。这个标签将允许部署强制在具有所需快速磁盘的应用程序节点上进行调度。第二项要求是将 us-east4-b 区域中运行的任何工作负载限制为仅需要 GPU 的应用程序。对于这个要求,我们决定将 us-east4-b 区域中的所有节点污点化为 workload=gpu。
为什么一个解决方案使用标签,而另一个使用污点?你可能还记得,标签和污点用于完成不同的调度需求:我们使用标签来吸引工作负载,而使用污点来排斥它们。在需求中,FooWidgets 明确指出 us-east4-a 和 us-east4-c 可以运行任何类型的工作负载,但 us-east4-b 必须仅运行需要 GPU 的工作负载。如果创建了一个没有在节点上指定标签的部署,调度器仍然会考虑该节点作为潜在的调度节点。标签用于强制部署到特定的节点,但它们不会拒绝不包含标签请求的工作负载。这种行为与被分配了污点的节点大不相同。当一个节点被污点化时,它会排斥任何不包含分配节点污点容忍的工作负载。如果一个部署没有为节点污点指定任何容忍,调度器将自动排除污点节点进行工作负载调度。
创建标签和污点
我们需要在 us-east4-a 中的节点上添加 disk=fast 的标签。为了添加标签,我们使用 kubectl label 命令,提供节点和标签:
kubectl label node gke-cls1-pool1-1d704097-4361 disk=fast
接下来,我们需要在 us-east4-b 区域的节点上添加 workload=gpu 的污点。记住,污点会排斥任何不能容忍分配节点污点的请求,但它不会吸引工作负载。这意味着你还需要添加一个标签来引导 GPU Pods 到正确的节点。为了污点节点,我们使用 kubectl taint 命令,提供节点名称和污点:
kubectl taint node gke-cls1-pool1-52bcec35-tf0q workload=gpu:NoSchedule
然后,为节点添加标签以吸引 GPU Pods:
kubectl label node gke-cls1-pool1-52bcec35-tf0q workload=gpu
注意,我们没有在 us-east4-c 区域的节点上添加标签或污点,因为该区域可以运行任何工作负载。
现在节点已标记,您需要创建示例部署以验证工作负载放置是否符合表格中的要求。
创建需要快速磁盘访问的部署
要将需要快速磁盘访问的部署强制到 us-east4-a 区域,您需要在部署中添加一个 nodeSelector。以下代码片段创建了一个包含使用标签 disk=fast 的 nodeSelector 的 NGINX 服务器,强制工作负载在 us-east4-a 区域的节点上运行:
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx-fast
name: nginx-fast
spec:
containers:
- image: nginx
name: nginx-fast
restartPolicy: Always
nodeSelector:
disk: fast
当您创建并执行清单时,nodeSelector 会告诉调度器使用带有标签 disk:fast 的节点。为了验证选择器是否正常工作,我们可以使用 -o wide 列出 Pods,以列出 Pod 运行的节点。在 us-east4-a 中,我们有一个单独的节点,gke-cls1-pool1-1d704097-436。kubectl get pods 的缩略输出确认 Pod 已正确调度:
NAME READY STATUS AGE IP NODE
nginx-fast 1/1 Running 4m49s 10.8.0.4 gke-cls1-pool1-1d704097-4361
现在您已确认需要快速磁盘访问的 Pod 可以正确调度,您需要创建一个部署来测试需要 GPU 的工作负载。
创建需要 GPU 的部署
任何需要 GPU 的工作负载都需要在 us-east4-b 区域的节点上调度。我们已经在该区域的节点上添加了污点,为了确认需要 GPU 的工作负载可以正确调度,我们需要创建一个使用以下代码的容忍度测试部署:
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx-gpu
name: nginx-gpu
spec:
containers:
- image: nginx
name: nginx-gpu
restartPolicy: Always
nodeSelector:
workload: gpu
tolerations:
- key: "workload"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
当应用此代码片段时,您可以使用 kubectl get pods -o wide 验证 Pod 是否正在 us-east4-b 区域的正确节点上运行:
NAME READY STATUS AGE IP NODE
nginx-gpu 1/1 Running 3s 10.8.2.6 gke-cls1-pool1-52bcec35-tf0q
将输出与列出每个区域节点的表格进行比较,可以验证 Pod 已在 us-east4-b 区域的节点上调度。
恭喜!您已成功解决工作负载需求,并证明了您理解如何根据节点标签和污点调度工作负载。
摘要
-
控制计划接收并存储对象并调度工作负载,而工作节点是实际容器在 Kubernetes 调度器调度后执行的地方。
-
可用两种不同的部署模型:声明式和命令式。
-
您已经了解了 Kubernetes 资源及其功能。
-
您可以使用选择器、污点、容忍度和亲和力以及反亲和力规则来控制哪些节点将用于特定工作负载。
4 Anthos 服务网格:大规模的安全性和可观察性
Onofrio Petragallo
本章涵盖
-
旁路代理和无代理架构
-
介绍 Istio 的主要功能
-
使用 Istio 的安全和可观察性
-
探索 Anthos 服务网格
-
带有代码的实际示例
云原生的一个关键方面是将您的应用程序拆分为微服务。这意味着原本可能运行在单个服务器上的应用程序现在有多个服务,由多个 Pod 作为独立组件支持。随着应用程序扩展其服务,您可能会遇到的问题变得难以调试。随着这种附加的复杂性,我们需要一个工具来帮助组织、安全和增强微服务引入的扩展复杂性。另一个重要问题是,企业通常拥有大量的微服务,并且并不总是能够控制、管理和观察它们——这是服务网格可以解决的问题。
在本章中,我们将讨论 Anthos 服务网格(ASM)以及 ASM 从流行的开源框架 Istio(istio.io/)继承的特性,Istio 是用于创建、管理和实施服务网格的框架。
服务网格的实施不仅通过专用通信管理控制平面促进了微服务之间的通信;还包括观察服务之间通信的工具——提高可观察性、增强安全性、控制应用流量流和模拟应用故障。
Anthos 服务网格是 Google 管理的一项服务,它允许企业从单一位置管理混合云或多云架构中存在的所有服务网格,提供对所有微服务的完整和深入可见性。服务网格拓扑的可视化和与 Cloud Monitoring 的完全集成,为用户提供识别失败的工作负载或其他问题的工具,使问题解决更快。
Anthos 服务网格提供的安全功能允许您通过相互认证(mTLS;mng.bz/1Mly)管理通信的认证、授权和加密,以确保微服务之间通信的双向安全和信任;mTLS 确保了高水平的安全性,最小化了相关风险。Istio 的流量管理功能为用户提供工具,通过请求路由、故障注入、请求超时、断路器和镜像来操纵流量。
正如您所看到的,Istio 包含了几个可能难以调试的复杂功能。目前市场上很少有产品提供对 Istio 的支持,这使您必须自行支持您自己的服务网格。Google 通过在 Anthos 中包含 ASM 来解决这一不足,为您的 Kubernetes 集群和 Istio 提供单一的支持点。
在详细讨论 Anthos 服务网格功能和 Istio 之前,让我们首先解释一下服务网格实际上是什么。
4.1 技术要求
本章的实践部分需要你能够访问一个运行在 GCP 上的 Kubernetes 集群,其部署模式如下:一个至少有三个节点、每个节点有四个 CPU 和 16 GB RAM 的 GKE 集群。
4.2 什么是服务网格?
要了解服务网格是如何工作的以及为什么它正在成为微服务工具箱中的标准工具,你需要了解服务网格提供的内容。采用服务网格的主要优势包括以下能力:
-
观察和监控各个微服务之间的所有通信
-
可用微服务之间的安全连接
-
通过多集群和多云架构模式提供具有弹性的服务(分布式服务)
-
提供高级流量管理:A/B 测试、流量分割和金丝雀发布
服务网格是微服务架构中的一个基础设施层,它控制服务之间的通信。我们不仅可以在运行在 Kubernetes 集群中的微服务架构内创建服务网格,还可以创建跨越多个集群或甚至运行在虚拟机上的非微服务服务的单个服务网格。
服务网格管理每个微服务的所有入站(或传入)流量和出站(或传出)流量。流量管理是一个复杂的话题,大多数用户都不想处理。为了减轻这种负担,Istio 不要求开发者在他们的应用逻辑中进行任何更改;相反,服务网格通过使用 Sidecar 代理方法或无代理方法来处理所有这些。
Sidecar 代理是服务网格的主要组件之一,它管理每个微服务的入站和出站流量,同时将自己从微服务的应用逻辑中抽象出来。因为所有流量都通过 Sidecar 代理流动,所以它可以监控这些流量,并将指标和日志发送到集中式控制平面。
以下三种方法可供选择,其中 Sidecar 代理是创建服务最常见的方法:
-
Sidecar 代理—在微服务架构中使用,每个代理都与微服务相连,具有与微服务相同的生命周期,但作为单独的进程执行,如图 4.1 所示。
![04-01]()
图 4.1 Sidecar 代理架构
-
无代理—在微服务架构中使用,微服务可以通过 Google 开发的远程过程调用系统 gRPC 直接将遥测数据发送到控制平面。
-
虚拟机内的代理—一个 L7 代理作为进程或代理在虚拟机内部运行,可以像 Sidecar 代理一样添加到服务网格中。
在了解了服务网格是什么以及创建服务网格的方法之后,让我们回顾 Anthos 服务网格如何使用每种方法。为了实时监控来自各种服务网格网络微服务之间所有传入和传出通信的遥测数据,ASM 使用以下两种方法:
-
使用 Envoy(
www.envoyproxy.io/)代理的无代理代理方法,每个 Pod 上附加的开源服务代理,以获取实时遥测,如图 4.2 所示。![04-02]()
图 4.2 侧边车代理方法
-
使用 Google Cloud Traffic Director(
cloud.google.com/traffic-director)的无代理方法,该方法可以使用 xDS API(github.com/envoyproxy/data-plane-api)与 gRPC 一起使用,正如图 4.3 所示,这是 Envoy 与控制平面通信所使用的技术。![04-03]()
图 4.3 无代理方法
无代理方法从您的部署中移除了 Istio 侧边车。通过移除侧边车,我们消除了服务网络流量中的额外跳数,从而降低了网络延迟,提高了服务的整体响应时间。
单个服务网格可以包含使用标准 Istio 侧边车和无代理方法的服务的组合。这种灵活性允许您为不同的应用程序使用正确的方法,包括使用无代理方法进行 gRPC,为不使用 gRPC 的服务使用侧边车,以及为使用 gRPC 的服务使用侧边车。
如前几章所述,Anthos 是一个完整的平台,由 Google 提供,用于构建在混合云或多云平台上运行的应用程序。Anthos 服务网格是主要组件,为开发人员和集群管理员提供服务管理。
在下一节中,我们将探讨 Istio 的特性,它是 Anthos 服务网格的基础。
4.3 Istio 简介
Istio 是一个开源平台,提供了一种统一的方式来集成微服务、管理微服务之间的流量流、执行策略和聚合遥测数据。Istio 的控制平面在底层集群管理平台(如 Kubernetes)之上提供了一个抽象层。Istio 的主要功能(mng.bz/WA6x)如下:
-
对 HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡
-
使用强大的路由规则、重试、故障转移和故障注入进行细粒度流量行为控制
-
支持访问控制、速率限制和配额的可插拔策略层和配置 API
-
集群内所有流量的自动指标、日志和跟踪,包括集群入口和出口
-
在集群中实现基于强身份验证和授权的安全服务间通信
由于其开源性质,Istio 可扩展且适用于各种环境:例如,您可以在本地、云中、虚拟机内或与微服务一起执行它,允许您根据安全和监控需求自定义服务网格。
要理解 Istio,您需要了解系统的底层架构。在下一节中,我们将解释 Istio 的组件及其提供的功能。
4.3.1 Istio 架构
Istio 的灵活架构允许您从头开始实现服务网格。开发者在使用集群之前不需要安装 Istio——服务网格可以在开发者实现和部署他们的服务之前或之后部署。记住,如图 4.4 所示,Istio 使用边车代理注入来拦截来自微服务网络内外部的入站和出站流量,因此没有对开发者的依赖。

图 4.4 详细 Istio 架构
从 Istio 版本 1.5 开始,Istio 架构的主要组件是边车代理和 istiod,其中包含三个子组件:Pilot、Citadel 和 Galley.
Istiod 提供服务发现、配置和证书管理,以及控制流量行为进入 Envoy 代理特定配置的高级路由规则,在运行时将它们注入到边车中。它还充当证书颁发机构,生成证书以允许数据平面中的安全 mTLS 通信。Istiod 包含以下三个进程以提供其服务:
-
Pilot—负责跨服务网格部署的 Envoy 代理实例的生命周期。Pilot 抽象了平台特定的服务发现机制,并符合任何可以消费 Envoy API 的边车。
-
Galley—解释 Kubernetes 的 YAML 文件,并将它们转换为 Istio 理解的格式。Galley 使得 Istio 能够与 Kubernetes 以外的环境(例如虚拟机)一起工作,因为它将各种配置数据转换为 Istio 理解的通用格式。
-
Citadel—通过内置的身份和凭证管理,实现强大的服务间和终端用户身份验证。
到目前为止,我们已经从高层次概述了 Istio,但现在让我们详细探讨 Istio 的功能。我们可以将这些功能分为三个主要类别:流量管理、安全和可观察性。
4.3.2 Istio 流量管理
Istio 提供强大的流量管理功能(istio.io/latest/docs/tasks/traffic-management/),允许用户控制入站和出站流量。这种控制不仅限于简单地路由流量到特定服务;它还提供了在应用程序的不同版本之间分割流量以及模拟故障和超时的能力。表 4.1 展示了 Istio 的流量管理功能。
表 4.1 Istio 流量管理功能
| 功能 | 描述 |
|---|---|
| 入口 | 控制服务网格的入口流量,通过 Istio 网关使用 TLS 或 mTLS 暴露服务到服务网格之外。在另一章中,我们将深入探讨 Anthos 的入口。 |
| 出口 | 控制服务网格的出口流量,将流量路由到外部系统,对出站流量执行 TLS,并配置出站网关使用 HTTPS 代理。 |
| 请求路由和流量分割 | 动态地将流量路由到多个微服务版本,或以逐步和受控的方式将流量从某个版本迁移到另一个版本。 |
| 故障注入 | 提供可配置的 HTTP 延迟和故障注入功能,通过 HTTP 状态码允许开发者发现生产环境中可能出现的问题。 |
流量管理是 Istio 的强大功能之一,允许开发者完全控制流量,甚至可以控制到将单个用户引导到应用程序的新版本,而其他所有请求都导向当前版本。故障注入功能使开发者能够在服务之间引入延迟,模拟 HTTP 延迟或故障,以验证应用程序对意外问题的反应。所有这些功能都可以在不修改应用程序代码的情况下由用户使用,这为旧“传统”开发时代提供了巨大优势。
安全是每个人的责任,但并非每个人都有足够的背景知识来编写增强应用程序安全性的代码。就像流量管理功能一样,Istio 提供了额外的安全功能,而无需开发者编写任何代码。
在下一节中,我们将解释 Istio 和 ASM 包含的安全功能。
4.3.3 Istio 安全性
网格中的服务需要通过网络连接相互通信,因此您需要考虑额外的安全措施来防御各种攻击,包括中间人攻击和未知服务通信。Istio 包括增强应用程序安全性的组件(istio.io/latest/docs/tasks/security/),从内置的证书颁发机构到对等认证和授权,帮助您采用零信任策略。
Istio 提供的第一个组件是为了提高您的应用程序安全性,包括处理证书管理,包括带有现有根证书的 Istio 证书授权(CA)。在密码学中,证书授权机构或认证机构是一个发行数字证书的实体。数字证书证实了证书中命名的主题对公钥的所有权。这允许其他人依赖与对应于认证公钥的私钥相关的签名或声明——证明证书所有者的身份。CA 充当受信任的第三方:既受证书所有者的信任,也受依赖证书的实体的信任。
在一个组织中,根证书的签署者可能希望继续负责签署组织中所有实体的所有证书。也可能出现负责签署根证书的人希望将签署证书的责任委托给下属实体。在这种情况下,我们将下属实体称为委托 CA。
Istio 的证书授权可以通过多种方式配置。默认情况下,CA 生成一个自签名的根证书和密钥,用于签署微服务的证书。Istio 的 CA 还可以使用管理员指定的证书和密钥以及管理员指定的根证书来签署证书。最后一种配置在企业环境中最为常见,其中 CA 配置了现有的根证书或委托 CA 签名证书和密钥。
Istio 中的 CA 用于为网格中的每个工作负载安全地提供强大的身份。证书使用 X.509 证书颁发,这是一个定义公钥证书格式的标准。X.509 证书用于许多协议中,包括 TLS/SSL,这是 HTTPS 的基础,是浏览网页的安全协议。
Istio 代理,与每个 Envoy 代理并行运行,与 istiod 的 Istio CA 组件协同工作,以实现大规模的关键和证书轮换自动化。由于证书的轮换和分发是自动化的,一旦配置完成,集群的操作员或用户几乎不需要额外的开销——这是 Istio 确保服务间通信安全的一个强大功能。
证书是我们服务网格中额外安全的基础。在下一节中,我们将讨论身份验证和相互 TLS 加密——一个依赖于颁发的证书来保护网格工作负载的安全层。
Istio 身份验证
Istio 使用对等身份验证进行服务间身份验证和验证发起连接的客户端。Istio 还提供 mTLS 作为全栈传输身份验证解决方案,无需修改任何应用程序代码即可启用。对等身份验证提供了以下好处:
-
每个服务都有一个强大的身份,代表其在集群中的角色,以实现集群内部的互操作性。
-
之间所有服务通信的加密。
-
一个密钥管理系统,用于自动化密钥和证书的生成、分发和轮换。
Istio 允许使用 JSON Web Token (JWT) 验证进行请求级别的认证,支持许多认证提供者(例如,Google Auth [developers.google.com/identity])。
Istio 授权
Istio 为操作员提供了一种定义授权策略的机制,以控制对服务网格、命名空间以及服务网格内工作负载的访问,如图 4.5 所示。可以通过类型(如 TCP 或 HTTP)和请求者的身份来限制流量。授权提供的优势如下:
-
授权—在工作负载之间以及从用户到工作负载之间。
-
灵活的语义—操作员可以在 Istio 属性上定义自定义条件,并使用 DENY 和 ALLOW 动作调整策略以满足其需求。
-
高性能—Istio 授权在 Envoy 代理上原生化应用。
-
灵活性—原生支持 gRPC、HTTP、HTTPS 和 HTTP2,以及所有常规 TCP 协议。
-
分布式—每个 Envoy 代理运行自己的授权引擎,授权每个请求执行。

图 4.5 Istio 授权架构
在本章开头,我们提到服务网格的一个优势是能够组织微服务。随着服务数量的增长,你的架构复杂性也会增加。维护健康状态和排查服务问题的唯一方法是拥有一个强大的工具集,允许你深入了解网格活动。在下一节中,我们将介绍你可以与 Istio 一起使用的工具,以查看网格中的活动。
4.3.4 Istio 可观察性
为了提供对服务网格的视图,Istio 提供了多个附加组件 (istio.io/latest/docs/tasks/observability/),这些组件提供分布式跟踪、指标和日志记录以及仪表板。
Istio 包含一些选项,提供具有分布式跟踪的网格。分布式跟踪允许你跟踪用户通过所有服务,并了解请求延迟、序列化和并行性。你可以配置 Istio 将分布式指标发送到不同的系统,包括 Jaeger (www.jaegertracing.io/)、Zipkin (zipkin.io/) 和 Lightstep (lightstep.com/)。
Jaeger 是 Uber 技术公司作为开源发布的一个分布式跟踪系统,用于监控和调试基于微服务的分布式系统,包括以下功能:分布式上下文传播、分布式事务监控、根本原因分析、服务依赖分析以及性能优化。
Zipkin 和 Lightstep 是其他分布式跟踪系统。它们帮助收集解决服务架构中延迟问题的所需时间数据。功能包括收集和查找此数据。
您可以从 Envoy 代理和 TCP 会话收集所有指标和日志,并使用 Istio 指标自定义指标,通过 Kiali (kiali.io/)、Prometheus (prometheus.io/) 或 Grafana (grafana.com/) 使所有数据可用。
如图 4.6 所示的 Kiali,是一个基于 Istio 的服务网格的管理控制台,可以根据来自 Envoy 侧边代理的遥测数据构建服务图。Kiali 提供仪表板和可观察性,并让您通过强大的配置和验证功能操作您的网格。它通过推断流量拓扑显示您的服务网格结构,并显示您的网格健康状况。Kiali 提供详细的指标、强大的验证、Grafana 访问以及与 Jaeger 的强大集成,用于分布式跟踪。此应用允许您使用 Kubernetes JWT 令牌提供原生 RBAC 权限。用户提供的 JWT 允许访问他们在集群中可以访问的所有命名空间,同时拒绝所有没有对命名空间权限的用户——所有这些都不需要集群管理员进行任何配置。

图 4.6 Kiali 控制台 UI
Prometheus 是一个开源的系统监控和警报应用,具有以下特性:一个多维数据模型,通过指标名称和键值对识别时间序列数据,以及一个名为 PromQL 的灵活查询语言来使用这种维度。时间序列收集通过 HTTP 的拉模型进行,并且支持通过中介网关推送时间序列。
Grafana 是一个开源的可视化和分析软件应用。它允许您查询、可视化、警报和探索您的指标,无论它们存储在哪里。它为您提供了将时间序列数据库数据转换为美丽图表和可视化的工具。Grafana 可以连接到 Prometheus 和 Kiali。
现在我们已经了解了 Istio,让我们看看 Istio 在由 Google Cloud 管理的 Anthos 服务网格中使用时提供了哪些功能和优势。
4.4 什么是 Anthos 服务网格?
Anthos Service Mesh 提供了一系列功能和工具,帮助您以统一的方式观察和管理安全、可靠的服务。使用 Anthos Service Mesh,您将获得 Google 测试和支持的 Istio 分发版,由 Google 管理,让您能够在 Google Cloud 和其他平台上创建和部署服务网格,并获得完整的 Google 支持。
根据您想要设计和实施的架构,在 Anthos Service Mesh 中使用 Istio 功能会有所不同,包括全云、多云、混合云或边缘。每种实现都有不同的可用功能;因此,有必要检查各种场景支持的功能可用性(见 mng.bz/81R2)。
在安装 Anthos Service Mesh 之前,请始终检查文档并选择最合适和最新的配置配置文件。配置配置文件是 IstioOperator API 使用的 YAML 文件,用于定义和配置与 Anthos Service Mesh 一起安装的功能。截至编写时,您可以在以下场景中安装 ASM:
-
在单个项目中运行的 Google Cloud 上的 Anthos 集群 (GKE)
-
在不同项目之间运行的 Google Cloud 上的 Anthos 集群 (GKE)
-
在 VMware 上的 Anthos 集群 (GKE)
-
在裸金属上运行的 Anthos 集群 (GKE)
-
在 AWS 上运行的 Anthos 集群 (GKE)
-
附加集群 Amazon Elastic Kubernetes Service (Amazon EKS)
-
附加集群 Microsoft Azure Kubernetes Service (Microsoft AKS)
4.5 安装 ASM
您在 GCP 上的 GKE 集群和本地安装 ASM 的方式不同。您可以在 ASM 网站上查看最新的安装程序,网址为 mng.bz/El7l。解释安装的每个选项超出了单章的范围,但将 ASM 部署到 GKE 集群并包含所有测试组件的步骤只需要几个步骤,如下所述,针对 ASM 1.12 在集群中:
-
按以下方式下载 ASM 安装脚本:
curl https://storage.googleapis.com/csm-artifacts/asm/asmcli_1.12 > asmcli -
使脚本可执行如下:
chmod +x asmcli -
使用 asmcli 安装 ASM:
./asmcli install --project_id PROJECT_ID --cluster_name CLUSTER_NAME --cluster_location CLUSTER_LOCATION --output_dir ./asm-downloads --enable_all
在 Istio 部署到 Kubernetes 集群后,您可以直接开始配置和使用它。要做的第一件事是定义您想要采用哪种方法来使代理在服务网格内进行通信。
在下一节中,我们将定义 Istio 如何处理边车代理注入。
4.5.1 边车代理注入
由于可以在每个工作负载或微服务旁边注入边车代理,因此激活 Anthos Service Mesh 功能是一个简单、透明的过程。您可以通过更新 Pod 的 Kubernetes 清单手动注入边车代理,或者您可以使用自动边车注入。默认情况下,所有命名空间都禁用了边车自动注入。要为单个命名空间启用自动注入,请执行
kubectl label namespace NAMESPACE istio.io/rev=asm-managed --overwrite
其中 NAMESPACE 是您应用程序服务的 namespace 名称,rev=asm-managed 是发布渠道(见 mng.bz/Nm72)*。
所有通道都基于一般可用(GA)版本(尽管某些功能可能并非总是 GA,如标记所示)。新的 Anthos Service Mesh 版本首先发布到快速通道,随着时间的推移,将升级到常规和稳定通道。这种进展允许您选择满足您的业务、稳定性和功能需求的通道。
由于 sidecar 在创建 Pod 时注入,在您执行命令后,您必须重启任何正在运行的 Pod 以使更改生效。当 Kubernetes 调用 webhook 时,将应用 admissionregistration.k8s.io/v1beta1#MutatingWebhookConfiguration 配置。默认配置将 sidecar 注入到任何命名空间中带有 istio-injection=enabled 标签的 Pod 中。该标签应与上一个命令一致。istio-sidecar-injector 配置映射指定了注入 sidecar 的配置。
您重启 Pod 的方式很大程度上取决于它们的创建方式,如这里所述:
-
如果您使用了部署,您应该首先更新或重新创建部署,如下所示,这将重启所有 Pod,并添加 sidecar 代理:
kubectl rollout restart deployment -n YOUR_NAMESPACE -
如果您没有使用部署,您应该按照以下方式删除 Pod。它们将自动与 sidecar 一起重新创建:
kubectl delete pod -n YOUR_NAMESPACE --all -
检查命名空间中的所有 Pod 是否都注入了 sidecar:
kubectl get pod -n YOUR_NAMESPACE -
在以下示例中,您将注意到上一个命令的输出中,READY 列表明每个工作负载存在两个容器:主容器和 sidecar 代理容器:
NAME READY STATUS RESTARTS AGE YOUR_WORKLOAD 2/2 Running 0 20s
我们现在已经看到了如何使用带有 sidecar 代理的方法安装 Anthos Service Mesh,以及选择正确配置文件的重要性。现在让我们看看 Anthos Service Mesh 的其他功能和使用它们的优点。
4.5.2 统一可观察性
Anthos Service Mesh 最重要的和最有用的功能之一是可观察性。通过代理架构实现服务网格并利用 Google Cloud Monitoring 服务确保对网格中存在的各种微服务之间发生的事情有深入的了解。
通过代理,每个微服务可以自动发送遥测数据,开发者无需在应用程序中添加任何代码。所有流量都被代理拦截,遥测数据被发送到 Anthos Service Mesh。此外,每个代理都会将数据发送到 Google Cloud Monitoring 和 Google Cloud Logging,无需额外开发,使用 Google 提供的 API。
第一章中讨论的 Anthos Service Mesh 控制平面提供了两个主要仪表板:表格视图和拓扑视图。在表格视图中,您可以看到集群中部署的所有服务。您可以查看所有指标,并且可以添加 SLI 和 SLO 以更好地监控您的服务。
在拓扑视图中,服务网格以图形地图的形式表示。所有服务,如工作负载、Pod、系统服务和相关所有者都作为节点网络连接。此视图提供了对整个服务网格整体性能的全面了解,以及对每个节点内部信息的深入了解。
4.5.3 运营敏捷性
如果可观察性是管理服务网格最“明显”的功能之一,那么在微服务架构中管理流量则是另一个管理操作的基本资产。由于 Anthos Service Mesh 基于 Istio,它继承了 Istio 提供的多数流量和网络管理功能(mng.bz/DZ79*),因此接下来让我们看看这些功能。
请求路由和流量分割
使用 Istio,您可以将流量重定向到集群中部署的同一微服务的多个版本,并安全地(在可能的配额下)控制从微服务的旧版本到新安装版本的部分流量。这两种选项都允许您在部署新功能或修复可能影响业务的错误时保持敏捷。
例如,让我们假设我们需要紧急修复一个微服务。在新版本部署后,我们可以将一小部分入站流量重定向,验证修复是否正确,然后完全将流量重定向到新版本,而无需任何停机时间。如果修复仅针对特定情况执行,则可以同时保持微服务的两个版本活跃,根据预先设定的规则将流量重定向到两个版本,而不必删除运行良好的旧版本。
通过这些流量管理功能,Anthos Service Mesh 可以管理 A/B 测试,允许您将特定百分比的流量引导到服务的某个新版本。当您想通过先使用一小部分用户流量测试新版本的服务,如果一切顺利,然后逐步增加百分比同时淘汰旧版本时,这种做法非常有用。
多亏了这些功能,可以直接测试发布的服务的新版本,实现金丝雀部署或渐进式发布策略。如果服务的新版本在少量流量下没有出现任何问题,您可以将所有流量转移到新版本,并丢弃旧版本。
在图 4.7 中,使用带有流量分流的金丝雀部署来将 5%的流量重定向到测试服务 A 的新版本。

图 4.7 基于 流量的 Istio 金丝雀部署功能
在图 4.8 中,使用带有流量分流的金丝雀部署将 iPhone 的流量重定向以测试服务 A 的新版本。

图 4.8 基于 user-agent 的 Istio 金丝雀部署功能
管理生产环境的运维部门利用这些功能,在发布修复和新版本的微服务时计划。这些场景中的每一个都可以即时执行,而不会干扰最终用户。
电路断开
微服务架构是为了可扩展性、敏捷性和弹性而生的,但设计并实现这些架构以管理高负载或管理外部服务的集成并不总是容易,这可能导致可能的停机或超时。如前所述,服务网格独立于应用程序代码和使用的编程语言,因此这有助于采用专门用于管理办公室的功能。
允许您管理架构中的超时、故障和负载的功能称为 电路断开 (mng.bz/lJAM)。在设计微服务架构时,您必须始终确保能够正确处理故障。这些故障可能不仅是由应用程序代码中的错误引起的,也可能是由外部因素引起的,例如网络或基础设施。在发生故障或无法达到 SLA(特定服务的可用性和/或性能)的情况下,电路断开会自动允许您将流量重定向到另一个微服务或外部服务,以限制停机时间或限制最终用户功能损失。
让我们看看一个例子。在图 4.9 中,服务消费者正在调用 Istio 入口以调用 Service A,该服务分布在两个 Pod 中。假设 Service A 在 Pod 1 中存在负载问题,变得不可达。多亏了电路断开功能,Istio 将关闭代理到 Pod 1 中 Service A 的连接,并将所有流量重定向到 Pod 2 中的代理,直到 Pod 1 中的 Service A 正常工作。

图 4.9 Istio 电路断开功能示例
出口控制
通常情况下,当涉及到服务网格时,一个重要的功能是控制入口网关以确保网络的安全性。然而,如果我们发现自己处于需要我们控制服务网格出向流量的情况下(例如,法规要求,如 PCI [mng.bz/Bl7g])或客户的要求,那么,多亏了 Istio 和出口网关控制,我们可以覆盖所需的安全。
使用 Anthos Service Mesh,您可以通过专用出口网关或必要时使用外部 HTTPS 代理来配置从服务网格到外部服务(HTTP 或 HTTPS)的流量路由。对于这些外部服务的连接,从服务网格执行 TLS 原始(SDS 或文件挂载)。请参阅图 4.10 以了解说明。

图 4.10 Istio 出口控制示例
4.5.4 政策驱动安全
自从采用容器、共享服务和分布式架构以来,减轻内部威胁和最小化及限制数据泄露变得更加困难,确保工作负载之间的通信保持加密、认证和授权。Anthos Service Mesh 的安全功能(mng.bz/dJOX)有助于减轻这些威胁,配置上下文相关的服务级别或上下文相关的网络。
在 Istio 等解决方案出现之前,保护应用程序是应用程序开发者的责任,许多任务复杂且耗时,包括以下内容:
-
加密应用程序与其他服务之间的通信,这需要证书管理和维护
-
创建特定语言的模块以基于开放身份标准(如 JSON Web 令牌(JWTs))进行访问认证
-
实施复杂的授权系统以限制使用呈现的 JWT 上的断言允许的权限
而不是开发者花费时间创建和管理这种安全措施,他们可以利用 Istio 的功能,这些功能无需任何额外代码即可解决每个任务。
使用 Anthos Service Mesh,可以通过声明性标准和无需修改任何应用程序代码的方式,采用与零信任安全原则一致的深度防御姿态。ASM 的主要安全特性包括管理的私有证书颁发机构、基于身份的访问控制、请求声明感知的访问控制策略、使用基于身份的代理进行用户认证以及访问日志和监控。
第一个特性,管理的私有证书颁发机构(Mesh CA),包括为 mTLS 颁发证书的 Google 管理的多区域私有证书颁发机构。Mesh CA 是一个高度可靠和可扩展的服务,针对云平台上的动态扩展工作负载进行了优化。Mesh CA 允许您在 Anthos 集群之间依赖单一信任根。当使用 Mesh CA 时,您可以使用工作负载身份池提供粗粒度隔离。默认情况下,如果客户端和服务器不在同一工作负载身份池中,则认证失败。
下一个特性,基于身份的访问控制(防火墙)策略,允许您根据 mTLS 身份与对等方的 IP 地址配置网络安全策略。这使您能够创建独立于工作负载网络位置的策略。目前仅支持同一 Google Cloud 项目中集群之间的通信。
第三个特性,请求声明感知的访问控制(防火墙)策略,允许您根据 HTTP 或 gRPC 请求的 JWT 头中的请求声明来授予对服务的访问权限。Anthos Service Mesh 允许您断言 JWT 是由受信任实体签发的,因此您可以配置策略,仅当请求声明存在或与指定的值匹配时,才允许来自某些客户端的访问。
第四个特性,使用身份感知代理进行用户身份验证,通过使用身份感知代理(IAP)对在 Anthos Service Mesh Ingress 网关上公开的任何服务进行访问的用户进行身份验证。IAP 可以验证从浏览器登录的用户,与自定义身份提供者集成,并颁发一个短期有效的 JWT 令牌或 RCToken,然后可以使用它通过边车在网关或下游服务(通过使用边车)授予访问权限。
最终特性,访问日志记录和监控,确保访问日志和指标在 Google Cloud 的操作套件中可用,并提供一个集成仪表板来理解基于这些数据的某个服务或工作负载的访问模式。您还可以选择配置一个私有目标。Anthos Service Mesh 允许您通过仅记录可配置时间窗口内的成功访问来减少访问日志中的噪音。被安全策略拒绝或导致错误的请求始终会被记录,这样您可以显著减少与日志摄取、存储和处理相关的成本,而不会丢失关键的安全信号。
4.6 结论
在本章中,我们了解了什么是服务网格,实施它的优势是什么,以及 Anthos Service Mesh 如何利用 Istio 的潜力来管理整个服务网格。得益于 Anthos Service Mesh,开发者可以更敏捷地实施微服务架构,并且不需要担心在应用程序代码中实现监控探针,通过利用边车代理和无代理方法。
运营结构可以实时监控服务网格内发生的所有事件,保证所需的服务级别。流量分割和滚动发布功能允许您有效地发布新版本的服务,确保一切正常工作。得益于安全功能,服务网格可以抵御来自网络外部或内部的潜在风险,实施有效的身份验证和授权策略。
4.7 例子和案例研究
使用本章的知识,解决以下案例研究中的每个要求。
4.7.1 永恒工业
永恒工业要求您在 GCP 上运行的 GKE 集群上启用 ASM。该集群将用于初始服务网格测试,并应安装所有功能,以便开发者可以测试任何功能。他们还要求您部署一个在线精品应用程序,以证明服务网格按预期运行。
由于他们刚开始使用 Istio 以及使用服务网格的优势,他们除了部署 ASM 和精品演示应用程序外,没有其他特殊要求。唯一的额外要求是提供证明,表明精品应用程序在 GCP 控制台中按预期在网格中运行。
下一节包含解决 Evermore 需求的解决方案。您可以跟随解决方案进行操作,或者如果您感到舒适,您可以配置您的集群以满足需求,并使用解决方案来验证您的结果。
Evermore Industries 解决方案:安装 ASM
要安装 ASM,您可以下载 ASM 安装脚本以部署带有所有组件的 ASM。按照以下步骤在运行在 GCP 上的 GKE 集群上安装带有所有组件的 ASM:
-
下载 ASM 安装脚本:
curl https://storage.googleapis.com/csm-artifacts/asm/asmcli_1.12 > asmcli -
使安装器可执行:
chmod +x asmcli -
您需要从您的项目和 GKE 集群中获取以下信息以执行安装脚本:项目 ID、GKE 集群名称和 GKE 集群位置。
-
使用您的集群信息执行安装脚本以安装 ASM:
./asmcli install --project_id gke-test1-123456 --cluster_name gke-dev-001 --cluster_location us-central1-c --output_dir ./asm-downloads --enable_all -
安装将花费几分钟。一旦安装完成,您将看到类似以下的消息:
asmcli: Successfully installed ASM. -
使用以下代码验证 istio-system 命名空间中是否有健康且成功启动的 Pods:
kubectl get pods -n istio-system -
这应该显示有四个正在运行的 Pods:两个 istio-ingressgateway Pods 和两个 istiod Pods。以下是一个示例输出:
NAME READY STATUS istio-ingressgateway-68fb877774-9tm8j 1/1 Running istio-ingressgateway-68fb877774-qf5dp 1/1 Running istiod-asm-1124-2-78fb6c7f98-n4xpp 1/1 Running istiod-asm-1124-2-78fb6c7f98-sgttk 1/1 Running
现在 Istio 已部署,您需要创建一个命名空间并启用 Istio 以进行 sidecar 注入。
Evermore Industries 解决方案:启用 sidecar 注入
要为命名空间启用 sidecar 注入,请按照以下步骤操作:
-
创建一个用于部署 Boutique 应用程序的命名空间。在我们的示例中,我们将使用名为 demo 的命名空间:
kubectl create namespace demo -
接下来,我们需要使用正确的标签标记命名空间以启用 sidecar 注入。从 Istio 1.7 开始,用于启用 sidecar 注入的标签从通用的 istio-injection 更改为使用控制平面版本的值。
-
要在标签中找到我们将使用的控制平面版本,检索 istio-system 命名空间中的标签:
kubectl -n istio-system get pods -l app=istiod --show-labels -
这将返回 istiod Pods 的标签,其中包含我们需要的值。输出将类似于以下示例。(注意:我们需要的标签值已加粗。)
NAME READY STATUS RESTARTS AGE LABELS istiod-asm-1124-2-78fb6c7f98-n4xpp 1/1 Running 0 44m app=istiod,install.operator.istio.io/owning-resource=unknown,istio.io/rev=asm-1124-2,istio=istiod,operator.istio.io/component=Pilot,pod-template-hash=78fb6c7f98,sidecar.istio.io/inject=false istiod-asm-1124-2-78fb6c7f98-sgttk 1/1 Running 0 44m app=istiod,install.operator.istio.io/owning-resource=unknown,istio.io/rev=asm-1124-2,istio=istiod,operator.istio.io/component=Pilot,pod-template-hash=78fb6c7f98,sidecar.istio.io/inject=false -
使用 istio/io 值,按照以下方式标记 demo 命名空间以启用 sidecar 注入:
kubectl label namespace demo istio.io/rev=asm-1124-2
Evermore Industries 解决方案:安装 Boutique 应用程序
现在 ASM 已安装,并且我们已经创建了一个带有正确标签的新命名空间以启用 sidecar 注入,我们可以部署 Boutique 应用程序。按照以下步骤部署 Boutique 演示:
-
从 Git 仓库下载 Boutique 演示应用程序。以下命令将下载 GIT 仓库到名为 online-boutique 的目录中:
kpt pkg get https://github.com/GoogleCloudPlatform/microservices-demo.git/release online-boutique -
使用 online-boutique 目录中的文件部署应用程序:
kubectl apply -n demo -f online-boutique此命令将安装几个部署和服务到演示命名空间。Pod 启动可能需要几分钟。您可以监视命名空间或列出命名空间中的 Pod 以验证每个 Pod 进入运行状态,并且每个 Pod 显示两个容器。(请记住,每个 Pod 将为 Istio 代理注入一个 sidecar。)
-
一旦所有 Pod 都在运行,演示命名空间的输出应类似于以下内容:
NAME READY STATUS adservice-6b74979749-2qd77 2/2 Running cartservice-6fc79c6d86-tvncv 2/2 Running checkoutservice-7c95787547-8dmzw 2/2 Running currencyservice-67674dbdf7-hkw78 2/2 Running emailservice-799966ff9f-qcb6s 2/2 Running frontend-597d957cdf-dmdwr 2/2 Running loadgenerator-88f7dbff5-cn78t 2/2 Running paymentservice-5bdd645d9f-4w9f9 2/2 Running productcatalogservice-7ffbf4fbf5-j98sq 2/2 Running recommendationservice-599dfdc445-gpmww 2/2 Running redis-cart-57bd646894-tdxwb 2/2 Running shippingservice-5f4d856dc-cwtcl 2/2 Running -
作为部署的一部分,创建了一个负载均衡器服务,允许从互联网连接到 Boutique 应用程序。要找到分配的 IP 地址,请从演示命名空间获取名为 frontend-external 的服务:
kubectl get services frontend-external -n demo此代码将输出服务详情,其中将包含您可以使用的外部地址来验证应用程序是否运行。
-
使用步骤 3 中的输出地址通过网页浏览器连接到应用程序。一旦连接,您应该看到 Boutique 的主页,如图 4.11 所示。

图 4.11 在线 Boutique 网络应用程序
Evermore Industries 解决方案:使用 GCP 控制台观察服务
Evermore 的最终要求是使用 GCP 控制台证明 Boutique 应用程序在网格中运行。为了证明这一点,您可以从 GCP 控制台导航到 Anthos > 服务网格,如图 4.12 所示。

图 4.12 Google Cloud 控制台:Anthos 菜单
此界面将提供服务网格中所有服务的列表。默认的表格视图,如图 4.13 所示,将显示每个服务及其指标,包括请求、延迟和失败。

图 4.13 Anthos 服务网格:服务列表
您可以通过点击控制台右上角的拓扑按钮从表格视图更改到拓扑视图。这将提供网格服务的图形拓扑布局,如图 4.14 所示。

图 4.14 Anthos 服务网格:拓扑视图
两个视图都会显示服务网格中的服务。因为我们看到了 Boutique 应用程序的预期服务,这证明了部署在网格内部成功运行。在这个练习中,你在 GKE 集群中部署了 ASM,创建了一个启用 sidecar 注入的新命名空间,并将测试应用程序部署到服务网格中。
摘要
-
基于 Anthos Service Mesh 的服务网格有助于组织在规模上运行微服务。
-
我们涵盖了 Istio 的所有组件以及每个组件如何提供服务网格功能。
-
ASM 通过使用相互 TLS(mTLS)加密网格资源之间的所有通信以及使用本地的 Istio 身份验证和授权策略来提高工作负载之间的安全性。
-
ASM 提供流量路由能力,允许更灵活的发布过程,包括 A/B 测试和金丝雀部署。
-
您可以在发布任何新代码之前发现应用程序故障,通过使用断路器和故障注入来主动查找应用程序处理常见问题(如网络延迟或 HTTP 错误)的方式,从而提高可用性和弹性。
-
ASM 提供了对整个服务网格以及多个环境之间的可见性、监控、安全和控制。
-
由于 Envoy 代理边车的存在,开发者无需修改他们的代码即可使用 ASM 的功能,该边车负责处理应用程序的流量流。
5 运维管理
Jason Quek
本章涵盖了
-
使用统一云界面管理 Kubernetes 集群
-
管理 Anthos 集群
-
日志记录和监控
-
Anthos 部署模式
运维是指确保你的集群运行正常、活跃、安全,并能向用户提供服务的行为。为此,在云时代,一种主流的思想已经得到采纳并迅速发展:一种称为 DevOps 的运维实践。
DevOps 最简单的定义是“开发者和 IT 运维的结合。”DevOps 旨在解决两大要点。第一点是通过对整个基础设施进行代码化管理,通过自动化测试、频繁发布来实现持续交付。你可以根据开发者的技能集使用如 Terraform 或 Pulumi 等框架来实现这一点。第二点,DevOps 经常被忽视的部分是 IT 运维,这包括诸如日志记录和监控等任务,然后利用这些指标来扩展和管理系统。你可以使用如 Prometheus 和 Grafana 等开源项目来管理这些任务。团队可以通过实施额外的安全工具链来进一步提高性能,从而构建现代的 DevSecOps 实践。
在 DevOps 开发之前,谷歌开发了一种称为站点可靠性工程(SRE)的方法。这种方法通过自动化和编码化基础设施操作中的所有任务,以增强系统的可靠性,如果出现问题,可以通过代码自动修复。SRE 团队不仅负责保持环境稳定,还要处理新的运维功能和基础设施的改进。
DevOps 和 SRE 都分配了不同的责任给不同的团队;然而,它们的目标是相同的:能够快速高效地实施变更,尽可能自动化,并持续监控和提升系统。这种共性是工程和运维团队打破壁垒(封闭团队)并共同承担系统责任“愿望”的基础。
任何一种方法都会带来许多相同的优势,但它们以不同的方式解决问题。例如,在 DevOps 方法中,一个专门的运维团队可能会负责基础设施的运维管理方面,将问题转交给另一个开发团队来解决。这与 SRE 方法不同,在 SRE 方法中,运维是由开发团队驱动的,并从软件工程的角度来处理,允许一个 SRE 团队解决他们自己团队内部的问题。
Anthos 提供了一条路径,使用框架中提供的工具来构建强大的 DevOps 或 SRE 文化。本章将向产品所有者、开发者和基础设施团队展示,通过使用 Anthos,他们能够构建一个 DevOps/SRE 文化,这将有助于减少他们公司中的壁垒,构建可靠的系统,并提高开发效率。
在下一节中,我们将解释 Anthos 包含的工具,从 Google Cloud 控制台中的统一用户界面开始,然后是集中式日志记录和监控,最后是环境,这些都是提供构建块以实现操作实践的关键概念。
5.1 Google Cloud 控制台的统一用户界面
在当今一切皆代码的时代,软件工程师以从命令行或作为代码执行所有操作为荣。然而,当出现影响现实服务的生产问题时,直观且辅助的用户界面可以帮助工程师快速识别问题。这正是 Google 统一用户界面发挥作用的地方,如图 5.1 所示。

图 5.1 已注册到 Google Cloud 控制台的多集群
这些工具允许您在一个视图中查看多个项目,如 Kubernetes 集群。将此视图提供给管理员,使他们能够对所有可用资源进行监督,而无需登录到三个不同的集群,如图 5.1 所示。此视图还显示了资源的位置、其提供者以及管理集群所需的任何操作。
访问此视图需要用户已经登录到 Google Cloud 控制台,该控制台由 Google Cloud Identity 保护,为防御恶意行为者提供了额外的安全层。拥有此类视图的访问权限满足了 DevOps 原则之一:使用工具来提供对系统的可观察性。
要获得单视图,您需要将您的集群注册到您的 GCP 项目中。在下一节中,我们将介绍如何注册在任意主要云服务提供商或本地运行的 Anthos 上的集群。
5.1.1 将集群注册到 Google Cloud 控制台
负责将集群连接到 Google Cloud 控制台的组件称为 Connect,通常在集群创建后作为最后一步之一部署。如果集群由 Anthos 在 GKE、AWS 或 Azure 上部署,Connect 代理将在集群创建时自动部署。然而,如果集群不是由 Anthos 部署的(例如 EKS、AKS、OpenShift 和 Rancher 集群),代理将需要单独部署,因为 Anthos 不参与安装过程。此过程将在本章后面进行说明。
由于 Anthos 是遵循 Kubernetes 最佳实践构建的,Connect 代理被表示为 Kubernetes 部署,该镜像由 Google 作为 Anthos 框架的一部分提供。代理也可以在 Google Cloud 控制台中看到,可以像任何其他 Kubernetes 对象一样进行管理,如图 5.2 所示。

图 5.2 部署在 GKE 集群上的 Connect 代理
Connect Agent 充当 Google Cloud 控制台向其已部署的集群发出命令并报告 vCPU 使用情况的渠道,以进行许可。这引出了一个重要观点:集群需要能够访问 Google Cloud API(egress);然而,集群不需要通过 Google Cloud API(ingress)可访问。由于在第一次连接后初始化的单向隧道,对延迟的影响最小。
那么,Google Cloud 控制台是如何发出 Kubernetes API 命令的,例如列出 Pod 以在 Google Cloud 控制台上显示?答案是通过对 Connect Agent 建立一个持久的 TLS 1.2 连接到 GCP 以等待请求,从而消除为用户集群设置入站防火墙规则的需要。
传输层安全性(TLS)是一种加密协议,旨在在发送方和接收方之间提供隐私和数据完整性。它使用基于共享秘密的对称加密来确保消息是私密的。消息使用公钥签名以确保真实性,并包含消息完整性检查以确保消息完整。简而言之,通过互联网到 Connect Agent 的通信通道与互联网银行转账一样安全。完整的通信流程可以在第二章图 2.2 中查看。
需要注意的一个重要观点是,如图 5.3 所示,用于 Anthos 部署与 Google Cloud 通信的互联网上的出站 TLS 加密连接。这种设置简化了事情,因为不需要为 Anthos 部署添加入站防火墙规则——只需向 Google Cloud 发送出站流量——而且不需要任何虚拟专用网络(VPN)。

图 5.3 Anthos 部署到 Google Cloud 的出站连接
Kubernetes 的一个优点是其标准化,这意味着这个代理将能够向由 Google 或任何提供符合云原生计算基金会定义的 Kubernetes 兼容分布的提供商创建的集群发出 Kubernetes API 命令。
在大型企业中,IT 安全通常想知道 Connect Agent 向 Google Cloud API 发送了什么,这是一个棘手的问题,因为人们担心如果 Google 共享解密流量的密钥,它实际上是在覆盖已经实施的安全措施。有关 Connect Agent 实际向 Google Cloud 发送的信息的更多细节,可以在 Google 的这篇白皮书中找到(mng.bz/rdAZ)。Google 还明确表示,没有客户数据通过 Connect Agent 发送,并且它仅用于提供与 Kubernetes API 通信的功能,并为 Anthos 计费提供许可度量。
5.1.2 认证
访问 Google Kubernetes Engine 应该使用身份和访问管理(IAM)角色来管理对 GKE 集群的访问。以下部分涉及 GKE 本地、GKE on AWS、GKE on Azure 以及与 Anthos 连接的集群。
要访问 Anthos 集群,拥有项目访问权限的用户始终必须提供 Kubernetes 服务账户(KSA)令牌、基本身份验证或针对集群配置的身份提供者进行身份验证。
使用 KSA 令牌将是最容易设置的,但它需要令牌轮换和一种安全的方式定期向需要访问集群的用户分发令牌。使用基本身份验证将是最不安全的,因为需要密码管理要求,但如果没有可用的身份提供者,它仍然作为身份验证方法得到支持。如果您必须使用基本身份验证,一个建议是在密码泄露事件中实施密码轮换策略。
推荐的做法是设置 Google Cloud Identity(OIDC)以与 Google Cloud Identity 配合使用,这样用户就可以利用现有的安全设置来管理对他们的集群的访问。截至 2020 年 9 月,OIDC 在 GKE 本地集群中通过命令行(而不是控制台)支持。强烈建议采用稳固的 KSA 令牌轮换和分发策略。这可以像利用 Google Secret Manager 那样简单,其中可以通过 IAM 权限控制检索令牌的权限,并且可以使用 Cloud Scheduler 每七天更新一次令牌。
一旦设置了 OIDC 与 Google Cloud Identity,用户可以使用 gcloud CLI 或 Google Cloud 控制台(如图 5.4 所示)对用户集群进行身份验证。

图 5.4 使用 Google Cloud Identity 的 OIDC 身份验证流程
在图 5.4 中,我们展示了使用 Google Cloud Identity 的 OIDC 身份流。通过 Anthos Identity Service,遵循 OIDC 和轻量级目录访问协议(LDAP)协议的其他提供者可以提供身份。这个过程允许使用 Microsoft Active Directory 或 LDAP 服务器等技术实现无缝的用户管理,并遵循只有一个单一的真实身份来源的原则。
5.1.3 集群管理
在注册集群和身份验证后,用户将能够看到 Pods、Services、ConfigMaps 和持久卷,这些通常可以从 GKE 原生集群中获取。在本节中,将介绍通过 Google Cloud 控制台可用的集群管理选项。然而,为了构建良好的 SRE 实践,集群管理应该是自动化和脚本化的。然而,能够从用户友好的界面进行修改也是很不错的。
在 GCP 上有 Google Kubernetes Engine 经验的管理员知道从 Google Cloud 控制台连接到集群是多么容易。他们只需导航到集群列表,如图 5.5 所示,然后点击连接按钮。

图 5.5 GCP 控制台中的集群列表
一旦点击连接,如图 5.6 所示的弹出窗口将提供在 Google Cloud Shell 中运行的命令,以连接到所选集群。

图 5.6 GKE 中最好的功能之一——通过 gcloud 生成 kubectl 凭据
对于本地和其它云集群,本章后面将讨论的 Connect 网关功能允许操作管理员通过不同的命令远程管理他们的集群。
如图 5.7 所示,Google Cloud 控制台提供了一个用户友好的界面来编辑和应用 YAML 部署。通过这个界面,管理员可以在不通过 kubectl 命令行的情况下修改 Kubernetes 配置,这在紧急情况下可以节省一些时间。这些在 Google Cloud 控制台上的操作转换为 Kubernetes API 调用或 kubectl edit 命令,并通过 Connect Agent 发送到 Anthos 集群。当然,这种方法应仅用于分类或开发情况,不一定适用于生产,但它展示了从本地命令行打开对 Connect Agent 访问的未来可能性。

图 5.7 从 Google Cloud 控制台编辑 YAML 定义
如图 5.8 所示,Google Cloud 控制台还提供了有关节点底层 Docker、kubelet 和内存压力的有用信息。利用这些信息,管理员可以在节点发生故障时快速进行根本原因分析,并且可以隔离和排空节点。

图 5.8 来自 Google Cloud 控制台的节点信息
在 Google Cloud 控制台中列出工作负载时,用户可以看到所有集群的部署,并按集群进行筛选。这种能力提供了对所有集群中运行的服务概述,并指示是否有任何服务出现问题或达到扩展限制。一个常见问题是由于 CPU 或内存不足而无法部署 Pods。这可以在控制台中清晰地看到,如图 5.9 所示的明亮的红色错误信息。

图 5.9 无法调度的 Pods 错误
使用工具交互式地查看集群对于实时查看对象状态、节点状态等非常有用。尽管这个工具在适当的场景下(例如,在诊断影响生产的未知问题,且用户友好的界面减少了在高压情况下记住命令的需求)可能很有帮助,但你可能会发现自己更频繁地查看日志和创建监控事件,而不是实时查看。在下一节中,我们将详细介绍 Anthos 包含的日志和监控功能。
5.1.4 日志和监控
Kubernetes 提供了不同类型的日志,这对于管理员在管理集群时进行调查非常有用。一种类型是系统日志,Kubernetes 系统服务如 kube-apiserver、etcd、kube-scheduler 和 kube-controller-manager 都会记录这些日志。集群还有应用程序日志,其中包含在 Kubernetes 集群上运行的所有工作负载的日志详情。这些日志可以通过 Connect Agent 访问,该 Agent 与 Kubernetes API 通信,并基本上发出一个 kubectl logs 命令。
这两种日志类型,如图 5.10 所示,不是存储在云端,而是根据需求从 Kubernetes API 中检索,这导致检索延迟增加,但在 IT 安全请求的情况下有时是必要的。

图 5.10 容器日志
日志主要关于错误——在执行任何 Kubernetes Pod 期间输出到标准输出流的警告。这些日志被写入节点本身,如果 GKE 集群上启用了 Google Cloud 操作套件(以前称为 Stackdriver)代理,则日志会被聚合并转发到云日志 API 并写入云端。
指标是关于服务的观察,例如内存消耗或每秒请求数。这些观察结果被保存为历史趋势,可用于扩展服务或识别实施中可能存在的问题。鉴于每个服务每秒或每分钟可能都有成十上百万的观察结果,这取决于业务需求,以可用的方式管理这些数据并非易事。我们将在下一小节中提出一些解决方案,涉及 Google 的云日志和监控服务。您还可以使用合作伙伴技术,如 Elastic Stack、Prometheus、Grafana 或 Splunk 来理解指标。更多信息请参阅mng.bz/VpmO或mng.bz/xdAY。
在本地部署 GKE 的日志和监控
当在本地集群上安装 GKE 时,管理员可以在几个不同的可观察性选项之间进行选择。第一种选择是使用 Google 的本地云日志和云监控解决方案。云日志和云监控处理基础设施和云服务,以及 Kubernetes 日志和监控。所有日志数据都可以根据 Kubernetes 对象类型以分层级别显示。默认情况下,GKE 日志仅从 kube-system、gke-system、gke-connect、istio-system 和配置管理系统命名空间收集日志和指标,这些命名空间用于跟踪集群健康,并将数据发送到 Google Cloud 的云日志和云监控。这项服务是完全管理的,包括仪表板和警报功能,以构建一个有用的监控控制面板。云日志和云监控通常用于监控 Google Cloud 资源,并对某些日志事件发出警报,同时也作为监控服务健康状况的单个视图。如果组织愿意使用和学习新的日志和监控堆栈,并希望有一个低成本且完全管理的选项,这是一个推荐的选择。
某些组织可能由于内部决策而希望禁用云日志和云监控。尽管可以禁用,但 Google 支持服务级别协议(SLA)将失效,并且 Google 支持在解决 GKE 本地操作问题时只能尽力而为。
第二种选择是使用 Prometheus、Alertmanager 和 Grafana,这是一个流行的开源项目集合,用于收集应用程序和系统级别的日志,并提供警报和仪表板功能。Prometheus 和 Grafana 作为 Kubernetes 监控附加工作负载部署,因此能够享受到在 Kubernetes 上运行的扩展性和可靠性。当使用此解决方案时,Google 的支持仅限于基本操作、基本安装和配置。有关 Prometheus 和 Alertmanager 的更多信息,请访问prometheus.io,有关 Grafana,请访问grafana.com。
此选项可以用于任何 Kubernetes 配置,并且可以使用许多预构建的 Grafana 包来监控 Kubernetes 集群的健康状况。一个缺点是,管理员必须管理 Prometheus,确保其健康,并管理其运行时的历史指标存储,就像管理任何其他应用程序工作负载一样。可以使用其他工具,如 Thanos,来查询、聚合、降采样和管理多个 Prometheus 源,以及将历史指标存储在对象存储中,如 Google Cloud Storage 或任何兼容 S3 的对象存储。有关 Thanos 的更多信息,请访问thanos.io/。
对于已经使用开源技术构建了日志和监控服务并且之前已经部署过此堆栈的组织来说,这个选项很简单。它还提高了可移植性,并减少了由于使用开源技术而导致的供应商锁定。
第三种选择是使用经过验证的解决方案,如 Elastic Stack、Splunk 或 Datadog,从 Anthos 集群中消费日志和指标,并将其提供给运维团队。如果当前日志方法已经到位,并且组织依赖合作伙伴来管理日志和监控系统的高可用性,那么这个选项很有吸引力。选择这个选项的组织通常已经购买了此堆栈,并使用它来处理其整体操作中的许多异构系统。
第四种选择也是一种分层遥测方法,对于开始使用 Anthos 进行混合之旅的组织来说,这是一个推荐的方法。这种方法的理由有很多,首先是因为 Anthos 集群的平台和系统数据始终与 Cloud Monitoring 和 Cloud Logging 紧密耦合,因此管理员无论如何都需要学习 Cloud Monitoring 和 Cloud Logging 以获取最新的日志和指标。此外,它没有任何额外成本,并且是 Anthos 套件的一部分。第二个原因是,构建混合环境通常需要将应用程序迁移到混合环境,开发者习惯于与这些合作伙伴解决方案一起工作,并围绕该堆栈构建调试和运营模式。这使得它成为一个受支持的选项,可以减少将工作负载迁移到混合环境时的运营摩擦。第三个原因是建立在不同提供商之间平衡故障点的能力,并有一个备份选项。
5.1.5 服务网格日志
如第四章所述,Anthos Service Mesh 是一个可选组件,但包含在 Anthos 平台中。它是开源 Istio 的扩展和受支持版本,包含在 Anthos 中并由 Google 支持。Google 扩展的部分能力是将注入您的 Pod 的边车代理的遥测数据直接上传到 Google Cloud 的 Cloud Monitoring API 和 Cloud Logging API。然后,这些指标用于在 Google Cloud 控制台中可视化预配置的仪表板。有关更多详细信息,请参阅第三章。
将这些指标存储在 Google Cloud 上还允许您拥有关于微服务之间延迟、错误和流量的历史信息,这样您就可以对任何问题进行事后分析。您还可以进一步使用这些指标来驱动服务级别指标和 Pod 扩展策略,并识别需要优化的服务。
5.1.6 使用服务级别指标和协议
Anthos 服务网格的服务级别指标(SLIs)、服务级别目标(SLOs)和服务级别协议(SLAs)是您可以使用来构建 Anthos 部署的 SRE 实践的功能。在设计 Anthos 的运营管理流程时,考虑这些概念是必要的。
两个指标衡量服务级别:延迟和可用性。延迟是服务响应所需的时间,而可用性表示服务响应的频率。当系统从 DevOps 视角进行设计时,管理员必须考虑 Anthos 升级和扩展需求,并相应地规划,以确保它们不影响这些指标。
对于服务级别目标,您应该从最坏情况的角度考虑,而不是最佳情况,尽可能使决策数据驱动。例如,如果延迟不切实际且不影响用户体验,甚至无法发布服务。根据用户体验找到可接受的最高延迟,然后根据业务需求进行降低。教育您的业务利益相关者,接近 99.99999% 的可用性目标非常昂贵,并且通常必须达成一个实际的权衡。谷歌 SRE 书籍中提到的一个重要概念是,努力使服务足够可靠,但不超过必须的程度。您可以在 mng.bz/Al77 上找到更多关于谷歌 SRE 书籍的信息。了解 Anthos 升级、回滚和安全更新的程序和风险对于确定服务级别目标是否现实是至关重要的。
您还应该为要衡量的服务级别目标定义一个合规期。设置的 SLO 可以是任何测量周期——一天、一周或一个月。这允许负责服务的团队决定何时回滚、发布热补丁或放慢开发速度以优先修复错误。SLI 和 SLO 还使产品所有者能够向需要它们的用户提供服务级别协议,并提供现实的延迟和可用性协议。
5.2 Anthos 命令行管理
您可以使用各种命令行工具来处理 Anthos 版本的集群创建、扩展和升级,例如 gkectl、gkeadmin 和 anthos-gke。本章的目的不是取代 Google Cloud 的文档,而是总结了一些操作和需要注意的问题。
提醒:管理员集群仅用于监控和管理用户集群。将其视为类似于 GKE 的无形控制平面,不要在那里部署可能影响它的服务。
小贴士:您可以使用类似 ktx 的 kubeconfig 管理器,从 github.com/heptiolabs/ktx,它允许管理员轻松地在管理员集群和用户集群上下文之间切换。
在下一节中,我们将把段拆分为 GKE on-prem 和 GKE on AWS,因为工具和安装过程不同。
5.2.1 使用 GKE on-prem 的 CLI 工具
GKE 本地安装使用 VMware 的 API¹以编程方式构建管理工作站、管理集群节点和用户集群节点。持久卷由单个 VMware 数据存储或 vSAN 提供电力,网络由分布式或标准 vSphere 交换机提供。这些就像在构建 GKE 集群时 Google Cloud 提供的 IaaS 组件:因此得名 GKE on-prem。拥有管理集群、用户集群和节点池的概念反映了 GKE 的最佳实践。
当前的安装过程是下载一个名为 gkeadm 的工具,该工具创建一个管理工作站。管理集群和用户集群都是从该管理工作站安装的,如以下所述。尽管 gkeadm 的版本适用于 Windows、Linux 和 macOS,但本节将仅解释 Linux 的简略过程:
-
第一步是从云存储桶下载工具:
gsutil cp gs://gke-on-prem-release-public/gkeadm/<anthos version>/linux/gkeadm ./chmod +x gkeadm -
接下来,创建一个预填充的配置文件:
./gkeadm create config -
填写 vCenter 凭证、GCP 白名单服务账户密钥路径(在购买 Anthos 后,客户被要求提供一个服务账户,Google 将将其列入白名单以便下载镜像和其他专有工具),以及 vCenter 证书授权机构证书路径。
vCenter 证书授权机构的证书可以按以下方式下载:
curl -k "https://[SERVER_ADDRESS]/certs/download.zip" > download.zip
解压 download.zip 文件后,相关证书可以在 certs/lin 文件夹中找到。带有 .0 后缀的文件是根证书。将其重命名为 vcenter.crt,并在安装配置文件的引用中使用它。
当您创建新的用户集群或在安装过程中时,vCenter 和 F5 Big-IP 凭证以纯文本形式保存在配置文件中。保护 F5 凭证的一种方法是通过围绕 Google Cloud Secret Manager 和 gcloud 的包装。
要创建一个由 Google Secret Manager 保护的密码,请使用以下代码:
echo "vcenterp455w0rd" | gcloud secrets create vcenterpass --data-file=- --replication-policy=user-managed --locations=us-east1
要检索由 Google Secret Manager 保护的密码,请输入以下代码:
gcloud secrets versions access latest --secret="vcenterpass"
此秘密现在通过 Google IAM 策略得到保护,并且可以编写一个包装脚本以检索秘密,替换配置文件中的占位符,应用它,然后删除文件。
创建 Anthos 集群组件的过程正在迅速演变,对于较新版本对配置文件进行一些更改并不罕见。您可以在 mng.bz/Zova 了解最新的发布流程。
集群管理:创建新的用户集群
gkectl 命令用于此操作。一般来说,管理员应该限制他们的设置,使其包含一个管理员集群与 10 个用户集群的比例。用户集群应至少有 3 个节点,最多有 100 个节点。如前所述,新版本可能会增加这些数字。当发布新的 Anthos 版本时,您可以在相应版本的配额和限制部分中检查新的限制。
一般建议至少为至少一个集群留出一些空间,该集群可以在您的本地环境中创建。这为运维团队提供了重新创建集群并在升级或分类期间移动 Pod 的空间。
保持良好的文档,例如,哪些 IP 地址已经被分配给其他用户集群,以便可以轻松地确定不重叠的 IP 地址。考虑到用户集群可以扩展到 100 个节点,因此请为每个范围保留多达 100 个 IP 地址以保持这种可能性。
将配置文件源代码控制起来,但不要提交 vSphere 用户名和密码。将此类敏感信息提交到存储库可能会带来安全风险,因为任何有权访问存储库的人都可以获取这些登录详情。可以使用 ytt 等工具来模板化配置 YAML 并执行代码审查,您应该使用存储库扫描器来防止此类错误发生(例如,mng.bz/Rl7O)。
节点池也可以使用不同的机器形状创建,因此请正确设置它们以适应您的工作负载。这样做还可以让您对要扩展的机器类型有更细粒度的控制,并节省成本。对于生产工作负载,使用三个副本的用户集群主节点以实现高可用性,但对于开发,一个副本应该就足够了。
验证配置文件以确保文件有效。检查既包括语法检查,也包括程序性检查,例如使用 gkectl check-config 命令检查 IP 范围冲突和 IP 可用性:
gkectl check-config --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] --config [CONFIG_FILE]
在进行几次验证后,可以通过传递 —fast 标志跳过大多数耗时验证。
接下来,如果选择了捆绑式负载均衡器,则应创建 seesaw 负载均衡器。如果您在配置了集成负载均衡器选项的集群构建之前没有创建 seesaw 节点,您将在集群预检查期间收到错误。要创建 seesaw 节点,请使用 gkectl create loadbalancer 命令:
gkectl create loadbalancer --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] --config [CONFIG_FILE]
在创建新的用户集群后,请记住,对于捆绑式负载均衡的 seesaw 版本,用户随后可以按以下方式创建用户集群:
gkectl create cluster --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] --config [CONFIG_FILE]
如果配置文件已经过验证,您也可以添加 —skip-validation-all 标志。
整个用户集群过程,包括启动带有主节点和工作节点镜像的新 VMware 虚拟机并将它们加入集群,可能需要 20-30 分钟,具体取决于硬件。管理员还可以从 VMware vCenter 控制台看到正在创建的节点。
高可用性配置
在生产环境中,由于堆栈的不同部分可能会出现故障,从网络到硬件再到虚拟化层,高可用性对于 Anthos 部署是必要的。
管理集群的高可用性(HA)利用 vSphere 集群设置中的 vSphere HA 来保护 GKE 本地集群在主机故障时不会中断。这确保了管理集群节点在 vSphere 集群的不同物理节点之间分布,因此,在物理节点故障的情况下,管理集群仍然可用。
要启用 HA 用户控制平面,只需在 GKE 本地配置文件中指定 usercluster.master.replicas: 3。这将为每个用户集群创建三个用户集群主节点,消耗三倍的资源,但提供高可用 Kubernetes 设置。
集群管理:扩展
管理员可以使用gkectl CLI 来扩展或缩减节点。他们更改配置文件以设置期望的副本数量,并执行以下命令来更新节点池:
gkectl update cluster --kubeconfig [USER_CLUSTER_KUBECONFIG] --config [CONFIG_FILE]
集群管理:升级 Anthos
与任何升级过程一样,在过程中可能会出现故障。已经投入了大量努力来使升级过程健壮,包括在执行升级之前添加预检查来捕捉潜在问题。当开发升级时,Google 的每个产品团队都紧密合作,以避免 Kubernetes、ACM 和 ASM 等组件之间出现任何潜在的不兼容性。为了方便访问,将此链接添加为书签以快速访问:mng.bz/nJV8。
由于对新功能的需求,新的 Anthos 版本频繁出现,因此升级 Anthos 是一种常见活动。这也可能意味着升级到 Kubernetes 的新版本,由于 Istio 对 Kubernetes 的依赖,这会影响 Anthos Service Mesh。升级链很复杂,这就是为什么我们建议保留一些备用硬件资源,这些资源可以用来创建 Anthos 集群的新版本,然后在拆除旧版本集群之前将工作负载迁移到新集群。这个过程通过在升级失败时提供简单的回滚路径来降低升级相关的风险。在这种升级路径中,你应该在即将升级的旧集群中运行的微服务前面有一个负载均衡器,它可以引导流量从旧集群到新集群,因为它们将同时存在。然而,如果这不是一个选项,管理员可以在原地升级 Anthos 集群。
首先,咨询升级路径。从 GKE on-prem 1.3.2 版本开始,管理员可以直接升级到同一次要版本中的任何版本;否则,需要按顺序升级。从版本 1.7 开始,管理员可以将他们的管理集群保留在较旧版本上,而只需升级管理工作站和用户集群。作为最佳实践,管理员仍然应该安排管理集群的升级以保持最新。
接下来,下载 gkeadm 工具,它必须与您升级的目标版本相同,并运行 gkeadm 来升级管理工作站,运行 gkectl 来升级您的用户集群,最后升级管理集群。
在原地升级时,会创建一个具有最新版本镜像的新节点,并将工作负载从旧版本中移除并逐步转移到最新版本,一个节点接一个节点。管理员应该为物理主机计划额外的资源,以容纳至少一个用于升级目的的用户节点。完整的流程可以在图 5.11 中查看。

图 5.11 升级流程
对于命令的详细列表,请参阅mng.bz/Px7v以获取确切细节。
集群管理:备份集群
可以通过遵循mng.bz/Jl7a中找到的步骤来备份 Anthos 管理集群。建议您将其作为生产 Anthos 环境设置的一部分,定期安排备份,并在升级 Anthos 版本时进行按需备份。
通过运行备份脚本可以备份 Anthos 用户集群的 etcd,您可以在此处了解更多信息mng.bz/wPAa。请注意,这仅备份集群的 etcd,即 Kubernetes 配置。Google 还表示,这应该是最后的手段。GKE 的备份承诺将使这个过程更简单,并且最近已提供(mng.bz/X5MM)。
此过程不会备份任何特定于应用程序的数据,例如持久卷。这些应该定期使用如 Velero 等几种可用的工具之一备份到另一个存储设备。
您应该将集群备份视为与从服务器备份的任何数据相同。建议您练习从备份中恢复管理集群和用户集群,以及特定于应用程序的数据,以增强对备份和恢复过程的信心。
Google 正在为 Anthos 开发几个新增功能。其中一个即将添加的重要功能将被命名为 Anthos 企业数据保护,它将提供备份集群级配置的功能,例如自定义资源定义,以及命名空间级配置和应用数据从 Google Cloud 控制台备份到云存储桶,以及使用备份进行恢复的能力。
5.2.2 AWS 上的 GKE
GKE 在 AWS 使用 AWS EC2 实例和其他组件来构建 GKE 集群,这意味着这些不是 EKS 集群。如果用户登录 AWS 控制台,他们将只能看到管理集群和用户集群节点作为单独的 AWS EC2 实例。区分这一点与在 Anthos 中管理 EKS 集群非常重要,因为根据集群类型,分配给各个云提供商的责任不同。
GKE 在 AWS 的安装是通过 gcloud CLI 的 gcloud container aws clusters create 命令完成的。对于 Terraform 用户,以下仓库中提供了安装 Anthos 上 GKE 的示例 terraform 代码:mng.bz/71R7。此示例代码将进一步简化安装过程,并消除后续步骤中提到的堡垒主机和管理服务器需求。
安装过程是首先获取 AWS 密钥管理服务 (KMS) 密钥,然后使用 anthos-gke,它反过来使用 Terraform 生成 Terraform 代码。Terraform 是 HashiCorp 提供的基础设施即代码开源工具,用于定义计算环境的目标状态。Terraform 代码是声明性的,并使用 Terraform 提供商,这些提供商通常由云提供商如 Google、AWS 和 Microsoft 贡献,将它们的云配置 API 映射到 Terraform 代码。生成的 Terraform 代码描述了 GKE 在 AWS 基础设施将如何看起来。它具有类似于 GKE on-prem 的组件,如负载均衡器和 EC2 虚拟机,但它使用 Terraform AWS 提供商在 AWS 上实例化基础设施。您可以在 www.terraform.io/ 上了解更多关于 Terraform 的信息。
GKE 在 AWS 的架构可以在图 5.12 中看到,该图来自 Google Cloud 文档,网址为 mng.bz/mJAW。

图 5.12 GKE 在 AWS 架构
节点池的使用类似于 GKE,能够在集群内拥有不同的机器大小。
注意:要进行任何 GKE 在 AWS 的操作管理,管理员将不得不登录到堡垒主机,它是管理服务的一部分。
连接到管理服务
在执行任何管理操作时,管理员需要连接到在管理服务初始安装期间部署的堡垒主机。此脚本名为 bastion-tunnel.sh,并在管理服务安装期间由 Terraform 生成。
集群管理:创建新的用户集群
使用 bastion-tunnel 脚本连接到管理服务。连接到堡垒主机后,管理员使用 Terraform 生成一个清单,在 YAML 文件中配置一个示例集群:
terraform output cluster_example > cluster-0.yaml
在此 YAML 文件中,管理员随后更改 AWSCluster 和 AWSNodePool 规范。请确保将集群文件保存到代码仓库中,因为它将被用于扩展用户集群。
自定义资源是 Kubernetes 的扩展,用于添加额外的功能,例如用于配置 AWS EC2 实例。AWS 集群和对象以 YAML 文件的形式表示,在管理服务集群中引用 AWSCluster 和 AWSNodePool 自定义资源,这些资源解释这个 YAML 文件并根据 AWS 相应地调整资源。要了解更多关于自定义资源的信息,请参阅mng.bz/51R8。
集群管理:扩展
你可能会遇到需要额外计算能力的情况,这时你需要扩展集群。幸运的是,Anthos 节点池可以扩展集群,包括最小和最大节点数。如果你创建了一个在最小和最大节点数上具有相同计数的集群,你可以在以后更改该设置以扩展你的集群。要扩展 AWS 上的 GKE 集群,你只需要管理员通过在创建用户集群时更新 minNodeCount 并应用到管理服务中来修改 YAML 文件:
apiVersion: multicloud.cluster.gke.io/v1
kind: AWSNodePool
metadata:
name: cluster-0-pool-0
spec:
clusterName: cluster-0
version: 1.20.10-gke.600
minNodeCount: 3
maxNodeCount: 10
集群管理:升级
在 AWS 上升级 GKE 分为两个步骤,首先处理管理服务,然后是用户集群。要升级 AWS 管理服务上的 GKE,管理员必须从具有 AWS GKE 配置的目录升级 AWS 管理服务上的 GKE。然后,用户必须首先下载最新的 anthos-gke 二进制文件。接下来,用户将需要修改 anthos-gke.yaml 文件到目标版本:
apiVersion: multicloud.cluster.gke.io/v1
kind: AWSManagementService
metadata:
name: management
spec:
version: <target_version>
最后,为了验证和应用版本更改,运行以下代码:
anthos-gke aws management init
anthos-gke aws management apply
管理服务将关闭,因此无法应用对用户集群的更改,但用户集群将继续运行其工作负载。
要升级用户集群,管理员需要使用以下命令在管理服务中切换上下文,从 AWS 目录上的 GKE 切换:
anthos-gke aws management get-credentials
然后,升级用户集群的版本就像使用以下命令一样简单:
kubectl edit awscluster <cluster_name>
编辑 YAML 文件以指向正确的 GKE 版本:
apiVersion: multicloud.cluster.gke.io/v1
kind: AWSCluster
metadata:
name: cluster-0
spec:
region: us-east-1
controlPlane:
version: <gke_version>
提交此更改后,CRD 开始逐个遍历控制平面中的节点并将它们升级到 AWS 上 GKE 的最新版本。此升级过程会导致控制平面停机,这意味着集群可能无法在完成之前报告不同节点池的状态。
最后,最后一步是升级实际的节点池。相同的程序适用:管理员只需编辑 YAML 文件到所需的版本,并按照以下方式将 YAML 文件应用到管理服务:
apiVersion: multicloud.cluster.gke.io/v1
kind: AWSNodePool
metadata:
name: cluster-0-pool-0
spec:
clusterName: cluster-0
region: us-east-1
version: <gke-version>
5.3 Anthos 附加集群
Anthos 附加集群允许您查看您的 Kubernetes 集群,并由 AWS 的 Elastic Kubernetes Service (EKS)、Azure Kubernetes Service (AKS) 或任何符合规范的 Kubernetes 集群提供配置和管理。在这种情况下,集群的扩展和配置是从各自的云中完成的。然而,这些集群仍然可以通过将它们注册到 Google Cloud 并部署 Connect Agent 来由 Anthos 附加和管理,如图 5.13 所示。

图 5.13 添加外部集群(自行提供 Kubernetes)
GKE 也以相同的方式处理,可以从另一个项目附加到 Anthos 项目中,如下所示:
-
管理员必须为 EKS 或 AKS 集群生成一个 kubeconfig,然后在该生成的集群注册命令中的 gcloud 中提供该 kubeconfig。有关如何为 EKS 或 AKS 集群生成 kubeconfig 文件的 AWS 和 Azure 文档。管理员还可以使用以下模板手动生成一个,并提供必要的证书、服务器信息和服务账户令牌:
apiVersion: v1 kind: Config users: - name: svcs-acct-dply user: token: <replace this with token info> clusters: - cluster: certificate-authority-data: <replace this with certificate-authority-data info> server: <replace this with server info> name: self-hosted-cluster contexts: - context: cluster: self-hosted-cluster user: svcs-acct-dply name: svcs-acct-context current-context: svcs-acct-context -
管理员必须创建一个 Google 服务账户和一个服务账户密钥,以提供注册,如图 5.14 所示。
![05-14]()
图 5.14 为外部集群生成注册命令
-
管理员将在生成的注册命令中提供这两项内容,并在 Connect Agent 部署到外部集群后,在 Google Cloud 控制台中可见。
5.4 裸金属上的 Anthos
在裸金属上运行和管理 Anthos 通常需要在操作系统配置空间中具备额外的技能集,因为它基于在 RHEL、Ubuntu 或 CentOS 上安装 Anthos。有关在裸金属上安装和升级 Anthos 的详细步骤,请参阅第十七章。
裸金属上的 Anthos 与 VMware 上的 Anthos 类似,但在其部署模型上具有更多灵活性,且不依赖于 VMware。与在虚拟化机器上运行 Kubernetes 相比,使用裸金属上的 Anthos 的好处包括性能提升、Google 在安装所有 Anthos 组件期间提供支持,以及能够直接从 Google Cloud Marketplace 将应用程序部署到 Anthos 集群。然而,与在 VMware 上使用 Anthos 并具有自定义存储驱动程序的原生支持相比,团队将不得不管理自己的存储设备,为裸金属集群上的 Anthos 提供持久和性能良好的存储。
在为裸金属上的 Anthos 设计操作管理流程时,你必须做出几个关键决策。首先是容量规划和资源估算。与需要使用公共云资源或 VMware 资源池来配置新节点的其他设置不同,新的裸金属节点必须进行配置。如果在节点升级期间有零停机时间的要求,这需要额外的容量需求,因为在升级过程中节点总是有可能失败,从而导致容量下降。
第二点是尽可能自动化节点的先决条件安装。许多公司还需要一个基础操作系统的金盘镜像,这必须由安全团队审核,并持续更新安全补丁和最新版本。这应该集成到裸金属上的 Anthos 配置过程中,以验证与 Anthos 安装的兼容性。一个选项是设置 PXE 引导服务器,并让新配置的裸金属服务器指向 PXE 引导服务器,以将裸金属节点的操作系统安装到正确的配置。
第三点是确定在裸金属上运行 Anthos 的不同部署方式,包括独立、多集群或混合集群部署。灵活性也意味着复杂性,并且需要为不同的部署构建不同的操作模型。第十七章将更详细地介绍差异,但本章强调了在选择不同的部署模型时以下操作考虑因素:
-
独立集群部署——这种部署模型,如图 5.15 所示,将管理员集群和用户集群放在同一个集群中。在这种配置下,工作负载在具有 SSH 凭证的同一节点上运行,并且在这些节点中存储了 Google 服务账户密钥。这种配置非常适合边缘部署,因此,操作模型应该为每个新配置和部署的独立集群引入 SSH 凭证和服务账户密钥生成,以及当集群被入侵或丢失时撤销这些凭证的计划。高可用性设置至少需要五个节点。
![05-15]()
图 5.15 独立部署
-
多集群部署——这种部署模型,如图 5.16 所示,有一个管理员集群和一个或多个用户集群,类似于 VMware 上的 Anthos。这种模型具有许多优点,例如集群的管理员/用户隔离、多租户设置(即每个团队都可以有自己的集群)以及升级的集中计划。缺点是节点需求增加,高可用性设置至少需要八个节点。因此,在为多个边缘位置设置时需要更多努力,并且更适合数据中心设置。
![05-16]()
图 5.16 多集群部署
-
混合集群部署——这种部署模型,如图 5.17 所示,允许在管理集群上运行用户工作负载并管理其他用户集群。这种模型将多集群部署所需的节点数量减少到五个,以实现高可用性设置,但它与在可能包含独立集群部署中敏感数据的节点上运行用户工作负载具有相同的安全问题。使用混合集群部署可以通过安全级别对工作负载进行分层,并为需要更高安全性的工作负载引入用户集群。
![05-17]()
图 5.17 混合部署
5.5 连接网关
注册 Anthos 集群允许用户通过 UI 与他们交互,但管理员通常有一套脚本工具箱,他们使用这些脚本来通过 kubectl 命令行与集群交互。在 GKE 本地、AWS 或 Azure 上,这些集群通常只能通过管理工作站或堡垒主机访问。另一方面,GKE 用户可以使用 gcloud 并从 kubectl 生成 kubeconfig 详细信息到他们的本地机器上的集群。通过连接网关,这个问题得到了解决。
管理员可以连接到任何已注册的 Anthos 集群,并通过连接代理生成 kubeconfig,使用户能够通过 kubectl 使用这些集群。有了这个功能,管理员将不需要使用跳转主机来部署到集群上的 GKE,而是可以通过运行 gcloud 命令来生成 kubeconfig,通过 kubectl 进行连接。
设置需要模拟策略,该策略允许连接代理服务帐户模拟用户帐户,代表他们发出命令。创建模拟的 ClusterRole 和 ClusterRoleBinding 的 YAML 文件示例在此处可见:
# [USER_ACCOUNT] is an email, either USER_EMAIL_ADDRESS or GCPSA_EMAIL_ADDRESS
$ USER_ACCOUNT=foo@example.com
$ cat <<EOF > /tmp/impersonate.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateway-impersonate
rules:
- apiGroups:
- ""
resourceNames:
- ${USER_ACCOUNT}
resources:
- users
verbs:
- impersonate
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gateway-impersonate
roleRef:
kind: ClusterRole
name: gateway-impersonate
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: connect-agent-sa
namespace: gke-connect
EOF
在设置好模拟策略后,管理员必须运行图 5.18 中显示的命令来生成 kubeconfig,如图 5.19 所示。

图 5.18 获取 GKE 本地集群凭证的命令

图 5.19 通过 gcloud 生成的 kubeconfig
在此 kubeconfig 就绪后,管理员即使从本地机器也可以管理 GKE 本地工作负载,同时受到 Google Cloud Identity 的安全保护。这种方法还开启了构建将部署到不同 Anthos 集群的管道的可能性。
5.6 Azure 上的 Anthos
Anthos GKE 集群可以安装在 Azure 上,其架构由一个托管在 GCP 上的多云 API 组成,该 API 为 Azure 中的 GKE 集群提供生命周期管理功能,如图 5.20 所示。您还可以通过本章中提到的 Connect 网关访问 Azure GKE 集群。Anthos 在 Azure 上使用 Azure 原生技术,如 Azure 负载均衡器、Azure Active Directory 和 Azure 虚拟机,但通过多云 API 依赖 Anthos 来管理 GKE 集群的生命周期操作。这为在三个主要公有云和本地部署应用程序提供了一种统一的方式。

图 5.20 Anthos 在 Azure 的架构
作为先决条件,管理员必须安装 gcloud CLI。此外,管理员必须拥有以下 Azure 内置角色,如所示:
-
应用程序管理员
-
用户访问管理员
-
贡献者
下一步是创建 Azure Active Directory 应用程序、虚拟网络和集群的资源组,并授予 Azure Active Directory 应用程序必要的权限。详细的先决条件信息可以在公共文档中找到,网址为mng.bz/61Rp。
5.6.1 集群管理:创建
要创建新的用户集群,管理员必须首先设置一个带有 SSH 密钥对的 Azure 客户端:
export SUBSCRIPTION_ID=$(az account show --query "id" --output tsv)
export TENANT_ID=$(az account list \
--query "[?id=='${SUBSCRIPTION_ID}'].{tenantId:tenantId}" --output tsv)
export APPLICATION_ID=$(az ad app list --all \
--query "[?displayName=='APPLICATION_NAME'].appId" --output tsv)
gcloud alpha container azure clients create CLIENT_NAME \
--location=GOOGLE_CLOUD_LOCATION *\*
--tenant-id="${TENANT_ID}" \
--application-id="${APPLICATION_ID}"
CERT=$(gcloud alpha container azure clients get-public-cert --location=GOOGLE_CLOUD_LOCATION \
CLIENT_NAME*)*
az ad app credential reset --id "${APPLICATION_ID}" --cert "${CERT}" --append
ssh-keygen -m PEM -t rsa -b 4096 -f KEY_PATH
SSH_PUBLIC_KEY=$(cat KEY_PATH.pub)
ssh-keygen -m PEM -t rsa -b 4096 -f ~/.ssh/anthos-multicloud-key
SSH_PUBLIC_KEY=$(cat ~/.ssh/anthos-multicloud-key.pub)
接下来,管理员需要将 Azure 资源组、VNet 和子网 ID 分配给环境变量;添加 IAM 权限;并运行 gcloud 命令以创建 Anthos 在 Azure 的集群:
CLUSTER_RG_ID=$(az group show --resource-group=CLUSTER_RESOURCE_GROUP_NAME \
--query "id" -otsv)
VNET_ID=$(az network vnet show --resource-group=VNET_RESOURCE_GROUP_NAME \
--name=VNET_NAME *--query "id" -otsv)*
SUBNET_ID=$(az network vnet subnet show \
--resource-group=VNET_RESOURCE_GROUP_NAME --vnet-name=VNET_NAME \
--name default --query "id" -otsv)
PROJECT_ID="$(gcloud config get-value project)"
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:$PROJECT_ID.svc.id.goog[gke-system/gke-multicloud-agent]" \
--role="roles/gkehub.connect"
gcloud alpha container azure clusters create CLUSTER_NAME \
--location GOOGLE_CLOUD_LOCATION \
--client CLIENT_NAME \
--azure-region AZURE_REGION \
--pod-address-cidr-blocks POD_CIDR \
--service-address-cidr-blocks SERVICE_CIDR \
--vm-size VM_SIZE *\*
--cluster-version 1.19.10-gke.1000 \
--ssh-public-key "$SSH_PUBLIC_KEY" \
--resource-group-id "$CLUSTER_RG_ID" \
--vnet-id "$VNET_ID" \
--subnet-id "$SUBNET_ID"
然后,此集群应可在管理员的 GKE 控制台中使用。最后,管理员向集群添加节点池以部署工作负载:
SUBNET_ID=$(az network vnet subnet show \
--resource-group=VNET_RESOURCE_GROUP_NAME --vnet-name=VNET_NAME \
--name default --query "id" -otsv)
SSH_PUBLIC_KEY=$(cat KEY_PATH.pub)
gcloud alpha container azure node-pools create NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location GOOGLE_CLOUD_LOCATION *\*
--node-version=1.19.10-gke.1000 \
--vm-size=VM_SIZE \
--max-pods-per-node=110 \
--min-nodes=MIN_NODES \
--max-nodes=MAX_NODES *\*
--ssh-public-key="${SSH_PUBLIC_KEY}" \
--subnet-id="${SUBNET_ID}"
5.6.2 集群管理:删除
要删除集群,管理员必须首先删除属于集群的所有节点池:
gcloud alpha container azure node-pools delete NODE_POOL_NAME \
--cluster CLUSTER_NAME \
--location GOOGLE_CLOUD_LOCATION
gcloud alpha container azure clusters delete CLUSTER_NAME \
--location GOOGLE_CLOUD_LOCATION
在 Anthos 在 Azure 上准备好自动扩展后,管理员控制成本和管理每个集群的最小资源需求变得容易。建议使用像 HashiCorp Vault 这样的安全设备来存储 SSH 密钥以进行检索和轮换。
摘要
-
最佳的学习方式是通过实践,最好的建议是尝试在各个提供商上构建集群,以了解可用的优化以及管理员在日常管理 Anthos 操作时需要执行的操作。这是构建持续改进过程的关键,因为 Anthos 经常发布新功能,以使 Kubernetes 集群管理更加简单和快速。
-
我们介绍了如何使用 Google Cloud 控制台操作和管理各种 Anthos 集群类型的工作负载。
-
您可以了解 Anthos 部署中可用的各种日志记录和监控选项以及需要考虑的标准。
-
你现在已经了解了如何通过命令行操作和管理各种类型的 Anthos 部署,以及 Google Cloud 与部署之间发生什么样的通信。
-
你学习了如何在混合环境中升级、扩展以及设计 Anthos 的操作管理流程。
^ (1.) 除了 VMware,还可以在裸金属上使用 Anthos。这是第十七章讨论的主题。
6 将所有内容整合
Onofrio Petragallo
本章涵盖
-
Anthos 组件如何提供独特且强大的开发者体验
-
使用不同的 Anthos 产品部署应用程序
-
使用策略执行进行管理和一致性
-
使用 Anthos Service Mesh 观察和保障应用程序
正如我们在前面的章节中看到的,Anthos 是一个现代应用程序平台,为云和混合环境提供一致的开发和运营体验。在本章中,您将了解平台的主要层和主要功能。图 6.1 展示了 Anthos 组件和功能以及它们如何跨越您的环境提供 Anthos 的功能,从基础设施管理到支持应用程序开发。

图 6.1 Anthos 组件和功能
6.1 应用程序开发
对于开发者来说,Anthos 提供了一个基于 Kubernetes 的最先进的容器管理平台。开发者可以使用这个平台快速轻松地构建和部署现有的基于容器的应用程序和基于微服务的架构。对开发者而言的关键好处包括以下内容:
-
使用 Anthos Config Management 进行配置以及代码的 Git 兼容管理和 CI/CD 工作流程
-
使用 Anthos Service Mesh 和 Cloud Monitoring 以及 Cloud Logging 提供的无代码抽象层,以实现统一的可观察性
-
使用 mTLS 和节流提供无代码的服务保护
开发者可以使用他们偏好的 IDE 开发现代应用程序:例如,他们可以使用 IntelliJ (www.jetbrains.com/idea/) 或 Visual Studio Code 来实现可在 Anthos 上运行的云原生应用程序。
Google Cloud 提供了 Cloud Code (cloud.google.com/code),这是一个 IntelliJ、Visual Studio Code 和 Google Cloud Shell 的插件,允许您获得一个与 IDE 完全集成的 Kubernetes 开发和调试环境。得益于 Cloud Code,您可以直接从 IDE 中创建和管理集群,并且可以轻点几下将代码部署到 Anthos 集群或 Cloud Run for Anthos。您还可以执行以下操作:
-
使用 Cloud Code 在 IDE 中调试代码,利用内置的 IDE 调试功能
-
查看您的 Kubernetes 集群和 Cloud Run 服务的底层资源和元数据。您只需点击一下即可对这些资源采取行动:您可以获取描述、查看日志、管理密钥或直接进入 Pod 的终端。
-
在与 Google Cloud 配置文件交互时,IDE 特性包括代码补全、内联文档、代码检查和代码片段的即插即用支持。
在底层,IDE 的 Cloud Code 使用流行的工具,如 Skaffold(skaffold.dev/)、Jib(github.com/GoogleContainerTools/jib)和 kubectl(mng.bz/Nm9X),以实时提供关于您代码的持续反馈。
6.2 应用程序部署
一旦您的应用程序开发完成,您可以为全面的应用程序测试和部署重用您喜欢的 CI/CD 工具。Google Cloud 提供了一些云原生工具,允许您加快构建、测试和发布应用程序的速度。
6.2.1 Cloud Source Repositories
Cloud Source Repositories 是由 Google 管理的 Git 仓库(见cloud.google.com/source-repositories)。Git(git-scm.com*)是一个免费、开源、分布式版本控制系统,旨在以速度和效率处理从小到非常大的项目。使用 Cloud Source Repositories,您可以免费访问无限数量的私有仓库,以您想要的方式组织代码。将 GitHub 或 Bitbucket 仓库的代码镜像到此处,以使用强大的代码搜索、代码探索和诊断功能。
图 6.2 显示了 Google Cloud 控制台的第一页,我们可以选择创建一个新的仓库或连接现有的一个。

图 6.2 从 Google Cloud 控制台连接现有的 Git 仓库
假设我们想要创建一个新的仓库,图 6.3 显示了项目“onofrio”内 Git 仓库的列表视图。“hello-world”是在项目内部创建的新 Git 仓库。

图 6.3 Git 仓库列表
图 6.4 显示新仓库的内容,示例.py 文件。

图 6.4 仓库根视图
如果我们点击单个文件,我们可以看到文件的内容,如图 6.5 所示。

图 6.5 文件内容视图
使用 Cloud Source Repositories,您可以通过内置的持续集成集成快速获得代码更改的反馈。当您将更改推送到 Cloud Source Repositories 时,您可以轻松配置触发器,以自动使用 Cloud Build 进行构建和测试。

图 6.6 使用正则表达式的文件搜索
您还可以使用强大的正则表达式在多个目录中进行搜索,如图 6.6 所示。正则表达式(regex)允许您细化您的搜索或在项目、文件和代码仓库中进行单一的目标搜索。
6.2.2 Cloud Build
Cloud Build (cloud.google.com/build) 是一种在 Google Cloud Platform 基础设施上运行构建的服务。Cloud Build 可以从各种仓库或云存储空间导入源代码,按照您的规格进行构建,并生成如 Docker 容器或 Java 存档等工件。使用 Cloud Build,您可以通过 Google 的全球网络访问连接的机器,从而显著减少应用程序的构建时间。您可以在高 CPU 虚拟机上运行构建,或缓存源代码、镜像或其他依赖项,以进一步提高构建速度。图 6.7 显示了 Cloud Build 中的构建历史。

图 6.7 构建历史
从 Git 仓库拉取请求进行构建、测试和部署的过程很简单。您可以在 Google Cloud 控制台上设置一个触发器,当您将更改推送到 Cloud Source repository、Bitbucket 或 GitHub 时,自动创建、测试或部署源代码。图 6.8 显示了如何将 Cloud Build 与现有的 Cloud Source repository 集成。在仪表板中,您可以找到 Cloud Source Repositories 上的所有 Git 仓库。您可以通过点击“添加触发器”来创建一个触发器,如图 6.8 所示。

图 6.8 从现有仓库添加触发器
在选择仓库后,您可以创建一个触发器来构建软件。如图 6.9 所示,带有“prod”标签的触发器将在仓库中进行推送操作时构建。

图 6.9 触发器配置
对于每个构建,您都可以看到所有日志的执行详情,如图 6.10 所示。

图 6.10 构建执行详情
Cloud Build 通过允许您识别软件包漏洞来帮助您保护容器。您可以为 Ubuntu、Debian 和 Alpine 自动运行软件包漏洞扫描。
一旦构建了容器化应用程序,您可以通过 Anthos 将其部署到多个云平台,作为 CI/CD 管道的一部分。Cloud Build 包含预装了语言和工具的构建器镜像。
在将构建任务发送到 Cloud Build 之前,您也可以在开发机器上本地运行构建。您可以在本地机器上使用本地开源构建器进行构建和调试。
6.2.3 艺术品注册库
一旦构建了容器化应用程序,Artifact Registry (cloud.google.com/artifact-registry) 提供了一个单一的位置,您的团队可以从这里管理 Docker 镜像,执行漏洞扫描,并使用细粒度访问控制来决定谁可以访问什么。当您将代码提交到 Cloud Source Repositories、GitHub 或 Bitbucket 时,您可以自动创建和推送镜像到私有仓库。
Artifact Registry 允许您在 Linux 发行版中扫描 Docker 容器中的软件包漏洞。您还可以在 Google Cloud 控制台 Web 界面中通过单点点击添加和删除镜像标签,以及执行以下任务:
-
创建触发器以自动保存您的构建
-
基于代码或存储库中的标签更改创建容器
-
从 Google Cloud 控制台搜索所有以前的构建
-
查看有关构建的信息,例如触发器、来源、步骤和日志
6.2.4 Google Cloud 市场 place
除了您开发的应用程序外,您还可以部署由 Google 合作伙伴和供应商在 Google Cloud Marketplace 上提供的现成市场应用程序(cloud.google.com/marketplace*)。您可以在 Google Cloud 上找到经过 Google Cloud 审查的集成解决方案,以满足您所有的 IT 需求。得益于与 Anthos 的紧密集成,您可以选择可以在本地和多云环境中部署的解决方案和应用程序。使用 Google Cloud Marketplace 可以加快您和您的团队获取解决方案的过程。如果 Google 已经是您的首选合作伙伴之一,您可以在无需联系产品供应商的情况下进行购买。您可以通过与 Google Cloud 集成部署来构建可扩展和可重复的采购流程,而无需单独联系产品供应商。有关 Anthos 的容器化和现成应用程序及解决方案的部署方式的所有详细信息,请参阅第十四章。
6.2.5 为 Anthos 迁移
如果您已经在本地或另一个云中的虚拟机上运行应用程序,并且希望将其部署到 Anthos 上,您可以利用专属的 Migrate for Anthos 技术(cloud.google.com/migrate/anthos). Migrate for Anthos 通过允许应用程序从虚拟机迁移到原生容器来简化并加快传统应用程序的现代化。这种独特的自动化方法允许您从虚拟机中提取关键应用程序元素,以便您可以将它们轻松地放置在 Google Kubernetes Engine 或 Anthos 集群中的容器中。Migrate for Anthos 的详细信息请参阅第十五章。
6.3 政策执行
扩展多个混合、本地和多云环境在资源管理和一致性方面增加了复杂性。Anthos 提供了一个统一的声明性模型,用于计算、网络,甚至管理云和数据中心服务。
将配置作为数据是管理这种复杂性的常见方法,允许您在版本控制下存储您混合环境的期望状态,并直接应用以获得可重复的结果。Anthos 通过 Anthos Config Management 实现了这一点,该管理工具与本地或云中的 Anthos 集群集成,允许您部署和监控存储在中央 Git 仓库中的配置更改,如图 6.11 所示。

图 6.11 使用 Anthos Config Management 应用和执行常见策略。
此方法使用核心 Kubernetes 概念,如命名空间、标签和注解,来确定如何以及在哪里将配置更改应用于您的所有 Kubernetes 集群,包括它们所在的位置。Anthos Config Management 为您的 Anthos 环境提供以下优势:
-
真实、控制和管理的单一来源
-
在所有集群上一步式部署
-
丰富的继承模型以应用更改
-
使用 Policy Controller 进行高级政策执行和控制
您可以在第十一章和第十三章中找到有关 Anthos Config Management 的所有详细信息。
6.4 服务管理
正如我们在第四章中看到的,Anthos Service Mesh 通过提供以下功能和服务的以下功能来管理您的服务网格环境:
-
您 mesh 的 GKE 集群内所有流量的服务指标和日志将自动导入 Google Cloud。
-
它在 Anthos Service Mesh 仪表板中自动生成深入的遥测数据。
-
一目了然地了解服务之间的服务关系——了解谁连接到每个服务以及它们依赖哪些服务。
-
通过 Anthos Service Mesh 证书授权机构(Mesh CA)保护服务之间的流量,自动生成和轮换证书,以便您能够轻松地使用 Istio 策略启用 TLS 身份验证(mTLS)。
-
快速查看您服务的通信安全状态,以及与其他服务的关联关系。
-
深入了解您的服务指标,并使用 Cloud Monitoring 将它们与其他 Google Cloud 指标结合使用。
-
通过服务级别目标,您可以清晰地了解您的服务健康状况,这使您能够轻松定义和发送关于您的服务健康标准的警报。
摘要
-
Anthos 组件为开发者提供所有开发和应用其应用程序所需的工具。
-
Anthos 应用程序开发功能包括 Cloud Code,它是 IntelliJ、Visual Studio Code 和 Google Cloud Shell 的插件。
-
可以使用各种组件来部署应用程序,包括使用 Cloud Source Repository 和 Cloud Build 进行版本控制,以构建源代码。
-
政策执行为多个云提供商和混合云环境提供管理和一致性。
-
Anthos Service Mesh 提供服务指标和日志,以传达安全状态和健康状况。
7 混合应用程序
贾森·奎克
本章涵盖
-
高可用应用程序
-
地理上分布式的应用程序
-
混合多云应用程序
-
受法律监管的应用程序
-
必须在边缘运行的应用程序
在现实世界中,应用程序受到诸如数据本地性要求、资源限制、无法保证稳定连接到云的情况(例如在棒球场、建筑工地或战斗机上)等规则的约束,需要在边缘进行低延迟计算以避免大量数据传输。应用程序必须可用,并能在区域灾难或云服务中断中生存。
然而,仍然存在运行与 Kubernetes 平台提供的一致性和稳定性相同的应用程序的需求。因此,像 Anthos 这样的解决方案被设计出来,为这类应用程序创建一个符合规定的分布式云平台。
在本章中,我们将探讨这些不同的情况,并展示涉及使用 Anthos 及其产品套件的各种架构,以支持这些类型的应用程序。
7.1 高可用应用程序
这类应用程序必须每天 24 小时、每周 7 天运行。管理交易的金融机构、医疗保健应用程序和交通管理只是少数几个在短时间内不可用就会影响现实世界应用的事例。
在 Google Kubernetes Engine 中,您可以在一个区域内创建跨可用区的集群。这种做法在区域内某个可用区发生故障时提供保障——其他可用区仍在运行应用程序。Kubernetes 调度器随后会在其他活跃的可用区上的节点上启动额外的副本,以满足 Kubernetes 配置中定义的副本要求。
然而,如果整个区域或整个云服务提供商都宕机了怎么办?福布斯杂志上的一篇文章(mng.bz/DZa0)提到了一个场景,其中一家银行客户希望使用单一云服务,而监管机构担心在故障期间会发生什么。客户估计在云服务中断期间最多会有两小时的停机时间,但该计划被监管机构拒绝,因为它不是一个可行的选择。
在这种情况下,公司可能需要跨越多个云和区域,但这样做会引入管理多个云服务提供商的复杂性和开销,同时还需要在他们的运营、开发和安全管理上具备双倍的技能集。
使用 Anthos,公司可以在一个统一的部署、扩展、安全和开发模式上标准化 Kubernetes,同时仍然能够利用多个云服务提供商的可用性,并在区域和可用区之间迁移工作负载。
7.1.1 架构
图 7.1 所示的设置很简单:安装 Anthos GKE、AWS 上的 GKE 和本地 GKE,并将它们全部包含在一个服务网格中。这样的设置不仅能在区域级别提供高可用性,还能在云服务提供商级别提供高可用性。

图 7.1 多云可用性与服务网格连接
注意,这种结构假设应用只需可用,但不一定需要从互联网上可访问。这种区别很重要,因为即使是在极其不可能的情况下,某个云服务提供商出现严重故障,这种架构也能生存。即使 Anthos 集群无法在有限时间内访问 Google Cloud API,它们仍然可以继续运行。
7.1.2 优势
在所有三个云中安装托管 Kubernetes 服务可能看起来很简单,但每个云都有不同的流程、选项和最佳实践。可用的 Kubernetes 版本在云服务提供商之间也有所不同。通过使用 Anthos,这些问题由幕后工作的 Google 工程师处理,确保一切在不同的云上都能正常工作。例如,Workload Identity 可以在混合云和多云环境中部署,以提供统一的身份验证框架。这种情况提供了真正的多云托管服务的感觉,客户对 Google 说:“把我的预算拿去,帮助我在任何地方管理我的集群,甚至是在你的竞争对手的服务上。”
7.1.3 局限性
这样的应用通常需要一个地方来持久化状态,这就会对提供商产生依赖,除非组织选择在云上托管自己的数据解决方案。随着 Kubernetes 原生数据库(如 CockroachDB)的出现,这些数据库可以部署在多个集群中,或者使用 MirrorMaker 在多个集群中的 Kafka 部署之间复制消息,这个问题开始有了稳健的解决方案。
Anthos 不管理构建集群所使用的底层网络、存储和计算资源,组织仍然需要管理网络并确保在混合云和多云环境中存储和计算的可用性。这全部关乎 Kubernetes API,并使其在整个组织中的任何表面上对开发者可用——这是一个与竞争对手产品不同的共享责任。
重要的是要理解,这样的架构可能不容易构建和维护,但对于有监管、财务和声誉原因需要其应用始终可用且具有灾难恢复能力的组织来说,Anthos 提供了一条通往这一目标的路径。
7.2 地理分布式应用
这些应用必须分布在全球各地,以服务全球用户。一个托管服务能够从世界任何地方的单个 IP 地址路由到最近的集群,这使得应用在全球范围内的扩展变得更加简单。
对于这种设置来说,最重要的是提供用户从他们最近的位置访问此应用程序的途径,以最小化延迟。该应用程序通常是部署到不同区域集群中的微服务的精确副本,但没有要求它跨越多个云。这与多地理数据库相结合,这些数据库可以作为 Google 的托管服务(例如 Spanner)或 CockroachDB 使用,CockroachDB 可以部署在全球范围内的多个 Kubernetes 集群中。
然而,使用 Anthos,同一个应用程序可以部署在多个区域,这为各种市场开辟了新的机遇。将这一切联系在一起的一个重要组件是 Anthos for Ingress,这是一个为分布式集群提供的云托管网关。
使用 Anthos for Ingress,所有应用程序的用户都可以通过一个任播 IP 访问它,并被路由到用户最近的集群。这种能力在零售行业中非常重要,因为客户流失已被证明与电子商务网站的延迟直接相关。
7.2.1 Anthos for Ingress 架构
Anthos for Ingress 建立在现有的 Google HTTP 负载均衡架构之上,使用 Google Cloud 存在点有效地将流量路由到最近的可用集群,如图 7.2 所示。在这种架构下,您可以在特定区域的 Anthos 集群上部署需要为不同区域的新受众提供服务的应用程序,并配置 Anthos for Ingress 将流量发送到该新区域,同时保持相同的 IP 地址和域名。

图 7.2 Anthos for Ingress 架构
任何集群都可以被指定为配置集群,并且在这个集群上部署了两个自定义 Kubernetes 对象,MultiClusterIngress 和 MultiClusterService,这只是一个 Anthos Ingress 控制器的集中配置存储,供其读取。
Anthos Ingress 控制器是一组 Compute Engine 实例,这些实例位于用户控制之外的多个 Google Cloud 区域,并由 Google 管理。这些实例必须放置在最近的 Google 存在点,以便根据 Anthos 集群(这些集群是同一 Anthos 舰队中的成员)和 Pod 可用性做出路由决策¹。
Anthos for Ingress 的关键概念是使用网络端点组(NEGs)。NEGs 是一组后端端点或服务,可以在 Anthos 集群上部署。如图 7.2 所示的 Anthos for Ingress 服务中的 Compute Engine 实例根据服务的可用性路由到正确的 NEG。
要了解更多关于 Anthos for Ingress 网络的信息,请参阅第十章。
7.2.2 Anthos for Ingress 的优势
创建负载均衡器以将流量从也了解每个集群服务可用状态的存在点路由到集群是一项复杂任务。这个过程将问题分解为单个集群问题,因此开发者可以专注于构建更多功能,并知道它们可以以标准化的方式在全球范围内部署,并且用户可以以低延迟访问。
7.2.3 Anthos 的入口限制
目前,Ingress for Anthos 仅限于 Anthos Google Kubernetes Engine 集群,不支持 GKE on-prem 或 GKE on AWS 集群。然而,可能存在一个同时支持 GKE on-prem 集群的解决方案——使用 Traffic Director 可能是一个可能的解决方案。
7.3 具有互联网访问的混合多云应用
一些企业已经投资于远程数据中心或采用多云策略,这使得 Anthos 成为适合他们的产品。然而,当将他们的服务暴露给公共互联网时,他们需要保护这些应用,以防止恶意行为者干扰其可用性和延迟。Anthos 的入口限制之一是这些集群必须在 Google Cloud 上,但它们还需要路由到部署在私有和公共云中的应用。因此,他们可以使用 Traffic Director,它可以将流量路由到混合多云架构中的集群。
7.3.1 Traffic Director 架构
Traffic Director 架构看起来与 Anthos 的入口设置相似,但关键区别在于所有服务都必须在 Service Mesh 中,Traffic Director 才能工作。有关 Service Mesh 的更多详细信息,请参阅第四章。图 7.3 概述了使用 Traffic Director 路由混合应用的方法。

图 7.3 混合应用的 Traffic Director 架构
在图 7.3 中,GKE on-prem 集群提供后端服务,用于与 Traffic Director 一起使用。然后,Traffic Director 将 Google Cloud 负载均衡器引导到将流量路由到 GKE on-prem 集群。这种范式也适用于其他云上的 Anthos 集群。
7.3.2 Traffic Director 的优势
Traffic Director 允许使用 Google Cloud 负载均衡器作为混合应用的入口,并且在这个过程中,可以使用云原生服务,例如 Google Cloud Armor (cloud.google.com/armor), Cloud CDN (cloud.google.com/cdn), Identity-Aware Proxy (cloud.google.com/iap), 以及托管证书 (mng.bz/lJPz).
所有进入应用中的交通,无论服务托管在何处,都将通过一个谷歌接入点进入谷歌云负载均衡器,然后通过由流量导演编程的 Envoy 代理进行代理,连接到服务网格中的服务。该服务可以托管在本地或多个云中,但通过服务网格来识别。通过使用这些服务,本地混合应用可以免受拒绝服务(DDoS)攻击的保护,这对于混合应用来说可能是一个问题。
如果应用不在谷歌 Kubernetes Engine 上运行,流量导演还可以将流量引导到谷歌计算引擎。流量导演还可以用于在云服务和本地服务之间分割流量,以帮助服务从本地迁移到云,而无需停机。
7.3.3 流量导演的限制
在图 7.3 中,中间代理部署在托管实例组上,根据来自外部负载均衡器的流量进行扩展,然后再将其转发到本地 GKE 集群。这种额外的计算成本由应用所有者承担。
7.4 受法律监管的应用
一组应用属于高度监管的行业,这些行业受到数据本地性限制的约束。这些行业的列表包括金融机构、医疗保健提供者、制药公司和政府机构。
这类应用需要持续的监控和复杂的审计和安全策略,这些可以通过 GKE 本地、Anthos 配置管理、Anthos 服务网格和 VPC 服务控制来辅助实现。
7.4.1 架构
VPC 服务控制允许管理员限制对某些谷歌云 API 的访问,仅允许特定的 IP 地址、身份和客户端设备。这些 API 包括 gkehub.googleapis.com、gkeconnect.googleapis.com、meshca.googleapis.com 和 containerregistry.googleapis.com,它们是 Anthos 提供中使用的 GKE Hub、GKE Connect、Anthos 服务网格和容器注册服务。此过程使用 BeyondCorp (cloud.google.com/beyondcorp),这是一个由谷歌云推广的概念:信任应该建立在身份上,而不是网络,网络内部使用零信任策略。这使用户能够从任何受信任的位置安全地工作,而无需 VPN。参见图 7.4 以了解设置的可视化。

图 7.4 带有 VPC 服务控制、ACM 和 ASM 的受监管应用
企业可以将 Anthos 集群配置为从本地托管的仓库读取配置管理,在一个位置设置基于角色的访问控制,并通过持续同步传播此设置。通过部署 Anthos Config Management 的 Policy Controller,管理员和安全团队可以定义策略以限制未经批准的容器注册库的使用,防止创建特权 Pod,并定义只读操作系统文件系统。要详细了解如何操作,请参阅第十三章。
使用 Anthos Service Mesh,管理员可以强制所有 Pod 之间的相互 TLS 通信,并定义哪些 Pod 可以相互通信——而且仅限于彼此,没有其他。这种限制防止了对敏感数据的未授权访问,并在系统上部署了恶意 Pod 的情况下防止数据泄露。欲深入了解此主题,请参阅第四章。
7.4.2 优势
上一节中提到的所有服务都是为了特定目的而构建的,并将安全性视为其最高考虑因素。例如,如果 Anthos Config Management 与仓库断开连接,最后同步的策略仍然有效。所有组件也都经过测试,以确保它们可以相互工作,并且任何问题都可以通过 Google 支持快速解决。
此架构也具有可扩展性和自动化能力,因此可以创建新的本地监管集群,将其连接到相同的 ACM 和 ASM 工件,并从已经完成的工作中受益。
7.5 必须在边缘运行的应用程序
边缘设备对不同公司和业务用例意味着不同的事情。例如,电信边缘用例将涉及 5G 能力的计算需求。请参阅第八章,了解 Anthos 如何实现这一用例的详细情况。
边缘设备还可以由零售商和远程制造站点使用,在这些地方,应用程序可以部署得更靠近用户,以提供低延迟体验,同时提供高性能计算。一个例子是在比赛进行时直接在体育场计算棒球比赛的统计数据,并将这些统计数据实时传递给解说员和观众。这是美国职业棒球大联盟决定在每个棒球场使用 Anthos 在云中以及本地处理和分析数据背后的驱动力(见mng.bz/Blyq)。
这些应用程序必须在资源需求低且不依赖于持续互联网连接的边缘设备上运行。最大的问题与通过空中部署软件的最新版本到这些边缘节点有关。Anthos 在边缘提供这种能力,同时仍然允许开发人员以云原生的方式统一部署他们的应用程序,并相信由于 Kubernetes 的合规部署,他们的应用程序将以与云相同的方式运行。
7.5.1 架构
图 7.5 所示的架构代表了未来的零售商店,顾客可以在没有任何收银员的情况下购物。零售商仍然可以通过视频安全地监控购买,通过商店中的应用程序进行交易,以及识别交通热点,确定何时补货商品,并在提供实时低延迟体验的同时遵守隐私法规。

图 7.5 Anthos 边缘零售架构
对于此类用例,将使用许多机器学习模型用于盗窃检测、库存不足检测、推荐和确定交通热点。例如,可以使用 RetailNet 在零售店中进行人数统计和热点检测,参考此处:mng.bz/dJ9z。为此设置所需的是一个可以持续训练和更新模型,并在边缘以高性能计算进行推理的可靠部署方式。如图 7.5 所示,您可以使用 Anthos on bare metal 来实现这一点。将流媒体视频数据回传到云中进行推理需要大量带宽,并导致延迟,从而降低商店的实时体验。
然后,可以将汇总和匿名化的数据发送回云中,并通过 Kubeflow 进行模型训练,然后更新并在本地再次部署,创建一个反馈循环,以持续更新和增强模型的准确性。
7.5.2 优势
一个关键的好处是由于直接访问硬件并跳过虚拟机许可证的成本,边缘应用程序的性能得到了提升。Anthos on edge 1.9+还可以使用私有镜像库而不是 gcr.io 来拉取容器镜像,这样它就可以完全断网运行。
7.5.3 限制
没有虚拟化层,节点扩展需要您安装新的硬件节点并将它们连接到裸金属设备的集群。
摘要
-
不同的 Google Cloud 和 Anthos 服务在可用性、地理分布、受监管行业和边缘计算的不同用例中发挥着重要作用。许多企业需要这些不同的用例来丰富他们的数字产品,并可以使用规定的架构来实现这一点。
-
使用 Anthos,公司可以采用统一的部署、扩展、安全和开发模式来标准化 Kubernetes,并保持跨区域和可用区迁移工作负载的能力。
-
像工作负载身份这样的解决方案可以部署在多个和混合云中,以提供统一的身份验证框架。
-
Anthos Ingress 允许您创建负载均衡器,将流量从存在点路由到集群,这允许以标准化的方式在全球范围内部署功能,并使用户能够以低延迟访问。
-
Traffic Director 允许使用 Google Cloud 负载均衡器作为混合应用程序的前端,并使用服务网格的一部分云原生服务。
-
VPC 服务控制允许管理员限制对特定 Google Cloud API 的访问,仅限于特定的 IP 地址、身份和客户端服务。
-
Anthos on the edge 通过直接应用访问硬件来提高应用程序的性能,从而绕过虚拟机许可证的成本。
^(1.)请参阅第二章以了解舰队的定义。
8 在边缘和电信世界工作
Giovanni Galloro
本章涵盖
-
电信网络功能向云原生网络功能的演变
-
Edge 应用场景
-
支持电信和边缘工作负载的 Anthos 特定功能
-
Google 分布式云边缘
本章主要介绍如何使用 Anthos 作为边缘和电信工作负载的启用平台,这些工作负载分为以下两类:
-
云原生网络功能 —电信网络功能的演变,无论是已经虚拟化还是仍以物理设备部署,向容器化工作负载发展,以实现更高的效率、性能和管理便捷性。这一演变也将由新的 5G 相关网络功能驱动。
-
新的边缘应用—将在边缘位置、靠近最终用户处部署的工作负载,以减少延迟并启用新的应用类型,如自动驾驶、智能城市、智能视频监控、增强现实、虚拟现实以及远程医疗/手术。通常此类应用将受益于并由 5G 网络提供支持,在很大程度上将以容器化工作负载的形式部署。
8.1 电信应用演变
在本节中,您将找到电信网络功能向网络功能虚拟化和云原生网络功能演变的回顾。
8.1.1 网络功能虚拟化简介
传统上,网络运营商通常在专用的、专有的硬件设备上实现网络功能。从 2010 年代中期开始,随着电信运营商考虑虚拟化其网络功能,网络功能虚拟化(NFV)的概念出现,遵循了导致 IT 服务器虚拟化的相同模式,将多种网络设备类型整合到行业标准的大批量服务器、交换机和存储中,以降低成本并提高效率、敏捷性和弹性。
一种趋势开始将网络设备转化为虚拟网络功能(VNFs):通过虚拟机管理程序在行业标准 x86 服务器上部署的虚拟机。如图 8.1 所示,NFV 架构的三个主要工作域如下:
-
虚拟化网络功能(VNFs**)—符合 x86 规范的虚拟机版本的网络设备
-
网络功能虚拟化基础设施(NFVI**)—构建托管虚拟网络功能的硬件(服务器、存储、网络设备)和软件组件(虚拟化软件)
-
管理和编排(MANO**)—支持基础设施虚拟化和虚拟网络功能生命周期管理及编排的物理或软件资源

图 8.1 高级 NFV 架构框架
8.1.2 NFV 用例
作为此倡议的一部分创建的一些虚拟化网络功能,其采用程度不同,如下所示:
-
vCPE (家庭和企业 CPE [客户场所设备] 的虚拟化)—将路由器引入运营商网络。采用这种方法,高级路由和网络功能从传统的服务提供商在企业场所或消费者家中部署的接入路由器转移到运行在运营商自己的 NFVI(网络功能虚拟化基础设施)上行业标准硬件上的 VNFs。客户的本地设备被更简单的硬件所取代。
-
vPE (PE [提供商边缘] 路由的虚拟化)—在此方法中,部署在服务提供商边缘的路由器,通常与部署在客户场所的路由器相连,也被虚拟化。
-
vEPC (演进分组核心) 虚拟化—虚拟化移动核心网络和 IP 多媒体子系统的网络功能:移动管理实体、服务网关和分组数据网络网关。
-
vCDN—CDN(内容分发网络)的虚拟化。本用例旨在虚拟化通常在本地部署的第三方 CDN 设备。
-
vRAN—无线接入网络(RANs)中移动基站的虚拟化最初被认为是 NFV 的一个用例,主要是因为移动基站占移动网络总拥有成本和能耗的大部分。这种方法在 NFV 中并没有有效实现,但获得前面描述的容器化工作负载的好处以及需要与 5G 相关的新的无线网络功能的目标正在推动这些功能的转型到 CNFs(云原生网络功能)。
8.1.3 向云原生网络功能的演进
电信运营商和网络功能供应商正在考虑基于容器的云原生网络功能,作为 VNFs(虚拟网络功能)的演进,以充分实现上述 NFV(网络功能虚拟化)的好处,并增加云原生应用在可移植性、敏捷性、可管理性和效率方面的改进。
云原生计算基金会(CNCF)内部的各项倡议旨在支持电信运营商(和网络供应商)获得云原生技术所宣称的好处。这些倡议主要由电信用户组(github.com/cncf/telecom-user-group)领导,该用户组产生了各种资产,包括存储库中可用的白皮书和以下关于云原生网络功能的定义:
云原生网络功能(CNF)是一个实现网络功能的云原生应用。一个 CNF 由一个或多个微服务组成,并已使用云原生原则开发,包括不可变基础设施、声明性 API 和“可重复部署过程”。
8.2 新边缘应用
下文包含了对利用 5G 网络更高带宽和更低延迟的新边缘应用特性的描述。
8.2.1 5G 作为新边缘应用的推动者
5G 网络的特点,包括其更大的连续频谱、更先进的无线电天线技术(大规模 MIMO)、更好的调制方案以及核心和 RAN 之间信号流的变化/优化,提供了具有显著更高带宽和更低延迟的网络能力。电信服务提供商和应用程序/数字服务开发者正在寻求利用这些特性,在将会有更多设备连接并且将以非常高的速度交换信息的应用中使用,从而实现改进的场景:自动驾驶、智能城市、智能工厂、智能视频监控、增强现实、虚拟现实和远程医疗/手术。
为了满足这些要求,工作负载将在许多情况下部署在边缘位置,靠近终端设备或用户,以进行近乎实时的数据处理和分析,使智能设备能够在不将数据发送到云端并返回的情况下进行操作和响应。这类应用将主要作为容器化工作负载部署。通常,5G 将主要基于软件定义,继续 NFV 开始的转型;将需要进一步的自动化,因为其将处理的速度和体积;并将基于开源软件。
8.2.2 边缘计算
边缘计算将使应用能够快速响应,提供近乎实时的洞察,减少对连接到中央数据中心或云的网络依赖,并减少需要集中传输的数据量。Gartner 预测,到 2025 年,75%的企业生成数据将在传统的集中式数据中心或云之外创建和处理(见mng.bz/rdDE)。
如图 8.2 所示,边缘基础设施将在广泛分布的位置部署,在许多情况下,其规模小于中央数据中心,如下所示:
-
电信边缘—电信运营商的小型数据中心、接入点和网络机柜
-
公共云边缘—云提供商/全球广播商的接入点和 CDN 边缘
-
企业边缘—企业/终端用户的分支机构、零售店、仓库和工厂

图 8.2 边缘部署
计算节点数量通常会增长,将出现需要具有管理数以万计的计算集群的能力的中央管理平面。
8.2.3 边缘应用示例
以下是一些应用和用例的示例,这些应用和用例将利用部署在边缘位置的优势,并通过本地执行 AI 模型对图像、视频、音频和其他类型的数据进行分析和预测:
-
预测性维护—在现场分析制造工厂和机器数据,以预测故障发生之前的情况,并优化正常运行时间和维护团队的工作
-
制造质量检查—分析装配线上的产品图片和视频,以检查是否符合质量标准
-
工人安全—通过图片和视频分析正确的安全措施实施和安全设备的使用
-
诊断服务和患者监测—使用部署到边缘的计算机视觉解决方案处理图像,这可以提高诊断准确性和检查效率
-
零售店的队列和货架管理—分析视频流以检查排队人数或货架上的商品可用性,以及打开现金收银机或相应地补充商品
-
自动驾驶汽车和工业车辆—为自动驾驶车辆摄取和收集的数据提供低延迟处理
-
通过 AR/VR 进行制造工人指导和培训—在边缘部署的 AI 模型,具有物体检测和识别、实时捕获等功能
-
物流跟踪—通过图像和视频识别运输中的包裹、物品、托盘和车辆,并更新跟踪系统的 AI 模型
-
库存管理和生产计划—通过图像对资产状态进行近实时分析,为生产和供应链履行提供输入
8.3 Anthos 作为边缘和电信工作负载的平台
在本节中,我们将讨论 Anthos 如何提供基础支持边缘 Anthos 部署和电信工作负载的执行。我们还将深入了解谷歌为此目的设计的特定解决方案。
8.3.1 Google 分布式云边缘
如图 8.3 所示的 Google 分布式云边缘(GDCE),是谷歌提供的一项全面管理解决方案,旨在支持电信虚拟化和云原生网络功能以及边缘应用程序,包括软件、操作系统和硬件(服务器和 TOR 网络交换机),这些都在谷歌管理的机架上。它基于 Anthos 在裸机(在第十七章中详细描述)上,并且可以部署在前述章节中描述的以下站点类型:
-
公共云边缘—谷歌边缘位置
-
电信边缘—由电信提供商拥有
-
企业边缘—由最终客户拥有(例如在零售店、工厂车间、分支机构和大体育场)

图 8.3 Google 分布式云边缘高级架构
GDCE 为用户提供车队管理功能,以管理所有硬件和软件资产,并通过在裸机上的 Anthos 功能支持容器化工作负载和虚拟机。
GDCE 还为用户提供 VPN 连接到 GCP,使用户能够与在客户 VPC 中运行的其他应用程序和其他 GCP 服务进行交互。为了服务高性能和低延迟工作负载,GDCE 还提供了一些高网络性能特性,如 SR-IOV 和 DPDK。谷歌云负责运营和管理底层基础设施,将云体验扩展到客户现场。
Google 提供计算、网络和存储硬件。这些硬件被运送到目标位置并由 Google 管理。Google 运营团队远程管理和监控 Google 设备。
客户需要在目标位置指定一个联系人(客户人员的一部分,不是 Google 人员),该联系人有权访问设备并执行基本管理任务。这些包括,例如,冷启动、更换部件、在设备上运行本地诊断的能力以及常见的系统管理任务。硬件连接并运行后,用户可以使用标准的 Google API 工具使用该服务。
GDCE Kubernetes 集群由控制平面和工作节点组成。工作节点组织成节点池。控制平面托管在 GCP 的单个计算区域。工作节点是 GDCE 机架上的服务器,每个工作节点使用一个完整的物理服务器。一个机架或一组共享空间、电源、冷却和连续网络布线的机架群定义为一个 GDCE 区域。
Google 分布式云边缘容器资源模型
GDCE 的资源模型与 Anthos 和其他 Anthos 部署选项不同。在这里,您可以找到用于描述、实现和管理 GDCE 实现计算架构的容器资源列表,如图 8.4 所示:
-
区域—区域代表一组共享网络布线或单个故障域的机器。区域可以代表一个机架或放置在同一位置的多个机架。GDCE 区域资源与 GCE 计算区域不同。列出 GCE 计算区域不会返回 GDCE 区域。区域代表单个故障域。为了部署具有高可用性和容错能力的应用,并帮助保护免受故障的影响,用户需要将应用部署到与同一区域相连的多个区域。
-
机器—机器代表一个物理服务器。机器资源元数据包括它所在的机架以及其他属性和标签。机器是用户只读资源。在部署时,根据 GDCE 系统的物理位置,将机器分配到特定的区域。每个物理机器都是分布式云边缘集群中的一个节点。机器可以是其指定区域内部署的 Kubernetes 集群的一部分。
-
集群 —集群由控制平面和零个或多个节点池组成。它位于特定区域,并且只能连接来自该区域的节点池。如果用户尝试连接位于不同区域的机器节点池,操作将失败。
-
节点池—节点池是 GDCE 区域内机器的逻辑分组,用于向集群添加工作节点。
-
VPN 连接——GDCE 支持设置 VPN 连接到 GCP 项目,允许在 GDCE Kubernetes 集群上运行的工作负载直接连接到 GCP 资源。在建立 VPN 连接之前,应在集群中创建至少一个节点池。

图 8.4 Google 分布式云边缘容器资源模型
Google 分布式云边缘网络资源模型
除了 Kubernetes 集群资源、API 和默认的 Kubernetes Pod 网络之外,GDCE 还允许客户在 GDCE 区域内配置额外的网络,并将它们与客户网络连接起来,用于不同的目的。例如,在网络功能用例中,客户可能会创建一个操作、管理和维护网络以及一个信号网络,每个网络都有不同的多个子网,这些子网连接到网络功能 Pod 的次要接口。
图 8.5 描述了 GDCE 中网络模型所涉及的资源及其关系。从高层次来看,以下五种类型的资源与边缘网络配置相关:
-
网络——GDCE 区域中的虚拟网络,具有私有地址空间,可能包含一个或多个子网。网络与其他 GDCE 区域中的网络隔离。
-
子网——GDCE 网络中的第二层(VLAN)子网。子网有自己的广播域和客户分配的无类别域间路由。网络内的子网可以相互通信。GDCE 区域内不同网络中的子网无法相互通信。
-
互连——代表 GDCE 与客户网络之间一个或多个物理链接的逻辑链路捆绑。互连只能在 GDCE 站点初始化时创建。通常配置多个互连以提供高可用性。
-
互连附加——根据客户请求在互连之上提供的虚拟链接,以在 GDCE 网络和客户网络(例如,VRF)之间提供隔离的连接。通过互连附加流动的数据包将是不标记的或标记为客户指定的 VLAN ID。
-
路由器——用于在 GDCE 区域内配置网络路由功能的虚拟路由实例。例如,客户可以使用它配置 GDCE 网络与客户网络之间的互连附加上的 BGP 对等会话,或者通过 Pod 子网,以便某些 Pod 可以向 GDCE 通告前缀。默认情况下,从子网接收到的路由将被重新广播。

图 8.5 Google 分布式云边缘网络资源模型
这些资源类似于 Google Cloud 网络抽象,但有一些差异,如下所述:
-
为 GDCE 创建的所有网络资源都位于 GDCE 区域内部。GDCE 网络无法直接连接到 GCP VPC。不同 GDCE 区域内的网络也无法直接相互连接,除非客户有意将其连接。
-
GDCE 子网支持 VLAN,因此在第二层中相互隔离。
系统管理员应创建和维护所有网络资源。应用程序开发者/所有者只能查看网络资源。
8.3.2 Anthos 针对电信和边缘工作负载的功能
除了 GDCE 的具体特性外,Anthos 的功能在标准产品中也是可用的,以帮助部署、执行和管理边缘和电信工作负载。其中一些功能是专门为此目的设计的,并且主要在 Anthos 裸金属上提供,这是最适合这些工作负载的版本,也是 GDCE 的核心。其他功能,如 Anthos Config Management,虽然提供的是通用功能,但也可以适应边缘和电信应用。
Pod 的多个网络接口
常见的容器化网络功能(CNFs)需求是在默认的 Kubernetes 接口之上为 Pods 提供额外的网络接口。这通常是为了在数据平面和管理/控制平面之间保持分离,出于性能或安全原因,或者为了隔离其他原因的网络流。Anthos 通过使用 Multus CNI 插件的特定实现,在裸金属上的 Anthos 上提供此功能。
建筑学
此功能允许单个 Pod 连接到多个网络。默认的 Kubernetes 接口在 Pod 中显示为 eth0,而通过 Multus CNI 创建的额外接口默认显示为 net1、net2 等,并可进行配置。用于额外接口的 CNI 可以是以下之一:
-
IPvlan
-
MacVLAN
-
桥接
-
SR-IOV
设置
要启用此功能,用户必须执行以下三个步骤:
-
启用多网络接口。 通过将 multipleNetworkInterfaces 字段添加到 Anthos 裸金属集群自定义资源的 clusterNetwork 部分并将它设置为 true,来为 Pods 启用多网络接口,如下所示:
... clusterNetwork: multipleNetworkInterfaces: true pods: cidrBlocks: - 192.168.0.0/16 services: cidrBlocks: - 10.96.0.0/12 ... -
指定网络接口。 使用 NetworkAttachmentDefinition 自定义资源来指定额外的网络接口。NetworkAttachmentDefinition 自定义资源对应于 Pods 可用的网络。这些自定义资源可以在集群创建时的集群配置清单中指定,或者直接添加到现有的目标集群中:
apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: gke-network-1 spec: config: ‘{ "type": "ipvlan", "master": “ens224”, “mode”: “l2”, "ipam": { "type": "whereabouts", "range": "172.120.0.0/24" } }’ -
将网络接口分配给 Pod。您可以通过 k8s.v1.cni.cncf.io/networks:注解在 Pod 或部署清单中启用多个 NIC,使用对应于特定 NetworkAttachmentDefinition 自定义资源和其命名空间的值,如下例所示,其中网络接口由两个 NetworkAttachmentDefinition 自定义资源的名称指定,即 gke-network-1 和 gke-network-2,在目标集群的默认命名空间中:
--- apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment spec: ... template: metadata: annotations: k8s.v1.cni.cncf.io/networks: default/gke-network-1, default/gke-network-2 labels: app: sample-deployment ...
将网络接口限制在节点池中
使用 k8s.v1.cni.cncf.io/nodeSelector 注解来指定对于哪些节点,NetworkAttachmentDefinition 自定义资源是有效的。在裸金属上的 Anthos 集群强制任何引用此自定义资源的 Pod 部署在这些特定的节点上。在以下示例中,裸金属上的 Anthos 集群强制将所有分配给 multinicNP 节点池的 gke-network-1 网络接口的 Pod 进行部署。裸金属上的 Anthos 集群相应地使用 baremetal.cluster.gke.io/node-pool 标签标记节点池:
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
annotations:
k8s.v1.cni.cncf.io/nodeSelector: baremetal.cluster.gke.io/node-pool=multinicNP
name: gke-network-1
spec:
...
关于 SR-IOV 插件的说明
SR-IOV 是一种规范,它本质上允许物理 PCIe 设备的虚拟化。它允许您将符合规范的网络设备(在主机节点上识别为物理功能 PF,通常代表单个 NIC 端口)分割成多个虚拟功能(VF),这些虚拟功能可以直接被虚拟化工作负载访问。SR-IOV 对网络硬件的直接访问提供了增强的性能,因此它被广泛应用于基于 VM 的 VNFs。
SR-IOV CNI 插件(github.com/intel/sriov-cni)允许 Kubernetes Pod 直接连接到 SR-IOV VF,并将 VF 绑定到 DPDK 驱动程序,这为云原生网络功能提供了增强的网络性能,就像之前为 VNFs 所做的那样。

图 8.6 使用多个 NIC 连接不同的网络段
在图 8.6 中,您可以看到一个示例图,展示了多个 CNF 串联在一起,通过使用多 NIC Pod 连接多个网络段来提供不同的服务(防火墙、深度包检测、SD-WAN)。
在裸金属上的 Anthos 上运行基于 VM 的工作负载
并非所有网络功能都将部署为 CNFs,其中一些将保持为 VNFs,因此对于一段时间内两种部署模型的共存将是必需的。为了满足这种情况以及其他将部分工作负载作为 VM 而不是容器运行的要求,裸金属上的 Anthos 提供了通过 Anthos VM Runtime 运行基于 VM 工作负载的可能性,该 Runtime 基于 KubeVirt。
在下一节中展示了在裸金属上的 Anthos 上运行 VM 所需的任务的综合描述。
启用 Anthos VM Runtime
要启用 Anthos VM Runtime,您需要执行以下操作:
-
更新 VMRuntime 自定义资源,将 enabled 设置为 true,如下例所示:
apiVersion: vm.cluster.gke.io/v1 kind: VMRuntime metadata: name: vmruntime Spec: enabled: true # useEmulation default to false if not set. useEmulation: true # vmImageFormat default to "qcow2" if not set. vmImageFormat: qcow2 -
如果您的节点不支持硬件虚拟化,或者您不确定,请将 useEmulation 设置为 true。如果可用,硬件虚拟化比软件仿真提供更好的性能。如果未指定,useEmulation 字段默认为 false。
-
您可以通过设置支持两种磁盘镜像格式值(raw 和 qcow2)的 vmImageFormat 字段来更改您创建的虚拟机使用的镜像格式。如果您不设置 vmImageFormat,Anthos VM Runtime 将使用 raw 磁盘镜像格式创建虚拟机。与 qcow2(一种写时复制格式)相比,raw 格式可能提供更好的性能,但可能使用更多的磁盘。
-
保存配置并验证 VMRuntime 自定义资源是否启用:您可以执行 kubectl describe vmruntime vmruntime 并检查描述是否显示 VMRuntime.Status.Ready 设置为 true。
创建虚拟机
在创建虚拟机之前,建议配置一个 cloud-init 文件以确保您在创建虚拟机后可以访问控制台。您可以通过以下两种方式创建自定义 cloud-init 文件。最简单的方法是在创建虚拟机时指定--os=<OPERATING_SYSTEM>标志。此方法自动配置一个简单的 cloud-init 文件,适用于以下操作系统:
-
Ubuntu
-
CentOS
-
Debian
-
Fedora
您的虚拟机创建后,您可以使用以下凭据首次访问它,然后更改密码:
user: root
password: changeme
如果您的镜像包含不同的基于 Linux 的操作系统或您需要更高级的配置,您可以手动创建一个自定义 cloud-init 文件,并通过指定--cloud-init-file=<path/to/file>标志来指定该文件的路径。在其最基本的形式中,cloud-init 文件是一个包含以下内容的 YAML 文件:
#cloud-config
user: root
password: changeme
lock_passwd: false
chpasswd: {expire: false}
disable_root: false
ssh_authorized_keys:
- <ssh-key>
要使用 kubectl 创建虚拟机,您需要遵循以下步骤:
-
使用以下命令安装 virtctl 插件:sudo -E ./bmctl install virtctl。
-
执行命令 kubectl virt create vm。以下示例包含参数:
kubectl virt create vm VM_NAME \ --boot-disk-access-mode=MODE \ --boot-disk-size=DISK_SIZE \ --boot-disk-storage-class="DISK_CLASS" \ --cloud-init-file=FILE_PATH \ --cpu=CPU_NUMBER \ --image=IMAGE_NAME \ --memory=MEMORY_SIZE
参数在此处解释:
-
VM_NAME—您想要创建的虚拟机名称。
-
MODE—启动磁盘的访问模式。可能的值是 ReadWriteOnce(默认)或 ReadWriteMany。
-
DISK_SIZE—您希望启动磁盘的大小。默认值是 20Gi。
-
DISK_CLASS—启动磁盘的存储类别。默认值是 local-shared。
-
FILE_PATH—自定义 cloud-init 文件的完整路径。根据镜像的不同,这可能是在创建虚拟机后获得控制台访问权限所必需的。
-
CPU_NUMBER—您想要为虚拟机配置的 CPU 数量。默认值是 1。
-
IMAGE_NAME—虚拟机镜像,可以是 ubuntu20.04(默认)、centos8 或镜像的 URL。
-
MEMORY_SIZE—虚拟机的内存大小。默认值是 4Gi。
如果未指定参数,则使用默认值。
或者,还可以应用一个定义 VirtualMachine 自定义资源的清单,这还启用了流行的 GitOps 部署方法(声明性和异步管理)。
大型计算集群的编排和自动化
边缘和无线接入网络 CNFs 部署的一个影响是需要一个中央控制平面,能够管理更广泛且更细粒度分布的计算集群,并且部署多个应用程序实例,这些实例可能比在传统的数据中心或公共云中部署的实例大几个数量级。在某些情况下,您可能需要在成百上千个计算集群上部署相同应用程序的实例,这些集群分布在边缘位置。通常,您需要根据特定标准动态定义实例必须部署的位置,以极短的通知时间来适应网络、监控对象或应用程序用户的变化需求。Anthos Config Management 提供的中央配置和政策管理能力将满足这一需求的关键。
Anthos Config Management
Anthos Config Management 的功能在第十一章中进行了详细描述。在这里,我们讨论了其中一些特别适用于在大量集群上管理应用程序和网络功能部署的功能:
-
多仓库模式
-
集群选择器
多仓库模式
在 Anthos Config Management 中启用多仓库模式允许您将来自多个仓库的配置同步到同一组集群中,如图 8.7 所示。一个单一的 root 仓库,通常由中央平台团队管理,托管集群和中央定义的命名空间范围内的配置,而可选的 命名空间仓库 用于配置特定命名空间中的对象。这种能力扩展了 ACM 的使用范围,不仅限于平台配置和政策管理,还包括应用程序的部署:可以将命名空间仓库的设置和控制委托给应用程序发布团队。中央定义的命名空间资源是继承的,而应用程序团队可以自由配置与应用程序相关的资源(部署、配置映射等)。如果根仓库和命名空间仓库之间出现冲突,只有根仓库中的声明应用于集群。

图 8.7 多仓库的 Anthos Config Management
命名空间仓库由 RepoSync 资源定义,由中央平台团队在特定命名空间中部署,或者如果由中央团队委托,则由应用程序团队直接部署。
图 8.8 中的图表示了根仓库和两个命名空间仓库的结构,其中数字标识以下内容:
1. 由中央管理员/平台团队定义的根配置。
2. 由中央团队定义的配置,由于它位于它们的父文件夹中,因此对命名空间是通用的。
3. 中央团队在每个特定命名空间文件夹中定义的资源,包括 RepoSync 资源。(这也可以委托给应用程序团队。)
4, 5. 应用配置清单由应用团队管理。

图 8.8 ACM 示例配置具有多个仓库
集群选择器
ACM 提供了两个特定的资源对象,允许您使用 Kubernetes 标签和选择器方法,有选择地选择应用特定配置或部署的集群。
集群对象识别 ACM 管理的特定集群,并分配任意标签以识别所有集群相关属性(位置、硬件能力、目的等):
kind: Cluster
apiVersion: clusterregistry.k8s.io/v1alpha1
metadata:
name: edge-cluster-112a
labels:
location: london-12
environment: production
kind: edge
gpu: yes
ClusterSelector 对象用于选择仅具有给定标签或标签组合的集群。以下 ClusterSelector 仅选择具有环境:生产和环境:边缘标签的集群——例如,用于针对所有在边缘位置部署的生产集群:
kind: ClusterSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: production-edge
spec:
selector:
matchLabels:
environment: production
kind: edge
可以使用 configmanagement.gke.io/ cluster-selector: 注解从任何 ACM 管理的 Kubernetes 资源引用 ClusterSelector 对象,以选择该资源将在哪个集群上部署。
以下 ClusterRole 仅将在边缘位置部署的生产集群上创建:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: node-reader
annotations:
configmanagement.gke.io/cluster-selector: production-edge
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
ClusterSelector 对象也可以由应用特定资源引用,以有选择地定义将托管应用实例的集群,并且如果使用多个仓库,则在 RepoSync 资源中仅同步特定命名空间仓库到特定集群。
在图 8.9 中,您可以看到一个由操作员管理的自定义资源(kind: DU)定义的分布式单元 CNF 示例,该资源部署在数百个标记为 cnfs: du-slice-1 的 Anthos 集群上,但不在专门用于中央单元(cnfs: cu-cp-slice1, cu-up-slice-1)的集群上。

图 8.9 ACM 示例配置使用集群选择器将不同的 CNFs 部署到不同的集群
所有这些配置都是通过持续与 Git 仓库(根目录和,如果存在,命名空间)同步来驱动的,该仓库作为事实来源。整个集群将定期收敛到期望状态,因此,例如,以下事情会发生:
-
被分配 cnfs: du-slice-1 标签的任何集群将立即部署 CNF。
-
任何通过更改标签更改目的地或目的的集群将删除 CNF,并立即应用新的期望配置。
-
CNF 配置的任何更新都将立即部署到所有期望的集群。
8.3.3 解决方案架构示例:智能零售
除了本章中提供的部署示例之外,我们还将描述一个基于 Anthos 为零售商构建的边缘应用架构。
零售商的一个目标是在商店中部署尽可能小的基础设施,只留下视频摄像头作为端点。部署的应用是实时排队管理,如图 8.10 所示。它从监控收银台结账线的视频摄像头开始,并通过商店中的 5G 调制解调器实时传输视频流,通过 5G 连接到电信运营商的边缘位置。电信运营商的边缘网络接收所有 5G 流量,那里的软件智能地将零售店流量发送到在此边缘部署的 Anthos 裸金属集群。在那里,基于容器的机器学习应用对传入的视频流进行机器学习推理,并检测零售店中有多少人排队。如果这个数字超过某个阈值,就会通过相同的低延迟 5G 路径发送通知到商店,该路径与视频流进入的路径相同。

图 8.10 边缘智能零售解决方案的高级架构
此外,AI/ML 应用还将有关此事件和其他事件的元数据发送到 Google Cloud。稍后,Google Cloud 安全地处理这些信息,为零售商提供洞察力,并训练未来模型的迭代。凭借 Google Cloud 精密的 AI/ML 产品套件,我们可以轻松训练和部署适用于任何应用的任何地点的高度精确模型。
这种架构可以扩展到其他智能零售应用,例如按客户定制的个性化、数字标牌、实时推荐、无接触结账和货架自动补货。所有对延迟敏感的处理,如视频或图像机器学习推理,都在电信边缘发生,而所有非实时组件,如模型训练和数据分析,则在云端运行。
摘要
-
市场趋势和持续发展的平台能力推动电信网络功能和边缘应用向 Kubernetes 和 Anthos 作为理想的部署平台发展。
-
NFV 的目标是实现电信网络功能从专用、专有硬件设备向在行业标准 x86 服务器上部署的虚拟机的转变。这种转型已经开始,但并未完全按照预期实现。
-
5G 正在推动新应用的兴起,这些应用以容器化工作负载的形式部署在边缘位置,并使用 5G 网络的高带宽和低延迟,提供近乎实时的数据处理,并允许智能设备在不将数据发送到云端并返回的情况下进行操作和响应。
-
Anthos 提供了关键能力,这些能力对于边缘和电信工作负载的部署、执行和管理至关重要:虚拟机运行时、硬件加速器、每个 Pod 的多个网络接口以及大型车队管理。
-
Google 分布式云边缘 (GDCE) 是 Google 提供的一个完全托管解决方案,基于裸金属上的 Anthos,旨在支持电信虚拟化和云原生网络功能以及边缘应用,并包括软件、操作系统和硬件,这些都在 Google 管理的机架上。它可以在 Google、电信或企业边缘部署。
9 无服务器计算引擎(Knative)
Konrad Cłapa
本章涵盖
-
无服务器简介
-
Knative Serving 和 Eventing 组件
-
Knative 在 Anthos 上
在我们深入细节之前,让我们设定场景。在本章中,我们将讨论基于名为 Knative 的开源项目构建的 Google Cloud Platform 的托管服务。该项目启动的目的是允许更快地开发 Kubernetes 应用程序,而无需理解它们使用的复杂 Kubernetes 概念。使用这项服务,Google 会将 Knative serving 安装并管理在您的 Anthos GKE 集群内部。使用 Knative 与 Anthos 而不是开源 Knative 的一个好处是,Google 的自动化和站点可靠性工程师处理所有安装和维护工作。Anthos 与众多 GCP 服务集成,如云负载均衡(cloud.google.com/load-balancing)、云装甲(cloud.google.com/armor)、云 CDN(cloud.google.com/cdn/docs/overview)等,使企业级的 Knative 成为现实。
我们已经在第三章中讨论了 Kubernetes,因此我们了解安装和维护它的复杂性。Google Kubernetes Engine 解决了这个问题。除了 Kubernetes 之外,我们还需要了解如何运行和操作云原生应用程序。Knative 做的是抽象那些实现细节,并允许您在任何 Kubernetes 集群上为无服务器容器化工作负载提供服务。
在本章中,我们将探讨什么是无服务器,向您介绍 Knative,并讨论 Anthos 如何提供企业级基于容器的无服务器平台。
9.1 无服务器简介
关于什么是无服务器的讨论很多。无服务器与函数即服务(FaaS)之间的比较很常见——这几乎是一场意识形态的争论。为了保持简单,让我们看看云原生计算基金会(Cloud Native Computing Foundation)的定义:
无服务器计算是指一种新的云原生计算模式,它通过不需要服务器管理来构建和运行应用程序的架构来实现。
Google 的完全托管云运行服务完美符合这一定义,因为它从开发者和操作者那里抽象了计算层。它允许您部署将用于服务 HTTP(S) 请求的容器。应用的扩展由平台本身处理。
虽然 Google Cloud Functions 提供了类似的功能,但它们对您可以使用的服务运行时语言有更多的意见。使用 Cloud Run,您可以使用任何可以运行响应 HTTPS 调用的服务的语言。Cloud Run 不需要您使用 Anthos。
当我们思考 Cloud Run 时,我们可以考虑以下一组无服务器功能:
-
无服务器—开发者无需担心底层计算基础设施。
-
多语言—应用程序可以用任何语言编写。
-
事件驱动—容器/函数由外部事件触发。
-
自动扩展—容器可以根据请求自动扩展。
-
可移植性—您的容器/应用程序应该能够在任何 Kubernetes 平台上运行。
9.2 Knative
因为您已经知道 Kubernetes 是一个用于构建平台的平台,为什么不使用它来构建基于容器的无服务器平台呢?Knative 就像任何其他 Kubernetes 应用程序一样运行在 Kubernetes 之上。您甚至可以看到一些 Knative 贡献者的声明,他们认为不应该称之为“无服务器”,那么让我们把 Knative 看作是一个可以在您运行 Kubernetes 的任何地方提供无服务器平台的平台。听起来公平吗?
9.2.1 简介
假设您想构建自己的基于 Kubernetes 的无服务器平台。您可能会得到图 9.1 所示的图表,显示了所有必需的组件。显然,在构建像自动扩展、可观察性、部署等基本功能方面存在一些重复的工作。Knative 正在为您提供所有这些基本功能,这样您就可以在 Kubernetes 上运行无服务器工作负载时拥有一个共同的体验。

图 9.1 Kubernetes 无服务器堆栈架构
现在从开发者的角度来看思考。他们只需要定义依赖项,编写代码,并将其放入容器中。然后,他们将应用程序部署到 Knative。他们不需要关心如何提供服务的细节。但这并不意味着他们失去了微调服务的能力。他们可以设置多个参数,如并发性(每个容器可以服务的请求数量)、最小/最大实例(为 Knative 服务可以配置的最小/最大容器实例),以及其他许多参数。Knative 隐藏了与扩展和流量管理相关的所有 Kubernetes 复杂性,并提供了一种观察工作负载的方法。这就是所说的简单开始开发 Kubernetes 应用程序,对吧?
Knative 与 CaaS、FaaS 和 PaaS 的比较
在本章的第二部分,我们了解 Knative 正在尝试解决什么问题:使无服务器工作负载能够在任何地方运行,同时具有 Kubernetes 的灵活性,但隐藏复杂性。表 9.1 展示了 Knative 与平台即服务(PaaS;mng.bz/WAKX)、容器即服务(CaaS;mng.bz/81gg)和函数即服务(FaaS;www.ibm.com/topics/faas)的比较,以及支持的各种功能。DIY 表示您需要开发一些功能才能使用该功能。
表 9.1 Knative 与 PaaS、CaaS 和 FaaS 的比较
| 功能 | Knative | PaaS | CaaS | FaaS |
|---|---|---|---|---|
| 简单的用户体验/设计体验 | 是 | 是 | 是 | |
| 事件驱动 | 是 | 是 | 是 | |
| 基于容器 | 是 | 是 | 是 | 是 |
| 自动扩展 | 是 | 是 | DIY | 是 |
| 资源缩放到 0 | 是 | 是 | 是 | |
| 负载均衡 | 是 | 是 | DIY | 是 |
| 无限制的执行时间 | 是* | 是 | 是 | |
| 无限制的计算/内存限制 | 是** | 是** | 是** | |
| 支持多种编程语言 | 是 | 是 | 是 | 有限 |
| * 对于像 Cloud Run 这样的托管服务可能会有所限制**。取决于平台。 |
如我们所见,Knative 提供了 FaaS 的所有优势,同时也赋予你几乎在任何语言中运行应用程序的能力。与 FaaS 相比,执行时间的限制要高得多。在许多需要更长时间请求处理时间的情况下,Knative 是一个解决方案。你终于可以访问诸如卷和网络等高级功能,以便在需要时调整你的工作负载。与所有具有更高灵活性的计算服务一样,责任划分线更多地转向了你。你需要构建自己的容器并确保你可以利用所有高级功能。但说真的:谁不喜欢对自己的应用程序有更多的控制,直到你获得 FaaS 的所有好处?
9.2.2 Knative 历史
Google 启动了 Knative,但现在有 IBM、RedHat 和 SAP 等多家公司参与其中。完整的文档和源代码可以在以下位置找到:github.com/knative。Knative 最初是一组组件,允许你构建和运行无状态工作负载,同时订阅事件。以下两个活跃的项目,如图 9.2 所示,正在 GitHub 上进展:
-
Knative 服务—允许你提供无服务器容器化工作负载
-
Knative 事件—允许订阅外部事件

图 9.2 Knative 组件
第三个项目,Knative 构建,它帮助构建容器,已被弃用并转变为 Tekton 管道(github.com/tektoncd/pipeline)项目。正如你在第九章中将学到的,它被 Google 用于构建 Anthos 的 Cloud Build。
在撰写本文时,Knative 服务和事件都已经进入 1.x 版本,其中事件略落后于服务。Knative 的开发愿景是提供 App Engine(cloud.google.com/appengine)的简单性,但允许 Kubernetes 带来的灵活性。例如,使用 Knative,你可以通过在 Knative 服务¹对象上设置流量配置来修改路由到应用程序的不同版本,而不是更改底层网络对象的配置(例如,Istio)。这种设置类似于 App Engine,你只需运行一个命令即可执行任务,它可以用于金丝雀部署和 A/B 测试。Knative 赋予你将无服务器容器运行在任何地方的能力,无论是在云中还是在本地数据中心。
正如您很快就会学到的那样,已经存在多个基于 Knative 的、完全托管的云服务,这使得避免陷入 Kubernetes 的复杂性变得更加容易。对于本书来说,最有趣的一个当然是 Knative for Anthos,这是市场上最先进的提供之一。
9.3 Knative 架构
让我们来看看图 9.3 所示的 Knative 架构。如您所见,存在多个层级,其中一些组件是即插即用或可选的。

图 9.3 Knative 架构
Knative 可以在任何可以运行 Kubernetes 的计算平台上运行。它既可以基于虚拟机,也可以基于裸金属服务器。对于流量路由,使用 Service Mesh Gateway。显然,最流行的是 Istio,但也支持其他替代方案,包括 Gloo、Ambassador、Contour 和 Kourier,还有更多即将到来。要了解更多关于 Istio 的信息,请参阅第四章。除此之外,我们还将 Knative 组件作为 Kubernetes 应用程序安装。请注意,这些组件可以单独安装和操作。如果您不感兴趣自己管理 Knative 安装,可以使用许多现有的托管服务之一——Google Cloud Run 和 Google Cloud Run for Anthos、OpenShift Serverless、IBM Cloud Kubernetes Service 的托管 Knative——在这些服务中,Knative 及其底层的 Kubernetes 都由提供商管理。这些服务的列表可以在以下链接找到:mng.bz/El6r。
9.3.1 Knative Kubernetes 资源类型
Knative 附带一组控制器和自定义资源定义(CRDs),它们扩展了原生 Kubernetes API。因此,与 Knative 的集成非常类似于与 Kubernetes API 本身的交互。我们将在下一节中查看 Knative 资源。
如果您考虑一个简单的 Kubernetes 应用程序,您应该有 Pods、Deployments 和 Services 等对象。如果您包含 Service Mesh,您将拥有额外的资源来处理流量管理,如虚拟服务和目标规则。使用 Knative,您可以通过单个资源——Knative Service——来控制您的部署,这允许您部署工作负载并处理流量。所有必需的 Kubernetes 和 Service Mesh 资源都将为您创建。
9.3.2 Knative Serving
Knative Serving 允许您轻松部署基于容器的无服务器工作负载,并通过 HTTP(s) 请求(最近宣布支持 gRPC)向用户提供服务。例如,您可以使用 Knative Serving 提供整个电子商务网站的前端。它根据需求自动扩展您的负载(从 0 到 N),并将流量路由或分割到您选择的版本(修订版)。要使用原生 Kubernetes 实现这一点,您需要使用额外的 Kubernetes 资源,如 HorizontalPodAutoscaler(HPA;mng.bz/NmaX)。Knative Serving 通过添加新的 CRDs(如 Knative Serving Service、Configuration、Route 和 Revision)扩展了 Kubernetes API。图 9.4 展示了 Knative 资源之间的依赖关系。

图 9.4 Knative Serving 资源
接下来将描述每个 CRD:
- 服务(API 路径 service.serving.knative.dev)—Knative Serving 中最重要的资源。它自动创建您的工作负载整个生命周期所需的其他 Knative 资源。随着服务的更新,会创建一个新的修订版。在 Knative 服务中,您定义容器版本和流量规则。
注意:这与原生 Kubernetes 服务 对象 不同,这可能会让新用户一开始感到困惑。
例如,一个将简单的 Hello World 工作负载部署到 Knative Serving 的服务定义将自动创建其他资源:修订版、配置和路由:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
namespace: default
spec:
template:
spec:
containers:
- image: docker.io/{username}/helloworld
env:
- name: TARGET
value: "Python Sample v1"
-
修订版(API 路径 revision.serving.knative.dev)—容器版本及其配置的不可变快照。它定义了实际提供给用户的内容。
-
配置(API 路径 configuration.serving.knative.dev**)—强制执行您工作负载所需状态的配置部分。它允许您将代码(容器)与配置部分分离。配置的修改会导致创建新的修订版。
-
路由(API 路径 route.serving.knative.dev)—将端点映射到一个或多个修订版。
当您使用 Knative 时,您不再需要担心原生 Kubernetes 和服务网格资源,如 Deployments、Services 和 VirtualServices。您将应用程序定义为 Knative 服务,所有“后端”资源都将为您创建。
流量管理
当您想使用新镜像更新 Knative 服务时,会创建一个新的修订版,并且默认情况下,流量将指向新的修订版,如图 9.5 所示。您可以在金丝雀(mng.bz/DZ50)发布上进行 A/B 测试,通过定义 metadata.spec.traffic 属性来控制应将多少流量路由到特定的修订版。您还可以仅通过专用 URL 标记特定的修订版以使其可访问。

图 9.5 Knative 服务流量流向
要实现图 9.5 中所示的路由,您需要在 Knative Service 中设置 metadata.spec 的 traffic 属性:
traffic:
- tag: current
revisionName: helloworld-v1
percent: 95%
- tag: candidate
revisionName: helloworld-v2
percent: 5%
- tag: latest
latestRevision: true
percent: 0
如您所见,通过单个 Kubernetes 对象,开发者可以控制整个工作负载的托管方式。无需深入 Kubernetes 后端。
Knative Serving 控制平面
现在,让我们看看 Knative Serving 控制平面,它允许所有这些魔法发生。正如我们之前所说的,Kubernetes 使用 Istio 或任何其他支持的服务网格进行流量管理。它还附带了一些服务,负责运行和扩展工作负载。
要检索您使用 Knative 安装的 knative-serving 命名空间中的服务列表,请使用 kubectl get services -n knative-serving。它将显示以下服务:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
activator-service ClusterIP 10.96.61.11 <none> 80/TCP,81/TCP,9090/TCP 1h
autoscaler ClusterIP 10.104.217.223 <none> 8080/TCP,9090/TCP 1h
controller ClusterIP 10.101.39.220 <none> 9090/TCP 1h
webhook ClusterIP 10.107.144.50 <none> 443/TCP 1h
如您所见,对于这样一个复杂的服务,它没有很多支持服务。让我们逐一查看:
-
Activator—接收并缓冲不活跃修订版的请求,并向自动扩展器报告指标。它还会在自动扩展器根据报告的指标扩展修订版后重试对修订版的请求。
-
Autoscaler—根据定义的参数设置处理负载所需的 Pod 数量。
-
Controller—监控和协调在 CRDs 中定义的 Knative 对象。当创建新的 Knative Service 时,它会创建配置和路由。它将创建修订版和相应的部署以及 Knative Pod 自动扩展器。
-
Webhook—拦截、验证和修改 Kubernetes API 调用,包括 CRD 插入和更新。设置默认值并拒绝不一致和无效的对象。
如果您使用 kubectl get deployments -n knative-serving 检索您安装 Knative 的命名空间中的部署列表,您将看到以下部署:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
activator 1 1 1 1 1h
autoscaler 1 1 1 1 1h
controller 1 1 1 1 1h
networking-certmanager 1 1 1 1 1h
networking-istio 1 1 1 1 1h
webhook 1 1 1 1 1h
我们已经讨论了这四个服务,但我们还没有看到以下两个部署:
-
Networking-certmanager—将集群入口与 cert manager 对象进行协调。
-
Networking-istio—将集群入口与 Istio 虚拟服务进行协调。
9.3.3 Knative Eventing
Eventing 是 Knative 组件,它协调来自 Kubernetes 集群内部或外部的各种来源的事件。这一事件驱动架构的重要元素允许您使用现有的事件源触发您的服务,并为需要自定义源但尚未提供的情况构建新的源。此过程与 FaaS 不同,在 FaaS 中,函数仅通过 HTTP 请求或其他预定义触发器(如 Google Cloud Storage 事件)触发。
所有的 Knative Eventing 对象都定义为 CRDs。这确保了事件按照 Knative 对象中定义的方式使用控制器进行处理。可扩展性会自动处理,因为事件触发对您的容器的调用。它为您提供了类似于 Knative Serving 的可扩展性,因此您可以从小规模的事件负载开始,并扩展以处理事件流。
您可以使用大约 20 个预定义的事件源,而且这个列表还在增长。您也可以开发自己的事件源。Knative Eventing 也是可插拔的,因此您可以选择在处理事件时如何存储事件——是在内存中还是持久存储——Knative 使用开放的 CNCF 标准 CloudEvents 来解析原始事件。事件的目标可以是 Knative 和 Kubernetes 服务。Eventing 管道很简单——就像一个简单的事件被发送到单个服务一样——但它们也可以变得非常复杂。为了理解 Cloud Run,我们先集中关注基础知识。
Knative Eventing 资源
Knative 事件的最基本组件是 Broker 和 Trigger。如果我们看图 9.6,我们会看到事件是从外部源生成的,并被 Broker 捕获。在那里,一个或多个 Trigger 接收事件,过滤它们,并将它们传递到服务。

图 9.6 Knative Eventing 资源
Knative 的架构明确地分离了关注点。Knative Eventing Broker 是一个事件网格,它拉取或接收事件,而 Knative Trigger 则负责过滤和将事件路由到目标。事件源是 Knative Eventing 的控制平面,确保事件被发送到 Broker。现在让我们更仔细地看看这些资源。
Broker API 路径 broker.eventing.knative.dev 实质上是一个可寻址的事件投递系统,您可以通过在命名空间上设置标签来安装它,这与您在想要对 Pods 进行旁路注入时对 Istio 所做的操作类似。事件由 Broker 接收,然后发送给订阅者。消息存储在由 Broker 管理的通道中。
通道可以是简单的内存通道,也可以为了可靠性目的使用持久存储。这些示例包括 Pub/Sub 和 Kafka。通道的配置存储在 ConfigMaps 中。如果您想有不同的消息类型,您可以将 Broker 安装到多个命名空间中。您还可以过滤 Broker 接受哪些事件。下面是一个 Knative Broker 的示例定义:
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
annotations:
eventing.knative.dev/broker.class: MTChannelBasedBroker
name: default
namespace: default
spec:
config:
apiVersion: v1
kind: ConfigMap
name: config-br-default-channel
namespace: knative-eventing
Triggers API 路径 trigger.eventing.knative.dev 将事件与一个服务匹配,因此它定义了事件类型(例如,一个 Cloud Storage 对象将事件发送到该服务)。触发器可以根据一个或多个属性过滤事件。如果存在多个属性,所有属性值都需要匹配。这种方法还可以从接收的事件中产生新的事件类型。这可以是一个过滤包含敏感数据事件的不错用例。下面是一个 Knative 触发器的示例定义:
apiVersion: eventing.knative.dev/v1alpha1
kind: Trigger
metadata:
name: helloworld-python
namespace: knative-samples
spec:
broker: default
filter:
attributes:
type: dev.knative.samples.helloworld
source: dev.knative.samples/helloworldsource
subscriber:
ref:
apiVersion: v1
kind: Service
name: helloworld-python
源 API 路径 <source_name>.eventing.knative.dev 被定义为 CRD。列表仍在增长,包括 AWS SQS、Google Cloud Pub/Sub、Google Cloud Scheduler、Google Cloud Storage、GitHub 和 GitLab。事件的全列表请参阅 knative.dev/docs/eventing/sources/。你可以使用现有的源或创建自己的源。以下示例展示了如何配置 CloudPubSubSource 事件源。每当消息被发布到名为 testing 的 Pub/Sub 主题时,将生成事件:
apiVersion: events.cloud.google.com/v1
kind: CloudPubSubSource
metadata:
name: cloudpubsubsource-test
spec:
topic: testing
sink:
ref:
apiVersion: v1
kind: Service
name: event-display
在图 9.7 中,你可以看到事件源是如何工作的。

图 9.7 事件源的工作原理
事件根据源是否能够推送事件而被拉取或推送。如果不能,则需要拉取事件。适配器被开发出来以理解事件并将它们转换为通用的 CloudEvents 格式。一旦转换,它们就可以供代理在新格式中拾取。
事件源的工作原理
事件源由控制平面和数据平面组成。控制平面负责与权威源配置事件交付、数据平面的设置和清理——简单来说,它创建 webhooks 和订阅。数据平面执行推送/拉取操作,然后验证并将数据转换为 CloudEvents。
在现有源的基础上,你可以使用 Kubernetes 运算符、容器源或现有服务创建自己的事件源。要了解如何开发自己的源,请参阅 Knative Eventing 文档 (mng.bz/lJBz)。
Knative 用例
使用 Knative,你可以覆盖从简单的单个服务到非常复杂的多微服务应用的各种用例。通过使用 Knative Serving,你可以创建 HTTP 和 gRPC (grpc.io/docs/what-is-grpc/introduction/) 服务、webhooks 和 API。你还可以管理发布和回滚,并控制应用程序的流量。使用 Knative Eventing,你可以创建简单或非常复杂的事件处理管道。通过结合这两个服务,你可以交付一个完全云原生、事件驱动的应用程序。
让我们看看将运行中的服务绑定到 Cloud IoT Core (cloud.google.com/iot-core) 的简单示例,如图 9.8 所示。来自 IoT 设备的消息被发送到 Google Cloud IoT Core 并同步到 Pub/Sub。Knative Eventing 服务使用 Pub/Sub 源从主题获取消息。消息被发送到代理并转换为 CloudEvents。触发器确保事件被发送到可以进一步处理、记录或显示给用户的正确服务。

图 9.8 将运行中的服务绑定到 IoT Core
如果你想要尝试 Pub/Sub 示例,我们鼓励你遵循mng.bz/Bljq上的逐步教程。
9.3.4 可观测性
Knative 自带日志和跟踪功能,如图 9.9 所示。以下开源软件得到支持:
-
Prometheus 和 Grafana 用于指标
-
ELK(Elasticsearch、Logstash 和 Kibana)堆栈用于日志
-
Jaeger 或 Zipkin 用于分布式跟踪

图 9.9 Knative 可观测性生态系统
要了解更多关于指标和跟踪的信息,请参阅第四章。
你还可以通过使用Fluent Bit代理与 Google Cloud Logging(以前称为 Stackdriver Logging)集成日志。每个组件的安装过程在mng.bz/dJlz找到的文章中有详细描述。
因为这些组件像任何其他 Kubernetes 应用一样部署,你可以通过暴露 Kubernetes 服务来访问它们。以下是一个部署后运行在集群中的 Pod 示例:
NAME READY STATUS RESTARTS AGE
grafana-798cf569ff-v4q74 1/1 Running 0 2d
kibana-logging-7d474fbb45-6qb8x 1/1 Running 0 2d
kube-state-metrics-75bd4f5b8b-8t2h2 4/4 Running 0 2d
node-exporter-cr6bh 2/2 Running 0 2d
node-exporter-mf6k7 2/2 Running 0 2d
node-exporter-rhzr7 2/2 Running 0 2d
prometheus-system-0 1/1 Running 0 2d
prometheus-system-1 1/1 Running 0 2d
9.3.5 安装 Knative
如果你运行一个包含但不限于以下内容的 Kubernetes 集群,你可以在多个云平台或本地安装 Knative:
-
Amazon EKS
-
Google GKE
-
IBM IKS
-
Red Hat OpenShift Cloud Platform
-
Minikube
最后,Knative 不过是一个 Kubernetes 应用。你可以使用 YAML 文件或操作符来安装它。要了解更多关于操作符的信息,请参阅mng.bz/rdRE。Knative Serving 组件的安装过程如下:
-
自定义资源定义的安装
-
安装 Serving 的核心组件
-
安装网络层
-
DNS 配置
-
可选 Serving 扩展的安装
Knative Eventing 组件的安装包括以下步骤:
-
自定义资源定义的安装
-
安装 Eventing 的核心组件
-
默认通道(消息传递)层的安装
-
安装(事件)代理层
-
可选 Eventing 扩展(源)
完成 Serving 和 Eventing 的安装后,你可以安装上一节中描述的可观测性组件。端到端安装的逐步过程可在mng.bz/Vp0r找到。
9.3.6 将应用部署到 Knative
你可以遵循一个简单的指南将你的第一个应用程序部署到 Knative,这就像应用一个单一的 Knative 服务对象一样简单,如下所示。这假设你已经在 Docker Hub 中存储了一个容器化的 Python 应用程序,该应用程序响应“Hello Python Sample v1!”(查看mng.bz/xdRq以检查该应用程序的源代码):
-
运行以下命令以创建 Knative 服务:
kubectl apply -f service.yaml其中 Service 在 service.yaml 文件中定义如下:
apiVersion: serving.knative.dev/v1 kind: Service metadata: name: test namespace: default spec: template: spec: containers: - image: docker.io/<user>/<image_name> env: - name: TARGET value: "v1" -
一旦部署,将为你创建多个对象,包括 Pods、Knative 服务、配置、修订和路由。你可以通过运行以下代码来验证它们:
kubectl get pod,ksvc,configuration,revision,route -
你可以通过以下方式访问服务并获取 Istio 入口网关的 IP 地址:
kubectl get ksvc helloworld-python --output=custom-columns=NAME:.metadata.name,URL:.status.url这将返回以下 URL:
NAME URL helloworld-python http://helloworld-python.default.1.2.3.4.xip.io -
现在通过运行 curl 查询来测试应用程序:
curl http://helloworld-python.default.1.2.3.4.xip.io注意,xip.io 域称为魔法 DNS。你可以在安装 Knative 时配置它(见
mng.bz/Al9E)。 -
你应该看到以下输出:
Hello Python Sample v1!你已成功部署了你的第一个 Knative 应用程序!
为了获得一些 Knative 的实践经验,我们建议你查看表 9.2 中所示的示例。它们涵盖了支持多种语言的 Knative 应用程序开发和部署场景。我们特别推荐 Mete Atamel 的 Knative 教程,它从非常简单的部署引导你到非常复杂的部署,包括使用 Google Cloud 服务如 Pub/Sub、AI API 和 BigQuery。我们相信你会有很多乐趣!
表 9.2 部署到 Knative 的参考
| 标题 | URL |
|---|---|
| Knative Serving 代码示例 | knative.dev/docs/serving/samples/ |
| Knative Eventing 代码示例 | knative.dev/docs/eventing/samples/ |
| Mete Atamel 带有多个示例的 Knative 教程 | github.com/meteatamel/knative-tutorial |
Knative 概述
使用 Knative 服务,你不再需要在 Kubernetes 的灵活性和函数即服务的简单性之间做出选择——你可以两者兼得。你可以在任何地方运行你的无服务器工作负载。使用 Knative Eventing,你可以订阅并接收来自多个预定义源的事件,以及使用云原生架构定义自己的源。
Cloud Run 与 Knative on Anthos 对比
Cloud Run 是一个完全管理的无服务器产品,而 Knative on Anthos 在你的 Anthos 集群之上运行,如图 9.10 所示。你可以与任何版本的 Cloud Run 交互。然而,Cloud Run 在 Google 基础设施上运行,因此你不需要担心底层平台。

图 9.10 Cloud Run 和 Knative on Anthos 架构
注意:为了本书的目的,我们将把 Cloud Run(完全管理)称为 Cloud Run。
尽管我们知道主要区别是什么,但你可能仍然想知道哪个服务更好地满足你的工作负载需求。表 9.3 展示了更多关于这些区别的细节。
Cloud Run 与 Knative on Anthos 对比
| 功能 | Cloud Run | Knative on Anthos |
|---|---|---|
| 价格 | 按使用付费 | GKE Anthos 成本 |
| 计算 | CPU 和内存限制 | 根据 GKE 集群节点的能力(包括 GPU) |
| 隔离 | 基于 gVisor 或其他沙盒 | 默认 GKE 隔离 |
| 缩放 | 1,000 个容器,具有可扩展配额 | 根据 GKE 集群 |
| URL/SSL | 自动生成 URL 和 SSL | 可以配置自定义域名 |
| 域名 | 可以创建自定义域名 | |
| 网络 | 通过无服务器 VPC 访问访问 VPC | 直接访问 VPC |
| 服务网格 | 集成服务网格 | 连接到 Istio 服务网格的服务 |
| 执行环境 | Google 基础设施 | GKE 集群 |
那么,何时选择每个提供项呢?这很大程度上取决于您希望对应用程序执行有多大的控制权,以及您是否需要为 GKE 节点定制硬件。例如,您可能想使用 GPU 来提升您的机器学习管道的性能。在这种情况下,选择在 Anthos 上运行的 Knative 是最佳选择。
摘要
-
Knative 抽象化了 Kubernetes 的复杂性。
-
工作负载可以移植到任何 Kubernetes 集群。
-
Knative 拥有多个组件,可以解决多个用例。
-
事件是协调来自各种来源的事件的组件。
-
托管是允许您部署基于容器的无服务器工作负载并将其提供给用户的组件。
-
无服务器 Kubernetes 工作负载可以使用 Anthos 上的 Knative 进行部署和托管。
-
应用程序的版本可以通过修订版进行控制。
-
可以使用修订版参数来管理应用程序的流量。
-
您可以使用丰富的开源生态系统中的工具来监控、记录和跟踪,从而深入了解您的应用程序。
^(1.)本章节的下一节将解释 Knative Serving。
10 网络环境
Ameer Abbas
本章涵盖
-
Anthos 云网络和多个云环境之间的混合连接
-
Anthos Kubernetes 和 GKE 网络,包括 Dataplane v2
-
Anthos 多集群网络,包括服务发现和路由
-
服务间和客户端到服务连接
Anthos 网络可以分为四个部分。每个部分为环境(例如,公共云和本地)、Anthos GKE 集群以及服务间通信等实体提供一层连接。如图 10.1 所示,这四层包括:
-
云网络和混合连接——涉及网络的最底层,涵盖不同基础设施环境如何相互连接。
-
Anthos GKE 网络——Anthos GKE 集群的实施方式多种多样,取决于它们部署的基础设施。本节涵盖 Anthos GKE 集群网络,包括在各种环境中如何进行入口操作。
-
多集群网络——讨论各种 Anthos GKE 集群如何相互连接。Anthos GKE 集群可以部署在单一基础设施环境中(例如,在 GCP 中),也可以部署在多个基础设施环境中(例如,GCP 和本地数据中心)。
-
服务和客户端连接——讨论在 Anthos 上运行的应用程序如何相互连接。本节还讨论运行在 Anthos 平台外部的客户端和服务如何连接到 Anthos 平台内部运行的服务。

图 10.1 Anthos 网络的四层
10.1 云网络和混合连接
本节讨论基础设施环境层面的网络连接的各个方面。Anthos 是一个多云平台,可以在一个或多个公共和私有云环境中运行。在基础设施层,您可以以下方式部署 Anthos:
-
在单一云环境中——例如,GCP 或本地数据中心,甚至在其他公共云中
-
在多/混合云环境中——例如,在 GCP 和一家或多家本地数据中心部署的平台
10.1.1 单云部署
Anthos 平台可以部署在单云环境中。单云环境可以是 GCP、其他公共或私有云,或本地数据中心。
Anthos 在 GCP 上
Anthos 在 GCP 中使用放置在虚拟专用云(VPC;cloud.google.com/vpc)内的资源。您可以在 GCP 中以多种方式配置 VPC。根据公司的需求,一个单一 VPC(在单个 GCP 项目中)可能就足够了。在更复杂的设计中,可能需要共享 VPC、对等 VPC,甚至多个不同的 VPC。Anthos 平台可以与各种 VPC 设计协同工作。在选择正确的 VPC 架构时,事先考虑是很重要的,因为这可能会在以后带来可扩展性和运营方面的后果。我们将在下一节讨论各种 VPC 设计和决策标准。
单一 VPC
单一 VPC 是最简单的设计。对于所有内容都包含在单个 GCP 项目中的小型环境,您可以选择单一 VPC。单一 VPC 导致网络扁平化,这意味着使用 VPC 的所有资源都在同一网络中。您可以通过 Anthos 平台各个层次的安全功能来控制资源之间的连接性。例如,您可以在网络层使用 VPC 防火墙(cloud.google.com/vpc/docs/firewalls),在 Kubernetes Dataplane 内使用 Kubernetes NetworkPolicies (mng.bz/ZoWj),以及在服务网格层使用 Anthos Service Mesh (mng.bz/RlOn) 认证和授权策略。采用这种方法,多个团队可以在同一 GCP 项目和同一 VPC 中使用资源。如图 10.2 所示的单一 VPC 设计也简化了网络管理。所有资源,无论在 Anthos 平台内部还是外部,都位于同一扁平网络中,并且可以按照安全规则允许的方式轻松通信。无需额外的配置即可连接资源。

图 10.2 GCP 中的单一 VPC 架构
单一 VPC 设计的主要挑战是可扩展性。尽管单一 VPC 设计可能适用于中小型实施,但对于大型实施来说,可能无法实现,因为你将开始遇到 VPC 限制(cloud.google.com/vpc/docs/quota)。随着组织的增长,可能需要为不同的产品、团队或环境创建单独的项目。单一 VPC 设计不支持多项目环境。根据行业,可能存在禁止在单一 VPC 中托管所有资源的法规,并要求进行某种程度的网络或项目分离。
当为 Anthos 设计您的网络结构时,您必须事先了解并考虑平台的长期性。例如,在两到四年后,平台将扩展多少,是否会出现需要考虑的任何其他限制,无论是配额还是法规方面的?
共享 VPC
使用共享 VPC(cloud.google.com/vpc/docs/shared-vpc)是 GCP 上为 Anthos 平台配置网络的推荐方式。您可以使用图 10.3 中显示的共享 VPC 设计,适用于简单和复杂(大规模和多租户)的 Anthos 环境。共享 VPC 允许单个 VPC 在多个项目中共享,从而在多个租户之间共享单个扁平网络空间,每个租户都在自己的项目中。通过产品/租户分离 GCP 项目,可以在项目级别实现细粒度的 IAM 权限控制。同时,多个项目中的资源仍然可以相互连接(如果允许),就像它们在单个网络中一样。

图 10.3 GCP 中的共享 VPC 架构
网络主机项目包含一个集中的“共享”VPC。所有网络资源都位于此网络主机项目中,包括子网、防火墙规则和网络权限。一个集中的网络团队拥有并控制网络主机项目。这种安排确保由一个合格的网络专家团队强制执行组织的网络最佳实践。然后,多个服务项目可以使用主机项目的网络资源。子网从网络主机项目共享到多个服务项目,并由每个服务项目内的资源使用。
对于 GCP 上的 Anthos,建议创建一个服务项目,并将其命名为类似 platform_admins。Anthos 平台(所有 GKE 集群)位于 platform_admins 项目中。platform_admins 项目(正如其名称所示)由平台管理员团队拥有,该团队负责管理和维护 Anthos 平台的生命周期。平台管理员是网络主机项目的众多租户之一。同样,产品和环境也有它们自己的服务项目。Anthos 是一个共享的多租户平台,每个租户都获得一个“着陆区”,在其中运行他们的服务。着陆区是一组在 Anthos 平台上运行服务所需的资源,通常是(一个或多个)Anthos GKE 集群中的一个(或多个)命名空间以及运行该服务所需的一组策略。所有非 Anthos 资源(属于一个服务)都在单个服务项目的 GCP 项目中配置和管理。这样,多个租户可以拥有自己的非 Anthos 资源项目,并且他们都可以在 GCP 集群上共享单个 Anthos GKE。使用共享 VPC 允许 Anthos 和非 Anthos 资源相互连接。
多个 VPC
前两个 VPC 实现导致网络扁平化,所有资源都在单个逻辑 VPC 中配置。在某些情况下,安全或监管限制可能需要将资源分离到多个 VPC 中。公司或组织还可能希望每个团队或产品管理自己的网络。

图 10.4 GCP 中的多个 VPC 架构
Anthos GKE 在 GCP 平台可以安装在一个 VPC 中。多租户允许您与多个租户共享 Anthos GKE on GCP,如图 10.4 所示。您可能需要将运行在 Anthos 平台上的服务连接到平台外的服务。在这个设计中,这些服务运行在不同的 VPC 中。例如,运行在 GCP 中 Anthos GKE 上的服务可能运行在名为 anthos_vpc 的 VPC 中,而非 Anthos 资源可能运行在名为 product_1_vpc 的 VPC 中。您可以通过以下方式连接这些服务:
-
IPsec VPN (
mng.bz/2a4N)—您可以在两个 VPC 之间创建一个 IPsec VPN 隧道。IPsec VPN 流量以安全的方式在公共互联网上传输。两个网络之间的流量由一个 VPN 网关加密,然后由另一个 VPN 网关解密,以保护数据在互联网上的传输。然而,通过公共互联网传输可能会导致性能下降。IPsec VPN 对于大规模环境可能很有帮助。 -
VPC 网络对等连接 (
mng.bz/1MvZ)—您可以对多个 VPC 进行对等连接,以实现 VPC 互连,而无需通过 IPsec VPN 连接 VPC。VPC 对等连接提供了与单个 VPC 相同的数据平面和性能特性,但具有管理(安全和配置)边界,从而为 VPC 到 VPC 流量提供更好的安全性和性能。VPC 网络对等连接需要两个 VPC 的网络管理员之间的协调。它不允许重叠的 IP 地址。此外,两个 VPC 的所有者都维护有单独的防火墙,并设置所需的规则以允许两个 VPC 的子网之间的流量。 -
公共互联网和安全的入口—如果 VPC 对等连接或 VPN 不是可行的选项,服务可以通过公共互联网进行通信。在这种情况下,可以使用高级功能,如 Anthos Service Mesh,使用 TLS 或 mTLS(相互 TLS)加密网络之间的流量。如果只有少数服务需要跨 VPC 的连接,这种方法效果很好,因为这种方法需要为每个服务(目标服务)进行配置,而前两种方法是在 TCP/IP 层连接两个网络。
在单个非 GCP 环境中部署 Anthos
您可以在各种非 GCP 环境中部署 Anthos,包括本地数据中心、公共云和私有云。在基础设施层,您应该考虑两种主要的网络设计:单网络和多网络。
单一扁平网络
如其名所示,扁平网络由一个单一的逻辑网络空间组成,其中既包含 Anthos 资源,也包含非 Anthos 资源(例如,在 Anthos 平台外运行的虚拟机)。扁平网络是一组通过路由器和交换机连接的子网,每个 IP 端点在正确的路由(和防火墙)规则下可以切换或路由到另一个端点。单个 GCP VPC 是扁平网络的一个例子,您可能拥有多个子网和路由/防火墙规则,以允许任何两个端点之间的路由。
与多个不同的网络相比,扁平网络更容易管理,但在安全性方面需要更加严谨,因为所有实体都在同一个逻辑网络空间中。防火墙规则、网络策略和其他功能可以确保只有允许的实体才能访问网络。扁平网络也可能遇到可扩展性问题。通常,这些网络使用 RFC1918 地址空间(datatracker.ietf.org/doc/html/rfc1918),它提供有限数量的 IP 地址(接近 1800 万个地址)。通常,扁平逻辑网络要求所有资源使用相同的 RFC1918 空间。在某些情况下,大型组织可能会使用自己的公共 IP 地址空间进行内部寻址,这违反了这一普遍规则。无论 IP 地址的使用情况如何,重要的是要注意,在扁平网络中,两个端点不能有相同的 IP 地址。
多个网络
Anthos 还可以部署在多网络环境中。根据需要,Anthos GKE 集群可以部署在单个或多个网络上。通常,如果 Anthos 在同一网络中部署,则更容易管理在 Anthos 平台上运行的应用的网络连接。尽管如此,在某些情况下,可能需要连接这些多个网络。您有以下几种方式将运行在 Anthos 平台上的应用连接到多个网络:
-
VPN/ISP—您可以通过 VPN 将多个网络连接在一起,或者选择的 ISP 可能提供这种连接性。这些是连接多个本地数据中心时的典型选择。
-
VPC 对接—如果 Anthos 部署在提供 VPC 对接功能的公共云上,您可以使用 VPC 对接。
-
网关或 mTLS—服务可以通过 TLS、mTLS 或安全的 API 网关在公共互联网上安全连接。这种功能通过服务网格(如 Anthos 服务网格(ASM;
cloud.google.com/service-mesh/docs/overview))或 API 网关(如 Apigeecloud.google.com/apigee)来实现。* 这是在每个服务级别上完成的,而前两种选项是在网络层配置的。
10.1.2 多/混合云部署
Anthos 是一个多云平台,可以部署到多个环境中,例如,公有/私有云和本地数据中心。在多个环境中管理网络具有挑战性,因为每个环境都是独特的,而且根据提供商的不同,管理资源的方式也不同。例如,GCP VPC 的配置方式与 AWS VPC 或数据中心网络不同。Anthos 在多个环境中提供了一个统一的接口。您可以通过以下三种方式将 Anthos 平台部署到多个环境中:
-
多云部署—您可以将 Anthos 平台部署到多个公有云环境中,例如,GCP 和一个或多个公有云,如 AWS 和 Azure。
-
混合云部署—您可以将 Anthos 平台部署到 GCP 和一个或多个本地数据中心。
-
多和混合云部署—这种部署是之前提到的两种部署的组合。例如,您可以将 Anthos 平台部署到 GCP、一个或多个本地数据中心以及一个或多个非 GCP 的公有云。
多/混合网络
当您在多个基础设施环境中部署 Anthos 时,这些环境必须与 GCP 具有网络连接。有三种网络连接选项可用于连接多个基础设施环境:云互连、云 VPN 和公共互联网。
云互连
云互连 (mng.bz/Pxe2) 通过一个高可用、低延迟的连接将本地网络扩展到 Google 的网络。您可以使用专用互连直接连接到 Google,或者使用合作伙伴互连通过支持的服务提供商连接到 Google。专用互连在您的本地网络和 Google 网络之间提供直接的物理连接。专用互连使您能够在网络之间传输大量数据,这可能比在公共互联网上购买额外的带宽更经济高效。
对于专用互连,您在公共位置(见 mng.bz/JlQp)配置 Google 网络和您自己的路由器之间的专用互连连接。图 10.5 显示了 VPC 网络和您的本地网络之间的单个专用互连连接。

图 10.5 GCP 和本地数据中心之间的专用互连
对于这种基本设置,在公共托管设施中,Google 网络和本地路由器之间配置了一个专用互连连接。
当您创建 VLAN 附件(mng.bz/wPR7)时,您将其与云路由器(mng.bz/qdlK)关联。此云路由器为 VLAN 附件及其对应的本地对等路由器创建 BPG 会话。云路由器接收您的本地路由器广播的路由。这些路由作为自定义动态路由添加到您的 VPC 网络中。云路由器还向本地对等路由器广播谷歌云资源的路由。
根据您的可用性需求,您可以将专用互连配置为支持关键任务服务或可以容忍一些停机时间的应用程序。为了达到特定的可靠性水平,谷歌提供了以下两种规定配置:
-
实现专用互连的 99.99%(每年 52.60 分钟)可用性(
mng.bz/71ax)(推荐) -
实现专用互连的 99.9%可用性(
mng.bz/516q)
云互连是将 GCP 和非 GCP 环境连接起来的最稳健和最安全的选项,也是连接 GCP 和一个或多个本地数据中心的推荐选项。
云 VPN
云 VPN(mng.bz/mJPn)*通过 IPSec VPN 连接安全地将您的对等网络连接到您的 VPC 网络。在两个网络之间传输的流量由一个 VPN 网关加密,然后由另一个 VPN 网关解密,这保护了您的数据在互联网上的传输。谷歌云提供高可用性 VPN,通过额外的/冗余 VPN 连接以更高的成本提供更高的正常运行时间和吞吐量。
每个云 VPN 隧道可以支持总吞吐量高达每秒 3 千兆比特的入站和出站。您可以使用多个云 VPN 隧道来增加您的入站和出站带宽。
您可以使用云 VPN 在 GCP 和本地数据中心之间,以及 GCP 和其他公共云供应商之间进行连接。这是设置最简单的选项,您可以在没有任何延迟的情况下运行。云 VPN 还可以与云互连结合使用,作为次要连接选项。
公共互联网
在多个环境中运行的 Anthos 平台上的应用程序可以在不使用云互连或 VPN 的情况下通过公共互联网连接。平台上的应用程序通过 TLS/mTLS 在公共互联网上连接。
Anthos 服务网格(ASM)是 Anthos 平台的一部分。ASM 使用注入到每个 Pod 中的客户端代理来连接服务。这些代理的一个安全特性是使用 mTLS 来确保连接的安全性。通过在多个环境中使用共同的根证书颁发机构,边车代理可以通过网关(例如,入口或东西向网关)在公共互联网上使用安全的 mTLS 连接。有关 Anthos 服务网格的详细信息,请参阅第四章。
如果许多服务需要在环境之间进行连接,那么此选项可能无法在操作上扩展。在这种情况下,建议您使用前面提到的网络连接选项之一。
断开连接的环境
在某些情况下,您可能需要具有完全相互断开的环境。Anthos 平台支持断开连接的环境。断开连接的环境必须与 GCP 有网络连接,以便平台(即 Anthos 集群)可以注册到 GCP 项目。这仅适用于控制平面流量。对于某些 Anthos 功能,需要注册集群。例如,要在 Anthos 集群上使用多集群入口,所有参与的集群都必须注册到 GCP。断开连接环境中的服务将无法相互通信。
10.2 Anthos GKE 网络
Anthos GKE 集群可以部署到各种环境中,例如,在 GCP 上、在本地数据中心 VMware 上、在裸金属服务器上,以及在 AWS 上。除了支持的 Anthos 集群外,您还可以将任何符合规范的 Kubernetes 集群注册到 Anthos 平台。例如,您可以将运行在 AWS 上的 EKS 集群和运行在 Azure 上的 AKS 集群注册到 Anthos 平台。目前,以下六种类型的 Anthos 集群可供使用:
-
GCP 上的 Anthos 集群(GKE)
-
VMware 上的 Anthos 集群(本地数据中心的 GKE)
-
基于裸金属的 Anthos 集群
-
AWS 上的 Anthos 集群(AWS 上的 GKE)
-
Azure 上的 Anthos 集群(Azure 上的 GKE)
-
Anthos 附加集群(符合 Kubernetes 规范的集群)
10.2.1 Anthos 集群网络
集群 IP 寻址
所有 Anthos GKE 集群都需要以下三个 IP 子网:
-
节点和 API 服务器 IP 地址
-
Pod IP 地址
-
服务或 ClusterIP 地址
节点和 API 服务器 IP 地址是局域网(对于本地数据中心)或 VPC(对于公共云)IP 地址。每个节点和 API 服务器都分配一个单独的 IP 地址。根据所需的节点/API 服务器的数量,确保您有足够的 IP 地址。
Pod IP 地址分配给 Anthos GKE 集群中的每个 Pod。Anthos 集群中的每个节点都分配了一个唯一的 IP 地址范围,该范围用于分配 Pod IP 地址(在该节点内部运行)。如果 Pod 从一个节点移动到另一个节点,其 IP 地址将根据新节点的 IP 地址范围进行更改。API 服务器使用一个大的 IP 范围,通常称为 Pod CIDR IP 范围,例如/14 或/16(你可以在mng.bz/610G上了解 IP 子网)。然后服务器将这个范围平均分成更小的 IP 范围,并为每个节点分配一个唯一的范围。你定义每个节点期望的 Pod 数量,API 服务器将使用这个数量将大子网切割成每个节点的小子网。例如,如果你希望每个节点有 30 个 Pod,每个节点至少需要一个/27。你的 Pod IP 范围必须足够大,以容纳N个子网,每个子网有 32 个地址,其中N是集群中节点的最大数量。
Pod IP 地址在集群内部是可路由的。它们可能或可能不可从集群外部路由,这取决于集群的类型和实现方式。这一点将在下一节中详细讨论。
服务或 ClusterIP 地址分配给每个 Kubernetes 服务。与 Pod IP 地址不同,Pod IP 地址可能会随着 Pod 在节点之间移动而改变,而 ClusterIP 地址保持静态,并作为多个表示单个 Kubernetes 服务的 Pod 的负载均衡虚拟 IP 地址(VIP)。正如其名所示,服务 IP 或 ClusterIP 对集群是本地相关的,并且不能从集群外部访问。集群内部的服务可以使用 ClusterIP 访问服务。
集群网络数据平面
Anthos GKE 集群提供了两种网络数据平面的选项。
GKE 数据平面 v1:kube-proxy 和 Calico
Kubernetes 使用 kube-proxy 组件管理 Pod 和 Service 之间的连接。默认情况下,它作为每个节点上的静态 Pod 部署。任何运行 1.16 或更高版本的 GKE 集群都部署了一个作为 DaemonSet 的 kube-proxy。
kube-proxy 不是一个内联代理,而是一个基于出口的负载均衡控制器。它监视 Kubernetes API 服务器,并通过向节点的 iptables 子系统添加和删除目标 NAT 规则,持续地将 ClusterIP 映射到健康的 Pod。当一个在 Pod 中运行的容器向服务的 ClusterIP 发送流量时,节点随机选择一个 Pod 并将流量路由到该 Pod。
当你配置服务时,你可以通过定义端口和 targetPort 的值来可选地重映射其监听端口。端口是客户端到达应用程序的地方。targetPort 是应用程序在 Pod 内部监听流量的端口。kube-proxy 通过在节点上添加和删除 iptables 规则来管理这个端口重映射。
在 GKE Dataplane v1 中,Kubernetes NetworkPolicies 使用 Calico 组件实现。Calico 是一个开源的容器、虚拟机和基于主机的工作负载的网络和网络安全解决方案。此实现使用依赖于 Linux 内核中 iptables 功能的组件。Dataplane v2 解决并解决了一些这些问题。
GKE Dataplane v2:eBPF 和 Cilium
如图 10.6 所示的 GKE Dataplane v2 是一个具有观点的数据平面,它利用了扩展伯克利包过滤器 (eBPF) 和 Cilium 的力量,Cilium 是一个开源项目,它使用 eBPF 使 Linux 内核对 Kubernetes 有所了解。

图 10.6 GKE Dataplane v2 架构
Dataplane V2 通过提供可编程数据路径来解决可观察性、可伸缩性和功能需求。eBPF,一种新的 Linux 网络范式,向 Linux 内核内部的网络堆栈公开可编程钩子。通过在用户空间和内核空间之间跳转,丰富内核的用户空间信息的能力,使得可以在高速下对网络数据包进行上下文感知的操作。
新数据平面增加了两个新的集群组件:用于编程 eBPF 数据路径的 cilium-agent DaemonSet 和管理 Cilium-内部 CRDs 并帮助 cilium-agent 避免监视每个 Pod 的 cilium-operator Deployment。
数据平面还消除了 Calico 集群组件——calico-node DaemonSet 和 calico-typha Deployment。这些组件提供 NetworkPolicy 执行功能,该功能由 cilium-agent DaemonSet 提供。
数据平面还从节点中移除了 kube-proxy 静态 Pod。kube-proxy 为集群提供服务解析功能,该功能也由 cilium-agent 提供。
Dataplane V2 为 Anthos 集群提供网络可编程性和可伸缩性,如图 10.7 所示。企业使用 Kubernetes NetworkPolicies 来声明 Pod 之间如何相互通信。然而,之前没有可伸缩的方式来调试和审计这些策略的行为。在 GKE 中使用 eBPF 后,你现在可以执行实时策略,以及以最小影响节点 CPU 和内存资源的方式,以行速率关联策略操作(允许/拒绝)到 Pod、命名空间和政策名称。当数据包进入虚拟机时,可以在内核中安装专门的 eBPF 程序来决定如何路由数据包。与 iptables 不同,eBPF 程序可以访问 Kubernetes 特定的元数据,包括网络策略信息。这样,它们不仅可以允许或拒绝数据包,还可以将带注释的操作报告回用户空间。这些事件使您能够生成网络策略日志。

图 10.7 GKE Dataplane v2:网络策略流日志
表 10.1 显示了 GKE Dataplane v1 和 v2 之间网络功能的比较。
表 10.1
| 网络功能 | 现有 | 新 Dataplane |
|---|---|---|
| 集群 IP 服务解析 | kube-proxy 使用 iptables | cilium-agent 在套接字上使用 eBPF |
| 节点端口服务解析 | kube-proxy 使用 iptables | cilium-agent 在 eth0 TC 钩子上使用 eBPF |
| 负载均衡器服务解析 | kube-proxy 使用 iptables 重定向到服务链 | cilium-agent 在 eth0 TC 钩子上使用 eBPF(与之前相同的钩子) |
| 网络策略执行 | Calico 使用 iptables | cilium-agent 在套接字以及 eth0 TC 钩子上使用 eBPF |
根据 Anthos 集群的类型和实现,网络设计和需求会有所不同。在下一节中,我们将从网络需求和最佳实践的角度分析每种类型的 Anthos 集群。
GCP 上的 Anthos GKE
Anthos GKE 集群在 GCP 上运行,并使用 GCP VPC 功能进行 Kubernetes 网络功能。GCP 上 Anthos GKE 的两种实现方式可用:VPC 原生集群和基于路由的集群。
VPC 原生集群
这是 Anthos GKE 在 GCP 集群中的默认和推荐实现。使用别名 IP 地址范围的集群称为 VPC 原生集群。VPC 原生集群使用真实的 VPC IP 地址作为 Pod IP 范围。此选项允许单个集群内的 Pod 到 Pod 通信,以及在同一 VPC 中多个(VPC 原生)集群之间的通信。它还允许 Pod 直接连接到任何可路由的 VPC 实体,例如 GCE 实例。VPC 原生集群使用次要 IP 地址范围用于 Pod IP 和服务 IP 范围。VPC 原生集群提供以下优势:
-
Pod IP 地址在集群的 VPC 网络内以及通过 VPC 网络对等连接的 VPC 网络中是原生可路由的。
-
在您的集群中创建 Pod 之前,Pod IP 地址已在 VPC 网络中预留。这可以防止与 VPC 网络中的其他资源发生冲突,并允许您更好地规划 IP 地址分配。
-
Pod IP 地址范围不依赖于自定义静态路由。它们不会消耗系统生成的和自定义静态路由配额。相反,自动生成的子网路由处理 VPC 原生集群的路由。
-
您可以创建仅适用于 Pod IP 地址范围的防火墙规则,而不是集群节点上的任何 IP 地址。
-
Pod IP 地址范围,以及通常的子网次要 IP 地址范围,可以通过连接到 Cloud VPN 或 Cloud Interconnect 的本地网络使用 Cloud Router 访问。
基于路由的集群
使用 Google Cloud Routes 的集群称为基于路由的集群。Google Cloud routes 定义了网络流量从 VM 实例到其他目的地的路径。基于路由的集群中的 Pod IP 地址范围不是 VPC IP 地址,因此不能在 VPC 内部原生路由。为每个 Pod IP 地址范围创建 Cloud Routes,以便集群内的 Pods 可以与其他节点上运行的 Pods 通信。基于路由的集群不提供多个 Anthos GKE 集群之间的 Pod 到 Pod 跨集群连接。要创建基于路由的集群,您必须明确关闭 VPC 原生选项。
在基于路由的集群中,每个节点为 Pods 分配了一个/24 范围的 IP 地址。使用/24 范围,您有 256 个地址,但每个节点的最大 Pod 数量是 110。通过提供大约是可能 Pod 数量两倍的可用 IP 地址,Kubernetes 可以在 Pod 被添加到节点和从节点移除时减轻 IP 地址重用的风险。
基于路由的集群有一系列 IP 地址,用于 Pods 和 Services。尽管这个范围用于 Pods 和 Services,但它被称为Pod 地址范围。Pod 地址范围的最后/20 用于 Services。一个/20 范围有 4,096 个地址,这些地址既用于 Services 也用于 Pods。
在命令输出中,Pod 地址范围被称为 clusterIpv4Cidr,用于 Services 的地址范围被称为 servicesIpv4Cidr。例如,gcloud container clusters describe 的输出可能包含如下内容:
clusterIpv4Cidr: 10.96.0.0/16
...
servicesIpv4Cidr: 10.96.240.0/20
对于 GKE 1.7 版本及以后的版本,Pod 地址范围可以从任何 RFC1918 块:10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16。对于早期版本,Pod 地址范围必须来自 10.0.0.0/8。
给定 GKE 集群的节点、Pods 和 Services 的最大数量由集群子网的大小和 Pod 地址范围的大小决定。创建集群后,您不能更改 Pod 地址范围的大小。在创建集群时,请确保您选择的 Pod 地址范围足够大,以容纳集群预期的增长。
Anthos GKE 集群 IP 分配
Kubernetes 使用以下 IP 范围来为节点、Pods 和 Service 分配 IP 地址:
-
节点 IP—在 Anthos GKE 集群中,节点是一个 GCE 实例。每个节点都从集群的 VPC 网络中分配了一个 IP 地址。这个节点 IP 提供了从控制组件(如 kube-proxy 和 kubelet)到 Kubernetes API 服务器的连接。这个 IP 是节点连接到集群其余部分的方式。
-
Pod IP CIDR—每个节点都有一个 IP 地址池,GKE 将这些地址分配给在该节点上运行的 Pods(默认情况下为/24 CIDR 块)。在创建集群时,您可以可选地指定 IP 地址的范围。灵活的 Pod CIDR 范围功能允许您减小给定节点池中节点 Pod IP 地址范围的尺寸。每个 Pod 从其节点的 Pod CIDR 范围内分配一个单独的 IP 地址。这个 IP 地址由 Pod 内所有运行的容器共享,并将它们连接到集群中运行的其他 Pod。您可以在节点上运行的 Pod 的最大数量等于 Pod IP CIDR 范围的一半。例如,您可以在/24 范围内运行最多 110 个 Pod,而不是您可能预期的 256 个。这个 Pod 数量提供了一个缓冲区,以便 Pod 不会因为特定节点 Pod IP 地址范围内的 IP 地址暂时不足而变得不可调度。对于小于/24 的范围,可以安排的 Pod 数量是范围内 IP 地址数量的一半。
-
服务 IP—每个服务都有一个 IP 地址,称为 ClusterIP,从集群的 VPC 网络中分配。在创建集群时,您可以可选地自定义 VPC 网络。在 Kubernetes 中,您可以将任意键值对称为labels分配给任何 Kubernetes 资源。Kubernetes 使用标签将多个相关的 Pod 组合成一个逻辑单元,称为服务。服务有一个稳定的 IP 地址和端口,并为标签选择器中定义的所有标签匹配的 Pod 集提供负载均衡。
出流量和控制
对于 VPC 原生集群,Pod 的出流量使用正常的 VPC 路由功能进行路由。Pod IP 地址作为源 IP 地址保留在 TCP 头部。您必须创建适当的防火墙规则以允许 Pod 与其他 VPC 资源之间的流量。您还可以使用 NetworkPolicy 进一步控制集群内 Pod 之间的流量以及 Pod 的出流量。这些策略由上一节中解释的 GKE Dataplane 实现强制执行。在服务层,您可以通过 ASM 使用出口策略来控制什么流量离开集群。在这种情况下,一个名为 istio-egressgateway 的 Envoy 代理存在于服务网格的边缘,所有出流量都通过它流过。对于基于路由的集群,所有 Pod 的出流量都通过节点 IP 地址进行 NAT。
负载均衡器和入口
GKE 提供以下三种类型的负载均衡器来控制访问并尽可能均匀地分散集群中的入流量。您可以为一个服务同时配置多种类型的负载均衡器:
-
外部负载均衡器管理来自集群外部和您的 Google Cloud VPC 网络外部的流量。它们使用与 Google Cloud 网络关联的转发规则将流量路由到 Kubernetes 节点。
-
内部负载均衡器管理来自同一 VPC 网络内部的流量。与外部负载均衡器一样,它们使用与 Google Cloud 网络关联的转发规则将流量路由到 Kubernetes 节点。
-
HTTP(S)负载均衡器是专门用于 HTTP(S)流量的外部负载均衡器。它们使用 Ingress 资源而不是转发规则来将流量路由到 Kubernetes 节点。
这里描述的外部和内部负载均衡器是 TCP/L4 负载均衡器。如果您的服务需要从集群外部和您的 VPC 网络外部可达,您可以通过将服务类型字段设置为 Loadbalancer 来配置您的服务作为负载均衡器。然后 GKE 在服务前面部署一个网络负载均衡器。网络负载均衡器了解您集群中的所有节点,并配置您的 VPC 网络防火墙规则以允许从 VPC 网络外部连接到服务,使用服务的公共 IP 地址。您可以将静态公共 IP 地址分配给服务。
对于需要从同一 VPC 网络内部到达您的集群的流量,您可以配置您的服务以部署一个内部负载均衡器。内部负载均衡器从您的集群 VPC 子网中选择一个 IP 地址,而不是外部 IP 地址。VPC 网络内的应用程序或服务可以使用此 IP 地址与集群内的服务进行通信。以下是一个创建内部负载均衡器的服务描述示例。您可以通过删除注释(这会创建一个内部负载均衡器)以相同的方式配置外部负载均衡器:
apiVersion: v1
kind: Service
metadata:
name: ilb-service
annotations:
cloud.google.com/load-balancer-type: "Internal" ❶
labels:
app: hello
spec:
type: LoadBalancer ❷
selector:
app: hello
ports:
- port: 80
targetPort: 8080
protocol: TCP
❶ 该注释创建了一个内部 Google 负载均衡器。
❷ 创建一个 Google 负载均衡器
许多应用程序,如 RESTful Web 服务 API,使用 HTTP(S)进行通信。您可以通过使用 Kubernetes Ingress 资源允许 VPC 网络外部的客户端访问此类应用程序。Ingress 资源允许您将主机名和 URL 路径映射到集群内的服务。Ingress 资源与一个或多个服务对象相关联,每个对象都与一组 Pod 相关联。当您创建 Ingress 资源时,GKE Ingress 控制器创建一个 Google Cloud HTTP(S)负载均衡器,并根据 Ingress 及其相关服务的信息进行配置。要使用 Ingress,您必须启用 HTTP 负载均衡附加组件。GKE 集群默认启用 HTTP 负载均衡。GKE Ingress 资源有以下两种类型:
-
外部 HTTP(S)负载均衡器的 Ingress 部署了 Google Cloud 外部 HTTP(S)负载均衡器。这个面向互联网的负载均衡器作为管理可扩展的负载均衡资源池在全球 Google 边缘网络上部署。
-
内部 HTTP(S)负载均衡的 Ingress 部署了 Google Cloud 内部 HTTP(S)负载均衡器。这个内部 HTTP(S)负载均衡器由位于您的 GKE 集群外部但位于您的 VPC 网络之外的 Envoy 代理系统提供支持。
HTTP(S)负载均衡,由入口配置,包括以下功能:
-
服务灵活配置。入口定义了流量如何到达您的服务以及如何将流量路由到您的应用程序。此外,入口可以为您的集群中的多个服务提供一个单一的 IP 地址。
-
与 Google Cloud 网络服务的集成。
-
支持多个 TLS 证书。入口可以指定使用多个 TLS 证书进行请求终止。
当您创建入口资源时,GKE 根据清单中的规则和相关服务清单在 Google Cloud 项目中配置 HTTP(S)负载均衡器。负载均衡器向节点的 NodePort 发送请求。在请求到达节点后,选择的 GKE Dataplane 将流量路由到适当的 Pod(对于所需的服务)。对于 Dataplane v1,节点使用其 iptables NAT 表来选择 Pod。kube-proxy 管理节点上的 iptables 规则。对于 Dataplane v2,GKE 使用 eBPF 和 Cilium 代理提供此功能。
在以下示例中,入口定义将 demo.example.com 的流量路由到名为 frontend 的服务,端口为 80,将 demo-backend.example.com 的流量路由到名为 users 的服务,端口为 8080:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
rules:
- host: demo.example.com ❶
http:
paths:
- backend:
serviceName: frontend ❶
servicePort: 80 ❶
- host: demo-backend.example.com ❷
http:
paths:
- backend:
serviceName: users ❷
servicePort: 8080 ❷
❶ 请求 demo.example.com 的托管服务被转发到端口 80 上的服务 frontend。
❷ 请求 demo-backend.example.com 的托管服务被转发到端口 8080 上的服务用户。
容器原生负载均衡
容器原生负载均衡是在 GKE 中使用网络端点组(NEGs)直接对 Pod 端点进行负载均衡的实践。使用入口,服务绑定的流量从 HTTP 负载均衡器发送到节点上的任何节点 IP。在请求到达节点后,GKE Dataplane 将流量路由到所需的 Pod,这个过程会产生额外的跳数。在某些情况下,Pod 甚至可能不在节点上运行,因此节点将请求发送到运行所需 Pod 的节点。额外的跳数增加了延迟,并使流量路径更加复杂。
使用 NEGs 时,流量直接从负载均衡器负载均衡到 Pod IP,而不是穿越节点。此外,Pod 就绪网关被实施,以从负载均衡器的角度确定 Pod 的健康状况,而不仅仅是 Kubernetes 集群内的健康探测。这使得负载均衡器基础设施能够意识到生命周期事件,如 Pod 启动、Pod 丢失或 VM 丢失,从而提高了整体流量的稳定性。这些功能解决了之前描述的限制,并导致网络性能更高且更稳定。
当以下所有条件都为真时,默认为服务启用容器原生负载均衡:
-
对于在 GKE 集群 1.17.6-gke.7 及更高版本中创建的服务
-
使用 VPC 原生集群
-
不使用共享 VPC
-
不使用 GKE 网络策略
对于 NEGs 不是默认设置的集群,仍然强烈建议使用容器本机负载均衡,但必须在每个服务的基础上显式启用。该注解应按以下方式应用于服务:
kind: Service
...
annotations:
cloud.google.com/neg: ‘{"ingress": true}’ ❶
...
❶ 该注解为服务中的 Pod 创建一个网络端点组。
在服务清单中,您必须使用 type: NodePort,除非您正在使用容器本机负载均衡。如果您正在使用容器本机负载均衡,请使用 type: ClusterIP。
共享 VPC 的考虑事项和最佳实践
GKE 入口控制器使用 Google Cloud 服务帐户来部署和管理 Google Cloud 资源。当 GKE 集群位于共享 VPC 的服务项目中时,此服务帐户可能没有管理主机项目拥有的网络资源的权利。入口控制器积极管理防火墙规则,以提供负载均衡器和 Pod 之间以及集中式健康检查器和 Pod 之间的访问。您可以通过以下方式管理:
-
手动防火墙规则提供—如果您的安全策略仅允许从主机项目进行防火墙管理,您可以手动提供这些防火墙规则。当在共享 VPC 中部署入口时,入口资源事件提供了您需要提供访问的具体防火墙规则。要手动提供防火墙规则,请使用 describe 命令查看入口资源:
kubectl describe ingress INGRESS_NAME此命令的输出,如下所示,应包含可以在主机网络项目中实施的所需防火墙规则:
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Sync 9m34s (x237 over 38h) loadbalancer-controller Firewall change required by network admin: `gcloud compute firewall-rules update k8s-fw-l7--6048d433d4280f11 --description "GCE L7 firewall rule" --allow tcp:30000-32767,tcp:8080 --source-ranges 130.211.0.0/22,209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 --target-tags gke-l7-ilb-test-b3a7e0e5-node --project <project>` -
自动防火墙规则提供—一种自动方法是授予 GKE 入口控制器服务帐户更新防火墙规则的权限。您通过创建自定义 IAM 角色,提供在主机网络项目中管理防火墙规则的能力,然后将此角色授予 GKE 入口服务帐户。
首先,创建一个具有所需权限的自定义 IAM 角色:
gcloud iam roles create ROLE_NAME \ --project PROJECT_ID \ --title ROLE_TITLE \ --description ROLE_DESCRIPTION \ --permissions=compute.networks.updatePolicy, compute.firewalls.*\ --stage GA
然后,将自定义角色授予 GKE 入口控制器服务帐户:
gcloud projects add-iam-policy-binding my-project \
--member=user:SERVICE_ACCOUNT \
--role=roles/gke-ingress-fw-management
多集群入口
在某些情况下,您必须在多个 GKE 集群上运行相同的服务。多集群拓扑结构由许多因素驱动,包括应用的用户邻近性、集群和区域高可用性、安全性和组织分离、集群迁移以及数据本地性。多集群 入口(MCI),如图 10.8 所示,是用于 Anthos GKE 集群的云托管多集群入口控制器。它是一个由 Google 托管的云服务,支持在集群和区域之间部署共享的负载均衡资源。多集群入口旨在满足多集群、多区域环境的负载均衡需求。它是外部 HTTP(S)负载均衡器的控制器,用于提供来自互联网的流量在单个或多个集群之间的入口。多集群入口的多集群支持满足许多用例,包括以下内容:
-
一个单一、一致的 VIP,与应用部署的全球位置无关
-
通过健康检查和流量故障转移实现的多区域、多集群可用性
-
通过公共 Anycast VIP 进行基于邻近性的路由,以降低客户端延迟
-
透明集群迁移以进行升级或集群重建

图 10.8 多集群入口到 GCP 中的多个 GKE 集群
多集群入口是一个 Ingress 控制器,它使用 NEGs(网络端点组)来编程外部 HTTP(S)负载均衡器。当你创建一个 MultiClusterIngress 资源时,GKE 会部署计算引擎负载均衡器资源,并在集群中配置适当的 Pod 作为后端。NEGs 用于动态跟踪 Pod 端点,因此 Google 负载均衡器拥有正确的健康后端集合。
多集群入口使用集中的 Kubernetes API 服务器在多个集群中部署入口。这个集中的 API 服务器被称为配置集群。任何 GKE 集群都可以充当配置集群。配置集群使用两种自定义资源类型:MultiClusterIngress 和 MultiClusterService。通过在配置集群上部署这些资源,Anthos 入口控制器在多个集群中部署负载均衡器。以下概念和组件构成了多集群入口:
-
Anthos 入口控制器—一个全球分布的控制平面,作为集群外部的服务运行。这允许控制器的生命周期和操作独立于 GKE 集群。
-
配置集群—一个选择的运行在 Google Cloud 上的 GKE 集群,其中部署了 MultiClusterIngress 和 MultiClusterService 资源。这是这些多集群资源的集中控制点,这些资源存在于单个逻辑 API 中,并且可以从单个逻辑 API 访问,以保持所有集群的一致性。入口控制器监视配置集群并协调负载均衡基础设施。
-
舰队—一个将集群和基础设施分组的概念,管理资源,并在它们之间保持一致的政策(有关舰队的更多详细信息,请参阅第二章)。MCI 使用舰队的概念来应用不同集群中的入口。你注册到舰队的集群对 MCI 可见,因此可以用作入口的后端。舰队具有一种称为命名空间一致性的特性,它假设跨集群中具有相同名称和相同命名空间的资源是同一资源的实例。实际上,这意味着不同集群中 ns1 命名空间具有标签 app: foo 的 Pod 都被视为多集群入口视角下的同一应用后端池的一部分。图 10.9 显示了两个服务 foo 和 bar 在两个集群上运行,并由 MCI 进行负载均衡的示例。
![10-09]()
图 10.9 多集群入口:舰队和命名空间一致性
-
成员集群—注册到舰队中的集群被称为成员集群。舰队中的成员集群构成了 MCI 所了解的后端的全范围。
在配置集群配置完成后,您为您的多集群 Service 创建了两个自定义资源,MultiClusterIngress 和 MultiClusterService。请注意,资源名称与 Service 和 Ingress 相比较相似,这是在单个集群中需要 Ingress 的。以下是在配置集群上部署的这些资源的示例:
# MulticlusterService with cluster selector
apiVersion: networking.gke.io/v1beta1
kind: MultiClusterService
metadata:
name: foo
namespace: blue
spec:
template:
spec:
selector:
app: foo
ports:
- name: web
protocol: TCP
port: 80
targetPort: 80
clusters: ❶
- link: "europe-west1-c/gke-eu" ❷
- link: "asia-northeast1-a/gke-asia-1" ❷
# MulticlusterIngress
apiVersion: networkin.g.gke.io/v1alpha1
kind: MultiClusterIngress
metadata:
name: foobar-ingress
namespace: blue
spec:
template:
spec:
backend:
serviceName: default-backend
servicePort: 80
rules:
- host: foo.example.com
backend:
serviceName: foo ❸
servicePort: 80
- host: bar.example.com
backend:
serviceName: bar ❸
servicePort: 80
❶ MultiClusterService 规范看起来与 Service 规范类似,增加了一个集群部分来定义在多个集群中的 Service。
❷ 多个集群中运行的 Service 的 GKE 集群 URI 链接
❸ MultiClusterIngress 规范与 Ingress 规范类似,但指向的是 MultiClusterService(而不是 Service)。
注意,MulticlusterService 在底部包含一个集群选择段。移除此段会将 Ingress 流量发送到所有成员集群。如果您想从特定集群(或多个集群)中移除 MCI 流量(例如,如果您正在对集群进行升级或维护),则添加集群选择器可能很有用。如果 MulticlusterService 资源中存在集群段,则 Ingress 流量只会发送到列表中可用的集群。集群通过 <region | zone>/
Anthos on-prem(在 VMware 上)
在 VMware 上的 Anthos on-prem 集群自动创建一个岛屿模式配置,其中 Pods 可以在集群内部直接相互通信,但不能从集群外部访问。这种配置在网络上形成一个“岛屿”,该岛屿未连接到外部网络。集群在集群节点之间形成一个完整的节点到节点的网状结构,允许 Pod 直接访问集群内的其他 Pod。
网络要求
Anthos on-prem 集群是通过一个管理员工作站虚拟机安装的,该虚拟机包含部署 Anthos on-prem 集群所需的所有工具和配置。管理员工作站虚拟机部署一个管理员集群。管理员集群部署一个或多个用户集群。您的应用程序运行在用户集群上。管理员集群管理多个用户集群的部署和生命周期。您不会在管理员集群上运行应用程序。在您的 Anthos on-prem 初始安装中,您创建了以下虚拟机(VM):
-
一个用于管理员工作站的虚拟机
-
四个用于管理员集群的虚拟机
-
三个用于用户集群的虚拟机(如果需要,您还可以创建额外的用户集群或更大的用户集群)
在您的 vSphere 环境中,您必须有一个能够支持创建这些虚拟机的网络。您的网络还必须能够支持 vCenter Server 和负载均衡器。您的网络需要支持向互联网的出站流量,以便您的管理工作站和集群节点可以获取 GKE 本地组件并调用某些 Google 服务。如果您想外部客户端调用您的 GKE 本地集群中的服务,您的网络必须支持来自互联网的入站流量。IP 地址架构和分配将在下一节讨论。
Anthos 本地集群 IP 分配
在 VMware 集群上运行 Anthos 本地所需的以下 IP 地址:
-
节点 IP—节点(虚拟机或 VM)的动态主机配置协议(DHCP)或静态分配的 IP 地址。必须在数据中心内可路由。您可以手动分配静态 IP。节点 IP 地址取决于 Anthos 本地集群中负载均衡器的实现。如果集群配置为集成模式负载均衡或捆绑模式负载均衡,您可以为节点使用 DHCP 或静态分配的 IP 地址。如果集群配置为手动模式负载均衡,您必须为节点使用静态 IP 地址。在这种情况下,请确保预留足够的 IP 地址以应对集群增长。负载均衡模式将在下一节详细讨论。
-
Pod IP CIDR—集群中所有 Pod 的非路由 CIDR 块。从这个范围中,每个节点分配较小的/24 范围。如果您需要一个N节点的集群,请确保此块足够大,以支持N x /24 块。
-
服务 IP—在孤岛模式下,类似于 Pod CIDR 块,因此这仅在集群内部使用,是任何不与节点、VIP 或 Pod CIDR 块重叠的私有 CIDR 块。您可以在多个集群之间共享相同的块。块的大小决定了服务的数量。除了您的服务外,一个服务 IP 地址块还用于集群控制平面服务。入口服务需要一个服务 IP,Kubernetes 服务(如集群 DNS)需要 10 个或更多的 IP 地址。
出站流量和控制
从 Pod 到集群外部的所有出站流量都通过节点 IP 进行 NAT。您可以使用 NetworkPolicy 进一步控制集群内 Pod 之间的流量以及 Pod 的出站流量。这些策略由每个集群内运行的 Calico 强制执行。在服务层,您可以通过 ASM 使用 EgressPolicy 来控制什么流量离开集群。在这种情况下,一个名为 istio-egressgateway 的 Envoy 代理存在于服务网格的边缘,所有出站流量都通过它流过。
负载均衡器
Anthos 本地集群提供两种从集群外部访问服务的方法:负载均衡器和入口。本节讨论负载均衡器和不同的实现模式。
Anthos on-prem 集群可以运行在三种负载均衡模式之一:集成、手动或捆绑:
-
集成模式—使用集成模式时,Anthos on-prem 使用 F5 BIG-IP 负载均衡器。客户需要提供带有适当许可的 F5 BIG-IP 负载均衡器。您需要拥有足够的权限来设置和管理 F5 负载均衡器的用户角色。管理员角色或资源管理员角色就足够了。有关更多信息,请参阅
mng.bz/oJnN。您需要预留多个 VIP 地址用于服务,这些服务被配置为负载均衡器类型。每个服务需要一个 VIP。所需的 VIP 数量取决于负载均衡器类型服务的数量。您需要在集群配置文件中指定这些 VIP,并且 Anthos on-prem 会自动配置 F5 BIG-IP 负载均衡器以使用这些 VIP。集成模式的优势在于您可以使用企业级负载均衡器,并且其配置主要是自动化的。此模式也是具有偏见的,因为它要求使用 F5 负载均衡器,这可能会产生额外的许可和支持成本。
-
手动模式—使用手动模式时,Anthos on-prem 使用您选择的负载均衡器。与集成模式相比,手动负载均衡模式需要额外的配置。您需要手动配置用于服务的 VIP。在手动负载均衡的情况下,您不能运行负载均衡器类型的服务。相反,您可以创建节点端口类型的服务,并手动配置负载均衡器以使用它们作为后端。您必须指定用于这些服务的节点端口值。您可以选择 30000-32767 范围内的值。有关更多信息,请参阅
mng.bz/nJov。手动模式的优势在于您在选择负载均衡器方面拥有绝对自由。另一方面,配置是手动的,这可能会导致运营成本增加。
-
捆绑模式—在捆绑负载均衡模式下,Anthos on-prem 提供并管理负载均衡器。与集成模式不同,不需要为负载均衡器购买许可证,并且您必须进行的设置工作非常少。GKE on-prem 提供的捆绑负载均衡器是 Seesaw 负载均衡器 (
github.com/google/seesaw)。Seesaw 负载均衡器在 VMware 内作为虚拟机运行。我们建议您在捆绑负载均衡模式下使用 vSphere 6.7+ 和 Virtual Distributed Switch 6.6+。您可以在高可用性 (HA) 和非 HA 模式下运行 Seesaw 负载均衡器。在 HA 模式下,配置了两个 Seesaw 虚拟机。在非 HA 模式下,配置了一个 Seesaw 虚拟机。捆绑模式的优点是一个团队可以监督集群创建和负载均衡器配置。例如,集群管理团队不需要依赖单独的网络团队提前获取、运行和配置负载均衡器。另一个优点是配置完全自动化。Anthos on-prem 会自动在负载均衡器上配置服务 VIP。
在 VMware 集群中,只要在服务的规范中配置了 loadBalancerIP 字段,Anthos on VMware 集群就可以运行类型为 Loadbalancer 的服务。在 loadBalancerIP 字段中,您需要提供您想要使用的 VIP。这将配置在 F5 上,指向服务的 NodePort。
以下是一个服务清单的示例。您可以通过 SERVICE VIP 访问名为 frontend 的 Anthos on-prem 集群内部运行的服务:
apiVersion: v1
kind: Service
metadata:
labels:
app: guestbook
name: frontend
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: guestbook
type: LoadBalancer
loadBalancerIP: [SERVICE VIP] ❶
❶ 负载均衡器 IP 地址在服务规范中定义。
除了服务 VIP 之外,负载均衡器还需要 Kubernetes API 服务器的控制平面 VIP。最后,每个 Anthos on-prem 集群内部运行一个 Ingress 控制器。Ingress 控制器服务也有一个称为 Ingress VIP 的 VIP。通过 Ingress 暴露的服务使用 Ingress VIP 访问 Kubernetes 服务。
Anthos on-prem 的高级负载均衡架构如图 10.10 所示。

图 10.10 Anthos on-prem:负载均衡器网络架构
表 10.2 总结了在各种模式下准备负载均衡必须执行的操作。
表 10.2 如何为负载均衡做准备
| 集成/捆绑模式 | 手动模式 | |
|---|---|---|
| 在创建集群之前选择 VIP | 是 | 是 |
| 在创建集群之前选择节点 IP 地址 | 如果使用 DHCP 否,如果使用静态 IP 地址 是 | 是 |
| 在创建集群之前选择 nodePort 值 | 否 | 是 |
| 手动配置您的负载均衡器 | 否 | 是 |
Ingress
Anthos on-prem 包含一个基于 Envoy 的 Ingress 控制器的 L7 负载均衡器,该控制器处理集群内部部署的 ClusterIP 服务中的 Ingress 对象规则。Ingress 控制器本身在集群中作为 NodePort 服务暴露。Ingress NodePort 服务可以通过 L3/L4 F5 负载均衡器访问。安装配置了负载均衡器上的 VIP 地址(Ingress VIP)(端口 80 和 443)。VIP 指向 Ingress 控制器的 NodePort 服务端口。这就是外部客户端如何访问集群中的服务。
要通过 Ingress 暴露服务,您必须创建一个 DNS A 记录,将 DNS 名称指向 Ingress VIP。然后您可以创建一个服务和一个 Ingress 资源。例如,假设您想暴露一个示例 guestbook 应用程序的前端服务。首先,为 guestbook 应用程序创建一个指向 Ingress VIP 的 DNS A 记录,如下所示:
*.guestbook.com A [INGRESS_VIP]
接下来,为前端部署创建一个服务。请注意,服务类型为 ClusterIP:
apiVersion: v1
kind: Service
metadata:
labels:
app: guestbook
name: frontend
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: guestbook
type: ClusterIP ❶
❶ 对于入口,服务类型是 ClusterIP(而不是 Loadbalancer)。
最后,创建入口规则:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: frontend
labels:
app: guestbook
spec:
rules:
- host: www.guestbook.com
http:
paths:
- backend:
serviceName: frontend ❶
servicePort: 80 ❶
❶ 入口规则指向服务名称和端口。
Anthos 在裸金属上
Anthos 在裸金属上是 GCP 支持的 Anthos GKE 实现,部署在裸金属服务器上。Anthos 在裸金属上消除了对虚拟化层或虚拟机管理程序的必要性。所有集群节点和 API 服务器都直接在裸金属服务器上运行。
Anthos 在裸金属部署模型和网络架构的详细描述见第十七章。
Anthos on AWS
AWS 上的 Anthos 集群(GKE on AWS)是一种混合云软件,它将 Google Kubernetes Engine 扩展到 Amazon Web Services。Anthos on AWS 使用 AWS 资源,如弹性计算云(EC2)、弹性块存储(EBS)和弹性负载均衡器(ELB)。AWS 上的 Anthos 集群具有以下两个组件:
-
管理服务—一个可以安装和更新您的用户集群的环境,使用 AWS API 来配置资源
-
用户集群—运行您的容器化应用程序的 Anthos on AWS 集群
网络需求
管理服务和用户集群都部署在 EC2 实例上的 AWS VPC 内。您可以在一个 专用 AWS VPC (mng.bz/v1ax) 或一个 现有 AWS VPC (mng.bz/41GB) 中创建您的管理服务。在您运行 Anthos on AWS 用户集群的每个 AWS VPC 中都需要一个管理服务。管理服务安装在单个 AWS 可用区中。每个 VPC 只需要一个管理服务;一个管理服务可以管理多个用户集群。
用户集群由两个组件组成:控制平面或 Kubernetes API 服务器以及运行应用程序的节点池。管理服务的主要组件是集群操作员。集群操作员是一个 Kubernetes 操作员,它创建和管理您的 AWSClusters 和 AWSNodePools。集群操作员将配置存储在具有存储在 AWS EBS 卷上的持久存储的 etcd 数据库中。AWSClusters 资源创建和管理用户集群的控制平面,AWSNodePools 资源创建和管理用户集群的节点池。
当您将管理集群安装到专用 VPC 中时,Anthos on AWS 在您在 dedicatedVPC.availabilityZones 中指定的每个区域创建控制平面副本。当您将管理集群安装到现有基础设施中时,Anthos on AWS 在相同的可用区创建一个具有三个控制平面副本的 AWSCluster。每个副本属于其自己的 AWS Auto Scaling 组,当实例被终止时,它会重新启动实例。管理服务将控制平面放置在 AWS 网络负载均衡器(NLB)后面的私有子网中。管理服务使用 NLB 与控制平面交互。
如图 10.11 所示,每个控制平面将配置存储在本地 etcd 数据库中。这些数据库被复制并设置在堆叠的高可用拓扑中 (mng.bz/wPKW)。一个控制平面管理一个或多个 AWSNodePools。

图 10.11 Anthos on AWS 架构
在专用 VPC 中创建 Anthos on AWS 集群时,需要以下 VPC 资源:
-
VPC CIDR 范围—anthos-gke 创建的 AWS VPC 的 IP 地址总 CIDR 范围,例如,10.0.0.0/16。
-
可用区—您想要在其中创建节点和控制平面的 AWS EC2 可用区。
-
私有 CIDR 块—您的私有子网的 CIDR 块。Anthos on AWS 组件(如管理服务)在私有子网中运行。此子网必须在 vpcCIDRBlock 中指定的 VPC 的 CIDR 范围内。您需要为每个可用区分配一个子网。
-
公共 CIDR 块—您的公共子网的 CIDR 块。您需要为每个可用区分配一个子网。公共子网将集群服务(如负载均衡器)暴露给 AWS 网络访问控制列表和安全组中指定的安全组和地址范围。
-
SSH CIDR 块—允许对您的堡垒主机进行 SSH 入站的 CIDR 块。例如,您可以使用 IP 范围,如 203.0.113.0/24。如果您想允许从任何 IP 地址进行 SSH,请使用 0.0.0.0/0。当您使用默认设置创建管理服务时,控制平面有一个私有 IP 地址。此 IP 地址无法从 AWS VPC 外部访问。您可以使用 堡垒主机 或使用其他连接到 AWS VPC 的方式(如 VPN 或 AWS Direct Connect (
aws.amazon.com/directconnect/)) 访问管理服务。
在现有 VPC 中创建 Anthos on AWS 集群时,需要以下 VPC 资源:
-
至少一个公共子网。
-
至少一个私有子网。
-
一个具有指向公共子网路由的互联网网关。
-
一个具有指向私有子网路由的 NAT 网关。
-
启用 DNS 主机名。
-
在您的 DHCP 选项集中没有为域名指定自定义值。Anthos on AWS 不支持除默认 EC2 域名以外的值。
-
选择或创建一个 AWS 安全组,允许从您将管理 AWS 安装上的 Anthos 集群的安全组或 IP 范围(端口 22)进行 SSH 入站。
Anthos on AWS 集群 IP 分配
管理服务创建用户集群,并使用具有资源的集群操作员 AWSClusters 和 AWSNodePools 分别创建用户集群的控制平面和节点池。每个用户集群的 IP 地址在 AWSCluster 资源中定义。以下是一个 AWSCluster 资源的示例:
apiVersion: multicloud.cluster.gke.io/v1
kind: AWSCluster
metadata:
name: CLUSTER_NAME
spec:
region: AWS_REGION
networking: ❶
vpcID: VPC_ID
podAddressCIDRBlocks: POD_ADDRESS_CIDR_BLOCKS
serviceAddressCIDRBlocks: SERVICE_ADDRESS_CIDR_BLOCKS
ServiceLoadBalancerSubnetIDs: SERVICE_LOAD_BALANCER_SUBNETS
controlPlane: ❷
version: CLUSTER_VERSION
instanceType: AWS_INSTANCE_TYPE
keyName: SSH_KEY_NAME
subnetIDs:
- CONTROL_PLANE_SUBNET_IDS
securityGroupIDs:
- CONTROL_PLANE_SECURITY_GROUPS
iamInstanceProfile: CONTROL_PLANE_IAM_ROLE
rootVolume:
sizeGiB: ROOT_VOLUME_SIZE
etcd:
mainVolume.sizeGIB: ETCD_VOLUME_SIZE
databaseEncryption:
kmsKeyARN: ARN_OF_KMS_KEY
hub: # Optional
membershipName: ANTHOS_CONNECT_NAME
workloadIdentity: # Optional
oidcDiscoveryGCSBucket: WORKLOAD_IDENTITY_BUCKET
❶ 定义了 Anthos on AWS 集群的网络值。
❷ 定义了 Anthos on AWS 集群的控制平面值。
您在网络部分定义所需的 IP 地址。
Anthos on AWS 集群需要以下 IP 地址:
-
节点 IP—节点 IP 在创建 EC2 实例时分配。每个 EC2 实例在其可用区中分配一个私有子网的单个 IP。这些地址在管理服务规范中定义。
-
Pod IP CIDR—集群 Pod 使用的 IPv4 地址的 CIDR 范围。该范围必须在您的 VPC CIDR 地址范围内,但不能是子网的一部分。
-
服务 IP—集群服务使用的 IPv4 地址范围。该范围必须在您的 VPC CIDR 地址范围内,但不能是子网的一部分。
出站流量和控制
从 Pod 到集群外部的所有出站流量都通过节点 IP 进行 NAT。您可以使用 NetworkPolicy 进一步控制集群内 Pod 之间的流量以及 Pod 的出站流量。这些策略由每个集群内运行的 Calico 强制执行。在服务层,您可以通过 ASM 使用 EgressPolicy 来控制离开集群的流量。在这种情况下,一个名为 istio-egressgateway 的 Envoy 代理存在于服务网格的边缘,所有出站流量都通过它流动。
此外,您可以在 AWSNodePools 安全组层控制流量。使用安全组,您可以进一步允许或拒绝进出流量的访问。
负载均衡器
当您创建一个类型为 Loadbalancer 的服务时,Anthos on AWS 控制器会在 AWS 上配置一个经典或网络 ELB。Anthos on AWS 需要在包含负载均衡器端点的子网上使用标签。Anthos on AWS 会自动为 AWSCluster 资源中 Networking.ServiceLoadBalancerSubnetIDs 字段指定的所有子网添加标签(mng.bz/X5mY)。
要创建标签,获取负载均衡器子网的子网 ID。使用 aws 命令行工具在子网上创建标签,如下所示。对于多个子网,请确保子网 ID 之间用空格分隔:
aws ec2 create-tags \
--resources [SUBNET_IDs] \
--tags Key=kubernetes.io/cluster/$CLUSTER_ID,Value=shared
您需要在子网上为每个用户集群添加一个标签。
您可以创建内部和外部负载均衡器。内部负载均衡器在私有子网上创建,而外部负载均衡器在公共子网上创建。您可以使用经典或网络负载均衡器创建任何类型的负载均衡器。有关负载均衡器类型之间的差异的更多信息,请参阅 AWS 文档(mng.bz/ydpJ)。
使用注解创建不同类型的负载均衡器。考虑以下服务规范:
apiVersion: v1
kind: Service
metadata:
name: my-lb-service
spec:
type: LoadBalancer
selector:
app: products
department: sales
ports:
- protocol: TCP
port: 60000
targetPort: 50001
此资源为服务创建一个经典公共负载均衡器。要创建公共网络负载均衡器,请将以下注解添加到前面的规范中:
...
metadata:
name: my-lb-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb ❶
...
❶ 该注解在 AWS 中创建一个经典公共负载均衡器,并暴露一个服务。
要创建一个私有经典负载均衡器,请将以下注解添加到服务规范中:
...
metadata:
name: my-lb-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true" ❶
...
❶ 该注解在 AWS 中创建一个内部负载均衡器,并暴露一个服务。
最后,要创建一个私有网络负载均衡器,请将这两个注解添加到服务规范中:
...
metadata:
name: my-lb-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb ❶
service.beta.kubernetes.io/aws-load-balancer-internal: "true" ❶
...
❶ 这两个注解共同在 AWS 中创建了一个内部网络负载均衡器。
Ingress
您可以在 AWS 集群上的 Anthos 中以下两种方式使用 Ingress:
-
应用程序负载均衡器—应用程序负载均衡器 (ALB) (
mng.bz/Mlr2) 是一个 AWS 管理的 L7 HTTP 负载均衡器。负载均衡器接收到请求后,将按优先级顺序评估监听器规则,以确定要应用哪个规则,然后从目标组中选择一个目标进行规则操作。此方法使用安装在 Anthos on AWS 集群中的 alb-ingress-controller,并具有适当的权限来为 Ingress 创建 ALB。 -
ASM Ingress—您可以在 Anthos on AWS 集群上安装 Anthos 服务网格并使用 ASM Ingress。ASM Ingress 是一个名为 istio-ingressgateway 的服务,它位于服务网格边缘的 L7 Envoy 代理中。istio-ingressgateway 服务本身使用 ELB 暴露,如前所述。所有 L7 负载均衡和路由都由 istio-ingressgateway 处理。
使用 Ingress 暴露服务
要使用 ALB 方法,请按照mng.bz/aMpJ中的说明操作,并将 alb-ingress-controller 部署到 Anthos on AWS 集群。alb-ingress-controller 是一个在 Anthos on AWS 集群上运行的 Deployment,具有适当的 AWS 凭证和 Kubernetes RBAC 权限,可以创建创建 ALB 所需的规则和资源。
您现在可以创建一个带有适当注解的 Ingress 资源,以创建 ALB 和您服务所需的相关资源。以下是一个服务规范的示例。请注意,服务类型必须是 NodePort:
apiVersion: v1
kind: Service
metadata:
name: "service-2048"
namespace: "2048-game"
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app: "2048"
下一个展示了使用 ALB 暴露此服务的 Ingress 资源。注意配置面向互联网 ALB 的两个注解:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: "2048-ingress"
namespace: "2048-game"
annotations:
kubernetes.io/ingress.class: alb ❶
alb.ingress.kubernetes.io/scheme: internet-facing ❶
labels:
app: 2048-ingress
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: "service-2048"
servicePort: 80
❶ 这些注解在 AWS 中创建了一个面向互联网的应用程序负载均衡器。
您还可以使用 ASM Ingress 来暴露您的服务。要使用 ASM,请按照mng.bz/gJKR中的步骤在您的 Anthos on AWS 集群上安装 ASM。一旦 ASM 安装完成,您应该在 istio-system 命名空间中看到 istio-ingressgateway 部署和服务。
服务规范的示例如下。请注意,服务类型是 ClusterIP,而不是在 ALB 方法中使用的 NodePort。原因是,在 ASM 的情况下,L7 代理在集群内部运行,而 ALB 是一个在集群外部运行的托管 HTTP 负载均衡器:
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-app
name: hello-app
spec:
type: ClusterIP
selector:
app: hello-app
ports:
- protocol: TCP
port: 8080
targetPort: 8080
Ingress 资源如下所示。注意使用 ASM 的注解:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: istio ❶
labels:
app: hello-app
name: hello-app
spec:
rules:
- host:
http:
paths:
- backend:
serviceName: hello-app
servicePort: 8080
❶ 该注解使用 Istio Ingress 控制器。
Anthos 附加集群
Anthos 集群的最后一种类型是附加集群。附加集群允许你在 Google Cloud 控制台中查看你的现有 Kubernetes 集群以及你的 Anthos 集群,并在它们上启用 Anthos 的一些功能子集,包括与 Anthos Config Management 的配置。你可以将任何符合标准的 Kubernetes 集群附加到 Anthos,并在 Cloud 控制台中与你的 Anthos 集群一起查看。
无论你的集群在哪里,你都需要使用 Connect 将你想要与 Anthos 一起使用的任何集群注册到你的项目舰队中。舰队提供了一种统一的方式来查看和管理多个集群及其工作负载,作为 Anthos 的一部分。我们之前讨论了与 GCP 上的 Anthos GKE 相关的舰队,但本地集群也可以加入舰队。任何 Anthos 集群都可以成为任何单一舰队的成员,尽管并非所有功能都可用,这取决于集群的位置。
网络要求
要成功注册你的集群,你需要确保以下域名可以从你的 Kubernetes 集群中访问:
-
cloudresourcemanager.googleapis.com—解决有关连接集群的 Google Cloud 项目的元数据
-
oauth2.googleapis.com—为了获取针对 gkeconnect.googleapis.com 的代理操作的短期 OAuth 令牌
-
gkeconnect.googleapis.com—用于接收来自 Google Cloud 的请求并发出响应的通道
-
gkehub.googleapis.com—用于创建与 Google Cloud 连接的集群相对应的 Google Cloud 端的枢纽成员资源
-
www.googleapis.com—用于验证来自传入 Google Cloud 服务请求的服务令牌
-
gcr.io—用于拉取 GKE Connect 代理镜像
如果你使用代理进行 Connect,你还必须更新代理的允许列表以包含这些域。如果你使用 gcloud 注册你的 Kubernetes 集群,这些域也必须在运行 gcloud 命令的舰队中可访问。
你只需要对这些域的 443 端口进行出站连接。注册附加集群不需要入站连接。你也可以使用 VPC 服务控制来提供额外的 TE 安全性。
使用 VPC 服务控制
如果你在应用程序中使用 VPC 服务控制 (mng.bz/51z1) 以提供额外的数据安全,请确保以下服务位于你的服务边界内:
-
资源管理器 API (cloudresourcemanager.googleapis.com)
-
GKE Connect API (gkeconnect.googleapis.com)
-
GKE Hub API (gkehub.googleapis.com)
你还需要设置私有连接以访问相关的 API。你可以在 mng.bz/610D 上找到如何做到这一点的方法。
10.2.2 Anthos GKE IP 地址管理
除了 Anthos GKE on GCP 之外,所有其他 Anthos 集群都在岛模式配置下运行,其中 Pod 可以在集群内部直接相互通信,但不能从集群外部访问。这种配置在网络上形成一个“岛屿”,该岛屿不连接到外部网络。这允许您使用相同的 IP 寻址创建多个 Anthos 集群。
对于岛模式下的 Anthos 集群,IP 地址管理和 IP 耗尽不是问题。您可以采用标准化的 IP 方案,并为所有集群使用相同的方案。
GCP 建议在 GCP 集群上运行 Anthos GKE,以 VPC 原生模式运行。在 VPC 原生模式下,任何集群使用的 IP 地址都是真实的 VPC IP 地址。这意味着在 VPC 原生集群中,您不能使用重叠的 IP 地址,并且必须为每个集群使用唯一的子网。回想一下,每个 Anthos GKE on GCP 集群都需要以下三个 IP 范围:
-
节点 IP—分配给 GCE 实例或属于集群的节点。每个节点需要一个 IP 地址。这些 IP 地址使用主子网自动分配。
-
Pod IP CIDR—分配给集群内部运行的每个 Pod。集群分配一个大子网。集群控制平面将这个大子网划分为更小的子网,每个子网(大小相等)分配给每个节点。例如,您可以有一个 Pod IP CIDR 为 10.0.0.0/16,集群控制平面将大小为/24 的子网(从 Pod IP CIDR 块中)分配给每个节点,第一个节点为 10.0.0.0/24,第二个节点为 10.0.1.0/24,依此类推。
-
服务 IP CIDR—分配给集群内部运行的服务。每个类型为 ClusterIP 的服务都需要一个 IP 地址。
让我们逐一更详细地讨论这些问题。
节点 IP
要确定节点 IP 池的大小,您必须知道以下信息:
-
GCP 区域中的集群数量
-
每个集群的最大节点数
如果您有大小相等的集群,您可以直接将这两个数字相乘,以得到在该区域运行所需的最大节点总数:
total number of nodes = number of clusters x max number of nodes per cluster
您可以从表 10.3 中确定节点 IP 子网所需的主机位。
表 10.3 确定所需的主机位
| 节点所需数量 | 节点主机位 |
|---|---|
| 1-4 | 3 (或 /29) |
| 5-12 | 4 (或 /28) |
| 13-28 | 5 (或 /27) |
| 29-60 | 6 (或 /26) |
| 61-124 | 7 (或 /25) |
| 125-252 | 8 (或 /24) |
| 253-508 | 9 (或 /23) |
| 509-1020 | 10 (或 /22) |
| 1021-2044 | 11 (或 /21) |
| 2045-4092 | 12 (或 /20) |
| 4093-8188 | 13 (或 /19) |
您可以使用单个子网为多个 GKE 集群提供服务。
Pod IP CIDR
要确定 Pod IP CIDR,确定您在集群生命周期内需要的每个节点上的 Pod 的最大数量。如果您无法确定所需的最高数量,请使用每个节点 110 个 Pod 的配额限制作为最大值。使用表 10.4 确定所需 Pod 数量的主机位。
表 10.4 确定 Pod 所需的主机位
| 每节点 Pod 数量 | Pod 主机位 |
|---|---|
| 1-8 | 4 |
| 9-16 | 5 |
| 17-32 | 6 |
| 33-64 | 7 |
| 65-110 | 8 |
要计算 Pod IP CIDR 块,你需要节点和 Pod 的主机位,并使用以下公式:
Pod IP CIDR block netmask = 32 - (host bits for Nodes + host bits for Pods)
例如,假设你每个节点需要 110 个 Pod,该区域所有 GKE 集群中的节点总数为 5,000。首先,使用表 10.3 确定节点的位数;这将是一个 13。然后,使用表 10.4 确定 Pod 的位数;这将是一个 8。然后,使用公式,你的 Pod IP CIDR 块的子网掩码需要如下所示:
Pod IP CIDR block netmask = 32 - (13 + 8) = 11
你需要一个掩码为 /11 的子网。
服务 IP CIDR
要计算服务 IP CIDR,确定你在集群生命周期内需要的最大集群 IP 地址数量。每个服务需要一个集群 IP。你无法在集群之间共享服务 IP 子网。这意味着你需要为每个集群使用不同的服务 IP 子网。
一旦你知道集群中服务的最大数量,你就可以使用表 10.5 来获取所需的子网掩码。
表 10.5 确定所需的子网掩码
| 集群 IP 地址数量 | 子网掩码 |
|---|---|
| 1-32 | /27 |
| 33-64 | /26 |
| 65-128 | /25 |
| 129-256 | /24 |
| 257-512 | /23 |
| 513-1,024 | /22 |
| 1,025-2,048 | /21 |
| 2,049-4,096 | /20 |
| 4,097-8,192 | /19 |
| 8,193-16,384 | /18 |
| 16,385-32,768 | /17 |
| 32,769-65,536 | /16 |
配置 Anthos GKE 的私有使用公共 IP
从上一节中,你可以看到在非常大的 GKE 环境中,你可能会遇到 IP 耗尽的问题。在大型 GKE 环境中,IP 耗尽的最大来源是 Pod IP CIDR 块。GCP VPC 使用 RFC1918 地址空间作为网络资源。在大型环境中,RFC1918 空间可能不足以配置 Anthos。这对于向 Anthos 的许多租户提供托管服务的托管服务提供商来说尤其是一个问题。
缓解地址耗尽的一种方法是为 GKE Pod CIDR 块使用私有使用公共 IP(PUPI)地址。PUPI 是任何客户可以在 Google Cloud 上私用的、不属于 Google 的公共 IP 地址。客户不一定拥有这些地址。
图 10.12 展示了一家(生产者)向客户(消费者)提供托管服务公司的示例。

图 10.12 使用私有使用公共 IP(PUPI)寻址的 Anthos GKE
这种设置涉及以下考虑因素:
-
主 CIDR 块—用于节点和内部负载均衡(ILB)的非 PUPI CIDR 块,必须在 VPC 之间不重叠
-
生产者次要 CIDR 块—用于 Pod 的 PUPI CIDR 块(例如,45.45.0.0/16)
-
消费者次要 CIDR 块—客户侧的任何其他 PUPI CIDR 块(例如,5.5/16)
该公司的托管服务位于生产者 VPC(vpc-producer)中,并基于 Anthos GKE 部署构建。公司的 GKE 集群使用 PUPI 45.0.0.0/8 CIDR 块为 Pod 地址。客户的程序位于消费者 VPC(vpc-consumer)中。客户还拥有一个 Anthos GKE 安装。消费者 VPC 中的 GKE 集群使用 PUPI 5.0.0.0/8 CIDR 块为 Pod 地址。两个 VPC 相互对等连接。两个 VPC 都使用 RFC1918 地址空间作为节点、服务和负载均衡地址。
默认情况下,消费者 VPC(vpc-consumer)将所有 RFC1918 地址空间导出到生产者 VPC(vpc-producer)。与 RFC1918 私有地址和扩展私有地址(CGN,E 类)不同,PUPIs 默认情况下不会自动向 VPC 对等方广播。如果 vpc-consumer Pods 必须与 vpc-producer 中的资源通信,消费者必须启用 VPC 对等连接以导出 PUPI 地址。同样,生产者必须配置生产者 VPC 以通过 VPC 对等连接导入 PUPI 路由。
导入到 vpc-producer 的 vpc-consumer 地址空间不得与 vpc-producer 中使用的任何 RFC1918 或 PUPI 地址重叠。生产者必须通知消费者托管服务使用的 PUPI CIDR 块,并确保消费者没有使用这些块。生产者和消费者还必须同意并为 vpc-producer 中的 ILB 和节点地址分配非重叠地址空间。
PUPIs 不支持服务网络。在大多数情况下,vpc-consumer 中的资源通过生产者集群中的 ILB 地址与 vpc-producer 中的服务通信。如果生产者 Pods 需要直接与 vpc-consumer 中的资源通信,并且 PUPI 寻址不重叠,那么生产者必须配置生产者 VPC 以通过 VPC 对等连接导出 PUPI 路由。同样,消费者必须配置 VPC 对等连接以将路由导入 vpc-consumer。如果消费者 VPC 已经使用 PUPI 地址,那么生产者应改为配置 IP 伪装功能,并将 Pod IP 地址隐藏在生产者节点 IP 地址之后。
之前的示例显示了一个更复杂的生产者/消费者模型。您可以在单个项目模型中简单地使用它。这将释放可能用于 Pod IP CIDR 的 RFC1918 空间。
10.3 Anthos 多集群网络
本节讨论了连接跨多个集群运行的服务机制。每个混合和多云 Anthos 架构,按定义,都有多个集群。例如,您有在 GCP 上运行的 Anthos GKE 集群和在本地数据中心运行的 Anthos GKE 本地集群。在 Anthos 集群上运行的服务通常需要与其他 Anthos 集群中运行的服务进行网络连接。对于多集群服务网络,让我们看看以下场景:
-
GCP 上的多集群网络—在这个架构中,所有服务都在 GCP 上的多个 Anthos GKE 集群上运行。
-
混合和多云环境中的多集群网络——在这个架构中,服务在混合和多云环境中的多个 Anthos GKE 集群上运行。
10.3.1 GCP 上的多集群网络
云原生企业可以在 GCP 上运行 Anthos 平台。这可以是在单个区域的单个集群中。通常,Anthos 平台由多个区域中的多个集群组成,以提供弹性。
在 GCP 中,谷歌建议使用具有多个服务项目的共享 VPC 模型。其中这些服务项目之一属于 platform_admins 组,并包含构成 Anthos 平台的全部 Anthos GKE 集群。这些集群上的资源由多个租户共享。我们还建议使用 VPC 原生集群。VPC 原生集群使用 VPC IP 地址作为 Pod IP,这允许跨多个集群实现 Pod 到 Pod 的直接连接。典型的 GCP 上 Anthos 平台架构如图 10.13 所示。

图 10.13 Anthos 架构:单一环境
此架构代表单一环境,例如,在这种情况下为生产环境。一个名为 project-0-nethost-prod 的单个网络主机项目管理共享 VPC。存在两个服务项目,一个是为平台管理员名为 project-1-platform_admins-prod 的项目,其中 Anthos 平台由平台管理员部署和管理,另一个是为产品名为 project-2-product1-prod 的项目,其中包含与 product1 相关的资源。在此示例中,Anthos 平台部署在两个 GCP 区域中,以提供区域冗余。您可以使用两个以上区域或甚至单个区域创建相同的架构。每个区域内部有一个单独的子网和次要范围。每个区域存在两个区域级别的 Anthos GKE 集群。每个区域多个集群提供集群和区域级别的弹性。您可以为每个区域超过两个集群使用相同的设计。所有集群都是 VPC 原生集群,允许集群之间的 Pod 到 Pod 连接。ASM 安装在每个集群上,形成一个多集群服务网格。ASM 控制平面发现所有集群中运行的服务和端点,并配置每个 Pod 内运行的 Envoy 边车代理的与网格内所有服务相关的路由信息。
每个租户或产品都会以 Kubernetes 命名空间(在网格内所有集群中)和一组策略的形式获得一个着陆区。租户只能在它们自己的命名空间内部署他们的服务。您可以在多个 Anthos GKE 集群中运行相同的服务以提供弹性。这些服务被称为分布式服务。分布式服务从所有其他实体的角度来看充当单个逻辑服务。如图 10.13 所示,product1-service 是一个具有四个端点的分布式服务,每个端点在不同的集群中运行。如图 10.14 所示,ASM 负责服务发现,VPC 原生集群允许 L3/L4 Pod 到 Pod 的连接。

图 10.14 Anthos GKE 多集群网络
10.3.2 混合和多云环境中的多集群网络
除了在 GCP 上的 Anthos GKE 之外,所有其他 Anthos GKE 集群都以孤岛模式运行。这意味着集群内部 Pod 和服务使用的 IP 地址在集群外部是不可路由的。在这种情况下,您仍然可以在同一环境中(例如,在本地数据中心运行的多个 Anthos GKE 集群)或跨多个基础设施环境(例如,在 GCP 的 Anthos GKE 和在本地数据中心环境中运行的服务)连接运行在多个集群上的服务。
在混合或多云环境中连接多个 Anthos GKE 集群时,应考虑以下三个方面:
-
在多个集群上运行的 Pod 之间的网络连接
-
多集群间的服务发现
-
在混合和多云架构的情况下,基础设施环境之间的连接
网络连接
每个 Anthos GKE 集群都有一个负载均衡器。负载均衡器在安装期间捆绑提供,或者可以手动配置。这些负载均衡器允许服务通过 NodePort 暴露给集群外部的资源。每个服务都获得一个 VIP 地址(服务 VIP),该地址在网络上可路由且可访问。负载均衡器将流量路由到服务 NodePort 上的节点 IP,该 IP 被转发到所需端口的 Pod IP。
在一个集群中运行的服务(和 Pod)可以访问另一个集群中运行的服务 VIP,该服务通过负载均衡器路由到所需的 Pod,如图 10.15 所示。

图 10.15 Anthos GKE 混合多集群网络
Anthos 集群还可以配置 Ingress 控制器。Ingress 控制器是位于集群内部的 L7/HTTP 负载均衡器。Ingress 控制器本身通过 L3/L4 负载均衡器暴露。这样,您可以使用一个 VIP(入口 VIP)为同一集群上运行的多个服务提供服务,如图 10.16 所示。Ingress 控制器根据入口规则操作,这些规则规定了如何在集群内部路由流量。

图 10.16 Anthos GKE 混合多集群网络:入口
多集群服务发现
Anthos Service Mesh 用于多集群服务发现,如图 10.17 所示。每个集群都安装了一个 ASM 控制平面。ASM 控制平面从所有集群发现服务和端点。这也被称为服务网格。ASM 控制平面必须能够访问服务网格内所有 Anthos 集群的 Kubernetes API 服务器。ASM 创建了自己的服务注册表,这是一个包含服务和它们相关联的端点(或 Pod)的列表。

图 10.17 Anthos GKE 混合多集群网络:Anthos 服务网格
在 GCP 上的 Anthos GKE 中,如果使用 VPC 原生集群,端点是实际的 Pod IP 地址。流量通过 VPC 路由从 Pod 流向 Pod。在非 GCP Anthos 集群中,集群间的流量通过一个 L7 Envoy 代理流过。此代理在每个 Anthos 集群中以服务形式运行,称为 istio-ingressgateway。流向集群内所有服务的流量都通过 istio-ingressgateway,该服务配置为检查主机头并将流量路由到集群内的适当服务。
对于分布式服务,我们建议使用 ASM,它提供跨多个集群的服务发现和流量路由功能。
混合云和多云连接
只要你能访问目标 Anthos 集群的 Kubernetes API 服务器和外部公共负载均衡器,你就可以连接运行在多个 Anthos 集群中的多个基础设施环境中的服务。你可以以下三种方式连接基础设施环境:
-
云互连—通过高度可用、低延迟的连接将本地网络扩展到 Google 的网络。你可以使用专用互连直接连接到 Google,或者使用合作伙伴互连通过支持的服务提供商连接到 Google。专用互连在你的本地网络和 Google 的网络之间提供直接的物理连接。
-
云 VPN—通过 IPsec VPN 连接安全地将你的对等网络连接到你的 VPC 网络。两个网络之间的流量由一个 VPN 网关加密,然后由另一个 VPN 网关解密。
-
公共互联网—多个环境上的 Anthos 平台可以通过公共互联网连接,而无需使用云互连或 VPN。平台上的服务通过 TLS/mTLS 在公共互联网上连接。此类连接是在每个服务级别使用 ASM 完成的,而不是在网络级别。
这些连接模型在 10.1.2 节“多/混合云部署”中进行了详细解释。
10.4 服务和客户端连接
本节讨论 Anthos 平台中的服务和客户端连接,可以分为以下三个类别:
-
客户端到服务连接—这也被称为南北流量,表示流量起源于平台外部(北)并进入平台(南)。
-
服务到服务连接—这也被称为东西流量,表示流量在平台横向穿越(因此是东西)。所有流量都在 Anthos 平台内部发起和终止。
-
服务到外部服务连接—这是离开平台的流量。
10.4.1 客户端到服务连接
在此上下文中,客户端指的是位于 Anthos 平台外部的一个实体以及运行在 Anthos 平台内部的一个服务。您可以通过以下两种方式访问 Anthos 平台内部的服务:
-
使用 ASM—使用 ASM,您可以使用 ASM Ingress 来处理 HTTP(S)和 TCP 流量。ASM 提供了额外的 L7 功能,例如,在 Ingress 处执行身份验证和授权的能力。ASM 是 Anthos 平台上访问基于 Web 服务的推荐方式。ASM 也可以用于基于 TCP 的服务。
-
不使用 ASM—所有 Anthos 集群都支持配置负载均衡器的选项。负载均衡器在您部署 Anthos 集群时可能集成/捆绑,或者可以手动配置。任何基于 TCP 的服务都可以使用类型为 Loadbalancer*的服务来暴露,这会创建一个客户端可以访问的服务 VIP。此外,所有 Anthos 集群都可以配置 Ingress。Ingress 控制器通常在集群内部作为 L7 代理运行(除了在 GCP 上的 Anthos GKE 和 AWS 上的 Anthos 使用 ALB)。Ingress 控制器本身是通过 L3/L4 负载均衡器暴露的。Ingress 是暴露基于 Web 服务的推荐方式。Ingress 规则作为服务部署管道的一部分实现,Ingress 控制器强制执行这些规则,包括监听和路由流量到适当的服务。
10.4.2 Service 到 Service 连接性
集群内部运行的服务需要网络连接。这可以通过两种方式实现:
-
使用 ASM—我们推荐使用 ASM,尤其是在多集群的 Anthos 平台上。ASM 提供服务发现以及 Service 之间的路由逻辑。ASM 还可以处理 Service 之间的身份验证和授权。例如,您可以在服务网格级别启用 mTLS,加密所有 Service 到 Service 的流量。您还可以在单个 Service 层配置安全策略。除了服务发现和网络功能外,ASM 还提供其他功能,如遥测、配额、速率限制和断路器。有关 ASM 的功能和好处,请参阅第四章。
-
不使用 ASM—如果您选择不使用 ASM,您仍然可以配置 Service 到 Service 连接性。从网络角度来看,您可以使用负载均衡器或 Ingress 模式来访问集群内部运行的服务。您将不得不自行配置服务发现。您可以使用 DNS 来提供此功能。
在任何情况下,您也可以在集群内部使用 NetworkPolicy 来控制/限制 Pod 和 Service 之间的流量。
10.4.3 Service 到外部服务连接性
您可以通过以下两种方式控制任何 Anthos 集群的出口流量:
-
使用 ASM—ASM 提供入站和出站网关。我们之前讨论了 Ingress 如何与 ASM 协同工作。同样,您可以在服务网格外围配置第二个代理,称为 istio-egressgateway。然后,您可以为仅允许从集群内部访问的服务配置 ServiceEntries。您可以将 outboundTrafficPolicy 模式设置为 REGISTRY_ONLY。这将阻止所有不是目标为网格内服务的出站流量。然后,您可以创建单独的 ServiceEntries 以访问平台外运行的服务。一个 ServiceEntry 的示例可能如下所示:
apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: httpbin-ext spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP resolution: DNS location: MESH_EXTERNAL ❶❶ 位置 MESH_EXTERNAL 表示服务位于服务网格之外,并且手动将 DNS 条目添加到网格注册表中。
此规则允许目标为端口 80 的httpbin.org的流量。注意服务位置为 MESH_EXTERNAL,表示此服务位于服务网格和 Anthos 平台之外。
-
不使用 ASM—您可以在集群内部使用 NetworkPolicies 根据标签选择器控制 Pod 的入站和出站流量。由于所有 Pod 出站流量都通过节点 IP 退出,您可以通过限制节点 IP 子网可以访问的目的地来进一步通过防火墙规则控制出站流量。
摘要
Anthos 网络可以分为以下四个层次:
-
云网络和混合连接—Anthos 网络的最低层。本层描述了如何在每个云环境中设置网络以及将多个云环境安全连接起来的选项。在 GCP 内部,您可以根据组织结构和功能需求设置单个网络(或 VPC)、共享 VPC 或多个 VPC。在非 GCP 环境中,所有 Anthos 集群都被视为孤立网络(或“岛屿模式”)。以下是一些混合连接选项:
-
专用互联—在您的本地网络和谷歌网络之间提供直接的物理连接。专用互联使您能够在网络之间传输大量数据,这可能比在公共互联网上购买额外的带宽更经济高效。
-
云 VPN—通过 IPsec VPN 隧道安全地将您的对等网络扩展到谷歌网络。流量被加密,并通过公共互联网在两个网络之间传输。云 VPN 适用于低流量数据连接。
-
公共互联网—连接不同的网络不需要任何特殊的软件或硬件。相反,使用 TLS/mTLS 连接来保护服务到服务的连接。
-
-
Anthos GKE 网络—Kubernetes 网络层。Anthos GKE 集群可以部署到各种环境中,例如 GCP、在本地数据中心 VMware 上、在裸金属服务器上,以及 AWS 上。除了支持的 Anthos 集群外,您还可以将任何符合 Kubernetes 规范的集群注册到 Anthos 平台。例如,您可以将运行在 AWS 上的 EKS 集群和运行在 Azure 上的 AKS 集群注册到 Anthos 平台。目前有六种类型的 Anthos 集群可供使用:
-
GCP 上的 Anthos 集群(GKE)
-
VMware 上的 Anthos 集群(本地 GKE)
-
基于裸金属的 Anthos 集群
-
AWS 上的 Anthos 集群(AWS 上的 GKE)
-
Azure 上的 Anthos 集群(Azure 上的 GKE)
-
Anthos 附加集群(符合 Kubernetes 规范的集群)
-
-
Anthos 多集群网络—处理需要跨集群边界通信的多个集群的环境。本节可以分为以下两个子节:
-
在 GCP 上的 GKE 与 Anthos 多集群网络—在 GKE on GCP 中,您可以选择平面网络架构(使用单个或共享 VPC)或多个网络(多个 VPC)模型。在平面网络架构中使用 VPC 原生 GKE 集群时,VPC 网络自动允许多个集群之间的 Pod 到 Pod 连接。集群可以位于任何区域。集群之间 Pod 到 Pod 连接不需要额外配置。在多个 VPC 架构中,您需要额外的配置来连接多个集群之间的 Pod 和服务。例如,您可以使用特殊的网关或入口模型在集群之间进行通信。
-
Anthos 多集群网络在非 GCP 环境中—在所有非 GCP 集群中,集群及其地址范围与其他集群隔离。这意味着多个集群之间的 Pod 之间不存在直接连接。要连接多个集群,您必须使用特殊的网关或入口。Anthos Service Mesh 可以用来部署此类网关。通常称为“东西向网关”,这些网关被部署在参与多集群网络的各个集群中。此外,ASM 还提供多集群服务发现。
-
-
服务层网络—Anthos 网络的顶层是服务层网络。这一层解决服务如何发现和相互通信的问题。在上一节中,我们提到了 Anthos Service Mesh,它可以让您执行以下任务:
-
ASM 允许您在运行在多云环境中的多个 Anthos 集群上创建服务网格。这一层抽象了底层网络的复杂性,让您可以专注于服务层。
-
ASM 使用每个工作负载的边车和专用网关连接多个环境中的多个集群。
-
通过使用 ASM,您可以专注于服务层功能——例如,身份验证、加密和授权——而不是在集群级别管理单个工作负载。这使得操作员和管理员能够在可能存在多个集群、多个环境、多个网络运行众多服务的情况下进行规模化操作。
-
11 配置管理架构
迈克尔·麦迪逊
本章涵盖
-
为什么大规模配置是一个挑战
-
Anthos Config Management 概述
-
ACM 实施的示例和案例研究,展示了该解决方案的实用性和多功能性。
在应用程序开发的世界里,我们总是希望有更多的速度、更多的能力以及更多的应用程序来满足更多任务,自动化更多细节,运行得更快,并在更接近实际使用地点的地方运行。智能手机、平板电脑和物联网设备的普及,以及计算机在我们日常生活中的不断进步,推动了更多计算能力的需求。环境因素、高速互联网和其他公用事业的可获得性以及政府法规正在改变公司部署资源的方式。根据具体情况,这可能导致计算资源集中在几个数据中心,转向主要基于云的计算,碎片化为许多“微型”数据中心,或者这些解决方案的组合。
组织很少决定减少他们管理的总资源。尽管可能会出现短期内的减少、整合甚至消除应用程序的情况,但大多数公司明天管理的资源将比今天更多。过去 40 年或更长时间以来,应用程序开发一直遵循这条道路。
但是,随着 Kubernetes 的广泛应用,许多组织在处理将成千上万的虚拟机和应用程序迁移到 Kubernetes 环境中时,这个问题变得突出。尽管许多传统工具仍然可以使用,但以同样的方式使用它们将消除 Kubernetes 提供的许多优势。更不用说,传统工具集通常彼此脱节,迫使管理者在一个工具中更改防火墙设置,在另一个工具中授予虚拟机访问权限,在第三个工具中设置路由。这些挑战主要落在负责实施和维护所有这些基础设施的 IT 运维团队肩上。
随着越来越多的公司转向 Kubernetes 进行日常运营,安全专业人士和管理人员对其配置、管理和审计 Kubernetes 集群的能力充满信心,这对商业成功变得至关重要。IT 安全团队负责在 IT 基础设施的各个方面开发和实施安全控制,包括软件、硬件和物理限制、政策、程序和指导。许多公司采用分层权限模型,允许超级用户拥有更大的能力子集,而不成为完整管理员。由于 Kubernetes 中的许多工作都是由一个通用的定义语言驱动的,这种语言以 JSON 或 YAML 的形式表达,因此安全框架也应该为那些经常与 Kubernetes 一起工作的 IT 安全团队所熟悉。
为了帮助组织满足这一需求,谷歌创建了 Anthos Config Management (ACM),以简化 Kubernetes 策略、资源和配置的开发、部署和维护。在下一节中,你将了解 ACM 帮助解决的全面挑战以及 ACM 为提高组织效率提供的机遇。
11.1 我们试图解决什么问题?
随着时间的推移,企业已经将流程转移到数字格式。即使没有互联网作为参与平台,公司也已经将内部运营转移到依赖数字应用程序和通信。当这加上与数字客户的巨大互动需求相结合时,公司对计算能力的需要比以往任何时候都更大,而且没有放缓的迹象。根据 Grandview Research 的预测,到 2030 年,边缘计算这一最新计算领域预计将成为一个超过 1550 亿美元的市场(mng.bz/oJnr)。
此外,许多企业通过让这些系统相互通信来自动化他们的流程,从而提高了效率。例如,基于票务的自助服务软件如 ServiceNow、人员管理解决方案如 Workday 以及结合认证和授权服务如 Okta 的普及,鼓励公司扩大其现场和云端的业务能力。随着公司转向更多地依赖员工的发展能力来应对关键任务解决方案,随着他们将其生态系统中的每个新供应商引入,这些应用的部署复杂性也在增加。
任何公司在设计其独特的客户价值时,其需求都会与最接近的竞争对手有所不同,但大多数企业都在本地和云端都有数字存在。尽管一些公司已经使用多个数据中心或互惠设施来提供其冗余和可靠的基础设施,但许多公司已经转向云服务提供商。但云服务提供商的最佳实践和用户体验可能差异很大。运营团队上线每个云都极大地增加了他们的技术负担和运营开销,如图 11.1 所示。即使在设计为相同的数据中心的情况下,安全控制和物理分离仍然对其运营和维护构成障碍。

图 11.1 启用多个基础设施平台增加了相当大的运营开销。
公司的数字足迹大小也增加了其系统和操作的配置和运营复杂性。多个工作地点、更多的数据中心以及参与这些系统管理的人数相应增加,都带来了各自的挑战。随着组织的发展,引入和使用系统安全性和配置控制变得至关重要。ACM 通过以下核心能力来解决这些挑战:
-
管理复杂性
-
工作负载可观察性和检查
-
在问题发生时进行修复和预防
接下来,你将了解 ACM 如何管理现代基础设施的复杂性。
11.1.1 管理复杂性
你可以以无数种方式配置计算基础设施,但大多数解决方案都遵循一些通用模式。这些解决方案通常可以根据系统是横向扩展还是纵向扩展来分组。对于采用或使用基于 Kubernetes 的基础设施的公司,公司必须就所有 Kubernetes 集群的整体设计做出类似的决定。使用多个、较小集群(例如,每个团队一个或多个)用于不同目的的公司(例如)正在实施横向扩展解决方案。使用较少数量的大型集群(例如,每个用于开发、测试和生产)的公司正在将其 Kubernetes 基础设施构建到纵向可扩展性中。这两种方法没有一种是优于另一种的,但公司应确定哪种最适合其部署和软件设计方法。
地理限制、边缘处理需求以及电信运营也对集群的划分方式施加了限制。某些国家的政府法规禁止数据从这些地区流出,要求数据库和应用层位于国内。即使没有政府监管,某些类型的业务(如餐馆、零售店,甚至银行)可能也更倾向于使用本地处理系统,运行能够从更短的通信循环中受益或需要的应用程序子集。
此外,大型企业需要更多的人员来有效地组织和运营 IT 基础设施。为了减轻 IT 人员中的单点故障,开发可以扩展到多人的简单流程对于长期成功至关重要。
11.1.2 透明度和检查
Kubernetes 集群的工作负载可见性和整体健康状况超出了本章的讨论范围(它主要在第五章中介绍)。然而,Anthos Config Management 提供的所有集群的策略和配置的明文表示可以在前端做很多事情,以确保遵循适当的策略。
Anthos Config Management 的目标是保持集群处于由存储在 Git 仓库中的策略目录指定的状态。这个策略目录存在于被管理集群之外,并以文本格式存储。因此,策略目录本身可以用作有关集群配置的信息来源。通过使用 Git 仓库本身的特性,IT 运维团队能够确定集群何时不符合规范,并且可以轻松跟踪集群配置的变化。
ACM 通过 nomos 命令提供命令行工具,可以直接查询集群并确定其当前状态。运维团队可以使用 nomos 诊断更改的部署情况,并确定是否发生错误或延迟,这可能导致问题。nomos 提供的大部分信息在 Google Cloud 控制台中的 Anthos UI¹中可见,显示每个集群当前正在运行哪个配置版本,以及 ACM 安装的整体状态。此外,系统日志的 Kubernetes 操作员以与其他容器相同的方式记录事件和信息,因此可以在 Cloud Logging 中查看,并在 Cloud Monitoring 警报和指标中使用。
11.1.3 补救和预防问题
IT 运维团队的主要职责之一是维护系统可靠性和正常运行时间。知道更改导致了中断,并且能够快速隔离问题并迅速应用补救措施,是团队武器库中的关键工具。在这三个要点上,ACM 都带来了独特的功能,使团队能够应对发生的情况。
因为 ACM 是由 Git 仓库驱动的,你可以通过现有的拉取请求机制轻松添加护栏和政策执行,或者将一个或多个分支上的活动与监控套件绑定,并在政策变更后带来额外的警报。使用仓库作为事实来源,团队可以调查在什么时间应用了哪些更改,以缩小任何问题配置的范围。然后可以使用现有的 Git 工具来回滚或修复配置。由于 ACM 的设计,这些更改通常在将更改推送到策略仓库后一分钟或两分钟内生效。
除了修复已部署的问题外,你还可以使用现有的 CI/CD 工具和流程在配置生效之前验证配置。围绕 Git 的其他工具,如拉取和合并请求、分支等,也可以用来允许多个用户开发新的策略,同时允许组织在部署之前批准这些更改。
ACM 包括将配置应用于集群子集的能力。虽然我们在示例中使用它通过地区部署应用程序的不同版本到集群,但相同的功能也可以用来以受控的方式部署更改,或者为每个集群应用不同的角色。例如,每个商店运行一个集群的零售连锁店可以在将其推广到整个连锁店之前,将应用程序的新版本部署到特定的测试商店。使用不同集群进行开发、测试和生产环境的公司可以根据集群授予用户不同的权限,同时仍然可以利用单个策略仓库。
11.1.4 整合一切
这三个问题都可以通过 Anthos Config Management 得到很好的处理。通过提供 IT 专业人士熟悉的工具,以及在一个高度分布式的生态系统中茁壮成长的设计,ACM 可以帮助团队轻松地管理大型系统。在下一节中,我们将简要概述 ACM 的工作原理以及可以包含在安装中的组件。
11.2 ACM 概述
现在我们已经对使用 Anthos Config Management 尝试解决的问题有了很好的了解,让我们更深入地看看 ACM 的技术实现。ACM 通过在每个要管理的集群上部署一个 Kubernetes 操作员²来实现。一个包含集群规范名称、Git 配置和一组功能标志的配置文件也被应用到集群上。操作员使用 Git 配置连接到任何可访问的 Git 服务中托管的 Git 仓库,该仓库包含集群的完整配置信息。功能标志是开关,用于激活配置同步、策略控制器或层次结构控制器,这些将在本章后面介绍。ACM 使用集群名称以及 Git 仓库中的策略配置,为集群添加临时标签。然后,这些标签可以在策略仓库中使用,以修改部署到每个集群的资源。
ACM 的工作基于最小化占用心态:它不会试图接管整个 Kubernetes 集群。相反,操作员知道策略配置中定义了哪些对象,并致力于仅管理那些特定对象。这允许多个部署机制在单个 Kubernetes 集群上并行工作,而不会相互干扰。然而,使用多个工具确实增加了额外的负担,需要知道哪些工具部署了每个对象。ACM 在其管理的对象上包含一个特定的注解³,但可能不是所有工具看起来都一样。正如我们稍后将会看到的,ACM 仓库可以配置为非结构化模式,允许组织继续使用支持输出到 YAML 或 JSON 的现有工具,同时仍然使用 ACM 执行实际的部署和管理过程。
操作员每隔几分钟同步一次,这个频率可以在配置中调整,取决于组织的需要。ACM 可以使用公共和私有仓库,并使用适当的凭据作为策略仓库。此外,Git 配置可以指向仓库顶层以下的目录。如果 Git 仓库使用模板引擎或甚至应用程序代码,其中可以使用子目录来存储策略,这可能很有用。
您可以根据所使用的 Kubernetes 集群类型以三种主要方式部署 Anthos Config Management:在 GCP 上部署的 Google Kubernetes Engine (GKE) 集群、VMware 上的 GKE 集群,或 Kubernetes 的其他版本。对于 GCP 上的 GKE,启用 ACM 只需在集群配置页面上勾选一个复选框。对于 VMware 上的 GKE,ACM 默认启用且无法禁用。只有不符合上述任一类别的集群需要手动配置来安装操作符:获取由 Google 提供的操作符自定义资源定义文件的最新版本,并将其应用到集群中。
到此为止,所有版本的 Kubernetes 都已安装并运行操作符,但 ACM 仍需启用并指定从哪里拉取策略。这通过创建一个操作符配置对象并将其应用到集群中完成,同时附带所需的 Git 凭据。支持多种 Git 认证方法,包括无需认证的公共仓库、SSH 密钥对、个人访问令牌和 Google 服务帐户。其中一些方法需要将特定信息加载到 Kubernetes Secret 中,以便操作符正确加载。配置对象允许指定 Git 仓库的代理,如果需要的话。除了 Git 连接信息外,配置对象还可以包含设置以启用或禁用之前提到的单个组件,以及为 ACM 策略规则中的集群命名。请注意,在集群上创建的 ConfigManagement 对象和 gcloud 用于最初安装 ACM 所使用的配置 YAML 相似,但并不相同。随着 ACM 功能的扩展,将向此配置对象添加更多选项,但初始部署 YAML 的当前结构如下:
applySpecVersion: 1
spec:
clusterName: <name of cluster>
enableMultiRepo: <true/false, enables multiple repository mode>
enableLegacyFields: <true/false, used with multi repo, see below>
policyController:
enabled: <true/false>
templateLibraryInstalled: <true/false, installs the Google-provided template library for policy controller>
sourceFormat: <hierarchy or unstructured. Sets the type of policy organization>
preventDrift: <if set to true, rejects changes to the cluster that conflict with managed resources>
git:
syncRepo: <url of the git repository>
syncBranch: <branch of the git repository to sync from>
policyDir: <relative path in the git repository to the policy directory>
syncWait: <number of seconds between sync attempts>
syncRev: <git revision to sync from. Used if a specific commit or tag should be used instead of a branch>
secretType: <ssh, cookiefile, token, gcenode, gcpserviceaccount or none. Specifies the type of authentication to perform>
gcpServiceAccountEmail: <email of the service account to use for git access. Only used when secretType is gcpserviceaccount>
proxy:
httpProxy: <proxy information for http connection, styled similarly to the HTTP_PROXY environment variable>
httpsProxy*: <proxy information for https connection, styled similarly to the HTTPS_PROXY environment variable>*
单个集群上的操作符是 ACM 用于更新每个集群上对象的机制。尽管 ACM 使用中央 Git 仓库,但由于单个集群会主动拉取配置,这大大简化了集群与仓库之间的连接性。仓库不会推送配置,因此我们不需要引入额外的复杂性或安全入口漏洞,中央仓库也不需要事先了解每个单个集群。
11.2.1 ACM 策略结构
ACM 策略目录必须采用两种支持的格式之一,要么是层次结构,要么是无结构,其中层次结构是默认格式。此设置也反映在前面提到的操作符配置对象中,在 spec.sourceFormat 键中。在两种情况下,策略目录定义 Kubernetes 对象,然后 ACM 操作符将检查并应用这些对象到连接到 Git 仓库的每个集群。ACM 本身使用其中一些对象内部来确定要应用到当前集群的资源。
除了存储库的整体格式外,您还可以使用多个存储库来配置集群。当使用 enableMultiRepo 功能时,单个存储库用作根存储库(可能是层次结构或非结构化),而所有其他存储库都用于在单个命名空间中配置对象。
层次结构
在层次结构存储库中,策略目录中的顶级目录根据目的和范围(系统、集群注册、集群和命名空间)来区分配置文件,如表 11.1 所示。
表 11.1 层次结构存储库中的顶级目录
| 目录 | 目的 |
|---|---|
| 系统 | 与策略存储库本身相关的配置,例如已部署配置的版本。 |
| 集群注册 | 存储集群和 ClusterSelector 对象,这些对象一起用于选择集群的子集,以限制特定对象的应用位置。集群定义通过名称给集群附加特定的标签;ClusterSelectors 可以使用这些标签来选择满足一定要求的集群集合。 |
| 集群 | 包含为整个集群定义的对象,但不包括命名空间。 |
| 命名空间 | 包含分配给一个或多个特定命名空间的对象,以及命名空间和 NamespaceSelector 定义。 |
在层次结构模式下,ACM 使用“抽象”命名空间的概念,即一个或多个实际命名空间的组合,这些命名空间应共享一组 Kubernetes 对象。例如,您可能在每个团队使用的命名空间中定义一个 Role 或 ConfigMap。当 ACM 分析存储库时,任何在抽象命名空间中定义的对象都会自动复制到其下所有的命名空间中。这些抽象命名空间也可以相互嵌套,以形成多个抽象层。例如,您可以将所有应用程序开发团队放置在 app-dev 抽象命名空间下,然后在 app-dev 内部为每个团队创建一个单独的抽象命名空间。
尽管 ACM 会将抽象命名空间中的对象复制到所有子命名空间中,但您可以使用 NamespaceSelector 来限制对象应用到的命名空间。以 app-dev 为例,我们希望将 ConfigMap 部署到多个团队跨多个命名空间中,但仅限于包含与财务相关应用程序的命名空间。通过给这些命名空间应用标签,我们就可以定义一个 NamespaceSelector 来选择这些命名空间,然后将 ConfigMap 配置对象链接到 NamespaceSelector。尽管这些选择器在层次结构存储库中确实有其用途,但它们的主要用途是在非结构化存储库中。此外,在层次结构存储库中,特定的命名空间必须是包含对象的文件夹的子文件夹,并且必须匹配选择器。一个包含配置对象定义的非结构化存储库的完整示例可以在本章末尾的 Evermore Industries 示例中找到。
一旦确定了要创建的特定命名空间名称,你也应该决定从哪个抽象命名空间继承。这可能意味着某些对象必须定义在比通常更高的级别,只是为了让它们被各个命名空间继承。一旦有了名称和抽象命名空间,你就在命名空间目录集的底部创建一个具有该名称的文件夹。在新建的目录内,你还必须创建具有相同名称的 Kubernetes 命名空间对象。在抽象命名空间中定义的所有对象也会在叶子命名空间内创建。让我们通过以下文件夹结构来举一个例子:
namespaces
├── staging
│ ├── qa-rbac.yaml
│ └── weather-app-staging
│ └── namespace.yaml
└── production
├── developer-rbac.yaml
├── app-service-account.yaml
├── weather-app-prod
│ ├── namespace.yaml
│ └── application.yaml
├── front-office-prod
│ ├── namespace.yaml
│ └── application.yaml
└── marketing
└── namespace.yaml
对于生产抽象命名空间,我们在 developer-rbac.yaml 中为开发者定义了一个角色和绑定,在 app-service-account.yaml 中为应用程序定义了一个 Kubernetes 服务账户。由于 weather-app-prod、front-office-prod 和 marketing 命名空间位于生产抽象命名空间下,因此角色、角色绑定和 Kubernetes 服务账户将在所有三个命名空间中创建。由于 ACM 分析策略存储库的方式,实际命名空间在其文件夹中不能有子目录,并且每个叶子目录都必须是一个实际命名空间,并在目录中有相应的命名空间声明。如果未能遵守此限制,当 ACM 部署时将导致配置错误。
除了抽象命名空间外,对象还可以使用 NamespaceSelectors(其声明方式类似于稍后在本章中介绍的 ClusterSelectors),以影响对象作用域内的子集命名空间。在之前的例子中,app-service-account 可以使用选择器仅部署到 weather-app-prod 和 front-office-prod 命名空间,而不是 marketing 命名空间。然而,在层次存储库中,NamespaceSelectors 仅在当前文件夹树中的命名空间上操作。例如,即使命名空间选择器在其标准中包括了 weather-app-staging,位于生产抽象命名空间下的 app-service-account 定义永远不会应用于 staging 命名空间,因为 weather-app-staging 目录不是包含 app-service-account 的目录的子目录。
优缺点
分层仓库简化了将对象部署到命名空间子集的过程,因为对象只能部署到仓库中配置文件所在级别或以下的命名空间。使用 NamespaceSelectors,组织可以进一步限制对象可以部署到的命名空间。如果有多种分组命名空间的方法,这可能特别有用。例如,一个开发团队可能会按命名空间分组,但他们可能还需要按功能(例如,前端、中间件)或业务单元分组。使用分层仓库,您必须选择一个“主要”的分组策略;如果对象需要部署到多个未分组的命名空间,则该对象将被放置在仓库的更高层级,并使用 NamespaceSelector 进行限制。这种组织方式使得确定对象部署到的命名空间变得非常简单,因为它们只能是定义文件中定义的或以下级别的那些。集群级别的资源和主要用于交付 ACM 的资源也有专门的文件夹,它们必须位于这些文件夹中,这使得找到特定对象变得更加容易。
然而,这种严格的结构在您组织实施 ACM 时可能会造成困难。许多组织已经至少对 Kubernetes 有基本的了解,并使用现有的工具集和流程来部署 Kubernetes 资源和应用程序。由于跨命名空间的对象必须在分层仓库的不同文件夹中进行配置,这可能会使 ACM 集成到现有的 CI/CD 管道中变得复杂。组织应权衡分层仓库提供的对象自动复制的好处与它施加的限制。
非结构化
与分层仓库不同,非结构化仓库没有特殊的目录结构。团队可以自由选择他们想要的任何组织风格,例如按应用程序或团队分组文件和对象。然而,使用非结构化仓库会阻止 ACM 使用抽象命名空间的概念来在多个命名空间中自动创建单个对象。为了弥补这一限制,对象必须声明一个命名空间或一个 NamespaceSelector。尽管 NamespaceSelectors 在分层仓库中的行为与在非分层仓库中相同,但它们不受仅在同一文件夹树中操作命名空间的限制,因此必须更加小心,以确保实际匹配的命名空间(或命名空间)确实是所需的。
优缺点
当一个组织已经使用模板引擎将对象部署到 Kubernetes 时,非结构化存储库变得更加有利。因为大多数模板引擎,包括 Helm,都包括将完成的 Kubernetes 对象导出到本地目录的能力,你可以使用这些命令的输出,并将生成的配置直接放置到 ACM 策略目录中。非结构化 ACM 存储库不关心配置在策略目录下的确切位置,因此在实施 ACM 时,这可以提供一条压力较小的升级路径。
然而,在命名空间分配方面,非结构化存储库存在一些问题。非结构化存储库中的配置无法推断它们应该分配到的命名空间,因此用户必须显式地分配所有对象。如果选择器定义或使用不当,这可能导致对象被部署到意外的命名空间。此外,由于配置文件的位置与部署命名空间之间没有隐含关系,查找资源变得更加复杂。
多存储库模式
将 ACM 配置为从多个存储库中提取,允许组织允许各个团队管理自己的命名空间,同时仍然可以利用 ACM 的许多好处。当集群配置对象设置为启用多个存储库模式(mng.bz/zmB6),使用 enableMultiRepo 标志时,spec.git 字段集不支持。相反,你创建一个单独的 RootSync 对象来保存根存储库的配置细节。
当 enableMultiRepo 被设置时,组织可以定义每个单独命名空间要使用的存储库。与 RootSync 对象一样,这些单独的 RepoSync 对象包含从 Git 存储库提取配置以及该存储库中策略树顶部的目录的配置。即使在多存储库模式下使用,根存储库也可以定义在任何命名空间中管理的对象。在根存储库与单个命名空间存储库之间发生冲突的情况下,使用的是根存储库的版本。
多仓库设置的根仓库的功能与不在多仓库模式中的配置相同;只是获取仓库的配置方式发生了变化。因此,多仓库模式是一个理想的解决方案,允许操作和安全团队实施策略、RBAC 规则、Istio 规则,配置命名空间等,同时使应用团队能够管理和部署自己的应用程序到各自的命名空间中。管理根仓库的团队还需要添加适当的策略来定义各个仓库可以修改的对象。这是通过定义自定义角色或 ClusterRole,或使用内置角色之一,然后使用 RoleBinding 将命名空间的 worker 服务帐户附加到该角色来完成的。这允许操作团队将配置特定应用程序的大部分工作转移到团队,并在需要时为每个团队定义自定义权限,而不是要求中央团队验证或自行执行工作。
11.2.2 ACM 特定的对象
虽然 ACM 可以管理任何有效的 Kubernetes 对象,但自定义对象可以调整系统的操作方式并应用新的配置。
ConfigManagement
ACM 使用此对象来确定如何以及在哪里获取用于集群的策略配置。将 ConfigManagement 对象部署到集群中激活了该集群的 ACM。此对象还定义了 ACM 内部使用的集群名称,并确定哪些插件(配置同步、策略控制器和层次控制器)对集群是激活的。
RootSync/RepoSync
当集群以多个仓库模式运行时,用于获取策略的配置,包括 Git URL 和 Secrets,不会存储在 ConfigManagement 对象中,而是在 RootSync 对象(对于核心仓库)或每个命名空间中的 RepoSync 对象中。
Cluster
在 ACM 策略仓库中创建集群配置,允许用户通过集群名称将标签附加到特定集群。然后,这些标签在 ClusterSelectors 中被用来选择特定类型的集群。在层次仓库中,集群定义必须在 clusterregistry 目录中。
ClusterSelector
此对象使用常见的 Kubernetes labelSelectors 模式⁴来选择集群的子集。ClusterSelector 然后可以被对象(如 Deployment、ConfigMap 或 Secret)使用,以仅在匹配选择器的集群中部署该对象。在层次仓库中,这些必须在 clusterregistry 目录中。
NamespaceSelector
与 ClusterSelector 类似,此选择器也使用 labelSelectors,但它用于选择命名空间。它主要用于非结构化仓库或作为在层次仓库中限制对象部署到哪些命名空间的附加方法。
HierarchyConfiguration
这些对象在单独的命名空间中声明,并指向其父对象。这设置了 Hierarchy Controller 所使用的层次命名空间关系。请注意,使用 Hierarchy Controller 与使用层次存储库不同;Hierarchy Controller 将在本章的后续部分进一步探讨。
11.2.3 其他组件
虽然 Config Connector、Policy Controller 和 Hierarchy Controller 并非 ACM 本身的一部分,但它们极大地增强了 ACM 和您的 Kubernetes 环境的功能。本节仅对每个组件进行了简要介绍,但所有三个组件都在本章末尾的示例中进行了演示。随着 Anthos 的发展,Google 也在集成额外的组件。请参阅mng.bz/Q8rw上的在线文档,获取有关可用附加组件的最新信息。
Config Connector
Config Connector (cloud.google.com/config-connector/docs) 是 Kubernetes 的一个附加组件,允许您使用 Kubernetes 对象配置 GCP 资源,例如 SQL 实例、存储桶和 Compute Engine 虚拟机。本章中提供了其中一个此类对象结构的完整示例。在适当的权限下,此附加组件允许熟悉 Kubernetes 的开发者创建多种类型的 GCP 资源,包括 SQL 数据库、网络、BigQuery 数据集和表、Compute 实例、Pub/Sub 主题和订阅以及存储桶。此外,这些配置可以相互引用,简化配置并允许单一事实来源。
用户还可以使用 Kubernetes Secrets 来存储敏感信息,例如密码,然后使用这些信息在 Config Connector 资源中。每个 Config Connector 对象还包括一个状态部分,描述了资源在 GCP 中创建或更新时的当前状态。
Policy Controller
虽然 Kubernetes 的基于角色的访问控制系统能够在命名空间和对象类型级别精细控制特定用户可以执行的操作,但它不强制执行任意策略或特定对象上的策略。例如,我们可能希望所有在特定命名空间中部署的 Pod 都为容器声明 CPU 限制,或者要求所有命名空间都包含一个自定义标签,以指示应向其收费的资源使用成本中心。我们可能还希望保护特定的部署并防止对该特定资源的修改,同时允许同一命名空间中的其他资源被修改。这正是 Policy Controller 发挥作用的地方。
由开源 OPA Gatekeeper 项目(mng.bz/ydpG)构建的策略控制器(mng.bz/X5mG)是一个准入控制器,它检查并验证任何对象的创建或更新是否符合已声明并加载到集群中的策略。每个策略由一个约束模板组成,该模板使用 Rego 编写以执行所需的测试,以及一个约束,它为特定策略提供模板的参数。当启用策略控制器时,默认提供一组现有的模板,称为模板库,但用户也可以创建定制的约束模板。然后,用户可以创建使用这些策略模板来对集群实施特定限制的约束。
由于我们正在使用 ACM,我们可以将策略约束与 ClusterSelectors 配对,以限制特定策略应用于哪些集群,锁定一些集群的同时,在另一些集群上允许更宽松的规则集。
层级控制器
层级控制器(mng.bz/Mlr7)是最新加入 ACM 体系下的附加组件,并在撰写本文时仍处于公开测试阶段。该控制器通过允许命名空间之间的继承,实质性地改变了 Kubernetes 中命名空间的工作方式,并由 Kubernetes 多租户工作组(github.com/kubernetes-sigs/multi-tenancy)推动。尽管与 ACM 仓库中抽象命名空间在层级结构中的工作方式相似,但该组件通过允许对象从父命名空间主动复制到子命名空间,进一步扩展了这一功能。这在使用 ACM 仓库且仓库中不包含机密信息(由于涉及的安全考虑)时特别有用。通过配置层级控制器从父命名空间复制机密到子或多个子命名空间,可以简化重工作量或手动干预的需求。
层级控制器的一个其他有用功能是控制器与云日志之间的协同作用。当在 ACM 配置文件上设置 enablePodTreeLabels 标志时,层级控制器会在所有 Pod 上设置标志,包括子命名空间中的 Pod。这也指示了 Pod 在层级树中的位置有多深。图 11.2 包含了一个示例。

图 11.2 当启用 enablePodTreeLabels 时,具有与层级相关的标签的命名空间和 Pod
如您在本例中可以看到,我们有 eom-prod 和 eom-staging 命名空间作为月末命名空间的孩子。月末命名空间是会计命名空间的孩子,而会计命名空间又是公司命名空间的孩子。如图 11.2 所示,应用后端 Pods 上的层级标签对应着命名空间层级。在 Kubernetes 中,您可以按标签的存在性以及标签值进行查询。因此,如果我们想查看会计及其子命名空间下的所有 Pods,我们可以运行 kubectl --all-namespaces get pods -l accounting.tree .hnc.x-k8s.io/depth,这将检索到报告后端的两个实例。这些标签也出现在云日志中,可以用来在多个命名空间中检索 Pods。
11.3 示例和案例研究
ACM 是建立在 Kubernetes 对象之上的,在集群生命周期内运行以高效管理集群的状态。到目前为止,我们已经看到了 ACM 的组件;在下一节中,我们将详细检查三个案例研究。这些虚构的公司中,每个要么目前正在使用 Kubernetes 并希望优化其部署,要么是第一次迁移到 Kubernetes;每个都将使用 ACM 来执行略微不同的功能。
我们的第一家公司 Evermore Industries 已经决定使用一个由许多节点组成的大型集群。他们所有的应用团队将在并行命名空间中运行他们的开发、测试和质量保证环境。Evermore 希望尽可能利用 GCP 资源,但他们的应用开发者对基础设施即代码(IaC)工具的经验不多。核心基础设施团队在 IaC 方面有经验,但缺乏足够的成员来提供应用团队所需的所有资源。管理层已经决定允许应用团队管理他们自己的云基础设施的一部分,但仍希望施加某些指南和政策轨道以防止无序支出。最后,由于公司中应用程序的多样性和涉及的权限级别不同,需要一个服务网格来隔离和控制流量。
村庄亚麻公司,LLC 大约二十年前成立,之前在其总部附近的两个数据中心本地运行所有基础设施。部分原因是其中一个数据中心的所有权发生变化,但也由于过去高流量购物日的糟糕结果,该公司决定使用云来实现快速可扩展性,同时保持其剩余的一个数据中心中的几个核心功能。然而,公司领导希望保留仅从本地数据中心运行整个应用程序堆栈的能力,并要求两个环境尽可能相似,并且故障转移应尽可能简单和快速。村庄亚麻还希望允许开发者自由管理自己的命名空间,而不会意外影响其他应用程序,也不会因批准每个变更而产生大量开销。
我们最后一家公司,模糊岩石盛宴,在美国和加拿大拥有数百家餐厅,并开始向欧洲和亚洲扩张。目前,他们的现场应用程序(包括库存控制、工资、前厅系统、调度和会计)通过每月补丁流程更新,将更改推送到各个门店。这需要专门的网络,有时可能会出现不稳定。该公司希望转向一种不需要他们的中央 IT 网络持续连接到各个门店的解决方案。他们过去在添加新应用程序到套件以及尝试将软件的目标版本部署到不同地区时,也遇到过修改他们的部署流程和技术的问题。
11.3.1 永恒工业
对于永恒工业来说,只需管理一个大集群的简单性是关键。然而,管理大量的命名空间、用户、权限和 GCP 资源对他们的 IT 运维来说证明是过于繁重。因此,他们转向 ACM、策略控制器和配置连接器来分担一些繁重的工作。
在迁移初期进行的一次简短的概念验证中,IT 运维团队意识到,一个非结构化的仓库可以让他们更容易地将特定策略附加到单个命名空间(例如,对生产命名空间应用一致的规则)的同时,也允许使用基于团队的规则,而无需大量重复。非结构化仓库还允许 IT 安全团队轻松限制哪些用户有权修改仓库中的特定文件夹。因此,格里芬团队的开发者不可能意外删除独角兽团队的东西,并且不允许任何应用程序团队成员修改全局策略。这减少了每个变更所需的配置审查量,但并未消除。
尽管 Evermore 已经使用 Kubernetes 几年了,但他们的 CI/CD 流程⁵使用模板引擎(Helm)直接部署到集群。这种设置在过去造成了一些问题,管理层已决定不再允许用户直接访问 prod 命名空间进行更改,包括 CI/CD 服务账户。由于非结构化存储库不强制要求目录中的配置元素属于任何特定组织,Evermore 已决定继续使用他们的模板引擎,但将配置直接写入 ACM 存储库,并在需要部署新版本时创建拉取请求。因为这些操作可以迅速由运营团队管理员验证,所以它们可以迅速部署到活动存储库。
此外,几个应用团队表示有兴趣使用 GCP 资源来卸载他们应用程序的一些工作负载。主要,这些团队对 Cloud SQL、Pub/Sub 和存储桶感兴趣。由于应用团队几乎没有人有使用 IaC 工具或 GCP 的经验,Evermore 将使用 Config Connector 允许团队在所有部署需求中保持 Kubernetes 空间,同时消除配置和培训用户访问 Kubernetes 和 GCP 本身的必要性。让我们看一下存储库概要,如下所示:
<Git Repo Parent>
├── bin
└── policies
├── namespace_selectors
├── global
│ ├── rbac
│ ├── namespaces
│ └── policy_controller
└── teams
├── griffins (accounting)
│ ├── rbac
│ ├── namespaces
│ └── applications
│ ├── reconciler
│ ├── expense_reports
│ └── accounts_pay_recv
├── unicorns (public-facing stores and APIs)
│ ├── rbac
│ ├── namespaces
│ └── applications
│ ├── storefront
│ ├── order_cap_and_ful
│ ├── payment_auth
│ └── inventory
├── dragons (internal apps)
│ ├── rbac
│ ├── namespaces
│ └── applications
│ ├── timesheets
│ └── shipping_manager
└── sylphs (reporting and analysis)
├── rbac
├── namespaces
└── applications
├── etl
└── reporting
我们不会详细介绍在这个存储库中创建的每个对象和文件,但这个概要为我们提供了一个起点,以了解 Evermore 所选择的架构。
在非结构化存储库中,策略目录不允许位于 Git 存储库的顶层,因此公司选择将其放置在一级以下的策略目录中。在该目录内,对象可以放置在任何级别,因此 IT 运营团队在 namespace_selectors 目录中放置了一套常见的命名空间选择器。其中之一是生产选择器,如下所示:
kind: NamespaceSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: production
spec:
selector:
matchLabels:
env: production
为了简化应用团队的工作,IT 运营团队也定义了一个选择器,该选择器通常只引用一个命名空间,如下所示:
kind: NamespaceSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: cc-project-ns
spec:
selector:
matchLabels:
evermore.com/is-active-project: true
为了防止在创建新项目时发生大规模变更,所有由团队定义的 Config Connector 对象都使用命名空间选择器方法来选择适当的命名空间以部署其对象。例如:
apiVersion: storagebuckets.storage.cnrm.cloud.google.com/v1beta1
kind: StorageBucket
metadata:
name: evermore-shipping-pk-list-archive
annotations:
configmanagement.gke.io/namespace-selector: cc-project-ns
spec:
versioning:
enabled: true
storageClass: ARCHIVE
在全局目录中,IT 运营团队定义了适用于整个集群的 RBAC 和策略控制器策略。在 RBAC 目录中,Dev/QA 和生产环境的命名空间范围角色分别定义。这些角色使用 NamespaceSelectors 通过一个配置应用到多个命名空间。NamespaceSelectors 通过注解使用,非结构化存储库中的所有命名空间范围对象必须直接声明一个命名空间(通过 metadata.namespace)或使用 NamespaceSelector。以下是大多数开发者将收到的基本生产角色:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: prod-developer
annotations:
configmanagement.gke.io/namespace-selector: production
rules:
- apiGroups: [""]
resources: ["pods", "configmaps"]
verbs: ["get", "watch", "list"]
- apiGroups: ["apps", "extensions"]
resources: ["deployments", "replicasets"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["list"]
policy_controller 目录是 Evermore 决定放置所有他们的 Policy Controller 约束的地方。除了需要定义容器限制和对 Istio⁶服务网格的限制之外,IT 运维团队还添加了以下约束,以强制团队为给定的命名空间定义环境和团队:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-env-and-team
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels:
- key: "env"
expectedRegex: "^(production|development|qa)$"
- key: "team"
expectedRegex: "^(griffins|unicorns|dragons|sylphs)$"
除了要求在命名空间上设置标签之外,此约束还限制了有效值的范围。Policy Controller 基础设施允许创建自定义约束模板,但 Evermore 已经能够使用提供的库实现所有他们希望实施的政策。
全局文件夹中的命名空间目录包含由 IT 运维管理的配置,这些配置要么未被任何应用团队使用,要么被大多数或所有团队使用。例如,这包括 Istio 命名空间和 Config Connector 项目命名空间。此外,此文件夹下的子文件夹包含将在整个系统中使用的 Secrets、ConfigMaps 和 Deployments。IT 运维人员已将一些通用的 Istio 配置以及应复制到多个命名空间(包括可以通过每个应用程序的环境变量挂载的联系人信息 ConfigMap)的配置放置在此结构中。
对于每个团队的文件夹,rbac 和命名空间目录由各个应用程序团队处理,尽管更改仍必须通过 IT 运维人员成员的 pull request 进行批准。命名空间目录包含每个应用程序和环境的命名空间声明,而 rbac 目录包含每个用户的 RoleBindings 和 ClusterRoleBindings。
在每个应用程序文件夹(reconciler、storefront、etl 等)内部,每个环境都存在三个文件夹。这些文件夹与每个应用程序已存在的 CI/CD 流程相连接。CI/CD 管道已经配置为生成要加载到集群上的 Kubernetes 对象,因此团队将目标更改为输出到适当环境目录中的一组文件。此 CI/CD 流程还会触发一个自动的 pull request,然后可以快速由 IT 运维人员成员批准和处理。
Evermore 选择这种配置用于他们的仓库,因为它最适合他们当前的需求。然而,他们正在使用一个无结构的仓库,因此如果需要,更改目录结构是一个低成本的选择。其他公司可能会选择将所有 RBAC 相关的对象集中到一个目录中,或者完全消除“团队”的概念,并根据单个应用程序组织一切。无结构仓库允许您以对组织最有意义的方式组织策略,而不是被限制在以命名空间为中心的结构中。
11.3.2 Village Linen, LLC
Village Linen 决定采用分层仓库,但他们将使用 Hierarchy Controller 来帮助自动复制他们的一些 Secrets 和 ConfigMaps。他们正在 GCP 上运行 GKE,同时在现有的数据中心中运行 VMware 上的 GKE,希望两者在集群内部几乎可以完全相同地运行。
灾难恢复是企业管理的重大问题,但管理层明白在处理故障转移时数据复制有时可能成为问题。因此,架构师们开发了一个系统,允许用户同时使用云和本地应用程序层,但在云中使用单个数据库集群。数据库在本地进行复制(此处不包括或覆盖复制配置),配置更改将应用程序指向数据中心中位于的数据中心的备用数据库。仓库通常如下所示:
<Git Repo Parent>
├── bin
└── policy_directory
├── namespaces
│ ├── rbac.yaml
│ ├── central
│ │ ├── namespace.yaml
│ │ └── database_location_config.yaml
│ ├── applications
│ │ ├── service_account.yaml
│ │ ├── website
│ │ │ ├── namespace.yaml
│ │ │ ├── hierarchy.yaml
│ │ │ └── repo-sync.yaml
│ │ └── inventory
│ │ ├── namespace.yaml
│ │ ├── hierarchy.yaml
│ │ └── repo-sync.yaml
│ └── village-linen-ac15e6
│ ├── namespace.yaml
│ ├── hierarchy.yaml
│ └── repo-sync.yaml
├── cluster
│ ├── rbac.yaml
│ ├── hierarchy.yaml
│ └── constraints.yaml
├── clusterregistry
│ ├── data center.yaml
│ ├── cloud.yaml
│ └── selectors.yaml
└── system
└── repo.yaml
从底层开始,我们有一个包含当前版本策略的仓库定义。在 clusterregistry 目录中,我们定义了本地数据中心中的集群以及 GCP 中的集群。我们还为这些集群中的每一个定义了选择器,以便我们可以在 namespaces 目录中限制资源。例如,云集群声明和选择器如下:
kind: Cluster
apiVersion: clusterregistry.k8s.io/v1alpha1
metadata:
name: vili-cloud
labels:
locality: cloud
---
kind: ClusterSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: sel-clu-cloud
spec:
selector:
matchLabels:
locality: cloud
在 cluster 目录中,我们有适用于整个集群的配置。这些包括 ClusterRoles 和 ClusterRoleBindings 以及 Policy Controller 约束。默认情况下,Hierarchy Controller 只从父命名空间传播 RBAC 角色和角色绑定到子命名空间。然而,Village Linen 想要使用 Hierarchy Controller 从 central 命名空间同步 Secrets 和 config maps 到应用程序和项目命名空间。这样,Secrets 可以直接应用于 central 命名空间,并自动复制,无需将其检查到 Git 仓库中。修改后的 HNCConfiguration 如下:
apiVersion: hnc.x-k8s.io/v1alpha1
kind: HNCConfiguration
metadata:
name: config
spec:
types:
- apiVersion: v1
kind: ConfigMap
mode: propagate
- apiVersion: v1
kind: Secret
mode: propagate
向上移动到 namespaces 目录,我们有一个顶层文件来定义在每个命名空间中要创建的一组 RBAC 角色。Village Linen 可以将这些角色绑定到应用程序抽象命名空间(这将将这些绑定应用于网站和库存命名空间),或者绑定到显式定义的命名空间,以控制谁可以访问这些角色。
此目录定义了总共四个命名空间:central、website、inventory 和 village-linen-ac15e6。最后一个命名空间与用于部署这些集群资源的项目 ID 匹配(也是云 GKE 集群部署的位置)。两个应用程序命名空间共享一个服务账户定义,尽管这将创建两个独立的服务账户,一个在每个命名空间中。在 central 命名空间中,我们声明了一个 ConfigMap,它告诉应用程序使用哪个数据库,无论是 Cloud SQL 还是本地集群。
在每个“子”命名空间(网站、库存和 village-linen-ac15e6)中,仓库都有一个 HierarchyConfiguration 对象,它使 Hierarchy Controller 能够从父级传播对象到子级:
apiVersion: hnc.x-k8s.io/v1alpha2
kind: HierarchyConfiguration
metadata:
name: hierarchy
spec:
parent: central
在这种情况下,所有“子”命名空间都继承自一个共同的父级,但可以将这些命名空间“堆叠”成链。例如,我们可以引入另一个命名空间——applications,它继承自中央,并将库存和网站修改为从 applications 继承。执行此类堆叠层次结构可以更精细地控制要复制的对象,如果启用,还可以为日志添加额外的标记。
当为特定集群启用 Hierarchy Controller 时,可以选择一个附加选项,该选项包括 Pods 上的树标签。这些标签表示 Pod 的层次关系,可以与命令行工具和 Cloud Logging 一起使用,以过滤来自给定命名空间的日志。
因为 Village Linen 使用分层仓库,所以对于 namespaces 目录中的对象,不需要显式定义 .namespace 字段。然而,需要显式定义命名空间本身;Village Linen 选择将这些定义放在 namespace.yaml 文件中,尽管这不是必需的。在网站和库存命名空间中定义的对象用于启用下一节中提到的多仓库功能。但是,Cloud SQL 集群是在 namespaces 目录的最后一个文件夹中定义的。cloud_sql.yaml 文件如下定义了 SQL 数据库、实例和用户:
---
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLInstance
metadata:
name: village-linen
annotations:
configmanagement.gke.io/cluster-selector: sel-clu-cloud
spec:
region: us-central1
databaseVersion: POSTGRES_9_6
settings:
tier: db-custom-16-61440
---
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLDatabase
metadata:
name: village-linen-primary
annotations:
configmanagement.gke.io/cluster-selector: sel-clu-cloud
spec:
charset: UTF8
collation: en_US.UTF8
instanceRef:
name: village-linen
---
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLUser
metadata:
name: village-linen-dbuser
annotations:
configmanagement.gke.io/cluster-selector: sel-clu-cloud
spec:
instanceRef:
name: village-linen
password:
valueFrom:
secretKeyRef:
name: db-creds
key: password
如您所见,Config Connector 允许引用其他 Config Connector 对象(前一个代码片段中的 instanceRef 声明)和 Secrets。Config Connector 还可以从 ConfigMaps 中提取信息。出于安全原因,db-creds Secret 没有存储在 ACM 仓库中。然而,由于 Hierarchy Controller 被配置为复制 Secrets 和 ConfigMaps,我们可以手动在中央命名空间中创建或更新 Secret,Hierarchy Controller 将处理复制到应用程序和项目命名空间。当 Config Connector 下次进行协调时,将使用新密码为用户。
所有 Config Connector 配置都包含一个带有集群选择器的注解。这引用了在 GKE 云安装中 clusterregistry 目录中定义的集群选择器。由于 Config Connector 旨在从 Kubernetes 对象创建 GCP 资源,因此它仅在 GCP 集群的 GKE 上处于活动状态。公司没有在本地集群中启用 Config Connector,因此尝试部署这些资源将会失败。即使 Config Connector 在本地集群中启用,部署这些资源在那里也不会有任何影响,可能会引起更多的故障排除问题,所以我们只将它们部署到云集群。
使用此配置,如果 Village Linen 需要从云数据库切换回本地数据库,只需对 database_location_config 进行简单更改。部署并推送更新后的配置后,单个应用程序需要重新启动。
在前面概述的目录结构中,每个应用程序命名空间都包含一个 repo-sync 文件。这些对象用于实现多个仓库模式:
apiVersion: configsync.gke.io/v1alpha1
kind: RepoSync
metadata:
name: repo-sync
namespace: website
spec:
git:
repo: https://source.developers.google.com/p/village-linen-ac15e6/r/website
branch: master
auth: gcenode
secretRef:
name: acm-website-repo
通过使用多个仓库模式,Village Linen 可以为每个命名空间创建单独的仓库,使得应用程序团队在修改 Kubernetes 对象(包括部署、服务和持久卷)时拥有更简单的体验。这种安排也限制了团队意外部署其命名空间之外的内容。操作团队仍然可以使用核心仓库向每个命名空间添加项目,这些项目与特定命名空间的对象并行存在。在发生冲突的情况下,核心仓库的版本将被使用,防止应用程序团队覆盖操作团队已经定义的策略、服务帐户、机密等。此外,由于操作团队已通过 RBAC 限制了命名空间工作员可以修改的对象,因此单个仓库被沙盒化,仅控制一组有限的对象,并且除非操作团队允许,否则不能授予自身权限。
对于 Village Linen,ACM 提供了一个方便的位置,以便所有核心配置可以集中管理和更新,同时释放应用程序团队控制他们自己的命名空间。它还在配置更改时提供了一个方便的审计跟踪。当本地数据中心集群或云集群因任何原因失败时,可以快速自动启动一个新的集群并将其连接到 ACM 仓库,部署完整的操作栈。
11.3.3 Ambiguous Rock Feasting
对于 Ambiguous Rock Feasting(A.R. Feasting),在过去几年中,管理他们不断扩大的餐厅群和部署的技术变得越来越困难。公司现在认为,技术组件的实施时间以及每个新位置给他们的 IT 运营团队带来的额外运营负担已经变得不可持续。因此,他们正在转向一个更具灵活性的模型,该模型可以更好地扩展。
这些餐厅已经在本地服务器上运行了 Kubernetes 集群,但更新部署的应用程序或解决问题导致每个位置都损失了大量的时间。因此,A.R. Feasting 已经转向使用 ACM 来管理单个集群。一般来说,仓库布局与 Village Linen 的布局相匹配,但 A.R. Feasting 没有使用层次控制器。
当部署 ACM 操作员时,每个位置的集群都被分配了一个专有的名称,例如 arf-043-01a。然后 IT 运维团队使用策略仓库中的集群定义对这些集群进行标记,如下所示:
kind: Cluster
apiVersion: clusterregistry.k8s.io/v1alpha1
metadata:
name: arf-043-01a
labels:
sales-area: us-midwest
country: us
region: texas
city: austin
location-code: alpha
或者像这个 arf-101-01a 的例子:
kind: Cluster
apiVersion: clusterregistry.k8s.io/v1alpha1
metadata:
name: arf-101-01a
labels:
sales-area: emea
country: uk
region: england
city: london
location-code: alpha
is-rollout-tester: true
IT 运维团队随后根据这些标签定义选择器,其中一些如下所示:
---
kind: ClusterSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: rollout-testers
spec:
selector:
matchLabels:
is-rollout-tester: true
---
kind: ClusterSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: non-testers
spec:
selector:
matchExpressions:
- key: is-rollout-tester
operator: DoesNotExist
---
kind: ClusterSelector
apiVersion: configmanagement.gke.io/v1
metadata:
name: country-us
spec:
selector:
matchLabels:
country: us
这些选择器随后用于控制应用程序新版本的部署,或者在某些地区仅部署某些应用程序。例如,只有美国的餐厅有快车道。因此,快车道管理应用程序只需要部署到 country-us 集群。公司还决定让某些选定的商店成为新软件的测试床,这可以通过它们集群上的 is-rollout-tester 标志来表示。这里包含了一个应用程序部署的示例。然而,模板的一些部分已被删除,因为它们在两个示例中是相同的:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: foh-engine
annotations:
configmanagement.gke.io/cluster-selector: rollout-testers
spec:
template:
spec:
containers:
- name: engine
image: gcr.io/ambiguous-rock/foh/engine:v2.1.0
imagePullPolicy: IfNotPresent
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: foh-engine
annotations:
configmanagement.gke.io/cluster-selector: non-testers
spec:
template:
spec:
containers:
- name: engine
image: gcr.io/ambiguous-rock/foh/engine:v2.0.3
imagePullPolicy: IfNotPresent
这两种部署之间的区别在于所使用的集群选择器和引擎镜像的版本。回顾一下定义的集群选择器,rollout-testers 和 non-testers 没有重叠。如果我们没有定义 non-testers 组,并且在第二个部署中提前移除了注释,那么 rollout-testers 就会发生冲突,因为两个部署都是有效的。
由于 ACM 使用与 Kubernetes 相同的日志标准记录其更改,并且 A.R. Feasting 餐厅将它们的日志转发到云日志,IT 运维团队可以使用云监控设置监控,以确定各个集群上特定应用程序和版本的状态。使用此仪表板,他们可以快速诊断潜在问题可能发生的地方(例如商店的停电),并更有效地工作。
11.4 结论
组织在管理其 IT 环境时面临着日益增加的复杂性。使用 Anthos Config Management 与 Kubernetes 集群(无论是在本地、Google Cloud 还是其他云服务提供商),为管理员提供了一个熟悉且声明式的控制其集群基础的方法。本章提供了该服务的广泛概述,一些采用 ACM 策略的原因,以及几个示例来说明 Anthos Config Management 的强大功能。
然而,我们还没有完全探索 Anthos Config Management 的能力和可能性:这样做可能需要一本完全属于自己的书。最终,ACM 旨在使您的业务更高效,并减少管理集群的复杂性。本章应该为您提供了如何在您的组织中使用 ACM 的想法,以及一些如何推动采用的示例。
关于本章涉及的各种主题的更多信息示例,请参阅本书相应的章节:
-
策略控制器:第十三章
-
云日志:第五章
摘要
-
随着组织管理的集群数量增加,强制执行最佳实践或提供核心功能变得越来越困难。
-
现代开发实践和安全格局鼓励组织采用能够快速适应和部署更改的技术。
-
Anthos Config Management 是 Anthos 平台的核心组件,旨在提供基础设施、安全和运营团队所期望的安全性和透明度,同时给予开发团队以最小的额外障碍部署其应用程序的能力。
-
ACM 可以部署在以下两种模式中,两者都提供了独特的优势:
-
分层模式允许轻松地将单个资源部署到多个命名空间,并需要一个逻辑的命名空间集合才能有效。
-
无结构模式允许开发人员和管理员更容易地选择将组件部署到哪些命名空间,但缺点是需要明确指定使用哪些命名空间。此模式也与许多可能在分层模式中无法正常工作的模板框架兼容。
-
-
ACM 包含自定义资源,允许对应用配置元素到哪些命名空间和哪些集群有更大的控制。
-
ACM 还基于开源工具引入了以下附加组件:
-
Config Connector 为 Kubernetes 集群提供基础设施作为数据的能力,允许通过声明 Kubernetes 资源来配置 Google Cloud 资源。
-
Policy Controller 为管理员提供了一个方便的工具,可以在其集群中创建和执行策略。
-
Hierarchy Controller 是一个旨在提供在集群中命名空间之间复制资源替代方法的倡议的结果。由于在 Git 仓库中存储 Secrets 是一种反模式,Hierarchy Controller 定义允许组织定义一个 Secret 或配置一次,并自动将其复制到子命名空间。
-
-
以下三个案例研究探讨了使用和实施 ACM 的不同原因:
-
Evermore Industries 希望减少直接在生产环境中工作的用户数量,并允许开发团队直接配置某些 Google Cloud 资源。他们目前正在使用,并将继续使用模板引擎来生成他们的 Kubernetes 配置。
-
Village Linen, LLC 正在使用 ACM 在本地和远程环境中,以及 Hierarchy Controller 来管理 ConfigMaps 和 Secrets 在这两组集群中的复制。
-
Ambiguous Rock Feasting 在 Kubernetes 方面经验丰富,但正在特定地使用 ACM 的 ClusterSelector 功能来更精确地控制其应用程序的部署位置。
-
^ (1.)Anthos UI 主要在第一章中介绍。
^ (2.)有关 Kubernetes 操作符模式的更多信息,请参阅 mng.bz/nJog。
(3.)注解为 configmanagement.gke.io/managed: enabled。
(4.)这是部署和作业使用的相同模式,详细信息请参阅mng.bz/41Ga。
(5.)有关 CI/CD 和 Anthos 的更多信息,请参阅第十二章。
(6.)第四章详细探讨了 Istio。
12 与 CI/CD 的集成
Konrad Cłapa 和 Jarosław Gajewski
本章涵盖
-
理解 CI/CD 概念
-
自动化持续开发工作流程
-
为您的 Anthos 应用程序介绍持续集成
-
使用 Cloud Deploy 管理持续部署
-
理解现代 CI/CD 平台
在本章中,我们将指导您开发和部署 Anthos 应用程序。为了简化这项任务,我们将使用一个简单的 Hello World 应用程序。我们将通过图 12.1 中显示的整个工作流程,使用 Python 和 Go 中的示例进行说明。我们将从持续开发开始,我们将学习如何开始开发 Anthos 应用程序,并在将代码提交到 Git 仓库之前预览它。然后,我们将查看持续集成,最后,我们将讨论持续部署和交付。
以下三个角色与 CI/CD 管道进行交互:
-
开发者—开发应用程序代码
-
运维人员—使用 Kubernetes 清单配置应用程序部署
-
安全—配置策略以确保 Kubernetes 部署的安全性

图 12.1 CI/CD 工作流程
在本章中,我们将专注于前两个角色。如果您想了解更多关于安全角色的信息,请参阅第十三章。
观察开发者的工作流程,我们看到他们开发应用程序代码,并希望立即看到应用程序的预览。然后,如果他们完成了他们的更改,他们会将代码提交到源代码仓库。这就是 CI 开始介入进行代码审查、测试和容器镜像构建的地方。
当我们考虑运维人员时,我们看到他们负责配置 Kubernetes 基础设施和部署应用程序。他们需要能够为多个环境配置应用程序,包括开发、测试和生产。一旦配置就绪,就可以使用 CD 工具部署应用程序。
现在我们已经了解了用例,让我们从 CI/CD 概念的简要介绍开始。
12.1 CI/CD 简介
现代软件开发流程复杂。以一致的速度和可持续的方式生产高质量的软件涉及多个流程和工具。实施 CI/CD 管道是达到这一目标的最佳实践之一。持续集成 (CI) 是软件开发的一种实践,其中开发者频繁地检查代码,定期(至少每天一次)集成,每次集成后都进行验证,这是一个自动化的过程,用于构建和测试集成更改 (mng.bz/aMpz)。这个过程使我们能够以恒定的速度和适当的水平实现可靠、可重复和可重用的构建,同时防止混乱并提高效率。
持续集成只是软件交付过程的一个方面。为了成功实现以管道驱动的开发,CI 必须由持续交付(CD)紧随其后。持续交付(CD) (continuousdelivery.com/) 是以可持续的方式安全且快速地将所有类型的更改(包括新功能、配置更改、错误修复和实验)引入生产的能力。它适用于基础设施配置、应用程序部署、移动应用发布以及数据库和静态资源修改。CD 管道通过使此过程更加自动化,从而提高了从源到生产的软件交付,改善了管道的可靠性、可预测性和可见性,从而降低了风险。¹
让我们来看看一些表征现代 CI/CD 平台的特征。
12.1.1 可重复性
可重复性允许对创建的代码和工件周围的要求和流程进行自动化。构建过程应该是确定性的,这样开发者才能对产生的工件有信心。可重复的构建和测试允许开发者在其本地环境中运行相同的流程。部署和配置管理的自动化有助于在不同环境中提供一致性。
12.1.2 可靠性
可靠性提高了开发和运营团队对保证工具可用性和适宜性、集成、测试和操作要求的完整性和充分性的流程和系统的信心。通过定义的工作流程进行自动化测试是捕捉和跟踪组件最终成功和失败状态的关键,这增加了团队在开发和发布周期中的信心和知识。
12.1.3 可复用性
可复用性使团队能够扩展、简化并加速开发工作流程。CI/CD 管道应该以允许为类似应用程序重用管道组件的方式进行实施。这不仅降低了设置新管道的成本,而且当跨企业处理多个应用程序时,也提高了开发者的效率。
12.1.4 自动化测试
在高质量交付过程中,验证开发系统的架构和功能至关重要。这可以通过在 CD 管道中实施一个强大的自动化测试流程作为其组成部分来实现。现代交付管道应该尽可能多地包含自动化测试,包括单元、组件和系统功能测试,以及检查能力、可用性和安全合规性的非功能性测试。自动化测试几乎立即为开发者提供反馈,减少了生产部署中的错误数量和错误率。
12.1.5 基于主干开发
当开发者工作在“分裂大脑”环境中时,持续交付可能会显著减慢,在这种环境中,功能或错误修复代码分支的寿命非常长。结果,在大团队中,代码更改在集成长期存活分支时可能会引起冲突。这可能需要手动活动,使 CI 流程陷入停滞。
12.1.6 环境一致性
环境一致性是降低生产部署风险的关键方面之一。开发环境和生产环境的部署必须依赖于相同的流程、架构原则和配置策略。完全自动化的部署对于在 CD 管道中实现自动化测试和反馈至关重要。它允许根据存储在版本控制系统中的代码和数据轻松地复制整个环境的状态。
12.1.7 部署自动化
重要的是要承认,部署自动化可能是一个需要分步骤实现的旅程。你应该从易于自动化的组件开始,减少手动步骤的数量,并逐步自动化更复杂的组件。在考虑部署自动化和测试时,一个因素起着重要作用:架构。如果我们架构引入了重大的限制并且是一个紧密耦合的设计,那么用于 CD 的最佳流程和工具将无法帮助我们。
12.1.8 团队文化
运营和开发团队之间的全面合作对于自动化构建、测试、部署和基础设施至关重要。这确保了所有相关方都完全理解整个过程,并且不会引入不必要的复杂性。这不是一个容易的过程,通常需要花费大量时间一起重新设计现有流程的架构。
12.1.9 内置安全/DevSecOps
预防胜于治疗。这一点同样适用于软件交付和安全相关的挑战。在软件交付过程中缩短团队的反馈循环被称为“左移策略”。同样的方法用于在开发过程早期以及整个持续交付流程中引入安全流程。这种方法使团队能够构建基于预先批准、标准化的工具和政策(mng.bz/gJKl)的开发栈。这些工具帮助团队将其常规的开发和交付活动中的安全需求作为一部分来处理。标准化使得额外的测试能力成为可能,其中自动化测试可以扩展以满足生产环境中的安全和监管要求。与自动化部署一样,安全措施的自动化可以分步骤实施,随着时间的推移减少对人工审查和测试的需求。因此,开发者不再需要关心这些。
12.1.10 版本控制
版本控制必须应用于我们交付和集成管道的每个工件,从应用程序代码、配置和系统配置开始,到用于自动化构建和配置环境的脚本结束。它通过“代码即配置”环境的可审计性或可伸缩性支持开发者在应用程序开发期间。它还响应对即时更改或由系统或环境中发现的漏洞或缺陷引起的生产中的灾难的需求,允许它们以可控的方式发布,并提供了自动回滚的简单方法。
维护一个小型版本控制系统相当简单,但当团队规模扩大时,代码的可维护性变得越来越具有挑战性。在这种情况下,允许所有团队成员轻松访问代码至关重要。因此,他们将重用现有代码而不是创建重复的副本,并扩展代码以实现新的功能或修复全局错误。版本控制通过团队之间轻松传递知识来促进快速软件交付。这导致代码质量更高,从而提高了可扩展性和可用性。
12.1.11 工件版本控制
构建工件需要是无条件重复和不可变的,这样团队才能信任构建系统的完整性。从相同源多次创建工件的系统可能会因为配置漂移而在每个步骤中生成略微不同的工件。管理构建工件及其版本对于防止在多个地方存储同一工件的多个版本非常重要。不可变的版本化工件可以在一个地方提供对历史和引用的全面可见性。这也帮助管理依赖关系并提高重用性。
12.1.12 监控
需要强调的最后一个能力是监控。理解和监控系统的健康状况对于在问题发生之前减轻潜在问题至关重要。基于阈值或变化率的主动故障通知构建了关于系统状态的运营知识。通过日志记录和监控扩展,将故障警报路由到团队或系统为及时对这些事件做出反应提供了机会,并防止了中断和停机。
全栈监控允许支持团队调试系统并测量其行为与定义的模式或变化。历史监控数据使我们能够快速引入持续改进,从而提高了 CI/CD 管道的效率。
12.2 持续交付与持续部署的比较
我们讨论了很多关于持续交付的内容,它通常与持续部署混合使用。尽管它们都隐藏在相同的 CD 缩写后面,但这两个概念之间存在细微的差别。持续部署通过添加自动部署交付的工件到用户环境,而不需要人工干预,从而扩展了持续交付。尽管持续交付适用于所有类型的软件,包括商业应用程序、移动应用程序和固件,但持续部署主要适用于代码变更可以立即应用到生产的情况。
在我们熟悉了 CI/CD 的概念和能力之后,我们现在可以进入实施选项、实践和工具的详细描述。
12.3 持续开发
开发云原生应用程序非常令人兴奋,但也带来了一些挑战。图 12.2 显示了开发者需要遵循的流程,以预览 Kubernetes 应用程序。

图 12.2 持续开发工作流程
正如我们所见,一旦代码开发完成,就需要按照预定义的步骤构建镜像并将其推送到容器注册库。接下来,应用程序需要部署到目标集群。这意味着对于开发者提交的每一个变更,都会触发相同的流程。想象一下,整整一天都在运行多个命令,只是为了预览你的应用程序!这正在成为开发者的噩梦。
在本节中,我们将探讨一些工具,这些工具将允许我们在不需要运行 Anthos 集群的情况下本地部署 Anthos 应用程序,并自动化我们确定的整个流程。
让我们从基于 minikube 设置我们的本地执行环境开始。接下来,我们将探讨如何自动化在代码变更后预览应用程序所需的重复性和繁重任务。最后,我们将讨论如何使用集成开发环境(IDE)提供完整的 Anthos 应用程序开发体验(DX)。
12.3.1 设置本地预览 minikube 集群
minikube (minikube.sigs.k8s.io/docs/start/) 是一款流行的软件应用程序,允许你在笔记本电脑上本地运行 Kubernetes 应用程序。它支持 Windows、Linux 和 macOS。你不必将应用程序部署到 Anthos 集群,而是可以本地部署并预览应用程序,然后再将代码推送到 Git 仓库。这将节省你的时间并降低开发环境成本。尽管 minikube 不是为托管生产工作负载而设计的,但它支持 Kubernetes 支持的大多数功能。
你可以使用 kubectl 命令行界面与之交互,就像与常规集群一样。Minikube 可以在满足以下最低要求的任何笔记本电脑上运行:
-
2 个 CPU
-
2 GB 的空闲内存
-
20 GB 的空闲磁盘空间
-
互联网连接
-
虚拟化软件,如 Virtual Box
图 12.3 显示了你可以用来与 minikube 交互的工具。我们将在本章的后续部分回顾 Skaffold 和 Cloud Code。它们为开发 Anthos 集群提供了一个很好的替代方案。

图 12.3 minikube 集成
安装过程相当简单,但取决于你使用的操作系统。这可能会随着新版本发布而改变,因此建议你参考minikube.sigs.k8s.io/docs/start/上的官方页面以获取安装步骤。让我们看看我们如何使用 minikube 部署我们的示例应用程序。
一旦 minikube 成功安装,你可以通过运行以下命令来启动它:
minikube start
现在,你可以创建一个简单的 hello-minikube Deployment,并使用 NodePort 服务将其公开。我们将使用一个现有的容器镜像,echoserver:1.4,但你也可以构建自己的镜像:
-
通过运行以下命令创建 Deployment:
kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.4 -
通过创建服务来公开 Deployment:
kubectl expose deployment hello-minikube --type=NodePort --port=8080 -
检查服务是否存在:
kubectl get services hello-minikube -
你应该看到以下提示:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-minikube NodePort 10.102.94.116 <none> 8080:31029/TCP 8s -
为服务配置端口转发到你的本地机器端口:
kubectl port-forward service/hello-minikube 8080:8080将出现以下提示,指示端口已转发:
Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080 -
现在,我们可以打开浏览器并看到服务正在地址 http:/ /localhost:8080 上响应,如图 12.4 所示。

图 12.4 浏览器结果页面
我们已经看到了如何预览我们的应用程序。正如你可能已经注意到的,它仍然需要我们构建镜像并使用 kubectl 更新应用程序的预览,随后是代码的更改。这个过程并不高效,理想情况下,我们需要一个工具来自动化这些步骤。实现这一目标的常用工具是 Skaffold。
12.3.2 使用 Skaffold 进行持续开发
Skaffold(skaffold.dev/)是一个由 Google 赞助的开源项目。它始于解决 Kubernetes 应用程序持续开发的需求。正如我们在上一节中学到的,为了部署应用程序,开发者必须编写创建容器镜像、将创建的镜像推送到仓库以及最终将其部署到集群的必要步骤。
Skaffold 通过自动处理所有这些步骤来实现这一点。它持续监视源文件,并触发之前提到的步骤,在本地 minikube 或远程 Anthos 集群上创建 Kubernetes 应用程序的预览。当开发者通过简单地按 Ctrl+C 停止 Skaffold 时,应用程序资源会自动清理。
在持续开发功能的基础上,Skaffold 还提供了 CI/CD 管道的构建块。它支持使用 kubectl、Helm(helm.sh/)和 Kustomize(kustomize.io/)进行部署。让我们看看图 12.5,它可视化了一个使用 Skaffold 进行开发的流程。

图 12.5 Skaffold 功能
在这个图中,你可以看到一个简单的管道可视化。Skaffold 正在监视指定文件夹中的源文件更改。当它检测到更改时,Skaffold 会自动构建镜像并将它们推送到注册表。一旦容器构建完成,Skaffold 会将容器镜像部署到预定义的 Kubernetes 端点。在接下来的部分中,我们将解释 Skaffold 如何与 Cloud Code (cloud.google.com/code) 集成,以提供更好的开发者体验。
使用 Skaffold
用户通过命令行界面(CLI)与 Skaffold 交互。Skaffold 的完整指南可以在这里找到:skaffold.dev/docs/references/cli/。为了快速了解如何使用 Skaffold,让我们看看基本步骤。我们将看到如何部署用 Go 编写的 Hello World 应用程序。
安装 Skaffold
安装 Skaffold 的过程因底层操作系统而异。Skaffold 可以作为 gcloud 组件安装。它也可以作为容器镜像 gcr.io/k8s-skaffold/skaffold:latest 提供,可以直接在云原生 CI/CD 工具中使用。所有安装选项都在官方网站上解释 (skaffold.dev/docs/install/)。对于本地预览,你可以使用 minikube,这将允许你在笔记本电脑上部署你的应用程序。
Skaffold 配置文件
Skaffold 使用单个配置 YAML 文件 skaffold.yaml 来定义 CD 管道中的步骤。它类似于 Kubernetes 资源清单。让我们在这里看看一个非常基本的示例配置文件:
apiVersion: skaffold/v2beta8
kind: Config
build:
artifacts:
- image: skaffold-example
deploy:
kubectl:
manifests:
- k8s-*
在之前的管道中定义了两个阶段:构建和部署。在构建阶段,Skaffold 寻找 Dockerfile 定义,并使用它来构建名为 skaffold-example 的容器镜像。在部署阶段,Skaffold 使用 kubectl 部署所有以 k8s-前缀开始的 YAML 文件中定义的对象。配置文件结构的详细解释可以在 Skaffold 网站上找到 (skaffold.dev/docs/references/yaml/)。
启动 Skaffold
你可以通过运行以下命令自动生成 skaffold.yaml 配置:
skaffold init
这将检测当前文件夹中的源文件,并创建一个包含构建和部署部分的非常简单的配置文件。让我们创建以下三个文件,如下面的代码片段所示:
-
Dockerfile—容器镜像定义
-
main.go—简单的 Hello World Go 应用程序
-
k8s-pod.yaml—Kubernetes pod 定义
Dockerfile 内容:
FROM golang:1.12.9-alpine3.10 as builder
COPY main.go .
ARG SKAFFOLD_GO_GCFLAGS
RUN go build -x -gcflags="${SKAFFOLD_GO_GCFLAGS}" -o /app main.go
FROM alpine:3.10
runtime
ENV GOTRACEBACK=single
CMD ["./app"]
COPY --from=builder /app .
Main.go content:
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("Hello world!")
time.Sleep(time.Second * 1)
}
}
k8s-pod.yaml content:
apiVersion: v1
kind: Pod
metadata:
name: getting-started
spec:
containers:
- name: getting-started
image: skaffold-example
这将生成一个 skaffold.yaml 文件,我们已经在上一节中看到了,包含两个阶段:
apiVersion: skaffold/v2beta3
kind: Config
metadata:
name: getting-started
build:
artifacts:
- image: skaffold-example
deploy:
kubectl:
manifests:
- k8s-pod.yaml
你可以从这里开始,根据你的需要扩展文件,使用 Skaffold 文档。
使用 Skaffold 进行开发
最终我们在文件夹中有四个文件,包括 Skaffold 配置文件。现在我们可以开始持续开发,其中 Skaffold 将监视源文件夹中的更改并执行 skaffold.yaml 文件中定义的所有步骤。要开始开发,请运行以下命令:
skaffold dev
Skaffold 将自动将部署容器的日志从控制台输出。现在如果您将源文件 main.go 中的内容改为从 Skaffold 打印 hello 而不是 hello world,Skaffold 将自动检测更改,重新构建镜像,将其推送到注册表,并部署它。由于日志输出到控制台,您应该看到来自 Skaffold 的消息 hello。
使用 Skaffold 单次运行
虽然 skaffold dev 一直在监视源文件,但您也可以通过运行 skaffold run 命令来执行单个工作流程。当您只想运行一次执行而不希望每次代码修改时都触发流程时,这很有用。
支持的功能
到现在为止,您应该已经基本了解了如何使用 Skaffold 开始开发,那么让我们看看其他有用的功能。
流程阶段
到目前为止,我们只看了 Skaffold 的基本功能。然而,这个工具还有更多能力可以解决高级流程阶段。例如,开发者可能不希望在每次代码更改后都重新构建镜像。在这种情况下,Skaffold 可以将文件同步到容器的主.go 源文件中。要实现这一点,您将使用文件同步功能。图 12.6 显示了工作流程中的所有步骤。

图 12.6 Skaffold 工作流程
以下列表显示了所有可以用来执行这些步骤的 Skaffold 流程阶段:
-
初始化—生成基本的 Skaffold 配置
-
构建—使用选择的构建器构建镜像
-
测试—使用结构测试测试镜像²
-
标记—根据不同的策略标记镜像
-
部署—使用 kubectl、Kustomize 或 Helm 部署应用程序
-
文件同步—将更改的文件直接同步到运行中的容器
-
日志输出—输出容器的日志
-
端口转发—将服务端口转发到本地主机
-
清理—清理清单和镜像
如您所见,我们有一个完整的流程,使我们能够部署和预览 Anthos 应用程序。
支持的环境
Skaffold 支持本地和远程 Kubernetes 集群。您可以使用本地开发集群,如 minikube 或在远程位置部署的 Anthos/Kubernetes 集群。
要连接到远程 Kubernetes 集群,您需要在 kubeconfig 文件中设置一个上下文,就像连接到任何 Kubernetes 集群一样。默认上下文可以通过运行以下命令来覆盖:
skaffold dev --kube-context <myrepo>
或者通过更新 skaffold.yaml 文件中的 deploy.kubeContext 属性:
deploy:
kubeContext: minikube
支持的构建工具
如果您需要使用其他工具来构建容器镜像,可以在 skaffold.yaml 配置文件的构建部分配置自定义构建器。要使用自定义构建器,请在构建部分定义适当的选项以使用该构建器。有关客户构建器的详细信息,请参阅 mng.bz/pdvG。以下工具目前受到支持:
-
Docker
-
Jib (
mng.bz/Oprn) -
Bazel (
mng.bz/Y64N) -
Buildpacks (
mng.bz/GRAq)
您还可以使用与 Skaffold 定义的规范一致的定制脚本。
在 CI/CD 管道中使用 Skaffold
您还可以将 Skaffold 作为 CI/CD 管道中的工具使用。现有的社区维护的构建器 (mng.bz/zmOa) 可以直接与 Cloud Build 一起使用,Cloud Build 是 Google Cloud 的原生 CI 工具(我们将在下一节中详细探讨它)。以下是一些在 CI/CD 工作流程中最有用的 Skaffold 命令:
-
skaffold build—构建和标记您的镜像(们)
-
skaffold deploy—部署给定的镜像(们)
-
skaffold delete—清理已部署的工件
-
skaffold render—构建和标记镜像,并输出模板化的 Kubernetes 清单
Skaffold 概述
在本节中,我们学习了如何安装 Skaffold 并将其用于持续开发工作流程。有关使用 Skaffold 与开发工作流程的更多信息,请参考 Skaffold 快速入门指南 skaffold.dev/docs/quickstart/。
12.3.3 云代码:使用本地 IDE 进行开发
我们已经学习了如何预览 Anthos 应用程序,但现在让我们看看如何提升这一体验。迄今为止尚未解决的问题之一是维护开发环境的配置。开发者希望在他们的首选 IDE 中开发应用程序。Cloud Code 通过集成已知的工具集来提高开发者体验,提供应用程序的容器化和部署,包括以下内容:
-
kubectl
-
Skaffold
-
Google Cloud SDK (gcloud)
Cloud Code 是 Visual Studio Code (code.visualstudio.com/) 和 IntelliJ (www.jetbrains.com/idea/) 等 IDE 的插件。它与 minikube 和 Kubernetes 集群(包括 Anthos 集群)集成。它包含 Google Cloud 平台 API 探索器和 Kubernetes 对象探索器。您可以直接从 IDE 中查看您的 Kubernetes 资源,而无需运行任何 kubectl 命令。
图 12.7 和 12.8 展示了可以运行和调试 Anthos 应用程序(包括 Kubernetes 和 Cloud Run)的预构建应用程序模板集合。第一个图允许您生成部署简单应用程序所需的所有文件。第二个图自动检测源文件的变化,构建容器镜像,并将应用程序部署到所选的 Kubernetes 端点。所有这些任务都是由 Skaffold 部署的。
图 12.7 还显示了 Anthos/Kubernetes 应用程序的流程,这与 Skaffold 流程非常相似。不同之处在于,开发者使用 IDE 来执行这些步骤。

图 12.7 使用 Cloud Code 运行和调试 Kubernetes 应用程序
如图 12.8 所示,Cloud Code 通过基于 minikube 设置模拟器来帮助我们。它在本地上运行,并允许开发者运行和测试 Cloud Run 应用程序。还可以将应用程序部署到 GCP 管理的服务,如 Cloud Run 或 Cloud Run for Anthos。

图 12.8 使用 Cloud Code 运行和调试 Cloud Run 应用程序
对于这两种选项,您可以通过在代码中设置断点来调试在本地和远程端点运行的代码。在下一节中,您将开始使用 Cloud Code 开发我们的 Hello World Anthos 应用程序。
使用 Cloud Code 开始开发
您可以使用为 Kubernetes 和 Knative (Cloud Run) 应用程序预构建的模板来启动您应用程序的开发。这包括简单单服务应用程序和多种语言的复杂多服务应用程序。
让我们看看如何使用 Cloud Code 开始开发。这次我们将使用以下步骤在 Visual Studio Code 中工作一个示例 Python Hello World 应用程序:
-
首先从 Visual Studio Code 市场安装 Cloud Code。
-
打开 Visual Studio Code。
-
在主窗口底部蓝色栏中找到并点击</> Cloud Code,如图 12.9 所示。
![12-09]()
图 12.9 Visual Studio Code:启动新应用程序
-
从屏幕顶部的下拉列表中选择“新建应用程序”选项,如图 12.10. 注意:这也是以下其他操作的起点:
-
在 Kubernetes 上运行应用程序
-
在 Kubernetes 上调试应用程序
-
在 Cloud Run 模拟器上运行应用程序
-
在 Cloud Run 模拟器上调试应用程序
-
将应用程序部署到 Cloud Run
![12-10]()
图 12.10 Cloud Code 新应用程序
-
-
现在选择 Kubernetes 应用程序,如图 12.11 所示。
![12-11]()
图 12.11 Cloud Code Kubernetes 应用程序
-
为了简单起见,我们将使用如图 12.12 所示的 Python (Flask) Hello World 应用程序。
![12-12]()
图 12.12 Cloud Code Python (Flask):Hello World
-
等待几秒钟,让 Cloud Code 拉取所有文件模板,包括 vscode 配置文件、Kubernetes 清单、源代码和 Skaffold 配置文件,如图 12.13 所示。
![12-13]()
图 12.13 Cloud Code skaffold.yaml
-
当所有文件准备就绪后,您可以通过再次点击Cloud Code并从下拉菜单中选择在 Kubernetes 上运行来运行应用程序,如图 12.14 所示。
![12-14]()
图 12.14 Cloud Code 在 Kubernetes 上运行的选项
-
Cloud Code 会询问您是否想使用默认上下文。在这种情况下,它指向 minikube。通过“是”确认或选择不同的上下文以部署到不同的集群,如图 12.15 所示。
![12-15]()
图 12.15 云代码:将上下文设置为 minikube
-
在控制台中,您应该看到图 12.16 所示的输出,包括访问应用程序的 URL。
![12-16]()
图 12.16 云代码控制台输出
-
如果您访问 URL,您将看到应用程序正在运行,如图 12.17 所示。
![12-17]()
图 12.17 Cloud Code 应用程序输出
-
现在您可以对源代码进行一些小的修改。在 app.py 文件中,找到图 12.18 所示的“Hello World”消息。
![12-18]()
图 12.18 云代码:浏览 app.yaml。
-
将消息更改为“Hello Anthos”并保存文件,如图 12.19 所示。
![12-19]()
图 12.19 云代码:将消息更改为“Hello Anthos。”
-
您会注意到,如图 12.20 所示,Cloud Code 已检测到更改并将应用程序部署到 minikube。
![12-20]()
图 12.20 Cloud Code:代码更改检测
-
现在我们访问应用程序时,会看到一个新消息,如图 12.21 所示。
![12-21]()
图 12.21 云代码:应用程序输出
任何对源代码的更改都将自动检测。请注意,您可以使用屏幕顶部的控制栏暂停或停止应用程序,如图 12.22 所示。

图 12.22 Cloud Code:持续开发菜单
您已成功创建了 Kubernetes Hello World 应用程序的预览。现在您可以尝试更复杂的应用程序示例。
如您在步骤 4 中的下拉菜单中看到的,您还可以创建和部署应用程序到 Cloud Run。您还可以通过在源代码中设置断点来调试您的应用程序。遵循如何指南,查看如何一步步操作的详细教程,请访问mng.bz/0yex。
Cloud Code 总结
Cloud Code 是一个工具,它不仅无缝集成到 GCP,还使您的 Anthos 应用程序的开发、容器化和预览变得简单。它将之前讨论过的 Skaffold 功能捆绑到您的 IDE 中,以自动化持续开发工作流程。
预览 Kubernetes 应用程序需要执行多个步骤,例如每次您对代码进行更改时,都需要构建容器镜像并将其部署到预览环境。使用 Cloud Code,您可以专注于源代码,让 Cloud Code 集成处理所有这些步骤。在本节中,我们使用了现有的模板来展示设置的样子。您可以从那里开始开发自己的 Anthos 应用程序,Cloud Code 将确保预览为您更新。
12.3.4 Anthos 开发者沙盒:使用云原生 IDE 进行开发
Anthos 开发者沙盒是开发者免费工具,让您体验在 Anthos 上开发的感觉。它允许执行上一节中描述的相同任务,但使用 Google Cloud Shell 而不是本地。它由以下组件组成:
-
云壳 —一个预装了 Google Cloud Platform 最佳工具的计算环境
-
云代码—我们之前见过的 IDE 插件
-
Minikube—一个单节点 Kubernetes 集群,我们之前已经讨论过
-
云构建本地构建器—在云壳中本地运行持续集成
您不需要进行任何前置配置即可使用 Anthos 开发者沙盒。您可以通过mng.bz/KlrK访问它并开始开发您的第一个 Anthos 应用程序。最重要的是,它对任何拥有 Google 账户的人免费提供。使用 Anthos 开发者沙盒,您可以执行以下日常开发任务:
-
在模拟的 Anthos 集群或 Cloud Run 模拟器上本地运行应用程序
-
使用云构建进行本地测试
-
在开发过程中迭代您的应用程序,并自动进行实时更新
-
使用构建包创建您的镜像
如果您刚开始开发 Anthos 应用程序,使用沙盒可以帮助您启动开发之旅,因为它提供了可以直接从界面访问的教程。
从 Anthos 开发者沙盒开始
让我们快速查看该工具的下一步操作:
-
通过在浏览器中打开我们之前提到的链接来访问工具。您将被告知 Anthos 开发者沙盒将被克隆,如图 12.23 所示。
![12-23]()
图 12.23 Anthos 开发者沙盒:欢迎屏幕
-
点击确认并等待环境设置完成。您可以看到为您配置的所有组件,如图 12.24 所示。
![12-24]()
图 12.24 Anthos 开发者沙盒:环境准备
-
一旦完成,您应该会看到 IDE 已加载,工作区已准备好,并克隆了仓库,如图 12.25 所示。在右侧面板中,您可以查看教程。
![12-25]()
图 12.25 Anthos 开发者沙盒:主屏幕
-
点击“开始”以开始教程。它将引导您完成与 Cloud Code 相同的流程。
正如您所看到的,您只需点击几下即可在 Anthos 上开始持续开发,无需特殊配置。
12.4 持续集成
在本节中,我们将探讨持续集成。我们将首先介绍 GCP 原生工具,然后查看第三方替代方案。为了为您的 Anthos 应用程序引入持续集成,您需要以下组件:
-
Git 源代码仓库
-
容器注册库
-
CI 服务器
首先,让我们创建一个 Git 仓库,用于存储和版本控制 Anthos 应用程序代码。
12.4.1 Cloud Source Repositories
Cloud Source Repositories (cloud.google.com/source-repositories) 是功能齐全的私有 Git 仓库,托管在 Google Cloud 上。该服务帮助开发者私下托管、跟踪和管理 Google Cloud Platform 上大型代码库的更改。它旨在轻松集成 GCP 服务,如 Anthos、GKE、Cloud Run、App Engine 和 Cloud Functions,如图 12.26 所示。您可以配置无限数量的仓库,还可以镜像 Bitbucket 和 GitHub 仓库。Cloud Source Repositories 中的更改会受到监控,并可以触发事件通知到 Cloud Pub/Sub 或 Cloud Function。Code Source Repositories 的一个不同之处在于,您可以使用正则表达式在您的仓库中搜索短语 (mng.bz/91jl)。Cloud Source Repository 的审计日志可在 Cloud Operations 中查看,因此您始终知道谁访问了您的仓库,以及何时访问。

图 12.26 Cloud Source Repositories 集成
如您在图 12.26 中所见,Cloud Run 的集成特别有趣。您可以使用 Cloud Source Repositories 和 Cloud Build 的组合来创建 CD 流水线,以便在您的代码仓库中发生代码合并时自动触发应用程序的部署流水线。Cloud Run 通过在幕后处理您的流量整形(蓝绿、金丝雀、滚动更新)来使操作更加流畅。有关如何配置的详细信息,请参阅第九章。
创建仓库
要开始使用 Cloud Source Repositories,您首先需要通过运行以下命令来创建仓库:
gcloud init
下一个片段将初始化您的 gcloud 命令行工具:
gcloud source repos create [REPO_NAME]
这将创建一个名为 REPO_NAME 的仓库。
现在仓库已经准备好使用,您需要选择以下三种认证方法之一:
-
SSH
-
Cloud SDK
-
手动生成的凭证
有关如何操作的逐步指南,请参阅以下链接:mng.bz/jmWx。
一旦设置好存储库并成功认证,您就可以使用 git clone、git pull 和 git push 等 Git 命令与之交互。
12.4.2 艺术品注册库
艺术品注册库是 Google 容器注册库服务的下一代迭代。除了能够存储容器镜像之外,艺术品注册库还可以存储其他包,如 Maven (maven.apache.org/)、npm (www.npmjs.com/) 和 Python,未来还将提供更多功能。这些服务完全集成在 Google Cloud Platform 生态系统之中,因此您可以使用 IAM 策略控制对您的艺术品的访问,访问 Cloud Source Repositories,使用 Cloud Build 触发自动构建,并将应用程序部署到 Google Kubernetes Engine、App Engine 和 Cloud Functions。您可以在离您的作业负载最近的地域创建艺术品存储库,以便利用高速的 Google 网络来拉取您的艺术品。
从安全角度来看,您可以扫描容器以查找漏洞,并可以使用二进制授权来批准可以推送到生产的镜像。您可以使用原生工具与艺术品注册库交互,因此它们很容易集成到 CI/CD 管道中。
使用 Docker 与艺术品注册库
让我们看看您如何使用以下程序与艺术品注册库交互以存储容器镜像:
-
首先创建一个艺术品存储库:
gcloud artifacts repositories create quickstart-docker-repo --repository-format=docker \ --location=us-central1 [--description="Docker repository"] -
您可以通过运行以下命令列出您的存储库:
gcloud artifacts repositories list -
在推送镜像之前,您应该对存储库进行认证:
gcloud auth configure-docker us-central1-docker.pkg.dev -
现在,出于演示目的,只需从 Docker Hub 拉取官方的 alpine 镜像,而不是构建一个新的镜像:
docker pull alpine -
使用存储库名称标记镜像:
docker tag alpine us-central1-docker.pkg.dev/PROJECT/quickstart-docker-repo/quickstart-image:tag1 -
您最终可以将镜像推送到艺术品注册库:
docker push us-central1-docker.pkg.dev/PROJECT/quickstart-docker-repo/quickstart-image:tag1
现在,您已经准备好从注册库中拉取您的容器镜像。
艺术品注册库总结
在撰写本文时,艺术品注册库已普遍可用,尽管一些功能可能处于预览状态。作为容器注册库的后继者,它最终将成为 GCP 中唯一的容器注册库,因此您所有的新项目都应该已经使用艺术品注册库。有关如何将现有项目过渡到艺术品注册库的逐步教程,请在此处找到:mng.bz/WAn0。
12.4.3 Cloud Build
我们已经看到如何对 Anthos 应用程序代码进行版本控制和构建容器镜像。现在让我们看看如何创建 CI 管道。
Cloud Build 是一个托管、GCP 原生的 CI/CD 平台,是 GitLab CI/CD、Jenkins 或 CircleCI 等工具的替代品。它允许您在包括 Anthos GKE 和 Cloud Run for Anthos 在内的所有 Google 计算服务上部署、测试和构建您的应用程序。Cloud Build 的管道步骤作为容器运行,如图 12.27 所示。

图 12.27 Cloud Build 步骤作为容器运行。
管道步骤在下面提供的简单易懂的 cloudbuild.yaml 文件中定义。这些步骤由 Cloud Build 读取并执行。每个步骤定义了一个作为任务运行的容器。管道中使用的容器是专门为 Cloud Build 构建的,被称为 云构建器。我们将在下一节中了解更多关于它们的信息。
# cloudbuild.yaml
steps:
# This step runs the unit tests on the app
- name: 'python:3.7-slim'
id: Test
...
# This step builds the container image.
- name: 'gcr.io/cloud-builders/docker'
id: Build
...
# This step pushes the image to a container registry
- name: 'gcr.io/cloud-builders/docker'
id: Push
...
# This step deploys the new version of our container image
- name: 'gcr.io/cloud-builders/kubectl'
id: Deploy
Cloud Build 完全无服务器,可以根据负载进行扩展和缩减。您只需为执行时间付费。它不需要您安装任何插件,并且可以支持各种工具,包括自定义云构建器。因为它连接到 GCP 网络,可以通过直接访问存储库、注册库和工作负载来显著减少构建和部署时间。您还可以将 Cloud Build 与 Spinnaker (spinnaker.io/) 等工具结合使用,以执行更复杂的管道,包括各种部署场景。Cloud Build 管道可以通过手动或通过代码存储库的拉取请求来触发。
现在我们已经了解了 Cloud Build 的工作基础,让我们来看看云构建器。
Cloud 构建器
正如我们已经学到的,Cloud Build 在容器中运行一系列在 cloudbuild.yaml 文件中定义的步骤,这些步骤在容器内执行。这些容器使用每个步骤名称属性中定义的容器镜像进行部署。这些容器镜像被称为云构建器,它们是特别打包的镜像,运行特定的工具,如 Docker、Git 或 kubect,并附带一系列用户定义的属性。以下列出了三种类型的构建器:
-
Google 支持的构建器
-
社区支持的构建器
-
自定义开发的构建器
让我们看看每种类型。
Google 支持的构建器
您可以在 GitHub 上找到完整的 Google 支持的构建器列表,网址为 mng.bz/819P。所有镜像都可在 gcr.io/cloud-builders/ <构建器名称> 下的容器注册库中找到。以下是在 Anthos 上下文中一些最重要的构建器:
-
docker
-
git
-
gcloud
-
gke-deploy
-
kubectl
社区支持的构建器
如果没有官方构建器符合您的需求,您可以使用社区构建器之一,这些构建器与 Helm、Packer、Skaffold、Terraform 和 Vault 等工具一起提供。社区云构建器的完整列表可以在此找到:mng.bz/ElrJ。
自定义开发的构建器
您可以创建自己的自定义构建器以用于构建。自定义构建器是 Cloud Build 拉取并运行与您的源代码一起的容器镜像。您的自定义构建器可以在容器内执行任何脚本或二进制文件。因此,它可以做任何容器能做的事情。有关创建自定义构建器的说明,请参阅 mng.bz/NmrD。
构建容器镜像
您可以使用 Cloud Build 通过配置文件或仅使用 Dockerfile 来构建容器。让我们看看每个选项。
使用配置文件构建容器镜像
构建容器的第一种方法需要您提供 cloudbuild.yaml 配置文件作为输入,如图 12.28 所示。

图 12.28 使用 Cloud Build 配置文件构建容器镜像
要从配置文件构建您的镜像,您需要使用以下方式在 cloudbuild.yaml 文件中指定构建步骤,使用 Docker cloud builder:
steps:
- name: ‘gcr.io/cloud-builders/docker’
args: [ ‘build’, ‘-t’, ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}’, ‘.’ ]
images:
- ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}’
接下来,运行以下命令提交构建:
gcloud builds submit --config [CONFIG_FILE_PATH] [SOURCE_DIRECTORY]
这将构建镜像并将其存储在 Google Artifact Registry 中,如配置文件中所示。如果您没有指定[CONFIG_FILE_PATH]和[SOURCE_DIRECTORY]参数,将使用当前目录。
使用 Dockerfile 构建容器镜像
您可以不使用配置文件创建容器镜像,因为您的 Dockerfile 包含使用 Cloud Build 构建 Docker 镜像所需的所有信息,如图 12.29 所示。

图 12.29 从 Dockerfile 构建镜像
使用您的 Dockerfile 运行构建请求,请从包含您的应用程序代码、Dockerfile 以及任何其他资源的目录中运行以下命令:
gcloud builds submit --tag us-central1-docker.pkg.dev//[PROJECT_ID]/[IMAGE_NAME]
这将构建镜像并将其存储在 Google Artifact Registry 中。
Cloud Build 通知
您有多种方式从 Cloud Build 获取通知。您可以收到有关构建状态任何变化的提醒,包括构建的开始、转换和完成。
Cloud Build 与 Pub/Sub 集成良好,并将消息发布到 Pub/Sub 主题。支持推送和拉取订阅模型。在 Pub/Sub 队列中有消息为您提供了将通知发送到下一步的无限选项。
除了 Pub/Sub 之外,您还可以通过以下通知通道之一从 Cloud Build 获取通知:
-
Slack—将通知发布到 Slack 频道
-
SMTP —通过 SMTP 协议发送通知
-
HTTP —以 JSON 格式向 HTTP 端点发送通知
所有三种类型的通知都使用作为 Cloud Run 服务运行的容器。如何创建此类通知的示例可以在mng.bz/DZrE找到。
部署到 Anthos Google Kubernetes Engine
使用 kubectl 或 gke-deploy 构建器将部署到 Google Kubernetes Engine 可以完成。请注意,gke-deploy(github.com/GoogleCloudPlatform/cloud-builders/tree/master/gke-deploy)基本上是 kubectl 的一个包装器,它结合了 Google 的最佳实践来部署 Kubernetes 资源。例如,它将标签 app.kubernetes.io/name 添加到部署的 Kubernetes 资源中。
接下来,您可以看到使用 gke-deploy 构建器部署到 GKE 集群的示例:
steps:
...
# deploy container image to GKE
- name: "gcr.io/cloud-builders/gke-deploy"
args:
- run
- --filename=[kubernetes-config-file]
- --location=[location]
- --cluster=[cluster]
在未来,我们可以期待其他云构建器,如 AnthosCLI,这将使体验更加统一。
部署到 Cloud Run 和 Cloud Run for Anthos
Cloud Build 允许您构建 Cloud Run 容器镜像,然后将其部署到 Cloud Run 或 Cloud Run for Anthos。在两种情况下,您首先使用标准的 Docker 构建器构建和推送镜像:
steps:
# Build the container image
- name: ‘gcr.io/cloud-builders/docker’
args: [‘build’, ‘-t’, ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_IMAGE}’, ‘.’]
# Push the container image to a registry
- name: ‘gcr.io/cloud-builders/docker’
args: [‘push’, ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_IMAGE}’]
然后使用 cloud-sdk 构建器运行 gcloud run 命令。对于 Cloud Run,将 --platform 标志设置为 ‘managed’:
# Deploy container image to Cloud Run
- name: ‘gcr.io/google.com/cloudsdktool/cloud-sdk’
entrypoint: gcloud
args: [‘run’, ‘deploy’, ‘SERVICE-NAME’, ‘--image’, ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_IMAGE}’, ‘--region’, ‘REGION’, ‘--platform’, ‘managed’]
images:
- ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_IMAGE}’
对于 Cloud Run for Anthos,将 --platform 标志设置为 ‘gke’,并通过设置 --cluster 和 --cluster-location 标志来指定要部署到的集群:
# Deploy container image to Cloud Run on Anthos
- name: ‘gcr.io/google.com/cloudsdktool/cloud-sdk’
entrypoint: gcloud
args: [‘run’, ‘deploy’, ‘SERVICE-NAME’, ‘--image’, ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_IMAGE}’, ‘--cluster’, ‘CLUSTER’, ‘--cluster-location’, ‘CLUSTER_LOCATION’, ‘--platform’, ‘gke’]
images:
- ‘us-central1-docker.pkg.dev/$PROJECT_ID/${_IMAGE}’
使用 Cloud Build 和 Connect 网关将应用程序部署到 Anthos
如图 12.30 所示的 Connect 网关允许用户使用 Cloud Console 中的 Google Cloud 身份连接到 Google Cloud 外部的已注册集群。您不需要从 Cloud Build 直接连接到 Anthos 集群 API。Anthos Hub 作为在云构建器中运行的 kubectl 命令的代理。

图 12.30 Connect 网关
要配置 Connect 网关并连接您的 Anthos 集群,请按照 Google 文档中描述的步骤操作,文档链接为 mng.bz/lJ5y。
一旦配置了 Connect 网关并将 Anthos 服务器注册,请运行以下命令以检查它们是否在集群中可见:
gcloud container fleet memberships list
在这种情况下,我们看到已注册了两个集群——一个是运行在 VMware 上的 GKE,另一个是 GCP GKE 集群:
NAME EXTERNAL_ID
my-vmware-cluster 0192893d-ee0d-11e9-9c03-42010a8001c1
my-gke-cluster f0e2ea35-ee0c-11e9-be79-42010a8400c2
让我们定义以下步骤以部署 myapp.yaml 清单中定义的应用程序:
steps:
- name: ‘gcr.io/cloud-builders/gcloud’
entrypoint: /bin/sh
id: Deploy to Anthos cluster on VMware
args:
- ‘-c’
- |
set -x && \
export KUBECONFIG="$(pwd)/gateway-kubeconfig" && \
gcloud beta container fleet memberships get-credentials my-vmware-cluster && \
kubectl --kubeconfig gateway-kubeconfig apply -f myapp.yaml
如我们所见,在这种情况下,使用了网关 kubeconfig 而不是集群 kubeconfig 本身。请求将被发送到网关,然后网关将其转发到 my-vmware-cluster。这意味着在 GCP 之外部署您的 Anthos 集群不需要混合连接,如 Cloud VPN 或 Interconnect。
触发 Cloud Build
在上一节中,我们学习了如何将应用程序部署到任何 Anthos 集群。现在让我们看看如何通过使用 gcloud 命令(我们已经在上一节中查看过)或自动触发器来触发 Cloud Build 管道。使用 Cloud Build,您可以使用以下三种类型的存储库:
-
Cloud Source Repositories
-
GitHub
-
Bitbucket
要创建触发器,您可以使用 Google Cloud Console 和命令行。首先,将存储库添加到 Cloud Build:
gcloud beta builds triggers create cloud-source-repositories \
--repo=[REPO_NAME] \
--branch-pattern=".*" \
--build-config=[BUILD_CONFIG_FILE] \
然后,添加触发器:
gcloud beta builds triggers create github \
--repo-name=[REPO_NAME] \
--repo-owner=[REPO_OWNER] \
--branch-pattern=".*" \
--build-config=[BUILD_CONFIG_FILE] \
使用 --branch-pattern,您可以指定哪个分支将触发构建。在这种情况下,将触发所有分支。
如果您想了解如何从其他存储库创建触发器,请参阅 mng.bz/BlrJ 的文档。
Cloud Build 概述
虽然 Cloud Build 使用简单,但它可以提供端到端 CI/CD 体验,以交付您的 Anthos 应用程序,如图 12.31 所示。如果您想获得更多关于端到端管道的实践经验,我们鼓励您按照自己的节奏遵循教程:mng.bz/dJGQ。在这个教程中,您将开发一个支持以下内容的管道:
-
提交代码的测试
-
构建容器镜像
-
将镜像推送到注册表
-
更新 Kubernetes 清单并将其推送到环境仓库
-
检测分支上的更改
-
将清单应用到 Anthos GKE 集群
-
将应用了 Kubernetes 清单的生产分支更新

图 12.31 基于 Cloud Build 的 CI/CD 管道步骤
这个教程将给您一个如何使用 Cloud Build 执行高级任务的清晰思路。请注意,您可以使用 GitHub、GitLab 或 Bitbucket 等第三方工具获得相同的结果,但 Cloud Build 是一个本地的 GCP 工具,它与 Anthos 集成得很好。
12.4.4 使用 Kustomize 生成特定环境的配置
在现实场景中,您将应用程序部署到多个环境中。在 CI/CD 管道中,您需要一个工具来调整应用程序的配置,以便为每个环境进行配置,而无需更改实际的代码库。
Kustomize 是一个独立的工具,通过使用 kustomization.yaml 文件来自定义 Kubernetes 资源。好消息是,自从 Kubernetes 1.14 版本以来,Kustomize 已被合并到 kubectl 工具中,如图 12.32 所示。

图 12.32 自定义 Kubernetes 清单
正如我们在图 12.32 中看到的那样,基本清单被修补并应用到每个环境中。
图 12.33,我们看到以下三个文件位于同一个文件夹中:
-
部署定义—deployment.yaml
-
Kustomize 文件—kustomization.yaml
-
修补文件—patch.yaml,它定义了在 Deployment 中应更改哪些属性

图 12.33 使用 Kustomize 修补部署镜像
要执行自定义,运行以下命令:
kubectl apply -k <kustomization_directory>
因此,输出已更新 spec.template.containers.image 属性。
Kustomize 功能列表
Kustomize 包含了自定义您的 Kubernetes 部署所需的所有功能,包括以下内容,如图 12.34 所示:
-
生成资源(ConfigMaps 和 Secrets)
-
设置跨切面字段
-
组合和自定义资源

图 12.34 Kustomize 功能
让我们详细看看每一个。
组合
您可以使用 resources 属性来定义您想要自定义的资源定义。如果您在文件中不包含任何其他自定义功能,资源将简单地组合成一个定义。在以下示例中,我们将 deployment.yaml 和 service.yaml 定义组合在一起:
# kustomization.yaml
resources:
- deployment.yaml
- service.yaml
要运行自定义,执行以下命令:
kubectl kustomize ./
自定义
定制允许您使用以下方法使用特定值修补您的资源:
-
patchesStrategicMerge (
mng.bz/rdQX) -
patchesJson6902 (
mng.bz/Vpo5)
例如,您可以通过创建以下文件来修补 deployment.yaml 文件中定义的 my-deployment Deployment 的副本数:
# increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 3
# kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
然后运行以下代码:
kubectl kustomize ./
除了这个定制功能之外,您还可以通过定义 image 属性来更改 Deployment 中的容器镜像。
设置交叉字段
使用交叉字段,您可以为您 Kubernetes 资源设置以下属性:
-
namespace
-
namePrefix
-
nameSuffix
-
commonLabels
-
commonAnnotation
在下一个示例中,我们将 namespace 设置为 my-namespace,用于 deployment.yaml 定义。注意:您可以使用 resources 属性来定义您想要受影响的资源。
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: my-namespace
resources:
- deployment.yaml
生成资源
使用 Kustomize,您可以生成 ConfigMaps 和 Secrets 资源。正如我们已经学到的,它们用于向您的应用程序提供配置和凭证。您可以从文本或文件中生成对象。以下是一些支持的生成器:
-
configMapGenerator
-
secretGenerator
例如,要生成具有键值对的 ConfigMap,您可以使用以下文件:
# kustomization.yaml
configMapGenerator:
- name: example-configmap
literals:
- FOO=Bar
然后运行下一代码:
kubectl kustomize ./
使用变量
变量在您想要捕获一个资源的属性并将其传递给其他资源时非常有用。例如,您可能想使用服务名称将其传递给要执行的容器命令。请注意,目前这支持字符串类型。您可以在 mng.bz/xdEB 看到这个用法的示例。
基础和覆盖
现在我们已经很好地理解了 Kustomize 提供的功能,我们可以看看如何使用它们来为 CI/CD 管道中的不同环境准备 Kubernetes。Kustomize 包含了 bases 和 overlays 的概念。基础是一个包含 Kubernetes 资源定义和主要 kustomization.yaml 文件的根目录。它执行第一层定制。请注意,您也可以在 Git 仓库中设置您的基。覆盖是一个存储用于定制基础层中已定制的资源的 kustomization.yaml 的目录。您可以根据图 12.35 所示创建多个覆盖,以表示每个环境。

图 12.35 Kustomize 基础和覆盖
接下来,您可以看到一个示例文件结构,用于单个基础和三个覆盖,分别针对开发、测试和生产环境:
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── dev
│ ├── kustomization.yaml
│ └── patch.yaml
├── test
│ ├── kustomization.yaml
│ └── patch.yaml
└── prod
├── kustomization.yaml
└── patch.yaml
您可以使用这种文件结构来设置每个环境的不同副本数。例如,对于开发环境,可能不需要像测试环境那样消耗那么多资源,在测试环境中,您可能想运行性能测试。
Kustomize 概述
正如我们所见,Kustomize 可以是 CI/CD 管道中的一种强大工具,用于为每个环境生成和修补 Kubernetes 资源。如果您想了解更多关于如何使用 Kustomize 的信息,请查看 mng.bz/AlKW 上的 Kustomize 示例和 kubectl.docs.kubernetes.io/references/ 上的 API 参考。
12.5 使用 Cloud Deploy 进行持续部署
Cloud deploy 是一种完全托管的 CD 服务,允许您根据提升序列将应用程序交付到一系列定义的目标环境中。您应用程序的生命周期通过发布进行管理,并由交付管道控制。
12.5.1 Anthos CI/CD 中的 Cloud Deploy
Google Cloud Deploy 与我们已了解的 Google Cloud Platform 生态系统中的服务集成,如图 12.36 所示,以完成 GKE 和 Anthos 集群的端到端 CI/CD 解决方案。

图 12.36 Cloud Deploy CI/CD 生态系统
图 12.36 显示了 Google Cloud Deploy 界面和以下服务:
-
CI 工具——调用 Google Cloud Deploy API 或 CLI 创建发布。因此,大多数 CI 工具都受支持,包括 Cloud Build。
-
Cloud Build——用于渲染清单并将其部署到目标运行时。
-
Skaffold——由 Cloud Build 用于渲染和部署清单。因此,应用程序被部署。
-
Cloud Storage——存储渲染源和渲染清单。
-
Google Cloud 的操作套件——收集并存储 Cloud Deploy 服务的审计日志。
-
Pub/Sub——允许将 Cloud Deploy 消息发布到 Pub/Sub 主题。这可以用于与外部系统集成。
-
GKE 和 Anthos 集群——Google Cloud Deploy 使用 Skaffold 部署应用程序的目标运行时,通过 Cloud Build 部署到您的目标运行时。
既然我们已经了解了 Cloud Deploy 如何与其他 Anthos CI/CD 工具交互,让我们看看如何配置它以进行 Anthos 应用程序的 CD。
12.5.2 Anthos 的 Google Cloud Deploy 交付管道
Cloud Deploy 使用交付管道清单来定义提升序列,以描述部署到目标的目标顺序。目标在管道的定义中或单独的文件中描述。Skaffold 配置文件用于渲染和部署 Kubernetes 资源清单。图 12.37 定义了 Cloud Deploy 使用的组件和流程。

图 12.37 Cloud Deploy 工作流程
让我们看看配置与 Cloud Build 一起进行持续交付所需的操作序列,如下一组步骤所示。作为先决条件,我们应该已经为每个环境部署了三个 GKE/Anthos 集群,如图 12.38 所示:
-
第一步是定义包含进展(提升顺序)和可选的运行时目标的交付管道。在此示例中,我们将创建单独的目标文件,因此可以定义以下管道:
delivery-pipeline.yaml apiVersion: deploy.cloud.google.com/v1 kind: DeliveryPipeline metadata: name: web-app description: web-app delivery pipeline serialPipeline: stages: - targetId: test - targetId: staging - targetId: prod -
目标可以定义为单独的文件。您可以针对每个目标定义一个单独的文件,最终将得到以下三个文件:
-
target_test.yaml
-
target_staging.yaml
-
target_prod.yaml
![12-38]()
图 12.38 目标 GKE/Anthos 集群
在每个文件中,您定义目标名称和目标集群。这里您可以看到一个测试目标的示例:
target-test.yaml apiVersion: deploy.cloud.google.com/v1 kind: Target metadata: name: test description: test cluster gke: cluster: projects/${PROJECT_ID}/locations/${REGION}/clusters/test -
-
在下一步中,您定义用于渲染和部署应用程序清单所需的 Skaffold 配置文件。在此阶段,您应该已经有一个要部署的容器镜像和一个标识容器镜像的 Kubernetes 清单——这些应该在您的 CI 流程中生成。有关如何使用 Skaffold 与 Cloud Deploy 的更多信息,请参阅第 12.3.2 节,“使用 Skaffold 进行持续开发。”
您的 Skaffold 配置可能如下所示:
skaffold.yaml apiVersion: skaffold/v2beta29 kind: Config build: artifacts: - image: example-image context: example-app googleCloudBuild: projectId: ${PROJECT_ID} deploy: kubectl: manifests: - kubernetes/* portForward: - resourceType: deployment resourceName: example-app port: 8080 localPort: 9000 -
接下来,通过运行以下命令注册管道和目标:
gcloud deploy apply --file=delivery-pipeline.yaml --region=us-central1 && \ gcloud deploy apply --file=target_test.yaml --region=us-central1 && \ gcloud deploy apply --file=target_staging.yaml --region=us-central1 && \ gcloud deploy apply --file=target_prod.yaml --region=us-central1现在 Cloud Deploy 已了解您的应用程序,并将根据您定义的提升顺序管理部署到目标。
-
现在,您可以通过从命令行或从 CI 工具创建发布来启动交付管道。Google Cloud Deploy 创建一个部署资源,该资源将发布与第一个目标环境相关联。基于该部署,您的应用程序被部署到第一个目标。从包含您的 Skaffold 配置的目录运行以下命令:
gcloud deploy releases create RELEASE_NAME --delivery-pipeline=PIPELINE_NAME -
如果您想使用 Cloud Build 作为 CI 工具,以下 YAML 文件显示了 Cloud Build 配置的示例,其中包含调用 Google Cloud Deploy 创建发布的功能,发布名称基于日期和用于构建的 Skaffold:
- name: gcr.io/k8s-skaffold/skaffold args: - skaffold - build - ‘--interactive=false’ - ‘--file-output=/workspace/artifacts.json’ - name: gcr.io/google.com/cloudsdktool/cloud-sdk entrypoint: gcloud args: "deploy", "releases", "create", "rel-${SHORT_SHA}", "--delivery-pipeline", "PIPELINE_NAME", "--region", "us-central1", "--annotations", "commitId=${REVISION_ID}", "--build-artifacts", "/workspace/artifacts.json" -
一旦您准备好将应用程序部署到序列中的下一个目标,您就可以提升它。调用 Google Cloud Deploy 并创建一个新的部署:
gcloud deploy releases promote --release=RELEASE_NAME --delivery-pipeline=PIPELINE_NAME -
您可以将提升继续到最后一个环境。在图 12.39 中显示的示例序列中,它是生产环境。
![12-39 图 12.39 提升顺序 1. 如果您想在进展过程中引入批准,您可以在目标定义中这样做。例如,我们可能希望批准图 12.40 中显示的测试到预发布和生产的所有提升。
![12-40]()
图 12.40 手动批准
您可以在每个目标定义中定义批准,如下所示:
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name:
annotations:
labels:
description:
requireApproval: true
gke:
cluster: projects/[project_name]/locations/[location]/clusters/[cluster_name]
参数 requireApproval: true 表示是否需要手动批准提升到该目标。其值可以是 true 或 false,且为可选值;默认为 false。
现在,您可以选择批准或拒绝部署。要批准部署,请运行以下命令:
gcloud deploy rollouts approve rollout-name --delivery-pipeline=pipeline-name
或者通过运行以下命令来拒绝审批:
gcloud deploy rollouts reject rollout-name --delivery-pipeline=pipeline-name
如您所见,这为您提供了对应用程序发布的完全控制。
云部署概述
在本节中,我们学习了如何使用云部署进行应用程序的持续交付。它包含许多重要功能,如审批、日志记录和与第三方工具的集成,使其成为企业级解决方案。它无缝集成到 Anthos 的端到端 CI/CD 管道中。要了解更多关于云部署的信息,请参阅cloud.google.com/deploy。
如果您想亲身体验云构建,我们鼓励您查看包含更多功能和集成的示例教程:mng.bz/ZoKZ。
12.6 现代 CI/CD 平台
现代 CI/CD 平台必须允许可持续地开发和运营整个应用程序交付管道。实现这一目标没有单一的方法,它始终依赖于应用程序和组织的具体情况。所有这些平台在解决以下三个关键层时都应遵循相同的模式,如图 12.41 和图 12.42 所示:
-
基础设施—用于托管
-
平台—由开发者用于创建、维护和消费持续集成能力
-
应用程序—面向最终用户的消费层

图 12.41 CI/CD 平台层
每一层至少由以下三种类型的角色负责:
-
开发者—主要关注应用程序开发、自动化测试和发布
-
操作员—专注于确保应用程序、底层平台和基础设施正常运行,以提供约定的性能和可用性指标
-
安全官—确保无论环境类型、结构或层,都应用了约定的政策和安全标准
根据组织不同,可能存在更多角色。每个角色不仅必须拥有不同的职责和角色,以及不同的约束和限制,而且它们还必须在整个团队中共享相同的方法,这导致了对交付的共同责任,如图 12.42 所示。

图 12.42 角色与代码仓库对比
Anthos 引入了集中管理和统一工具集的能力,同时保持将外部工具集成到管道中的灵活性。现代 CI/CD 平台的目标是支持企业级和安全的 GitOps 实现。这意味着每个组件都必须描述为一组配置文件和定义,这些文件和定义存储在版本控制系统内。每个集合由一个单独的团队管理和维护。已经提到,现代 CI/CD 平台依赖于共享责任。在这样的模型中,所有各方都通过公共接口(如代码仓库、镜像构建和 Kubernetes 清单定义阶段)进行接触。
现代应用交付依赖于 Kubernetes 调度程序和基于微服务的架构。在这种情况下,开发者和操作者游乐场之间必须有分离。实施取决于定义的需求。我们可以使用单个集群和多个命名空间来设置单站点或非生产环境。如果我们交付的服务必须具有高可用性或在全球范围内提供高延迟,或者我们必须限制基础设施生命周期活动的影响,请考虑使用多个 Anthos 集群。多集群设置允许我们在完全发布之前以小步骤向各个集群推出应用程序。
让我们定义一个示例应用程序:一个简单的基于微服务的投票系统,能够可视化投票结果,如图 12.43 所示。

图 12.43 应用架构
基础设施底层使用 GCP 上的 Anthos GKE 集群。创建了三个命名空间,每个服务一个:
-
投票
-
转移
-
结果
它还使用了以下三个 Google 管理的服务:
-
云 Memorystore 作为托管的 Redis
-
Cloud SQL 作为所有作为托管 Postgres 提供的投票的中心数据库
-
Secret Manager 作为安全的密钥管理系统,用于存储 Memorystore 和 Cloud SQL 的凭证
开发者消费基础设施,并不关心它是如何交付的。它必须满足他们与命名空间和管理服务相关的需求。一个负责任的团队必须创建一个 CI/CD 管道,可用于应用程序托管目的,并具有完全的灵活性来测试任何更改。
为了实现这一目标,我们可以使用多种不同的工具。如果我们的团队熟悉 Terraform,我们可以利用已有的知识并将其集成到我们的 CI/CD 流程中。这种做法完全符合 DORA 的 DevOps 状态研究计划(www.devops-research.com/research.xhtml)。它定义了组织实施 DevOps 的关键成功因素之一:选择开发人员和运维人员使用的工具的自由。还有一个问题存在:我们能否以更简单的方式提供这样的基础设施?因为我们使用的是 GCP 管理的资源,而不是使用外部工具,我们可以利用 Anthos Config Connector 功能,将 Secret Manager、Cloud Memorystore 和 Cloud SQL 作为代码仓库中的声明性对象提供。
如果我们需要为其他来源提供服务,如 Anthos on-prem,那么从第一天开始以自动化的方式引入基础设施更改是很重要的,如图 12.44 所示。每个在 VMware 或裸金属上运行的 Anthos 都必须依赖于预定义的实践和安全策略,如果需要,可以不断重复使用。

图 12.44 基础设施资源
深入了解我们的现代平台基础设施,它必须提供以下元素以实现应用程序交付的成功:
-
高性能、高可用性和稳定的共享工具基础设施——它被用作 CI/CD、容器镜像以及应用程序和基础设施代码和配置的中心存储库。它可以扩展以支持公司要求的额外业务支持工具。
-
将预生产和多个生产环境通过一致的配置分开——一致的安全策略、RBAC 或网络配置可以提高测试质量和效率,降低错误率,并提高生产软件交付。
-
开发基础设施——用于广泛的单元测试,并赋予我们的开发者在其自己的命名空间中工作的自由。
这将我们引入目标 CI/CD 平台。平台选择的多维度性和必须由以下因素驱动是很重要的:
-
操作该平台的团队必须了解该平台。 平台已经被使用并不必要,但必须提供适当的培训,并且团队必须有时间熟悉它。
-
平台必须适应应用程序和基础设施交付模型所期望的状态。 这包括在企业中实施的操作模型和业务逻辑。
-
必须在所有层面上正确测量和监控应用程序的可用性和健康状况。 这意味着从基础设施开始,通过工具平台,最后在应用程序本身级别结束。
-
如介绍部分所述,平台必须为 DevOps 准备就绪。
在选择代码仓库时,考虑对你来说哪些功能是必需的。对于小规模的简单代码版本管理,Google Cloud Source Repository 可能足够。当需要额外的功能时,你必须考虑其他 Git 提供商。GitLab、GitHub 或 Bitbucket 的常见模式可能是要求将代码保留在本地数据中心,或者通过实施代码所有者来对 Git 中的特定文件夹引入责任。对于集成和部署工具,也必须做出类似的选择。受额外需求驱动,我们可能已经在本地上实施了 GitLab CI/CD。对于复杂的应用交付,你可以使用 Spinnaker 作为 CD 工具。基于 Anthos 的平台在该领域具有灵活性。我们可以使用 Google Cloud Platform 工具或轻松集成到外部工具,同时仍然从开箱即用的 Anthos 自动化和功能中受益,如图 12.45 所示。

图 12.45 软件资源
一旦我们的基础设施和 CI/CD 平台准备就绪,我们就可以为开发活动启用它们。我们定义了角色以及他们使用哪些接口来相互协作。让我们看看图 12.46 中展示的这种协作的端到端工作流程。

图 12.46 应用交付工作流程
一旦代码准备就绪,它必须被部署到类似生产环境,以确保新代码更新验证过程中的质量。如前所述,代码可以被推送到 Cloud Code 或任何其他 Git 仓库,在那里进行质量和健全性检查。当它通过时,你可以生成容器镜像并将它们推送到容器注册库。当镜像被操作员确认后,他们将这些最佳实践、应用程序和公司标准应用于它们,这些标准来自操作实践 Git 仓库。操作员使用 Kustomize 等工具定义管道,创建特定环境的仓库,这些仓库成为特定环境清单的真相来源。此外,因为所有环境都依赖于相同的应用程序和操作实践代码仓库,它们保证是一致的。因此,非生产环境尽可能接近生产环境。
我们已经提到了尽可能在开发生命周期中左移安全适应性的重要性。开发环境和生产环境之间的 Kubernetes 集群一致性在应用交付速度中起着重要作用。在第十三章中,我们将学习 Anthos Policy Controller 的工作原理,而在第十一章中,我们已经学习了 Anthos Config Management 如何帮助保持配置的一致性。我们可以将策略和基础设施控制器应用到我们的 CI/CD 管道最终版本中。类似于应用一致性,所有环境单一事实来源保证了安全措施的一致性,这使我们能够以现代声明式的方式合并基础设施和安全更改。
让我们回到我们的参考应用程序,看看之前的流程是如何应用到它上面的。在我们的案例中,我们可以有三个独立的开发生态。每个团队都生产一个单独的镜像,并将其交给负责端到端应用程序的操作员。Kubernetes 集群以专用命名空间的形式提供应用程序着陆区,如图 12.47 所示。这为我们提供了在资源、安全和连接级别上实现工作负载隔离的能力。

图 12.47 应用着陆区
摘要
-
现代应用交付 CI/CD 平台在现代企业应用交付过程中发挥着重要作用。
-
开发者可以专注于应用程序,这增加了开发团队的性能和效率。
-
同样适用于可以控制早期阶段应用程序交付的运营商,减轻日常任务,并最小化配置开销。
-
自动化管道统一了与应用程序和基础设施协同工作的方式。
-
安全团队成为集成和交付过程不可或缺的一部分。
-
现代 CI/CD 平台引入了统一工具。它们构建了所有相关方的知识、期望意识和工作方式。
-
统一的工具集提高了平台引入组织中的共享责任模型下的合作。
-
流程、运营模式、学习和沟通路径必须适应这一新模型。其好处包括减少变更的提前期、增加部署频率以及显著降低服务恢复时间。
^(1.)Jez Humble 和 David Farley,持续交付:通过构建、测试和部署自动化实现可靠的软件发布(Addison-Wesley Professional,2010)。
^(2.)结构测试是 Google 开发的一种容器测试机制;有关详细信息,请参阅 mng.bz/eJzz。
13 安全与策略
Scott Surovich
本章涵盖
-
Kubernetes 安全概述
-
Anthos 安全功能
-
理解根容器与特权容器
-
使用 ACM 保护集群
Google 已经使部署 Anthos 集群变得简单、自动化。由于过程是自动化的,管理员可能不会考虑初始简单集群创建之后的任务,如安全设置。当您在未考虑安装后任务(如安全)的情况下部署集群时,攻击者很可能只需付出很少的努力就能控制您的集群。
与许多产品的初始安装一样,一个新的 Kubernetes 集群可能包含很少或没有增强的安全设置。对于大多数企业系统,这种设置是设计如此。Kubernetes 设计者选择将安全作为一个集群安装后的过程,这个过程由组织设计和实施,而不是强迫组织采用一个可能不适合某些组织的严格安全模型。
在今天这个互联互通的世界里,似乎没有一天没有关于新的黑客攻击的新闻。勒索软件、僵尸网络、分布式拒绝服务攻击以及无数其他攻击正在成为组织与黑客之间每日的猫鼠游戏。无论您的集群位于本地还是远程,您都需要保护所有可能被利用的区域。对这些攻击缺乏充分的规划可能导致数据泄露、服务中断、罚款、品牌变更或收入损失。
在本章中,我们将讨论 Anthos 提供的用于保护您的 Kubernetes 集群的功能。例如,Anthos 配置管理(ACM)和 Anthos 服务网格(ASM)等工具提供了保护集群的功能,限制或阻止恶意行为者和诚实用户错误的影响。
例如,Kubernetes 的默认安装可能允许用户部署一个挂载主机卷、使用主机 PID 和主机网络、以 root 身份运行或以特权模式运行的容器。所有这些都可能引起不同的问题,但让我们看看其中最危险的一个:特权容器。特权容器允许用户将主机的根文件系统挂载到运行中的容器的挂载点上。一旦文件系统被挂载,用户就可以进入运行中的容器并浏览工作节点的整个文件系统。在挂载了主机文件系统的情况下,攻击者可以更进一步,重新挂载根文件系统,从而允许他们停止运行中的容器、启动新的恶意容器或破坏主机操作系统文件系统。
运行特权容器是一个常用的例子,说明了为什么您需要向集群添加额外的安全措施。尽管安全策略通常是集群创建的第一种策略类型,但您不能忘记其他可能影响集群和您服务的设置。为了保护集群,您需要了解攻击者可能采取的行动,这些行动不仅可能导致安全漏洞,还可能导致服务中断和数据丢失。
13.1 技术要求
本章的实践部分将要求您能够访问一个在 GCP 上运行的带有 ACM 和 Policy Controller 启用的 Google Kubernetes Engine 集群。
13.2 虚拟机管理程序与容器运行时对比
当一项新技术发布时,它通常在没有适当知识的情况下被部署,以安全地运行。这通常导致人们认为新技术不如更成熟的技术安全,例如容器与虚拟机相比。直到最近,人们普遍认为容器不如虚拟机安全,许多人指出,共享主机内核是主要的安全担忧。
这个共享内核为恶意行为者开辟了攻击途径,可能允许他们黑入一个不够安全的容器,并从那里突破到主机本身。如果攻击者从容器中突破出来,他们可能,潜在地,完全控制主机操作系统。这与在虚拟机管理程序上运行的虚拟机形成对比,在那里突破是不可能发生的。或者,可能吗?
在过去的几年里,不同的虚拟机管理程序都存在常见的漏洞和暴露(CVE),导致了不同程度的网络安全问题,包括特权提升,允许攻击者以管理员权限访问虚拟机管理程序。(有关 CVE 的更多信息,请参阅cve.mitre.org/。)一旦攻击者破坏了虚拟机管理程序,他们就会访问主机上的每个虚拟机,包括运行虚拟机的虚拟磁盘。
本节的目的不是引发关于容器安全与虚拟机安全之间的辩论。我们的目的是指出,没有系统是完全安全的,当像 Kubernetes 这样的系统在没有理解基本安全的情况下部署时,您和您的组织都会面临风险。
让我们来看看在集群被认为是“生产就绪”之前需要检查的一些常见的 Kubernetes 安全关注点。
13.3 Kubernetes 安全概述
一个基本的 Kubernetes 集群通常只启用有限的安全设置,如果没有的话,这使组织必须自行解决安全问题,如下所述:
-
配置任何基本 Kubernetes 安全功能
-
寻找附加产品来解决基本集群中未包含的任何缺失安全功能
-
对每个组件的安装和支持进行培训
-
扫描镜像以查找漏洞
-
启用网络安全以加密工作负载之间的流量
这些任务在某些组织中可能听起来并不是克服的大障碍。你可能已经了解了一些开源软件包,如 OPA(Open Policy Agent)或 Gatekeeper 这样的准入控制器,它们可以为集群增加安全性。一个组织可以决定使用开源项目发布版部署 Gatekeeper,但这样做将使他们需要内部处理支持或通过在 GitHub 仓库上提交 Gatekeeper 的问题来处理。准入控制器的问题可能会对集群产生有害影响,可能造成每个部署请求的障碍。在你成为准入控制器问题的接收者之前,你可能不会完全理解其影响,以及拥有一个支持联系人如何成为集群的救命稻草。
在整本书中,我们讨论了 Anthos 如何通过提供由完整 Google 支持的后备集群的附加组件,将 Kubernetes 集群提升到新的水平。正如你在第十一章所读到的,安全性是 Anthos 擅长的关键领域之一,其中你了解了一些 ACM 的功能,包括配置同步和 Config Connector。ACM 还可以用来配置 Kubernetes 安全的基础方面,包括角色和角色绑定,同时还通过包含 Gatekeeper 策略引擎提供额外的安全措施。
在深入探讨策略控制器及其可以实施的政策之前,让我们快速回顾一下作为基础 Kubernetes 安装的一部分提供的安全机制。
13.3.1 理解 Kubernetes 安全对象
作为集群管理员,你需要了解包含的安全选项以及它们如何解决或未解决你组织的网络安全策略。全面涵盖 Kubernetes 中包含的基础安全对象超出了本章的范围。它们在此处展示,以提供一个概述,你可以进一步使用提供的参考链接进行深入研究。以下是一些常用的安全对象:
-
网络策略—定义了控制服务入站和出站流量的条件 (
mng.bz/61vy) -
基于角色的访问控制 (RBAC)—通过用户和组成员资格提供对 Kubernetes 对象的细粒度访问 (
mng.bz/oJMM)
一种曾经常见的 Kubernetes 安全概念,Pod 安全策略(PSPs),在当前的 Kubernetes 版本中已被弃用。然而,策略控制器解决了 PSPs 之前提供的条件。
由于本章和本书旨在强调 Anthos 本身为您带来的 Kubernetes 体验优势,我们将不会涵盖 RBAC 策略或 NetworkPolicies,这些在之前提到的 kubernetes.io 页面上以及几本其他 Kubernetes 书籍中有更详细的解释。本章的目的不是提供关于保护 Kubernetes 集群和工作负载的详尽教程。相反,我们将专注于 Anthos 提供的额外工具,以简化、实施和监控针对常见安全问题的解决方案。我们将使用特定的漏洞来展示解决方案,但无论如何,这种覆盖都不是详尽的。
13.3.2 安全类型
保护任何数字服务必须包括几个攻击途径:物理的、内部的(无论是员工或承包商的恶意或意外)、外部的。此外,此类攻击的目的有多种形式。意图是窃取数据或代码、中断服务还是使系统成为人质?没有任何解决方案是 100%安全的——它需要可用的这一事实意味着它始终会以某种形式受到攻击。然而,作为一个行业,我们应该努力使我们的服务尽可能难以中断。
Kubernetes 背后的部分驱动力是降低部署功能性工作负载的障碍。这减少了运行集群本身的团队的支持开销,但代价是更多的人可以访问部署可能导致服务中断的工作负载和配置。因此,从集群安全的角度来看,我们需要实施具体政策以最大限度地减少漏洞被利用的可能性。尽管一些组织可以完全通过以人为本的政策来完成这项工作,但最佳的安全政策是那些执行机制是自动的,不依赖于人工干预的。
与任何计算抽象平台一样,Kubernetes 包含多个攻击途径,尤其是在默认配置下。其中一些始终以某种程度存在,以提供集群中工作负载的价值。例如,一个存储和检索数据库数据的中间件服务始终需要访问数据库服务器,从而在两个组件之间留下一个开口。
每个组织都应该减少其系统可能的攻击途径。然而,没有两个组织是完全相同的。因此,大多数 Kubernetes 版本都附带了一些故意不那么限制性的安全设置。Kubernetes 管理员的首要任务应该是应用一套更严格的安全政策,以符合其组织的指令和需求。我们无法为每个组织提供每个可能政策的详尽列表。¹ 然而,我们将介绍一些适用于大多数集群的基本政策。
特权容器和 root 用户
基于容器的编排系统的一个巨大优势是通过与底层容器共享系统内核(通常还包括文件系统的一部分)来减少资源使用;Kubernetes 也不例外。这些编排器,包括 Kubernetes,包括防止容器内进程直接访问主机机器资源的保护措施。然而,编排系统的某些组件可能需要以用户或 root 身份访问主机基础设施的特定部分。在容器内镜像构建器开发之前,这是在容器内干净环境中运行时构建镜像的常见方式。
在 Kubernetes 中,容器“突破”并向主机系统发出命令的能力是通过容器或 Pod 规范上的 privileged 标志来管理的。在主机系统上以单个用户身份运行命令在大多数情况下可能用途有限,除非容器以超级用户身份运行或假定了一个超级用户的身份。为了简单起见,许多公开可用的容器镜像内部以 root 用户身份运行,以避免容器内的权限问题。然而,如果 privileged 标志设置为 true,这将允许容器内的进程突破并作为超级用户影响主机系统。
为了防止容器以超级用户账户运行,必须采取两项安全措施:强制容器防止权限提升,并防止默认以 root 用户运行镜像。
以前,Kubernetes 包括 PodSecurityPolicy 对象类型来强制实施针对已部署 Pod 的具体策略。然而,从 Kubernetes 1.21 开始,PSPs 已被弃用,并在 1.25 版本中将以当前形式被移除。Kubernetes SIG 决定弃用 PSPs,原因有很多,包括以下这些:
-
由于策略的适用方式,故障排除策略存在困难。Pod 安全策略(PSPs)绑定到 Pod 的服务账户或提交请求的用户。
-
无法限制持久卷声明(PersistentVolumeClaims)的类型,这意味着用户可以使用 HostPath 创建持久卷声明。
-
关闭失败,这意味着如果未定义策略,操作将失败。由于这种行为,你无法在集群滚动推出时启用 PSPs——你需要在启用整个集群的 PSPs 之前创建所有策略。
即使在 PSPs 弃用之前,许多组织也由于上述限制而跳过了使用它们。相反,他们决定实施一个准入控制器,如 Gatekeeper(之前称为 OPA 或 Gatekeeper 1.0)。
为了确保集群的安全,你需要在降低风险之前考虑恶意行为者可能会尝试执行的操作。让我们讨论一些在新的集群上线前需要考虑的常见安全担忧。
13.4 常见安全担忧
Kubernetes API 和配置设计提供了大量的灵活性,以支持广泛的部署场景和应用。然而,大多数组织不需要,也不希望启用更安全的配置选项。默认允许的一些敏感字段包含在表 13.1 中。
表 13.1 可能导致安全事件的安全事件字段
| pod.spec fields |
|---|
| Field |
| hostPID |
| hostIPC |
| hostNetwork |
| pod.spec.containers.securityContext fields |
| Field |
| privileged |
| allowPrivilegeEscalation |
如果容器被设置为以 root 用户身份运行,并且 privileged 字段被设置为 true,则在 Kubernetes 中会出现一个漏洞。许多广泛分布的镜像使用 root 用户作为默认用户——开发人员和管理员可以,并且应该将其更改为使用非 root 用户。然而,仅仅以 root 用户身份运行并不给容器访问宿主系统的权限,因为容器守护进程将阻止访问。但是,如果用户可以将 privileged 字段设置为 true,那么以 root 用户身份运行的容器将能够访问宿主系统并做出或提取他们不应访问的更改或数据。为了防止这种情况发生,我们需要创建一个新的 Gatekeeper 策略实例。
这些字段仅代表可能被用来危害宿主机的一小部分项目。在本章的后面部分,我们将使用这些选项来演示攻击者如何使用它们来获得对集群中 Kubernetes 宿主机的完全访问权限。
攻击者并不总是想要接管宿主机系统。他们可能只是满足于破坏服务并造成一般混乱。不幸的是,这种类型的事件也可能由一个可能没有完全了解系统的无辜用户触发,导致系统故障或降级。您的安全标准需要考虑所有可能导致服务中断的行动,这些行动可能来自外部实体,例如允许但恶意用户或善意用户的潜在误配置。
以下列表概述了一些经常被忽视的设置,如果不加以解决,可能会导致收入损失、罚款、服务中断或负面公司品牌后果:
-
Ingress 控制器 URL 重复
- 可能导致冲突的 Ingress 规则的服务中断
-
消耗一个节点所有资源的应用程序或命名空间
- 导致宿主机资源问题,影响宿主机上的所有应用程序
-
未从已批准的注册表中拉取的恶意容器镜像
- 可能导致恶意软件或勒索软件
-
一个使用“*”的 Istio 策略
- 导致所有 Istio 服务的服务中断
-
集群中 Pod 之间的未加密流量
- 可能导致数据泄露
这只是一个需要考虑以增加集群的安全性和可用性的常见问题列表。如果你必须考虑可能影响 Kubernetes 应用程序的每个场景,创建解决每个任务的策略可能需要数月时间,而且它们可能不会涵盖你没有想到的场景。过于频繁的是,你只有在事件发生后才会了解到你没有考虑到的动作。
Anthos 包括提供配置管理和增强安全性的产品,这些产品包括社区和 Google 开发的一系列策略。但在深入了解 Anthos 的安全性和策略功能之前,让我们回顾一下通用的容器安全性,以便我们能够理解 Anthos 提供的工具的需求。
13.4.1 理解策略控制器
ACM 策略控制器为集群提供了一个准入控制器。准入控制器是一个组件,它验证或修改发送到 Kubernetes API 服务器的请求,在允许或拒绝请求之前执行控制器的逻辑。
当你启用策略引擎时,会创建一个 ValidatingWebHook 配置,该配置将引擎注册为 API 服务器的准入控制器。一旦注册,API 服务器将发送对象请求到准入控制器进行评估,如图 13.1 所示。

图 13.1 准入控制器策略验证流程
在图 13.1 所示的流程中,API 服务器收到了创建新 Pod 的请求。由于集群已安装 ACM 并启用了策略控制器,请求被发送到 Gatekeeper 服务。然后该服务将请求转发到 Gatekeeper Pod,该 Pod 检查配置的策略是否存在违规。
在这一点上,你可能想知道一旦部署了 Gatekeeper,集群可能会体验到什么样的延迟或性能影响。平均而言,策略评估大约需要一毫秒,即使评估较大的策略也是如此。像任何允许你创建自己的对象的系统一样,你可以创建一个会影响策略引擎性能的策略,从而导致整体系统延迟。创建策略超出了本章的范围。如果你想了解更多关于策略和性能的信息,你可以在 Open Policy Agent 网站上找到更多详细信息,网址为mng.bz/v1GM。
在图 13.1 所示的示例中,发现了一个拒绝请求的策略,导致准入控制器将拒绝信息发送到 API 服务器。由于准入控制器返回了拒绝,API 服务器将不会创建对象,并将使用策略引擎提供的错误更新对象的状况。
策略引擎是一个简单的评估系统,它检查请求并决定是否允许该请求。策略引擎有一个简单的流程,但其中的真正力量在于策略本身,它为决策过程提供逻辑。在 ACM 中,我们使用约束模板和约束在我们的集群中实现安全策略。在下一节中,我们将解释约束模板是什么以及它们是如何通过创建约束在集群中实现的。
介绍门卫约束模板
将约束模板视为策略引擎用于做出决策的逻辑。当在集群上启用门卫时,它将创建一组默认策略,包含常见用例的规则。在撰写本文时,ACM 的策略控制器包括 32 个模板,包括以下这些:
-
允许的容器注册库
-
Istio 特定的策略
-
资源约束
-
提供类似于 PSPs 的安全性的替代方案
注意:您可以通过访问mng.bz/41oV找到每个模板的完整列表及其描述。
每个策略都是称为 ConstraintTemplate 的自定义资源类型。您可以通过执行 kubectl get constrainttemplates 来查看集群中的所有模板。简化的列表如图 13.2 所示。

图 13.2 约束模板列表
约束模板本身仅是策略的定义——用于评估的逻辑。在下一节中,我们将解释如何使用约束模板创建约束,从而在集群上启用所选策略。
启用策略
要启用策略的执行,您需要创建一个 YAML 文件,该文件定义了一个约束,当创建新对象时将对其进行评估。这是一个需要记住的关键行为:因为策略引擎是一个准入控制器,它仅在对象创建或被集群接受时评估对象。它不会对任何现有对象执行策略,直到它们被重新创建,但它会显示集群中正在运行的策略违规。这一点常常被初学者忽视,当您在集群中实施新策略时,这是一个需要记住的关键点。
之前我们解释了如何使用以特权容器启动的容器来损害主机,最终损害集群。由于这种潜在风险,您可能希望拒绝创建特权 Pod。由于这是一个常见用例,ACM 包括一个拒绝特权容器的模板。以下示例清单创建了一个名为 deny-privileged 的对象,使用自定义资源类型 K8sPSPPrivilegedContainer:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: deny-privileged
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
注意,在清单的 spec 部分中,我们定义了一个匹配参数。此参数定义了策略引擎将如何评估约束的对象。在示例中,策略将针对对象类型 pod 的所有 apiGroups 进行评估。这意味着每次收到 Pod 请求时,都会检查它是否试图以特权容器的形式启动。
你可能想知道为什么我们只匹配 Pod,而不是 Deployments 或 ReplicaSets。Pod 匹配将评估任何创建 Pod 的尝试,包括使用 Pod 类型的清单,或者当其他对象如 Deployment 试图创建 Pod 时。当 Deployment 被提交时,API 服务器将创建一个 Deployment 对象,它创建一个 ReplicaSet 对象,然后创建 Pod。无论 Pod 如何创建,它都将与策略进行核对。
默认情况下,一旦创建了一个约束,它将对匹配列表中定义的每个对象生效。这包括 Anthos 系统命名空间,如 kube-system、gke-system 和 gke-connect。如果你在先前的示例中添加了约束,像 kube-proxy 和 Calico 或 Cilium 这样的 CNI Pod 将无法启动。如果 CNI Pod 被拒绝启动,集群节点将没有任何网络连接,导致所有 Pod 失败。由于约束具有集群级影响,你需要仔细规划和理解策略将如何影响整个集群,包括现有对象。
可能看起来策略会影响每个命名空间,并且默认情况下,对于新策略来说确实是如此。幸运的是,ACM 允许你通过在 spec.match.excludedNamespaces 中添加包含命名空间的约束来排除命名空间,或者你可以根据此处记录的说明配置 Policy Controller 以具有 exemptableNamespaces:mng.bz/Q84j。
由于策略可能产生意外的后果,Anthos 策略管理器有一个选项允许你在不实际强制执行约束的情况下审计约束的结果。在下一个小节中,我们将讨论如何审计约束。
约束的审计
在强制执行新的约束之前,你应该在集群上测试它以避免任何意外结果。如前一小节所述,当你创建一个新的约束时,它将默认生效。你可以通过将 enforcementAction: dryrun 选项添加到约束清单中,将此默认行为从强制执行更改为审计。使用 psp-privileged-container 示例,我们可以添加 dryrun 选项来将默认的强制执行行为更改为审计,如下所示:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: psp-privileged-container
spec:
* enforcementAction: dryrun*
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
现在强制执行已更改为审计,任何违反约束的 Pod 都只会被记录为违规,但它仍然可以启动。此外,与默认强制执行行为不同,将约束设置为 dryrun 将评估不仅新请求,还包括所有正在运行的 Pod。这允许您验证约束对每个 Pod 的影响,而不仅仅是新请求,因此您将知道它将如何影响任何重新启动的 Pod。
一旦设置为 dryrun,您可以使用 kubectl get <约束类型> <约束名称> -o yaml 查看审计结果。以我们的示例,我们可以通过执行 kubectl get K8sPSPPrivilegedContainer psp-privileged-container -o yaml 来查看受影响的 Pod。根据违规的数量,您可能会收到一个受影响容器的长列表。以下是从默认集群中运行 Anthos 的简略列表:
violations:
- enforcementAction: dryrun
kind: Pod
*message: 'Privileged container is not allowed: cilium-agent, securityContext:*
*{"capabilities": {"add": ["NET_ADMIN", "SYS_MODULE"]}, "privileged": true}'*
name: anetd-4nldm
namespace: kube-system
- enforcementAction: dryrun
kind: Pod
*message: 'Privileged container is not allowed: kube-proxy, securityContext: {"privileged":*
*true}'*
name: kube-proxy-4z8qh
namespace: kube-system
输出显示,如果我们强制执行此策略,kube-proxy 和 Cilium Pod 将被拒绝启动。这构成了一个两难境地:我们希望拒绝运行特权容器,但我们需要特权容器来允许系统容器运行。某些容器违反会拒绝容器启动的策略并不罕见。由于这是一个常见的场景,策略引擎允许您免除命名空间被评估,无论是所有策略还是仅某些策略。
创建命名空间免除
一旦创建约束,它将影响每个启动的容器,而不考虑正在启动的 Pod 的类型。许多常见的系统容器,如网络或日志代理,可能需要被集群策略拒绝的权限。由于策略保护集群,它们在集群级别强制执行,跨越所有命名空间。这可能适用于某些策略,但其他策略可能会阻止合法容器被调度。为了允许免除,准入控制器包括允许命名空间免除所有策略或仅某些策略的控制。
免除特定处理中的命名空间
要免除命名空间的所有门卫策略,您可以创建一个包含您想要免除的命名空间的配置对象。您可以通过添加一个或多个处理选项来免除每个命名空间的所有门卫功能或仅某些过程,如审计。表 13.2 显示了可以设置的四个处理选项。
表 13.2 命名空间免除选项
| 处理选项 | 免除结果 |
|---|---|
| 审计 | 命名空间将不会报告审计结果,但仍将是 webhook 和同步流程的一部分。 |
| Webhook | 命名空间将免于准入控制器,但仍将是审计和同步流程的一部分。 |
| 同步 | 命名空间资源将不会报告给门卫,但仍将是审计和 webhook 流程的一部分。 |
| * | 免除命名空间(s)从所有 Gatekeeper 进程。 |
例如,我们可能希望免除一些命名空间的所有 Gatekeeper 处理。要免除所有进程,我们可以在包含命名空间的配置中创建一个新的配置,在进程字段中使用*。下面显示的清单创建了一个配置,该配置免除 kube-system 和 gatekeeper-system 命名空间的所有 Gatekeeper 进程:
*apiVersion: config.gatekeeper.sh/v1alpha1*
kind: Config
metadata:
name: config
namespace: "gatekeeper-system"
spec:
match:
- excludedNamespaces: ["kube-system", "gatekeeper-system"]
processes: ["*"]
您可以通过添加额外的匹配项为不同的命名空间添加不同的进程免除。例如,您可以创建一个仅免除命名空间从 webhook 进程的匹配项,而另一个命名空间可能仅免除 Gatekeeper 的审计进程。
免除所有策略的命名空间
在某些组织中,为所有 Gatekeeper 策略创建免除可能会违反安全标准。创建命名空间免除既快又简单,但它将免除该命名空间中所有部署的所有 Gatekeeper 策略,无一例外。
将命名空间排除在所有策略之外是一个两步过程。第一步是添加一个策略引擎将允许忽略策略的命名空间列表,第二步是将您想要免除的命名空间(s)标记为 admission.gatekeeper.sh/ignore=true。
如果您尝试跳过第一步,只标记一个命名空间来免除它,您将收到来自 API 服务器的以下错误,只有免除命名空间才能有 ignore 标签:
Error from server (Only exempt namespace can have the admission.gatekeeper.sh/ignore label): admission webhook "check-ignore-label.gatekeeper.sh" denied the request: Only exempt namespace can have the admission.gatekeeper.sh/ignore label
在标记任何命名空间之前,您必须首先通过编辑已安装的 configManagement 对象并在 exemptableNamespaces 字段中添加命名空间列表来添加命名空间。该列表是通过 GCP 控制台添加的。
要使用 Anthos 控制台将命名空间添加为免除项,您需要编辑集群的配置管理设置。在 GCP 控制台中,打开 Anthos > 配置管理以查看可用的集群列表。选择您想要配置的集群旁边的按钮,然后在 GCP 控制台页面顶部点击“配置”。如果您展开设置并滚动到页面底部,您将看到策略控制器部分。点击您集群的 ACM 设置以打开免除命名空间列表,如图 13.3 所示。
注意:在添加新命名空间时,您必须非常小心。控制台不会验证命名空间是否已存在或是否拼写错误。
在图 13.3 中,您可以看到我们已经创建了免除四个命名空间的能力。要添加另一个命名空间,您只需在“免除命名空间”框中点击,输入命名空间名称,然后点击“完成”。始终要检查您输入的命名空间拼写是否正确。系统不会将列表与集群进行验证,因此任何拼写错误都将导致无法将命名空间添加到免除列表中。一旦命名空间被添加到免除列表中,您必须使用 admission.gatekeeper.sh/ignore=true 标签标记该命名空间,使其免于所有 Gatekeeper 策略。

图 13.3 使用 GCP 控制台添加豁免
为命名空间标记以忽略 Gatekeeper 将导致准入控制器忽略该命名空间中创建的任何对象的 所有 策略。与其从每个策略中豁免命名空间,你可能会考虑从单个策略中豁免命名空间,这样你可以执行某些策略,同时仅豁免命名空间中对象创建所需的策略。
从约束模板中豁免命名空间
如果你发现自己处于需要从策略中豁免特定命名空间的情况,但你不能从 所有 策略中豁免该命名空间,你可以向约束本身添加豁免。例如,假设我们有一个要求所有命名空间都必须分配计费代码的策略。然而,我们希望豁免 kube-system 命名空间以及将要创建的新命名空间 web-frontend。我们可以通过向我们的约束中添加 excludedNamespaces 字段来实现这一点,如下所示:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-billing
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
excludedNamespaces:
- kube-system
- web-frontend
parameters:
labels:
- key: "billing"
如果我们尝试创建一个名为 test-fail 的新命名空间,但没有标签,Gatekeeper 将会拒绝请求并显示以下错误:
Error from server ([denied by ns-billing] you must provide labels: {"billing"}): admission webhook "validation.gatekeeper.sh" denied the request: [denied by ns-billing] you must provide labels: {"billing"}
然而,如果我们尝试创建没有标签的 web-frontend 命名空间,如以下所示,Gatekeeper 将允许这样做,因为它包含在约束的 excludedNamespaces 中:
[root@localhost gke-bm]# kubectl create ns web-frontend
namespace/web-frontend created
ACM 通过提供从所有策略或仅某些策略中豁免命名空间的能力,提供了细粒度的控制。你可以为不同的命名空间混合使用这两种类型,为某个命名空间豁免所有策略,而其他命名空间可能仅豁免某些策略。尽量避免从所有策略中豁免命名空间,除非你有充分的理由这样做。一旦豁免,完全豁免的命名空间将永远不会执行任何策略。
虽然 Anthos 包含几个约束模板,但可能存在一些场景,你需要创建自定义约束。在下一节中,我们将解释如何创建自定义约束模板,这样你可以扩展包含的策略集。
创建约束模板
ACM 内置的默认模板库从早期版本中的少量策略增长到当前版本中的超过 32 个。Google 和社区继续向默认库添加策略,但你可能对你的集群有独特的策略需求,而 Google 并不提供。
如果你发现自己需要创建策略,你可以通过使用名为 Rego 的语言创建自己的策略来创建自定义约束模板。深入介绍 Rego 超出了本书的范围,但你可以在 mng.bz/X5e6 上了解更多关于 Rego 以及如何使用它来创建策略的信息。
要创建一个新的模板,你需要创建一个新的 ConstraintTemplate 对象,该对象将包含用于评估策略的 Rego 代码。Google 提供了文档来帮助你创建模板,请参阅mng.bz/ydKq。
下一个示例创建了一个新的模板,当创建新容器时将检查图像摘要:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8simagedigests
annotations:
metadata.gatekeeper.sh/title: "Image Digests"
description: >-
Requires container images to contain a digest.
https://kubernetes.io/docs/concepts/containers/images/
spec:
crd:
spec:
names:
kind: K8sImageDigests
validation:
openAPIV3Schema:
type: object
description: >-
Requires container images to contain a digest.
https://kubernetes.io/docs/concepts/containers/images/
properties:
exemptImages:
description: >-
Any container that uses an image that matches an entry in this list will be excluded
from enforcement. Prefix-matching can be signified with '*'. For example: 'my-image-*'.
It is recommended that users use the fully-qualified Docker image name (e.g. start with a domain name)
in order to avoid unexpectedly exempting images from an untrusted repository.
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8simagedigests
import data.lib.exempt_container.is_exempt
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not is_exempt(container)
satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)]
not all(satisfied)
msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
not is_exempt(container)
satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)]
not all(satisfied)
msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image])
}
violation[{"msg": msg}] {
container := input.review.object.spec.ephemeralContainers[_]
not is_exempt(container)
satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)]
not all(satisfied)
msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image])
}
libs:
- |
package lib.exempt_container
is_exempt(container) {
exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", [])
img := container.image
exemption := exempt_images[_]
_matches_exemption(img, exemption)
}
_matches_exemption(img, exemption) {
not endswith(exemption, "*")
exemption == img
}
_matches_exemption(img, exemption) {
endswith(exemption, "*")
prefix := trim_suffix(exemption, "*")
startswith(img, prefix)
}
重要的是要注意,Rego 代码包含多个违规部分。乍一看,这些代码可能看起来是相同的,但仔细检查时,你会在 container :=行上注意到一个细微的差异。第一个违规块检查所有容器是否有摘要,而第二个违规块检查所有 initContainers 是否有摘要,第三个检查任何 ephemeralContainers。因为它们都是独特的对象,所以我们需要在我们的代码中包含每个对象,否则策略引擎将不会检查它们。
最后,为了激活约束,我们应用了一个使用之前模板创建的新自定义资源 manifest,即 K8sImageDigests:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sImageDigests
metadata:
name: container-image-must-have-digest
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
一旦应用到集群中,任何没有提供摘要的新 Pod 请求都将被准入控制器拒绝。
13.4.2 使用二进制授权来保护供应链
自从 SolarWinds 安全漏洞以来,人们开始关注如何保护你的软件供应链。你应该始终考虑并实施这一点,但通常需要像 SolarWinds 漏洞这样的事件来吸引公众的注意。保护供应链是一个大话题,要给它应有的关注就需要一个专门的章节,但我们想提供一个概述,介绍 Google 提供的工具,以帮助你保护你的供应链。
你可能最近听说过“左移安全”这个短语。这个术语指的是在软件开发过程中更早地考虑安全性的做法。在左移时,你应该考虑多个主题;如果你想阅读由包括 Google、CloudBees、德勤等公司赞助的独立报告,请阅读 2019 年的《DevOps 状态》,它涵盖了多家公司的关键发现及其 DevOps 实践,请参阅cloud.google.com/devops/state-of-devops。
Anthos 包括一个强大的工具,它将 Anthos on GCP 和 Anthos on-prem 上的工作负载的软件供应链安全性集中化,称为二进制授权(BinAuth)。从高层次来看,BinAuth 通过要求部署的镜像上有受信任的权威签名来为你的集群增加安全性,这在容器部署时得到验证。如果部署的容器不包含与受信任的权威匹配的签名,它将被拒绝调度并失败部署。Google 的 BinAuth 为你提供了几个功能,包括以下内容:
-
策略创建
-
策略执行和验证
-
云安全命令中心集成
-
审计日志
-
云 KMS 支持
-
使用开源工具 Kritis 进行签名验证
-
支持模拟运行
-
紧急支持
-
支持第三方工具,包括 Twistlock、Terraform 和 CloudBees 的支持
除了提供的功能外,您可以将 BinAuth 与 Google 的 Cloud Build 和容器注册库扫描集成,允许您根据构建元数据和漏洞扫描结果来保护您的供应链。Google 在二进制授权页面提供了多个集成文档,该页面位于cloud.google.com/binary-authorization/,它将指导您如何将 BinAuth 与 CircleCI、Black Duck、Terraform 和 Cloud Build 等系统集成。
13.4.3 使用 Gatekeeper 替代 PSPs
随着 Kubernetes 弃用 PSPs,您可能希望开始逐步停止使用 PSPs 来保护您的集群。从 PSPs 作为主要安全机制中退出的一种方法是将使用 Gatekeeper 策略。Gatekeeper 项目有一个 GitHub 存储库,专门用于设计用于替代 PSPs 的策略,该存储库位于mng.bz/Ml6n。
在下一节中,我们将通过了解如何使用 Google 容器扫描来保护镜像来结束本章。
13.5 理解容器扫描
与任何标准操作系统或应用程序一样,容器可能包含已知漏洞的二进制文件。为了确保您的集群安全,您需要通过持续扫描每个容器来验证其完整性。
市场上许多解决方案,包括 Aqua Security、Twistlock、Harbor 和 Google 的容器注册库,都会扫描容器以查找漏洞。这些工具中的每一个都提供不同级别的扫描能力——在大多数情况下,需要额外付费。至少,您希望扫描您的镜像以查找来自常见漏洞和暴露(CVE)列表的任何漏洞。
CVE 列表(cve.mitre.org/cve)是公开披露的各种软件组件(包括操作系统和库)的安全漏洞列表。列表中的条目仅包含漏洞的简要概述——它们不包含任何详细信息,如后果、风险或如何修复问题。要获取 CVE 的详细信息,每个条目都有一个链接,该链接将带您访问国家漏洞数据库,该数据库将提供有关 CVE 的额外详细信息,包括描述、严重性、引用和变更历史。
虽然 Anthos 不包含漏洞扫描器,但如果您将镜像存储在 Google 容器注册库中,Google 会提供扫描服务。在本节中,我们将解释如何在您的存储库中启用扫描以及如何查看扫描结果。
13.5.1 启用容器扫描
在您的注册表中启用扫描的第一个要求是在您的 GCP 项目中启用两个 API:容器分析 API 和容器扫描 API。容器分析 API 允许在您的项目中存储元数据,并且是免费的,而容器扫描 API 将启用漏洞扫描,并且按扫描的图像计费。您可以在扫描 API 的定价详情中查看 mng.bz/aMjB.*
要使用 gcloud CLI 启用所需的 API,请按照以下步骤操作:
-
按照以下方式设置您的默认项目。我们的示例使用了一个名为 test1-236415 的项目:
gcloud config set project test1-236415 -
接下来,启用容器分析 API:
gcloud services enable containeranalysis.googleapis.com -
最后,启用容器扫描 API:
gcloud services enable containerscanning.googleapis.com
一旦在项目上启用了 API,您将需要创建一个存储图像的存储库。下一个示例在 us-east4 位置创建了一个名为 docker-registry 的 Docker 注册表,并带有注册表的描述:
gcloud artifacts repositories create docker-registry --repository-format=docker --location=us-east4 --description="Docker Registry"
要将图像推送到您的存储库,您需要在您的客户端上配置 Docker 以使用您的 GCP 凭据。GCP 中存储库的认证是按区域配置的。在上一个步骤中,我们在 us-east4 区域创建了一个注册表,因此要配置认证,我们将在此处执行 gcloud 命令:
gcloud auth configure-docker us-east4-docker.pkg.dev
现在,您的注册表和 Docker 已配置完毕,您可以使用注册表来存储图像。在下一节中,我们将解释如何标记图像并将它们推送到您的新存储库。
13.5.2 将图像添加到您的存储库
要将图像添加到 GCP 注册表,您将遵循与任何其他 Docker 注册表相同的步骤,但标记可能与您习惯的不同:
-
如果您没有本地图像,您必须使用 Docker 构建新的图像或从另一个注册表拉取图像。
-
使用您的 GCP 注册表标记图像。
-
将新图像推送到注册表。
例如,要将 CentOS 8 图像添加到注册表,请按照以下步骤操作:
-
从 Docker Hub 下载 CentOS 8 图像:
docker pull centos:8 -
接下来,使用 Google 注册表信息标记新拉取的图像。当您标记一个将存储在 GCP 注册表中的图像时,您必须遵循特定的命名约定。图像标记将使用以下约定:LOCATIONdocker .pkg.dev/<project_ID>/
/<image_name>。在下一个示例中,区域是 us-east4,项目是 test-236415,注册表名称为 docker-registry: docker tag centos:8 us-east4-docker.pkg.dev/test1-236415/docker-registry/centos:8 -
最后,将新图像推送到注册表:
docker push us-east4-docker.pkg.dev/test1-236415/docker-registry/centos:8
在下一节中,我们将解释如何查看您的图像以及其中发现的任何漏洞。
13.5.3 审查图像漏洞
由于我们的项目已启用所需的 API,每次图像推送到注册表时都会进行扫描。要审查漏洞,请打开 GCP 控制台并点击“Artifact Registry”>“Repositories”,如图 13.4 所示。

图 13.4 导航到您的注册表
这将显示您项目中的所有注册表。继续我们的示例,我们创建了一个名为 docker-registry 的注册表,如图 13.5 所示。

图 13.5 项目注册表
打开您推送图像到的存储库,并点击图像以查看它。之前,我们已经将 CentOS 图像推送到我们的注册表,如图 13.6 所示。

图 13.6 图像列表
点击图像将显示图像的摘要和图像包含的漏洞数量。我们的示例如图 13.7 所示。

图 13.7 图像哈希列表
要查看每个漏洞,请点击漏洞列中的数字。将打开一个新窗口,列出图像的所有 CVE。根据图像和扫描结果,您可能看到不同的 CVE 链接或选项。以图 13.8 所示的 CentOS 图像示例,我们可以看到结果中有一个链接,可以查看每个 CVE 的修复方案。

图 13.8 带修复的 CVE 示例列表
在另一个示例中,Ubuntu 图像的 CVE 中没有列出任何修复,因此结果屏幕将包含不同的选项,如图 13.9 所示。

图 13.9 无修复的 CVE 示例
您可以通过点击名称列中的 CVE 来查看每个 CVE 的详细信息,或者您也可以点击右侧的“查看”。点击 CVE 名称将带您到供应商的网站,而点击“查看”将提供有关漏洞的更多详细信息。
在本节中,我们介绍了 Google 的容器注册表扫描,如何启用它以及如何查看扫描结果。这只是一个服务的介绍,但您可以通过与 Pub/Sub 集成、添加访问控制等功能来扩展其功能。要查看更多文档,您可以访问 Google 的如何操作指南,网址为mng.bz/gJ6E。
13.6 理解容器安全
在创建安全策略时,您应该考虑两个主要概念:容器将运行的用户以及容器是否可以以特权模式运行。这两个概念最终决定了潜在的容器突破对主机将有什么样的访问权限。
当容器启动时,它将以在图像创建时设置的用户的身份运行,这通常是 root 用户。然而,即使您以 root 用户运行容器,这并不意味着容器内的进程将在工作节点上具有 root 访问权限,因为 Docker 守护进程本身将根据有关特权容器的策略限制主机级别的访问。为了帮助解释这一点,表 13.3 显示了每个设置及其产生的权限。
表 13.3 根和特权容器权限
| 运行容器用户 | 特权值 | 主机权限 |
|---|---|---|
| 以 root 用户运行 | False | None |
| 以 root 用户运行 | True | Root access |
| 以非 root 用户运行 | False | None |
| 以非 root 身份运行 | True | 受限;只有授予主机系统上同一用户的权限 |
两个值决定了运行容器在主机上将被授予的权限。仅仅以 root 身份运行镜像并不允许该容器在主机上以 root 身份运行。为了更详细地解释这种影响,我们将展示当你以 root 身份运行容器时会发生什么,以及允许用户部署特权容器如何使某人能够接管主机。
13.6.1 以 root 身份运行容器
多年来,容器安全已经获得了一些不良声誉。许多被用作支持这一点的证据的例子实际上并不是容器问题,而是集群上的配置问题。不久前,许多开发者创建了以 root 身份运行的新镜像,而不是创建一个新用户并以新用户身份运行,这限制了任何安全后果。这是一个提到如果你经常从第三方注册库下载镜像,你应该在使用它们在生产环境中之前始终在沙盒环境中运行它们的好时机。你不知道镜像是如何创建的,它以什么身份运行,或者它是否包含任何恶意代码。在将镜像用于生产之前,始终检查镜像。在本章的最后部分,我们将介绍 Google 容器扫描,它将扫描你的镜像以查找已知的安全问题。
你可以使用多个工具来限制恶意容器的部署,包括
-
容器扫描——包含在具有扫描功能的 Google 容器注册库中
-
仅允许受信任的容器仓库——无论是内部仓库还是受信任的合作伙伴注册库
-
要求镜像签名
最危险且常被忽视的安全问题之一是允许容器以 root 身份运行。为了解释为什么这是一个坏习惯,让我们用一个虚拟机示例来说明:你会允许应用程序以 root 或管理员身份运行吗?当然不会。如果你有一个以管理员身份运行其进程的 Web 服务器,任何应用程序突破都将授予运行该进程的用户权限。在这种情况下,那将是一个具有 root 或管理员权限的账户,这将提供对整个系统的完全访问权限。
为了减轻任何突破带来的问题,所有应用程序都应该使用它们所需的最小权限集运行。不幸的是,开发者以 root 身份运行容器的情况非常普遍。如果我们以 root 身份运行容器,任何容器突破都将使入侵者获得对主机上任何资源的访问权限。Docker Hub 和 GitHub 上许多镜像都是使用 root 作为默认用户分发的,包括常见的 busybox 镜像。
为了避免以 root 身份运行镜像,你需要在你的镜像中创建并设置一个用户账户,或者在你启动容器时提供一个用户账户。因为 busybox 通常是从 Docker Hub 拉取的,我们可以通过在部署中配置安全上下文来以非 root 账户运行它。
作为 Pod 定义的一部分,可以通过添加 securityContext 字段强制容器以用户身份运行,这允许您为用户、组和 fsGroup 设置上下文:
spec:
securityContext:
runAsUser: 1500
runAsGroup: 1000
fsGroup: 1200
使用带有 additional securityContext 的镜像部署将使容器以用户 1500 的身份执行。我们还设置了组为 1000,fsGroup 为 1200。我们可以使用 whoami 和 groups 命令确认所有这些值,如图 13.10 所示。

图 13.10 以 root 用户运行并使用 securityContext 更改定义的用户和用户组的 Pod
在镜像中使用的 UID 和组 ID 是未知的,因为它是从 Docker Hub 拉取的,并且它只包含在创建镜像时包含的用户和组。在您或您组织中的某人创建的镜像中,您会在 Docker 构建期间添加所需的组,并且不会收到未知 ID 警告。
在本节中,我们解释了如何在部署时设置安全上下文以以非 root 用户或组运行镜像。这仅涵盖了保护我们的主机免受恶意容器侵害的第一部分。下一节将解释特权容器如何影响我们的安全以及它们如何协同工作以提供对主机的访问。
13.6.2 运行特权容器
默认情况下,容器在没有主机权限的情况下执行。即使您以 root 用户启动容器,任何尝试编辑任何主机设置的尝试都将被拒绝,如图 13.11 所示。

图 13.11 以 root 身份运行的非特权容器
例如,我们可以尝试从作为 root 用户运行但不是特权容器的容器中设置内核值,如图 13.12 所示。

图 13.12 从没有权限的容器尝试的内核更改
内核更改被拒绝,因为运行中的镜像在主机系统上没有提升的权限。如果有一个原因需要从容器允许此操作,则可以以特权容器启动镜像。要运行特权容器,您需要在 Pod 的 securityContext 中允许它:
apiVersion: v1
kind: Pod
metadata:
name: root-demo
spec:
containers:
- name: root-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
privileged: true
现在 Pod 已被允许以特权容器运行,并且正在以 root 身份运行,它将被允许更改内核参数,如图 13.13 所示。

图 13.13 以 root 身份运行的特权容器
在图 13.14 中,请注意域名更改没有返回错误,这验证了容器可以修改主机级别的设置。

图 13.14 从运行中的容器允许的主机内核更改
这次,内核更改成功有两个原因:容器正在以root用户身份运行,并且容器被允许以特权容器启动。
对于最后一个场景,manifest 已被编辑为以用户 1000 运行,该用户没有 root 权限,并且以特权容器启动:
apiVersion: v1
kind: Pod
metadata:
name: root-demo
spec:
containers:
- name: root-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
privileged: true
runAsUser: 1000
尽管容器以特权容器的身份运行,但用户是标准用户,因此任何内核更改都将被拒绝,如图 13.15 所示。

图 13.15 以非 root 身份运行的特权容器
总结来说,控制容器在主机上可以执行的操作是由容器中运行的用户以及容器是否被允许以特权容器身份运行来控制的。为了保护集群,您需要创建一个策略,该策略定义了每个这些值的控制措施。
目前,你知道为什么不应该允许容器以 root 身份运行,以及为什么你应该限制允许以特权容器身份运行的 Pods,但我们还没有解释如何在集群上阻止这些操作之一的发生。这是 Anthos 专长的一个领域!通过提供 Anthos Config Manager,Google 包含了您需要使用这些以及其他许多常见安全设置来保护您的集群的所有工具。
在下一节中,我们将解释如何使用包含的策略管理器 Gatekeeper 通过 ACM 来保护集群。
13.7 使用 ACM 保护您的服务网格
正如你在本书的整个过程中所看到的,Anthos 不仅仅提供基本的 Kubernetes 集群。它还提供了额外的组件,如 Anthos Service Mesh (ASM) 以提供服务网格,二进制授权,无服务器工作负载,以及 ACM 来处理基础设施即代码。
在第十一章中,你学习了如何设计和配置 ACM 以在 Anthos 集群上实施部署和对象。在本节中,我们将使用策略通过 ACM 保护集群中服务之间的通信。然后我们将继续介绍 ACM 包含的另一个组件,即策略控制器,它提供了一个基于开源项目 Gatekeeper 的准入控制器。
注意:当使用 ACM 策略启用 mTLS 时,请记住,该策略将应用于所有由外部存储库管理的集群,除非您使用 ClusterSelector 来限制将配置的集群。
13.7.1 使用 ACM 实施双向 TLS
在第四章中,你学习了 ASM 包括使用双向 TLS (mTLS) 加密服务之间流量的能力。双向 TLS 是在通过 Istio 的 sidecar 允许服务之间通信之前验证服务身份的过程。一旦身份得到验证,服务之间的通信将被加密。然而,默认情况下,Istio 被配置为使用宽容的 mTLS。宽容的 mTLS 允许没有 sidecar 运行的作业使用 HTTP(明文)与启用 sidecar 的服务进行通信。
对于服务网格新手来说,开发者或管理员通常使用宽容设置。虽然这对学习 Istio 有益,但允许 HTTP 流量进入运行 sidecar 的服务会使它不安全,从而抵消了 Istio 和 sidecar 的优势。一旦您对 Istio 感到舒适,您可能希望考虑将宽容策略更改为更安全的严格设置。
您可以通过创建一个名为 PeerAuthentication 的 Kubernetes 对象来强制整个网格或仅某些命名空间使用严格的 mTLS。对于每个组织和集群来说,决定 mTLS 的正确作用域都是不同的。您应该在将任何 mTLS 策略更改部署到生产环境之前,始终在开发环境中进行测试,以避免任何意外应用故障。
由于这是一个重要的策略,它是一个完美的例子,用以展示使用 ACM 作为配置管理工具的重要性。请记住,一旦对象被 ACM 管理,配置管理器将控制它。这意味着管理器将重新创建任何因任何原因编辑或删除的管理对象。对于 mTLS 用例,您应该看到使用 ACM 确保策略设置以及如果编辑,则修复到配置的严格值的重要性。
要启用全局严格的 mTLS 策略,您需要创建一个新的 PeerAuthentication 对象,并将 mTLS 模式设置为严格。下面是一个示例清单:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
清单假设 Istio 已安装在 istio-system 命名空间中。因为命名空间选择器是 istio-system 命名空间,它将为集群中的所有命名空间强制执行严格的 mTLS 策略。
注意:为了强制执行集群中每个命名空间的严格 mTLS 策略,PeerAuthentication 对象必须创建在 Istio 安装的相同命名空间中。默认情况下,这是 istio-system 命名空间。
如果您决定实施按命名空间强制执行,清单需要单一修改,即命名空间值。例如,如果我们想在一个名为 webfront 的命名空间上启用 mTLS,我们会使用以下清单:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: webfront
spec:
mtls:
mode: STRICT
要使用这些清单中的任何一个与 ACM 强制执行严格的 mTLS 网格策略,您只需将其存储在您的 ACM 存储库中。因为策略存储在 ACM 存储库中,它将由控制器管理,任何更改或删除都将导致使用严格设置重新创建对象。mTLS 策略只是我们如何使用 ACM 和 ASM 一起强制执行集群安全策略的一个示例。
13.8 结论
ACM 的策略引擎是所有 Anthos 集群中包含的一个强大附加组件。Gatekeeper 允许组织创建细粒度的策略,通过提供额外的安全性和稳定性来保护集群免受潜在攻击者的影响。Google 提供了一系列默认策略,这些策略解决了从社区和 Google 自身经验中收集的一些最常见的安全问题。如果包含的策略库没有解决你组织中的安全问题,你可以使用 Gatekeeper 的策略语言 Rego 创建自己的策略。
13.9 示例和案例研究
使用本章的知识,解决以下案例研究中的每个要求。
13.9.1 永恒工业
永恒工业要求你评估其 Anthos Kubernetes 集群的安全性。集群已按以下方式配置:
-
多个控制平面节点
-
多个工作节点
-
ASM 提供 Istio,配置为宽容的 mTLS
-
ACM 配置了启用了策略引擎,包括默认模板库
他们要求你记录任何当前的安全问题以及补救措施,以满足以下要求:
-
审计任何安全问题,并提供任何由策略覆盖的利用的证明。
-
所有容器只允许从批准的注册表列表中拉取,包括以下这些:
-
gcr.io
-
hub.evermore.local
-
-
除了批准的注册表策略之外,所有策略都必须在实施前进行测试,以评估其后果。
-
容器必须拒绝任何权限提升尝试,而不影响任何 Anthos 命名空间,包括以下这些:
-
kube-system
-
gke-system
-
config-management-system
-
gatekeeper-system
-
gke-connect
-
-
容器不得能够在除了 kube-system 命名空间之外的任何命名空间中使用 hostPID、hostNetwork 或 hostIPC。
-
必须仅使用现有的 Anthos 工具来满足所有要求。
下一个部分包含了解决永恒工业要求的解决方案。你可以跟随解决方案进行操作,或者如果你感到舒适,配置你的集群以满足要求并使用解决方案来验证你的结果。
永恒工业解决方案:测试当前安全性
满足要求 1
第一个要求需要你记录当前集群中存在的任何安全问题。为了测试前三个安全要求,你可以部署一个尝试提升容器权限的清单。测试清单应从不在批准列表中的注册表中拉取镜像,并将字段设置为提升权限和不同的主机值。我们在此提供了一个示例清单:
apiVersion: v1
kind: Pod
metadata:
labels:
run: hack-example
name: hack-example
spec:
hostPID: true
hostIPC: true
hostNetwork: true
volumes:
- name: host-fs
hostPath:
path: /
containers:
- image: docker.io/busybox
name: hack-example
command: ["/bin/sh", "-c", "sleep infinity"]
securityContext:
privileged: true
allowPrivilegeEscalation: true
volumeMounts:
- name: host-fs
mountPath: /host
此清单将在单个部署中测试所有安全要求。正在拉取的镜像标签来自 docker.io,它不在批准的注册表列表中。它还将主机的根文件系统映射到容器的/mount/host 位置,并以特权容器的形式启动。
由于容器启动成功,我们可以记录集群可以从不在接受列表中的注册表中拉取镜像。成功的启动还表明 Pod 以特权容器启动,并且对 hostPath 的挂载也成功了。为了记录容器确实可以访问主机文件系统,我们可以访问镜像并列出/host 目录。图 13.16 显示我们可以成功列出主机的根文件系统。

图 13.16 在容器中访问主机文件系统
在捕获输出并将其添加到文档后,您可以删除 Pod,因为我们将在下一个测试中启用策略来测试相同的部署。您可以通过执行 kubectl delete -f use-case1.yaml 来删除它。
Evermore Industries 解决方案:添加仓库约束
满足要求 2
Evermore 的第二项要求是容器只能从受信任的注册表中拉取。在需求中,只有从 gcr.io 和 hub.evermore.local 拉取的镜像被允许在集群中部署。
为了限制镜像只从两个注册表拉取,我们需要创建一个新的 ConstraintTemplate,该模板使用 k8sallowedrepos.constraints.gatekeeper.sh 对象。下面提供了一个 ConstraintTemplate 的示例:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: allowed-registries
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
repos:
- "gcr.io"
- "hub.evermore.local"
一旦部署了此清单,任何尝试从除 gcr.io 和 hub.evermore.local 之外的注册表拉取镜像的尝试都将导致准入控制器拒绝 Pod 创建,并出现以下错误,即使用了无效的镜像仓库:
Error creating: admission webhook "validation.gatekeeper.sh" denied the request: [denied by allowed-registries] container <nginx2> has an invalid image repo <bitnami/nginx>, allowed repos are ["gcr.io", ""hub.evermore.local""]
现在我们已经解决了要求 2,我们可以继续解决要求 3 和 4。
Evermore Industries 解决方案:添加特权约束
满足要求 3 和 4
我们需要解决 Evermore 集群的安全需求。为了保护集群免受运行特权 Pod 的影响,但不影响任何 Anthos 系统命名空间中的 Pod,我们需要启用一个带有豁免的约束。然而,在启用约束之前,Evermore 要求所有约束都必须经过测试,并且受影响 Pod 的输出作为文档的一部分提供。
第一步是创建一个清单来创建约束。下面显示的清单仅创建一个名为 privileged-containers 的约束,处于审计模式。它还排除了 Evermore 在需求文档中提供的所有系统命名空间:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: privileged-containers
spec:
enforcementAction: dryrun
excludedNamespaces:
- kube-system
- gke-system
- config-management-system
- gatekeeper-system
- gke-connect
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
要将审计输出添加到文档中,您必须描述约束并将输出重定向到文件,通过执行以下 kubectl 命令:
kubectl get K8sPSPPrivilegedContainer psp-privileged-container -o yaml > privtest
这将在当前文件夹中创建一个名为 privtest 的文件,包含 psp-privileged-container 约束的审计结果。您应该检查该文件,以验证它是否包含在违规部分下的预期审计结果。以下是我们审计的简略输出:
violations:
- enforcementAction: dryrun
kind: Pod
message: 'Privileged container is not allowed: cilium-agent, securityContext:
{"capabilities": {"add": ["NET_ADMIN", "SYS_MODULE"]}, "privileged": true}'
name: anetd-4qbw5
namespace: kube-system
- enforcementAction: dryrun
kind: Pod
message: 'Privileged container is not allowed: clean-cilium-state, securityContext:
{"capabilities": {"add": ["NET_ADMIN"]}, "privileged": true}'
name: anetd-4qbw5
你可能已经注意到,审计输出包含被添加为排除项的命名空间中运行的 Pods。请记住,当你在一个约束中排除一个命名空间时,该命名空间仍然会被审计——排除项只会阻止策略被强制执行。
由于输出看起来正确,我们可以强制执行策略以满足安全要求,拒绝特权容器。要删除现有的约束,请使用清单文件执行 kubectl delete -f <清单文件>。
接下来,更新清单文件,从清单中删除 enforcementAction: dryrun 行,并重新部署约束。
Evermore Industries 解决方案:添加主机约束
满足要求 5
来自 Evermore 的第五个要求是在所有命名空间中拒绝 hostPID、hostNetwork 和 hostIPC,除了 kube-system。我们还需要在实施之前测试策略,如要求所述。
为了满足既定要求,我们需要实施两个新的策略。第一个是 k8spsphostnamespace,它将阻止对包括 hostPID 和 hostIPC 在内的主机命名空间的访问。最后,为了解决阻止 hostNetwork 的问题,我们需要实施 k8spsphostnetworkingports 策略。
要阻止从所有命名空间(除了 kube-system)访问主机命名空间,您需要创建一个新的约束,该约束豁免 kube-system。我们还需要在实施之前测试约束,因此需要将 enforcementAction 设置为 dryrun。以下是一个示例清单:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNamespace
metadata:
name: psp-host-namespace
spec:
enforcementAction: dryrun
excludedNamespaces:
- kube-system
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
在此清单部署之后,任何尝试使用主机命名空间(如 hostPID)的 Pod 都会被准入控制器拒绝启动。设置 dryrun 选项将仅审计策略,而不强制执行。一旦测试通过,您可以从清单中删除 enforcementAction: dryrun 并部署它以强制执行策略。
要阻止主机网络,我们需要创建另一个约束,该约束将使用 k8spsphostnetworkingports 策略:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
name: psp-host-network-ports
spec:
enforcementAction: dryrun
excludedNamespaces:
- kube-system
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
hostNetwork: false
就像之前的约束一样,我们包括了 dryrun 选项,在强制执行之前测试约束。一旦测试并通过部署,任何尝试将 hostNetwork 设置为 true 的 Pod 都会被准入控制器拒绝,并显示以下错误,指出只允许 hostNetwork=false:
Error creating: admission webhook "validation.gatekeeper.sh" denied the request: [denied by psp-host-network-ports] The specified hostNetwork and hostPort are not allowed, pod: privileged-test-7694b64776-qmp47\. Allowed values: {"hostNetwork": false}
恭喜!通过部署最后两个约束,我们已经满足了 Evermore 的所有要求。
摘要
-
根和特权容器可以被用来接管未受保护的主机。
-
Anthos 可以通过部署内置策略或使用 Anthos Configuration Management 部署的自定义策略来保护集群。
-
虚拟机比容器提供更好的安全性。两种模式都有独特的安全关注点,并且必须正确部署,从它们部署的开始就要考虑安全性。
-
我们概述了 Kubernetes 的安全性和 Anthos 包含的功能,以帮助解决集群中的安全担忧,包括 ACM 和 ASM。
-
以 root 或特权容器运行容器的安全问题可能被用来危害主机。
-
您可以使用 ACM 功能通过 Gatekeeper 以及由 Anthos 提供的包含约束模板库来保护集群。
-
谷歌的容器漏洞扫描引擎可以识别容器漏洞。
(1.) Kubernetes.io 提供了一组初始推荐:mng.bz/nJyK。
14 市场概览
安东尼奥·古利
本章节涵盖
-
公共 Google 市场
-
私有 Google 市场
-
部署市场解决方案
-
现实场景
Google Cloud Marketplace 是一个一站式解决方案,用于尝试、购买、配置、管理和部署软件产品。通常,多个供应商提供相同的包,为您的特定用例和行业提供了操作系统、虚拟机、容器、存储成本、执行环境和 SaaS 服务等方面的多种选择。Google Cloud 为新用户提供了一笔初始信用额度,这笔额度也可以在市场中使用。截至 2023 年 1 月,这笔信用额度为 300 美元,但未来可能会有所变化。在本章中,我们将讨论如何使用 Google Cloud Marketplace 在不同的 Kubernetes 环境中自动部署包,包括 Anthos、GKE 和本地 GKE。当涉及到简化开发者体验时,市场通过尽可能简化用户安装组件的过程,同时利用维护者/提供者的最佳实践配置来增加价值。
14.1 Google 市场
Google Cloud Platform (GCP) 市场网站 (cloud.google.com/marketplace) 为 GCP 客户提供了一个单一的地方,用于查找免费和付费应用程序,这些应用程序由 Google 或第三方合作伙伴提供,扩展了平台提供的内容。部署可以使用默认配置,也可以针对特定需求进行定制,例如增加内存、存储或使用更大的 vCPU 提供更多的计算能力。每个包都有安装后获取帮助的具体说明。请注意,市场团队会持续更新每个镜像,以修复关键问题和错误。然而,更新您环境中已部署的解决方案是您的责任。
14.1.1 公共市场
目前,在 GCP 上有超过两千种解决方案可供使用,包括合适的应用程序包和数据集。您可以通过点击云控制台中的市场链接来访问 GCP 市场。要选择一个包,您可以搜索包名称或使用市场屏幕左侧的面板进行浏览,如图 14.1 所示。市场中的解决方案使得通过简单的“点击”操作部署新应用程序变得容易,这在多个环境中都是一样的,无论是在公共云还是在本地。

图 14.1 通过 GCP 控制台访问市场并列出包
对于本书的范围,我们关注在 Kubernetes 上运行的应用程序。从 Google Cloud Marketplace 网站,选择“探索市场”,您将到达市场提供的产品(mng.bz/41Nv)。在左侧的类型面板中,选择 Kubernetes 应用。目前,大约有 100 种不同领域的解决方案可供 GKE 使用,包括网络、数据库、分析、机器学习、监控、存储等,如图 14.2 所示。

图 14.2 Anthos GKE 环境可用的解决方案
解决方案根据许可模式进行分类:开源、付费或“自带许可证”(BYOL)。BYOL 是一种许可模式,允许企业灵活地使用其许可证,无论是在本地还是在云端。
截至 2023 年 3 月,大约有 70 种解决方案已针对 GKE on-prem 环境进行了测试。我们可以通过向搜索选项添加适当的过滤器部署-env:gke-on-prem,如图 14.3 所示,来查看本地解决方案。截至 2023 年 3 月,已有 93 种解决方案针对 Anthos 环境进行了测试。

图 14.3 Anthos GKE-on-prem 环境可用的解决方案
在浏览市场中的解决方案时,您可以通过寻找列表中附带的“与 Anthos 兼容”标志来识别与 Anthos 兼容的第三方解决方案。在图 14.4 中,您可以看到带有小 Anthos 按钮的解决方案。此按钮展示了经过认证可与 Anthos 一起工作的解决方案。这些列表符合 Anthos Ready 计划的要求(cloud.google.com/anthos/docs/resources/anthos-ready-partners),该计划确定了遵守 Google Cloud 互操作性要求的合作伙伴解决方案,并经过验证可与 Anthos 平台一起工作,以满足企业客户的基础设施和应用开发需求。为了符合条件,合作伙伴提供的解决方案必须完成、通过并维护集成要求,以获得“与 Anthos 兼容”徽章。

图 14.4 Anthos 环境可用的解决方案
如果你选择了一个经过 Anthos 认证的提供产品,你将在所选提供产品的详细信息屏幕中看到“与 Anthos 兼容”的标志,如图 14.5 所示。

图 14.5 一个经过认证“与 Anthos 兼容”的示例解决方案
公共市场为各企业提供由 NetApp、Aqua、JFrog 和 Citrix 等不同供应商提供的多个应用程序的快速部署。但如果你想要为你的开发者添加自己的解决方案呢?当然,你可能不希望这个解决方案包含在公共市场中,而 Google 通过提供私有市场来满足这一需求,我们将在下一节中讨论。
14.1.2 服务目录
服务目录为私有企业提供市场功能,以便内部使用,而不将其内部暴露给世界上的其他人。管理员可以在组织、文件夹和项目级别管理应用程序的可见性和部署权限。部署经理可以根据企业政策定义预设配置,例如部署区域、用于部署的服务器类型、部署权限和其他参数。

图 14.6 访问服务目录
您可以通过云控制台导航菜单下的工具访问服务目录(见图 14.6)。从那里,您可以创建新的私有市场、添加应用程序和配置访问权限。每个服务目录应由一个 GCP 项目托管,您可以在文件夹和项目级别添加目录 IAM 权限。与 GCP 组织、文件夹或项目共享目录允许客户与其最终用户共享他们的解决方案。步骤非常直观,感兴趣的读者可以在网上找到更多信息(cloud.google.com/service-catalog)。
14.1.3 在 GKE on-prem 集群上部署
如果您打算将市场中的解决方案部署到 Anthos GKE 本地集群,那么您需要在目标集群上定义一个或多个命名空间,并使用 Secret 注解它们,这将允许您部署所选的解决方案。以下步骤是必需的:
-
如果您的集群运行 Istio,则默认情况下会阻止对第三方服务的任何外部连接,因此配置 Istio 出站流量以允许连接到外部操作系统软件仓库非常重要(参见第四章)。
-
您需要通过创建允许访问 marketplace.gcr.io 的防火墙或代理规则来允许从 Google 容器注册库下载镜像。
-
在您的 GKE on-prem 集群中,您可能需要创建一个 Google Cloud 服务账户。这可以通过类似以下方式的云壳完成:
gcloud iam service-accounts create sa-name \ --description="sa-description" \ --display-name="sa-display-name" -
使用令牌或具有 Kubernetes 集群管理员角色的 Kubernetes 服务账户凭据登录到您的 Anthos GKE 本地集群。(角色在第三章中讨论过。)这将允许您对任何资源执行任何操作的超用户访问权限。
从控制台,您可以通过运行以下命令生成一个新的公钥/私钥对并将其下载到您的机器上:
gcloud iam service-accounts keys create ~/key.json \ --iam-account sa-name@project-id.iam.gserviceaccount.com -
如果您是第一次从云市场部署,请通过运行以下命令在您的集群中创建一个应用-system 命名空间:
kubectl create namespace application-system -
然后,创建包含应用-system 的 imagePullSecret 的 Kubernetes Secret:
JSON_KEY_FILENAME=path_to/service_account_key.json IMAGEPULLSECRET_NAME=gcr-json-key kubectl create secret docker-registry $IMAGEPULLSECRET_NAME \ --namespace="application-system" \ --docker-server=gcr.io \ --docker-username=_json_key \ --docker-password="$(cat $JSON_KEY_FILENAME)" -
下一步是将 imagePullSecret 应用到应用-system 命名空间中的默认服务账户:
kubectl patch sa default -n application-system -p '"imagePullSecrets": [{"name": "gcr-json-key" }]' -
最后,对于您想要在其中部署应用程序的每个命名空间,您必须创建一个新的 Secret,并使用以下命令将命名空间注解为该 Secret:
JSON_KEY_FILENAME=path_to/service_account_key.json IMAGEPULLSECRET_NAME=gcr-json-key kubectl create secret docker-registry $IMAGEPULLSECRET_NAME \ --namespace=$NAMESPACE_NAME \ --docker-server=gcr.io \ --docker-username=_json_key \ --docker-password="$(cat ~/$JSON_KEY_FILENAME)" kubectl annotate namespace $NAMESPACE_NAME marketplace.cloud.google.com/imagePullSecret=$IMAGEPULLSECRET_NAME -
一旦按照上一步所述定义了 $NAMESPACE_NAME,此命名空间就可以用于在您的本地集群上安装。
换句话说,在 Anthos 上部署,无论是在 GCP 上还是在本地,只需在您的目标 Kubernetes 集群上定义适当的命名空间,并用用于拉取解决方案镜像的 Secret 密钥注解该命名空间即可。
在下一节中,我们将介绍如何安装属于不同类别的几个预定义解决方案,包括现代化工具、数据库、监控和日志、CI/CD、生产力和机器学习。
14.2 实际场景
在本节中,我们简要介绍了如何在 Anthos 上部署可用的 Marketplace 解决方案。我们的示例故意具有异质性,并属于不同的类别。请注意,在您从 Cloud Marketplace 启动部署后,您可以使用 Google Cloud 工具查看、修改和监控您的部署。例如,您可以使用 Cloud Deployment Manager 向部署添加资源或删除不再需要的软件部署。
14.2.1 示例 1:Elasticsearch
Elasticsearch 是一个开源解决方案,用于实时搜索和分析您的数据。此解决方案可以本地部署,但此示例展示了在 GKE 上的部署。解决方案(参见图 14.7)可在 mng.bz/Q8OQ 获取。

图 14.7 部署 Elasticsearch 解决方案
选择解决方案后,您可以选择部署的集群和命名空间(参见图 14.8)。在这种情况下,我们保留默认选择,它将在 us-central-1 区域的集群上安装,实例名称为 elasticsearch-1,并有两个副本。

图 14.8 部署 Elasticsearch 解决方案
创建集群可能需要几分钟(参见图 14.9),这总是喝杯咖啡并让 Marketplace 做所有工作的好理由。

图 14.9 为新的 Elasticsearch 解决方案创建集群
一旦集群创建完成,Marketplace 将开始部署解决方案(参见图 14.10)。

图 14.10 部署 Elasticsearch 解决方案的应用程序组件
当部署成功执行后,您可以在选择的集群中看到已部署的解决方案,如图 14.11 所示——确实很简单。Marketplace 节省了您大量时间,并加快了维护 Anthos 应用程序所需的行政任务。

图 14.11 已部署的 Elasticsearch 解决方案
一旦从 Marketplace 部署了 Elasticsearch,您可以使用 Anthos 来管理集群。在图 4.12 中,您将看到 CPU、内存和磁盘的详细信息。

图 14.12 从 Marketplace 部署的 Elasticsearch 的 CPU、内存和磁盘监控
14.2.2 示例 2:MariaDB
现在,让我们关注如何部署 MariaDB,这是一个流行的开源数据库,它在 2009 年被 Oracle 收购后,从更受欢迎的 MySQL 关系型数据库管理系统分支出来。该解决方案(见图 14.13)可在 console.cloud.google.com/marketplace/details/google/mariadb 获取。

图 14.13 部署 MariaDB 解决方案
在这种情况下,我们决定更改默认参数,并需要更多的副本数——两个(见图 14.14)。

图 14.14 使用更多副本数部署 MariaDB 解决方案
我们部署的结果很简单(见图 14.15)。再次强调,Marketplace 允许我们在管理 Anthos 集群时节省时间。

图 14.15 部署的 MariaDB 解决方案
一旦从 Marketplace 部署了 MariaDB,您就可以使用 Anthos 来管理集群。图 14.16 展示了检查集群和运行中的 Pods 的示例。

图 14.16 检查从 Marketplace 部署的 MariaDB 解决方案
14.2.3 我们到目前为止所做的工作
到目前为止,我们在 GKE 的 Anthos 集群上安装了两个应用程序。如果我们想检查它们的状态,我们可以通过应用程序访问我们的 GKE,如图 14.17 所示。

图 14.17 通过 Marketplace 部署的解决方案
14.2.4 示例 3:Cassandra
Cassandra 是一个 NoSQL、高度可扩展、高性能的分布式数据库,具有高可用性。部署 Cassandra 集群非常简单。您可以通过 console.cloud.google.com/marketplace/details/google/cassandra?q=anthos (图 14.18) 访问该解决方案。

图 14.18 部署 Cassandra 解决方案
安装完成后,您可以访问和管理您的已部署解决方案。例如,您可能对监控特定时间段内的 CPU、内存和磁盘使用情况感兴趣,如图 14.19 所示。

图 14.19 管理 Cassandra 解决方案
14.2.5 示例 4:Prometheus 和 Grafana
一旦您理解了机制,安装新的解决方案就是一个简化的过程。例如,假设我们想要安装一组更复杂的应用程序,这些应用程序可以协同工作。一个经典的例子是 Prometheus 和 Grafana。Prometheus 是一个开源的监控和警报平台,许多公司将其作为监控工具采用,而 Grafana 提供了几个仪表板,这些仪表板可以可视化 Prometheus 服务器收集的指标。该解决方案可通过 console.cloud.google.com/marketplace/details/google/prometheus?q=anthos 访问,如图 14.20 所示。

图 14.20 部署 Prometheus 和 Grafana 解决方案
让我们使用图 14.21 所示的默认参数来部署解决方案。

图 14.21 使用 Prometheus 和 Grafana 解决方案的默认参数
部署完成后,我们可以在应用程序详情中看到可用的解决方案,如图 14.22 所示。

图 14.22 Prometheus 和 Grafana 部署的解决方案
当然,你可以像图 14.23 所示的那样使用 Anthos 来管理已部署的解决方案。

图 14.23 管理 Prometheus 和 Grafana 解决方案
一旦解决方案部署完成,你就可以在 Prometheus 时间序列数据库中开始记录实时指标。然后你可以使用 Grafana 创建仪表板并监控你的系统性能。
这个例子结束了本节。值得注意的是,Grafana 可以通过市场单独部署,并且支持在 Anthos 中使用,因此它可以与托管 Prometheus 兼容。
摘要
-
公共和私有市场都可以用来为开发者部署简单和复杂的工作负载。
-
公共 Google 市场是 Google 提供的一项服务,其中包含多个供应商解决方案,包括针对 Kubernetes 的解决方案,无论是在 GCP 还是本地。
-
私有 Google 市场允许公司为其内部开发者提供私有解决方案,使公司能够提供与 Google 在公共市场中提供的相同部署简便性。
-
在本地消费市场解决方案需要额外的设置步骤,而 GCP 集群则不需要。
-
我们部署了一些市场解决方案来展示在现实世界中部署工作负载是多么简单,使用的是提供的解决方案。
15 迁移
安东尼奥·古利
本章涵盖
-
使用 Migrate for Anthos 的好处
-
推荐迁移的工作负载
-
Migrate for Anthos 架构
-
使用 Migrate for Anthos 迁移工作负载
-
Migrate for Anthos 的最佳实践
与虚拟机(VMs)相比,容器为开发者提供了多项优势,包括部署和配置工作负载时的速度加快、资源利用率更高、可移植性和成本效益,以及更高的效率。
然而,许多客户在过去的几年中在虚拟机基础设施上使用遗产框架编写了数千个应用程序。对于这些客户来说,重写他们的应用程序将耗费太多时间和金钱。因此,他们需要工具来现代化工作负载,并在不从头开始重写应用程序的情况下提供现代云原生环境的好处。整个价值主张是减少客户在转型项目中的上市时间,并通过现代云基础设施和服务增强和优化传统工作负载。
Google 认为,现代化不一定是全有或全无。微服务架构将应用程序结构化为一系列高度可维护和可测试的服务集合,通过 API 松散耦合,并可独立部署。然而,即使您最初没有使用微服务架构,您也可以将您的应用程序转换为容器,并仍然能够利用云原生应用程序通常获得的好处。这正是本章将要展示的内容。
Migrate for Anthos(简称 M4A)是一个工具,它帮助您从虚拟机中提取遗留工作负载,并将它们转换为容器,包括执行所需的所有内容——运行时、系统工具、库、代码、配置和设置。一旦您的应用程序迁移完成,您就可以在 Anthos 上运行它,无论是在 Google 的 Kubernetes Engine(GKE)上、本地还是在其他云中。这样,基础设施、硬件和操作系统/内核的管理就被“抽象化”并委托给您的云提供商(们)。
此外,M4A 生成使您能够切换到使用 CI/CD 管道的现代软件开发的艺术品,并从包管理转移到基于容器/镜像的管理。您可以将 M4A 视为现代化最终目标的加速器,这种加速可以在规模上发生,许多遗留应用程序可以一起大量迁移。M4A 可以通过现代化底层计算基础设施、网络、存储和管理,以规模的方式让您操作数千个遗留应用程序。
M4A 支持将 Linux 和 Windows 迁移到容器。源环境可以包括 GCP 计算引擎环境、VMware vSphere 环境、Microsoft Azure 虚拟机环境或 Amazon 弹性计算云(Amazon EC2)环境。所有工作负载都直接迁移,无需访问原始源代码、重写工作负载或手动容器化工作负载。
大部分迁移工作都是自动完成的,你可以修改生成的迁移计划以微调所需的现代化。在迁移过程执行期间,应用程序可以继续不间断地运行,你可以在几分钟内启动运行容器化应用程序。如果你想回到初始状态,你可以回滚而不会丢失数据。由 M4A 生成的迁移工作负载容器镜像会自动部署到 Google 容器注册库(GCR)或其他本地存储库,并且可以在任何环境中运行,无需你在目标工作负载集群上安装 M4A 组件。当然,整个 M4A 流程都可以通过 Google Cloud 控制台 UI 来执行和监控。
既然我们已经设置了上下文,让我们详细看看 M4A 的好处。
15.1 迁移至 Anthos 的好处
M4A 允许我们从虚拟机内部解包越来越多的基础设施,并用 Kubernetes 来管理它。这种现代化将应用程序管理与现代 IT 技能统一起来。确实,在本章详细描述的众多案例中,可以将遗留应用程序提升为云原生环境中的第一类对象,而无需更改或访问代码。规模化的解锁改进如下:
-
使用声明性 API、动态扩展、自我修复和程序化部署来定义基础设施。
-
利用数据中心提高的工作负载密度,从而实现更好的资源利用率。
-
维护基础设施指标、业务指标、网络策略和项目访问控制。
-
集成 CI/CD 管道和构建系统。
M4A 的好处在不同领域透明获得:密度、成本、安全性、基础设施、自动化、服务管理和第二天运营。让我们更详细地讨论每一类。
15.1.1 密度
虚拟机从底层物理硬件中抽象出来。而传统的裸金属服务器只能支持单个应用程序,虚拟化管理程序¹ 允许多个虚拟机的应用程序在单个裸金属服务器上运行,共享底层资源。裸金属的使用在此描述:
-
通常,裸金属利用率在 5%-15%,而虚拟机可以将利用率提高到 30%。
-
容器通过在同一个虚拟机或裸金属服务器上运行多个容器来提高工作负载密度。此外,由于操作系统/内核、网络和存储等抽象化,正如本章前面所讨论的,密度也增加了。
实际的利用率提升将取决于您环境中的一些特定因素。通常,许多组织在从物理服务器迁移到虚拟机,再到容器时,会报告显著的收益。例如,《金融时报》的内容平台团队报告说,通过采用容器,服务器成本降低了 80%(见mng.bz/mJ0P)。
15.1.2 成本
密度的增加会导致基础设施成本立即降低。如前所述,密度的增加是由两个事实造成的:多个容器可以打包在同一台物理机器上,许多软件层被抽象化,这导致了对可用资源的更好利用,需要更少的服务器,从而实现总体成本节约。成本是能够弹性扩展的副产品。如果需求低,则可以减少资源,从而节省运营成本。
此外,迁移后,遗留应用程序与云原生应用程序一起被提升为第一类公民。作为副作用,您不需要维护两个工作环境(既包括遗留的也包括现代的),因此,工作负载的统一管理允许在规模上进一步降低成本。
如果您想了解更多关于成本降低的信息,请查看 Google Cloud 定价计算器cloud.google.com/products/calculator,以估算您的月度费用,包括集群管理费和 GKE 的工作节点定价。
15.1.3 基础设施
将应用程序迁移到容器后,您可以以代码的形式看到整个基础设施,了解应用程序、进程和依赖项是如何协同工作的。任何基础设施的变化都可以存储在仓库(简称 repo)中,对基础设施的任何部分(包括配置文件)都可以应用操作,如提交、推送、拉取、合并和分支。传统上,维护基础设施是企业的一项重大成本。转向基础设施即代码允许团队实施 DevOps/SRE 方法,这由于提高了灵活性和可靠性,从而在规模上进一步节约成本。
15.1.4 自动化
由于需要手动或使用大量第三方工具修补和升级基础设施,因此管理虚拟机是一个昂贵、耗时且容易出错的过程,这可能会增加复杂度。Anthos 是现代化和促进将遗留工作负载迁移到容器的推动者,这对成本有间接影响。例如,在 Anthos 的 GKE 上,许多操作都是代表客户自动运行的,包括以下内容:
-
节点自动修复——保持您的 Kubernetes 集群中的节点处于健康、运行状态。
-
节点自动升级——当您的集群主版本更新时,保持您的 Kubernetes 集群中的节点与集群主版本保持最新。
-
节点自动安全——安全补丁可以以透明的方式自动部署。
-
节点自动扩展—根据瞬时负载的增加/减少动态扩展您的 Kubernetes 节点。
-
节点自动配置—代表用户自动管理一组 Kubernetes 节点池。
-
渐进式发布/金丝雀/A/B 测试—在 Kubernetes 集群上以编程方式部署应用程序,在出现问题时进行回滚。
按照惯例,增加您基础设施中的自动化程度将降低意外错误的风险,提高整个系统的可靠性,并降低成本。
15.1.5 安全
一旦迁移到容器,就可以简化多个安全操作。在 Anthos 上,这些操作包括以下内容:
-
安全优化的节点内核和操作系统更新—Anthos 为工作节点提供自动操作系统升级和内核补丁,让您摆脱维护操作系统的负担,如果您的服务器群很大,这会是一笔巨大的成本。虚拟机必须运行完整的客户操作系统,即使它们只托管单个应用程序。相反,容器减少了运营成本,因为不需要运行操作系统。
-
二进制授权和容器分析—Anthos 提供部署时的安全控制,确保只有受信任的容器镜像被部署到您的环境中。
-
零信任安全模型—在第四章中介绍的 Anthos Service Mesh(ASM)和 Kubernetes 的核心功能使我们能够在不更改应用程序代码的情况下提供网络隔离和 TLS 安全。
-
基于身份的安全模型—使用 ASM,您可以获得安全见解、安全策略和政策驱动的安全。这些案例在第四章中详细讨论。
透明地提高安全性将降低事件发生的风险及其相关的高昂成本。
15.1.6 服务管理
迁移到容器后,您可以使用 Anthos Service Mesh(见第四章)来确定您的服务连接在哪里,并在不更改代码的情况下获取应用程序的遥测和可见性。在 Anthos 上透明获得的以下好处:
-
加密—应用程序可以无需更改代码即可使用端到端加密进行通信。
-
集成日志和监控—您可以在应用程序中获得统一的指标和流量流日志。
-
统一可观察性—您可以从端到端观察服务依赖关系,了解关键客户旅程及其如何影响您的服务级别协议(SLA²)。您通过在应用程序上设置服务级别目标(SLO³)来完成此操作。
-
操作敏捷性—您可以在环境中动态迁移流量和执行断路器,⁴ 重试,金丝雀⁵,以及 A/B 测试。以金丝雀为例,您可以根据权重,将一定量的流量从一个服务移动到该服务的较新版本。
-
桥接—您可以使用服务网格在本地和多个云之间桥接流量。
通常情况下,采用服务网格将增强您对基础设施的理解,随着时间的推移,这可能变得相当复杂。
15.1.7 第二天运营
Anthos 减轻了第二天运营的负担。一旦您的应用程序迁移完成,您就可以享受许多 Google Cloud Platform (GCP)的能力,例如以下内容:
-
云日志和云监控—云日志允许您存储、搜索、分析、监控和警报来自 Google Cloud 的日志数据和事件,而云监控提供了对云应用程序性能、正常运行时间和整体健康状况的可见性。迁移后,这两个服务仅通过配置更改即可使用。
-
统一策略和集成资源管理—Anthos 通过 Anthos Config Management 提供声明式期望状态管理,这在第十一章中有详细说明。声明式意味着用户仅定义所需的最终状态,而 Anthos 负责定义实现更改的优化步骤。Anthos Config Management 允许您通过高级标记策略和选择策略,在所有环境中自动化和标准化安全策略和最佳实践。作为用户,您将有一个单一的 UI 来定义统一策略的创建和执行(第十三章)。
-
使用 Cloud Build 实现第二天维护程序—Cloud Build 提供了定义跨多个环境和多种语言的构建、测试和部署的定制工作流的控制。
-
CI/CD 流水线—Anthos 集成了 CI/CD 流水线,以增强您环境的敏捷性。这使得您能够进行更小的代码更改,更快地完成功能更改,缩短发布周期,并更快地进行故障隔离。
-
GCP Marketplace—Anthos 集成在 GCP Marketplace 中,包括服务目录,可以一键部署新应用程序。这将在第十四章中详细说明。
M4A 最重要的好处之一是,传统应用程序被提升为第一类对象,在第二天运营方面的好处与在云原生环境中通常期望的相同。
在本节中,我们讨论了使用 Migrate for Anthos 来现代化现有 VM 工作负载并自动容器化您的应用程序(无需重写)的好处。正如所讨论的,容器化应用程序由于比 VM 需要更少的管理时间,因此可以提高灵活性和效率。此外,它们提供了更高的基础设施密度和相关的成本降低。最后,容器化应用程序可以从服务网格中受益,包括可观察性、第二天运营流程简化以及跨环境的统一策略管理和执行。
在下一节中,我们将深入探讨哪些工作负载最适合迁移。
15.2 推荐的迁移工作负载
将应用程序现代化以适应云可能很困难。复杂的应用程序通常是多层的,并且通常具有多个依赖项。数据具有重力,迁移可能依赖于大量数据,无论是文件还是数据库。遗留应用程序可能是在过时的代码和遗留框架中编写的,并且在许多情况下,代码本身可能无法在现代环境中重新编译。在本节中,我们讨论以下类型的应用程序,这些应用程序特别适合自动迁移:
-
无状态 Web 前端—一个合适的类别包括无状态应用程序,如 Web 服务器和类似的应用程序,它们服务于客户流量。容器通常比虚拟机更轻量级,因此根据各种负载情况上下扩展它们更容易。
-
多虚拟机、多层堆栈和业务逻辑中间件—在这个类别中包括多层 Web 服务堆栈,如 LAMP(Linux、Apache、MySQL、PHP/Perl/Python)或 WordPress,因为它们可以被分解成多个独立的容器。此外,还包括 Java Tomcat 和其他 COTS(现成商业)应用程序。在 M4A 术语中,我们通常说,最佳应用类别包括多层 Web 企业应用程序。
-
中等至大型数据库—支持如 MySQL、Postgres 和 Redis 等数据库;数据层通常可以与计算层分离,因此容器可以帮助管理轻量级计算。
-
低负载周期和突发工作负载—在任何计算活动间歇性上升和下降的情况下,容器都是首选解决方案,因为它们比虚拟机更轻量级。因此,在需要快速设置 Dev/Test 环境、培训环境或实验室时,应考虑 M4A。
总体而言,我们可以这样说,理想的迁移候选者包括以下内容:
-
通过完整重写进行现代化改造要么不可能,要么成本过高的工作负载
-
具有未知依赖项的工作负载,如果被触及可能会破坏某些内容
-
虽然得到维护但不是积极开发的工作负载
-
已不再维护的工作负载
-
没有源代码访问的工作负载
有时可能很难实现自动迁移。如果存在对特定内核驱动程序或特定硬件的依赖,或者如果软件许可证需要绑定到某些硬件或虚拟机,则情况如此。另一个相关的情况是,基于虚拟机的工作负载需要整个 Kubernetes 节点容量,包括高性能和高内存数据库(如 SAP HANA)。除了这些特定情况外,所有其他工作负载都应考虑从虚拟机迁移到容器。
在本节中,我们快速回顾了适合迁移的相关工作负载。在接下来的几段中,我们将讨论迁移架构和一些迁移的实例。
15.3 M4A 架构
在本节中,我们将讨论一个典型的迁移工作流程以及虚拟机如何转换为几个不同的容器。迁移完成后,生成的工件可以在任何地方运行。在出现故障的情况下,工具会报告详细的调试和检查动机。
注意:您不再需要在目标集群上安装迁移组件。
15.3.1 迁移工作流程
迁移包括三个阶段:设置、实际迁移和优化(见图 15.1)。让我们更详细地看看每个步骤。

图 15.1 Anthos 的设置和迁移
在设置阶段,会创建一个处理集群,并定义迁移源。在支持的迁移源中,包括 VMware、AWS EC2、Azure VM、GCE VM、裸金属和本地 VMware。截至 Anthos Migrate 1.9 版本,支持的迁移操作系统有 RHEL、CentOS、SUSE、Ubuntu、Debian 和 Windows。列表始终在扩展,因此建议在线查看最新列表(见 mng.bz/51Gz)。
在设置阶段,我们需要设置云着陆区,考虑到身份、网络配置、安全和计费。一些工具可以帮助使基础设施即代码任务更加自动化,包括 Cloud Foundation Toolkit (cloud.google.com/foundation-toolkit) 和 Terraform (www.terraform.io/)。这些模板可以直接使用,以快速构建一个可重复、企业级的基础设施,具体取决于您的特定需求。此外,在设置过程中,您需要发现您想要迁移的工作负载。期望的工作负载可以通过手动方式或通过发现工具如 StratoZone (www.stratozone.com/; 现已被 Google 收购)、modelizeIT (www.modelizeit.com/)、Cloudamize (www.cloudamize.com/en/home/) 或 CloudPhysics (www.cloudphysics.com/) 来识别。自 M4A 1.5 版本以来,已包含原生发现工具,将在下一节中介绍。
在迁移阶段,运行 M4A 并自动生成新的容器镜像,包括 Dockerfile、数据卷和新的 YAML 部署文件。我们将在下一节中看到这些细节,其中我们将涵盖命令行界面(CLI)和图形用户界面(GUI)过程。一旦这些工件自动生成,您就可以在 GKE/Anthos 或其他云中进行测试,如果一切看起来都很好,您可以将它们部署到 GKE/Anthos。值得注意的是,数据作为迁移过程的一部分自动移动和同步。
Anthos 支持实时迁移,这意味着应用程序可以在没有任何中断的情况下迁移到现代环境。在幕后,M4A 为源虚拟机创建了一个快照,并且这个源虚拟机被留下运行和操作,无需停机。与此同时,所有存储操作都在该虚拟机快照上进行。所有工作负载都直接迁移,无需原始源代码。
在优化阶段,部署的艺术品可以根据您的特定偏好与 CI/CD 平台集成,例如 Cloud Build、GitHub、Jenkins (www.jenkins.io/)、Spinnaker (spinnaker.io/)、GitLab CI/CD (docs.gitlab.com/ee/ci/) 等(参见第十二章)。
15.3.2 从虚拟机到容器
一个典型的虚拟机由多个层组成(参见图 15.2 左侧)。在最上面是用户运行的应用程序,以及 cron 作业、配置文件和用户数据。紧接着是多个服务,包括在用户空间运行的服务和 SysV 或 Systemd⁶ 服务。然后,一个日志和监控层位于操作系统内核和操作系统驱动程序之上。在最底层是虚拟硬件,包括网络、具有各种文件系统上的逻辑卷的存储、CPU 和内存。

图 15.2 Anthos Migrate:从虚拟机到容器
对于每个应用程序,M4A 以 Docker 镜像、Dockerfile 和部署 YAML 文件的形式生成 CI/CD 艺术品,包括应用程序、用户服务和持久卷(参见图 15.2 右侧)。特别是,存储被重构为 Kubernetes 支持的持久卷。常见的功能,如网络、日志和监控,以及操作系统内核和驱动程序都被抽象化并委托给 Kubernetes 管理。持久卷是通过 Migrate for Anthos 容器存储接口(CSI)驱动程序挂载的(参见附录 D)。然后数据直接从源虚拟机文件系统流式传输。内部,Migrate 还负责生成命令行输入和客户资源定义(CRD⁷)。从逻辑上讲,迁移在容器化镜像中产生两层:第一层是捕获的用户模式系统,而第二层是迁移的运行环境,包括所有必要的 CRDs。然而,迁移后,您不需要维护第二层,生成的艺术品可以在任何符合 Kubernetes 的发行版上运行。⁸
Kubernetes 环境中对于应用程序非必要的 VM 相关文件和组件被明确排除。实际上,这种排除意味着好处。正如讨论的那样,与虚拟机相比,容器由于其轻量级特性,可以实现更高的密度和成本降低。应用程序生命周期保持在系统容器内。一旦迁移,应用程序可以在任何 Anthos 环境中运行(本地、GCP 等),或者独立于 M4A 部署在符合 Kubernetes 标准的任何发行版上。
15.3.3 查看 Windows 环境
Migrate for Anthos 的 1.4+ 版本支持将工作负载从 Windows 服务器迁移到 GKE/Windows。与 Linux 环境一样,目标是自动化工作负载的重构,并将其集成到一个更现代的云环境中。到 2021 年底,从 Windows Server 2008r2 到 Windows Server 2019 的所有 Windows 服务器平台都可作为目标。目前,仅支持 GCE 作为 Windows 应用程序现代化的源,计划在下一个版本中直接支持本地 VMware、AWS 和 Azure。然而,您可以使用 Migrate for Compute Engine(有时称为 Migrate to Virtual Machines⁹)将来自其他源的 Windows VM 迁移或克隆到 Compute Engine,然后将生成的 VM 迁移到容器中。好消息是迁移后的 Windows VM 不必配置为在 Compute Engine 上运行。
在幕后,迁移是通过提取 ASP.NET 应用程序和 IIS 配置,并将它们应用于官方 Windows 2019 服务器镜像上实现的。M4A for Windows 与使用 IIS 7+、ASP.NET 开发的应用程序兼容良好,尤其是与 Web 和业务逻辑中间件。迁移的理想对象是无状态的 Windows Web 应用程序层、应用服务器和 Web 前端。
15.3.4 现代化旅程的全面视图
现在我们已经讨论了 Linux 和 Windows 工作负载的现代化旅程,我们提供了一个全面的视图,这还包括大型机(见图 15.3)。

图 15.3 完整的现代化旅程
如果源应用程序是现代应用程序,则它会被容器化,集成 CI/CD,并可以在 Anthos 上运行,与整个生态系统的集成可以促进进一步重构为微服务环境。如果源应用程序是 Linux 或 Windows 上的传统单体应用程序,则我们可以使用 M4A 来容器化它。
如果源应用程序是具有特定需求的 Linux/Windows 应用程序,无论是特定驱动程序还是遗留支持,那么仍然可以直接将虚拟机迁移到 GCP,无论是在裸金属(BMS;cloud.google.com/bare-metal)还是在 GCVE(Google Cloud VMware Engine;cloud.google.com/vmware-engine),之后手动将应用程序重构为微服务。
15.4 现实场景
在本节中,我们将回顾使用 M4A 的迁移实例。首先,我们将介绍迁移匹配评估工具(mng.bz/v1VM)。然后,我们将提供关于如何迁移 Linux 和 Windows 的实战演练。
15.4.1 使用匹配评估工具
在本节中,我们介绍了一个自助匹配评估工具,用于确定工作负载迁移到容器的适用性。该工具包括一个名为 mfit 的实用程序,这是一个独立的 Linux CLI 工具,用于驱动评估过程,以及专用的 Linux 和 Windows 数据收集脚本,这些脚本可以由 mfit 自动调用或根据场景手动调用。
匹配评估工具生成一份报告,展示预虚拟机评估结果,包括虚拟机迁移到容器的适用性分数以及解决各种障碍的建议。表 15.1 提供了可能的匹配分数的摘要。
表 15.1 匹配评估工具生成的匹配分数
| 匹配分数 | 描述 |
|---|---|
| 分数 0 | 优秀匹配 |
| 分数 1 | 匹配良好,但有一些可能需要关注的发现 |
| 分数 2 | 迁移前需要最小努力 |
| 分数 3 | 迁移前需要适度努力 |
| 分数 4 | 迁移前需要大量努力 |
| 分数 5 | 不匹配 |
| 分数 6 | 收集的数据不足以评估虚拟机 |
匹配评估过程
匹配评估过程包括三个不同的阶段:发现、评估和报告。接下来将详细介绍每个阶段:
-
发现—收集有关虚拟机数据并将其存储在本地轻量级数据库中,用于下一阶段(默认位于~/.mfit 文件夹)。以下两种数据发现方法:
-
(可选)虚拟机/库存级别发现—使用 mfit 工具通过 vSphere API 从一个或多个 vCenters 拉取虚拟机的库存和配置信息。fit 评估工具的后续版本将支持从公共云(如 GCP、AWS 和 Azure)拉取库存。此方法为可选,即使没有它,也可以执行匹配评估,尽管可能不够彻底。
-
虚拟机级别数据收集—包括在要评估的虚拟机内部运行数据收集脚本。fit 评估工具为 Linux 虚拟机提供 Bash 脚本,为 Windows 虚拟机提供 PowerShell 脚本。每个脚本都会收集有关操作系统配置以及正在运行的服务、进程、已安装的软件包等信息,并生成一个单独的存档文件,该文件将被 mfit *工具导入数据库,并在后续的评估阶段使用。运行收集脚本和导入数据的过程可以是手动或自动的,以下场景中使用 mfit 工具:
-
仅限 Linux—运行收集脚本并通过 SSH 收集结果。
-
vSphere 上的 Linux 和 Windows—运行收集脚本并使用 vSphere API 收集结果。
-
-
-
评估—使用 mfit 工具分析收集的数据,并为每个评估的虚拟机应用一套 fit 评估规则¹⁰。
-
报告—使用 mfit 工具生成报告,以 CSV、HTML 或 JSON 格式呈现评估结果。然后可以在 Google 的云控制台(
mng.bz/ydVq)中显示。
现在你已经知道了工具如何发现和报告工作负载,我们可以继续介绍如何使用该工具,以便你可以开始你的迁移之旅。
基本工具使用说明
下面是使用 fit 评估工具的基本概述。完整文档可在 mng.bz/41YV 查找。
注意,将 --help 添加到每个 mfit 命令将显示详细的命令使用说明,包括所有可能的标志和子命令。
安装
在撰写本文时,你可以使用以下命令在你的工作站上下载 mfit 工具(版本 1.9),该工作站用于驱动 fit 评估:
wget https://anthos-migrate-release.storage.googleapis.com/v1.9.0/linux/amd64/mfit
chmod +x mfit
库存发现
运行以下命令以在 vCenter 中发现所有虚拟机:
./mfit discover vsphere -u <vcenter username> --url <https://vcenter-host-name-or-ip>
注意:如果你的虚拟中心正在使用一个在运行 mfit 的机器上不受信任的证书,你可以添加 -i 选项来忽略 SSL 错误。
你将被提示输入 vCenter 密码,一旦执行,你将看到发现过程的摘要:
Running preflight checks...
[✓] DB Readable
[✓] DB Writable
[✓] Available Disk Space
[✓] Supported VC version
[+] Found 27 VMs
Collecting data...
27 / 27 [-------------------------------------------------------] 100.00% 13 p/s
你可能想知道实际上发生了什么,因为发现过程的输出有限,只告诉你预检查已通过,工具发现了 27 个虚拟机。这只是初始收集步骤,一旦收集完毕,你可以使用 mfit 工具评估和创建虚拟机的报告,我们将在手动收集过程解释之后介绍。
手动虚拟机级别数据收集
在撰写本文时,你可以使用以下命令在要评估迁移的虚拟机上下载 Linux 收集脚本:
wget https://anthos-migrate-release.storage.googleapis.com/v1.9.0/linux/amd64/mfit-linux-collect.sh
chmod +x mfit-linux-collect.sh
按照以下方式运行收集脚本:
sudo./mfit-linux-collect.sh
脚本将在当前目录下生成一个名为 m4a-collect-
对于 Windows 用户,在撰写本文时,您可以从以下 URL 下载要评估迁移的虚拟机上的 Windows 收集脚本:mng.bz/X5E6。
按照以下方式运行收集脚本:
powershell -ExecutionPolicy ByPass -File .\mfit-windows-collect.ps1
脚本将在当前目录中生成一个名为 m4a-collect-
导入收集的数据文件
在评估虚拟机上运行收集脚本后,通过任何方式将其下载到安装了 mfit 的工作站。然后,将其导入到 mfit 的本地数据库中:
./mfit discover import m4a-collect-<MACHINE NAME>-<TIMESTAMP>.tar/zip
自动客户端级别数据收集
mfit 包含嵌入的客户端收集脚本,可以在以下场景中自动运行它并检索结果。
VMware 工具
如果评估的虚拟机运行在 vSphere 上并且已安装 VMware 工具,mfit 可以使用 vSphere API 来自动执行收集脚本(适用于虚拟机操作系统类型的脚本)和检索结果。要通过 VMware 工具运行客户端级别收集,请运行以下命令:
./mfit discover vsphere guest -u <vcenter username> --url <https://vcenter-host-name-or-ip> --vm-user <vm username> <vm MoRef id or name>
您将被提示输入 vCenter 和 VM/OS 密码。
SSH
如果运行 mfit 的 Linux 机器可以访问评估的虚拟机 SSH,mfit 可以使用它来自动执行收集脚本和检索结果。要使用当前本地用户的 SSH 密钥(位于 ~/.ssh)通过 SSH 运行客户端级别收集,请运行以下命令:
./mfit discover ssh <vm-ip-or-hostname>
要使用附加的身份验证选项通过 SSH 运行客户端级别收集,请运行以下命令:
./mfit discover ssh -i </path/to/ssh_private_key> -u <remote-username> <vm-ip-or-hostname>
若要获取通过 SSH 运行客户端级别收集的附加选项,请参阅官方文档或运行 ./mfit discover ssh -help。
评估
要检查发现的虚拟机和收集的数据,请运行以下命令:
./mfit discover ls
要对此数据进行评估,请运行以下命令:
./mfit assess
这将创建一个评估结果并将其存储在 mfit 的本地数据库中,以便在生成报告时使用。
报告生成
一旦完成评估,我们就可以生成报告。要生成独立的 HTML 报告,请运行以下命令:
./mfit report --format html > REPORT_NAME.xhtml
要生成 JSON 报告,请运行以下命令:
./mfit report --format json > REPORT_NAME.json
然后,可以在 Google 云控制台中显示报告:mng.bz/Q8zj。
在本节中,我们讨论了用于确定工作负载是否适合迁移到容器的 fit 评估工具。一旦完成评估并选择了适合迁移的工作负载,我们就可以开始迁移过程本身。这就是下一节的主题。
15.4.2 基本迁移示例
在这个基本示例中,我们将使用命令行界面(CLI)在 GCE 上设置一个 Compute Engine 虚拟机,然后使用 M4A 将其迁移到 GKE 集群。请注意,我们需要创建另一个用于驱动迁移过程的 Kubernetes“处理集群”。处理集群将负责从虚拟机中拉取应用程序并生成所有容器化的工件。让我们开始吧。
首先,我们创建一个源虚拟机。在这个基本示例中,虚拟机将托管 Apache 网络服务器。可以使用以下命令创建虚拟机:
gcloud compute instances create http-server-demo --machine-type=n1-standard-1 --subnet=default --scopes="cloud-platform" --tags=http-server,https-server --image=ubuntu-minimal-1604-xenial-v20200702 --image-project=ubuntu-os-cloud --boot-disk-size=10GB --boot-disk-type=pd-standard
然后,让我们确保使用以下命令从互联网上可以访问虚拟机:
gcloud compute firewall-rules create default-allow-http --direction=INGRESS --priority=1000 --network=default --action=ALLOW --rules=tcp:80 --source-ranges=0.0.0.0/0 --target-tags=http-server
现在,我们可以使用 GUI(见图 15.4)登录到刚刚配置的虚拟机并安装 Apache:
sudo apt-get update && sudo apt-get install apache2 -y

图 15.4 连接迁移集群
现在我们有一个运行 Apache 网络服务器的源虚拟机。下一步是创建 Kubernetes 处理集群:
gcloud container clusters create migration-processing --machine-type n1-standard-4 --image-type ubuntu --num-nodes 1 --enable-stackdriver-kubernetes
接下来,让我们确保我们给处理集群正确的处理权限。我们需要为 M4A 创建一个特定的服务帐户,添加具有存储管理员权限的策略绑定,创建一个 JSON 密钥以访问处理集群,并获取处理集群的凭证。我们可以使用以下四个命令来完成此操作。请注意,named-tome-295414 是我的项目名称,您应该将其更改为与您的匹配:
gcloud iam service-accounts create m4a-install
gcloud projects add-iam-policy-binding named-tome-295414 --member="serviceAccount:m4a-install@named-tome-295414.iam.gserviceaccount.com" --role="roles/storage.admin"
gcloud iam service-accounts keys create m4a-install.json --iam-account=m4a-install@named-tome-295414.iam.gserviceaccount.com --project=named-tome-295414
gcloud container clusters get-credentials migration-processing
一旦我们有了凭证,我们就可以登录到处理集群并安装 M4A。让我们使用以下命令来完成此操作。请注意,m4a-install.json 是我们刚刚创建的 JSON 密钥:
migctl setup install --json-key=m4a-install.json
我们可以使用 migctl 检查部署是否成功:
migctl doctor
[✓] Deployment
之后,我们可以设置迁移源,包括特定的服务帐户 m4a-ce-src,迁移过程中所需的 compute.viewer 和 compute.storageAdmin 策略绑定,以及创建 JSON 密钥 m4a-ce-src.json:
gcloud iam service-accounts create m4a-ce-src
gcloud projects add-iam-policy-binding named-tome-295414 --member="serviceAccount:m4a-ce-src@named-tome-295414.iam.gserviceaccount.com" --role="roles/compute.viewer"
gcloud projects add-iam-policy-binding named-tome-295414 --member="serviceAccount:m4a-ce-src@named-tome-295414.iam.gserviceaccount.com" --role="roles/compute.storageAdmin"
gcloud iam service-accounts keys create m4a-ce-src.json --iam-account=m4a-ce-src@named-tome-295414.iam.gserviceaccount.com --project=named-tome-295414
一旦我们为源创建了凭证,我们可以使用以下命令来设置源。请注意,ce 代表 Google Compute Engine (GCE):
migctl source create ce http-source --project named-tome-295414 --json-key=m4a-ce-src.json
在创建迁移源之后,我们现在可以创建一个迁移计划来容器化我们的虚拟机:
migctl migration create my-migration --source http-source --vm-id http-server-demo --intent Image
如果您想查看迁移计划(例如,修改它),可以使用以下命令:
migctl migration get my-migration
然后,您就可以开始实际的迁移了:
migctl migration generate-artifacts my-migration
结果,您应该看到如下内容:
running validation checks on the Migration...
migration.anthos-migrate.cloud.google.com/my-migration created
一旦迁移开始,您可以使用以下命令检查进度。请注意,标志 -v 会提供详细的输出状态,这在出现问题时很有用:
migctl migration status my-migration
迁移完成后,您将看到类似于此处所示输出的内容:
NAME CURRENT-OPERATION PROGRESS STEP STATUS AGE
my-migration GenerateMigrationPlan [2/2] CreatePvcs Completed 11m23s
下一步是获取生成的工件:
migctl migration get-artifacts my-migration
一旦生成完成,您应该看到如下内容:
Downloaded artifacts for Migration my-migration. The artifacts are located in /home/a_gulli.
要访问迁移的工作负载,我们需要使用服务暴露 Pods。修改生成的 deployment_spec.yaml 以添加一个类型为 LoadBalancer 的服务将使我们能够通过端口 80 访问工作负载:
apiVersion: v1
kind: Service
metadata:
name: hello-service
spec:
selector:
app: http-server-demo
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
我们现在可以像这样在我们的 Kubernetes 集群上部署工件:
kubectl apply -f deployment_spec.yaml
deployment.apps/app-source-vm created
service/app-source-vm created
service/my-service created
检查一切是否顺利可能是有用的:
kubectl get service
结果,您应该看到如下内容:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app-source-vm ClusterIP None <none> <none> 44s
kubernetes ClusterIP 10.63.240.1 <none> 443/TCP 41m
my-service LoadBalancer 10.63.243.209 35.232.24.49 80:32417/TCP 43s
在这种情况下,外部 IP 地址是 35.232.24.49。现在我们可以打开浏览器并检查一切是否正常(见图 15.5)。

图 15.5 访问从虚拟机迁移到容器的网络服务器
恭喜!您已成功使用 CLI 将运行在 GCE 上的虚拟机迁移到运行在 GKE 上的容器。如果您想看到另一个基本迁移的示例,我们建议您考虑在mng.bz/X5jp提供的“迁移到容器:快速入门”动手实验室。
现在您已经知道如何使用 CLI 执行迁移,我们将进入下一节,我们将使用 Cloud console UI 来执行迁移。
15.4.3 Google Cloud 控制台 UI 迁移示例
在本节中,我们使用 M4A 将运行在 Google Compute Engine 上的虚拟机中的应用程序迁移到 GKE。当使用控制台 UI 时,Google Cloud 集群是唯一支持的环境,不是 AWS 或 VMware 上的 Anthos。GKE 处理集群可以在云中或本地。迁移将通过 Google Cloud 控制台的可用图形用户界面(GUI)运行。请注意,迁移过程在 CLI 和 GUI 之间是一致的。
将使用 GKE 集群作为“处理集群”来控制迁移。在迁移过程中生成的工件将存储在 Google Cloud Storage(GCS)上,最终的容器镜像将推送到 Google Container Registry。在底层,这与 CLI 驱动的迁移相同。
第一步是访问控制台中的 Anthos 迁移(见图 15.6),网址为mng.bz/Mlpn。

图 15.6 访问 Anthos 迁移到容器
为了简化,我们将从 Marketplace 部署一个预装 Tomcat 服务器的 VM。然后,我们将从 VM 迁移 Tomcat 到容器。
让我们从访问带有 Tomcat 的 Google Click to Deploy 仓库开始(见图 15.7)。URL 是console.cloud.google.com/marketplace/details/click-to-deploy-images/tomcat。

图 15.7 将 Tomcat 应用程序部署到虚拟机
然后,让我们选择我们想要部署的区域(见图 15.8)。

图 15.8 部署的 Tomcat 应用程序
一旦部署了带有 Tomcat 服务器的 VM,您可以从外部 IP 访问网站,如图 15.9 所示。

图 15.9 使用 Google Click to Deploy 部署的 Tomcat 解决方案
在此部署中,IP 地址是 http://35.238.48.196/,因此如果您访问网站,您应该看到图 15.10 中显示的输出。

图 15.10 使用网络浏览器访问 Tomcat
下一步是启动适当的迁移过程。首先,创建一个“处理集群”,这是一个将用于控制我们源虚拟机迁移的集群。您可以通过访问 Anthos 上的“迁移到容器”菜单并选择添加处理集群选项来完成此任务(见图 15.11)。

图 15.11 开始迁移过程
按照 GUI 提供的建议创建一个专门用于处理的新集群是很方便的(见图 15.12)。

图 15.12 为处理集群选择名称
一旦集群准备就绪,你应该能够在 GKE 部分中的 Google Cloud 控制台中看到它(见图 15.13)。

图 15.13 处理集群已准备好使用。
然后,你可以选择集群(见图 15.14)并选择目标是否为 Linux 或 Windows。

图 15.14 选择处理集群
在这一点上,我们需要确保处理集群具有适当的处理权限。为此,GUI 建议在云壳中运行一系列命令。你只需像图 15.15 所示点击运行云壳即可。

图 15.15 使用 UI 运行 M4A 所需的设置
让我们详细看看所需的步骤。首先,我们需要启用 Google Cloud API。然后,我们需要在容器注册库和云存储中创建一个服务帐户来存储迁移工件。然后,我们需要添加访问容器注册库和云存储的权限。最后,我们需要创建并导出一个新密钥到 M4A 使用服务帐户所需的文件。
完成这些步骤后,我们可以迁移到容器。同样,GUI 使这一步骤非常直观。最后一步是使用 migctl doctor 检查部署状态是否正确(见图 15.16)。

图 15.16 M4A 的正确部署
一旦配置了处理集群,请选择一个迁移源,从该源拉取虚拟机(见图 15.17)。

图 15.17 添加迁移源
目前,你可以从 GCE 拉取(见图 15.18)。(你还可以使用 Migrate for Compute Engine [mng.bz/eJav]将本地 vSphere 环境、AWS 和 Azure 导入 GCE。)

图 15.18 添加迁移源
一旦你选择了名称,你可以选择放置源虚拟机的项目(见图 15.19)。

图 15.19 选择放置源虚拟机的项目
现在处理集群和迁移源已经创建,我们可以开始迁移(见图 15.20)。

图 15.20 开始迁移过程
迁移需要一个名称、一个源、一个虚拟机操作系统类型、虚拟机 ID 和迁移意图。让我们通过 GUI 指定这些,如图 15.21 所示。

图 15.21 指定迁移名称、迁移源、虚拟机操作系统类型、虚拟机 ID 和迁移意图。
然后,M4A 将开始生成迁移计划(见图 15.22)。

图 15.22 生成迁移计划
在迁移过程中,我们可以使用以下命令检查进度,该命令将生成详细的调试日志:
migctl migration status my-migration -v
一旦生成迁移计划(见图 15.23),您可以使用 GUI 检查结果。

图 15.23 M4A 生成的迁移计划概述
尤其是选项菜单允许您编辑生成的迁移计划,如图 15.24 所示。

图 15.24 审查和编辑生成的迁移计划
让我们看看通过编辑迁移计划生成的结果,如图 15.25 所示。

图 15.25 编辑生成的迁移计划
通常,您不需要更改迁移计划。然而,如果您需要移除不必要的 VM 组件或需要添加一些额外的配置,那么能够这样做是有用的。在检查并必要时编辑迁移计划后,您可以开始生成工件(见图 15.26)。

图 15.26 使用编辑后的迁移计划生成工件
一旦生成迁移计划,您可以通过访问 Google Cloud 控制台中的工件选项卡来检查它们。这包括 Dockerfile、部署容器镜像(可以直接部署)、容器镜像基础层(不可运行的镜像层)、部署规范 YAML、迁移计划 YAML 以及工件链接 YAML(见图 15.27)。

图 15.27 生成的迁移工件
生成的工件存储在 GCS 中,基础层和镜像层分别使用不同的存储桶(见图 15.28)。

图 15.28 存储在 GCS 中的工件
现在我们来看带有 Dockerfile、部署规范、清单和迁移 YAML 的系统镜像(见图 15.29)。

图 15.29 Dockerfile、部署规范、清单和迁移文件
此外,为迁移生成的镜像会自动推送到 Google Container Registry,您可以通过控制台浏览它们,如图 15.30 所示。

图 15.30 用于迁移并推送到 GCR 的镜像
所有生成的工件都可以通过以下命令从 CLI 下载:
migctl migration get-artifacts my-migration
这些工件包括以下内容:
-
deployment_spec.yaml—配置您的负载
-
Dockerfile—用于构建迁移 VM 的镜像
-
migration.yaml—迁移计划的副本
Dockerfile 概述
在本节中,我们将深入探讨 M4A 生成的 Dockerfile。您可以编辑文件来自定义镜像,例如,用于安装新包或安装 M4A 运行时的升级版本。该文件包含运行时的原始容器仓库、包含从源虚拟机捕获的数据的镜像以及初始入口点。一个典型的 M4A Dockerfile 如下:
# Please refer to the documentation:
# https://cloud.google.com/migrate/anthos/docs/dockerfile-reference
FROM anthos-migrate.gcr.io/v2k-run-embedded:v1.5.0 as migrate-for-anthos-runtime
# Image containing data captured from the source VM
FROM gcr.io/named-tome-295414/tomcat-vm-gulli-vm-non-runnable-base:11-13-2020--15-0-39 as source-content
# If you want to update parts of the image, add your commands here.
# For example:
# RUN apt-get update
# RUN apt-get install -y \
# package1=version \
# package2=version \
# package3=version
# RUN yum update
# RUN wget http://github.com
COPY --from=migrate-for-anthos-runtime //
# Migrate for Anthos image includes entrypoint
ENTRYPOINT [ "/.v2k.go" ]
在本章讨论迁移后与 CI/CD 管道集成时,我们将在本章后面看到 M4A 生成的 Dockerfile 的更多细节。在下一节中,我们将讨论 deployment_spec.yaml 文件的详细信息。
deployment_spec.yaml 概述
在本节中,我们将讨论 M4A 生成的 deployment_spec.yaml。首先,让我们定义一些我们稍后将要使用的术语:
-
无状态—当服务器不存储有关客户端会话的任何状态时,应用是无状态的。换句话说,没有对过去事务的存储知识或引用。
-
有状态—当服务器存储有关客户端会话的数据时,应用是有状态的。换句话说,当前事务可能会受到之前事务发生的影响。因此,有状态的应用需要在每次处理用户请求时使用相同的服务器。
在这个背景下,让我们考虑 deployment_spec.yaml。这个文件将根据 UI 中选择的意图标志而有所不同,如下所述:
-
意图:镜像—YAML 定义了一个无状态应用,具有相同的 Pods 作为服务管理。¹¹ YAML 的不同部分如下:
-
部署—从您迁移的虚拟机生成的镜像中部署的一组相同的 Pods。它们存储在 GCR 中。
-
服务—将您的部署中的 Pods 组合成一个单一的资源,可以从稳定的 IP 地址访问。默认情况下,单个集群内部 IP 只能在集群内部访问,没有负载均衡。Kubernetes 端点控制器将修改 DNS 配置以返回指向 Pods 的记录(地址),这些 Pods 被标记为"
": " ",其中应用名称是从 migctl 迁移创建 my-migration 命令中推断出来的。请注意,默认情况下,Pods 只能在集群内部可见,因此,可能需要将 Pods 暴露在集群之外。我们将在本章后面看到一个示例。 -
日志配置—通过列出许多最常见的日志文件来配置将日志记录到云日志。
-
-
意图:镜像和数据—YAML 定义了一个具有与持久卷相关联的不同 Pods 的有状态应用。YAML 的不同部分如下:
-
StatefulSet—从您迁移的虚拟机生成的镜像中部署的一组 Pods。它们存储在 GCR 中。
-
服务—类似于在镜像部分定义的服务。
-
持久卷—用于管理持久存储。
-
持久卷声明—表示对持久卷资源(如特定大小和访问模式)的请求和声明。
-
日志配置—类似于为无状态定义的内容。
-
-
意图:数据—YAML 的不同部分如下:
-
持久卷—类似于为有状态定义的内容。
-
持久卷声明—类似于为有状态定义的内容。
-
下一个列表显示了典型的 M4A deployment_spec.yaml。
列表 15.1 M4A 生成的 deployment_spec.yaml
# Stateless application specification
# The Deployment creates a single replicated Pod, indicated by the 'replicas' field
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: tomcat-vm-gulli-vm
migrate-for-anthos-optimization: "true"
migrate-for-anthos-version: v1.5.0
name: tomcat-vm-gulli-vm
spec:
replicas: 1
selector:
matchLabels:
app: tomcat-vm-gulli-vm
migrate-for-anthos-optimization: "true"
migrate-for-anthos-version: v1.5.0
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: tomcat-vm-gulli-vm
migrate-for-anthos-optimization: "true"
migrate-for-anthos-version: v1.5.0
spec:
containers:
- image: gcr.io/named-tome-295414/tomcat-vm-gulli-vm:11-13-2020--15-0-39
name: tomcat-vm-gulli-vm
readinessProbe:
exec:
command:
- /code/ready.sh
resources: {}
securityContext:
privileged: true
volumeMounts:
- mountPath: /sys/fs/cgroup
name: cgroups
volumes:
- hostPath:
path: /sys/fs/cgroup
type: Directory
name: cgroups
status: {}
---
# Headless Service specification -
# No load-balancing, and a single cluster internal IP, only reachable from within the cluster
# The Kubernetes endpoints controller will modify the DNS configuration to return records (addresses) that point to the Pods, which are labeled with "app": "tomcat-vm-gulli-vm"
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
name: tomcat-vm-gulli-vm
spec:
clusterIP: None
selector:
app: tomcat-vm-gulli-vm
type: ClusterIP
status:
loadBalancer: {}
---
部署由 M4A 生成的容器
在本节中,讨论了部署由 M4A 生成的容器的步骤。部署 deployment_spec.yaml 非常简单:
migctl setup install --runtime
kubectl apply -f deployment_spec.yaml
因此,你应该看到类似这样的内容:
deployment.apps/tomcat-vm-gulli-vm created
service/tomcat-vm-gulli-vm created
如果你想,你可以检查已部署 Pods 的状态:
kubectl get pods
你应该看到类似这样的内容:
NAME READY STATUS RESTARTS AGE
tomcat-vm-gulli-vm-66b44696f-ttgq6 1/1 Running 0 21s
默认情况下,容器以无负载均衡和单个集群内部 IP 的方式部署,只能从集群内部访问。Kubernetes 端点控制器将修改 DNS 配置,以返回指向标记为"app": "tomcat-vm-gulli-vm"的 Pods 的地址。当然,你可以更改部署并添加一个类型为 LoadBalancer 的服务。让我们通过在部署规范中添加以下内容来实现这一点:
apiVersion: v1
kind: Service
metadata:
name: hello-service
spec:
selector:
app: tomcat-vm-gulli-vm
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
然后,让我们检查服务是否确实可访问:
kubectl get service hello-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-service LoadBalancer 10.88.10.207 34.67.239.170 80:32033/TCP 76s
图 15.31 显示了当我们尝试从互联网访问服务时发生的情况。

图 15.31 使用 M4A 迁移后访问 Tomcat 容器
恭喜!你现在拥有一个可路由的容器,它包含了之前在虚拟机中可用的完整 Tomcat 安装!迁移是自动发生的,无需重新编译或访问原始源代码。
在结论之前,这里有一个关于 GUI 的提示:如果你需要编辑多个文件,使用基于 Eclipse 的内置编辑器可能很方便。编辑器是快速轻松地审查和更改 M4A 生成的所有文件的一种方式(见图 15.32)。

图 15.32 用于操作迁移配置的内置编辑器
在结论之前的一个注意事项:除了 Google Container Registry 和 Google Cloud Storage 用于数据存储库之外,M4A 1.6 及以上版本支持包括 ECR、S3 和 Docker 注册表在内的其他存储库。在下一节中,我们将讨论 Windows 迁移。
15.4.4 Windows 迁移
在本节中,我们讨论如何将 Windows 虚拟机迁移到 GKE。请注意,Windows 迁移支持将计算引擎作为源。然而,如前所述,您可以使用计算引擎迁移(有时称为迁移到虚拟机;见mng.bz/pdj8)将来自其他源的 Windows 虚拟机迁移到计算引擎。然后,可以将生成的虚拟机迁移到 GKE。不出所料,Windows 迁移与 Linux 迁移类似。实际上,在幕后,M4A 使用一个名为 migctl 的统一 M4A CLI 工具。让我们通过 CLI 接口快速看一下示例。
首先,与 Linux 类似,您可以使用以下语句使用 migctl 添加迁移源:
migctl source create ce my-ce-src --project my-project --json-key=m4a-ce-src.json
请记住,my-ce-src 是源名称,my-project 是项目名称,m4a-ce-src.json 是创建用于作为迁移源使用计算引擎的服务账户后获得的 JSON 键文件名称。然后,您可以使用以下命令创建迁移
migctl migration create my-migration --source my-ce-src --vm-id my-id --intent Image -workload-type=WindowsIIS
其中 my-migration 是迁移的名称,vm-id 是计算引擎实例的名称,如 Google Cloud Console 中所示。可以使用以下命令检索刚刚创建的迁移计划:
migctl migration get my-migration
如果需要,您可以通过编辑文件 my-migration.yaml 来自定义迁移计划。编辑完成后,您可以使用以下命令上传编辑后的迁移计划:
migctl migration update my-migration
下一步是执行迁移并生成工件:
migctl migration generate-artifacts my-migration
在迁移过程中,您可以监控状态:
migctl migration list
迁移完成后,您可以访问工件:
migctl migration get-artifacts my-migration
结果,您应该看到类似以下内容:
Artifacts are accessible through 'gsutil cp gs://PATH/artifacts.zip ./'
因此,您可以使用以下命令获取工件:
gsutil cp gs://PATH/artifacts.zip ./
下一步是使用工件构建 Docker 镜像。我们可以使用 Windows PowerShell 展开 artifacts.zip:
Expand-Archive .\artifacts.zip
然后登录到容器注册表:
docker login gcr.io
下一步是使用以下代码片段构建容器:
docker build -t gcr.io/myproject/myimagename:v1.0.0 .\artifacts\
docker push gcr.io/myproject/myimagename:v1.0.0
当您为 Windows 工作负载生成工件时,工件将被复制到云存储桶中作为中间位置,您可以从中下载。此文件包含 Dockerfile、deployment_spec.yaml 文件以及来自源的一些目录,您可以使用这些目录构建 Windows 容器。构建完成后,容器镜像将被放置在容器注册表中,并且可以部署到 GKE 集群。请注意,自 M4A v1.5 版本起,Google Cloud Console for Anthos 已包含对 Windows 工作负载的支持。体验与之前讨论的 Linux 相同。如果您想看另一个 Windows 迁移的示例,请考虑在mng.bz/yd7y可用的“Migrate for Anthos: Windows”动手实验室。
15.4.5 从其他云迁移
截至 2021 年 11 月,从其他云迁移基于两步方法。首先,虚拟机被迁移(技术上,它们被转换为 GCE 实例)。然后,迁移的虚拟机被容器化。
M4A 使用 Migrate for Compute Engine (M4CE)(有时称为迁移到虚拟机;cloud.google.com/migrate/compute-engine)产品,将位于其他云或本地云上的虚拟机流式传输到 GCE 实例。Migrate for Compute Engine 可以通过市场(mng.bz/Mlao)安装,并允许从源平台(如 VMware、Microsoft Azure 和 Amazon EC2)迁移数千个应用程序到多个数据中心和云。
要使用 M4CE,您需要设置站点到站点的 VPN 连接和防火墙规则,以启用位于管理器所在 VPC 和位于另一云的源虚拟机 VPC 之间的通信。感兴趣的读者可能会发现cloud.google.com/vpc/docs/firewalls上的在线防火墙文档很有用。可以通过 GCP Cloud Router (mng.bz/0ygN) 在 Cloud VPN (mng.bz/aMro) 或专用高速 Cloud Interconnect (mng.bz/Klgj) 上设置基于 BGP 协议的动态路由(mng.bz/zmVB)。Cloud Interconnect 通过一个高可用、低延迟的连接将您的本地网络扩展到 Google 的网络。
此外,可以根据它们的逻辑角色将成千上万的虚拟机分批迁移,通过波次聚合它们。M4CE 允许我们定义运行手册来决定哪些虚拟机应该迁移以及迁移的顺序。在有效迁移之前可以计划一个模拟测试阶段。M4CE 的主要组件如下:
-
迁移管理器—用于编排迁移。管理器在单独的 Google Compute Engine 虚拟机上运行,并提供一个迁移控制台来管理和监控所有系统组件。请注意,管理器可能需要特定的权限来处理特定的操作,例如开启和关闭虚拟机。这些权限可以通过策略来定义。
-
云扩展—用于处理从源平台迁移的存储。扩展是迁移源和目标之间虚拟机存储的通道。这些扩展在单独的 Compute Engine 虚拟机上运行,并在迁移过程中本身为迁移的工作负载提供服务。请注意,扩展使用双节点主动/被动配置进行高可用性;每个节点提供服务,同时为另一个节点提供备份。
然后根据以下描述,在源平台上部署不同的组件:
-
在 vSphere 上—后端组件从 VMware 向 Google Cloud 的扩展提供运行时数据。然后,数据由 Compute Engine 上的虚拟机使用。此外,vCenter 插件将 vSphere 连接到迁移管理器,并在 vCenter 上编排迁移。
-
在 Amazon EC2 和 Azure 上—在运行时部署导入器,并将源数据从 Google Cloud 上的扩展服务中提供。然后,数据由 Compute Engine 上的虚拟机使用。
自 Migrate 1.9 以来,您还可以将容器部署到 GKE Autopilot 集群和 Cloud Run,但这个主题超出了本书的主题范围。
在本节中,我们简要介绍了 M4CE,这是 M4A 用来在云和本地之间移动虚拟机的方法。迁移可以在几分钟内完成,而数据则在后台透明迁移。感兴趣的读者可以在mng.bz/GRXv上了解更多信息。此外,有关如何将 EC2 实例从 AWS 迁移到 Google Cloud 上的 Compute Engine 的更多有用信息可在mng.bz/gJ2x找到。下一节将介绍为 M4A 采用的一些 Google 最佳实践。
15.5 高级主题:M4A 最佳实践
在本节中,我们讨论了 M4A 的一些最佳实践。目的是为顾客经常遇到的实时场景提供指导。本节相当高级,并假设您非常熟悉 Kubernetes 环境。详细讨论了 Kubernetes 的不同细节。让我们从以下内容开始:
-
虚拟机主机名—一个方便的模式是将虚拟机主机名转换为 Kubernetes 服务名称(见
mng.bz/WAQa)。请注意,服务名称是一组 Pod 端点,它们被组合成一个单一的资源。因此,保留这种命名约定有助于保持一致性。 -
每个虚拟机多个应用/服务—如果每个虚拟机存在多个应用程序或服务,为它们中的每一个定义一个 Kubernetes 服务可能很方便。同样,这种命名约定有助于保持一致性。
-
主机文件自定义—如果您的虚拟机在主机文件上使用特定的自定义以进行 DNS 解析,那么建议使用 Kubernetes Pod 规范中的 hostAliases(
mng.bz/81qz)。向 Pod 的/etc/hosts 文件中添加条目提供了对主机名解析的 Pod 级别覆盖。此外,它有助于复制多个应用程序环境,如生产、预发布和测试。 -
多虚拟机堆栈—如果您有一个多虚拟机堆栈环境,那么将相互依赖的 Pod 放置在同一个 Kubernetes 命名空间中并使用简短 DNS 名称可能很方便。此外,您应该使用 Kubernetes 的 NetworkPolicy 来限制前端 Pod 和后端 Pod 之间的访问。这种组织有助于保持您的环境有序、更安全、更有效。
-
引用外部服务—如果您的应用程序使用外部服务,考虑使用 Kubernetes ExternalName Service 而不使用选择器(
mng.bz/Elqd)是一个 Kubernetes 的最佳实践,用于抽象外部后端。 -
NFS 文件共享—目前,M4A 不会自动迁移 NFS 挂载。因此,您需要手动定义 NFS 持久卷指令并将它们添加到生成的 Pod YAML 中。感兴趣的读者可以在网上找到有关挂载外部卷的更多信息(
mng.bz/Nmqn)。 -
不必要的服务—迁移是一个整合时刻。因此,检查您虚拟机上运行的所有服务并禁用不需要在容器上运行的服务是合适的。Migrate for Anthos 将自动禁用不必要的硬件或特定于环境的服务和在 VM 上运行的一组预定义的附加服务。有关自动禁用的不同服务的详细列表,请参阅
mng.bz/DZqR。 -
环境变量—如果您的应用程序需要环境变量,将定义移动到 Kubernetes Pod YAML 中是一个好习惯,以确保您遵循将所有基础设施作为代码的最佳实践。
-
使用 Cloud 实例元数据的脚本—如果您的脚本查找元数据,将此查找替换为 Kubernetes ConfigMap (
mng.bz/lJl2)或再次使用在您的 Kubernetes Pod YAML 定义中定义的 env 变量是值得的。 -
应用程序日志—您可以使用 M4A 将工作负载容器生成的日志迁移并写入 Cloud Logging。默认情况下,M4A 会将写入 init(所有 Linux 进程的父进程)的 stdout 的条目以及来自/var/log/syslog 的内容视为条目。采用此策略将提高您环境中自动化的程度和应用程序的可观察性。
-
GKE 入口控制器—如果您迁移到 GKE,使用 GKE 网络入口控制器来控制访问工作负载的网络流量可能很方便。这样做将消除更改应用程序以添加额外路由规则、VPN、过滤器或 VLAN 的需求。例如,如果您迁移一个三层应用程序,您可能希望将其拆分为多个容器。前端服务通过 GKE Google 负载均衡器(
mng.bz/Blq1)进行访问,以实现负载可伸缩性。此外,您可能还想定义网络策略,以确保只有前端 Pod 可以访问应用程序服务,而外部世界不能访问。同样,您可能还想定义策略,以确保应用程序层只能访问数据库层。这些选择将提高您环境中安全性。 -
Linux 特定的运行级别 3—在 Linux 环境中,某些服务被配置为默认只在运行级别 5 时启动。目前,M4A 只能达到运行级别 3。使用 M4A 迁移到 GKE 的 VM 将在 Linux 运行级别 3 下启动。因此,某些服务应该被配置为在运行级别 3 时自动启动。这些可能包括 X11、XDM 和用于 VNC 的 GUI。
在本高级章节中,我们讨论了您可以采用的一些最佳实践,以微调使用 M4A 迁移的环境。在下一节中,我们将讨论迁移后如何升级镜像。
15.6 迁移后与 CI/CD 管道的集成
使用 M4A 生成的工件可用于第二天的操作,例如软件更新、配置更改、安全补丁以及与文件的附加操作。您可以将这些工件轻松集成到典型的 CI/CD 管道中,该管道包括源代码、构建、测试和部署(见图 15.33)。

图 15.33 典型的 CI/CD 开发阶段
通过多阶段构建生成的工件可以逐步维护,而不会增加生成容器镜像的风险。图 15.34 展示了 M4A 与 CI/CD 管道的集成示例。

图 15.34 M4A 与 CI/CD 管道的集成
典型的 Docker 工件由两部分组成(见图 15.35)。第一部分是 M4A 运行时,第二部分是不可运行的基镜像,代表从迁移的虚拟机中捕获的系统镜像层。

图 15.35 M4A 生成的典型 Dockerfile,适用于 CI/CD 管道
如果您需要更新 M4A 运行时,您可以直接从 Dockerfile 中替换第一个 FROM 指令。例如,假设您需要支持 M4A 1.8.1。您可以使用以下新指令来实现,这将替换当前的指令:
FROM anthos-migrate.gcr.io/v2k-run-embedded:v1.8.1 as migrate-for-anthos-runtime
如果您需要更新您的应用程序,您可以更改第二个 Docker FROM 指令。具体来说,您通常从容器注册库(如 GCS)下载生成的 Dockerfile,编辑 Dockerfile 以应用您希望进行的更改,构建一个新的分层镜像,并通过滚动更新来更新现有的部署。如前所述,这种基于镜像层的方法非常适合基于 CI/CD(见第十二章)的部署环境,其中 DevOps 和站点可靠性工程(SRE)方法是关键。
在本节中,我们讨论了如何集成 CI/CD 管道以增加您的组织敏捷性。在下一节中,我们将讨论如何与服务网格集成。
15.7 迁移后与 ASM 的集成
在本章前面,我们讨论了使用服务网格的好处——在通信、策略管理、可观察性和敏捷性方面的透明收益。关键观察结果是采用 Anthos Service Mesh(见第四章)是采用 SRE 和 DevOps 方法论的另一步。
例如,ASM 使得我们可以检查应用程序的关键指标(如错误、延迟和请求速率)的服务状态;可视化拓扑;检查估计成本;并定义服务级别指标(见图 15.36)。

图 15.36 使用 ASM 检查迁移后的应用程序
再次强调,这些收益是免费的,无需更改迁移应用程序中的任何代码。一旦容器化,您的应用程序就变成了第一类云原生应用程序,可以使用现代云原生方法进行管理,并实现显著的成本节约。您可以通过使用 WorkloadEntry 将您的遗留虚拟机添加到网格中。关键是您获得了在 Kubernetes 上(可移植性、可扩展性等)的所有好处,以及封装集群内所有服务的服务网格,而无需扩展到集群边界之外。
摘要
-
迁移到基于云的应用程序提供了使用比传统虚拟机更有效的方式使用基础设施的现代基于容器的环境的优势。收益包括降低成本、提高可移植性、可扩展性、弹性、简化开发者体验以及缩短上市时间。
-
您可以使用 Migrate for Anthos 进行完全自动化的转换,无需原始源代码。
-
最佳迁移工作负载候选者包括无状态 Web 前端、多虚拟机、多层堆栈、业务逻辑中间件、中到大型数据库以及低负载周期和突发工作负载。我们已经一起审查了构成 Migrate for Anthos 架构的组件以及实际的迁移场景。
-
我们已经学习了使用 Migrate for Anthos 进行迁移的一些常见最佳实践,包括与 CI/CD 管道以及与 Anthos Service Mesh 的迁移后集成。
(1.) 虚拟机管理程序是创建和运行虚拟机的软件、固件或硬件。
(2.) SLA 是指定应提供什么服务、如何支持、时间、地点、成本、性能以及相关方责任的协议。
(3.) SLO 是 SLA 的具体可衡量指标,例如可用性、吞吐量、频率、响应时间或质量。
(4.) 断路器是一种在现代软件开发中用于检测故障并防止故障在维护期间、外部故障或意外问题中不断出现的模式。
(5.) 金丝雀部署是一种将发布部署到用户或服务器子集的模式。想法是首先将更改部署到一小部分服务器/用户,测试它,然后将其部署到剩余的服务器/用户。
(6.) 两个常见的 Unix 服务层;请参阅 fossbytes.com/systemd-vs-sys-v-vs-upstart/。
(7.) CRD 是 Kubernetes API 的扩展,这并不一定在默认的 Kubernetes 安装中可用。CRD 是一种标准机制,以模块化方式自定义 Kubernetes。请参阅 mng.bz/61zy。
(8.)截至 2023 年,共有 90 个经过认证的 Kubernetes 兼容发行版。参见 mng.bz/oJ9M。
(9.)参见 cloud.google.com/migrate/compute-engine。
(10.)有关拟合评估规则的列表,请参阅 mng.bz/v1VM。
(11.)Pod 封装了一个或多个应用程序,是 Kubernetes 中最小的执行单元。
16 打破单体
菲尔·泰勒
本章涵盖
-
现代化遗留应用程序
-
使用 Anthos 进行现代化
-
Anthos 对微服务的优势
-
现实世界的例子
-
避免的反模式
在当今市场上开发和支持大规模应用程序比以往任何时候都更难。随着商业市场的快速加速,应用程序迅速从早期原型发展到大规模应用程序。使用传统的部署方法和流程,我们可以随着应用程序的扩展而演进我们的架构,并有机地发现和修复问题。由于团队需要以多快的速度移动才能跟上业务需求,我们的架构和部署流程需要从第一天起就具有敏捷性和可扩展性。幸运的是,容器和容器平台(如 Anthos)的最新创新,以及现代开发模式,如微服务架构,帮助我们轻松构建和部署应用程序,而不会牺牲效率、性能或质量。
16.1 现代化遗留应用程序
虽然这些新的模式和工具非常适合绿地开发项目,但支持我们的遗留应用程序可能会令人沮丧,有时甚至令人不知所措。许多团队面临着在飞行中重建飞机的挑战。可能会很有诱惑力将所有的鸡蛋都放在一个篮子里,只专注于使用现代、软件架构模式和容器来重建你的应用程序。我们已经看到几个团队采取了这种方法并失败了。最成功的团队将这个过程视为对原始设计的一系列渐进式改进。
当考虑如何从单体遗留设计迁移到现代架构设计时,我们推荐以下方法:
-
现代化遗留应用程序的开发和部署流程。
-
考虑语言和/或框架升级或替换,这可能会改善开发和部署生命周期。例如,如果我们有一个 Java WebSphere 应用程序,如果我们认为应用程序并没有与 WebSphere 的功能紧密绑定,我们可能会考虑将其迁移到 Apache Tomcat web 服务器框架。
-
在容器中现代化,你可以使用 Migrate for Anthos 快速将你的应用程序的运行环境从虚拟机迁移到容器。这将有助于对应用程序的操作进行渐进式改进,这应该会给你的团队时间来专注于现代化工作。
-
添加一个持续集成管道,用于构建和单元测试你的应用程序,可以帮助团队更快地识别和修复问题。反过来,这将为他们提供一个快速反馈循环,这将给他们提供开始现代化应用程序所需的信心。
-
添加一个持续部署管道,将你的应用程序部署到较低的环境,并执行自动集成或用户验收测试,这将进一步提高团队的生产力。
-
在这个阶段,添加端到端的可观察性和仪表化至关重要。我们不能再依赖于登录到专用的虚拟机来查看日志或调试我们的应用程序。我们需要能够监控和调查可能在我们操作环境的大量节点上发生的故障。
-
使用像 GKE 或 Anthos 这样的托管容器操作环境,将使您的团队能够专注于软件和部署创新,而不是运营容器环境。
接下来,您将希望使旧应用程序本身现代化,而不仅仅是开发和部署过程。这将为开发团队和基础设施创造敏捷性、速度和效率。将应用程序分解成更小的领域,并将其实体化到具有已知契约的独立服务中,将创造额外的效率。例如,您将能够独立构建和测试单个业务领域服务,从而允许快速迭代功能。服务之间的标准契约将创建一个明确的边界,以确定何时引入可能影响其他依赖服务的破坏性更改。您将有两个选择:逐步提取和重写功能或重写整个应用程序。大多数情况下,这个选择将取决于企业的目标和投资意愿。我们将简要介绍第一种选择,因为它是我们看到客户采用的最常见方法。
您有方法在边缘剥离功能并重写它们以成为云原生。我们想说的是,在现实生活中这总是那么容易。许多团队从常见的服务开始,如身份验证和授权或日志记录。这种方法将使您的团队能够逐步采取较小的步骤,开始将您的应用程序架构迁移到现代微服务设计。
到这个时候,你可能自己会问,为什么不直接使用适用于旧应用的 Anthos 迁移,然后就此结束呢?答案取决于您的特定用例和应用程序的生命周期。这种方法可能非常适合计划停用或被替换的应用程序。对于将长期存在的应用程序,您最终将希望重新编写它们,以利用现代架构模式,如微服务和无服务器架构。以下列出了上述架构的许多优势:
-
发展优势
-
小型团队专注于单一的业务问题领域。
-
代码的开发和测试的现代技术支持服务的 100%自主构建、测试和部署。尽管使用旧应用程序可以实现 100%的测试覆盖率和自动化部署,但所需的努力比从一开始就支持它的设计要大得多。
-
解耦的服务允许我们选择最适合团队构建的业务能力的技术堆栈。
-
不同的团队可以管理不同的微服务。这种做法通常用于为每个团队创建一个服务,其中团队只需要理解适用于他们正在开发的服务的企业领域。考虑一个包含支付和税务逻辑的服务。在这种情况下,开发者需要理解支付交易和网关、PCI 合规性以及联邦或地方税务规则等概念。通过在支付和税务之间分割服务领域边界,我们可以减少支持每个服务的开发者所需的领域知识。采用微服务方法,支付团队不再需要理解联邦或地方税务规则的复杂性;他们只需要理解添加适当税费到特定交易的 API 接口。
-
-
运营优势
-
提高可靠性和高可用性——每个应用程序服务都是单独设计编译和部署的。这减少了服务中断的影响范围,仅限于单个微服务。
-
可移植性——容器创造了移动性,允许我们在合理的地方运行服务,无论是在本地还是在云服务提供商处。尽管这也可以通过虚拟机实现,但容器平台使得在其他环境中部署和调度工作负载或自动将工作负载移动到更好的操作节点(零停机时间)变得更加容易。
-
降低运营成本——容器比虚拟机具有更高的密度,与虚拟机或物理环境相比,可以节省更多成本。
-
单个服务的需求弹性——采用微服务设计,我们可以自动扩展服务以满足需求,并在空闲时间缩小规模以实现成本效益。这也适用于基于虚拟机的架构,但团队传统上由于缺乏理解如何在虚拟机内部扩展单个服务,因此会扩展整个虚拟机。
-
自动化部署管道——使用基于容器的解决方案,我们可以更轻松地自动化端到端操作。
-
自我修复——通过将需要高可用性的服务迁移到容器平台,我们可以更轻松地设置自动化来处理常见的故障和恢复任务。Kubernetes 提供了原生的存活性和就绪性检查以及重新调度功能,这在大多数情况下是一个简单任务。
-
16.2 使用 Anthos 进行现代化
Anthos 提供了一个完整的解决方案来运行我们的容器化应用程序或我们希望迁移到容器的传统应用程序。Anthos 可以帮助我们在原地现代化,将我们的工作负载迁移到云端,并利用保持云和本地环境之间集群一致性以及高级服务网格网络的能力,更轻松地实现混合应用程序策略。请参阅图 16.1,了解此处描述的 Anthos 组件概述:
-
Anthos 配置管理提供了一种简单的方法来集中管理配置代码。
-
Anthos 服务网格为我们提供了一种指定松散耦合的服务依赖关系、在服务之间建立安全通信通道以及配置集中可观察性系统的方法。
-
Anthos GKE 为我们的基于 Kubernetes 的工作负载在本地或公共云环境中提供了一个可靠和一致的计算环境。
-
Cloud Logging 和 Cloud Monitoring 提供了集中式工具,用于监控、审计和故障排除集群和工作负载。

图 16.1 Anthos 组件概述
16.2.1 现代化方法
正如我们在引言中讨论的那样,存在几种方法可以使您的应用程序现代化,您选择的路径可能因具体的应用程序和业务需求而异。您的应用程序中的一些应用程序或组件可能不适合容器化。以下是一些可能影响您决定将应用程序或应用程序组件容器化的因素:
-
使用 GCE——如果应用程序是业务关键型且风险过高,您在容器化之前可能需要考虑将此应用程序迁移到 Google Compute Engine(GCE)虚拟机。通过首先将应用程序迁移到 GCE,您可以降低学习新操作模式以支持应用程序的风险。这可以给您的团队时间来首先学习 Kubernetes 和 Anthos 在不太关键的工作负载中的应用。
-
许可限制——例如,您的应用程序可能依赖于一个不允许容器化的软件应用程序。
-
运营支持——支持您的应用程序的团队尚未准备好承担支持容器化应用程序所需的新工具链。
-
其他因素——这包括法规遵从性要求、与其他应用程序交互时的性能以及现有的硬件投资。
考虑图 16.2,它可视化了一个 Java 应用程序现代化的高级流程。

图 16.2 现代化 Java 应用程序
无论您最初使用哪种技术堆栈来构建应用程序,方法都是相同的。同时,请记住,这是一个简单的示例——您的应用程序可能由多个应用程序组件或服务组成,它们都需要交互以创建端到端的应用程序用户体验。根据前面列出的标准,您需要决定哪些应用程序组件将重新部署到容器中,哪些将保留为虚拟机。然后,您可以按照图示的工作流程进行现代化计划。以下大纲为每个步骤添加了更多的清晰度:
-
步骤 0——确定要现代化的目标应用程序或组件。
-
步骤 1——如果应用程序适合,我们将使用 Anthos Migrate(第十五章)来容器化目标应用程序。
-
步骤 2—如果应用过于复杂,我们将手动容器化应用。我们将在下一节中详细介绍这种方法。
-
步骤 3—更新现有的 CI/CD 管道,或构建一个新的管道,用于构建、测试和部署应用到 Anthos。
-
步骤 4—使用 Anthos 来管理配置、安全性和与遗留应用的连接来运行你的应用。
-
步骤 5—将你的应用重构为微服务架构。
-
步骤 6—将目前不适合容器化的遗留应用迁移到 Compute Engine,然后通过将每个应用重构为微服务,使用为云原生应用设计的现代开源框架来现代化它们。
-
不在现代化计划范围内的遗留应用将保持其当前形式,并可能继续留在遗留数据中心。我们将使用 Anthos Service Mesh 来保护对这些工作负载的连接,例如 ERP 系统和核心主机应用。
图 16.3 展示了三层 Java 应用,也称为单体应用。在某些情况下,遗留应用将使用商业 Java 应用服务器(例如,WebSphere、WebLogic)。如果你已经分析了应用源代码,并且它没有利用商业应用服务器的专有功能,那么现在是迁移到开源应用服务器(Apache Tomcat、JBOSS)并消除不必要的许可成本的好时机。毕竟,你将重新构建应用部署,并且公共容器镜像可以作为上述开源应用服务器的起点。如果你的团队正在考虑重新设计或重写,你还可以考虑将应用中的现代 Java 框架迁移到 Spring Boot (spring.io/projects/spring-boot)。如果你选择这条路径,你还可以考虑使用 Spring Cloud GCP (spring.io/projects/spring-cloud-gcp)项目,这将加速你的迁移并提供与常见 GCP 服务(如 Pub/Sub、Cloud Spanner 和 Cloud Storage)交互的库。如果你希望避免锁定到特定供应商,你还可以通过使用接口设计来抽象上述服务,从而抽象出云提供商特定的实现。

图 16.3 传统三层 Java 应用
一旦你确定了哪些应用或应用组件最适合容器化,你就可以遵循下一步。
容器化你的应用
旅程的第一步是在容器内运行你的应用程序。如果你正在容器化 ASP.NET 应用程序,你将有两个选择考虑:迁移到 .NET Core 或使用 Windows 经典 Kubernetes 节点。你选择的方法将取决于你将 ASP.NET 应用程序迁移到 .NET Core 的难易程度以及应用程序将得到多长时间的支持。一般来说,我们建议将应用程序迁移到 .NET Core,这样它将在 Linux 上运行,从而简化你的 Anthos 集群。此外,与 Java 应用程序一样,它可能需要彻底的重写。
在本章中,我们将重点关注将典型的企业级 Java 应用程序重新部署到在 Anthos 上运行的容器所需的步骤。Java 开发者有一些工具可以使用,使构建应用程序容器镜像的过程更加容易,这些工具可以集成到现有的构建工作流程中(见图 16.4)。如果你的团队不习惯编写容器镜像描述符,你可以考虑使用以下工具:
-
Jib (
github.com/GoogleContainerTools/jib)—与 Maven 集成,在构建机器上不需要 Docker 守护进程。开发者遵循典型的构建过程,Jib 为你的应用程序构建并输出一个优化的容器镜像。优化的容器镜像将依赖项从类中分离出来,使其在未来的构建中快速高效。只有发生变化的层才会被重新构建。 -
Google Cloud buildpacks (
mng.bz/dJKo)—Buildpacks 被设计用来抽象容器镜像构建过程,这样开发者可以遵循正常的构建过程。基于 CNCF v3 规范,这些 buildpacks 会输出遵循最佳实践的容器镜像,以便在 GCP 容器服务上运行:Anthos、Cloud Run 或 GKE。

图 16.4 Docker 构建 vs. Jib/buildpack 流程
一旦你选择了你的路径并容器化了你的应用程序,就是时候将其连接到 CI/CD 构建管道以实现更快的部署迭代了。在这个时候,你已经容器化了单体应用程序。在本章的后面部分,我们将讨论如何将其重构为微服务。
使用现代 CI/CD 构建和部署你的应用程序
接下来,我们想要构建一个 CI/CD 管道来管理我们的新构建过程并部署我们的应用程序。这将通过消除手动任务以自动化任务来提高我们的开发过程的效率,从而允许我们更快地构建、验证和发布代码。随着我们重构到微服务,我们将应用程序服务解耦成独立部署的组件,这增加了部署和管理我们现代应用程序的整体复杂性。如果没有定义良好且完整的 CI/CD 管道以及用于解决质量控制和支持部署的自动化方法,我们看到的团队速度减慢而不是加快。
图 16.5 展示了构建 CI/CD 管道的必要阶段和流程,以构建和部署 Kubernetes 应用程序。

图 16.5 Kubernetes 应用程序的示例 CI/CD 管道
在 Anthos 上运行您的应用程序
在这一点上,您可以使用 Anthos 作为一致的 Kubernetes 操作环境,以减少您的运营开销,同时提高开发周期速度。有关运行应用程序的更多信息,请参阅第五章。将您的应用程序迁移到容器中并添加 CI/CD 管道,应该会给您的操作员和开发者更多的时间来关注现代化其他应用程序,或者继续对已经在 Anthos 上运行的现有应用程序进行更深入的现代化(重构为微服务)。
将您的应用程序重构为微服务
自从公共云平台发明以来,我们所学到的是,对于云原生应用程序而言,有一种架构优于所有其他架构:微服务。微服务架构由像谷歌这样的公司开创,此后已被主流公司采用,这些公司在精英 DevOps 领域表现突出(见mng.bz/rd4J)。本章的目的不是成为构建微服务应用程序的圣杯——关于这个主题有很多好书。尽管如此,我们将花时间突出这种架构和这种方法的关键优势。如图 16.6 所示,在单体架构中,我们将所有服务代码耦合到一个单一的编译应用程序中,这会在技术组件和构建它们的团队之间创建硬耦合。这也意味着当该应用程序在单个进程中运行时,存在已知副作用:一个组件的应用程序崩溃可能会使整个应用程序崩溃,并且扩展应用程序意味着扩展所有组件,这会导致我们计算环境中的浪费。

图 16.6 单体架构与微服务架构对比
大多数团队在设计创建微服务时使用领域驱动设计(见mng.bz/Vp4y)。在微服务架构中,我们将负责不同业务领域的服务解耦到它们自己的独立服务中。这使得我们可以将负责开发每个服务的团队解耦,减少所需的领域专业知识。我们通过使用行业最佳实践来标准化服务之间的交互,包括协议和数据负载,这为基于微服务的架构提供了以下技术和开发效益:
-
我们将应用程序分解为一系列更易于理解的小服务。
-
由于我们限制了所需的领域知识范围,它们开发更快,维护也更简单。
-
这些服务可以由专注于该服务的团队独立开发,从而提高整体产品开发速度。
-
它们可以独立部署和扩展;我们正在扩展服务,而不是服务器。
-
它使得在复杂应用程序上启用持续部署变得容易,因为我们可以在服务开发迭代期间将测试边界限制为单个服务。
商业效益如下:
-
我们增加了部署频率,从而减少了新特性和补丁的上市时间。我们可以迭代开发,并向单个服务添加新功能,而对其他应用程序服务的影响很小或没有。
-
我们获得了更好的基础设施利用率,因为我们扩展的是服务,而不是服务器。因为我们有更清晰定义的应用程序服务边界,我们可以单独部署服务,并仅扩展需要扩展的服务。在过去,运维团队通常会扩展整个服务器或虚拟机,因为单个服务的扩展是一个复杂任务,而且他们并不足够了解应用程序来将其拆分。
-
我们实现了安全补丁的更快的平均恢复时间。因为微服务主要是使用容器部署的,我们只需修补代码,然后使用 Kubernetes 滚动更新重新部署应用程序,实现零停机时间。在过去,我们可能会尝试修补虚拟机并就地升级应用程序。大多数运维团队都会同意这比通常计划的时间导致更多的停机时间。
-
我们经历了部署失败或回滚的减少。因为我们已经隔离了服务边界,我们的部署范围也相应减少。结合应用程序的自动化测试和部署,我们的成功率显著提高。
当选择将应用程序重构为微服务架构时,你可以采取两种方法:首先,组建一个专注于使用绿色田野方法重写整个应用程序的团队。这种方法对生产应用程序的干扰较小,但会增加整体项目的风险,因为在你能够实现效益之前,你需要重写整个应用程序。第二种方法是应用绞杀榕模式(mng.bz/xdgd),逐步迭代掉遗留应用程序的设计,并将其重构为微服务。
我们建议使用绞杀榕模式,因为它降低了采用新设计模式和将应用程序整体重构为微服务架构的风险。这种方法可能会给整体项目增加一点工作量,因为我们需要提取逻辑并将其重新整合到现有应用程序中。它允许我们逐步改进应用程序架构,每次创建新的生产版本时都提供更多价值,从而减少风险并更快地向业务提供价值。
许多团队在简单的问题上挣扎,即我们从哪里开始?答案将因每个应用而异。然而,模式通常是相同的:寻找支持应用且易于解耦的功能。例如,集中式身份验证和授权服务通常是一个不错的选择。
考虑使用谷歌推荐的框架(mng.bz/Alqo)来评估哪个功能应该首先移动。以下是对该框架的总结:
-
业务流程
-
设计和开发
-
运维
-
人员和团队
业务流程
您应该评估和考虑移动功能对商业用户可能产生的影响。开发者和运维团队需要学习许多新概念才能成功实现应用的现代化。在您的现代化过程中早期,应避免移动业务关键系统或功能。
设计和开发
接下来,您应该评估功能的复杂性、其依赖关系以及移动它所需的重构量。考虑以下因素:
-
数据使用、模式数量(隔离或共享)和大小
-
对其他功能的依赖
-
依赖于此功能的其他功能
-
连接性需求
-
在重构中可能增加复杂性或没有明确解决方案的设计元素
运维
在评估哪些功能应首先移动时,您应考虑以下因素:
-
与商业的 SLA 服务
-
维护窗口和停机容忍度
考虑专注于对停机时间更宽容且没有要求高可用性的关键业务 SLA 的功能。
人员和团队
在早期阶段,最好专注于支持现代化且拥有明确流程的团队。如果可能,避免那些抵制或流程仅通过部落知识可用的团队。
使用 Anthos Service Mesh 优化您的本地遗留应用
大多数采用这种方法来现代化其应用的人最终会有些组件或依赖仍然运行在虚拟机上。我们可以使用 Anthos Service Mesh (ASM)来为这些工作负载添加可观察性和安全功能,与我们的 Kubernetes 工作负载保持一致。ASM 为虚拟机提供的优势列在这里(并参见图 16.7):
-
使用与在 Anthos 上运行的容器相同的声明式策略和安全管理系统框架。
-
无需代码更改;一旦虚拟机注册到 Anthos,它就像在 GKE 中运行的服务一样被处理。
-
利用您从容器工作负载中在单个仪表板中获得的相同可观察性;指标就像在 GKE 中运行的服务一样出现。

图 16.7 将虚拟机与 Anthos Service Mesh 集成
16.3 Anthos 为微服务带来的好处
微服务架构的目标是将业务服务逻辑解耦成独立的、自包含的服务,以提供开发加速和性能优化。缺点是您正在创建应用程序配置、部署和维护操作中的复杂性。由于通用软件的更新,您需要重新安装的软件包每次您必须重新做和更新大量不同环境时都会带来不便。Anthos 解决了与支持这些类型的应用程序相关的最常见问题:
-
一致性—在多个公共云和本地数据中心之间提供一致的运行时环境。
-
自动化—在微服务中取得成功的关键是您自动化整个应用程序部署的能力。Anthos 提供配置为代码的功能来实现这一能力。您可以应用配置和安全策略,甚至使用 ACM 部署应用程序组件。
-
依赖管理和安全—在解耦服务中,使用服务网格可以更轻松地管理增加的复杂性。我们不是在应用程序中嵌入物理服务间的依赖关系,而是采用在基于微服务解决方案中流行的模式,嵌入由服务网格解析的逻辑引用。ASM 提供了这一功能,以及注入安全策略、强制执行双向 TLS 和将传统虚拟机桥接到您的应用程序,就像它们是其他基于 Kubernetes 的服务一样。
-
可观察性—一旦将应用程序分解成微服务,理解应用程序的性能就会变得更加困难。您将需要监控大量服务以了解性能,并了解何时某个服务性能下降或损坏。Anthos 服务网格提供了可视化和检查应用程序性能的能力,以及设置服务级别目标(SLOs),这样您就可以收到警报或自动处理服务性能。
16.4 现实世界示例
存在许多现实世界的例子,其中我们需要在用户附近(即边缘)运行计算工作负载。这些是 Anthos 的绝佳用例,它提供了将配置和安全策略作为代码应用的能力。两个易于识别的用例是零售和制造。
想象一下,你是一家大型邮轮公司。你们团队利用本书中描述的许多概念开发了一种新的用户体验。你们团队构建了一个基于微服务的架构,其中包括网页和移动应用程序的用户体验。这种新的数字体验被用来向客户提供大量的船载功能,如活动规划、餐点订购、活动、公告和礼宾服务。你一直面临的问题是船队缺乏一致性。你难以在每艘船上更新硬件和软件,导致用户体验不一致、断电以及更多问题。更新工作需要消耗大量的人力,包括应用补丁和升级软件。因此,尽管你们开发团队采取了现代化的方法,但你们在运营这个复杂解决方案时仍然感到吃力。你需要 Anthos。尽管它不能消除更新硬件或核心网络更改的过程,但它将处理其他所有事情,缩小手动和自动化流程之间的差距,并降低你运营解决方案的额外开销。Anthos 将为你提供以下功能,以掌握你的环境并避免配置和部署问题:
-
Anthos GKE——提供托管 Kubernetes 分发版,确保你在每个环境中运行相同的运行时平台。
-
Anthos Service Mesh——提供安全和可观察性功能,确保你的容器环境和工作负载是安全的,并且你的开发者可以通过使用 SLOs 轻松地找到问题。
-
Anthos Configuration Management——提供集中式的策略即代码方法,用于核心集群配置、安全策略和应用程序部署一致性。
现在想象一下,如果你的团队已经将 Anthos 作为运营的核心构建了解决方案。你们团队已经设计了每个集群,并使用 Anthos Config Management 将核心集群配置和安全策略作为代码进行文档化。要将新的船载数据中心上线,只需简单地将设备上架、将硬件接入网络、安装 Anthos,然后使用控制平面和 ACM 注册集群。然后 ACM 将使用正确的配置和安全策略引导集群。
16.5 需要避免的反模式
几年来,在帮助团队将应用程序现代化并转型为微服务架构的过程中,我们发现了几个反模式:
-
诱惑性的大爆炸方法—许多团队决定放弃他们已有的东西,从头开始,一次性将整个应用程序重写为微服务架构。根据我们的经验,这往往会导致瀑布式方法,在业务能够实现效益之前,需要付出更长的时间和超出预算的努力。一个更好的方法是像我们之前在章节中提到的,一层层地剥洋葱,这样更适合精益或敏捷方法来现代化应用程序,并且可以更快地开始提供效益。
-
忽视微服务架构设计原则 (
mng.bz/ZoMR)—为了正确创建微服务,我们将所有功能隔离在新的服务中。这通常意味着移动接口逻辑、业务逻辑以及状态服务所需的数据模式。许多团队在这里会遇到困难,并留下数据模式在共享数据存储中。当团队不很好地理解服务边界或不知道如何解决下游能力,如分析或报告时,这可能会很有吸引力。在一个成熟的基于微服务的解决方案中,所有组件都必须是隔离的,并且可以独立版本化和部署。 -
数据驱动迁移 (
mng.bz/Rl6Z)—鉴于我们之前讨论的第一个反模式,人们可能会倾向于过分关注数据,并试图使用数据边界作为服务边界。这在遗留系统中通常是一个错误,通常会导致迁移震荡(许多迁移迭代才能正确)。相反,考虑一个中间步骤,首先关注逻辑,其次关注数据。这将使你能够正确地确定业务服务边界,并更好地理解如何分割数据。 -
解耦功能而非代码 (
mng.bz/2adg)—开发人员和技术经理负责编写代码,这就是为什么他们在重构单体代码库到微服务时,会倾向于提取和重用现有代码,但实际上,这种方法会产生高成本和低价值。大多数组织和团队将从代码的重写中受益。这允许他们重新审视业务流程,可能优化遗留流程,并在过程中改进代码库(添加单元测试,采用新语言等)。在某些情况下,重用现有代码是有意义的——一个很好的例子是提取一个复杂但理解或文档不佳的算法。在这种情况下,提取和重用代码,然后在团队理解了他们在做什么并且可以安全地重写之后,再进行现代化是更安全的。
摘要
-
现代化遗留应用程序不一定要从完全重写或重构开始。将应用程序迁移到容器中可以帮助减少运营负担,并给你的团队时间来创新下一个版本的软件。
-
在现代化应用程序的过程中,寻找机会减少技术债务,例如迁移您的网络服务器框架或更新核心库。
-
减少技术债务的其他方法包括移除用于引导 TLS 安全性的代码或观察并依赖 Anthos 在平台级别提供这些功能。
-
如果您将重写或重构应用程序,请考虑使用微服务这样的新设计模式。
-
避免采取大爆炸式的方法——优先考虑对应用程序进行渐进式改进。
-
使用 Anthos 提供一致的运行时、自动化、依赖管理、安全性和可观察性,以确保开发团队在其操作环境中有一套一致的能力可以依赖。
17 在裸金属上运行的计算环境
乔治·加洛罗
本章涵盖
-
裸金属 Anthos 简介
-
部署选项
-
网络架构
-
存储架构
-
在裸金属上安装和配置 Anthos
Anthos 的原始发布版本要求您在 vSphere 基础设施上部署您的集群,并且不提供在不同的虚拟机管理程序或物理服务器上部署的选项。对于初始发布版本来说,这样做是有道理的,因为 vSphere 被众多企业使用,这允许企业使用他们现有的基础设施和技能集。然而,随着容器和 Kubernetes 用例的增长,组织越来越希望并且需要更灵活的部署选项。
为了解决这些额外的用例,Google 将 Anthos 扩展到包括裸金属部署模型。需要强调的一点是,您不必在裸金属上实际部署 Anthos 到物理服务器。裸金属模型允许您将部署到任何支持的操作系统,无论是物理服务器还是虚拟机,甚至是运行在 Hyper-V 或 KVM 上的虚拟机。
您可以将裸金属选项视为“自带 Linux”的部署模型。与 vSphere 部署模型不同,您需要提供可用的服务器,然后才能在裸金属上部署 Anthos。现在让我们向您介绍裸金属 Anthos。
17.1 裸金属 Anthos 简介
如前几章所述,Anthos 是一个为多个部署环境设计的平台,如图 17.1 所总结。

图 17.1 Anthos 部署环境
裸金属上的 Anthos 是一种部署选项,可以在客户提供的操作系统上运行的物理服务器上运行 Anthos。它内置了网络、生命周期管理、诊断、健康检查、日志记录和监控功能。此外,它支持 CentOS、Red Hat Enterprise Linux (RHEL) 和 Ubuntu,所有这些都经过 Google 验证。使用裸金属上的 Anthos,您可以使用组织的标准硬件和操作系统镜像,利用现有投资,这些投资将自动检查并验证是否符合 Anthos 基础设施要求。
17.1.1 比较本地 Anthos 部署选项
现在您有选择在本地部署 Anthos 的选项,那么您如何决定哪种最适合您的组织?这两种选项都有其自身的优缺点,为了决定哪种部署最适合您,您需要考虑您个人的需求。在表 17.1 中,我们概述了每个选项的一些优缺点。
表 17.1 Anthos 在 VMware 和裸金属上的优缺点
| VMware 上的 Anthos | 裸金属上的 Anthos |
|---|
| 在 VMware 上运行最佳适用于
-
vSphere 作为企业标准
-
涉及多个团队或集群(开发/测试)共享硬件
-
集成操作系统生命周期管理
-
集群的自愈/自动扩展
| 在裸金属或本地 IaaS 上运行,最适合希望
-
降低成本和复杂性(由于消除了 vSphere 许可证)
-
低延迟工作负载(电信和高性能计算)
-
为了通过简化的软件堆栈解锁边缘计算的新的用例
-
为了更接近硬件以获得更好的性能
|
| 部署优点 |
|---|
|
-
部署多个集群更容易
-
提供的节点设备需要很少的维护
-
包括两个用于持久磁盘的 vSphere 存储提供程序
-
节点自动修复
-
容易扩展集群节点
|
-
可以部署到任何支持的 Linux 节点,本地或云服务提供商
-
没有工作负载调度冲突
-
扩展 GPU 兼容性
-
允许节点定制以满足组织的需求
-
更好的节点性能
-
使用现有的企业标准(例如,日志记录和监控标准)
|
| 部署缺点 |
|---|
|
-
需要额外的 VMware 许可证。
-
不支持节点设备的定制。
-
通过直通支持有限的 GPU。
-
需要对虚拟机团队或 Kubernetes 支持团队进行额外的培训。
-
vSphere 调度程序和 Kubernetes 调度程序互不认识。
-
Storage DRS 可能会破坏您的集群。
|
-
需要规划以正确调整节点大小,以避免资源浪费
-
除了本地主机存储外,不包括其他存储分配器
-
在大多数企业中难以扩展
-
没有节点自动修复
-
管理和更新操作系统底层的节点
|
17.2 Anthos 裸金属架构
与 Anthos on VMware 集群节点从 Google 提供的预配置 VM 映像部署不同,Anthos on bare metal 依赖于客户提供他们自己管理和打补丁的受支持的操作系统版本。如图 17.2 所示,操作系统可以直接安装在物理服务器上,或者安装在支持与 Anthos on bare metal 兼容的 Linux 分发的任何虚拟化平台(KVM、OpenStack)上运行的 VM 上。

图 17.2 Anthos 本地部署选项,共享责任模型
17.2.1 集群架构
在本节中,我们将讨论裸金属集群的架构。您从 Anthos on VMware 部署中了解到的许多架构对于裸金属也是相同的;然而,裸金属选项包括一些与 VMware 模型不同的架构差异。
集群角色
Anthos 裸金属安装有以下两种类型的集群:
-
用户集群—应用程序部署的地方,它包括控制平面节点和运行容器化应用程序实例的工作节点。
-
管理集群—管理一个或多个用户集群的集群。它通过配置在两个自定义资源(集群和 NodePool)中的 Anthos 在裸金属上特定的操作员来安装、更新、升级和删除用户集群。
管理员集群仅包括控制平面节点,其中运行用于管理安装的组件。它还托管一些安全敏感的数据,包括访问节点 OS 的 SSH 密钥和 GCP 服务账户密钥。与在 VMware 上运行的 Anthos 不同,用户集群控制平面节点与管理员集群解耦。
高可用性
你可以在高可用性(HA)模式下运行用户或管理员集群控制平面,这样控制平面节点故障就不会影响集群操作。此模式需要三个或更多控制平面节点。如果不需要高可用性,你可以在每个集群中运行单个控制平面节点,但这种方法仅适用于非生产工作负载。
除了控制平面外,你还需要考虑工作节点的可用性。对于需要高可用性的应用程序,你需要至少两个工作节点。与控制平面一样,你不应该在没有为工作节点启用高可用性的情况下运行生产工作负载。
部署模型
这是你开始看到 Anthos 在 VMware 和裸金属之间部署差异的地方。在裸金属上运行的 Anthos 提供几种不同的部署模型,以提供灵活性以满足不同的组织需求。
独立集群部署
在独立集群部署模型中,如图 17.3 所示,单个集群同时作为管理员集群和用户集群。由于此模型不需要单独的管理员集群,你可以在高可用性设置中节省三个节点。这种情况在需要独立管理每个集群或对单个集群每个部署位置都有要求的情况下可能很有用,例如边缘用例或隔离网络。

图 17.3 独立集群部署
从安全角度来看,你需要考虑用户工作负载将在与控制平面相同的集群上运行。你需要仔细考虑保护你的集群,以保护诸如节点 SSH 密钥和 GCP 服务账户密钥等信息。实施 RBAC 策略、OPA 策略、网络策略和适当的审计将有助于保护集群。
为了为这些类型的部署提供更多灵活性,从 Anthos 版本 1.8 开始,Google 将每个集群支持的最小节点数从两个减少到一个,并为独立集群引入了新的边缘配置文件,这进一步降低了硬件要求。
多集群部署
这是 Anthos 在 VMware 上使用的相同部署模型。在多集群部署模型中,如图 17.4 所示,你有一个单个管理员集群管理多个用户集群。如果需要集中管理在同一数据中心部署的集群系列,则此模型很有用。

图 17.4 多集群部署
混合集群部署
混合集群部署模型,如图 17.5 所示,与多集群部署类似,只有一个区别:你可以使用管理集群来运行用户工作负载以及标准工作节点。

图 17.5 混合集群部署
如你所见,与 VMware 部署模型相比,Anthos 在裸金属上增加了更大的部署灵活性。然而,增加的灵活性并不止于此。在下一小节中,我们将讨论网络架构的更新。
网络架构
对于裸金属选项的网络架构与 VMware 模型的不同是有道理的。在 VMware 部署中,你可以使用外部负载均衡器,或者使用捆绑的负载均衡器,Seesaw。如果你选择 Seesaw 选项,Anthos 将在你的 VMware 环境中部署一个预配置的虚拟机,或者以 HA 模式运行的机器。
在裸金属部署中,Google 不提供任何组件的设备或虚拟机镜像。不过,不用担心——Google 通过其他组件如 HAProxy 和 MetalLB 来解决这个问题。
负载均衡
Anthos 在裸金属上需要使用层 4(L4)负载均衡来暴露控制平面端点、入口端点和应用程序,使用 LoadBalancer 类型的服务。负载均衡器的责任是路由和平衡流量到适当的节点。
无论你选择哪种集群部署模型,Anthos 在裸金属上可以通过捆绑的 L4 负载均衡器(捆绑负载均衡器模式)提供所需的负载均衡功能,或者,你也可以使用客户提供的和配置的外部负载均衡解决方案(手动负载均衡器模式)。
无论你选择哪种 L4 负载均衡选项,在安装过程中都会部署基于 Envoy 的 Istio Ingress 网关,并通过 L4 负载均衡器以 LoadBalancer 类型的服务公开。这个 Envoy 部署用于为应用程序提供代理功能,通过标准的 Kubernetes 入口对象暴露它们。
捆绑式负载均衡器模式
首先,让我们讨论控制平面的负载均衡。如果你选择捆绑的负载均衡,Anthos 在裸金属上部署 L4 负载均衡器,在集群安装期间,无需提供外部负载均衡器。负载均衡器可以运行在专用的工作节点池上,或者位于与控制平面相同的节点上。在任一情况下,负载均衡器节点必须在同一子网中。
从 Anthos 1.9 版本开始,Google 改变了 L4 负载均衡器的部署方式。之前,HAProxy 容器镜像作为标准 Docker 容器(即非 Kubernetes 控制)以 systemd 服务的形式部署到节点(s)。从版本 1.9 开始,Keepalived 和 HAProxy 容器已更新为在负载均衡器节点上作为静态 Kubernetes Pod 运行。
HAProxy 仅用于控制平面的负载均衡。为了向数据平面提供 L4 服务,Anthos 部署了一个流行的开源解决方案,称为 MetalLB,该解决方案为集群中任何使用 LoadBalancer 类型部署的服务提供服务。
为了回顾捆绑的负载均衡器组件:
-
控制平面负载均衡——控制平面虚拟 IP 地址(VIP),将流量路由到运行在控制平面节点上的 Kubernetes API 服务器,通过在负载均衡器节点上作为 Kubernetes Pod 运行的 HAProxy 负载均衡器公开,同时还有一个容器化的 Keepalived 服务来管理 HAProxy 的高可用性。
-
数据平面负载均衡——为应用程序创建的 LoadBalancer 类型服务对象以及与裸金属上的 Anthos 一起部署的 Istio Ingress 网关,通过在负载均衡器节点上运行的 Anthos 管理的 MetalLB 部署公开,IP 地址可以从预定义的池中自动分配,并且是负载均衡器节点部署的同一子网的一部分。
控制平面负载均衡组件(HAProxy 和 Keepalived)以及数据平面负载均衡组件(MetalLB)都在指定的节点上一起运行(集群控制平面节点或专用负载均衡器工作节点)。
图 17.6 显示了在单个子网中部署的用户集群的架构示例,其中捆绑的负载均衡器在控制平面节点上运行。图 17.7 显示了在单个子网中部署的用户集群的架构示例,其中捆绑的负载均衡器在专用工作节点上运行。

图 17.6 在控制平面节点上运行的负载均衡器

图 17.7 在专用工作节点上运行的负载均衡器
手动负载均衡器模式
如果你选择手动负载均衡器模式,Anthos 安装不会部署捆绑的负载均衡器,你需要负责部署外部负载均衡解决方案。
图 17.8 显示了在单个子网中部署的用户集群的示例,其中配置了手动负载均衡模式的外部负载均衡器。

图 17.8 手动负载均衡架构
内部集群网络
在裸金属上部署的 Anthos 使用基于 GENEVE 隧道的覆盖网络,这要求集群中的节点之间具有第 3 层(L3)连接性,除了需要位于同一第 2 层(L2)域中的负载均衡器节点。
类似于 Anthos 在 VMware 上的工作方式,Pod IP 寻址在孤岛模式下工作,这意味着分配给 Pod 的 IP 地址只能从同一集群访问,Pod CIDR 范围可以在集群之间重复使用。
存储架构
为在裸金属上运行的 Anthos 工作负载提供持久存储的主要方法是通过来自 Anthos 准备存储合作伙伴的 Container Storage Interface 驱动程序。您可以在 mng.bz/1MdX 找到合作伙伴列表和经过验证的存储解决方案。
裸金属上的 Anthos 还捆绑了 sig-storage-local-static-provisioner,它为每个节点提供挂载点,并为每个挂载点创建一个本地持久卷 (PV)。由于其局限性,您应仅将本地 PV 用于非生产环境或特定的先进用例。
可观测性
您可以使用 Google Cloud 操作收集裸金属上 Anthos 的日志和监控指标,就像在其他 Anthos 部署环境中一样。默认情况下,系统组件日志被发送到 Cloud Logging,系统组件指标被发送到 Cloud Monitoring。通过在集群配置中启用它,Cloud 操作还可以收集应用程序日志和指标(使用 Google Managed Service for Prometheus)。
作为云操作的一种替代方案,如果您更倾向于使用其他解决方案,可以选择 Prometheus/Grafana、Elastic Stack、Sysdig、Datadog 或 Splunk。
身份集成
通过 Anthos Identity Service 认证代理,裸金属上的 Anthos 可以与支持 OpenID Connect (OIDC) 或 LDAP 的任何身份提供者集成,以使用现有的用户身份和凭据管理对集群的用户和组身份验证。如果您已经使用或希望使用 Google IDs 登录到您的 Anthos 集群而不是 OIDC 或 LDAP 提供商,建议您使用 Connect 网关进行身份验证。
通过这种集成,您可以使用组织内部创建、启用和禁用账户的标准程序来管理对裸金属上 Anthos 集群的访问。您可以使用 Kubernetes RBAC 将特定角色绑定到身份提供者中定义的用户和组,以授权他们在特定资源上执行特定操作。
17.3 安装和配置概述
在本节中,我们将概述部署集群所需的要求。在尝试部署集群之前,了解这些要求是一个重要的步骤,我们将在下一节中进行讨论。
Google 已经使在裸金属上部署 Anthos 变得简单。与 VMware 部署类似,您在配置文件中配置集群选项,并使用名为 bmctl 的单个二进制可执行文件执行部署。
Anthos 要求您满足软件和硬件的要求。大多数组织很容易满足这些要求,但在部署之前,您应始终验证您的基础设施是否满足所有要求。
17.3.1 操作系统和软件要求
如介绍和架构部分所述,Anthos on bare metal 是安装在客户提供的并由客户配置的服务器上。服务器可以是物理的或虚拟的,只要它们具有支持的操作系统之一,并配置以满足 Anthos 的要求。用作 Anthos on bare metal 节点的服务器需要以下操作系统之一:
-
CentOS 8.2/8.3/8.4/8.5
-
Red Hat Enterprise Linux (RHEL) 8.2/8.3/8.4/8.5/8.6
-
Ubuntu 18.04 和 20.04
每个支持的版本都需要稍有不同的配置。如果您使用 RHEL 或 CentOS,必须配置 firewalld 服务以允许流量通过 TCP 和 UDP 端口——这些将在 17.3.4 节中的内部连接性要求中介绍。在这些操作系统上,如果 SELinux 以强制模式启用,则在 Anthos on bare metal 设置期间将配置容器隔离和安全策略。如果您在 Ubuntu 上运行节点,则必须禁用 Uncomplicated Firewall 服务。
时间对于集群来说非常重要。为确保所有节点的时钟同步,所有服务器都需要配置并启用 NTP 服务。最后,因为安装会在节点上建立 SSH 连接,所以您需要一对 SSH 密钥来以 root 权限访问每个节点。
17.3.2 硬件容量要求
Anthos on bare metal 可以在任何与支持的操作系统兼容的硬件上运行。安装所需的节点数量取决于选择的部署和负载均衡模型,如前所述。所需的 worker 节点数量将取决于集群(们)将要托管的应用程序的能力要求。
表 17.2 描述了每个节点的最小和推荐硬件要求,无论其角色如何,使用默认配置文件,不包括应添加的应用程序容量要求。
表 17.2 Anthos on bare metal 的硬件要求
| 资源 | 最小 | 推荐 |
|---|---|---|
| CPU/vCPU | 4 核 | 8 核 |
| 内存 | 16 GiB | 32 GiB |
| 存储 | 128 GiB | 256 GiB |
表 17.3 描述了 Anthos on bare metal 版本 1.8 中引入的边缘配置文件的硬件要求。
表 17.3 边缘配置文件的硬件要求
| 资源 | 最小 | 推荐 |
|---|---|---|
| CPU/vCPU | 2 核 | 4 核 |
| 内存 | Ubuntu: 4 GBCentOS/RHEL: 6 GiB | Ubuntu: 8 GBCentOS/RHEL: 12 GiB |
| 存储 | 128 GiB | 256 GiB |
17.3.3 管理工作站
除了节点之外,建议再有一个工作站来运行安装工具。此工作站必须运行与集群节点相同的 Linux 操作系统,并配置 Docker 19.03 或更高版本,以便由非 root 用户管理。除了 Docker 之外,该机器还必须具备以下条件:
-
已安装带有 anthos-auth 和 kubectl 的 gcloud。
-
需要 50 GB 以上的空闲磁盘空间。
-
到所有集群节点机器的 L3 连接性。
-
通过私钥和密码无根访问权限通过 SSH 访问所有集群节点机器。访问可以是直接或通过 sudo。
-
访问控制平面 VIP。
17.3.4 网络需求
Anthos 对外部和内部网络连接有不同的需求。
外部连接需求
所有在裸金属节点上的 Anthos 都需要出站 HTTPS 连接到互联网以执行以下操作:
-
在 GCP 控制台中注册并从那里通过 GKE Connect 进行管理
-
将指标和日志发送到云操作端点
-
从 Google 容器注册库拉取镜像
这种连接可以使用公共互联网、HTTP 代理或类似 Google Cloud VPN 或专用互连的私有连接。
内部连接需求
本节将详细说明您集群的内部网络需求。集群的每个组件都有不同的需求,表格 17.4-17.7 列出了用于集群节点流量的特定连接端口。
表 17.4 控制平面节点
| 协议 | 方向 | 端口范围 | 目的 | 使用者 |
|---|---|---|---|---|
| UDP | Inbound | 6081 | GENEVE 封装 | Self |
| TCP | Inbound | 22 | 管理集群节点的配置和更新 | 管理工作站 |
| TCP | Inbound | 6444 | Kubernetes API 服务器 | All |
| TCP | Inbound | 2379-2380 | etcd 服务器客户端 API | kube-apiserver 和 etcd |
| TCP | Inbound | 10250 | kubelet API | Self 和控制平面 |
| TCP | Inbound | 10251 | kube-scheduler | Self |
| TCP | Inbound | 10252 | kube-controller-manager | Self |
| TCP | Inbound | 10256 | 节点健康检查 | All |
| TCP | Both | 4240 | CNI 健康检查 | All |
表 17.5 工作节点
| 协议 | 方向 | 端口范围 | 目的 | 使用者 |
|---|---|---|---|---|
| TCP | Inbound | 22 | 用户集群节点的配置和更新 | 管理集群节点 |
| UDP | Inbound | 6081 | GENEVE 封装 | Self |
| TCP | Inbound | 10250 | kubelet API | Self 和控制平面 |
| TCP | Inbound | 10256 | 节点健康检查 | All |
| TCP | Inbound | 30000-32767 | NodePort 服务 | Self |
| TCP | Both | 4240 | CNI 健康检查 | All |
表 17.6 负载均衡节点
| 协议 | 方向 | 端口范围 | 目的 | 使用者 |
|---|---|---|---|---|
| TCP | Inbound | 22 | 用户集群节点的配置和更新 | 管理集群节点 |
| UDP | Inbound | 6081 | GENEVE 封装 | Self |
| TCP | Inbound | 443 | 集群管理 | All |
| TCP | Both | 4240 | CNI health check | All |
| TCP | Inbound | 7946 | Metal LB 健康检查 | 负载均衡节点 |
| TCP | Inbound | 10256 | 节点健康检查 | All |
| UDP | Inbound | 7946 | Metal LB 健康检查 | 负载均衡节点 |
表 17.7 多集群端口需求
| 协议 | 方向 | 端口范围 | 目的 | 使用者 |
|---|---|---|---|---|
| TCP | Inbound | 22 | 集群节点的配置和更新 | 所有节点 |
| TCP | Inbound | 443 | 添加集群的 Kubernetes API 服务器 | 控制平面和负载均衡节点 |
在网络要求得到解决后,让我们继续讨论配置集群负载均衡器的附加要求。
负载均衡要求
在裸金属上安装 Anthos 之前,您需要选择一个负载均衡的架构(手动或捆绑)以及在捆绑的情况下,决定您的负载均衡器是否将安装在控制平面节点或专用工作节点上。无论您选择哪种解决方案,以下 VIP 地址都必须预留:
-
每个集群的控制平面一个 VIP——如果您使用捆绑的负载均衡器,这将根据您在安装过程中定义的配置自动创建。如果您使用手动负载均衡器,则需要手动将其关联到一个包含集群控制平面节点所有 IP 地址的后端服务器组。控制平面监听的后端端口是 6444。
-
每个用户集群的 Ingress 服务一个 VIP——如果您使用捆绑的负载均衡器,这将根据您在安装过程中定义的配置自动创建。如果您使用手动负载均衡器,则需要手动配置,使用分配给在集群 gke-system 命名空间中创建的 istio-ingress Service 的相同 IP 地址,并关联到一个包含集群节点 IP 地址的后端服务器组。后端端口将是 istio-ingress Service 的 NodePort。如果您想同时使用 Ingress 网关处理 HTTP 和 HTTPS 流量,可能需要为每个端口配置一个 VIP(和后端池)。
-
集群中每个 LoadBalancer 类型 Service 创建一个 VIP——如果您使用捆绑的负载均衡器,这些将根据您在安装过程中定义的池自动分配。如果您使用手动负载均衡器,则需要手动配置,使用分配给 Service 对象的相同 IP 地址,并关联到一个包含集群工作节点所有 IP 地址的后端服务器组。后端端口将是 Service 对象的 NodePort。
如果集群部署将使用捆绑的负载均衡器,以下项目必须进行配置:
-
负载均衡节点需要位于同一 L2 网络中,而其他连接,包括工作节点,只需要 L3 连接性。
-
所有 VIP 必须位于负载均衡器机器子网中,并且完全可路由。
-
负载均衡器子网的网关必须监听免费 ARP 消息并将 ARP 数据包转发到负载均衡器节点。
接下来,下一节将介绍 Google Cloud Platform 的要求。
17.3.5 Google Cloud Platform 要求
Anthos 在裸金属上的安装有几个 GCP 项目要求,包括必需的 API、服务帐户和必需的角色。
必需的 GCP API
为了成功部署,将连接到集群的项目必须启用几个 API。您可以手动完成此操作,或者您可以在使用 bmctl 执行部署时自动启用它们作为选项。在用于安装的 GCP 项目中必须启用以下 API:
-
anthos.googleapis.com
-
anthosaudit.googleapis.com
-
anthosgke.googleapis.com
-
cloudresourcemanager.googleapis.com
-
container.googleapis.com
-
gkeconnect.googleapis.com
-
gkehub.googleapis.com
-
iam.googleapis.com
-
serviceusage.googleapis.com
-
stackdriver.googleapis.com
-
monitoring.googleapis.com
-
logging.googleapis.com
-
opsconfigmonitoring.googleapis.com
如果在运行部署之前未启用任何 API,预检检查将捕获缺失的 API 并停止部署继续进行。
必需的服务帐户和角色
在裸金属上部署 Anthos 之前的一个要求是创建所需的服务帐户和所需的角色。尽管您可以使用具有所有角色的单个帐户,但这被认为是一种不良的安全实践。您的组织将有其自己的安全要求,但建议您创建所有帐户作为不同的服务帐户。
您可以选择手动创建服务帐户,或者您可以在安装过程中创建它们,使用 bmctl 安装工具的参数。在裸金属上运行的 Anthos 需要以下具有指定角色的 Google Cloud 服务帐户:
-
没有特殊角色的服务帐户 Container Registry (gcr.io)
-
用于将集群注册到 GCP 控制台并具有 GKE hub 管理员 IAM 角色的服务帐户
-
用于维护集群与 Google Cloud 之间连接并具有 GKE Connect 代理 IAM 角色的服务帐户
-
用于将日志和指标发送到 Google Cloud 操作套件并具有以下 IAM 角色的服务帐户:
-
日志记录器
-
监控指标写入器
-
Stackdriver 资源元数据写入器
-
监控仪表板配置编辑器
-
Ops 配置监控资源元数据写入器
-
如果您想通过 bmctl 工具启用这些 API 并在安装过程中创建所需的 GCP 服务帐户,用于安装的帐户必须具有项目所有者/编辑角色,或者至少分配以下角色:
-
服务帐户管理员
-
服务帐户密钥管理员
-
项目 IAM 管理员
-
计算机查看器
-
服务使用管理员
最后,我们将涵盖一个 Anthos 将用于集群指标的要求。
云指标要求
要将指标发送到 Google Cloud 的操作套件,除了上一节中列出的服务帐户外,您必须在 GCP 项目中创建一个云监控工作区。
17.4 创建集群
满足所有要求后,您可以继续创建集群。以下章节假设所有安装任务都是在满足第 17.3.3 节所述要求的机器上执行的。
17.4.1 创建管理员、混合或独立集群
正如我们详细说明的,您可以使用几种不同的集群模型在裸金属上部署 Anthos,包括独立的管理员/用户集群、混合集群或独立集群。在本节中,我们将讨论部署每种模型的过程。
安装流程摘要
您可以使用 bmctl 工具在特定的部署环境中安装第一个集群,无论选择哪种模型。在相同环境中创建附加用户集群可以通过应用 Anthos on bare metal 用户集群配置文件实现,该文件与第一个集群配置类似,只有一些细微的更改。创建第一个集群的高级步骤如下:
-
下载 bmctl 工具。
-
使用 bmctl 创建集群配置模板文件。
-
使用所需的设置修改配置文件。
-
运行 bmctl 创建集群。
图 17.9 展示了使用 bmctl 创建第一个集群的流程。

图 17.9 使用 bmctl 创建集群的流程
前四个步骤由用户启动,当您执行第 4 步,即 bmctl create cluster 命令时,将执行以下步骤:
-
验证配置—检查集群配置文件,以验证规范是否格式正确,没有 IP 地址冲突发生,服务账户密钥可用,并且集群尚未在 GCP 控制台中注册。
-
创建 kind 集群—作为设置的一部分,bmctl 首先在管理员工作站上创建一个临时的 kind(Docker 中的 Kubernetes)集群,其中一些用于管理员集群的资源,如集群和 NodePool 对象或包含静态站点生成器和服务账户密钥的 Secrets,是从配置文件规范创建的。
-
预检查—对集群机器和网络要求进行检查,例如操作系统版本和配置、文件系统可用空间以及 GCP API 端点的可达性。
-
配置裸金属集群—二进制文件被复制到目标节点,并执行安装,包括节点初始化和加入。
-
安装附加组件—安装附加组件,如 GKE Connect Agent、日志和监控组件、裸金属操作员和 MetalLB。
-
转换—将裸金属资源从 kind 集群移动到已配置集群的过程。之后将从 kind 集群中删除 Kubernetes 资源。
最后,让我们深入探讨如何创建一个集群!
登录 GCP 并下载 bmctl 工具
记住,Google 提供了一个名为 bmctl 的工具,用于在裸金属上部署 Anthos。在您将用于部署集群的工作站上,按照以下步骤下载 bmctl 工具(在我们的示例中,我们将假设工作目录是 ~/baremetal):
-
使用具有“安装账户角色要求”部分中描述的角色之一的用户,通过 gcloud auth application-default login 登录 gcloud。
-
从文档中找到的 URL 或存储桶下载 bmctl 工具,如下所示:
gsutil cp gs://anthos-baremetal-release/bmctl/<VERSION>/linux-amd64/bmctl bmctl) -
使 bmctl 可执行:
chmod a+x bmctl
现在我们有了 bmctl 可执行文件,我们可以继续创建集群配置。
创建集群配置
要部署集群,我们需要有一个包含部署所需所有参数和选项的集群配置文件。bmctl 工具可以通过使用 create config 选项为我们创建一个新的配置文件:
bmctl create config -c CLUSTER_NAME --project-id=CLOUD_PROJECT_ID
其中 CLUSTER_NAME 是你想要给集群的名字,CLOUD_PROJECT_ID 是你想要与裸金属上的 Anthos 一起使用的项目的项目 ID。
如果你还没有启用所需的 API,你可以在之前的命令中添加--enable-apis 选项来启用它们,如果你还没有创建所需的服务帐户,你可以添加选项--create-service-accounts 以在创建所需角色时同时创建它们。
填充集群配置文件
在创建集群之前,我们需要正确准备由 bmctl 创建的配置文件。该文件默认保存在名为bmctl-workspace的文件夹内,其名称与集群名称相同。在本节中,我们将解释配置文件中的选项。
SSH 私钥
这是将在集群部署期间用于连接到节点的 SSH 私钥。将 sshPrivateKeyPath:规范添加到完整的路径,以便访问授权访问所有目标节点作为 root 的 SSH 私钥,例如:
sshPrivateKeyPath: /root/.ssh/anthoskey
GCP 服务帐户密钥
如果你已经在运行 bmctl 之前手动创建了 GCP 服务帐户,你需要使用以下示例中的完整路径填充相关字段,以服务帐户密钥的完整路径。如果你使用了 bmctl --create-service-accounts 参数,它们将已经填充:
gkeConnectAgentServiceAccountKeyPath: /root/bmctl-workspace/.sa-keys/anthos-demos-anthos-baremetal-connect.json
gkeConnectRegisterServiceAccountKeyPath: /root/bmctl-workspace/.sa-keys/anthos-demos-anthos-baremetal-register.json
cloudOperationsServiceAccountKeyPath: /root/bmctl-workspace/.sa-keys/anthos-demos-anthos-baremetal-cloud-ops.json
gcrKeyPath: /root/bmctl-workspace/.sa-keys/anthos-demos-anthos-baremetal-gcr.json
集群类型
根据所选的集群部署模型,在 Cluster 自定义资源中设置 type spec 的值,选择 admin、hybrid*或 standalone,如下例所示:
---
.gke.io/v1
kind: Cluster
metadata:
name: admin-cluster
namespace: cluster-admin-cluster
spec:
type: hybrid
控制平面配置
根据所选的控制平面架构,在 controlPlane:部分的 nodePoolSpec:规范中添加目标控制平面节点的 IP 地址。以下是一个基于三个控制平面节点的 HA 架构的示例。记住,如果你想启用高度可用的控制平面,你需要提供至少三个 IP 地址:
controlPlane:
nodePoolSpec:
nodes:
# Control plane node pools. Typically, this is either a single machine
# or three machines if using a high availability deployment.
- address: 172.16.0.3
- address: 172.16.0.4
- address: 172.16.0.5
Pod 和服务的 CIDR 块
clusterNetwork:部分包括分配给集群内 Pods 和 Kubernetes Service 对象的 CIDR 范围;这些范围仅在集群内部可见,永远不会用于外部。只有当与你的网络中现有服务的任何重叠时,才更改默认值,这些服务是集群中运行的 Pod 可能需要联系的服务。
负载均衡器配置
您需要根据所选的负载均衡器模式(捆绑式或手动)以及该模式的期望配置选项来填写 loadBalancer: 部分。以下是对各种规范的描述:
-
mode—负载均衡器模式;您需要在捆绑式或手动之间进行选择。
-
ports.controlPlaneLBPort—负载均衡器服务 Kubernetes API 服务器所使用的端口。
-
vips.controlPlaneVIP—分配给集群中 Kubernetes API 服务器上的 VIP。
-
vips.ingressVIP—分配给集群中第 7 层(L7)Istio Ingress 网关的 VIP;这必须是稍后定义的地址池的一部分。如果集群是混合型、独立型或用户型,则需要此 VIP;在管理集群中不需要,可以保持注释状态。
-
addressPools—数据平面负载均衡器使用的池,用于将 VIP 分配给 Ingress 网关和 LoadBalancer 类型的 Kubernetes 服务对象;它必须包括之前定义的 Ingress VIP,但在管理集群中不需要,可以保持注释状态。
-
nodePoolSpec—列出您想要部署捆绑式负载均衡器的节点地址。只有在您想为捆绑式负载均衡器指定专用工作节点时才需要使用它。如果未注释,负载均衡器将部署在控制平面节点上。
请记住,如果正在部署捆绑式负载均衡器,所有 VIP(包括控制平面和地址池以及 Ingress 网关)都必须位于负载均衡器节点的同一子网中。以下代码显示了一个配置示例,用于在两个专用工作节点(IP 地址为 172.16.0.7 和 172.16.0.7)上部署捆绑式负载均衡器的混合集群:
# Load balancer configuration
loadBalancer:
mode: bundled
ports:
controlPlaneLBPort: 443
vips:
controlPlaneVIP: 172.16.0.16
ingressVIP: 172.16.0.17
addressPools:
- name: pool1
addresses:
- 172.16.0.17-172.16.0.26
nodePoolSpec:
nodes:
- address: 172.16.0.7
- address: 172.16.0.8
代理配置
如果节点需要通过 HTTP 代理连接到互联网,请在 proxy: 部分填写所需信息:
-
url—代理服务器可访问的 URL,格式为 http://username:password@fqdn:port
-
noProxy—不应代理的 IP 地址、主机名或域名列表
以下示例配置了一个可访问于 http://172.16.0.101:3128 的代理服务器条目,无需身份验证,并为 172.16.0.0/16 范围添加了 noProxy 条目,该条目告诉系统不要将此范围内的 IP 地址发送到代理服务器:
proxy:
noProxy: // specifies a list of IPs, hostnames, and domains that should skip the proxy.
- 172.16.0.0/16
url: http://172.16.0.101:3128 // address of the proxy server.
日志和监控的云操作
要配置日志和监控的选项,您需要在 clusterOperations: 部分中添加 projectID 和 location,如下所述:
-
projectID—您想要托管指标和日志的项目 ID。
-
location—您想要存储日志和指标的 Google Cloud 区域。选择靠近您的本地数据中心所在的区域是个好主意。
默认情况下,云操作仅收集管理集群和工作负载以及系统命名空间(如 kube-system、gke-system、gke-connect、istio-system 和 config-management-system)中的工作负载的日志和指标。系统组件的日志和指标也由 Google 支持用于解决支持案例中的问题。除了系统命名空间的指标外,云操作还收集来自所有 Pod 的节点资源使用情况的指标。
您还可以配置云操作收集应用程序日志并使用 Prometheus 托管服务收集应用程序指标。您可以通过修改 stackdriver 自定义资源来在安装后启用这两种功能,就像在其他 Anthos 部署选项中一样。
存储配置
storage:部分包括用于使用本地节点上的挂载点提供持久卷的本地卷提供程序(LVP)的配置。使用本地持久卷将 Pod 绑定到特定的磁盘和节点。如果该磁盘或节点变得不可用,则 Pod 也变得不可用。因此,使用本地 PV 的工作负载需要能够抵御此类故障。因此,通常使用本地持久卷适用于数据持久性不是关键或数据已复制到其他卷且在节点或磁盘不可用的情况下可恢复的证明概念或高级用例。
Anthos 裸金属集群中本地 PV 的存储类有三种类型如下:
-
LVP 节点挂载—此存储类为指定目录中每个挂载的磁盘创建一个本地 PV。每个 PV 映射到与底层磁盘容量相等的磁盘。集群中创建的本地 PV 总数是所有节点下路径挂载的磁盘数量。
-
LVP 共享—此存储类为集群中每个节点的本地共享文件系统上的子目录创建一个由本地 PV 支持的存储类。这些子目录在集群创建期间自动创建。使用此存储类的工作负载将共享容量和每秒输入/输出操作,因为 PV 由相同的共享文件系统支持。
-
Anthos 系统—此存储类在集群创建期间创建预配置的本地 PV,供 Anthos 系统 Pod 使用。不要更改或删除此存储类,也不要为此存储类使用有状态应用。
lvpNodeMounts:部分包含以下参数,用于配置 LVP 节点挂载:
-
path—用作本地持久卷的磁盘挂载的本地节点目录路径。
-
storageClassName—将创建 PV 的 StorageClass。StorageClass 是在集群创建期间创建的。
lvpShare:部分包含以下参数以配置 LVP 共享:
-
path*—在每个主机上创建子目录的本地节点目录路径。将为每个子目录创建一个本地 PV。
-
storageClassName—将创建 PV 的 StorageClass。StorageClass 在集群创建期间创建。
-
numPVUnderSharedPath—在路径下创建的子目录数量。在集群中共享持久卷的 LVP 总数将是此数量乘以节点数。
下一个示例配置使用混合集群的默认参数:
storage:
lvpNodeMounts:
path: /mnt/localpv-disk
storageClassName: local-disks
lvpShare:
path: /mnt/localpv-share
storageClassName: local-shared
numPVUnderSharedPath: 5
认证
如前所述,Anthos 在裸金属上使用 Anthos Identity Service 认证代理通过 OpenID Connect (OIDC) 或 LDAP 与现有的身份提供程序集成。Anthos Identity Service 允许用户通过 GCP 控制台和 kubectl(在这种情况下,使用 gcloud CLI 进行身份验证并创建一个包含用于 kubectl 的 ID 令牌的 kubeconfig 文件)使用现有的企业凭据进行身份验证。
集群配置文件中的 authentication:部分可用于在创建集群时配置身份验证。在集群创建后,也可以使用 ClientConfig 对象或集群级别的 Anthos Identity Service 配置身份验证。
下一个示例配置设置创建集群时 OIDC 认证的参数:
authentication:
oidc:
issuerURL: "https://infra.example.dev/adfs"
clientID: "be654652-2c45-49ff-9d7c-3663cee9ba51"
clientSecret: "clientSecret"
kubectlRedirectURL: "http://localhost:44320/callback"
username: "unique_name"
usernamePrefix: "oidc:"
group: "groups"
groupPrefix: "oidc:"
scopes: "allatclaims"
extraParams: "resource=token-groups-claim"
deployCloudConsoleProxy: true
certificateAuthorityData: base64EncodedCACertificate
proxy: http://10.194.2.140:3128
下一个示例使用 LDAP:
authentication:
- name: ldap
ldap:
connectionType: ldaps
group:
baseDN: ou=Groups,dc=onpremidp,dc=example,dc=net
filter: (objectClass=*)
identifierAttribute: dn
host: ldap.google.com:636
user:
baseDN: ou=Users,dc=onpremidp,dc=example,dc=net
filter: (objectClass=*)
identifierAttribute: uid
loginAttribute: uid
serviceAccountSecret:
name: google-ldap-client-secret
namespace: anthos-identity-service
type: tls
工作节点节点池
如果安装中的第一个集群是混合或独立集群,旨在托管用户工作负载,您需要在集群配置文件中配置工作节点 NodePool 资源,提供目标工作节点的 IP 地址。以下是一个使用节点池中的三个工作节点的示例:
# Node pools for worker nodes
apiVersion: baremetal.cluster.gke.io/v1
kind: NodePool
metadata:
name: node-pool-1
namespace: cluster-hybrid-cluster
spec:
clusterName: hybrid-cluster
nodes:
- address: 172.16.0.8
- address: 172.16.0.9
- address: 172.16.0.10
注意:如果集群是管理集群,本节内容不需要。
创建集群
现在我们已经有一个完整的配置文件,我们可以使用 bmctl create cluster 选项部署集群,如下所示:
bmctl create cluster -c CLUSTER_NAME
将 CLUSTER_NAME 替换为您在创建集群配置文件时定义的集群名称。这个过程需要一些时间,一旦集群成功创建,您就可以通过使用生成的 kubeconfig 文件来连接到它。
连接到集群
集群创建完成后,您可以使用安装工具在 bmctl-workspace/CLUSTER_NAME 文件夹中创建的 kubeconfig 文件来使用 kubectl 连接到它。
您也可以使用承载令牌从 GCP 控制台连接。支持多种类型的承载令牌。最简单的方法是在集群中创建一个 Kubernetes 服务帐户,并使用其承载令牌进行登录。
如果您已将集群配置为与身份提供程序进行身份集成,您可以通过创建 RoleBindings 或 ClusterRoleBindings 来授权现有用户和组对特定资源执行特定操作,将它们分配到具有所需权限的角色。在创建所需的绑定后,您可以通过选择 GCP 控制台中的“使用为集群配置的身份提供程序进行身份验证”选项从 GCP 控制台登录到集群。
要通过 kubectl 对集群进行认证以执行操作,您需要在创建了所需的 RoleBindings 和/或 ClusterRoleBindings 之后执行以下步骤:
-
创建和分发认证配置文件。 您需要创建一个认证配置文件,该文件将被分发给需要使用 kubectl 访问集群的客户端。此文件包含从 gcloud CLI 获取的 OIDC 配置,以从客户端启动认证和令牌请求。
从管理员工作站或任何可以访问安装过程中创建的 kubeconfig 文件的机器执行以下命令:
gcloud anthos create-login-config --kubeconfig CLUSTER_KUBECONFIG将 CLUSTER_KUBECONFIG 替换为安装过程中创建的 kubeconfig 文件。如果命令成功完成,将在当前目录中创建名为 kubectl-anthos-config.yaml 的认证配置文件。此 kubeconfig 文件提供了对集群的 admin 访问权限,并且仅应提供给需要使用 kubectl 进行管理任务的人员。大多数组织应使用现有的安全标准来保护此文件,这些标准是“破窗”过程的一部分。
-
使用集群进行认证。 用于访问集群的客户端机器需要安装 kubectl 和 gcloud CLI,包括 anthos-auth 组件。从客户端机器执行以下命令以从 OIDC 提供者获取 ID 令牌,并相应地配置本地 kubeconfig 以成功认证集群:
gcloud anthos auth login \ --cluster CLUSTER_NAME \ --user USER_NAME \ --login-config AUTH_CONFIG_FILE_PATH \ --login-config-cert CA_CERT_PEM_FILE \ --kubeconfig CLUSTER_KUBECONFIG登录选项在此处描述:
-
CLUSTER_NAME—可选。这是您希望在目标 kubeconfig 文件中定义的集群名称。如果省略此标志,系统将提示您从您的认证配置文件中指定的集群中选择。
-
USER_NAME—可选。这是在 kubeconfig 文件中使用的用户名;如果省略,则默认为 CLUSTER_NAME-anthos-default-user。
-
AUTH_CONFIG_FILE_PATH—指定认证配置文件的路径。
-
CA_CERT_PEM_FILE—指定从您的 CA 获取的 PEM 证书文件的路径,如果认证配置文件存储在 HTTPS 服务器上,则需要此证书。
-
CLUSTER_KUBECONFIG—写入 OIDC ID 令牌的目标 kubeconfig 文件;如果省略,则默认为 kubectl 默认位置。
-
命令将在 OIDC 提供者的同意登录页面打开浏览器,您需要在此处输入凭据。您的 kubeconfig 文件现在包含一个 ID 令牌,您的 kubectl 命令将使用此令牌与集群上的 Kubernetes API 服务器进行认证。
17.4.2 创建用户集群
一旦您创建了一个管理员或混合集群,您就可以向其中添加用户集群。您可以通过应用一个只包含新集群的 Cluster 和 NodePool 自定义资源清单的新配置文件来完成此操作。创建第一个集群的高级步骤如下:
-
使用 bmctl 创建集群配置模板文件。
-
使用所需的设置修改配置文件。
-
使用 bmctl 应用配置文件。
这些任务是你已经为创建第一个集群所做任务的一个子集。在下一节中,我们将详细说明部署用户集群的配置文件。
创建集群配置
与创建第一个集群时相同,使用以下命令启动集群配置文件:
bmctl create config -c CLUSTER_NAME
其中 CLUSTER_NAME 是您希望赋予用户集群的名称。
填充集群配置文件
与创建第一个集群时相同,您需要准备由 create config 命令创建的配置文件。该文件默认保存在名为 bmctl-workspace 的文件夹内,以集群名称命名的文件夹中。
对于配置文件中的许多部分,已经为第一个集群创建提供的相同说明也适用于用户集群,因此请遵循第 17.4.1 节中“填充集群配置文件”给出的说明。
注意:确保控制平面和负载均衡器部分以及 NodePool 资源中使用的 IP 地址与您为第一个集群已使用的地址不冲突。
在下一节中,您将找到针对用户集群特定的任务。
删除凭据部分
用户集群将使用在管理员/混合集群创建期间提供的凭据,因此我们不需要为 GCP 提供凭据。因为这些不是必需的,我们需要从文件中删除,例如包含指向密钥的节:
gcrKeyPath: <path to GCR service account key>
sshPrivateKeyPath: <path to SSH private key, used for node access>
gkeConnectAgentServiceAccountKeyPath: <path to Connect agent service account key>
gkeConnectRegisterServiceAccountKeyPath: <path to Hub registration service account key>
cloudOperationsServiceAccountKeyPath: <path to Cloud Operations service account key>
集群类型
在集群中将类型规范值设置为用户:
---
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
name: user-cluster
namespace: cluster-user-cluster
spec:
# Cluster type. This can be:
type: user
负载均衡器配置
接下来,您需要提供用户集群负载均衡器的配置,如下所示。这里使用的 IP 地址不能与分配给第一个集群的负载均衡器重叠:
# Sample user cluster config for load balancer and address pools
loadBalancer:
vips:
controlPlaneVIP: 10.200.0.71
ingressVIP: 10.200.0.72
addressPools:
- name: pool1
addresses:
- 10.200.0.72-10.200.0.90
创建集群
完成集群配置文件后,您可以使用以下命令创建第一个集群:
bmctl create cluster -c CLUSTER_NAME --kubeconfig ADMIN_KUBECONFIG
用户集群部署完成后,您可以使用生成的 kubeconfig 连接到新集群。
连接到集群
集群创建后,您可以使用 kubectl 从用户集群命名空间中安装过程创建的 Secret 中提取 kubeconfig 来连接到它。以下是一个提取 kubeconfig 的示例命令:
kubectl --kubeconfig ADMIN_KUBECONFIG get secret USER_CLUSTER_NAME-kubeconfig -n USER_CLUSTER_NAMESPACE -o ‘jsonpath={.data.value}’ | base64 -d > bmctl-workspace/user-cluster/USER_CLUSTER_NAME-kubeconfig
您也可以使用承载令牌从 GCP 控制台连接,或者如果您已为集群配置了身份集成,用户可以按照第 17.4.1 节中“连接到集群”所述的步骤从 GCP 控制台和 gcloud CLI 验证集群身份。
17.5 升级集群
当 Anthos on bare metal 发布新版本时,您可以升级您的集群。在非独立集群安装中,您需要首先升级管理员/混合集群,然后升级用户集群。
17.5.1 升级管理员、独立或混合集群
执行升级到管理员、独立或混合集群的步骤如下:
-
修改在集群创建过程中使用的集群配置文件,以将 Anthos 在裸金属集群的版本从现有版本更改为要升级到的版本。以下是一个升级到版本 1.13 的示例配置:
apiVersion: baremetal.cluster.gke.io/v1 kind: Cluster metadata: name: admin-cluster namespace: cluster-admin-cluster spec: type: hybrid # Anthos cluster version. anthosBareMetalVersion: 1.13.0 -
下载所需的 bmctl 工具版本(您要将集群升级到的版本):
gs://anthos-baremetal-release/bmctl/<VERSION>/linux-amd64/bmctl -
执行以下命令以升级集群
bmctl upgrade cluster -c CLUSTER_NAME --kubeconfig ADMIN_KUBECONFIG
其中,CLUSTER_NAME 是集群名称,ADMIN_KUBECONFIG 是由安装创建的 kubeconfig 文件。
17.5.2 升级用户集群
在您升级了管理员或混合集群之后,可以按照以下步骤升级用户集群:
-
如同管理员/混合集群配置文件的做法,修改用户集群配置文件,以将 Anthos 在裸金属集群的版本从现有版本更改为要升级到的版本。
-
执行以下命令以升级集群版本
bmctl upgrade cluster -c CLUSTER_NAME --kubeconfig ADMIN_KUBECONFIG其中,CLUSTER_NAME 是要升级的用户集群名称,而 ADMIN_KUBECONFIG 是由第一个管理员/混合集群安装创建的 kubeconfig 文件。
摘要
-
Anthos 在裸金属上允许组织在非 VMware 平台上部署 Anthos,包括裸金属或替代虚拟机管理程序。
-
在使用裸金属安装时,提供了不同的部署选项,包括管理员/用户、混合和独立集群。
-
Anthos 在裸金属上提供了多种负载均衡选择,包括使用外部负载均衡器(称为手动模式)或包含的选项(称为捆绑模式)。捆绑模式将为控制平面部署 HAProxy 解决方案,并为工作负载部署 MetalLB。
-
裸金属安装提供的默认存储选项仅限于本地主机存储,并且应仅用于开发集群。
-
在裸金属上安装 Anthos 提供了一个简单的部署和升级过程,使用几个自文档化的配置文件,这些文件通过单个可执行文件 bmctl 部署。
附录 A. 云是一个新的计算堆栈
菲尔·泰勒
本章将涵盖以下主题:
-
数字速度和企业的困境
-
传统的应用程序开发和交付模型
-
打破应用程序交付格局和云的诞生
-
微服务和容器
-
软件定义一切和 DevOps
-
云是现代计算堆栈
A.1 简介
许多技术高管和工程师将云视为一个新的目的地。实际上,它是一种新的思维方式。云最好被定义为一套现代模式和最佳实践,它抽象化了底层基础设施。在新的技术堆栈之上,是分布式系统新架构的演变,这允许在不要求开发者管理底层基础设施及其设计的情况下进行扩展。这大大降低了构建高度可扩展、安全和分布式应用的门槛。
大多数小型公司或初创公司已经在云上运行并实现了这些优势。然而,与云相比,企业计算平台和应用程序通常更为复杂。这意味着企业需要在未来许多年里支持他们的数据中心和分支机构。他们的云迁移必须更加有目的和深思熟虑。
在过去,开发新应用程序的前期劳动力和成本代表了公司投资的大部分。有三个主要因素影响了这些成本:
-
购买硬件和为您的新产品构建软件所需的资本。
-
获取基础设施并正确部署到数据中心所需的时间。
-
快速扩展基础设施以应对预期和非预期使用高峰。
早期的云计算能力通过允许消费者以基础设施即服务(IaaS)模式租用硬件来解决这些问题。在这种模式下,一个新的产品团队可以在几分钟或几小时内部署所需的基础设施,并几乎立即开始开发他们的应用程序。云基础设施的按分钟计费模式也有助于控制前期成本。
在任何成功产品的生命周期中,都有多次扩展事件和更高的可靠性需求,这要求您扩展基础设施以满足新的需求。公共云提供商使您能够轻松扩展或缩减您的网络、计算和存储基础设施,以适应这些事件。
尽管企业公司跟上变化步伐的难度比以往任何时候都要大,但启动一家初创公司并在此领域竞争却比以往任何时候都要容易。这为企业应用程序设计、计算模型和交付生命周期创造了巨大的创新需求。
在 2011 年,马克·安德森在《华尔街日报》上发表了一篇题为“软件正在吞噬世界”的社论(由他的风险投资公司在此处a16z.com/2011/08/20/why-software-is-eating-the-world/)。他的大部分同行投资者和世界各地的商业高管可能都认为马克疯了。毕竟,自上次.com 泡沫破裂以来已经过去了 10 年,他们都认为它将再次发生。变化的步伐并不像今天这样快,技术愿景家马克又一次对了。他发明了现代网络浏览器和公司网景,之前他已经见过这种变化了。
马克所谈论的变化现在才被大型企业公司大规模应用,这得益于新的能力,如谷歌云平台(GCP)和 Anthos。变化的步伐比以往任何时候都要快。这个术语已经成为数字速度的代名词。
A.2 数字速度与企业困境
在 20 世纪初,商业增长缓慢,平均需要 90 年才能达到 10 亿美元(美元)的年营收(见www.inc.com/laura-montini/infographic/how-long-it-takes-to-get-to-a-1-billion-valuation.xhtml)。这使得那些首先或早期进入市场的公司能够有效地垄断其行业。二战后的制造业创新将这个平均时间缩短到大约 25 年。快进到 20 世纪 90 年代末,随着公司利用技术加速其商业模式,事情开始变得热烈。大多数加速发生在没有实体存在的公司(真正的网络公司)中,在这个时代,除了少数闪耀的明星如谷歌、亚马逊和 Netflix 之外,大多数全栈公司都失败了。今天,软件开发和基础设施运营的创新导致了惊人的加速。这些数字速度的进步在相对较短的时间内颠覆了整个市场。想想 Netflix 对流媒体、亚马逊对零售、AirBnB 对短期租赁和 Uber 对出租车所做的事情。
在 2021 年及以后,由于新的软件开发模式和更高效的资源,没有哪个市场能够免受数字速度进步带来的颠覆。每个公司都在发现他们正在迅速成为软件公司。在下一节中,你将开始分析这些软件开发模式。
A.3 应用程序开发和交付的传统模式
从历史上看,企业应用程序最常使用单体软件开发模式。为了帮助处理规模化的单体,许多开发者从 COBOL 等语言中的函数式编程转向现代语言如 C++或 Java 中的面向对象编程(OOP),并利用模块化设计模式。这使得开发者可以将代码库分解成库,这些库可以在整个应用程序组合中共享和重用。例如,其他提高效率的尝试包括在关系数据库中使用存储过程来更快地处理数据。这些创新有助于减少劳动强度,但它们很少允许企业将创新思想扩展到超过几个团队。相反,企业更常陷入处理由这些新开发范式引入的遗留问题。
当 IT 行业开始时,代码会被编写并保持相对静态数月甚至数年。大多数企业没有投资于重写或重新平台化代码。随着这些基于面向对象编程(OOP)的新应用程序有机增长,支持它们变得越来越复杂。如今,这些混乱的解决方案区域或“漏洞”如它们通常被称为,正式被称为技术债务。技术债务被视为一个一等因素,可以用来衡量组织或特定项目的数字速度。过多的技术债务会导致随着时间的推移速度降低,而不足则意味着在大多数情况下,你移动的速度不够快,无法跟上业务需求。
企业应用程序使用三种流行的设计模式构建(1)客户端-服务器,(2)n 层 Web 架构和(3)面向服务的架构。
A.3.1 客户/服务器架构的优点和缺点
客户/服务器架构(见下文图 A.1)简单且易于构建。几种流行的编程语言和运行时环境有助于更快地构建客户/服务器应用程序。这些快速应用程序开发(RAD)平台,如 Visual Basic 或 Delphi,易于使用,许多开发者能够快速得到结果。
这种应用架构的缺点包括逻辑重复(业务逻辑在客户端和服务器代码库中重复),需要在最终用户机器上安装应用程序,在这些机器上更新应用程序,并保持服务器及其客户端同步。所有上述问题都导致了用户可用性问题、更高的可持续性成本以及将新功能推向市场所需的时间更长。

图 A.1 客户/服务器架构
A.3.2 Web 架构的优点和缺点
随着现代网络浏览器的发明,一种更复杂的架构开始演变。这种架构类似于旧哑终端时代,当时应用程序是集中部署和管理的。这种新的多层架构(见图 A.2)基于我们应该将我们的应用程序一般性地分为三个层次:表示层、应用程序或业务逻辑层和数据层。

图 A.2 N-Tier(Web)应用程序架构
尽管这种架构和部署模型解决了客户端-服务器的一些陷阱(在客户端安装和更新应用程序),但在规模上仍然存在类似的问题。这些应用程序中的大多数仍然存在重复的逻辑(数据验证、业务逻辑),这导致可用性问题、更高的可持续性成本以及将新功能推向市场所需的时间更长。
A.3.3 面向服务的架构
客户端-服务器和多层架构都存在另一个共同陷阱:服务器上的应用程序崩溃会影响每个模块或服务,甚至可能影响大多数用户。面向服务的架构(SOA),如图 A.3 所示,有助于解决单体架构和运行时支持的一些挑战。SOA 模型将应用程序业务逻辑分解为众所周知领域,并在其他层之间通信和安全性方面采用标准协议。这种模式提供了许多操作和开发优势,包括更好的可扩展性和弹性。尽管 API 革命仍然有效,但在采用 SOA 时仍存在一些陷阱,包括商业产品所需的底层框架的成本和复杂性,这些框架难以安装和维护,导致更高的总拥有成本(TCO)。然而,其最大的陷阱是采用复杂模式和协议的学习曲线。这些限制和高成本导致近年来其受欢迎程度下降,微服务模式兴起。我们在第??章,应用程序现代化中更详细地介绍了微服务。

图 A.3 SOA 架构
在这个演变过程中,数据中心也在经历变革和颠覆。
A.4 打破应用程序交付并诞生云
随着应用开发方法的演变,团队仍然难以成功构建他们的源代码并将其部署到现有的基础设施中。流程是手工的且容易出错。开发人员、运维团队和管理人员深夜进行电话会议以部署和调试应用程序的情况并不少见。为了帮助解决这个问题,开发了 持续集成 (CI) 和持续交付 (CD)。持续集成是在一天中一次或多次合并所有开发人员更改的过程,以验证构建完整性。持续交付是在任何时间点验证和打包部署工件以发布的过程。CI/CD 的目标是创建一个可靠的构建和打包过程,以实现可重复的成功。即使有像 CI/CD 这样强大的框架,实现其效率也很有挑战,因为用于开发软件的框架是为设计数月或数年的应用程序设计的,并且在长时间内基本没有变化。其中最受欢迎的项目管理流程之一被称为水瀑布。
A.4.1 打破软件制作方式
水瀑布是一种项目管理流程,旨在根据里程碑、时间表和资源来管理项目。在水瀑布项目中,团队会进行大量的前期工作,以思考所有需求并设计解决方案。这通常会导致在产品周期后期出现问题,因为业务需求已经改变,而设计没有反映新的业务需求。这不可避免地导致错过截止日期和最终产品的质量问题。
从 2001 年发布《敏捷宣言》(agilemanifesto.org/) 开始,开发团队开始评估他们的项目管理流程。一个提供更高效软件开发的主要流程是敏捷团队通过思考主要需求和草拟高层次设计来开始一个项目,而不是进行完整详细的设计。
随后,团队通过迭代工作来交付具有更现实设计的可工作软件,每次迭代都会有所改进。Scrum 是一个广为人知的框架,用于使用敏捷思维开发和交付复杂产品。许多团队更喜欢使用 Scrum 方法来运行他们的敏捷项目,以及被称为冲刺的两周迭代。一旦团队转向敏捷,他们就必须实施 CI/CD,因为他们现在需要在每个迭代的结束时构建、测试和发布系统。
A.4.2 谷歌的开发创新
在谷歌,我们利用多种模式来创建加速,如单一代码库和主干开发,这些模式在流行的书籍谷歌软件工程,O'Reilly中都有描述。谷歌用于创建加速的许多模式已被整个行业采用。
A.4.3 行业中的应用程序开发
2017 年,根据 InfoQ 发布的文章,Facebook 团队每天仅为其 Android 应用程序进行 50,000 次构建。我们刚才提到的统计数据仅指他们的持续集成过程,该过程负责构建源代码并运行本地测试以验证构建。它不包括持续交付工作流程,这些工作流程需要大量基础设施来部署 50,000 个应用程序版本到物理或虚拟设备,并运行额外的测试。
这些基础设施挑战并不仅限于 Facebook。多年前,谷歌和亚马逊在构建和运营其核心基础设施和应用程序时遇到了类似的挑战。这些挑战直接导致了我们今天所知道的云。云平台的出现很大程度上是由内部 IT 团队无法在可接受的时程内响应业务需求所驱动的。影子 IT,如通常所知,是利用第三方 IT 提供商来满足业务需求,而无需内部 IT 团队。许多早期的云客户在完全采用新的云平台作为基础设施和应用程序交付的标准之前,都是从影子 IT 模式开始的。2006 年,当亚马逊推出 Amazon Elastic Compute Cloud (EC2)时,Heroku(2007 年)、GCP(2008 年)、Azure(2010 年)和 Cloud Foundry(2011 年)迅速跟进 EC2。Heroku 和 Cloud Foundry 都是基于云的平台即服务(PaaS)解决方案,专注于构建12 因子应用程序的理念。尽管所有这些基于云的平台在创造渐进式改进方面都很出色,但企业客户在创造全面转型方面却遇到了困难。公共云需要更多的成熟度,而早期的 PaaS 平台如Google App Engine范围较窄,对语言和高级语言功能的支持有限。
虽然上述平台都有其局限性,但这标志着数据中心和许多商业市场的颠覆时代的开始。这是历史上第一次,你不需要构建软件、购买硬件和建立数据中心来启动你的新创业公司。你只需从云或 PaaS 提供商那里租赁基础设施,构建和部署你的应用程序!
这一代初创公司通常被称为“数字原生者”;在云中诞生的公司。他们的创新继续推动应用程序的创建方式。
A.4.4 首先制定合同的开发、SOA 以及向微服务的演变
大约在 2005 年,架构师和开发者开始讨论测试驱动开发(TDD)的想法。测试驱动开发(TDD)的原则表明,遵循这些原则可以使代码更易于测试,最终更可靠。TDD 的概念是在编写代码之前,先思考编码问题,编写测试计划和实际测试。许多开发者在这个实践中取得了成功,它演变成了设计由合同的概念。如果你正在编写一个公开 API 的 Web 服务,那么你应该首先定义合同和数据模型。这迫使开发者思考输入/输出边界,并构建一个封装良好的服务。它还给你的 API 消费者团队提供了一个合同,以便在他们的开发过程中开始使用。设计由合同利用了 SOA 的几个概念。在 SOA 中,开发者使用 Web 服务模式构建所有子系统,并在服务之间使用消息协议。随着新想法的应用,新的技术开始出现。
A.5 微服务和容器
当企业采用 SOA 来构建复杂的后端子系统时,科技初创公司继续进行创新。在许多方面,微服务是 SOA 的一种演变。它们共享相同的核心理念,即构建所有子系统作为相互通信的 Web 服务,如图 A.4 所示。

图 A.4 微服务架构
微服务与传统的企业服务总线(ESB)和简单对象访问协议(SOAP)协议不同,它们更倾向于智能端点和简单的协议。ESB 的功能是集中化服务通信、消息转换和路由。而微服务则利用发布/订阅(Pub/Sub)消息总线,并倾向于服务之间的去中心化通信。
相反,团队使用 HTTP + JSON 作为传输和有效载荷协议来构建REST Web 服务。以下是一些其他关键区别:
-
微服务的设计围绕业务能力(领域驱动设计)进行组织。这使得我们能够编写具有清晰边界的软件,专注于解决单个业务问题或一个微服务内的一组相关问题。
-
团队选择编程语言、数据库或其他技术堆栈架构以满足需求。这允许团队选择适合解决微服务负责提供的领域问题的技术。
-
“无共享”方法,每个服务都有一个隔离的数据存储。这种方法允许团队在 API 层面上进行集成,将所有功能封装在其服务中,并对任何依赖服务有清晰的边界。
-
所有通信都通过单个合同进行,通常通过 RESTful API 公开。服务之间的所有通信(内部消费者或外部消费者)都访问相同的 API 接口。
-
智能端点,哑管道 - 利用简单的协议,服务知道如何处理输入和发送输出。
-
消息队列被用于大规模的异步处理和节流。这是服务的责任,实现一个消息栈来支持这一功能。并非所有服务都需要它。
-
使用这些云原生设计模式进行自动化测试要容易得多,我们能够创建专用于测试特定组件或功能的不持久环境,在将软件发布到集成环境进行端到端测试之前。在过去,大多数团队都难以编写能够准确验证其软件且在部署之间不需要大量更改的自动化测试。测试金字塔 是一个隐喻,告诉我们将测试分组到不同粒度的桶中(UI 测试、服务测试、单元测试)。大多数单体应用开发团队专注于构建 UI 测试来验证应用程序。由于 UI 组通常需要更多的集成,这意味着这些测试通常需要定期更新。这使他们无法实现像 金丝雀 或 蓝/绿 部署这样的高级模式。金丝雀是指我们会缓慢地将测试过的软件推出给一小部分用户,收集实时反馈,然后再推出给所有用户。而蓝/绿则允许我们维护两个副本;一个绿色或生产环境和一个蓝色或预发布环境,这样如果出现问题,我们可以快速回滚到之前的状态。由于这些应用大多数是从零开始构建的,因此团队能够正确应用测试金字塔,以及像金丝雀或蓝/绿部署这样的高级端到端部署模式。这导致了完全自主的部署和无可匹敌的开发速度。单体团队面临的另一个重大挑战是数据恢复;向软件平台注入自动化测试所需数据的可能性。数据恢复的挑战不再是问题,因为这些团队通常将所需的数据集作为其自动化测试代码库的一部分构建起来。这使得他们能够满足测试计划中每个用例的独特需求,并避免将实时数据复制到测试系统所造成的合规性问题。
微服务架构可以快速、高效且强大。但要得到广泛的应用,它们也需要基础设施的创新。这种创新发生在 Linux 容器进入市场的时候。
A.5.1 容器化使微服务成为可能
容器化自 Solaris Unix 时代以来就有一些形式。历史上容器的问题在于它们很难构建,构建一个容器需要一系列命令行界面(CLI)调用。2010 年,Docker 通过发布他们自己的开源容器引擎,彻底改变了这一过程。
这个新引擎允许我们在源文件中记录容器需求,并大大减少了我们成功构建容器所需的 CLI 调用次数。新的 Dockerfiles,Docker 的另一个创新,为开发者提供了一种使用基础设施即代码(IaC)方法来记录容器需求的方式,而不是记录 CLI 调用。通过将应用程序或微服务打包到容器中,开发者可以快速构建、测试并将他们的应用程序部署到目标环境中。这允许开发者构建软件、构建目标环境,然后将整个应用程序堆栈作为一个单一的工作单元进行部署和测试。
单个容器是一个第一步,但完整的应用程序需要编排多个容器并在底层基础设施上实例化它们,这使得事情变得更加复杂。
Kubernetes 解决了大多数基础设施和部署问题(配置、服务发现、密钥、调度等),并为应用程序基础设施提供了一个通用的编排接口。随着团队扩大其解决方案,他们通常需要超出 Kubernetes 提供的基本功能的更多能力。运行大型解决方案的团队通常需要更高级的功能,并利用其他生态系统服务,如 Istio 进行服务网格或 Apigee 进行 API 网关流量。
A.5.2 软件定义一切和 DevOps
正如你可能开始意识到的,速度的关键是通过软件开发和独立部署,这允许团队在有限的协调下并行工作。仅仅用软件构建你的应用程序是不够的。云已经向我们展示了,当整个解决方案可以定义为代码时,真正的速度才会发生。这个概念被行业定义为 DevOps,它涵盖了不仅仅是技术组件。我们不会在这个书中展开所有 DevOps 概念,而只会关注技术方面。如果你想了解更多关于 DevOps 的信息,我们建议你阅读《DevOps 手册》。
要完全自动化应用程序的构建、测试和部署,团队需要成为 CI/CD 概念的专家,并掌握基础设施即代码 (IaC)。下面的示例,图 A.5 展示了支持 Kubernetes 应用程序部署的 CI/CD 管道的可视化。

图 A.5 Kubernetes 应用程序的 CI/CD 管道
在早期尝试部署容器的团队中,结果参差不齐,因为他们需要解决大量核心平台问题,这些问题对于以规模服务于这些应用程序至关重要。为了成功构建、测试和部署应用程序,还有很多工作要做。这就是为什么 Google 创建了 Kubernetes,随后又推出了 Anthos。Anthos 大大简化了创建和管理 Kubernetes 集群以及支持多个集群和混合集群架构所需的辅助组件和流程。Anthos 将帮助您的团队部署核心 Kubernetes 发行版,统一将安全策略应用于集群,提供增强服务网格的能力以处理混合云或混合集群路由,以及更容易地应用升级或其他操作任务。有了 Anthos,开发者可以实现“一次编写,到处运行”,包括跨多个云、边缘和本地环境。
A.5.3 云是现代计算堆栈
在本章中,你了解了现代企业崛起的速度以及技术和软件模式是如何改变以实现这种加速的。十年前,一家新企业进入出租车市场并在短短几年内颠覆整个行业是不可想象的。今天,由于新企业的快速增长,这已成为一种常态,这得益于数字速度软件架构和互联网带来的普遍访问。
使这一切成为可能的概念可以归结为分布式高度可扩展的架构,如微服务,以及使用 DevOps 模式如 SRE 来自主交付这些解决方案,从而实现快速迭代变化。这种创新步伐的快速开始于云原生初创公司开发新技术。在短短几年内,它们现在也成功地应用于企业工作负载和现有应用程序。
A.6 摘要
-
企业正在利用公共云来满足其业务需求和敏捷性。
-
微服务在软件设计中变得越来越受欢迎,允许并行开发以满足软件需求,而不需要单体架构的典型缺点。
-
能够实现自主部署的良好的 CI/CD,能够利用 IaC 和自动化测试,对于成功至关重要。
-
团队正在利用容器和 Kubernetes 对这些应用程序进行打包和操作。
-
Google Anthos 正在填补空白,使 Kubernetes 成为企业的可靠可扩展平台。
附录 B. 来自现场的经验教训
凯尔·巴塞特
B.1 简介
从前,“云”出现之前,我们中的许多人都是在主要静态的数据中心内部交付基础设施和平台服务。我们大部分的架构和实施工作都是基于先进行研究,然后是概念验证和供应商选择。在大多数情况下,真正的实施工作直到“箱子”到达并上架堆叠之前从未开始。这与今天的情况大相径庭,今天,无尽的基础设施只需一个 API 调用和一张信用卡就能触手可及。大多数最受欢迎的软件也得益于开源和志同道合的社区成员的共同努力,他们不断努力添加功能和功能。开始和运行实验的门槛非常低,我们可以通过尝试某事来快速做出决定,而不是依赖于广泛的研究或进行传统的 RFP。这也使得我们能够接受失败,并专注于在实现更大目标的过程中学习。当进行实验时,即使它被视为过程中的失败,也可以被视为成功。在实验中,你很可能学到了一些有价值的东西。
我们还应该认识到,这种加速的步伐和发展速度在很大程度上得益于更大的“云”和“企业”公司大量投资于开源和软件,以推动事物向前发展。这些投资使我们能够以产品化的方式消费大量的开源软件,并附带支持和保证。那些投资的人承诺在过程中与你合作。在提供投资收益的同时投资开源可能是一个复杂的商业模式,但代码已经被破解,Anthos 就是谷歌大量投资获得回报的一个很好的例子。提供即插即用的可扩展云服务,帮助我们迁移、重新平台化和现代化我们的应用程序集群。
Anthos 由一组基础开源项目组成,这些项目提供了构建的基础,并提供了增强的托管云服务。Kubernetes 是一个经过验证的坚实基础,它允许许多平台功能来增强整体用户体验。当我们深入研究从现实世界的 Anthos 实施中学到的经验教训时,我们将关注如何构建在这些基础技术之上,以提供基于现代 Kubernetes 的平台服务。
在这本书中,你有机会了解 Anthos 的许多技术方面和能力。正如你所看到的,Anthos 并不是仅仅作为一个可以在数据中心运行的另一个 Kubernetes 发行版,或者另一个云服务提供商而存在的。GKE 和 Kubernetes 社区为我们打下了坚实的基础,使我们能够超越单个应用,开始大规模提供平台服务,而不是仅仅关注单个应用。在本书的结尾,我希望你能将 Anthos 视为一个平台战略,通往“云”、“云原生思维”的门户,以及推动企业业务应用现代化的催化剂。持续改进是成功实施任何事物的关键方面,本章将尝试传授在客户思维导向的客户合作中学习到的一些经验教训。
作为 Anthos 早期设计合作伙伴,有机会与谷歌的产品和工程团队合作,这为理解 Anthos 背后的战略提供了广阔的视角。这也为我们提供了在 Anthos 推向市场时贡献客户视角的机会。开发一个解决新兴“云原生”用例的产品是我们许多人开始感到兴奋的地方,但 Anthos 旨在满足你的当前需求,解决今天许多基础设施、应用和业务挑战。我邀请你思考一下“一次编写,到处运行”的概念,以及能够利用一套通用的工具和体验来提高你的应用集群的效率和一致性。
作为一个行业,我们倾向于关注软件开发和云平台服务的技术方面。现实是,开发成功的技术并将其推向市场是一回事,但要实现真正带来商业价值的基本成功,需要从不同的角度看待事物。考虑一下你的客户体验,记住客户也可以是内部利益相关者和团队成员。采用客户导向的平台和应用交付方法帮助我们所有人关注重要的事情,以及哪些领域应该优先于其他领域。客户体验思维方式开始重新定义我们做事背后的文化和我们为什么这样做。我们开始问自己,哪些原则和成功标准将推动业务向正确的方向发展?最终,帮助实现最终的商业案例和投资。
例如:让我们来看看初创文化与企业文化的对比。考虑到它对不同人可能意味着不同的事情,文化这个词可能有点棘手。但让我们从事情如何完成的视角来看,以及一个组织如何确定优先级并推动变革。从在初创公司工作的角度来看,变革以持续改进的形式伴随着工作性质,在许多情况下,风险和赌注都相对较低。不做大胆行动的风险远大于对现状感到舒适。如果你的团队没有感到赋权,安全地突破边界和跳出思维定式,你很可能无法生存,也无法改变你打算颠覆的市场。这从来不是关于建造一个更好的捕鼠器,而是关于解决大多数人从未承认存在过的真实商业问题。
现在,如果我们转换到一个大型、成熟的企业公司的视角,做出大胆行动的风险自然更大。公司已经建立,正在解决真实问题。你很可能面临着巨大的压力,需要提供一致和可靠的服务,更不用说可能还受到监管和合规审查。这使得变革变得困难,有时人们开始陷入困境,创新受到影响。现在,对于一家更大的成熟企业来说,这也可以是一个机会,因为它们也有更大的能力吸收失败。随着他们学会做出更小、更频繁的变革并更快地发布软件,“变革”变得更加舒适、可靠,风险特征在许多方面开始产生较小的影响。商业利益...
在当今竞争激烈的经济环境中,现有企业面临着更大的压力,以保持竞争力并保持领先地位。技术是颠覆性变革的巨大推动力,允许小型企业从大型成熟玩家那里赢得市场份额。这对大型成熟公司开始拥抱变革并推动其技术资产现代化是一个巨大的催化剂。那么,如何平衡这些动机呢?是努力寻求稳定并在我们的组织中减少变革,还是接受一些风险,采用新技术以推动边界和业务向前发展?你如何确保自己永远不会落后?
这并不总是一个容易回答的问题,找到“最佳平衡点”是成功的关键。我们旨在拥有两者的最佳结合;我们希望有一个稳定、安全的平台来托管我们的应用程序,但同时也需要创新以保持竞争力并利用新的商业和市场机会。这些动机总是相互拉扯,平衡对于长期成功至关重要。如今,一个流行的策略是开始思考接近“云原生”架构和“云原生”思维。理解这一方法的一个简单方式是将应用程序分解成更小的部分,将业务逻辑分离成独立的服务。这使你能够以更少的相互依赖性开始开发、测试和发布应用程序。最终,这应该使你能够提高向生产环境交付特性和功能的速度。虽然这种方法不会立即带来成功,但它需要大量的工作和一个与组织内部一致的战略。它已经被证明多次为许多大型企业公司带来巨大价值,并且绝对值得你考虑。
本章的其余部分将专注于分享在实施新技术(如 Anthos)时的经验教训,这些技术并不总是以严格的设置要求或目标开始。许多这些经验教训来自与大型企业客户的实施经验,这些客户已经非常稳定,通常拥有长期的企业和技术流程。他们渴望快速行动并突破边界,但同时也认识到变化对他们组织来说是一项挑战,并且需要采取平衡的方法以实现长期成功。
在许多情况下,初始目标是为了拥抱和采用新技术以推动业务发展,同时也要在变化速度、稳定性和不需要改变那些正在有效缓解风险的既定业务流程之间保持平衡。另一个重要的考虑因素是从第一天起就采取“安全第一”的方法,如今,采用声明式自动化方法进行配置安全性的平台可以从一开始就集成。一个流行的趋势是将安全考虑和需求早期整合到配置管理流程中。这也使得平台用户能够持续获得反馈,提升开发者体验,并且不提及其他方面,将安全作为平台和应用部署流程的一部分。
B.2 来自实践的一些经验教训
B.2.1 首先——你试图去哪里,为什么?
这可能听起来像一个非常开放的问题,但确保你保持正确的方向并朝着共同的目标努力是至关重要的。你正在组建的团队需要投入于共同的成功。最初最重要的方面之一是就一些高层次的目标达成一致。通常,如果你四处询问,开始这段旅程的主要原因可能是“达到云”,现在“云”有很多不同的定义,取决于你问谁,但我们可能可以就一些目标达成初步共识。
一些值得初步考虑和思考的是:
-
保持面向未来的心态,更多地关注战略而不是单个功能。你正在构建或选择的平台可能今天并不具备所有功能。你感觉会是这样吗?你是在选择正确的合作伙伴来为你的未来做好准备吗?
-
早期就认识到你是在为未来解决问题,你不仅仅是在根据一组需求实施基于软件的参考架构。新的技术和业务需求将继续被识别。
-
将“转型”作为进行所有这些工作的更重要的原因。认识到真正的转型将会很困难,并且失败的可能性很高。
-
就一些简单的关注领域达成一致,例如“速度、平台稳定性和减少运营活动”。提升开发者体验。
-
尝试融入最佳实践,并寻求帮助以找到一些捷径。
-
记住你的用户社区,他们很可能希望有更智能的默认设置,确保你在开始时提供具有明确选项的平台和服务目录将是成功的关键。
同时也要问问自己,你作为领导者的遗产会是什么?你为组织带来了什么样的真正转型?正如我提到的,这不仅仅是安装软件,理想情况下,你是在为组织的未来成功、速度和运营稳定性打下基础。我认为我们都可以同意,向“云”和“云原生”的转型只会增加,我们需要帮助我们的组织做好准备,并为他们设定长期成功的基调。
B.2.2 对变化感到舒适
让我们面对现实……改变对每个人来说都很困难,而不仅仅是商业和技术方面。技术变革也可能带来一系列全新的挑战。任何告诉你有“一键式”解决方案的人,很可能是在试图向你推销,而不是帮助你解决问题。在很多情况下,投资于变革或现代化的原因并不总是显而易见,或者并不在你面前。这需要一些前瞻性的战略思考和一支有动力的团队来迎接未来的挑战。
B.2.3 与他人分享经验,无论是好是坏
我们之前讨论了开源和繁荣社区的强大力量。从许多繁荣的社区和项目的崛起和增长中,我们学到了无数的教训。我们必须记住,我们中的许多教训都是通过“艰难的方式”和克服挑战学到的。与他人分享这些故事是传承经验和培养成功项目的一种最佳方式。努力扩大你在组织内部的部门间影响力,找到分享你的项目信息并尽早邀请反馈的方法。这种早期合作将鼓励外部利益相关者成为团队的一员,并投资于你项目的成功。记住,在某个时候,还需要其他团队加入、运营和维护你实施的平台。与你的谷歌同事合作,你指尖就有大量的社区经验。谷歌知道如何推动团队间的协作,并将软件推向生产并在客户手中。Anthos 是一个加速这一过程的软件平台,但我们也都可以从这次经历中学到许多非技术性的人性化教训。
B.2.4 确定你的动机,包括短期和长期的成功标准
在开始任何项目时,花些时间记录你开始项目的动机总是个好主意。另一个有助于以后调整优先级并保持你按计划进行的方面是,就成功的样子达成一致。理解这些并不是总是固定不变的,你需要找到激励自己和团队的方法。尝试在你的具体技术愿望之外,确定一些商业目标,技术上的胜利通常更容易识别,但商业目标通常是更重要的。在这个过程中,你将希望不断地回顾你的成功标准,并在必要时进行细化。这有助于你将项目与你的原始目标对齐和评估。这也给你一个机会,做一些调整以确保你实现商业目标。记住,在项目过程中,你的动机和成功指标往往会发生变化,这是正常的...
B.2.5 制定有意义的指标 - 发布一个简单的仪表板
另一个需要考虑的重要问题是,你将如何衡量这些过程中的结果。如果你没有衡量方法,将很难知道你的项目是否在正轨上,或者何时需要调整方向并重新对齐。与利益相关者和组织内部感兴趣的人分享这些指标。确保与你的组织合作,设定有意义的指标,而不仅仅是容易图表化的虚荣指标。一个简单的周度仪表板可以走很长的路。它为你的项目提供了透明度,以及每个人投入工作的动机,同时也为每个人提供了了解的机会。在一个大型组织中,有许多利益相关者,其中一些在早期就参与其中,而另一些则可能直到后期才需要。尽早邀请其他人参与并了解,将在项目后期带来巨大的好处。Anthos 附带了许多优秀的指标和数据点,可以帮助你开始,你可以扩展视图访问权限,让感兴趣的团队成员对项目和平台感到兴奋。
B.2.6 选择项目团队、工具,并确保每个人都“上车”
在确定你项目成功标准的基础上,也花些时间来识别你的团队需要哪些角色参与项目。始终与团队成员的动机和兴趣保持一致是个好主意。确保每个人都能有机会学习新知识或承担新角色,以获得新的视角也是一个很好的想法。使用 Anthos 工具包来扩展团队成员的访问权限,并让他们在过程中进行实验和学习。团队应该始终“实验室学习和实践”。
例如,有时在项目设计阶段早期,你可能没有一份完整的文档化的安全要求列表来实现生产就绪。特别是对于基于“云”的项目,实现安全对齐将对于到达终点至关重要。这只是其中一个例子,最终确保你获得的项目成员将需要输入和批准,以使你的项目成功。考虑生产发布,而不仅仅是启动项目所需的人员。这肯定很棘手,因为你试图在拥有专注的团队以实现速度和敏捷性的同时,在整个组织中实现对齐。
另一个至关重要的方面,确保你的项目能够成功的关键是确保你的团队能够有足够的时间投入到项目中。在几乎所有情况下,项目团队都将有许多其他日常任务需要处理,这些任务会分散对项目工作的注意力。考虑使用协作工具和定期的站立会议来设定期望,保持标准一致,并专注于持续改进。最后,别忘了你可能正在与外部团队和合作伙伴打交道,能够访问一致的工具和实验室环境对你的成功至关重要。GCP 和 Anthos 已经提供了一些这些工具,使得实施变得简单。
B.2.7 早期进行研讨会并制定架构
我们都有一种自然的倾向,想要立即跳进去开始构建一些东西,尤其是当我们能够轻松访问我们想要验证的软件和想法时。这绝对不是要你推迟测试、学习和发现与你的用例相关的软件的边缘。但与你的项目团队安排一些工作坊和研讨会是一个很好的主意。这些研讨会的主要目标是制定一个初步的架构和一系列任务,让团队开始着手。不要只局限于考虑短期方面,还要让你的团队思考所有未来可能出现的需求。把这看作是构建一个可以用来推动优先级讨论的待办事项清单。你不必在项目期间完成所有这些项目,重要的是要确定所有应该考虑的项目,以确保你能提出最佳可能的架构。这也是邀请业务各个部门参加这些会议的另一个好理由,你将获得更广泛的视角,避免遗漏重要的需求或考虑事项。谷歌已经发布了大量的最佳实践架构文档,这将非常有帮助,还有许多工具可以帮助你节省时间并帮助你的团队成功。
在这个初步规划和发现阶段结束后,重要的是要记录你的当前架构计划,并为你的前几个冲刺列出实施任务。拥有这份文档将允许整个团队和利益相关者进行审查并提供初步反馈,最重要的是,如果他们有任何担忧或具体要求缺失或未考虑,要尽早提出。所以现在是我们开始构建并进入有趣的部分的时候了吗?嗯,还不完全是……
B.2.8 验证你的先决条件并准备好你的服务账户
在你可以继续进行安装和配置之前,我们需要确保一些初步的先决条件已经到位并得到验证。Anthos 非常注重“自动化一切”,这需要设置一些服务账户和密钥。像没有连接到适当 API 的互联网连接这样的小事情可能会暂停你的项目,这些变更通常需要变更请求和批准,你才能开始安装和配置。记得你邀请参加最初研讨会和项目启动会议的安全团队吗?他们将会派上用场,并且很可能会愿意帮助,因为他们早期就参与了,并且对项目的成功也有利益相关。Anthos 提供了出色的文档来列出所有这些要求,以及一些有用的工具来帮助你验证所有先决条件。
B.2.9 寻找能够专注于“应用”的设计合作伙伴
在实施新技术和基于 Kubernetes 的平台和一般性倡议时,常常犯的最大错误之一就是没有尽早关注将在你的平台上运行的应用。有时我们过于专注于构建和交付平台,而没有做工作来吸引开发和应用利益相关者。这些通常是那些一直在请求你构建的平台团队。确保你的成功标准列表上的一个项目是“将一个应用投入生产”。这将确保你能够尽早找到一个友好且投资于你成功的合作伙伴。
考虑“应用”而非“集群”,请别误会,平台、基础设施和工具至关重要,但没有在“平台”上运行的应用,实际上没有必要保留它。如果这一点在最初的项目定义中没有明确指出,那也行,开始与具有共同目标和强大商业案例的应用团队取得联系。请他们加入团队作为设计和测试合作伙伴,他们所能带来的价值会让你感到惊讶。在很多情况下,当一切尘埃落定,你正在努力教育你的组织了解所交付的平台时,这些团队将成为你最大的支持者,并且非常愿意分享他们所学到的知识,包括他们在过程中构建和实施的工具。想想社区...
您还希望花一些专注的时间来选择一些要上线的应用程序,理想情况下,选择一些已经容器化且相对简单的应用程序,但确实有进入生产的实际需求。同时选择一些更复杂的应用程序,这将使团队能够发挥潜力,并探索未来可能的可能性。还有使用像 Anthos 的 Migrate 这样的工具来加速您的容器化工作,并快速将一些虚拟机工作负载迁移到 Kubernetes 和 Anthos 的可能性。在许多情况下,这是一个加速您的业务案例、将更多应用程序投入生产并减少对传统虚拟化数据中心依赖的重大机会。Anthos 有工具可以帮助您做到这一点,并且运营预算和软件许可的成本降低可以帮助资助更多项目。
B.2.10 是时候开始构建并实施一个坚实的基础
对于很多人来说,到达实际实施工作总是最有乐趣的部分,这是您可以看到您最初的辛勤工作和计划如何结合在一起的部分。如果您在架构和规划方面的工作做得很好,这一阶段将肯定会更加顺利,并且速度会更快。这一阶段的技术工作对于您初始项目以及平台的未来运营的长期成功至关重要。将这项初始工作视为构建和部署在顶部的一切的基础,薄弱的基础会在以后对其他人产生负面影响。当您有很多应用程序在生产中时,替换基础也是非常困难的。
由于其多云能力,您可能已经对 Anthos 进行了深入了解,更不用说 Google Kubernetes Engine 的坚实基础了。确保您考虑了一些未来的需求,并至少从 2 个部署选项/位置开始。理想情况下,从 GCP 上的 GKE 和另一个受支持的平台开始。如果您还有大量的本地部署需求,可以考虑使用 VMware 或裸金属的 Anthos。如果您在其他云服务提供商上投入了大量资金,可以考虑在 AWS 或 Azure 上使用 Anthos。选项很多,但也能帮助您实现一些初始的多云目标。
这也将使所有参与您项目的人在与您构建 Anthos 平台时获得更多视角,拥有多个部署选项将迫使您思考共同体验和工具包的价值。任何平台都始终存在设计和运营方面的考虑。当您的平台需要支持更多多样化的选项时,重要的是要更加重视共同工具和流程,以减轻您在扩展时的运营需求。
例如,让我们思考一下未来开发者的体验,开发者是否需要根据他们的应用程序是部署在本地还是云端而额外考虑?目标应该是回答“不”,可能会有一些小的差异,但平台应该能够处理这些变量,在可能的情况下提供选项并抽象化部署位置。更多关于这一点,当我们深入探讨开发者体验和 GitOps 时再讨论。
B.2.11 你的组织成熟度水平如何?
我们开始讨论一些额外的先进主题,比如实现多云、抽象化平台和开发者的部署决策。现实是,当我们谈到平台和应用程序现代化之旅时,我们只是触及了表面。在考虑你正在实施的软件和能力时,考虑你组织的成熟度水平总是一个好主意。现实是,在团队对基础能力进行教育之前,过于强调先进主题和功能可能会吓跑一些人。相反,如果你的开发团队已经使用了一些先进的功能,如果一切保持过于基础,你可能会面临他们不对平台实施感到兴奋的风险。找到这个甜蜜点在处理内部客户时将是关键,你可能会以不同的方式与不同的团队合作,这是可以的,只需记住,每个人的教育和成熟度水平都不同,相应地调整你的谈话路线。
这可能看起来像是一个微不足道的事情要考虑,但请记住,人是复杂的,满足他们的需求符合每个人的最佳利益。记住,Anthos 是一个基于许多当今最受欢迎的开源项目的基础平台。这意味着你不必做所有的测试和集成工作,谷歌已经做了这些工作,这也是平台价值主张的一个巨大部分。它允许你以安全的方式加速你组织的成熟度水平,你可以更多地关注你实施的平台的商业影响。这对“业务”来说是一个大胜利...
B.2.12 GitOps 和管道的力量
我们讨论了思考未来以及当你“进入云端”时你希望如何操作你的软件和平台。我坚信,你的整个平台和应用程序配置应该被编码、版本化和自动化。有人跳入生产环境来解决配置问题的那天应该成为过去式。现实是,这些为了解决生产问题而进行的“临时”更改从未被正确捕获或记录,并且在修复后很少出现在较低的环境中。
GitOps 背后的主要概念是一切都是声明性的,你的集群和平台都从安全的基于 git 的仓库中获取配置。当一个更改经过测试并与适当的仓库合并时,平台将应用配置更改。考虑一下拉取工作流程而不是推送配置活动。如果你需要管理成千上万的集群,这可以很容易地实现规模效应。如果你需要大规模回滚更改,你可以利用相同的流程和方法。所有内容在过程中都进行了版本控制、管理和审计。当涉及到 GitOps 时,有许多概念和事情需要考虑,但让我们从版本控制和自动化所有配置开始。同时,让团队中的每个人都熟悉 YAML。
当谈到管道时,我们可以同意许多相同的原则,重点在于自动化所有工作流程,而不是手动更改我们的平台。现实情况是,任何应用平台配置都有许多步骤和方面,我们始终需要在这个过程中进行更改和改进。这可能是由平台配置驱动的,可能是一个需要解决的安全要求。也可能是由需要实现以满足客户需求的新功能驱动的。我想传达的基础原则是,所有内容都检查到 git 中并进行了版本控制……总是!合并和审批驱动自动化管道、配置更改和新代码部署。这个工作流程始终如此,并在较低环境中得到验证,当所有内容都经过验证和测试后,才会被推广到生产环境。Anthos Config Management 将是一个帮助你开始的绝佳工具,并有许多稳健的原则。有各种各样的最佳实践配置,参与社区并开始根据您组织的需要定制。
B.2.13 采用安全优先的方法
一个经过深思熟虑的稳健方法和对安全的关注从未如此关键。我们的系统正变得越来越复杂,并且比以往任何时候都有更多的集成点。现在不要误解我,微服务的兴起和采用确实带来了许多优势,但也可能引入额外的复杂性。如今,你可以有多个团队在完全不同的应用方面工作,每个团队可能都专注于一组特定的功能,并且可能没有能力详细了解应用的所有方面。在安全方面,每个团队也可能有不同的观点和经验。
这使得对强大安全框架的需求更加突出,并制定一套标准,让你的团队能够努力实现。显然,在旅程的早期实施这些安全最佳实践是至关重要的。我们还知道,安全需求将继续演变,需要持续重构。我看到的一种驱动许多团队成功和扩展的方法是采取“集成安全”的方法。我的意思是,平台及其各种组件都有一套默认的安全方法。安全方面可以采取与平台配置管理相似的方法。我们上面已经讨论过这一点,GitOps 的力量,你当然可以增强这些安全默认设置,但它确实设定了可以管理和自动化的最低要求。
从“传统”的过去方法中需要改变的一个方面是,你的平台安全应该在可能的情况下是活配置。根据我的经验,以前安全专业人员负责记录这些标准、规则和方法。在大多数情况下,这些内容出现在一份详细说明团队成员如何处理应用开发和部署的文档中。这要求安全团队定期审计平台和应用。我挑战你专注于将这些规则和安全标准规范化。为了使应用能够在你的平台上部署,它应该通过自动检查点,并验证是否符合安全标准。这将改变安全专业人员所需的技术技能,以实现“集成安全”。每个人都需要采取以安全为首要的方法,并将这些规则和政策构建到平台和管道中。同时也要意识到,这不仅仅是一次性实施的方法,维护和更新政策将是一项持续的操作活动。正如我提到的,Anthos 堆栈和社区中有许多优秀的工具可以帮助你顺利开始。
B.2.14 服务网格的力量
在过去几年中,在 Kubernetes 和微服务社区中,最热门的话题之一就是服务网格。我不会深入探讨所有方面、部署选项和你可以通过服务网格启用的能力,但我确实鼓励你在旅程的早期就开始尝试。有几个地方你可以开始,更好地理解你的应用、简化的安全到增强的流量管理。
利用服务网格实现一些快速胜利的最简单方法之一是利用高级遥测和对你应用及服务通信的可见性。服务网格可以详细捕捉和汇总你的应用通信和工作流程。这可以让你的团队能够轻松地排查性能问题,并开始为你的应用服务设定一些基本的服务级别。这种方法最好的部分是,你不需要对应用代码进行任何更改就能获得这些洞察,你还可以汇总这些数据并将其与平台日志相关联。Anthos Service Mesh 允许你在 GCP 控制台中管理所有这些数据和洞察,以增强你的运营洞察。从小处着手,利用基本功能,你可以在未来利用更多功能。
B.2.15 应用集成和迁移
理想情况下,当你开始这段旅程时,你已经确定了一些应用和团队将参与其中。与其等待平台准备就绪,这些利益相关者应成为旅程的一部分,并且对团队的成功高度投入。尽管我们总是试图为每一种情况做计划,但总会有挑战和意外出现。我建议你尽早考虑应用需求,以便及早发现任何意外或挑战。尝试确定一些常见用例,并尽早将其纳入平台实施中,考虑一些新的应用以进行集成,但也确定一些将作为迁移一部分的其他应用。越早处理独特情况,你在准备进入生产阶段时就会越充分。最后一个重要方面是始终关注原始的商业案例。你是否在朝着实现你最初设定的目标和指标前进?也许现在是时候调整或回到商业领域,验证任何新的假设或沿途学到的宝贵经验了。
B.2.16 开发者体验和智能默认设置
当我们上线应用并确保我们的平台和服务能够满足业务需求时,我们不能忽视将使用并依赖该平台的使用者社区。我们需要始终考虑开发者的体验,并记住成功的早期定义之一。增强开发者体验有时很难衡量,但对于你平台的成功以及上线新应用和发布新服务的能力将极为关键。不要忘记我们之前讨论的一个挑战:“改变是困难的”,并且需要时间和教育让每个人接受这些新的工作方式。当我们早期上线应用团队时,让我们继续与用户社区沟通,并创建一个持续的反馈循环。当你开始解释你的足迹并上线新用户和应用时,这种早期反馈将非常有价值。
另一个需要考虑的方面,我们之前也提到过,是“智能默认设置”。意识到你的用户社区中会有非常不同的成熟度水平。显然,你需要为高级团队提供能力,以便进行许多自定义配置以满足他们的平台需求。让我们也考虑那些对技术新手,最初可能只是尝试让一个简单的应用运行起来的用户。如果这些用户需要考虑每个配置选项才能开始,可能会吓跑他们。想想他们需要做出多少决定才能部署一个应用,创建一些智能默认设置,并为他们做出这些决定。随着他们对平台越来越熟悉,他们可以开始做出定制决策。这将增强开发者体验,并帮助每个人早期看到价值。
B.2.17 在过程中教育每个人
有时候眼见为实,一个出色的演示可以帮助他人开始看到并相信你所构建的组织平台上的可能性。需要记住的是,这些新技术对于你的团队和组织来说可能都是新的。尽早开始教育将参与其中并与新技术栈互动的团队。动手工作坊可以是一个帮助他人获得一些技术经验的好方法,而且能够轻松访问实验室也将带来巨大的好处。培养实验室和学习的文化是你将要投资和支持的事情。我想你会对你的团队在能够跳出思维定势时能想出什么感到惊讶。最后,别忘了商业方面。有时我们倾向于关注技术方面,但记住,做所有这些工作的真正原因是“商业效益”。
B.2.18 打造一个出色的前门
将前门视为一个框架,展示其他人如何利用这个平台。这个过程需要简单、易于理解。尝试构建一些用户故事,并思考某人如何获取访问权限并使用这项新技术。你能够促进更多的人际互动就越好,但要知道这并不总是能够扩展以满足新的需求。有很多事情需要考虑和记录,包括治理、安全要求、工具标准和教育。我们之前提到的那些智能默认设置在这里会很有用,理想情况下,这些将帮助用户社区达到最低要求以便加入,进而帮助他们的社区。
B.2.19 进入生产阶段
现在这一点似乎很明显……但很多时候我们可能会专注于初始环境构建,而忽略了到达终点线并将应用程序投入生产所需的东西。现在,如果你在早期就很好地让应用程序团队参与并投入,你就有更大的成功机会。此外,如果我们回顾最初的成功标准,应该有一些令人信服的理由推动到生产环境。总是有一些更大的关卡需要通过,但理想情况下,需要签字的利益相关者早期就参与了,并且也投资于平台的成功。
B.2.20 继续关注和测试新技术…
所以你已经在终点线了,对吧?嗯,理想情况下不是……如果你已经走到这一步,你已经在你的组织中产生了重大影响,但肯定还有更多的事情要做。
-
需要更多的应用程序进行上线
-
需要教育和培训更多的团队成员
-
需要构建和实施更多的自动化工具
-
需要编写更多的安全策略
-
需要构建更多的仪表板
-
需要与更多的社区成员合作
-
有更多的乐趣可以享受…
继续学习并致力于酷炫的技术,并适应变化。
附录 C. 在 VMware 上运行的计算环境
Jarosław Gajewski
本章涵盖:
-
理解 VMware 和 Anthos 架构
-
管理平面的部署
-
用户集群的部署
-
Anthos 网络负载均衡器选项
如您所知,谷歌提供了一种名为 Google Kubernetes Engine (GKE) 的托管 Kubernetes 服务,该服务托管在其基础设施上。这种托管解决方案已为 Kubernetes 消费者解决了多个问题,包括生命周期管理、安全和物理资源交付。虽然每年在云中部署应用程序都在增长,但许多企业在其自己的数据中心中仍然拥有大量的资源。
谷歌认识到,组织可能出于各种原因而希望将某些工作负载保留在本地,包括延迟担忧、数据担忧以及可能限制云使用的其他监管要求。为了帮助公司解决必须保留在本地但仍然希望利用 Kubernetes 等云原生技术的工作负载,本地 GKE 应运而生——现在被称为 Anthos。
本地实施引入了一些要求,公司必须提供以允许配置 Anthos 基础设施组件。我们不会深入探讨与特定版本的 Anthos 相关的约束条件,或 VMware 要求,因为它们始终在演变。一般来说,需要提供 VMware vSphere 资源^([1]),这些资源可用于托管管理控制平面、Kubernetes 基础设施和应用工作负载。
在 VMware 上部署的 Anthos 使用 Kubernetes 构建的管理控制平面,通过配置 vSphere 虚拟机(VMs)。每个新的用户集群都配置为包含具有 Kubernetes 控制平面和用户节点的专用 VM 集合,由管理集群完全管理。负载均衡可以由 Anthos 在 VMware 实例上管理的 VM 或外部负载均衡器提供,具体取决于用例和实施架构。
在本章中,我们将解释在本地数据中心安装 Anthos 的各种部署场景和需求,从您可能为什么想要在本地部署 Anthos 开始。
C.1 为什么我应该使用 VMware 上的 Anthos?
让我们来解决第一个问题——为什么谷歌选择在 Anthos 的初始版本中支持 VMware?大多数企业已经拥有现有的 VMware 足迹,利用一个虚拟平台提供一致的环境和 API,用于自动化、全栈配置。通过支持 VMware,谷歌为组织提供了利用现有投资、基础设施以及扩展和节点管理能力来创建 Kubernetes 集群的能力。
通常,有多种驱动因素和约束条件要求企业将某些数据和工作负载保留在专用数据中心(DCs)中运行。最常见的要求是靠近数据或用户、监管要求,或利用现有本地投资的必要性。
公司必须提高应用程序的可用性和可扩展性以保持竞争力。在容器中开发应用程序将提供效率、敏捷性和可移植性——这为开发者提供了增加部署敏捷性和速度的能力。已经拥有数据中心(DC)的组织可能能够以比迁移到云服务提供商(CSP)更低的成本为开发者提供类似云的服务。利用本地容量,您可以创建类似云的体验,感觉类似于在 GCP 上使用 Kubernetes,为您的开发者提供在本地或异地运行的集群的统一体验。它还提供了在多个环境中运行多集群架构的能力,提供更好的可靠性,并允许工作负载在云中爆发,使用更多按需资源来满足负载的短期峰值,然后在本地工作者上缩回。
Kubernetes 的管理、维护、集成和生命周期管理需要大量的时间和技能。在生产规模上运行集群增加了日常挑战,将业务注意力从应用程序转向基础设施管理。这正是 VMware 上的 Anthos 发挥作用的地方,它包括符合标准的、经过安全测试的 Kubernetes 版本,捆绑了各种网络服务的集成,最重要的是,为 Kubernetes 和所有 Anthos 组件提供企业级支持。最后但同样重要的是,所有集群都是统一的,从 GKE 控制台提供全面管理。
对于企业级架构,通常需要将新创建的平台和服务集成到现有的企业身份解决方案中。根据公司需求,可以通过以下方式在本地提供对 GKE 集群的授权:
-
基于 Active Directory 联邦服务 OpenID Connect^([2])的提供者集成,例如
-
基于 Google,
-
基于 Active Directory 联邦服务(ADFS)的公司
-
-
轻量级目录访问协议(LDAP)
VMware 上的 Anthos 包含一系列插件,帮助管理员和安全官员启用管理、转向基于 git 的管理以及渐进式部署,以实现企业中的部署速度和敏捷性。Anthos 配置管理(ACM)允许全面实现基础设施即代码(IaaC)的 GitOps 方法。它包括基于 Open Policy Agent 的准入控制器,为云原生基础设施提供安全约束和企业标准。策略控制器包括多个预定义的约束,并且可以扩展到来自业务或安全的任何自定义策略。这两个工具在单独的章节中有详细描述,但重要的是要强调,它们是 Anthos on VMware 实现上现成的扩展。
在下一节中,我们将探讨成功在 VMware 集群上部署 Anthos 所需的架构要求。
C.2 VMware 上的 Anthos 架构
Anthos on VMware 作为一组在 VMware vSphere 集群上部署的虚拟机实现。在那一章中,我们将讨论 Anthos on-prem 实现的技術要求。
从一般要求开始,Anthos on VMware 必须安装在由标准或分布式虚拟交换机或 VMware NSX-T 软件定义网络支持的 vSphere 集群上。由于 Google 经常更新 Anthos,有关最新版本的详细要求可在 GCP Anthos on VMware 文档页面^([3])中找到。
就像 OSS Kubernetes 发布一样,Anthos 有一个敏捷的发布周期^([4]),与整个 Anthos 发布保持一致,它遵循每月补丁发布周期和季度版本升级周期。建议部署版本更新,我们可以直接升级到同一次要版本的任何版本或下一个次要版本,例如,我们可以从版本 1.9.0 升级到 1.9.4 或直接升级到 1.10.1,但要从 1.9.X 升级到 1.11.X,您需要首先升级到 1.10.X。

图 C.1 升级选项
为了简化更新过程并允许测试新版本,从 Anthos 版本 1.7.0 开始,可以在管理员集群升级之前更新用户集群。因此,您可以启动一个具有较新 Anthos 版本的新的集群,对其进行测试,并根据结果,启动生命周期过程以将整个环境升级到新版本。一旦用户集群升级,管理员集群就可以在合适的时间窗口内进行更新,而无需急于进行。
现在您已经了解了 Anthos on VMware 的高级视图,我们可以继续到安装新集群的细节。
本地部署包括一个管理员工作站,配备部署管理员集群和用户集群(s)所需的所有工具。安装需要三个配置文件,这些文件必须配置为环境:
-
管理员工作站配置文件
-
管理员集群配置文件
-
用户集群配置文件
每个文件都是 YAML 格式,包含必选和可选部分。默认情况下,每个可选部分都是注释掉的,每个配置元素后面都跟着简短的描述和用法,提供了一个易于遵循、自我文档化的配置文件。
配置文件中的一些选项包括:
-
配置安装以使用本地注册表存储 Anthos 组件镜像
-
Google 服务帐户用于 GCP 集成,包括用于 Anthos 连接和云日志的帐户。
-
OIDC 配置
-
vSphere 配置
-
负载均衡器配置
配置包含基本集群配置的选项,只有一个例外是启用 Cloud Run。像 Anthos Config Management、Anthos Policy Controller 或 Service Mesh 这样的附加元素可以在集群生命周期中的任何时候安装或删除。
整体部署流程在图 3 - Anthos on VMware 部署流程中展示。所有选项和可选步骤都用虚线标记。

图 C.2 Anthos on VMware 部署流程
在下一节中,我们将解释如何部署管理平面,这是新本地部署的第一步。
部署管理平面
管理平面的创建始于管理工作站的部署,提供创建和管理管理员和用户集群的工具。此虚拟机拥有创建 VMware 上 Anthos 集群所需的所有软件。使用管理工作站,Google 可以保证一致性,并从管理员那里移除创建和维护工具的责任。
管理工作站准备
部署管理工作站需要准备,下面的图形显示了创建管理工作站的步骤。

图 C.3 管理工作站部署
第一步是在您的本地机器上安装 Google Cloud SDK。这可以是任何 Linux、Windows(工作站或服务器)或 MAC OS 机器。
安装 SDK 后,您需要下载 gkeadm 工具。使用 gsutil 工具,使用以下命令下载文件。
gsutil cp gs://gke-on-prem-release/gkeadm/{Anthos on VMware version number}/linux/gkeadm ./
如果您使用的是 Linux,您需要使用 chmod 命令使二进制文件可执行。
chmod +x gkeadm
现在您已经下载了 gkeadm,您可以部署管理工作站。
C.3 部署管理工作站
管理工作站的部署基于一个单一的 YAML 配置文件,它有四个主要部分:
-
gcp
-
vCenter
-
proxyUrl
-
adminWorkstation
GCP 部分专门用于 GCP 集成配置元素。在撰写本书时,只需要一个元素,即 componentAccessServiceAccountKeyPath,它定义了一个组件服务账户的路径。此服务账户有权访问 VMware 上的 Anthos 二进制文件并使用相关的 API。如果使用不同的项目进行监控、日志记录等,则该账户必须在每个或那些项目中具有 serviceusage.serviceUsageViewer 和 iam.roleViewer 权限。
gcp:
componentAccessServiceAccountKeyPath: "whitelisted-key.json"
配置文件的第二部分描述了与 vCenter 服务器的集成。它涵盖了凭证子部分,包括 vCenter 的定义,以及包含用于 vSphere 访问的用户名和密码的凭证文件。以下是一个名为 credential.yaml 的凭证文件示例。
apiVersion: v1
kind: CredentialFile
items:
- name: vCenter
username: "myaccount@mydomain.local"
password: "Th4t1$4Nth05"
所需的 vCenter 信息包括数据中心名称、数据存储名称、集群名称、网络和 vCenter 根证书。可选地,可以指定资源池名称和文件夹,以便将虚拟机放置在其中。
vCenter:
credentials:
address: "10.10.10.10"
fileRef:
path: credential.yaml
entry: vCenter
datacenter: "MY-DATACENTER"
datastore: "MY-DATASTORE"
cluster: "MY-CLUSTER"
network: "MY-VM-NETWORK"
folder: “MY-FOLDER”
resourcePool: "MY-POOL"
caCertPath: "vcenter-root.cert"
如果您为您的 vCenter 服务器有一个自签名的证书,需要添加到 caCertPath 值中,您可以使用 curl 获取它,如下面的命令所示。
curl -k "https://{SERVER_ADDRESS}/certs/download.zip" > download.zip
下载完成后,解压缩文件,它将在 certs/lin 文件夹中提取证书。
如果您的环境需要代理服务器来访问互联网,您可以配置 proxyUrl 部分。此配置参数仅在 VM 部署期间由 gkeadm 命令使用。
proxyUrl: "https://my-proxy.example.local:3128"
当配置代理时,您还需要将适当的地址添加到操作系统或系统 no_proxy 变量中。此配置针对每个公司和部署都是特定的 - 代理服务器如何工作的完整解释超出了本书的范围。作为一个起点,您可能需要添加您的 vCenter 服务器、本地注册表(如果已配置)以及 ESX 主机的 CIDR 范围。
最后一个部分是配置文件生成过程中部分预填充的唯一部分:
-
dataDiskName
-
dataDiskMB
-
虚拟机的名称
-
CPU 数量
-
内存大小(以 MB 为单位)
-
基础磁盘大小(以 GB 为单位)
注意:新磁盘创建的 dataDisk 文件夹必须存在。因此,您必须事先手动创建它。
管理工作站可以使用静态 IP 分配或通过 DHCP 服务器分配 IP 地址。您的实现选择在配置文件的网络子节中使用 ipAllocationMode 属性定义。
对于 DHCP 用例,ipAllocationMode 必须定义为 DHCP,并且所有其他子网络配置元素保持未定义。
当使用静态 IP 分配时,ipAllocationMode 属性必须设置为“static”,然后是 IP、网关、子网掩码和 DNS 配置。DNS 值可以定义为具有多个值的属性数组。
最后,设置管理工作站使用的 NTP 服务器。必须使用与 vSphere 基础设施同步的 NTP,否则时间差异将导致部署失败。
下面显示了两个示例配置文件,第一个已配置为使用静态 IP,第二个已配置为使用 DHCP。
adminWorkstation:
name: "gke-admin-ws-200617-113711"
cpus: 4
memoryMB: 8192
diskGB: 50
dataDiskName: "gke-on-prem-admin-workstation-data-disk/gke-admin-ws-data-disk.vmdk"
dataDiskMB: 512
network:
ipAllocationMode: "static"
hostConfig:
ip: "10.20.20.10"
gateway: "10.20.20.1"
netmask: "255.255.255.0"
dns:
- "172.16.255.1"
- "172.16.255.2”
proxyUrl: "https://my-proxy.example.local:3128"
ntpServer: "myntp.server.local"
adminWorkstation:
name: "gke-admin-ws-200617-113711"
cpus: 4
memoryMB: 8192
diskGB: 50
dataDiskName: "gke-on-prem-admin-workstation-data-disk/gke-admin-ws-data-disk.vmdk"
dataDiskMB: 512
network:
ipAllocationMode: "dhcp"
hostConfig:
ip: ""
gateway: ""
netmask: ""
dns:
proxyUrl: "https://my-proxy.example.local:3128"
ntpServer: "myntp.server.local"
现在,我们可以使用 gkeadm 实用程序在我们的 vSphere 基础设施上创建管理工作站。
./gkeadm create admin-workstation --auto-create-service-accounts
添加 auto-create-service-accounts 标志允许您在项目中自动创建相关的服务帐户。
一旦创建管理工作站,您就可以部署管理集群了。在下一节中,我们将介绍创建管理集群的步骤。
创建管理集群
管理集群是 Anthos 控制平面的关键组件。它负责监督在 VMware 上的 Anthos 实现,以及用户集群的配置和管理。它作为一个使用单个控制平面节点和两个工作节点的 Kubernetes 集群部署[图 8]。
控制平面节点将为管理控制平面提供 Kubernetes API 服务器、管理集群调度器、etcd 数据库、审计代理以及任何集成的负载均衡器 Pod。
工作节点为 Kubernetes 插件如 kube-dns、云监控(前身为 stackdriver)或 vSphere pods 提供资源。
除了管理控制平面和插件外,管理集群还托管用户控制平面。因此,用户集群的 API 服务器、调度器、etcd、etcd 维护和监控 Pod 都托管在管理集群上。

图 C.4 Anthos on VMware 管理集群架构
要创建管理集群,您需要 SSH 进入上一节中创建的管理工作站。使用在部署管理工作站时创建的密钥连接到管理工作站,该密钥位于 .ssh/gke-admin-workstation 目录下。
ssh -i /usr/local/google/home/me/.ssh/gke-admin-workstation ubuntu@{admin-workstation-IP}
与管理工作站创建过程类似,管理集群使用一个分为几个部分的 YAML 文件。vCenter、gkeconnect、stackdriver 和 gcrkeypath 部分预先填充了从管理工作站 YAML^([5]) 文件中收集的值,而所有其他部分必须在创建集群之前填写。
您可以使用包含的管理集群配置文件,或者您可以使用已安装在管理工作站上的 gkectl 工具生成一个新的管理集群配置文件。与预先创建的模板文件不同,使用 gkectl 手动生成的任何模板都不会包含任何预先填充的值。要创建新文件,请使用 gkectl create-config admin 选项。
gkectl create-config admin --config={{ OUTPUT_FILENAME }}
两种创建方法将包含相同的部分,配置文件的前两个部分必须保持不变,定义 API 版本和集群类型。
apiVersion: v1
kind: AdminCluster
下一个部分是 vSphere 配置,包含对虚拟机和磁盘放置的要求。
TIP: 良好的做法是始终使用完全限定的域名 (FQDN) 用于 vCenter,并在生产环境中避免使用 IP 地址。
vCenter:
address: "FullyQualifiedDomainName or IP address of vCenter server"
datacenter: "vCenter Datacenter Name"
cluster: "vCenter Cluster name"
resourcePool: "vCenter Resource Pool name"
datastore: "vCenter Datastore Name for GKE VM placement "
folder: “Optional: vCenter VM Folder”
caCertPath: "vCenter public certificate file"
credentials:
fileRef:
path: “path to credentials file”
Entry: “Name of entry in credentials file referring to username and password of vCenter user account“
# Provide the name for the persistent disk to be used by the deployment (ending
# in .vmdk). Any directory in the supplied path must be created before deployment
dataDisk: "Path to GKE data disk"
TIP: 良好的做法是将数据磁盘放入一个文件夹中。dataDisk 属性必须指向存在的文件夹。Anthos on VMware 创建一个虚拟机磁盘 (VMDK) 来存储管理集群的 Kubernetes 对象数据,这是安装程序为您创建的,因此请确保名称是唯一的。
TIP: 如果您希望不使用资源池并将管理集群资源直接放置在集群级别,请在资源池配置中提供“
在下一个部分中,我们定义管理集群节点、服务和 Pod 的 IP 设置。这些设置也将用于用户集群主节点的部署。
首先,我们必须定义 Anthos on VMware 管理集群节点和用户集群主节点将使用 DHCP 还是静态 IP 分配。如果使用静态选项,必须定义一个额外的 YAML 文件来指定 IP 地址分配;此文件在 ipBlockFilePath 属性中指定。
下面的两个属性专门用于 Kubernetes 服务和 pod CIDR 范围,这些范围在下面的表 1 中详细说明。它们由 Kubernetes pods 和服务使用,并在基于 Kubernetes 构建的计算环境章节中详细描述。分配的网络范围之间不得相互重叠,也不得与由管理平面使用的任何外部服务重叠,例如用于与 GCP 通信的任何互联网代理。
TIP:由于 Anthos on VMware 在孤岛模式下运行,Pod 和 Service 使用的 IP 地址无法路由到数据中心网络。这意味着您可以为每个新的集群使用相同的 IP 地址。
最后,最后一节定义了 Kubernetes 节点一旦配置后将要使用的目标 vSphere 网络名称。
表 C.1 管理集群属性
| Kubernetes 资源 | 描述 |
|---|---|
| network | |
| ipMode | type 和 ipBlockFilePath 的父键 |
| type | 要使用的 IP 模式("dhcp"或"static") |
| ipBlockFilePath | 用于静态 IP 分配的 yaml 配置文件的路径。必须与 type: static 键值对一起使用 |
| serviceCIDR | 用于控制平面部署服务的 Kubernetes 服务 CIDR。最小地址数 128 个 |
| podCIDR | 用于控制平面部署服务的 Kubernetes pods CIDR。最小地址数 2048 个 |
| vCenter | networkName 的父键 |
| networkName | 管理集群节点和用户集群主节点分配到的 vSphere 端口组名称。 |
下面显示了示例配置。
network:
ipMode:
type: dhcp
serviceCIDR: 10.96.232.0/24
podCIDR: 192.168.0.0/16
vCenter:
networkName: "My Anthos on VMware admin network"
正如我们提到的,节点 IP 分配可以通过静态配置文件进行配置。此类文件的路径必须在 ipBlockFilePath 键下指定,该键必须取消注释,并且仅在 ipMode.type 键设置为 static 时才考虑。此外,必须指定 DNS 和 NTP 服务器,并定义搜索域,如下面的示例所示。
network:
ipMode:
type: “static”
ipBlockFilePath: "myAdminNodeHostConfFile.yaml"
hostConfig:
dnsServers:
- "8.8.8.8"
ntpServers:
- "myNTPServer"
searchDomainsForDNS:
- "myDomain.local"
静态主机配置文件使用两个主要配置键构建:hostconfig 和 blocks。Hostconfig 定义了 DNS 服务器、NTP 服务器和搜索域的信息。blocks 定义了 Kubernetes 节点的子网掩码和网关,随后是一个主机名数组及其对应的 IP 地址。
| 属性键 | 属性描述 |
|---|---|
| blocks | |
| netmask | 网络子网掩码 |
| gateway | 网络网关 |
| ips | 与对应值相对应的 IP 和主机名键的数组。 |
blocks:
- netmask: 255.255.255.128
gateway: 10.20.0.1
ips:
- ip: 10.20.0.11
hostname: admin-host1
- ip: 10.20.0.12
hostname: admin-host2
- ip: 10.20.0.13
hostname: admin-host3
- ip: 10.20.0.14
hostname: admin-host4
- ip: 10.20.0.15
hostname: admin-host5
TIP:分配给节点的 IP 地址不是按照文件中定义的顺序分配的。它们在调整大小和升级操作期间从可用的 IP 池中随机选择。
配置的下一部分是集群负载均衡。Anthos on VMware 需要一个负载均衡器为 Kubernetes API 服务器提供虚拟 IP(VIP)。对于您的集群,您可以选择使用基于 MetalLB 的集成负载均衡器、F5 或其他任何使用手动配置的负载均衡器。MetalLB 正在成为包括 VMware^([6])在内的裸金属实现中的一种流行解决方案,这些解决方案不包括 HyperCaller 构建的解决方案。在管理集群上启用 MetalLB 仅限于在管理集群配置文件中定义 kind: MetalLB,如下所示。
loadBalancer:
vips:
controlPlaneVIP: “133.23.22.100”
kind: MetalLB
我们将在本章的负载均衡器部分更详细地解释这些选项。
为了确保 Kubernetes 控制平面节点将分布在不同 ESXi 主机上,Anthos 支持 vSphere 反亲和性组。这种实现保证了物理 ESXi 主机故障只会影响单个 Kubernetes 节点或提供生产级配置控制平面的附加节点。此值应设置为 true 以利用反亲和性规则,或设置为 false 以禁用任何反亲和性规则的使用。
antiAffinityGroups:
enabled: true/false
您可以通过在配置文件的 stackdriver 部分设置适当的值,使用 Google Cloud Logging 来监控集群。
日志和指标可以发送到专门的 GCP 项目,或者创建集群所在的同一项目。您需要提供用于日志的项目 ID、集群位置、VPC 选项、具有适当项目权限的服务账户密钥文件,以及您启用或禁用 vSphere 指标的决定。
stackdriver:
projectID: "my-logs-project"
clusterLocation: "us-central1"
enableVPC: false
serviceAccountKeyPath: "my-key-folder/log-mon-key.json"
disableVsphereResourceMetrics: true
此外,您还可以将集群 API 服务器的审计日志与云审计日志集成。您必须指定集成应针对的项目(可以是用于云操作集成的同一项目)、集群位置以及具有适当权限的服务账户密钥。
cloudAuditLogging:
projectID: "my-audit-project"
clusterLocation: "us-central1"
serviceAccountKeyPath: "my-key-folder/audit-log-key.json"
确保 Kubernetes 节点上的问题能够快速检测和修复非常重要,类似于 GKE 集群,Anthos on VMware 使用节点问题检测器。检测器会监视可能出现的节点问题,并将它们作为事件和条件报告。当任何 Kubelet 变得不健康或由 kubelet 或 docker systemd 服务报告 ContainerRuntimeUnhealthy 条件时,自动修复功能将尝试自动重启它们。
Anthos on VMware 集群的自动修复功能允许在它们被错误删除或无法响应的虚拟机被重新创建时自动创建 Kubernetes 节点虚拟机。它可以在集群部署配置文件中通过将 autoRepair enabled 选项设置为 true 或 false 来启用或禁用。
autoRepair:
enabled: true/false
当启用时,集群健康控制器部署将在 kube-system 命名空间中对应的集群上创建。如果节点被标记为不健康,它将被移除并重新创建,如图 C.5 所示。

图 C.5 节点自动修复过程
注意:要在管理集群上禁用自动修复功能,必须从管理集群中删除 cluster-health-controller 部署。
可以从私有 docker 注册库而不是 gcr.io 部署 Anthos。要配置您的部署以使用私有注册库,您需要在配置文件的 privateRegistry 部分设置值。您需要提供注册库地址、注册库的 CA 以及用于凭证文件的凭证引用。
privateRegistry:
address: "{{Private_Resistry_IP_address}}"
credentials:
fileRef:
path: "{{my-config-folder}}/admin-creds.yaml"
entry: "private-registry-creds"
caCertPath: "my-cert-folder/registry-ca.crt"
这就完成了管理集群配置文件的配置,现在让我们转向用户集群配置。
对于基于 Anthos 的 Kubernetes 实现,安全性非常重要。Anthos on VMware 引入了密钥加密功能,以确保它们在静态存储时加密,无需外部密钥管理服务。因此,在密钥存储在 etcd 数据库之前,它会被加密。要启用或禁用该功能,请编辑配置文件的 secretsEncryption 部分。
secretsEncryption:
mode: GeneratedKey
generatedKey:
keyVersion: 1
提示:每当密钥版本更新时,都会生成一个新的密钥,并使用该新密钥重新加密密钥。您可以使用 gkectl update 命令强制执行密钥轮换,结果所有现有和新密钥都将使用新密钥加密,旧密钥将被安全删除。
用户集群创建
每个新的用户集群都需要连接到一个管理集群,实际上,没有管理集群就无法创建工作负载集群。一个管理集群可以管理多个用户集群,但单个用户集群只能由一个管理集群监督。
每个已配置的用户集群都可以部署在两种配置中,带有或没有高可用性(HA)的生产级管理平面。如图所示,启用 HA 的集群使用 3 个管理节点构建(图中的用户集群#2),而没有 HA 的则使用单个节点(图中的用户集群#1)。单节点管理平面消耗较少的计算资源,但在节点或物理主机故障的情况下,管理集群的能力会丢失。在 HA 模式下,单个主节点故障不会影响 Kubernetes 集群配置管理能力。

图 C.6 Anthos on VMware 用户集群架构
重要:部署后,不能在不重新创建整个集群的情况下更改管理节点的数量。
每个新的用户集群都会放置在管理集群中的一个专用命名空间中。它用于托管和交付服务、部署、Pod 和 ReplicaSets 以进行管理目的。
命名空间名称与集群名称一致,允许您通过 kubectl get all -n {{ clusterName }} 轻松获取所有详细信息。任何用户集群命名空间都将托管在添加到管理员集群中以创建用户集群的专用节点上。这些节点将标记为集群名称,当创建集群管理器 pods 时,它们将使用节点选择器来强制将它们放置在专用用户集群节点上。
其他非系统命名空间是在工作负载集群节点之上创建的,如下图中所示

图 C.7 Anthos 在 VMware 用户集群命名空间
与管理员集群类似,用户集群部署基于 YAML 配置文件。配置文件的前两部分必须保持不变,定义 API 和集群类型。
apiVersion: v1
kind: UserCluster
提示:您可以使用以下命令将旧版本的配置文件转换为配置文件:gkectl create-config cluster --config $MyAwsomeClusterConfigFile.yaml --from MyOldConfigFile.yaml --version v1
下一个部分是您提供新集群名称和 Anthos on VMware 版本的地方。集群名称必须在 GCP 项目内是唯一的,版本必须与管理员集群版本一致。
name: “MyAwesomeOnPremCluster”
gkeOnPremVersion: 1.10.0-gke.194
下一个部分是可选的。它用于管理 vSphere 集成和工作节点放置。强烈建议在 vSphere 层面上分离管理员和工作负载计算资源,以确保 Kubernetes 管理平面的可用性。这保证了在资源饱和或对 vSphere 访问有限的情况下,每个 Anthos on VMware 集群都有资源。按照此做法,您的用户集群工作节点将被放置在 vCenter 部分下定义的资源池和数据存储^([8])。此外,如果需要,用户集群还可以部署到单独的 VMware 数据中心。为了确保 vSphere 资源正确应用了权限分离,建议为用户集群 vCenter 通信使用专用账户。
vCenter: “MyAwsomeOnPremCluster”
datacenter: “MyWorkloadDatacenter”
resourcePool: "GKE-on-prem-User-workers"
datastore: “DatastoreName”
credentials:
fileRef:
path: “path to credentials file”
Entry: “Name of entry in credentials file referring to username and password of vCenter user account“
提示:您可以选择只使用单个属性,例如 vCenter.resourcePool。在这种情况下,注释其他行,在行首添加 #,注释属性的配置将继承自管理员集群配置。
网络部分的结构与管理员集群部分中描述的管理节点相同,并扩展了定义可用于 Kubernetes 有效负载的附加网络接口的能力。
network:
ipMode:
type: dhcp
serviceCIDR: 10.96.232.0/24
podCIDR: 192.168.0.0/16
vCenter:
networkName: "My Anthos on VMware user network"
additionalNodeInterfaces:
- networkName: "My additional network"
type: dhcp
或者,在静态 IP 分配的情况下:
network:
ipMode:
type: “static”
ipBlockFilePath: "myNodeHostConfFile.yaml"
additionalNodeInterfaces:
- networkName: "My additional network"
type: “static”
ipBlockFilePath: "mySecondNodeHostConfFile.yaml"
在该章节的开头,我们提到管理平面可以是高可用性保护的,也可以不是。这样的决定是通过集群配置文件中的 masterNode.replicas 部分配置的,定义为 3 或 1 个副本。
如果需要,您可以在本节中扩展主节点 cpu 和内存,或者设置自动调整大小功能。
masterNode:
cpus: 4
memoryMB: 8192
replicas: 3
masterNode:
autoResize:
enabled: true
小贴士:配置文件是键值对形式的。所有在引号“”下定义的值都被解释为字符串,而没有引号则解释为整数。所有基于数字的配置元素,如副本数量、CPU 或内存,都必须指定为整数。
用户集群工作节点被定义为节点池。这允许您在同一个 Kubernetes 集群中拥有不同大小的节点,并为节点对象应用标签和污点。最后,每个定义的节点池的最后配置元素是节点操作系统,提供 Google 的强化 Ubuntu 镜像或 Google 的不变容器优化操作系统(COS)。如果使用捆绑的负载均衡器类型-MetalLB-,至少有一个池必须将 enableLoadBalancer 配置设置为 true。
nodePools:
- name: “My-1st-node-pool”
cpus: 4
memoryMB: 8192
replicas: 3
bootDiskSizeGB: 40
labels:
environment: "production"
tier: "cache"
taints:
- key: "staging"
value: "true"
effect: "NoSchedule"
vsphere:
datastore: "my-datastore"
tags:
- category: "purpose"
name: "testing"
osImageType: "cos"
enableLoadBalancer: false
注意:工作节点虚拟机将被命名为与定义的节点池名称一致,后跟随机数字和字母,例如 My-1st-node-pool-sxA7hs7。
在集群创建过程中,vSphere 上会创建反亲和性组,并将工作节点放置在其中。这个 vSphere 功能允许我们在集群的不同 vSphere 主机之间分配工作节点虚拟机,避免在同一个物理主机上放置过多的节点。因此,在 VMware ESXi 主机故障的情况下,只有有限数量的 Kubernetes 节点受到影响,从而降低对托管服务的影响。
要启用反亲和性组,vSphere 集群中至少需要 3 个 ESXi 主机。您可以通过在配置文件中更改 antiAffinityGroups.enabled 部分的默认值来启用或禁用此功能,将其设置为 true 或 false。
antiAffinityGroups:
enabled: true
默认情况下,所有工作负载集群都可以通过自动生成的 kubeconfig 文件访问。在这种情况下,不需要额外的配置,但访问范围不受限制,并且管理起来非常困难。为了解决这个问题,Anthos on VMware 集群有一个选项可以通过 OpenID Connect (OIDC)集成到外部身份提供者,并使用 Kubernetes 授权(图 12)授予对命名空间或集群的访问权限。

图 C.8 基于 Kubernetes 集群和命名空间的访问
您可以将集群集成到现有的 Active Directory Federation Services (ADFS)、Google、Okta 或任何其他认证的 OpenID 提供者^([9])。要配置这些设置,我们必须提供所有提供者特定的信息以利用 Anthos Identity Service,并在集群创建后编辑 ClientConfig 文件^([10])。
小贴士:要恢复用户集群 kubeconfig,可以触发:kubectl --kubeconfig $ADMIN_CLUSTER_KUBECONFIG get secrets -n $USER_CLUSTER_NAME admin -o jsonpath='{.data.admin.conf}' | base64 -d > $USER_CLUSTER_NAME-kubeconfig
下一个选项,类似于管理员集群,是在配置文件级别启用或禁用自动修复功能。
autoRepair:
enabled: true/false
与管理员集群配置的关键区别在于,它可以通过将更改应用到 YAML 配置文件并触发 gkectl update 命令来轻松更改。
在我们继续讨论网络之前,需要覆盖的最后一部分是存储。默认情况下,VMware 上的 Anthos 包括 vSphere Kubernetes 卷插件,该插件允许在连接到 vCenter 集群的数据存储上动态配置 vSphere VMDK 磁盘^([11])。在创建新的用户集群后,它配置了一个默认的存储类,该类指向 vSphere 数据存储。除了卷连接器外,新部署的集群自动获得 vSphere 容器存储接口(CSI)。CSI 是一个标准 API,它允许您直接连接到兼容的存储,绕过 vSphere 存储。值得一提的是,VMware 上的 Anthos 集群仍然支持使用树内 vSphere 云提供商卷插件,该插件允许直接连接到存储,绕过 vSphere 存储。然而,由于已知的限制,如缺乏动态配置支持,不建议使用树内插件 - 您应使用 CSI 驱动程序。
我们已经定义了用于 VMware 上 Anthos 部署的计算和存储组件。让我们总结一下。我们的构建基于管理员工作站、管理员集群和部署在 vSphere 环境中的用户集群。下面的图片展示了基于为每个用户集群专用的资源池以及与用户主节点结合的管理集群资源的资源分离。

图 C.9 VMware 上 Anthos 的资源分布
您已经了解了关于 VMware 上 Anthos 实现计算部分的很多内容。在下一节中,我们将详细介绍根据网络实施选择进行的通信能力、要求和限制。
C.3.1 Anthos 网络
要理解网络在 Anthos 集群中的作用,我们需要了解 Anthos 集群由两种不同的网络模型组成。第一个是放置整个基础设施的 vSphere 网络,另一个是 Kubernetes 网络。
在本章开头,我们提到 VMware 上的 Anthos 不需要在 vSphere 基础设施上应用任何软件定义网络,并且可以完全基于 VLAN。
IP 管理
既然我们已经熟悉了部署流程,让我们更深入地探讨配置和架构元素。
除了前几章中提到的配置文件外,根据部署场景还可能有额外的需求。当使用 DHCP 时,所有节点都从它那里分配了 IP 地址,如图 C.10 所示。

图 C.10 基于 DHCP 的部署
如果部署没有利用 DHCP 服务进行节点 IP 分配,则必须为管理员集群和每个用户集群创建额外的主机配置文件(图 C.11)。一些组织认为静态分配的地址是最稳定的实现,因为它消除了任何 DHCP 问题或节点租约到期,不会对节点通信造成任何干扰。然而,虽然它可能消除任何 DHCP 问题,但它引入了主机配置文件准备的管理开销和创建集群的可扩展性限制。最佳实现是您必须为您的集群和组织决定的事情。

图 C.11 静态 IP 分配场景
可以遵循混合部署场景,其中既部署了基于 DHCP 的集群,也部署了非 DHCP 基于的集群,如下面的图片所示。

图 C.12 混合 DHCP 和静态 IP 分配场景
使用此配置,我们可以有一个使用静态 IP 地址进行其管理平面和用户 Kubernetes 主节点管理的管理员集群,为第一个用户集群使用 DHCP,为第二个用户集群的 Kubernetes 工作节点使用静态 IP 地址,或者完全相反。由于 Kubernetes 节点 IP 地址的变化会对存储访问造成重大问题,因此建议为管理员集群节点使用静态 IP 分配,而 DHCP 可以用于短期用户集群。
与混合部署相关有一些限制:
-
IP 分配必须在整个管理员集群和用户集群主节点中相同,因为它们共享相同的 IP 地址池
-
所有用户集群工作节点池必须使用整个集群相同的 IP 分配方法
-
即使由同一个管理员集群管理,不同的用户集群也可以使用不同的 IP 分配方法
到目前为止,我们已经讨论了 IP 分配选项以及每种实现的优缺点。现在让我们谈谈详细的网络实施配置、管理和平摊工作负载的良好实践和建议。
管理平面
深入到管理平面网络配置,我们需要根据要执行的活动与两个元素进行通信。我们必须为 VMware 上的 Anthos 部署的第一个元素是管理员工作站,该工作站由 Google 完全预配置并加固。
第二个通信点是整个管理员集群,托管所有管理员节点和用户集群主节点。两者都要求与 VMware 基础设施通信以自动部署虚拟机。没有技术要求将管理员工作站、节点和 vSphere 基础设施分开,但从安全角度来看,强烈建议在图下所示的第二层上隔离这些网络。

图 C.13 Anthos 在 VMware vSphere 网络上的 Anthos
由于 Anthos on VMware 集群集成到 GCP 控制台,它们需要与外部世界进行通信。这种连接可以通过直接互联网连接或通过互联网代理来实现。
新的 Anthos 集群的默认网络模型被称为孤岛模式。这意味着 Pod 可以相互通信,但默认情况下被阻止从外部网络访问。另一个重要的注意事项是,Pod 到位于外部的服务的出站流量通过节点 IP 地址进行 NAT。
同样的规则适用于服务。它们可以在集群之间重叠,但不能与 Pod 子网重叠(图 C.14)。此外,Pod 和服务的子网也不能与集群消耗的外部服务重叠,例如互联网代理或 NTP^([12]),否则流量将无法路由到创建的集群外部。

图 C.14 Pods 和 services
服务 CIDR 和 Pod CIDR 都在管理集群配置 YAML 文件中定义,内置的预检检查确保两者的 IP 地址不重叠。
network:
serviceCIDR: 10.96.0.0/16
podCIDR: 10.97.0.0/16
负载均衡器
要管理 Kubernetes 集群,您必须访问其 Kubernetes API 服务器。管理集群通过 LoadBalancer IP 公开它,可以根据类型配置 3 种风味。在撰写本章时,Anthos on VMware 支持以下类型:MetalLB、F5BigIp 和 ManualLB,它们取代了 SeeSaw。
内置 - MetalLB
MetalLB 是 Google 开发的针对 Kubernetes 集群的开源^([13]) Cloud Native Computing Foundation 沙盒项目网络负载均衡器实现。它运行在裸机实现上,允许在任何集群中使用 LoadBalancer 服务。
MetalLB 解决了超大规模 Kubernetes 实现中的一部分需求,但在本地环境中却缺乏,即外部公告和地址分配。地址分配提供了自动将 IP 地址分配给创建的 LoadBalancer 服务的功能,无需手动指定。此外,您可以根据需要创建多个 IP 地址池,可以并行使用,例如用于内部服务暴露的私有 IP 地址池和提供外部访问的 IP 地址池。一旦分配了 IP 地址,它必须在网络上进行公告,这时其外部公告功能就派上用场。MetalLB 可以以两种模式部署:二层模式和 BGP 模式。
当前 VMware 上的 Anthos 的实现仅使用层 2 模式。在层 2 实现中,外部通告通过使用标准地址发现协议进行管理:IPv4 使用 ARP,IPv6 使用 NDP。每个 Kubernetes 服务都作为专用的 MetalLB 负载均衡器呈现,因此当创建多个服务时,流量会在负载均衡器节点之间分配。这种实现具有优点和限制。关键限制与这样一个事实相关,即服务 IP 的所有流量都将始终流向一个节点,在那里 kube-proxy 将其传播到所有服务 Pod。因此,服务带宽始终限制在单个节点的网络带宽。在节点故障的情况下,服务将自动故障转移。这个过程不应超过 10 秒。当考虑 MetalLB 层 2 实现的优点时,我们当然必须提到这样一个事实,即它是完全集群内的实现,没有任何对物理网络(如硬件等)的特殊要求。层 2 实现不会对每个网络创建的负载均衡器数量引入任何限制,只要可用 IP 地址可以分配。这是使用 memberlist Go 库维护集群成员列表和成员故障检测使用基于 Gossip 协议而不是例如虚拟路由器冗余协议^([14])的结果。

图 C.15 使用 metalLB 的管理员集群网络
INFO:管理员集群 Kubernetes VIP 没有利用 MetalLB,因为管理员集群没有实现高可用性。所有用户集群都使用 MetalLB 部署来暴露其 Kubernetes VIP。
MetalLB 是 Anthos on VMware 的一部分,在 Anthos 许可下得到覆盖,并且与所选支持模型一起提供标准支持,包括每个版本的生命周期管理活动。
集成 - F5
引入负载均衡器功能的第二种选择是与 F5 BIG-IP 负载均衡器集成——称为集成负载均衡器模式。与 MetalLB 相比,F5 基础设施必须提前准备,并且不是由 Google 自动部署。对于 VMware 上的 Anthos,BIG-IP 提供外部访问和 L3/4 负载均衡服务。当定义集成负载均衡器模式时,VMware 上的 Anthos 会自动执行预检查并安装单个支持的 F5 BIG-IP 容器入口服务(CIS)控制器。

图 C.16 使用 F5 BIG-IP 的管理员集群网络
生产许可证为在 VMware 负载均衡器上的 Anthos 提供高达 40 Gbps 的吞吐量。
BIG-IP 集成在 Google 的支持兼容性矩阵内得到完全支持,但根据 F5 许可单独授权。
手动负载均衡器
为了允许灵活性和使用现有负载均衡基础设施的能力,Anthos on VMware 可以通过手动模式配置负载均衡器进行部署。在这种实现中,在集群部署开始之前需要设置一个带有 Kubernetes API VIP 的负载均衡器。配置步骤取决于你使用的负载均衡器。Google 提供了详细的文档,描述了 BIG-IP 和 Citrix 的配置步骤。在手动模式下,你不能将类型为 LoadBalancer 的服务暴露给外部客户端。
由于缺乏与手动负载均衡模式的自动化集成,Google 不提供支持,并且任何与负载均衡器相关的问题都必须由负载均衡器的供应商管理。
我们已经了解了所有三种模式类型。让我们看看配置文件。配置在 admin 配置 yaml 文件的专用 loadBalancer 部分中,将根据所选选项而有所不同。
对于 admin 集群中的 MetalLB 配置,我们必须定义负载均衡器 kind 为 MetalLB 并提供 Kubernetes API 服务 VIP。
loadBalancer:
vips:
controlPlaneVIP: "203.0.113.3"
kind: MetalLB
当选择 F5 BIG-IP 集成模式时,负载均衡器部分必须更改为 kind: F5BigIP。整个 MetalLB 部分(默认情况下在新生成的配置文件中启用)必须注释掉,并且必须使用凭据文件和分区详细信息定义 f5BigIp 部分。
loadBalancer:
vips:
controlPlaneVIP: "203.0.113.2"
kind: F5BigIP
f5BigIP:
address: "loadbalancer-ip-or-fqdn"
credentials:
fileRef:
path: “name-of-credential-file.yaml”
entry: “name of entry section in above defined file”
partition: “partition name”
snatPoolName: “pool-name-if-SNAT-is-used”
最后一个用例是涵盖手动负载均衡。在这种情况下,我们必须定义 kind: ManualLB 并注释掉 seesaw 部分。接下来,我们必须手动定义 NodePort 配置选项。
loadBalancer:
vips:
controlPlaneVIP: "203.0.113.2"
kind: ManualLB
manualLB:
controlPlaneNodePort: “9000”
addonsNodePort: “9001”
用户集群
用户集群的网络基于与 admin 集群相同的原理,但为了工作负载部署能力而外部化。每个集群都以孤岛模式部署,其中服务和 Pods CIDR 在用户集群配置文件中不得重叠。
network:
serviceCIDR: 10.96.0.0/16
podCIDR: 10.97.0.0/16
我们再次有三种负载均衡器部署和集成模式:捆绑式、集成式和手动式。
捆绑式部署同样使用 MetalLB 实现。你已经了解到用户集群的主节点被部署到 admin 集群节点网络中,并且 IP 地址是从预定义的静态池或 DHCP 服务器分配的。Kubernetes API 服务也自动在同一个网络中暴露,但其 IP 地址必须在用户集群配置文件中手动定义。
用户集群的工作节点可以部署在与 admin 节点相同的网络中,或者部署到单独的专用网络中。第二种选择更受欢迎,因为它允许将管理平面的流量分离。每个新的用户集群都附带一个新的专用 MetalLB 负载均衡器用于数据平面。Kubernetes API 的控制平面 VIP 始终与 admin 集群负载均衡器实例共同托管。用户集群的 ingress VIP 自动部署到集群工作节点池网络中。因此,你可以将 MetalLB 限制在专用节点池上托管,而不是在用户集群的所有节点上。

图 C.17 使用 MetalLB 的用户集群网络
在多集群部署中,用户集群可以共享单个网络或使用专用网络。当使用单个网络时,请确保配置文件中的节点 IP 地址不重叠。
正如我们已经提到的,MetalLB 是一个完全捆绑的负载均衡器。这意味着每次创建服务类型 LoadBalancer 时,VIP 都会在负载均衡器上自动创建,发送到 VIP 的流量将被转发到服务。由于 MetalLB 具有 IP 地址管理(IPAM),因此每个服务的 IP 地址都会自动分配。IP 池和托管 MetalLB VIPs 的节点的定义在用户集群负载均衡器配置文件部分中,如下所示。
loadBalancer:
vips:
controlPlaneVIP: "Kubernetes API service VIP"
kind: MetalLB
metalLB:
addressPools:
- name: "name of address pool"
addresses:
- "address in form of X.X.X.X/subnet or range X.X.X.X-X.X.Y.Y”
# (Optional) Avoid using IPs ending in .0 or .255.
avoidBuggyIPs: false
# (Optional) Prevent IP addresses to be automatically assigned from this pool (default: false)
manualAssign: false
此外,我们必须在已详细描述的 worker pools 部分允许 MetalLB 服务在一个(或多个)虚拟机池上,通过定义配置为“enableLoadBalancer: true”的形式。
集成负载均衡允许集成到 F5 BIG-IP,并自动提供 LoadBalancer 服务类型,类似于我们描述的 admin 集群集成。在这种情况下,集成点可以是 admin 和用户集群相同的,不需要使用 F5 的单独实例。重要的是要记住,每个新的集群在部署之前必须在负载均衡器侧预先配置并适当准备。

图 C.18 使用 F5 BIG-IP 的用户集群网络
用户集群负载均衡器的手动模式实现遵循相同的规则,引入相同的约束和限制,如 admin 集群。每个服务暴露都需要与外部团队联系,并执行官方文档中描述的手动活动^([15])。
在本节中,我们探讨了 Anthos on VMware 中管理集群和工作负载集群的不同网络配置选项。重要的是要记住,与 IP 分配类似,我们可以选择使用单个负载均衡器集成模式,或者为不同的集群选择不同的模式。因此,我们可以拥有基于 MetalLB 的管理集群、一个 MetalLB 用户集群、第二个集成 F5 BIG-IP 的用户集群以及第三个手动集成的 Citrix Netscaler 负载均衡器。
loadBalancer:
vips:
controlPlaneVIP: "Kubernetes API service VIP"
ingressVIP: “Ingress service VIP (must be in use node network range)
kind: MetalLB
MetalLB:
addressPools:
- name: "my-address-pool-1"
addresses:
- "192.0.2.0/26"
- "192.0.2.64-192.0.2.72"
avoidBuggyIPs: true
loadBalancer:
vips:
controlPlaneVIP: "Kubernetes API service VIP"
kind: F5BigIP
f5BigIP:
address: "loadbalancer-ip-or-fqdn"
credentials:
fileRef:
path: “name-of-credential-file.yaml”
entry: “name of entry section in above defined file”
partition: “partition name”
snatPoolName: “pool-name-if-SNAT-is-used”
loadBalancer:
vips:
controlPlaneVIP: "Kubernetes API service VIP"
kind: ManualLB
manualLB:
ingressHTTPNodePort: Ingress-port-number-for-http
ingressHTTPSNodePort: Ingress-port-number-for-https
controlPlaneNodePort: “NodePort-number-for-control-plane-service”
C.3.2 GCP 集成功能
在前面的章节中,我们讨论了 Anthos on VMware 的计算和网络架构。在本节中,我们将介绍 GCP 服务的不同集成功能,以便利用单个控制面板来管理所有 Anthos 集群,无论它们是在本地部署还是在其他云上。
正如您在部署新的管理员和用户集群时已经注意到的,定义一个将被集成到其中的 GCP 项目是强制性的。这使连接代理能够正确注册并与中心建立通信,如操作管理章节中详细描述的那样。一般来说,GKE Connect 执行两个活动,启用连接和身份验证以注册新集群。

图 C.19 舰队与连接代理的关系
为此目的,使用了两个专用的服务帐户。该部分是强制性的,并且必须为用户集群正确定义。请注意,由于代理服务帐户使用工作负载身份功能,因此它不需要密钥文件。
gkeConnect:
projectID: “My-awsome-project”
registerServiceAccountKeyPath: register-key.json
注意:GKE connect 在本地到 GCP 集成中发挥着重要作用。这使我们能够直接从 GCP 控制台云市场、云运行选项中利用它,通过 Anthos 授权与 CICD 工具链集成,而无需公开 Kubernetes API。
Anthos on VMware 具有将基础设施日志和指标发送到 GCP 云监控的能力。这适用于管理员和用户集群。我们可以选择仅发送与 Kubernetes 相关的指标,也可以包括 vSphere 指标。每个集群的指标可以发送到不同的项目。
stackdriver:
projectID: “My-awsome-project”
clusterLocation: gcp-region-name
enableVPC: false/true
serviceAccountKeyPath: monitoring-key.json
disableVsphereResourceMetrics: true/false
另一个适用于管理员和用户集群的集成功能是能够发送 Kubernetes API 服务器审计日志。如前所述,我们可以选择存储日志的项目和位置区域以及用于该集成服务帐户。
cloudAuditLogging:
projectID: “My-awsome-project”
clusterLocation: gcp-region-name
serviceAccountKeyPath: audit-key.json
最后两个集成功能仅适用于用户集群。第一个是选择从 Google Cloud Platform 控制台云运行 Anthos(在“Anthos,无服务器计算引擎(Knative)”章节中详细描述)中消费,并将服务直接部署到 VMware 集群上的 Anthos。在这里没有太多配置,因为服务本身正在利用连接功能,并在用户集群的专用命名空间中部署 Knative。这意味着它必须在与 VMware 集群注册的 Anthos 相同的项目中启用。您将在“Anthos Cloud Run”章节和相关的文档中了解更多关于云运行 Anthos 和 Knative 的信息^([16])。
功能列表描述以计量结束。启用计量功能后,用户集群将资源使用和消耗数据发送到 Google Bigquery。这使我们能够分析它,并根据实际需求调整集群大小,或者将其公开并作为报告等展示。
usageMetering:
bigQueryProjectID: “My-awsome-project”
bigQueryDatasetID: dataset-name
bigQueryServiceAccountKeyPath: metering-key.json
enableConsumptionMetering: false/true
C.4 摘要
-
在现有的 vSphere 基础设施之上消费云原生功能的 Anthos on VMware 是一个很好的选择
-
架构由两个元素组成:
-
负责托管应用程序资源交付的用户集群
-
负责管理和控制已部署用户集群的管理员控制平面
-
-
它可以用作与托管虚拟机共存的附加组件,以及为混合云实施和云原生之旅准备的本地 Kubernetes 实现。
-
我们可以利用现有的 VMware 技能进行基础设施管理,保持对云操作的全面可见性,并在需要时从自己的数据中心消费 GCP 服务。
-
设置可以是独立的和自包含的,使用捆绑功能如 MetalLB,或者集成到现有基础设施中,以及它带来的自动化能力和约束。
-
集群配置可能因目的、规模和可用性要求而异。
^([1]) cloud.google.com/anthos/gke/docs/on-prem/how-to/vsphere-requirements-basic#resource_requirements_for_admin_workstation_admin_cluster_and_user_clusters
^([2]) developers.google.com/identity/protocols/oauth2/openid-connect
^([3]) cloud.google.com/anthos/gke/docs/on-prem/how-to/vsphere-requirements-basic
^([4]) cloud.google.com/anthos/clusters/docs/on-prem/version-history
^([5]) 如果使用 --auto--create-service-accounts 标志,则会填充部分。
^([6]) metallb.universe.tf/installation/clouds/
^([7]) vSphere 高可用性功能可以减轻这种行为,并将 Kubernetes API 的停机时间减少到分钟,直到虚拟机在新主机上重新启动。vSphere HA 不会保护虚拟机免受损坏。
^([8]) 对于基于 vSAN 的部署,所有节点都必须放置在同一个数据存储上。
^([9]) Anthos on VMware 支持所有认证的 OpenID 提供商。完整列表可以在 openid.net/certification/ 下找到。
^([10]) cloud.google.com/anthos/identity/setup/per-cluster
^([11]) vSphere 数据存储可以由任何块设备、vSAN 或 NFS 存储支持。
^([12]) 网络时间协议
^([13]) github.com/metallb/metallb
^([14]) tools.ietf.org/html/rfc3768
^([15]) cloud.google.com/anthos/clusters/docs/on-prem/how-to/manual-load-balance
附录 D. 数据和分析
Patricia Florissi
本章涵盖:
-
理解可移植性与移动性
-
Kubernetes 和存储
-
Anthos 和存储
-
BigQuery Omni
-
Anthos Hybrid AI
直到最近,Anthos 通常在计算和网络的环境中提到,很少在存储或数据的环境中提到。尽管如此,Anthos 有潜力将它在可观察性、安全、配置和控制方面引入的许多基本原理带给有状态的工作负载。此外,Anthos 有潜力像它已经颠覆计算的可移植性和移动性一样,颠覆数据的可达性和可访问性。通过 Anthos,容器可以无缝地跨混合和多云环境访问存储设备,在配置、配置、分配和访问这些资源方面保持一致性。
一旦 Anthos 集群能够使有状态的容器在混合和多云环境中部署,它就为这些容器提供了以安全和一致的方式访问数据的途径,这样分析数据的执行方式就为重新设计做好了准备。在传统的环境中,从众多数据源收集的数据被存储在中央位置,以数据仓库或数据湖的形式存在,这就是分析执行的地方。因此,包括使用人工智能(AI)和机器学习(ML)的分析解决方案,长期以来都是基于假设所有所需数据都可以集中访问而设计和优化的。
然而,最近的事件一直在挑战在分析之前集中所有数据的能力。组织通常会将数据分散在组织边界或地理位置之间,无论是在本地托管还是在公共云中。通常,法规遵从性、安全或数据隐私会强制实施某种形式的数据居住地,数据必须存储在物理或逻辑围栏内,不能移出该围栏。此外,即使数据可以跨越这些边界,带宽限制,如容量、速度和成本,可能会对可以传输到中央目的地的数据量施加限制。Anthos 使得将数据分析带到数据所在之处变得更加容易,无论是在本地还是在公共云中,数据发生或需要发生的地方。
Anthos、数据和分析的交集只是一个新兴话题,在 Anthos 向现代应用程序提供支持的道路上,它是最初级的。随着你阅读本章,大量与如何使 Anthos 能够支持下一代许多数据服务以及如何使分析在混合和多云环境中无缝工作相关的工作正在许多领域继续进行,包括:
-
数据备份和灾难恢复,从本地到云以及云之间的;
-
数据库,其中计算引擎可以是容器原生,存储可以是软件定义的;
-
联邦学习,其中 AI 模型的训练在多个地点进行协调,处理数据所在地的数据,并仅集中聚合此类计算的中间结果;
-
AI 和 ML 管道允许在生产环境中实现模型的工业化,从而结束实验阶段。
如您从引言中可以看到,Anthos 上的数据开放了多种需要数据的额外工作负载,这些工作负载跨越各种多云和混合云解决方案——容器不再仅限于无状态工作负载。但是,在更深入地探讨在 Kubernetes 和 Anthos 上使用数据之前,我们需要了解可移植性和移动性之间的区别,这将在下一节中讨论。
D.1 可移植性与移动性
当涉及到 Anthos 和数据时,区分可移植性和移动性的细微差别对于理解处理混合和多云环境中分散数据背后的挑战至关重要。应用程序的可移植性使 Anthos 能够实现“一次编写,到处运行”的前提,而应用程序的移动性则使这一概念扩展到“一次编写,到处运行,随意移动”。可移植性在软件设计阶段对软件开发者很重要,在操作阶段对管理员很重要,因为它减少了可能需要配置的环境类型。移动性在运行时对操作者来说最为重要,因为它使他们能够动态地重新分配工作负载,实时调整以满足需求。在许多方面,移动性旨在避免将工作负载锁定在特定配置的具体细节中,并根植于开放标准的采用。可移植性和移动性共同使得工业规模的操作更加可行和可扩展。然而,与可移植性和计算移动性相关的挑战可能比与计算移动性相关的挑战要复杂得多。
虽然增加了可移植性,扩大了有状态容器可以部署的硬件表面,但这并不一定直接等同于有状态工作负载从一个位置移动到另一个位置。在某些情况下,运行在位置 L1 并访问持久存储 PS 的有状态工作负载 SW 可能无法移动到位置 L2。例如,SW 可能在 L2 上运行时无法访问 PS,而且数据本身可能没有可移植性,无法转移到 L2 位置可访问的物理存储。数据往往表现出一种重力元素,由于数据本身的巨大规模、移动数据的财务和运营成本、带宽限制、安全要求、法规遵从性和隐私限制等多种因素,这给移动带来了挑战。此外,在许多情况下,数据是持续创建的,应用程序需要在时间敏感的窗口内摄取和处理不断增长的数据集。在这些场景中,一次性复制或一系列离散的数据副本可能无法满足应用程序的要求。
关于可移植性
可移植性指的是在多个位置执行的能力。在许多方面,可移植性在涉及工作负载放置的移动性担忧之前就已经存在。在工作负载能够在某个位置运行之前,工作负载应该与底层架构兼容,并且应该有足够的资源来运行工作负载。为了提高可移植性,开发环境寻求最小化对特定基础设施配置和库的依赖。
然而,可移植性可以被视为有效移动性的一个要求。在某个位置运行的计算工作负载应该只移动到它可以在那里继续执行的其他位置。本质上,一个应用程序可以被制作成可移植到更多位置,它就可以移动到更多位置。执行性能在这些位置之间可能会有所不同,因为每个位置可能具有不同的计算、内存、网络和存储配置,但无论如何,应用程序实际上是可以执行的。
容器通过将应用程序代码及其所有库依赖项打包在一起,减少了在特定库配置方面的需求,这些配置需要在运行之前在某个位置可用。对于有状态的容器,可移植性要求容器与一个位置上的存储设备交互的方式与容器与另一个位置上的存储设备交互的方式兼容。
关于移动性
在计算机科学领域,移动性指的是将资源的位置从一个物理位置转移到另一个位置的能力。对于计算工作负载,它指的是将工作负载的执行从一组物理计算资源(如服务器节点)转移到另一个资源。对于数据,它指的是将数据内容从物理存储设备移动到另一个设备。
虚拟机(VM)使跨物理边界移动计算成为可行的方法,通常在实时进行,并且服务中断最小,如果没有中断。当涉及到这些虚拟机访问的数据时,并没有赋予相同的移动性。在网络上移动数据可能会受到延迟、带宽限制以及从其位置读取和将数据写入新位置的成本的影响,还可能受到在飞行中更改数据地址的挑战。应用程序通常在执行开始时将地址绑定到物理位置,并且这些绑定不容易更改。此外,根据需要移动的数据大小,带宽和读写吞吐量限制不容忽视。随着大小的增加,数据获得更多的重力并失去移动性。
因此,需要访问驻留在持久存储中的数据的虚拟机(VM)只能绑定到移动到其他物理计算资源,这些资源仍然可以访问最初存储数据的位置。本质上,计算工作负载移动了,但数据没有。
当通过简单地在新目标位置启动新的容器并终止旧的容器来移动工作负载变得可行且更容易时,容器增加了移动性的灵活性。与实际移动正在运行的工作负载相比,这种方法更加有效。然而,对访问持久存储的容器(称为有状态容器)也适用类似的约束。只要有状态容器的新的位置可以访问与旧容器在其先前位置使用的相同持久存储,移动性就更容易。然而,容器有一个有趣的特点。由于容器是从零开始重新启动的,因此可以在容器和物理存储之间建立新的绑定。因此,只要副本是彼此的精确镜像,容器也可以移动到存在数据副本的位置。
D.1.1 章节组织
本章简要介绍了 Anthos、数据和数据分析的主题,其组织结构如下:
-
第 Kubernetes 和存储 节回顾了 Kubernetes 如何与存储层交互的一些重要概念,为下一节奠定了基础;
-
第 Anthos 和存储 节讨论了 Anthos 如何在 Kubernetes 的基础上增加价值,以增强访问持久存储的工作负载的可移植性;
-
由 Anthos 驱动的 BigQuery 部分解释了 Anthos 如何使 Google Cloud 数据仓库分析引擎 BigQuery 能够在存储在其他公共云平台上的数据上执行查询;
-
Anthos 混合人工智能 部分解释了 Anthos 如何使 Google Cloud 分析解决方案在本地运行,允许云原生分析在无需将数据移动到云的情况下部署和执行;
-
摘要 部分概述了本章涵盖的主要主题。
D.2 Kubernetes 和存储
关于基于容器和云原生应用 (CNAs) 的一个基本问题是它们如何支持持久数据。这些问题范围从它们如何在集群内支持像块或文件操作这样简单的事情,到它们如何与交易数据库和 PB 级规模的对象存储交互。由于 Anthos 是 Kubernetes 之上的管理平面,因此首先了解 Kubernetes 如何公开块和文件存储的配置和管理至关重要,然后了解 Anthos 不仅在今天在 Kubernetes 存储之上添加了什么,而且了解 Anthos 未来可以添加什么。
在 Kubernetes 中,卷代表存储分配的单位,与存储系统直接交互的容器被称为有状态容器。图 D.1 数据和控制平面 展示了使有状态容器能够与存储系统交互的技术堆栈。数据位于持久物理存储层,这是堆栈中的最低层,包括例如 互联网小型计算机系统接口 (iSCSI) 逻辑单元号 (LUN)、网络文件系统 (NFS) 共享以及对象、块和文件的云服务。在物理层之上,在操作系统 (OS) 层,有块和文件系统,这些系统可以是本地的或网络化的。这些系统实现了驱动程序,通常在操作系统内核级别运行,允许上层通过块级或文件级抽象与物理存储交互。在最基本的形式中,容器通过两个平面与存储系统交互:
-
数据平面:由有状态容器用于执行读取和写入操作。在很大程度上,数据平面已经标准化。例如,可移植操作系统接口 (POSIX) 是将数据读入和写入文件和块存储的事实上标准协议接口。
-
控制平面:由 Kubernetes 存储插件用于在物理存储中分配、释放和管理空间。
与数据平面不同,控制平面接口直到最近才实现标准化。2017 年,涉及 Kubernetes、Mesos、Docker、Cloud Foundry 和其他几个容器的容器编排器之间的努力,导致了容器存储接口(CSI)规范的制定。存储供应商通过使用其特定的 API 和存储协议将 CSI 规范实现为驱动程序。然后,供应商的 CSI 驱动程序被打包并部署在 Kubernetes 集群中作为 Pods,通常分为控制器部署和每个节点的部署。当编排容器工作负载的卷时,Kubernetes 会调用这些驱动程序实现的适当 CSI API。CSI 将在接下来的会话中进一步解释。

图 D.1 数据平面和控制平面
在本章的上下文中,数据专指持续应用程序执行的数据。因此,数据不仅需要持久存储,而且在创建或更改它的应用程序终止后,无论是正常还是异常终止,都需要对其进行寻址和访问。这些应用程序的范围可以从非常短暂的,例如在手机中记录视频流的相机应用程序,到更具有弹性的数据库应用程序,例如可以成为数字银行服务后端的数据库应用程序。
D.2.1 标准化的出现
Kubernetes 卷插件为供应商提供了一个抽象层,以便在 Kubernetes 中添加对他们的块和文件存储系统的支持,从而自动化容器的存储配置、附加和挂载。此外,Kubernetes 对持久卷(PVs)、持久卷声明(PVCs)和存储类(StorageClass)对象的抽象使得存储和有状态容器的可移植性成为可能。但其他挑战仍然存在。
在 2017 年初,Kubernetes 还不是最广泛采用的容器编排平台。Mesos、Docker Swarm 和其他平台拥有相当大的市场份额。每个编排系统都有不同的方式将卷暴露给它们自己的容器。为了解决容器市场,存储供应商需要为每个容器编排系统开发多个存储插件,许多供应商决定在创建标准或市场领导者出现之前推迟开发。
同时,Kubernetes 卷插件机制也面临着几个挑战。卷插件必须作为树内卷插件在核心 Kubernetes 中实现。存储供应商必须使用 Go 编程语言实现插件,向 Kubernetes 代码仓库贡献源代码,并将代码作为 Kubernetes 主发布的一部分进行发布和维护。
树内卷插件为不同的社区带来了不同的挑战,如下所述:
-
对于 Kubernetes 开发社区:卷插件直接嵌入到仓库中,作为 Kubernetes 代码库的一部分,在 Kubernetes 二进制代码中进行编译和实现,这变得令人畏惧。引入的紧密耦合带来了挑战,包括:
-
安全性:卷插件拥有完全权限访问所有 Kubernetes 组件,整个源树都暴露于安全漏洞的利用;
-
稳定性:卷插件中的错误可能会影响关键 Kubernetes 组件,导致组件故障或整个 Kubernetes 系统故障;
-
质量和测试:外部代码的测试和维护与 CI/CD 管道交织在一起,因此在每次发布之前测试 Kubernetes 代码以针对所有支持的存储配置变得越来越具有挑战性。Kubernetes 开发者通常无法访问包含所有存储版本及其相关专业知识的研究室。对于某些插件,Kubernetes 依赖于用户在问题得到解决之前找到并报告问题。
-
-
对于存储供应商:树内卷插件(in-tree volume plugins)的运行速度减慢,甚至阻碍了驱动程序的开发和支持,这归因于插件生命周期多个阶段的挑战,包括:
-
在开发期间:存储供应商需要有效地扩展 Kubernetes 代码,并将代码提交到 Kubernetes 核心仓库,这要求存储供应商掌握 Go 编程语言和 Kubernetes 的专业知识。强制使用单一编程语言 Go 进一步限制了智力资本池,因为 Go 是一种新兴语言,市场上可用的开发者比 Java 或 C 等其他语言要少;
-
在发布期间:存储供应商需要与 Kubernetes 发布周期保持一致,这限制了他们只能在 Kubernetes 发布代码时发布新代码和更新,每年仅四次。这种紧密耦合的发布周期严重影响了部署速度;
-
在商业化期间:卷插件的代码被迫开源;
-
-
对于用户:这些动态影响了有状态容器的整体 Kubernetes 体验,并阻止了大规模采用,因为:
-
生态系统薄弱:随着存储供应商努力开发插件,存储选择数量有限;
-
速度慢:发布周期长且测试质量差,用户必须等待很长时间才能解决问题得到解决。
-
在 Google 强有力的领导下,Kubernetes 社区决定放弃树内插件模型,并为供应商开发卷插件创建一个独立的方法。Kubernetes 并非孤军奋战。所有容器编排系统都面临着类似的挑战——它们需要尽可能多地暴露容器给不同的存储供应商产品,尽可能少的工作,以最安全的方式。同时,存储供应商也希望尽可能多地将其产品暴露给尽可能多的用户,无论他们使用的是哪种容器编排系统,利用尽可能多的系统中的插件,对代码进行很少或没有修改。因此,Kubernetes 社区与其他容器编排社区结成联盟,开始制定一个规范以创建一个可扩展的卷层。最初的设计完全集中在用户体验和跨供应商的标准存储平台功能上。
除了创建标准之外,Kubernetes 还拥有一个独特的需求,即通过动态存储分配按需提供存储。在运行时,应用程序应能够随时请求存储,Kubernetes 应能够联系后端系统以获取所需的存储并将其提供给应用程序。不应需要管理员介入,不应发生对应用程序执行的中断,也不应需要为每个应用程序进行专有的存储预分配。一旦应用程序不再需要存储,它应被释放回池中以供重新分配。
D.2.2 容器存储接口
容器存储接口(CSI)是一个开源标准,用于将任意块和文件存储系统暴露给由容器编排系统(如 Kubernetes)管理的容器化工作负载。CSI 规范就是这样一个规范。规范没有定义插件应该如何打包,它不要求任何部署机制,也不强加或包含任何关于如何监控的信息。
CSI 的核心功能是提供一个接口以执行以下操作:
-
创建/删除卷
-
将卷附加/从节点分离
-
在节点上为工作负载挂载/卸载卷
-
对卷进行快照并从快照创建新的卷
-
克隆卷
-
调整卷大小
CSI 中的接口实现为以下三组 API,如下所示,并且所有 API 都是幂等的,这意味着它们可以被同一客户端多次调用,并且会产生相同的结果。这些 API 都需要一个卷标识符,这允许调用接收者知道之前已经进行了调用。API 的幂等性带来了可预测性和鲁棒性,使得系统能够处理从失败中恢复,尤其是在组件之间的通信中。
-
身份服务:提供有关插件的基本信息操作,例如其名称、基本功能和当前状态。
-
节点服务:需要在将使用卷的节点上运行的卷操作,例如挂载和卸载。
-
控制器服务:可以在任何节点上执行的卷操作,例如卷挂载和卸载,以及卷创建和卷删除。
gRPC 远程过程调用(gRPC)被选为线协议,因为它与语言无关,拥有庞大的用户社区,并有一套广泛的工具来帮助实现。API 是同步的,这意味着调用者在调用后将被阻塞,等待结果返回。规范没有强加任何打包和部署要求。唯一的要求是提供通过 Unix 套接字的 gRPC 端点。
D.2.3 CSI 背后的差异化
CSI 标准是在努力实现几个目标的过程中出现的,并真正成为创建一个非常可扩展的卷层的基础。CSI 为 Kubernetes 创建了一个存储生态系统,其中不仅所有主要存储供应商都支持它,而且最终用户还可以为他们的应用程序编写自己的自定义 CSI 驱动程序。本质上,CSI:
-
标准化存储控制平面:促进存储供应商和容器编排器之间的互操作性。存储供应商构建一个单一驱动程序,任何编排器都可以使用,容器编排器可以与任何驱动程序接口;
-
支持动态存储分配:消除预配置的需求;
-
加速存储供应商生态系统的扩展:增加 Kubernetes 支持的选择数量;
-
提供了源代码树外的设计:降低开发人员实现卷驱动程序的门槛,消除源代码贡献的风险,并使 Kubernetes 发布周期与存储供应商的开发周期解耦。
下一节将讨论 Anthos 如何通过 Anthos Ready Storage 和遵循 CSI 来使有状态容器更具可移植性。
D.3 Anthos 和存储
将存储抽象为一系列不同大小的持久卷,这些卷在需求时动态分配和释放,构成了 Kubernetes 提供给最终用户的核心价值。CSI 为供应商的存储系统提供了一个可扩展的南向接口,屏蔽了存储设备谱系的异构性,为 Kubernetes 以及其他所有容器编排引擎提供了一个一致和统一的接口。同时,Kubernetes 为 Kubernetes 用户提供了一个标准的北向接口,以便以更高层次的抽象(即 PV 和 PVC)与存储进行交互,而 CSI 还允许开发者根据磁盘加密、快照和调整大小来对磁盘进行建模。
到目前为止,所有涵盖的 CSI 主题都与 Kubernetes 有关,而不是 Anthos。这引发了一个有趣的问题。除了 Kubernetes 所做的工作之外,Anthos 在存储领域增加了什么价值(如果有)?一个简单、甚至可能是微不足道的答案是,Anthos 通过简化 Kubernetes 环境的部署和管理来帮助存储空间。通过支持 CSI,Kubernetes 实际上扩大了 Anthos 可以部署和管理支持有状态容器的 Kubernetes 集群的环境范围。
然而,实际上,Anthos 今天提供了很多价值,并且在未来有潜力提供更多价值,以支持混合和多云环境中的存储使用,并扩展有状态容器的可移植性和管理。
在 Anthos 中,就像在 Kubernetes 中一样,任何需要持久存储的 pod 都构成一个有状态 pod。持久存储存储的数据超出了 pod 及其可能存放的任何封装物的生命周期,例如其 VM、集群中的节点或集群本身。在 Anthos 中,只有当具有执行此操作所需身份和访问管理(IAM)权限的实体删除数据时,数据才会停止存在。
Anthos 允许在有状态 pod 在混合和多云环境中部署,并且 pod 可以与可能运行在基础设施范围内的任何地方的数据服务进行通信。如图 D.2 Anthos 中的有状态 pod 所示,虚线矩形界定了从左到右的不同环境:GCP 云(蓝色)、本地私有云(红色)以及除 GCP 以外的任何公共云(棕色)。在每个云环境中,都有运行的有状态 Anthos pod,它们访问自己的本地物理存储进行读写数据。

图 D.2 Anthos 中的有状态 pod
如以下各节所述,Anthos 提供了两种方法来扩展可以利用的基础设施存储范围:
-
Anthos 托管存储驱动器
-
Anthos Ready Storage Partner Program
D.3.1 Anthos 托管存储驱动器
Anthos 在每个平台上安装、支持和维护大量存储驱动器。这些是 Anthos 托管存储驱动器的差异化优势:
-
驱动器选择的自动化:Anthos 选择应在集群中的每个节点上支持和管理特定版本的驱动器。例如,Anthos 在 GCP 上部署 GCE 持久磁盘和文件存储驱动器,在 AWS 上部署 AWS EBS 和 EFS 驱动器,在 Azure 上部署 Azure 磁盘和 Azure 文件驱动器,在 vSphere 上部署 vSphere 驱动器。在裸金属上的 Anthos 集群还捆绑了sig-storage-local-static-provisioner.。Anthos 有效地扩大了可以自动部署和管理 Kubernetes 集群的环境范围;
-
驱动程序管理:随着驱动程序数量的增加,Anthos 帮助将这些驱动程序集成和部署到客户的 Kubernetes 环境中。随着新节点的创建,Anthos 确保存储对新的节点动态可用且可访问,无需用户干预。Anthos 自动化了在特定场景中决定使用哪个驱动程序版本的决策。Anthos 还具有管理整个驱动程序生命周期并提供支持的能力。
Google Cloud Marketplace 包含一系列 Anthos 客户可以使用的有状态引擎,例如 Redis Enterprise。
D.3.2 Anthos Ready Storage 合作伙伴计划
除了 Anthos 管理的存储驱动程序之外,用户还可以引入他们选择的其它存储供应商。Anthos 创建了 Anthos Ready Storage 计划,与选定的第三方存储合作伙伴合作,开发、测试和验证他们的 CSI 驱动程序与 Anthos 兼容。此计划确保这些资格认证的存储供应商合作伙伴提供的 CSI 驱动程序的实现,在 Anthos 中提供无缝体验。合格驱动程序的最新列表可以在Anthos Ready Storage 合作伙伴网站上找到。
为了使存储系统被验证为 Anthos Ready Storage,它必须通过 CSI 驱动程序的 Anthos 资格认证流程。Anthos 提供了一项质量保证流程来测试驱动程序并检查 Kubernetes、驱动程序和底层存储之间的互操作性。此流程确保第三方 CSI 驱动程序符合 Anthos 标准。通过引入标准化,CSI 扩展了编写插件的存储供应商生态系统,并降低了开发它们的门槛。因此,市场上开始涌现大量新的插件和更新,需要测试和质量保证。存储供应商的驱动程序必须满足以下要求:
-
客户所需的卷和其他 Kubernetes 原生存储 API 函数的动态存储分配;
-
使用 Kubernetes 部署存储 CSI 驱动程序及其依赖项;
-
管理 Kubernetes 的扩展和缩减场景中的存储;
-
使用持久存储的有状态工作负载的可移植性。
D.3.3 Anthos 备份服务
在 Anthos 中管理的 Kubernetes 集群中,具有良好开发、稳定的 CSI 功能,用户可以可靠地部署和运行他们的有状态工作负载,如关系型数据库。有状态工作负载通常比无状态工作负载有额外的需求,包括备份和存储管理。
Anthos 提供了一个简单易用的云原生服务,即Backup for GKE,供用户保护、管理和恢复在 Google Cloud GKE 集群中运行的容器化应用程序和数据。
备份中捕获两种形式的数据:
-
集群状态备份或配置备份:它由从正在备份的集群的 API 服务器中提取的一组 Kubernetes 资源描述组成;并且
-
卷备份:它由一组与配置备份中找到的 PersistentVolumeClaim 资源相对应的 GCE 持久磁盘(PD)卷快照组成。
Backup for GKE 中的备份和恢复操作是可选的。在执行备份时,用户可以选择要备份的工作负载,包括选择“所有工作负载”的选项。同样,在执行恢复时,用户可以选择要恢复的工作负载,包括选择“在此备份中捕获的所有工作负载”。您可以从一个集群备份工作负载并将它们恢复到另一个集群。
恢复操作涉及在目标集群中精心编排的 Kubernetes 资源的重新创建。一旦资源创建完成,工作负载功能的实际恢复将受正常集群协调过程的约束。例如,Pods 被调度到 Nodes,然后在那些 Nodes 上启动。在恢复过程中,用户还可以选择性地应用一组转换/替换规则,在创建目标集群中的资源之前更改特定资源中的特定参数。
这种选择性的备份和恢复与转换的组合旨在启用并支持多种不同的备份和恢复场景,包括但不限于:
-
备份集群中的所有工作负载并将它们恢复到单独准备的灾难恢复(DR)集群;
-
备份所有工作负载,但选择性地恢复,即回滚源集群中的单个工作负载;
-
在一个命名空间中备份资源并将它们克隆到另一个命名空间中;
-
将工作负载从一个集群迁移或克隆到另一个集群;并且
-
更改特定工作负载的存储参数。例如,将工作负载从区域持久磁盘(PD)移动到区域 PD 或将存储提供程序从树内 PD 驱动程序更改为 CSI 驱动程序。
在这一点上值得注意,GKE 的备份不包括备份 GKE 集群配置信息,例如节点配置、节点池、初始集群大小和启用的功能。GKE 的恢复操作也不涉及创建集群。如果目标集群不存在,用户需要创建一个目标集群,并在任何恢复操作开始之前将 Backup for GKE 代理安装到该集群中。
D.3.4 展望未来
展望未来,Anthos 有可能使在混合和多云环境中管理和使用 Kubernetes 存储变得更加简单和自动化。以下是一些例子:
-
简化驱动器的部署:通过创建蓝图和更高层次的抽象,以方便存储供应商指定其 CSI 驱动器的部署;
-
引入一个驱动器市场:通过在谷歌云中提供一键部署,而不是要求用户跳出上下文到达存储供应商网站以检索 YAML 文件来部署驱动器。
D.4 由 Anthos 驱动的 BigQuery Omni
BigQuery,一个 PB 级规模的数据仓库,已成为用户访问谷歌不断增长的分析产品组合的平台,例如 Auto-ML 和 Tables。谷歌的 BigQuery 团队希望将这些相同的分析能力扩展到其他公有云上的数据,而无需要求客户将数据迁移或复制到谷歌云。无需移动数据即可分析其他云中驻留的数据,这定义了一个新的领域,被称为多云分析。
BigQuery Omni 扩展了 BigQuery 的能力,以分析驻留在多个云中的数据,无论是使用标准 SQL 还是使用 BigQuery 的所有交互式用户体验来对数据进行即席查询。从高层次来看,BigQuery 由两个完全解耦的组件组成:计算和存储。计算组件由一个非常健壮且无状态的查询引擎组成,在谷歌内部被称为Dremel,能够以非常高效的方式执行标准 SQL 查询。存储组件由一个高度可扩展、最优分区、密集压缩的基于列的数据存储引擎组成。这两个组件通过一组定义良好的 API 进行交互。这种解耦允许两个组件独立扩展。对于需要比分析更多数据的用例,存储扩展以适应数据大小。对于计算密集型的用例,计算相应扩展,而无需分配更多存储。
BigQuery Omni 工程团队面临着在谷歌内部“borg”基础设施之外运行这些组件的挑战。他们利用 Kubernetes 和“borg”的相似性,以及 Anthos 的多云支持来克服这些挑战。
BigQuery Omni 使用 Anthos GKE 作为管理软件,在公共云中与数据驻留的同一区域运行 Dremel 查询引擎。Dremel 在公共云中存储数据的 Google 管理账户上的 Anthos GKE 中部署、运行和操作。通过 Anthos,Google Cloud 能够推出 BigQuery Omni,这使得 Google Cloud 能够将其分析能力扩展到其他云中的数据,例如 AWS 和 Microsoft Azure。请参阅 此链接 以查看 BigQuery Omni 的演示。
需要注意的是,尽管 BigQuery Omni 利用 Anthos GKE 的强大功能,但用户并不必须成为 Anthos 的客户。在这种情况下,BigQuery Omni 工程团队是 Anthos 的客户,BigQuery Omni 用户不会直接与 Anthos GKE 交互。
如 图 D.3 BigQuery Omni 技术栈 所示,BigQuery Omni 引入了在 GCP 和其他公共云(如 AWS 和 Microsoft Azure)上运行 BigQuery 查询引擎 Dremel 的能力。架构组件分布如下。在 GCP 中,BigQuery 技术栈保持不变。从下到上,它包括通过 Petabit 网络连接到运行 Dremel 的 BigQuery 计算集群的 BigQuery 存储。为了临时存储和缓存中间查询结果,这些结果对于某些复杂分析可能达到千兆字节级别,Dremel 实现了一个分布式内存洗牌层。当在除 GCP 之外的公共云(例如 AWS)上运行时,而不是将数据从该云迁移到 Google 管理的 BigQuery 存储中,BigQuery Omni 在云的本地存储系统中执行分析。
在 BigQuery Omni 中,当用户执行查询以访问多云数据时,BigQuery 路由器会使用安全连接将查询直接路由到数据驻留处的 Dremel 引擎。必须授予 Dremel 工作负载访问公共云中驻留的数据的权限。查询结果可以直接导回到数据存储,无需跨云移动查询结果或用于查询的数据。BigQuery Omni 还支持将文件加载到“常规”BigQuery 中,以满足需要将驻留在 BigQuery 中的数据合并或使用 VertexAI 训练 ML 模型的用户。

图 D.3 BigQuery Omni 技术栈
D.4.1 授予 BigQuery 访问 AWS 中的数据
为了使 BigQuery Omni 能够在 AWS 上对驻留的数据进行查询,用户需要拥有 AWS 账户,并有权修改 S3 数据的标识符和访问管理(IAM)策略,以授予 BigQuery 访问权限。以下各节概述了与此过程相关的几个步骤。
创建 AWS IAM 角色和读取策略
用户必须首先创建一个 AWS IAM 角色和读取策略,以便为用户想要授予 BigQuery 访问权限的 S3 创建,然后将角色和政策一起附加。请参阅 Google Cloud BigQuery Omni 文档或 AWS 文档,获取执行这些任务的最新说明。
定义外部表
创建连接后,用户需要为存储在 S3 中的数据创建一个外部表定义。请参阅 Google Cloud BigQuery Omni 文档或 AWS 文档,获取执行这些任务的最新说明。
D.4.2 利用 BigQuery 存储设计优化
BigQuery 的可扩展性和高性能源于一系列相互增强的设计选择。例如,为了优化查询分析,BigQuery 存储引擎以 列式格式存储数据,并对数据进行分区和聚类以减少查询的搜索空间。如果远程数据没有以相同的方式存储和组织,这可能会导致相对于在 Google Cloud 上运行 BigQuery 的性能有所下降。然而,能够使用 BigQuery 分析来解锁数据的价值,无论其现有格式和位置如何,且无需进行任何迁移工作,这可能是一个可接受的权衡。
用户始终可以选择通过模拟 BigQuery 执行的一些技术方法来优化 BigQuery Omni 分析的数据,包括:
-
将数据转换为列式格式:使数据能够按列检索。在大多数用例中,分析查看列中的所有值,而不是对表中的行进行范围扫描。因此,如 Apache Parquet 这样的列式格式优化了列的检索,减少了分析过程中访问的数据量,从而提高了性能并降低了成本。
-
数据压缩:使从存储中检索的字节数更少。对于存储在列式格式中的数据,压缩可以利用列式条目非常重复或遵循模式的事实,例如连续数字的模式。Apache Parquet 使用 Google Snappy 来压缩列式数据。
-
数据分区:在搜索特定数据值时,使数据扫描更加高效。BigQuery 使用 Hive 分区。
D.4.3 BigQuery Omni 的差异化
BigQuery Omni 与其他分布式查询引擎(如 Presto)不同,它能够随着时间的推移,利用 Anthos 作为管理平台,不仅部署,还能监控、操作、更新和管理查询的整个生命周期。本质上,BigQuery 希望为用户提供一个多云故事。BigQuery 需要一个类似于 Google “borg” 的多云解决方案,以便 Dremel 能够在 AWS 和 Microsoft Azure 上几乎与在 Google Cloud 上一样工作。
BigQuery 查询引擎也运行在 GKE 环境中,充分利用了云原生部署的所有现代功能。
需要注意的是,也许历史上第一次,一个云服务提供商,在这个案例中是 Google,在云竞争对手的边界内部署了真正专有的和差异化的代码,即 Dremel。可以争论说,Google 已经在 AWS 和 MS Azure 上运行 GKE,这同样是专有代码。但在此案例中的关键区别在于,GKE 是一个管理容器的平台,这是一个今天所有云提供商都拥有的能力,而 Dremel 则掌握着大规模分析的关键,为 Google 用户带来了显著的价值。
最终,BigQuery Omni 为多云世界带来了一致的用户体验,通过一个统一的界面,对驻留在多个云中的数据进行数据分析,打破了之前围绕云边界的壁垒。通过 Anthos,BigQuery Omni 利用它作为安全的多云基础设施平台,为基础提供对驻留在其他云中的数据的分析。BigQuery 做所有这些事情,而不进行任何跨云数据移动,也不创建任何数据的副本。
D.4.4 Anthos 混合 AI
Google 是 AI 革命的先锋,并将其最前沿的 AI 技术融入了许多产品中,为用户提供了诸如在输入任何 Google 产品时自动完成等功能。Google Cloud AI 向用户提供了许多这些由 Google Cloud、Google 以及更广泛的 Alphabet 公司家族公司构思、孵化、实施并持续改进的行业领先 AI 技术。Google 继续吸引和培养顶尖的 AI 人才。最近,图灵奖,被认为是计算机领域的诺贝尔奖,授予了两位 Google 员工,以表彰他们在该领域的贡献。2017 年,David Patterson 因帮助开发了一种更快、功耗更低的微处理器方法而获得奖项,现在这种方法被用于 99% 的智能手机、平板电脑和许多物联网 (IoT) 设备中的微处理器。2018 年,Geoffrey Hinton 因奠定了深度神经网络的基础而获得奖项,这些神经网络推动了计算机视觉、语音识别和自然语言理解的重大进步。
然而,到目前为止,客户只能通过将数据移动到谷歌云来从这些技术进步中受益,由于包括安全、隐私和合规性在内的多个限制,许多企业无法满足这一要求。此外,即使部分数据可以移动到云端,由于本地没有相同的工具和 API,软件开发方面的任何学习都无法带回剩余的本地数据。
通过 Anthos,谷歌云推出了一项策略,让用户能够从谷歌在人工智能方面的进步中受益,而无需将数据移动到谷歌云。类似于 Anthos 在 BigQuery Omni 中使谷歌的 BigQuery 查询引擎 Dremel 在其他公有云上部署的情况,谷歌云混合人工智能利用 Anthos 在本地部署和运行谷歌的人工智能服务,靠近数据所在的位置。
D.4.5 混合人工智能架构
如图 D.4 混合人工智能技术栈所示,混合人工智能使得经过谷歌训练的相同人工智能模型能够在本地部署和运行,使得在云端使用的同一套人工智能 API 也能在本地使用,从而能够访问本地的数据集。

图 D.4 混合人工智能技术栈
混合人工智能的起点是用户已经在 GCP 上注册了一个或多个 Anthos 本地集群。通过 GCP 市场 place,用户可以搜索和发现谷歌云人工智能解决方案,例如下文将要解释的将语音转换为文本的解决方案。用户可以选择一个解决方案,并在本地 Anthos 集群上点击部署。这些人工智能解决方案被打包成 Anthos 应用,可以在任何 Anthos 集群上部署,包括在本地运行的集群。这些解决方案由 Anthos 完全管理,并享有所有 Anthos 功能,包括自动扩展,这保证了本地计算资源仅在需要时分配,并且只分配所需的资源。Anthos 对这些人工智能解决方案进行计量,并基于使用情况向客户收费。Anthos 混合人工智能允许人工智能应用程序动态地部署、运行和卸载。
D.4.6 混合人工智能解决方案
Anthos 混合人工智能的第一个版本在本地提供了以下谷歌云人工智能服务:
-
光学字符识别 (OCR):将文档转换为数字格式的文本;以及
-
语音转文本:将语音转换为文本,支持包括英语、法语、西班牙语、粤语和日语。谷歌云版本已经支持一百多种不同的语言和变体,使得轻松将额外的语言包含到本地版本中,由需求驱动。
下文将更详细地讨论这些用例。
光学字符识别
企业持有大量数据被囚禁在非数字化媒体中,如纸质文件,或者隐藏在不允许它们被轻松数字化分析的数据格式中。例如,发票或政府颁发的标题的扫描数字图像可能分别作为交易记录和所有权证明,但仍然非常具有挑战性,难以提取可以单独分析的单个信息片段。交易中涉及的实体的名称、日期、地点、价值以及交换物品的详细信息可能仍然隐藏在数字图像中。以前手动数字化这些信息并让人类输入数据的努力已被证明是易出错的、耗时的、成本高昂且难以扩展。
从这些文档中提取信息是全面分析数据的先决条件。一旦合同、专利、表格、发票、收据、PDF、图像以及许多其他形式的文档中持有的数据可以被分解成单个数字组件,它们就可以在规模上自动分析,并可能解锁前所未有的洞察。这些数据可能使企业能够更好地了解他们的客户、产品和服务、财务运营、内部流程、员工绩效以及他们业务的许多其他方面。用例涉及许多行业,包括:
-
药品行业:用于分析从实验室实验到临床试验的药物开发数据,数据来自多样化的数据源;
-
法律:用于信息发现;
-
保险:用于处理索赔,这可能包括分析图像和处理手写表格;
-
资产管理:用于分析保修和维护数据。
光学字符识别(OCR)包括从文档中提取单个信息片段并以自动化的方式将它们转换为数字格式。近年来,人工智能在自动化这一过程中取得了显著进步,严重依赖于卷积神经网络(CNN)模型,这些模型现在可以在大量数据上进行训练,并将巨大的准确性带给这一过程。待定:找到一些具体的例子和数据大小,以及准确度提高的情况添加在此。
虽然公共云在 OCR 技术方面取得了大多数进展,并以托管服务的形式提供,但这些文档的内容必须扫描并移动到云端进行处理。在许多情况下,这些文档中驻留的信息非常敏感,并且通常包含个人可识别信息(PII)。因此,企业不愿意承担将任何此类数据转移到云中的风险。混合人工智能使所有规模的组织都能够释放其本地数据的价值。混合人工智能不需要将数据移动到云端,而是将尖端分析移动到数据所在的位置。本质上,利用云人工智能技术,而无需被迫将数据和托管在云端。
语音转文本
无论是以纯音频记录的形式还是作为视频或实时对话中的音频流,语音都构成了另一种格式,其中有价值的信息仍然被困其中。语音识别的常见方法首先是将语音转换为文本,然后使用自然语言处理(NLP)来深入了解语音的语义。如今,企业拥有捕捉人与人之间以及人与机器之间交互的语音数据。例如,客户向客服中心的电话可能包括一个完全由机器辅助的初始部分,目的是收集关于问题的数据并更有效地将电话路由到可用的真人代理,以及一个客户与真人代理沟通以解决问题的第二部分。
与 OCR 类似,需要从语音转换为文本的数据可能需要保留在本地。这些录音不仅可能包含 PII 和敏感信息,而且可能在许多业务方面持有知识产权(IP),例如战略方向、产品发布、技术创新以及与人力资源相关的决策。
语音转文本的另一个挑战是与通信中使用的词汇。企业往往在谈话的上下文中存在差异,这些上下文往往特定于其行业、产品线以及内部使用的代号。因此,通用模型需要定制以更具上下文性和相关性,针对每个业务进行优化。
D.4.7 混合人工智能背后的差异化
混合 AI 引入了一种独特的方法来利用 Google Cloud AI 解决方案的最佳解决方案和技术进步,数据驻留得到保留,之前设计、开发、训练和测试的 AI 代码在数据所在的地方,即在本地,而不是强迫数据移动到云端。通过使用 Google 开发的 AI 模型,企业可以受益于经过优化的模型,这些模型运行所需的计算资源更少,设计并训练以提供更准确的结果,并且被设计成更小,消耗更少的资源。
通过使用 Anthos,混合 AI 为这些 AI 工作负载在本地运行带来了众多优势,减少了它们的生产时间,并使现代实践得以用于管理其整个生命周期。这些 AI 工作负载在本地 GKE 集群上运行,由 Anthos 管理,因此,它们可以享受所有 Anthos 功能,包括:
-
一键部署:AI 应用可以通过一键操作启动或终止,所有底层资源都会相应地动态分配或释放。在 AI 工作负载的情况下,这可能包括使用加速器,如 GPU,使组织能够利用任何现有的基础设施,并提高其利用率;
-
自动扩展:随着模型的训练、定制或用于推理,运行 AI 应用的集群会自动扩展和缩小,这极大地减少了与 AI 工作负载相关的运营工作量;
-
A/B 测试:可以轻松比较和对比新 AI 模型的表现;
-
金丝雀部署:新模型的分阶段部署可以大大减少在模型定制或再训练中引入的任何错误;
-
政策管理:AI 工程师可以通过声明性策略来管理这些模型的部署和运行;
-
生命周期管理:AI 模型可以受益于版本控制和一键升级模型部署;
-
指标日志记录和监控:AI 模型获得所有方面的可观察性,所有日志都发送到集中位置。状态可以自动监控,AI 模型可以使用与其他应用程序相同的框架和应用性能工具进行管理;
-
基于使用量的计费:AI 模型仅根据其使用量计费。
-
服务网格:可以利用预构建的 Istio 对象扩展到数千个连接;
-
市场:在这里可以轻松搜索和发现 AI 模型;
-
一致的持续集成/持续开发(CI/CD)流程:在本地和云端可以使用相同的流程;以及
-
单一视角:无论用户的 AI 工作负载运行在何处,用户都能获得相同的体验。
混合 AI 还为云和本地运行的所有 AI 工作负载提供一致和连贯的用户体验,使用户能够学习一套工具来管理 AI 应用程序的生命周期。此外,在 GKE 环境中运行 AI 工作负载,允许这些工作负载自动利用云原生部署的所有现代功能。
混合 AI 只是开始,所有规模的组织都可以将 AI 工具应用于本地数据,不仅定制和部署模型,还可以使用笔记本开发新模型,使用工具管理 AI 应用程序的生命周期,以及使用管道管理数据摄取、转换和存储。Anthos 还可以用于启用多种边缘处理类型,例如使用视觉识别进行图像或对象分类。未来,Anthos 还将支持在本地以相同方式部署第三方 AI 模型。在这种情况下,Anthos 可能还会执行第三方软件的二进制授权和漏洞扫描。
D.5 摘要
-
Anthos 和 GCP 为开发者提供可移植性和移动性,为超出无状态应用程序的工作负载提供持久存储,并为分析提供选项。
-
Anthos 致力于为数据工作负载提供严谨性,成为组件之间控制、安全、可观察性和通信的单层。
-
Anthos 在每个平台上管理第一方 CSI 驱动程序,并且 Anthos Ready Storage 计划认证来自行业领先存储合作伙伴的第三方驱动程序。
-
Anthos 将有状态应用程序从底层硬件的异构性中隔离出来,使有状态容器更具可移植性。
-
Anthos 支持广泛的存储系统,包括第一方和第三方,满足用户的需求,并允许他们利用现有的存储系统。
-
理解可移植性与移动性的区别 - 可移植性指的是在多个位置执行的能力,而移动性指的是将资源的地理位置从一地转移到另一地的能力。
-
Kubernetes 支持使用容器存储接口 (CSI) 进行存储,而 Anthos 则支持这一功能。
-
BigQuery Omni 可以在 GCP、AWS 上的 GKE 或 Microsoft Azure 上执行。这允许 BigQuery 查询引擎访问位于其他公共云上的客户数据,而无需移动任何数据。
-
Anthos 混合 AI 允许在本地部署和执行 Google 训练的模型,以满足数据驻留要求。
-
光学字符识别 (OCR) 将文档分解为数字格式,其中可以分析各个组件。
-
语音转文本将音频记录转换为文本,其中自然语言处理 (NLP) 可用于理解语音的语义。
附录 E.机器学习应用的端到端示例
Amita Kapoor
本章涵盖
-
为什么要在云中做机器学习?
-
何时在云中做机器学习?
-
如何在 Anthos 上使用 Kubeflow 构建机器学习管道?
-
理解 TensorFlow Extended
-
学习 Vertex AI 的功能
在前面的章节中,你已了解到 Anthos 以及如何将现有应用程序迁移到 Anthos 平台。本章将演示如何在多个云提供商和本地环境中运行端到端的机器学习工作负载。将深入讨论一个完全工作且生产就绪的项目。我们将使用 Anthos 平台上的 Kubeflow。
具体来说,本章将介绍机器学习管道中自动化的必要性、MLOps 的概念、TensorFlow 扩展和 Kubeflow。我们将学习如何在本地和云上使用 Kubeflow 来自动化机器学习管道,并以手写数字识别为例。最后,我们将探索 Vertex AI——一个完整的 MLOps 一站式商店。
E.1 MLOps 的必要性
云计算已经使机器学习世界民主化。计算资源如 GPU/TPUs 不再仅限于大型机构或组织;云使得它们对大众可及。你手机上的谷歌地图或你路上使用的谷歌翻译;两者都使用了在云上运行的机器学习算法。无论你是大型科技公司还是小型企业,将你的机器学习任务转移到云上可以让你利用云提供的弹性和可扩展性。你的系统资源不再限制你;此外,你还能从云服务提供商提供的专有工具中受益。
作为一名 AI/ML 科学家/工程师,我能听到你说云等是好的,但转移到云上很麻烦。你的观点也不是片面的;我们中许多人都在努力将我们的 AI/ML 模型部署到网络上。从 AI 研究到生产的旅程漫长且冗长,充满了许多障碍。从模型构建到模型部署再到分配网络资源,整个 AI/ML 工作负载都很繁琐——因为任何一步的改变都会导致其他步骤的改变。如图 E.1 所示,只有一小部分现实世界的机器学习系统与学习和预测相关;然而,它需要一个庞大而复杂的支持基础设施。问题因“改变任何东西都会改变一切”(CACE)而加剧,对超参数的微小调整、改变学习设置、修改数据选择方法——整个系统都需要改变。

图 E.1 机器学习系统的不同组件[1]
在 IT 行业,速度、可靠性和信息获取是成功的关键组成部分。无论你的公司从事哪个行业,都需要 IT 灵活性。当我们谈论基于 AI/ML 的解决方案和产品时,这一点变得更加重要。今天,大多数行业都是手动执行 ML 任务,导致在构建 ML 模型和其部署之间出现巨大的时间差距(图 E.2)。收集的数据被准备和处理(归一化、特征工程等),以便可以输入到模型中。模型被训练,然后根据各种指标和技术进行评估;一旦模型满足要求,它就会被发送到模型注册表,在那里它被容器化以供服务。
从数据分析到模型服务的每一步都是手动执行的,从一个步骤到另一个步骤的过渡也是手动的。数据科学家与运维团队分开工作;他们将训练好的模型交给开发团队,然后开发团队将其部署到他们的 API 基础设施中。这可能导致训练-服务偏差^([2])——即模型在训练期间和部署期间的性能差异。

图 E.2 机器学习工作流程[3]
此外,由于模型开发与其最终部署是分开的,因此发布迭代频率较低。此外,最大的障碍是缺乏主动性能监控。预测服务不跟踪或维护模型预测的日志,这些预测对于检测模型性能下降或行为漂移是必要的。理论上,如果模型很少改变或训练,这个手动过程可能是足够的。然而,在实践中,模型在现实世界部署时往往失败^([4])。
失败的原因是多方面的:
-
模型过时:随着时间的推移,模型的准确性下降,在经典的机器学习流程中,没有持续监控来检测模型性能的下降并纠正它。然而,最终用户却承受着痛苦。想象一下,你正在为一个时尚屋提供服务,根据客户的过去购买和时尚趋势建议新的服装设计。时尚随着时间的推移而急剧变化;在秋季流行的颜色在冬天就不再适用了。如果你的模型没有摄取最新的时尚数据并据此向客户提供推荐,客户会抱怨——访问网站的用户会减少,经过一段时间延迟后,业务团队会注意到,然后在确定问题后,你会被要求更新模型到最新数据。如果有一种持续监控模型性能的选项,并且有系统来对新获得的数据实施持续训练(图 3),这种情况是可以避免的。
![E_03]()
图 E.3 持续训练
-
数据漂移:训练数据集和测试数据集中输入特征与输出的联合分布之间的差异可能导致数据集漂移[2]。当模型部署时,现实世界的数据分布与训练数据集相同,但随着时间的推移,分布发生了变化。假设你基于当时可用的数据构建了一个用于检测网络入侵的模型。六个月过去了,你认为它还会像部署时那样高效吗?可能会,但可能性不大,因为随着时间的推移,模型可能会迅速偏离,在互联网世界中——六个月几乎相当于六代!如果有机会获取最近数据的指标切片,这个问题是可以解决的。
-
反馈循环:可能存在无意识的反馈,其中模型的预测最终影响了其自身的训练数据。例如,假设你为一家音乐流媒体公司工作,该公司使用一个基于用户过去收听历史和资料推荐新音乐专辑的系统。系统以超过 70%的置信度推荐专辑。公司决定为用户提供喜欢或不喜欢音乐专辑的功能。最初,你会感到非常高兴,因为推荐的专辑越来越受欢迎,但随着时间的推移,查看历史将影响那个模型预测,并且不知不觉中,系统会越来越多地推荐用户之前听过的类似音乐,而忽略了用户可能喜欢的新音乐。为了减轻这个问题,持续监控系统指标将是有帮助的。
-
要了解更多关于机器学习模型产生的技术债务,我建议读者阅读 Sculley 等人撰写的论文《机器学习:技术债务的高息信用卡》。在论文中,他们详细讨论了机器学习中的技术债务,以及使用 AI/ML 解决方案的系统相关的维护成本。
虽然消除技术债务是不可能的,甚至是不必要的,但整体方法可以减少债务。所需的是一个允许将标准 DevOps 管道与我们的机器学习工作流程集成的系统——即 ML 管道自动化:“MLOps”。让我们看看 Anthos 如何促进 MLOps。
-
在混合和多云环境中运行 AI/ML 应用程序:Anthos,一个托管的应用程序平台,允许您通过管理本地和云端的架构以及数据和安全模型来方便且高效地管理整个 AI/ML 产品生命周期。传统上,AI 工程师在不同的环境中开发机器学习代码,这些环境有不同的集群、依赖关系,甚至基础设施需求(例如,训练是计算密集型的,通常需要 GPU)。一旦模型完全训练完成,开发团队将其带入下一个阶段——部署和生产阶段的基础设施非常不同(部署可以在 CPU 上进行)。Anthos 提供的基础设施抽象提供了急需的可移植性;它允许用户高效且安全地构建和运行 AI/ML 应用程序。Anthos 的真正混合云架构让您可以在任何地方构建和部署代码,而无需进行任何更改。使用 Anthos 混合架构,您可以在本地和云端开发并运行一些代码块。Anthos 让您能够在混合和多云环境中构建、测试和运行您的 AI/ML 应用程序。
-
使用 Anthos GKE 管理 CPU/GPU 集群:使用 Anthos 进行您的 AI/ML 工作流程的另一个优点是 Anthos 提供的 GPU 支持。与全球最大的 GPU 制造商 NVIDIA 合作,Google 的 Anthos 使用 NVIDIA GPU 运营商来部署启用 Kubernetes 上 GPU 所需的 GPU 驱动程序。这为用户提供了一个广泛的 GPU 选择,如 V100、T4 和 P4 GPU。使用 Anthos,您因此可以轻松管理本地现有的 GPU,甚至支持您未来做出的任何 GPU 投资。如果您需要更多的计算资源,还可以将工作负载转移到集群中。因此,使用 Anthos GKE,您可以轻松管理本地和云端内的 GPU/CPU 集群。
-
使用 ASM 保护数据和模型:数据和模型的安全性至关重要。Anthos ASM 允许您配置整个工作环境的安全访问权限。关于 Anthos 服务网格的章节详细介绍了如何使用它来提供弹性、可扩展、安全和可管理的服务。
-
使用 Cloud Run 在云端部署 AI/ML:最后,可以直接在云运行上部署训练好的容器化模型,这是 Google 的无服务器容器即服务平台。
在接下来的章节中,我们将看到如何利用 Anthos 和 GCP 工具(如 CloudRun、TensorFlow Extend)以及操作编排工具(如 Kubeflow 和 Vertex AI),我们可以解决核心 MLOps 问题,如可移植性、可重复性、可组合性、敏捷性、版本控制和构建生产就绪的 AI/ML 解决方案。让我们首先从理解我们所说的完整机器学习管道自动化究竟是什么开始。
E.2 机器学习管道自动化
在上一节(图 E.2)中,我们详细介绍了从构思到生产交付机器学习(ML)项目的各个步骤。这些步骤中的每一个都可以手动完成或通过自动管道完成。在本节中,我们将探讨如何自动化这些步骤。这些步骤的自动化程度决定了训练新模型与部署之间的时间间隔,并有助于解决上一节中讨论的挑战。自动化的机器学习(ML)管道应该能够:
-
允许参与产品开发的各个团队独立工作。理想情况下,许多团队参与人工智能/机器学习(AI/ML)工作流程,从数据收集、数据摄入、模型开发到模型部署。如引言部分所述,任何一个团队的任何变化都会影响其他所有团队(CACE)。理想的机器学习(ML)管道自动化应该允许团队在各个组件上独立工作,而不受其他团队的干扰。
-
主动监控生产中的模型。构建模型并不是真正的挑战。真正的挑战在于保持模型在生产中的准确性。如果生产中的模型得到积极监控——维护日志并在模型性能低于阈值时生成触发器,这是可能的。这将允许你检测到性能的任何下降。这可以通过执行在线模型验证步骤来完成。
-
适应数据漂移,它应该随着新数据的到来而演进新的数据模式。这可以通过在生产管道中添加自动数据验证步骤来实现。任何数据模式(缺失特征或特征的不期望值)的偏差都应触发数据科学团队进行调查,而任何数据统计特性的重大变化都应触发重新训练模型的触发器。
-
在人工智能/机器学习领域,每周都会有新的模型架构出现,你可能对尝试最新的模型或调整超参数感兴趣。自动化的管道应该允许进行持续训练(CT)。当生产模型低于其性能阈值或观察到数据漂移时,CT 也变得必要。
-
此外,可重复性是人工智能领域的一个大问题,以至于顶级人工智能会议 NeurIPS 已经设立了可重复性主席^([6])。目标是研究人员提交可重复性清单,以便其他人能够重现结果。使用模块化组件不仅允许团队独立工作,而且在不影响其他团队的情况下进行更改。它允许团队将问题缩小到特定的组件,从而有助于可重复性。
-
最后,为了在生产级别实现快速且可靠的更新,应该有一个强大的持续集成/持续部署(CI/CD)系统。快速、可靠和安全地交付人工智能/机器学习(AI/ML)解决方案可以帮助提升您组织的性能。
-
在你将模型服务于实时流量之前,你可能还想进行 A/B 测试;你可以通过配置新模型服务于 10-20%的实时流量来实现。如果新模型的表现优于旧模型,你可以将所有流量都导向它;否则,回滚到旧模型。
从本质上讲,我们需要 MLOps - 将机器学习(ML)与 DevOps(Ops)相结合 - 一种统一的工程解决方案,它将机器学习系统开发和机器学习系统操作统一起来。这将允许数据科学家探索各种模型架构,实验特征工程技术和超参数,并将更改自动推送到部署阶段。下面的图 E.4 展示了机器学习 CI/CD 自动化管道的不同阶段。我们可以看到完整的自动化管道包含六个阶段:
-
开发/实验:在这个阶段,数据科学家迭代地尝试各种机器学习算法和架构。一旦满意,他们就会将模型的源代码推送到源代码仓库。
-
管道持续集成:这个阶段涉及构建源代码,识别并输出需要在后续阶段部署的包、可执行文件和工件。
-
管道持续交付:阶段 2 产生的工件被部署到目标环境。
-
持续训练:根据设置的触发器,训练好的模型在这个阶段被推送到模型注册库。
-
模型持续交付:在这个阶段,我们得到了一个已部署的模型预测服务。
-
监控:在这个阶段,收集模型性能统计数据并用于设置触发器以执行管道或执行新的实验周期。

图 E.4 自动化机器学习管道的阶段
在接下来的章节中,我们将介绍一些可以用于实现 MLOps 的 GCP 工具。我们将讨论 Cloud Run、TensorFlow Extend 和 Kubeflow。本章的重点将是 Kubeflow 和 Vertex AI。
在我们深入本章之前,我们应该参考一些重要概念:
-
Cloud Run,已在另一章节中介绍。如您所知,Cloud Run 是 Google 的无服务器容器即服务平台。Cloud Run 允许您在容器中运行整个应用程序。Cloud Run 可以用来部署任何无状态的 HTTP 容器。您只需指定一个包含所有依赖项以及您想要运行的机器学习预测代码的 Docker 文件,将它们打包成容器,然后,服务就部署在云端了。最近^([7]),Google 扩展了 Cloud Run 的功能,包括端到端 HTTP/2 连接、WebSocket 兼容性和双向 gRPC 流。因此,现在您可以使用 Cloud Run 部署和运行各种网络服务。虽然 Cloud Run 可扩展、弹性好,并且提供简单的 AI/ML 应用部署,但它也有一些限制。例如,可以请求的最大 vCPU 数量^([8])限制为 4(在撰写本书时,可以选择预览增加到 8vCPU 的选项)。
-
将 Cloud Run 与 Cloud Build 集成,您可以自动化整个流程,并快速为您的 AI/ML 工作流程实现 CI/CD。与 Cloud Build 相关的概念——GCP 原生的 CI/CD 平台——将在另一章节中介绍。Cloud Build 基于容器技术。有关容器注册和构建容器镜像的详细信息将在另一章节中介绍。
E.3 TensorFlow 扩展
TensorFlow 扩展 (TFX) 是一个可扩展的端到端平台,用于在 TensorFlow 中开发和部署 AI/ML 工作流程。TFX 包括用于数据验证、数据预处理、特征工程、构建和训练 AI/ML 模型、评估模型性能以及最终作为 REST 和 gRPC API 提供模型的库。您可以通过了解许多 Google 产品^([9]),如 Chrome、Google 搜索、邮件等,都是通过 TFX 驱动的来判断 TFX 的价值。Google 广泛使用 TFX,Airbnb、PayPal 和 Twitter 也同样如此。作为平台,TFX 使用各种库来实现端到端 ML 工作流程。让我们看看这些库以及它们能做什么:
-
TensorFlow 数据验证 (TFDV):这个库包含模块,允许您探索和验证您的数据。它允许您可视化模型训练和/或测试所使用的数据。它提供的统计摘要可以用来检测数据中存在的任何异常。它具有自动模式生成功能,允许您获取数据预期范围的描述。此外,当比较不同的实验和运行时,您还可以用它来识别数据漂移。
-
TensorFlow Transform (TFT):借助 TFT,您可以在规模上预处理您的数据。TFT 库提供的函数可用于分析数据、转换数据并执行高级特征工程任务。使用 TFT 的优势在于预处理步骤是模块化的。Apache Beam 和 Tensorflow 的混合体允许您处理整个数据集,例如获取最大值和最小值或所有可能的类别,并将数据批量作为张量进行操作。它使用 Google DataFlow 云服务。
-
TensorFlow Estimator 和 Keras:这是您可以使用来构建和训练模型的标准 TensorFlow 框架。它还为您提供了访问一系列预训练模型的机会。
-
TensorFlow 模型分析 (TFMA):它允许您在分布式方式下,使用您在训练时定义的相同模型评估指标,在大量数据上评估您的训练模型。它有助于分析和理解训练模型。
-
TensorFlow Serving (TFServing):最后,如果您对您的训练模型感到满意,您可以将模型作为 REST 和 gRPC API 在线提供服务。
下面的图示显示了不同的库如何集成形成一个基于 TFX 的 AI/ML 流程。

图 E.5 基于 TFX 的 AI/ML 流程[10]
虽然可以手动运行上述每个步骤,但正如我们在上一节中讨论的,对于 MLOps,我们希望这些步骤能够自动运行。为此,我们需要一个编排工具,一个将 ML 工作流程的这些不同块(组件)连接在一起的工具——这就是 KubeFlow 发挥作用的地方,它将是下一节的主题。
E.4 Kubeflow:简介
Kubeflow 允许您管理整个 AI/ML 生命周期。它是一个 Kubernetes 原生的 OSS(运营支持系统)平台,用于在混合和多云环境中开发、部署和管理可扩展的端到端机器学习工作负载。Kubeflow 流程,作为 Kubeflow 服务的一部分,帮助您自动化整个 AI/ML 生命周期——换句话说,让您能够组合、编排和自动化您的 AI/ML 工作负载。
这是一个开源项目,正如您从下面的提交图像中可以看到——它是一个活跃且不断发展的项目。Kubeflow 的主要目标之一,即构建 Kubeflow,是使每个人都能轻松地开发、部署和管理可移植、可扩展的机器学习。

图 E.6 如其在 Github (github.com/kubeflow/kubeflow/graphs/contributors) 仓库中所示,2021 年 2 月 4 日对 Kubeflow 项目的提交[10]。
最好的部分是,即使您对 Kubernetes 不太了解,也可以使用 Kubeflow API 构建您的 AI/ML 工作流程。您可以在本地机器上使用 Kubeflow,在任何云(GCP、Azure AWS)上,您可以选择单个节点或集群,它被构建成能够在各种环境中一致运行。2020 年 11 月,Google 发布了 Kubeflow 1.2 版本,允许组织在 Anthos 跨环境中运行他们的机器学习工作流程。Kubeflow 围绕以下三个关键原则构建:
-
可组合性:Kubeflow 扩展了 Kubernetes 的能力,使用机器学习特定框架(如 TensorFlow、PyTorch 等)和库(Scikit-Learn、Pandas 等)运行独立和可配置的步骤。这使得您可以为 AI/ML 工作流程中涉及的不同任务使用各种库,例如,在进行数据处理步骤时,您可能需要 TensorFlow 的不同版本,而在训练期间,您可能使用的是不同版本。因此,AI/ML 工作流程中的每个任务都可以独立容器化并处理。
-
可移植性:您可以在任何您想要的地方运行 AI/ML 工作流程的所有部分——在云上、在本地,或者在度假时在您的笔记本电脑上——唯一条件是它们都在运行 Kubeflow。Kubeflow 在您的 AI/ML 项目和系统之间创建了一个抽象层,从而使得在 Kubeflow 安装的地方运行 ML 项目成为可能。
-
可伸缩性:当您需要更多资源时,可以拥有它们,当不需要时,可以释放它们。Kubeflow 扩展了 Kubernetes 的能力,以最大化可用资源,并以尽可能少的手动努力进行扩展。
在本节中,我们将学习如何在 Anthos 提供的云原生生态系统中使用 Kubeflow,该系统在 Kubernetes 上运行。使用 Kubeflow 的一些优势:
-
标准化通用基础设施
-
利用开源云原生生态系统实现整个 AI/ML 生命周期的开发、编排、部署和运行可伸缩和可移植的 AI/ML 工作负载。
-
在混合和多云环境中运行 AI/ML 工作流程。
-
此外,当在 GKE 上运行时,您可以利用 GKE 的企业级安全、日志记录、自动扩展和标识功能。
Kubeflow 向集群中添加了 CRDs(自定义资源定义)。Kubeflow 利用容器和 Kubernetes,因此可以在 Kubernetes 已经运行的地方使用,尤其是在使用 Anthos 和 GKE 的本地环境中。以下列出了一些 Kubeflow 应用程序和组件,可用于在 Kubernetes 之上安排您的机器学习工作流程:
-
Jupyter Notebook:对于人工智能/机器学习从业者来说,Jupyter 笔记本^([11])是快速数据分析的事实上工具。大多数数据科学项目都是从 Jupyter 笔记本开始的。它是现代云原生机器学习管道的起点。Kubeflow 笔记本允许您在本地运行实验,或者如果您想的话,可以取用数据、训练模型,甚至通过笔记本部署它。笔记本与基础设施的其他部分集成良好,例如使用集群 IP 地址访问 Kubeflow 集群中的其他服务。它还与访问控制和身份验证集成。Kubeflow 允许用户设置多个笔记本服务器,每个服务器可以运行多个笔记本。每个笔记本服务器属于一个单独的命名空间,具体取决于该服务器的项目或团队。Kubeflow 通过命名空间提供多用户支持,这使得协作和管理访问权限变得更容易。在 Kubeflow 上使用笔记本允许您动态扩展资源。最好的部分是,它包含了您在 Jupyter 中训练模型可能需要的所有插件/依赖项,包括 TensorBoard 可视化以及您可能需要的自定义计算资源。Kubeflow 笔记本在本地提供与 Jupyter Notebook 相同的体验,并增加了可扩展性、访问控制、协作以及直接提交作业到 Kubernetes 集群的额外好处。
-
Kubeflow UI:一个用于运行管道、创建和启动实验、探索图、配置和管道输出的用户界面,甚至可以安排运行。
-
Katib:超参数调优是人工智能/机器学习工作流程中的关键步骤。找到合适的超参数空间可能需要大量努力。Katib 支持超参数调优、早期停止和神经网络架构搜索。它帮助用户在选择的指标周围找到最佳的生产配置。
-
KubeFlow Pipelines:Kubeflow 管道允许您构建一系列步骤,从收集数据到部署训练好的模型。它是基于容器的,因此每个步骤都是可移植和可扩展的。您可以使用 Kubeflow 管道编排端到端的机器学习工作流程。
-
元数据:它有助于跟踪和管理人工智能/机器学习工作流程产生的元数据。这种元数据记录可用于实时评估模型。它可以帮助识别数据漂移或训练-服务偏差。它还可以用于审计和合规性——您可以了解哪些模型在生产中以及它们的运行情况。元数据组件默认安装于 Kubeflow 中。许多 Kubeflow 组件会写入元数据服务器,此外,您还可以使用代码向元数据服务器写入。您可以使用 Kubeflow UI 通过工件存储查看元数据。
-
KFserving:它允许在任意框架上提供 AI/ML 模型。它包括自动缩放、网络和金丝雀发布等功能。它提供了一个易于使用的界面来在生产中提供模型。使用 YAML 文件,您可以配置用于提供和计算的资源。金丝雀发布允许您在不影响用户体验的情况下测试和更新您的模型。
-
Fairing:一个 Python 包,允许您在混合云环境中构建、训练和部署您的 AI/ML 模型。
总结来说,Kubeflow 提供了一套经过精心挑选的兼容工具和工件,这些工具和工件是运行生产级 AI/ML 应用的核心。它允许企业在整个机器学习生命周期中采用通用的建模基础设施。让我们深入了解 Kubeflow 包含的核心应用和组件集。
E.4.1 Kubeflow 深入探讨
到现在为止,您已经知道如何使用集群、应用程序、Anthos Service Mesh 和 Anthos Config Management 部署您的 Anthos 环境。您已经选择了项目并启用了服务管理 API。此外,请确保启用了 Istio ingress 网关服务以处理流量。这将用于 Anthos 服务网格向其入站流量添加更复杂的路由。要继续深入探讨,您需要安装 Kubeflow^([12])。由于 Kubeflow 使用 Kustomize^([13])来管理不同环境中的部署。因此,要在您的集群中使用 Kubeflow,首先要安装 Kustomize^([14])。
您可以使用 kubectl get all 命令验证集群上部署的所有 Kubeflow 资源,下面您可以查看 get all 命令的输出摘要:

图 E.7 kubectl get all 命令的输出
现在,让我们深入探讨 Kubeflow 的不同组件和功能。您还可以使用 Anthos Config Management 来安装和管理 Kubeflow^([15])。
最简单的方法是尝试来自 GCP Marketplace 的解决方案,如 MiniKF 或 Kubeflow pipelines。GCP 上的 AI 平台提供了一个简单的图形界面,用于创建集群并为您的 ML/AI 工作流程安装 kubeflow pipelines。只需点击三次,您就可以拥有一个可供使用的 kubeflow 集群。
E.4.2 Kubeflow 中央仪表板
就像所有其他 GCP 服务一样,Kubeflow 有一个中央仪表板,它提供了对您集群中安装的组件的快速概述。仪表板提供了一个酷炫的图形用户界面,您可以使用它来运行管道、创建和启动实验、探索图、配置以及管道的输出,甚至安排运行。
Kubeflow 中央仪表板可以通过以下模式的 URL 访问:
https://<KF_NAME>.endpoints.<project-id>.cloud.goog/
您还可以使用 Kubeflow 命令行 kubectl 访问 UI。您首先需要使用以下命令设置到 Istio 网关的端口转发^([16]):
kubectl port-forward -n <name_space> svc/istio-ingressgateway 8080:80
然后使用以下命令访问中央仪表板:
http://localhost:8080/
记住,你应该有一个受 IAP 保护的 web 应用程序用户角色才能访问 Kubeflow UI。此外,你应该已配置 Istio Ingress 以接受 HTTPS 流量。中心仪表板包括以下内容:
-
主页:用于在各个 Kubeflow 组件之间导航的中心仪表板。
-
管道
-
笔记本服务器
-
Katib
-
艺术品存储库
-
管理贡献者

图 E.8 使用 MiniKF 部署的 Kubeflow 中心仪表板
我们将在下一节中探讨这些组件。
E.4.3 Kubeflow 管道
Kubeflow 管道,Kubeflow 的一项服务,允许你编排你的 AI/ML 工作负载。它可以与 Kubeflow 一起安装或作为独立服务安装。GCP 市场提供了一个单点点击即可轻松安装 Kubeflow 管道的选项。正如我们前面所讨论的,构建 AI/ML 解决方案是一个迭代过程,因此以有序、组织的方式跟踪更改非常重要——跟踪更改、监控和版本控制可能具有挑战性。Kubeflow 管道通过为你提供易于组合、共享和可重复的 AI/ML 工作流程来简化此过程。Kubeflow 管道允许完全自动化模型的训练和调整过程。为此,Kubeflow 管道利用机器学习过程可以被分解成一系列标准步骤的事实,这些步骤可以以有向图的形式排列(图 E.8)。虽然过程看起来很简单,但使问题复杂化的是,它是一个迭代过程,AI 科学家需要尝试多种预处理、特征提取、模型类型等。每次这样的实验都会产生一个不同的训练模型,这些不同的训练模型在所选指标上的性能进行比较。然后,最佳模型被保存并部署到生产环境中。为了能够持续执行此操作,DevOps 需要基础设施足够灵活,以便多个实验可以在同一环境中共存。Kubeflow 通过 Kubeflow 管道实现了这一点。图 E.9 中的每个框都是一个作为 Docker 容器概念化的自包含代码。由于容器是可移植的,因此每个任务都继承了相同的可移植性。

图 E.9 将机器学习过程作为有向图
任务容器化提供了可移植性、可重复性和封装性。每个容器化任务都可以调用其他 GCP 服务,如 Dataflow、Dataproc 等。Kubeflow 管道中的每个任务都是一个自包含的代码,打包成 Docker 镜像,包含其输入(参数)和输出。这种任务的容器化——允许可移植性——因为它们是自包含的代码——你可以在任何地方运行它们。此外,你可以在另一个 AI/ML 管道中使用相同的任务——任务可以被重用。

图 E.10 Kubeflow 管道的示例图
Kubeflow 管道平台由五个主要元素组成:
-
一个用于创建、管理和跟踪实验、作业和运行的用户界面。
-
它在后台使用 Kubernetes 资源,并利用 Argo^([18]),在 Kubernetes 上编排可移植和可扩展的 ML 作业。
-
它提供了一个 Python SDK,用于定义和操作管道和组件。
-
Jupyter Notebooks,您可以使用 Python SDK 与系统交互。
-
以及 ML 元数据,它存储有关不同执行、模型、数据集使用和其他工件的信息,本质上是一种元数据日志。这种元数据日志允许您可视化度量输出并比较不同运行的结果。
Python SDK 允许用户通过代码描述管道,也可以使用 Kubeflow UI 可视化管道并查看不同的任务。将 ML 管道配置为容器化任务,以有向无环图(DAG)的形式排列,可以并行运行多个实验。此外,Kubeflow 允许用户重用预构建的代码,这节省了大量时间,因为无需重新发明轮子。GCP 还提供了 AI Hub,其中包含各种即插即用的可重用管道组件。图 E.9 展示了 Kubeflow 管道的示例图。
Kubeflow 使用领域特定语言(DSL)来描述您的管道和组件(图 E.10)。可以使用 kfp.dsl.pipeline 装饰器指定 Kubeflow 组件。它包含元数据字段,您可以在此处指定其名称和用途。组件的参数描述了该组件将接受哪些输入。函数的主体描述了组件中实际要执行的 Kubeflow 操作。这些操作是在任务运行时执行的 Docker 容器。

图 E.11 Kubeflow 组件的基本结构
Kubeflow 管道支持三种类型的组件:
-
预构建组件:这些是在 GitHub 仓库中可用的预构建组件:
github.com/kubeflow/pipelines/tree/master/components。这里提供了广泛的可用于不同平台的组件,从预处理、训练到部署机器学习模型。要使用它们,您只需要组件.yaml 的 URI,这是组件的描述。它包含容器镜像的 URI 和组件运行参数。这些参数传递给管道代码中的相应 Kubeflow 操作。其中一个预构建组件可以代表所有操作,如训练、调优和部署模型。 -
轻量级 Python 组件:如果你有小的 Python 函数,为每个函数编写完整的 Dockerfile 是没有意义的,Kubeflow SDK 允许你使用 func_to_container_op 辅助函数(在 kfp.components 中定义)将这些轻量级函数包装成 Kubeflow 组件。我们将函数作为输入传递给 func_to_container_op 和一个基础镜像。
-
自定义组件:如果我们用其他语言(例如 Go)编写了函数,可以使用自定义构建组件。在这种情况下,你需要编写描述组件行为的代码,创建容器的代码,以及代码的所有依赖项。
让我们通过一个简单的例子来演示如何创建 Kubeflow 组件。作为第一步,你需要将你的组件代码定义为独立的 Python 函数,例如,我们定义一个函数来乘以两个数字:
def mul_num(a: float, b: float) -> float:
return a*b
接下来,使用 kfp.components.create_from_func 生成组件规范 YAML。
mul_op = kfp.components.create_from_func(mul_num, output_component_file= ’mul.yaml’ )
YAML 文件是可重用的,也就是说,你可以与他人共享它,或者在其他 AI/ML 管道中重用它。现在你可以创建你的管道:
@kfp.dsl.pipeline(
name = ’multiply numbers’, description = ‘An example to show how to build Kubeflow pipeline’)
def mul_pipeline( a = 0.4, b = 0.2):
first_task = mul_op(a, 2)
second_task = mul_op(first_task,b)
最后,你可以使用 create_run_from_pipeline_func()创建一个管道运行。
E.4.4 使用 Katib 进行超参数调整
在 AI/ML 工作流程中找到合适的超参数非常重要。AI 科学家花费数小时甚至数天来寻找合适的超参数。这项工作涉及频繁的实验。这通常具有挑战性和耗时。我们可以使用前一个章节中描述的预构建组件之一来自动化超参数调整的过程,或者我们可以使用 Kubeflow 上的 Katib 来完成同样的工作。
Katib 是一个可扩展的 Kubernetes 原生 AutoML 平台,它允许进行超参数调整和神经网络架构搜索。图 E.12 显示了 Katib 的设计。要了解更多关于它的工作原理,读者应参考论文《Katib:基于 Kubernetes 的分布式通用 AutoML 平台》。

图 E.12 Katib 作为通用 AutoML 系统的设计[19]
Katib 允许你通过命令行(通过 YAML 文件规范)或使用 Jupyter Notebook 和 Python SDK 来定义超参数调整。它还提供了一个图形用户界面,你可以使用它来指定要调整的超参数并可视化结果。
图 E.13 显示了 Katib 的图形界面。

图 E.13 Katib 图形界面
Katib 允许你选择指标以及你是否想要最小化它或最大化它。你可以指定你想要调整的超参数。它允许你可视化整个实验的结果以及单个运行的结果。图 E.14 显示了以验证准确率作为指标,学习率、层数和优化器作为要调整的超参数的 Katib 运行结果。

图 E.14 Katib 生成的超参数调整结果
E.5 在 Kubeflow 上进行端到端机器学习
现在我们已经了解了 Kubeflow,是时候将其付诸实践了。我们将构建一个完整的管道,从数据摄取到使用 Kubeflow 的服务。由于本章的目的是讨论 Kubeflow,而不是 AI/ML 模型,我们将使用 MNIST 示例,并训练一个基本的模型来分类 MNIST 的手写数字,训练好的模型将部署在 Web 界面上。完整的代码可在仓库中找到:github.com/EnggSols/KubeFlow。为了保持简单和成本效益,我们将使用仅 CPU 的训练,我们将使用命令行 Kubeflow。
确保所有环境变量都已正确设置,并且已启用 GKE API。训练好的模型将存储在存储桶中。如果您还没有,可以使用 gsutil 创建一个:
gsutil mb gs://${BUCKET_NAME}/
这里 BUCKET_NAME 是整个 GCS 中的唯一名称。我们使用 model.py 文件进行训练;这是一段相当简单的代码。对于 Kubeflow 平台,程序在训练后将训练好的模型上传到指定的路径,几乎没有变化。
现在要在 Kubeflow 上执行训练,我们首先需要构建一个容器镜像,以下是我们将从 GitHub 仓库中使用的 Dockerfile:
FROM tensorflow/tensorflow:1.15.2-py3
ADD model.py /opt/model.py
RUN chmod +x /opt/model.py
ENTRYPOINT ["/usr/local/bin/python"]
CMD ["/opt/model.py"]
我们使用 docker build 命令来构建容器镜像。一旦构建完成,就将镜像推送到 Google 容器注册库,以便您可以在集群上运行它。在实际上传镜像之前,您可以使用 docker run 命令在本地检查模型是否确实正在运行:
docker run -it $IMAGE_PATH
您应该看到如图 14 所示的训练日志,这表明训练正在工作。

图 E.15 训练日志
如果您看到这个日志,这意味着您可以安全地将镜像推送到 GCS 注册库。现在镜像已推送,我们通过设置所需的训练参数来构建一个 Kustomize YAML 文件。
kustomize build .
图 E.16 显示了 Kustomize 构建命令的输出截图。

图 E.16 Kustomize 构建输出
最后,我们将这个 YAML 清单通过 kubectl 管道传递,这将在集群中部署训练作业。
kustomize build . | kubectl apply -f -
训练可能需要几分钟,在训练进行时,您可以检查存储桶以验证训练好的模型是否已上传。

图 E.17 云存储桶,您可以看到保存的模型在此列出
与之前一样,创建用于服务的 Kustomize 清单 YAML,并将模型部署到服务器。现在剩下的唯一步骤是运行 Web UI,您可以通过使用 Web 前端清单来完成此操作。建立端口转发,以便您可以直接访问集群并查看 Web UI:

图 E.18 已部署模型
您可以使用随机图像进行测试,端到端 MNIST 分类器已部署。
E.6 Vertex AI
Kubeflow 允许您编排 MLOps 工作流程,但仍然需要管理 Kubernetes 集群。更好的解决方案将是如果我们根本不需要担心集群的管理:介绍 Vertex AI Pipelines。Vertex AI 为机器学习工作流程的每一步提供工具:从管理数据集到不同方式的模型训练、评估、部署和预测。简而言之,Vertex AI 是 AI 需求的一站式商店。您可以在 Vertex AI 中使用 Kubeflow 管道或 TensorFlow 扩展管道。无论您是初学者,没有代码经验但有很好的想法使用 AI,还是经验丰富的 AI 工程师,Vertex AI 都有一些东西可以为您提供。作为一名初学者,您可以使用 Vertex AI 提供的 AutoML 功能,只需加载您的数据,使用 Vertex AI 提供的数据探索工具,然后使用 AutoML 训练模型。经验丰富的 AI 工程师可以构建自己的训练循环,在云上训练模型并使用端点进行部署。此外,您可以在本地训练模型,仅使用 Vertex AI 进行部署和监控。本质上,Vertex AI 为整个 AI/ML 工作流程提供了一个统一的接口(图 E.19)。

图 E.19 Vertex AI,完整的 AI/ML 工作流程统一接口
图 E.20 展示了 vertex AI 仪表板,在以下小节中,我们将探讨仪表板中的一些重要元素。

图 E.20 Vertex AI 仪表板
E.6.1 数据集
Vertex AI 支持四种类型的管理数据类型:图像、视频、文本和表格数据。下表列出了 vertex-managed 数据集支持的 AI/ML 任务。
| 数据类型 | 支持的任务 |
|---|---|
| 图像 | 图像分类(单标签)图像分类(多标签)图像目标检测图像分割 |
| 视频 | 视频动作识别视频分类视频目标跟踪 |
| 文本 | 文本分类(单标签)文本分类(多标签)文本实体提取文本情感分析 |
| 表格 | 回归分类预测 |
对于图像、视频和文本数据集,如果您没有标签,您可以直接从您的计算机上传文件。如果有包含图像 URI 及其标签的文件,您可以从您的计算机导入文件。此外,您还可以从 Google 云存储导入数据。请记住,上传的数据将使用 Google Cloud Storage 存储您从计算机上传的文件。对于表格数据,Vertex AI 仅支持 csv 文件;您可以从您的计算机、云存储上传 csv 文件,或从 BigQuery 导入表或视图。
一旦指定了数据,Vertex AI 允许您浏览和分析数据。如果数据未标记,您可以在浏览器本身上浏览数据并分配标签。此外,Vertex AI 允许您手动或自动进行测试-训练验证分割。图 E.21 显示了使用 vertex AI 管理数据集服务对泰坦尼克号生存数据集进行分析。
Vertex AI 还为您提供了一个功能存储选项,您可以使用它来分析数据的特征,它可以帮助缓解训练/服务偏差 - 确保训练和服务的特征数据分布相同。功能存储还可以帮助检测模型/数据漂移。如果需要数据标注服务 - 这也通过 Vertex AI 提供。
E.6.2 训练和实验
训练选项卡列出了您在 Vertex AI 平台上正在进行的和已经完成的全部训练作业。您还可以使用它来启动一个新的训练流程。整个过程非常直接;只需点击创建并遵循屏幕上的说明。如果您选择 AutoML,那么您可以选择用于训练的特征以及要忽略的特征;您还可以在表格数据选项卡上提及转换。还有一个选项可以选择目标函数。在做出所有选择后,只需决定您想要分配给训练的最大预算(最小为 1 小时)并开始训练。始终使用早期停止选项会更好,这样如果模型性能没有改进,训练就会停止(图 E.22)。
实验(Experiment)让您跟踪、可视化和比较机器学习实验,并与他人分享。

图 E.21 选择训练参数和转换

图 E.22 选择预算和早期停止
为了演示目的,我们使用了 HR 分析数据^([20]) 来预测数据科学家是否会进行工作变动。我们使用除了注册 ID 以外的所有数据进行模型训练。数据文件包含一个目标列,说明数据科学家是否在寻找工作。
E.6.3 模型和端点
所有训练模型的详细信息都提供在“模型”选项卡中。这些模型包括在测试数据集上对模型的评估(当使用托管数据集进行训练时)。不仅如此,在表格数据的情况下,还可以看到所有输入特征的特征重要性。这些信息以视觉和文本形式直接在仪表板上提供。
我们为模型训练设置了 1 个节点小时的预算。训练完成大约需要 1 小时 35 分钟。图 E.23 显示了 AutoML 在测试数据集上训练的模型评估,图 E.24 显示了相关的混淆矩阵。

图 E.23 在测试数据集上对模型的评估

图 E.24 混淆矩阵和特征重要性
可以直接从仪表板检查模型的预测。要测试模型,需要将模型部署到端点。Vertex AI 还提供了将模型(TensorFlow SavedModel 格式)保存到容器中的选项,您可以使用它来在其他本地或云服务中启动模型。让我们选择部署模型,点击“部署到端点”按钮。部署时,您需要选择以下选项:
-
为端点命名。
-
选择流量分配,对于单个模型是 100%,但如果您有多个模型,则可以分割流量。
-
选择最小计算节点数。
-
选择机器类型。
-
选择是否需要模型可解释性选项,对于表格数据,Vertex AI 提供了样本 Shapley 可解释性方法。
-
选择是否要监控模型的特征漂移、训练-服务偏差,并设置警报阈值。
部署完成后需要几分钟时间。现在我们已准备好测试预测(批量预测也受支持)。在图 E.25 中,您可以看到对于所选输入,数据科学家不寻求置信度为 0.67 的职位。可以使用 REST API 或通过 Python 客户端向模型发出样本请求。Vertex AI 端点包括用于样本请求的必要代码。

图 E.25 模型预测
您项目中的所有模型和端点分别列在“模型”和“端点”选项卡的仪表板中。
E.6.4 工作台
Vertex AI 通过工作台提供 JupyterLab 和笔记本支持。用户可以选择托管笔记本或自定义笔记本。托管笔记本包含所有流行的深度学习框架和模块,您还可以使用 Docker 镜像添加自己的 Jupyter Kernels。用户管理的笔记本提供广泛的基环境。用户在设置笔记本时可以选择 vCPUs 和 GPU。如果您想开始使用 Vertex AI,托管笔记本是个不错的选择;如果您想更好地控制环境,用户管理的笔记本是个好选择。一旦创建笔记本,点击“打开 JupyterLab”链接即可访问您的 Jupyter Lab 环境。

图 E.26 Google Cloud Console 中的托管笔记本
Vertex AI 工作台可用于进一步探索数据、构建和训练模型,以及作为 TFx 或 Kubeflow 管道的一部分运行代码。
E.6.5 Vertex AI- 最后的话
Vertex AI 提供了一个包含 AI/ML 工作流程所有组件的单个接口。您可以设置管道来训练模型并运行多个实验。该接口提供了一个简单的界面用于超参数调整。用户可以选择自定义训练,用户可以从容器中选择并直接在所选机器上加载他们的训练代码。为了加速机器学习工作流程,VertexAI 还集成了 AutoML。对于托管数据集,您可以使用 AutoML 功能获得一个高效的机器学习模型,而无需具备最低的机器学习专业知识。Vertex AI 还提供了使用特征归因对模型的可解释性。最后,当您的模型可用时,您可以设置批处理或单次预测的端点并部署您的模型。我在部署时发现的最重要功能是,您甚至可以在边缘设备上部署——将您的模型带到数据所在的地方。
E.7 摘要
-
现今的 AI/ML 工作流程引入了技术债务,这使得采用 MLOps 工具变得必要。
-
GCP 提供了各种 MLOps 解决方案,包括:Cloud Run、TensorFlow Extend 和 Kubeflow。本章深入探讨了 Kubeflow,这是在 Kubernetes 上编排您的机器学习工作流程的云原生解决方案。
-
Kubeflow 提供了一套经过精心挑选的兼容工具和工件,这些工具和工件是运行生产级 AI/ML 应用程序的核心。它允许企业在整个机器学习生命周期中标准化通用的建模基础设施。
-
Vertex AI 为整个 AI/ML 工作流程提供了一体化解决方案。Vertex AI 的功能通过在 HR 分析数据集上使用 AutoML 训练模型来展示。
E.7.1 参考文献
-
Sculley, David, Gary Holt, Daniel Golovin, Eugene Davydov, Todd Phillips, Dietmar Ebner, Vinay Chaudhary, Michael Young, Jean-Francois Crespo, 和 Dan Dennison. "机器学习系统中的隐藏技术债务。" 收录于《神经信息处理系统进展》,第 2503-2511 页。2015。
-
Quionero-Candela, Joaquin, Masashi Sugiyama, Anton Schwaighofer, 和 Neil D. Lawrence. 《机器学习中的数据集偏移》。麻省理工学院出版社,2009。
-
Sculley, David, Gary Holt, Daniel Golovin, Eugene Davydov, Todd Phillips, Dietmar Ebner, Vinay Chaudhary, 和 Michael Young. "机器学习:技术债务的高利率信用卡。" (2014).
-
周金南,等人。 "Katib:基于 Kubernetes 的分布式通用 AutoML 平台。" 2019 {USENIX} 操作机器学习会议 (OpML 19)。2019。
^([1]) 改编自 [1]
^([2]) developers.google.com/machine-learning/guides/rules-of-ml/#training-serving_skew
^([3]) 图片来源:cloud.google.com/solutions/machine-learning/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning
^([4]) www.forbes.com/sites/forbestechcouncil/2019/04/03/why-machine-learning-models-crash-and-burn-in-production/#64ca83e92f43
^([5]) thepoweroftwo.solutions/overview/
^([6]) www.wired.com/story/artificial-intelligence-confronts-reproducibility-crisis/
^([7]) cloud.google.com/blog/products/serverless/cloud-run-gets-websockets-http-2-and-grpc-bidirectional-streams
^([8]) cloud.google.com/run/quotas (在撰写本书时,增加至 8vCPUs 的选项作为预览版可用
^([9]) TF Dev Summit 2019: TensorFlow Extended Overview and Pre-Training Workflow
^([10]) 图片来源:cloud.google.com/solutions/machine-learning/architecture-for-mlops-using-tfx-kubeflow-pipelines-and-cloud-build
^([11]) www.altexsoft.com/blog/datascience/the-best-machine-learning-tools-experts-top-picks/
^([12]) 请参考 Kubeflow 文档以获取最新的安装说明:www.kubeflow.org/docs/started/installing-kubeflow/
^([13]) github.com/kubernetes-sigs/kustomize
^([14]) 请注意 Kustomize 的版本,Kubeflow 与 Kustomize 的后续版本不兼容,要了解最新状态,请参阅此 GitHub 问题:github.com/kubeflow/manifests/issues/538
^([15]) github.com/kubeflow/gcp-blueprints/blob/master/kubeflow/README.md#gitopswork-in-progress-using-anthos-config-managment-to-install-and-manage-kubeflow
^([16]) 请记住,并非所有 UI 都支持通过反向代理进行端口转发,这取决于您如何配置 Kubeflow。
^([17]) 这将授予访问应用程序和其他使用 IAP 的 HTTPS 资源的权限。
^([19]) 来自论文周金南等人撰写的 "Katib: A distributed general automl platform on kubernetes." 2019 {USENIX} Conference on Operational Machine Learning (OpML 19). 2019.
^([20]) www.kaggle.com/arashnic/hr-analytics-job-change-of-data-scientists?select=aug_train.csv
附录 F. 运行在 Windows 上的计算环境
Kaslin Fields
本章包括:
-
Windows 容器是什么以及它们与 Linux 容器有何不同
-
如何在 Anthos 和 GKE 集群上运行 Windows 容器。
-
在 Anthos 和 GKE Windows 环境中存储和网络独特的考虑因素。
F.1 Windows 容器
要理解 Windows 容器,首先需要建立对容器技术的理解。容器是运行应用程序的轻量级打包和隔离机制。与虚拟机方法虚拟化硬件堆栈不同,容器在操作系统级别进行虚拟化,多个容器直接在操作系统(OS)内核上运行。
从本质上讲,“容器”通常只是在其宿主操作系统上运行的一个进程或一组进程,其中包含一些关键工具来隔离该进程及其依赖项,使其与其他环境隔离开来。目标是使该运行进程安全隔离,同时从系统中占用最少的资源来执行隔离。
这引发了一个问题:如果容器基于操作系统内核级的能力,那么对于在具有完全不同内核的系统上运行的容器意味着什么?与 Windows 相比,Linux 中用于隔离进程以创建容器的工具通常归结为 cgroups 和 namespaces(以及其他一些工具),这些工具本身是集成到 Linux 内核中的。Linux cgroups 或“控制组”用于管理内存和 CPU 等资源,而 namespaces 通过将进程分组提供一定程度的隔离。对于 Windows 容器,微软实现了 Windows 内核的本地功能,以创建本地的“Windows Server 容器”。(微软还有一个名为“Hyper-V 容器”的概念,我们将在接下来的几段中更详细地探讨。)
容器的优势,无论是 Linux 还是 Windows 版本,包括:
-
提高可移植性和敏捷性
-
更快的部署和增强的开发者生产力
-
改进的扩展性和可靠性
-
容器将操作系统与应用程序代码中的依赖项解耦。由于应用程序代码和相关库被打包成一个单元,版本不一致性更少,你也不会遇到“在我的机器上它工作过”的问题。
Windows 容器的独特优势之一是它们可能有助于用户节省许可费用。作为一个专有操作系统,Windows 有许可费用,在运行操作系统副本时必须考虑。通过使用容器,应用程序可以隔离,而无需运行操作系统的完整副本。通过共享单个底层操作系统,Windows 容器用户可以在打包和隔离其应用程序的同时节省许可费用。图 F.1 比较了 VM 隔离应用程序的架构与容器隔离应用程序的架构。

图 F.1 说明了在节点上对多个容器进行装箱可能带来的潜在成本节约。
F.1.1 Windows 容器的两种运行时隔离模式
从 Windows Server 2016 开始,微软开始为 Windows 容器提供两种运行时隔离模式。进程隔离模式与 Linux 容器最相似,而 Hyper-V 隔离模式本质上是在一个非常轻量级的虚拟机上运行容器。Hyper-V 隔离容器旨在以类似于进程隔离容器的方式使用,但每个容器通过 Hyper-V 虚拟机而不是进程隔离来获取其内核,这与标准 Linux 容器不同。
进程隔离容器是在主机上运行的容器,它们与主机共享相同的内核,并通过资源控制、命名空间和其他进程隔离技术相互隔离。在这两种模式中,这是与原生 Linux 容器更相似的实施方式。Windows Server 容器提供了一个进程和资源隔离边界,因此可用于企业多租户。然而,由于微软表示他们不打算服务 Windows 容器逃逸漏洞,因此在敌对的多租户场景或需要不同风险水平的情况下不建议使用进程隔离容器。Kubernetes 在 2019 年春季发布的 1.14 版本中增加了对在 Windows Server 2019 节点上运行的 Windows Server 容器的支持。
Hyper-V 隔离容器在内核级别进行隔离 - 每个容器都拥有自己的内核并在虚拟机(VM)内部运行。这提供了更好的安全/隔离和主机与容器操作系统版本之间的兼容性。由于虚拟机/内核级别隔离的资源成本,它们通常占用更多资源,如 CPU 和内存,比进程隔离容器(Windows Server 容器)的占用更多。Hyper-V 容器的较高资源利用率和内核级别隔离使它们与原生 Linux 容器最不相似。截至撰写本文时,这些容器尚未由 Kubernetes 官方支持,因此 GKE 或 Anthos 也不支持。
由于 Kubernetes 目前不支持 Hyper-V 容器,因此从现在起所有关于 Windows 容器的讨论都将指代进程隔离的 Windows Server 容器。在本文本中,我们交替使用“Windows 容器”和“Windows Server 容器”这两个术语。
F.2 使用 Windows 容器
本节概述了使用 Windows 容器的用例和核心概念,包括适合 Windows 容器的良好工作负载、.NET 与 .NET Core 应用程序的探讨,以及 Windows 容器许可的详细信息。
F.2.1 适合 Windows 工作负载的良好候选者
适合 Windows 容器的应用程序包括:
-
基于 .NET Framework 3.5+ 的现有应用程序——N-Tier 应用程序、WCF 服务、Windows 服务等。
-
所有 ASP.NET 应用程序,包括 Web Forms、ASP.NET MVC、ASP.NET Web Pages、ASP.NET Web API 等。
-
IIS 7+ 应用程序,包括 ISAPI 过滤器和其他管道技术。
-
经典 ASP 应用程序。
-
任何没有 WinUI 依赖的控制台/批处理应用程序。
-
应用程序重构为基于云原生和微服务架构。
-
基于 .NET Core、.NET 5.0+ 或 ASP.NET Core 的新应用程序*。
基于 .NET Core、.NET 5.0+ 或 ASP.NET Core 的新应用程序具有跨平台兼容性,可以部署为 Linux 或 Windows 容器。
不适合 Windows 容器的应用程序:
-
带有可视化用户界面的 UI 应用程序。
-
使用 Microsoft 分布式事务协调器 (MSDTC) 的应用程序。
-
Windows 基础设施角色(DNS、DHCP、DC、NTP、PRINT、文件服务器、IAM 等)以及 Microsoft Office 不受支持。
要查看最新的限制集,请参阅 (docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/lift-shift-to-containers#applications-not-supported-by-containers)。
注意,现有的应用程序(包括单体和 N-Tier)不需要重新架构或重写,以利用容器化和现代化的好处。根据用例、业务需求和应用程序类型,有多种选项可供选择,其中一些选项不需要昂贵的重写或重新架构。以下部分将更详细地解释这一点。
F.2.2 .NET Core 与 .NET Framework 应用程序
现代化现有的 .NET Framework 应用程序有两种流行的选择——应用程序可以容器化到 Windows Server 容器中并在 Windows 节点上运行,或者应用程序可以移植到 .NET Core/.NET 5+ 并在 Linux 节点上作为 Linux 容器运行。这两种容器化 Windows 应用程序的过程在图 F.2 中进行了说明。

图 F.2 显示了将.NET 应用程序容器化的可能分支过程。可以直接在 Windows Server 操作系统上运行的 Windows Server 容器,或者应用程序可以被移植到.NET Core,以便在 Linux 操作系统上的容器中运行。
第一个选项(在 Windows 上运行 Windows Server 容器)允许用户通过一些部署更改获得显著的现代化好处。它不需要更改应用程序的代码或架构,因此是一个更简单的选项。用户可以使用 Docker 工具(例如,Image2Docker)、Visual Studio Docker 扩展或手动创建 docker 文件,然后使用 CLI 生成镜像。他们还可以使用 Migrate for Anthos 选项创建容器镜像,而无需接触应用程序代码。凭借 Windows 容器带来的 bin 打包和更好的资源利用,用户除了获得容器化带来的众多好处外,还可以节省许可和基础设施成本。
第二个选项(将应用程序移植到.NET Core/.NET 5+并使用 Linux 容器)需要前期投资,并且应用程序需要移植或重新架构/重写。然而,在初始的辛勤工作之后,应用程序运行时无需依赖 Windows Server 许可,从而在许可成本上节省了 100%。此外,与 Windows 容器相比,Linux 容器轻量且性能更佳。
两种选项的选择取决于用户及其业务目标和限制。假设用户需要运行相对较少的应用程序的大量副本(高可扩展性要求),在这种情况下,建议他们花费额外精力将他们的 Windows 应用程序完全重写以在 Linux 上运行,或者将它们移植到.NET Core/.NET 5+。前期的大量工作是为了更好的性能,并且消除了对 MS 许可的依赖。
相反,如果用户有几个遗留应用程序,将应用程序移植到.NET Core 或重写以在 Linux 上运行可能会很繁琐且痛苦。移植涉及非平凡的劳动和开发投资,并且由于依赖关系,可能无法转换某些应用程序。在这种情况下,在 Windows 主机上运行 Windows Server 容器是一个更受欢迎且更易于访问的选项——它通过一些轻量级的部署更改提供了显著的好处。
F.2.3 容器许可
目前,Kubernetes 支持两种 Windows 操作系统:Windows Server Standard 和 Windows Server Datacenter。这些操作系统对您可能运行的进程隔离 Windows 容器没有限制。Windows Server Standard 限制了您只能运行两个 Hyper-V 隔离容器,而 Windows Server Datacenter 则允许无限数量的 Hyper-V 隔离容器。
在撰写本文时,开源 Kubernetes 以及因此 GKE 仅支持进程隔离的 Windows 容器。因此,Kubernetes 集群可以包括运行任何支持进程隔离容器的 Windows Server Standard 或 Datacenter 版本的节点:Windows Server 2016、Windows Server 2019 或不久的将来,Windows Server 2022。
GKE 支持的 Windows Server 版本在“支持哪些 Windows 版本/类型”部分有更详细的说明。
一定要检查微软的资源,以获取最新的容器许可模式信息。(docs.microsoft.com/en-us/virtualization/windowscontainers/about/faq#how-are-containers-licensed--is-there-a-limit-to-the-number-of-containers-i-can-run)
F.2.4 Windows 容器基础镜像
当考虑如何在容器中运行你的.NET 应用程序时,你的第一步将是选择一个基础镜像来构建你的容器,这个镜像需要与你要运行的应用程序兼容。微软为用户提供了四个基础镜像,用于构建 Windows 容器:Windows Server Core、Windows Nano Server、Windows 和 Windows Server。大多数用例只需其中两个即可满足,即 Windows Server Core 和 Windows Nano Server。此外,你还可以在 Linux 容器中运行.NET Core 应用程序。图 F.3 展示了如何选择最适合.NET 应用程序需求的容器基础镜像。

图 F.3 展示了确定运行.NET 应用程序时应使用哪种类型的容器基础镜像的决策树。
Windows Nano Server 基础镜像 - 在 Windows 上运行的现代化或新开发的.NET 应用程序可能能够利用 Windows Nano Server 容器镜像。Windows Nano Server 镜像旨在轻量级和资源高效,提供与 Linux 容器基础镜像最相似的资源利用率。该环境具有比全功能的 Windows Server 操作系统更少的特性,但足以运行许多应用程序。这个镜像在四个原生 Windows 容器基础镜像中占用的空间最小。
Windows Server Core 基础镜像 - 对于可能之前在 Windows Server VM 上运行的遗留.NET 应用程序,Windows Server Core 基础镜像提供了一个更全面功能的类似 Windows Server 的环境。这是两个最常用基础镜像中较大的一个。与所有四个基础镜像相比,它是第二小的。
Windows 基础镜像 - 这是微软目前提供的容器基础镜像中最大的一个。它提供了完整的 Windows API,使您能够运行各种工作负载。然而,与使用其他基础镜像构建的运行相同应用程序的容器相比,您的容器将具有最大的资源利用率。该镜像适用于 Windows Server 2019 LTSC 和 SAC 版本。
Windows Server 基础镜像 - 这个基础镜像与之前提到的“Windows 基础”镜像类似,但没有设计上的限制,因为它被视为“Windows Server”类型的许可。这个基础镜像从 Windows Server 2022 开始可用。
Linux 容器中的 .NET 应用 - 另一个需要考虑的因素是在 Linux 上使用 .NET Core/.NET 5+ 运行 .NET 应用程序。这可以使您完全避免 Windows 许可费用,但要求应用程序被编写或重写以使用 .NET Core/.NET 5+。在这种情况下,应用程序将能够使用 Linux 容器运行,因此可以使用许多可用的 Linux 容器基础镜像之一进行构建。
F.3 Windows 容器与 Linux 容器的不同之处
Windows 容器和 Linux 容器都是打包和隔离机制,在 Windows Server 容器的情况下,它们在共享底层内核的同时运行应用程序。由于这些概念的实施是针对 Windows 和 Linux 内核的独特,因此它们之间会有许多差异是有道理的。当您探索容器资源时,您可能会发现世界上大多数“容器”信息都是针对 Linux 容器的,并且通常没有明确指出这个假设。本节突出了 Linux 和 Windows 容器之间的重要差异,这应该有助于您识别对 Windows 用例有用的容器资源和产品。在您探索使用容器进行进程打包和隔离的世界时,请记住这些差异。
Windows 容器通常需要更多的资源。在原生 Windows 和 Linux 容器之间最常见的差异之一是,Windows 容器通常比它们的 Linux 对应物占用更多的资源。容器技术的一个常见好处是,容器提供“轻量级”、资源高效的隔离。这是一个相对判断,很大程度上取决于容器技术的实现以及您试图运行的应用程序。虽然正在运行的应用程序的大小是一个因素,但与 Linux 容器相比,Windows 容器平均资源利用率更高的另一个关键因素可以很大程度上归因于前一部分中讨论的两个可用的 Windows 容器基础镜像的设计,即 Windows Server Core 和 Windows Nano Server。
Windows 容器可用的基础镜像较少。作为一种专有技术,Windows Server 容器可用的基础镜像仅限于微软提供的“风味”,并基于其 Windows Server 操作系统。这与 Linux 容器从开源和专有来源可用的丰富基础镜像形成对比。
Windows 容器镜像的拉取时间通常较慢。Windows 容器的基础镜像通常比 Linux 容器的基础镜像大得多。因此,从存储库拉取 Windows 镜像通常需要更长的时间,因为镜像大小较大。
Linux 安全功能与 Windows 安全功能。以进程隔离模式运行的 Windows Server 容器在隔离级别上与 Linux 容器相似。尽管如此,一些特定于 Linux 系统和容器的安全功能,如 Seccomp 和 SELinux,在 Windows 中没有对应的功能。Windows 的 HostProcess 容器相当于 Linux 的特权容器,并提供对主机的特权访问——在基线策略中已禁用。请注意,截至编写时,HostProcess 容器通常不可用(Kubernetes v1.23 时的 beta 功能)。
RunAsUserName 等同于 Linux 的 RunAsUser,可以用来使用非默认用户运行容器。它可以取值如 ContainerAdministrator 和 ContainerUser。ContainerAdministrator 具有提升的权限,用于执行管理任务、安装服务和工具以及进行配置更改。遵循最小权限原则,除非需要管理员访问权限,否则建议以 ContainerUser 运行容器。
如果用例需要运行敌对的多租户工作负载,即至少有一个工作负载是不可信的,则不建议在同一集群中运行具有进程隔离的 Windows Server 容器。
此外,Linux 在处理文件路径、文件权限、信号、身份等方面与 Windows 处理这些方面的方式存在一些差异。例如,Windows 在文件路径中使用反斜杠而不是正斜杠。了解这些差异是有好处的。更多信息请参阅(kubernetes.io/docs/setup/production-environment/windows/_print/#compatibility-linux-similarities)。
F.4 Anthos 和 Google Kubernetes Engine (GKE) 集群上的 Windows 容器
本节探讨了运行 Windows 工作负载的 Anthos 和 GKE 集群的架构和考虑因素。这两种类型的集群在架构方面有相当大的重叠,因此它们是相互关联地解释的。具有一些独特考虑因素的 On-Prem Anthos 集群将在本节稍后单独说明。通常,最好的学习方式是亲自尝试,因此在本节中,您将找到一个动手教程,指导您创建 Windows 容器并将其部署到 Kubernetes 上,通过 GKE 集群。对于在非 GCP 环境中运行的 Anthos 集群,过程将类似,尽管工具略有不同。
F.4.1 带有 Windows 节点池的 Anthos 和 Google Kubernetes Engine (GKE)集群的架构
在大规模运行容器时,需要一个容器编排工具。迄今为止,最受欢迎的容器编排工具是 Kubernetes。Anthos 管理的 Kubernetes 集群可以在各种环境中运行,无论它们在哪里运行,它们主要基于 GKE 集群的架构。务必查看本书中关于基于 Kubernetes 的计算环境的章节,以获得对 Google Kubernetes Engine 及其与 Anthos 之间关系的更全面概述。
本节提供了通过 GKE 或 Anthos 集群使用 Windows 节点池运行基于 Windows 容器的参考架构。

图 F.4 在同一集群中并排运行 Windows Server 和 Linux 容器的说明
图 F.4 说明了带有 Windows 节点池的 Anthos 或 GKE 集群的高级架构。绿色块代表继续使用 Linux 运行的托管主节点或控制平面,而黄色块代表工作节点池。Windows Server 节点池可以连接到现有的或新的 GKE 或 Anthos 集群,就像您添加 Linux 节点池一样。Linux 和 Windows 共享的控制平面是提供一致体验的关键因素。
单个集群可以使用不同的 Windows Server 版本拥有多个 Windows Server 节点池,但每个节点池只能使用一个 Windows Server 版本。标签用于将 Windows pod 引导到 Windows 节点。可以使用污点(Taints)和容忍度(Tolerations)来防止或排斥 Linux pod 在 Windows 节点上运行。Kubelet 和 Kube-proxy 在 Windows 节点上本地运行。整体架构允许您在同一个集群中无缝运行混合的 Windows 和 Linux 容器工作负载。
使用 Anthos 运行 Windows 工作负载的优点
现代化优势:使用 Kubernetes 容器化和运行 Windows 工作负载允许用户利用许多以前仅限于基于 Linux 应用程序的现代化优势。有众多优势,从更好的可伸缩性和可移植性到简化的管理和部署速度。
运营一致性:通过以一致的方式在 Windows 和 Linux 工作负载中并行运行,用户可以获得运营效率。您不再需要多个团队专门针对不同的工具或平台来管理不同类型的应用程序——您可以在 Windows 和 Linux 应用程序之间实现一致的运营。
成本节省:GKE/Anthos Windows 提供更好的二进制打包——通过在工作节点上以容器形式运行多个应用程序,用户可以获得更好的资源利用率,从而节省基础设施成本,更重要的是,您还可以从 Windows Server 许可证节省中获得好处。
支持的 Windows 版本/类型
在撰写本文时,GKE 和 Anthos 集群中的 Windows Node Pools 支持将 Windows Server 2019 LTSC(长期服务渠道)版本作为节点操作系统镜像。Windows Server 2022 的支持正在计划中。尽管 Windows Server 2016 中添加了对 Windows 容器的支持,但 Kubernetes 在 2019 年 3 月的 1.14 版本中提供了 Windows Server 容器的 GA 支持,使用的是 Windows Server 2019。因此,Windows Server 2016 不再受支持。
注意,GKE 之前也支持 Windows Server 的半年度渠道(SAC)版本;然而,从 Windows Server 2022 开始,Microsoft 弃用了 对 SAC 渠道的支持。
容器运行时有两个选项——Docker 和 containerd。容器运行时由 Kubernetes 节点用于启动和管理构成 Kubernetes Pod 的容器。containerd 支持在 2018 年由 Kubernetes 发布到开源社区,并显示出降低资源使用和提高启动延迟的效果。对于 2022 年及以后创建的 GKE 和 Anthos 集群,如果可用,强烈建议您使用 containerd 运行时(这是默认设置)。
容器基础操作系统版本与主机操作系统之间的兼容性
对于以进程隔离模式部署的 Windows Server 容器,容器的基础镜像的操作系统版本必须 匹配 主机的版本(如图 F.5 所示)。在四部分版本元组 - 主版本.minor.build.patch 中,前三个部分(即主版本、次要版本和构建版本)需要匹配。修补版本不需要匹配。
此限制不适用于在 Hyper-V 隔离模式下运行的 Windows Server 容器,版本可以不同。

图 F.5 Windows 容器版本必须共享容器元组的第三个值。例如,运行 Windows Server 版本 10.0.16299.1 的主机与运行版本 10.0.16299.0 的容器兼容,但相同的容器与运行版本 10.0.17134.0 的主机不兼容。
先决条件
-
即使是专门的 Windows 集群,GKE/Anthos 集群中也至少需要一个 Linux 节点,因为一些系统 Pod 只能在 Linux 节点上运行。
-
建议使用更大的机器类型来运行 Windows Server 容器:在 GCP 上,n1-standard-2 是最低推荐的机器类型,因为 Windows Server 节点需要额外的资源。不支持较小的机器类型 f1-micro 和 g1-small。
-
许可证:
-
在 GCP 云环境中,许可证已嵌入到虚拟机中。当用户将 Windows 虚拟机添加到他们的 GKE 或 Anthos 集群时,相应的许可证也会添加。这与客户在 GCE 中配置 Windows 虚拟机的方式相同。请查阅 Google Cloud 的计算磁盘镜像定价文档以获取最新信息和详细信息。
-
在 Anthos On-Premises 环境中,用户需要自行采购 Windows Server 许可证(BYOL - 带自己的许可证模式)。因此,用户需要从 Microsoft 下载 Windows Server ISO,或者根据 Microsoft 的许可条款使用公司定制的操作系统镜像。建议使用 Microsoft 的纯操作系统镜像。用户需要从 Windows Server ISO 创建一个基本的 Windows 虚拟机模板,该模板在向用户集群添加节点池时使用。
-
在 Google Cloud 和 GKE 上运行 Windows 容器(教程)
本节提供了一个动手教程,用于创建 Windows 容器并在 GKE 上运行它。它改编自以下“在 Google Cloud 上运行 Windows 容器”codelabs:
第一部分: codelabs.developers.google.com/codelabs/cloud-windows-containers-computeengine
第二部分: codelabs.developers.google.com/codelabs/cloud-windows-containers-kubernetesengine
设置和需求
本教程假设您有一个 Google Cloud Platform 项目用于工作。您可以使用现有的项目,或者创建一个新的项目。
第一部分:创建 Windows 容器
创建 Windows 虚拟机
为了创建一个 Windows 容器,您需要访问支持它们的 Windows 操作系统。首先,在 Google Cloud 上创建一个 Windows Server 实例,您将在该实例上创建您的 Windows 容器。您可以使用 gcloud cli 或控制台来完成此操作。在本节中,我们提供了在 Google Cloud 控制台上执行此操作的说明。
在 Google Cloud Platform 控制台中,转到计算引擎部分并创建一个实例。对于这个练习,选择如图 F.6 所示的 Windows Server 2019 Datacenter for Containers 作为引导磁盘的版本。

图 F.6 在 Google Cloud Platform (GCP) 上虚拟机创建工作流程的“引导磁盘”部分有一个“操作系统镜像”标签,您可以在其中选择您虚拟机的所需操作系统镜像。对于本教程,我们将使用“Windows Server 2019 Datacenter for Containers。”
确保此虚拟机的 HTTP 和 HTTPS 流量已启用,如图中所示。

图 F.7 在虚拟机创建工作流程的“防火墙”部分提供了两个必须勾选的复选框,以便进行本教程: “允许 HTTP 流量”和“允许 HTTPS 流量。”
选择如图 F.8 所示的“允许访问所有云 API 的完全访问权限。”

图 F.8 在虚拟机创建工作流程的“身份和 API 访问”部分的“访问范围”子部分中,选择“允许访问所有云 API 的完全访问权限。”
点击“创建”后,虚拟机启动需要几分钟。一旦虚拟机启动,您应该在控制台中看到您的虚拟机正在运行,如图 F.9 所示。

图 F.9 在 Google Cloud 中运行的虚拟机实例将显示虚拟机名称,名称右侧的行将显示附加信息,如区域和 IP。
通过远程桌面 (RDP) 登录到 Windows 虚拟机
要访问您创建的虚拟机,您需要配置一个密码。有两种方法可以做到这一点。您可以使用如图 F.10 所示的 RDP 按钮设置新的 Windows 密码:

图 F.10 点击如图中上一张图片所示的虚拟机信息中的“RDP”下拉菜单将提供设置 Windows 密码的选项。
或者,您可以点击“查看 gcloud 命令以重置密码”并运行显示的命令以设置密码。
几秒钟后,您应该在控制台或 Cloud Shell 中看到 Windows 密码。请确保您安全地记录下来。您将需要它来访问 Windows 虚拟机。
要登录到 Windows 虚拟机,您可以点击虚拟机的 RDP 按钮,如图中最后两张图片所示,这次点击“RDP”而不是下拉符号。
如果您愿意,您也可以使用自己的 RDP 客户端登录到虚拟机。
一旦进入虚拟机,以管理员模式打开一个命令提示符。默认安装了 Docker 和 Windows Server Core 基础镜像,您可以通过运行如图 F.11 所示的“docker images”来确认。

图 F.11 在创建的 Windows 虚拟机的命令提示符中运行“docker images”将提供输出,显示 Windows Server Core 基础镜像已经安装。
创建一个用于容器化的应用程序
对于 Windows 容器内的应用程序,我们将使用 IIS Web 服务器。IIS 为 Windows Server 2019 提供了一个镜像。直接使用这个镜像将允许我们提供默认的 IIS 页面。让我们配置 IIS 以提供自定义页面。
创建一个名为 my-windows app 的文件夹,其文件夹和文件结构如下:
C:\my-windows-app>dir /s /b
C:\my-windows-app\content
C:\my-windows-app\Dockerfile
C:\my-windows-app\content\index.xhtml
将 index.xhtml 替换为以下内容:
<html>
<head>
<title>Windows containers</title>
</head>
<body>
<p>Windows containers are cool!</p>
</body>
</html>
这是 IIS 将提供的页面。
使用 Docker 构建容器镜像
要使用 Docker 容器化此 IIS Web 服务器应用程序,你需要创建一个名为 Dockerfile 的文件。Dockerfile 包含几个关键命令,这些命令本质上指导 Docker 如何创建一个容器镜像来运行你的应用程序。
创建一个名为“Dockerfile”的文件,没有文件扩展名,包含以下行:
FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
RUN powershell -NoProfile -Command Remove-Item -Recurse C:\inetpub\wwwroot\*
WORKDIR /inetpub/wwwroot
COPY content/ .
构建 Docker 镜像,并使用 Google 容器注册库(GCR)和你的项目 ID 进行标记。这将在我们稍后推送镜像到 GCR 时很有用。运行以下命令,将[project id]替换为你的项目 ID。
docker build -t gcr.io/[project id]/iis-site-windows .
一旦 docker 镜像构建完成,你可以通过运行“docker images”看到它及其 IIS 依赖项。
运行 Windows 容器
在运行容器之前,你可能需要从虚拟机实例中打开端口 80。在 Windows 虚拟机内的命令提示符中运行以下命令:
C:\>netsh advfirewall firewall add rule name="TCP Port 80" dir=in action=allow protocol=TCP localport=80
C:\>netsh advfirewall firewall add rule name="TCP Port 80" dir=out action=allow protocol=TCP localport=80
你现在应该准备好运行 Windows 容器了。要运行容器并在端口 80 上公开它,请执行以下命令,将[project id]替换为你的项目 ID。
docker run -d -p 80:80 gcr.io/[project id]/iis-site-windows
通过运行命令 docker ps 确认容器现在正在运行。
要查看网页,请转到计算引擎实例的外部 IP 列,并在浏览器中简单地使用 HTTP 打开它。它应该类似于图 F.12。

图 F.12 将你的工作负载的外部 IP 输入到浏览器中应该会打开一个宣称“Windows 容器很酷!”的网站
你现在已经在 Windows 容器内运行了一个 IIS 网站!
注意,这个设置对于生产环境来说并不理想。它不能在服务器重启或崩溃时存活。在一个生产系统中,你希望为你的虚拟机获取一个静态 IP,并有一个启动脚本来启动容器。这将处理服务器重启,但对于服务器崩溃帮助不大。
要使应用程序能够抵御服务器崩溃,你可以在由 Kubernetes 管理的 pod 内运行容器。这就是第二部分你要做的事情。
第二部分:在 GKE 上运行 Windows 容器
将容器镜像推送到 Google 容器注册库(GCR)
要使第一部分中创建的容器镜像在 GKE 中可用,你需要将其托管在镜像仓库中。我们将为此目的使用 Google 容器注册库。
要将容器镜像从 Windows 虚拟机推送到 GCR,你需要:
-
确保你的项目中启用了容器注册库 API。
-
配置 Docker 以指向 GCR。
首先,确保通过在具有管理员权限的 Windows VM 命令提示符中运行以下 gcloud 命令来启用 Container Registry API:
gcloud services enable containerregistry.googleapis.com
通过运行以下命令配置 Docker 以指向 GCR:
gcloud auth configure-docker
当你被询问是否继续时,输入“Y”。
要将镜像推送到 GCR,请运行以下 docker 命令,将 [项目 ID] 替换为你的项目 ID:
docker push gcr.io/[project id]/iis-site-windows
如果你转到云控制台的 GCR 部分,你应该能看到镜像,如图 F.13 所示。

图 F.13 在 Google Cloud 中导航到容器注册表的镜像部分应显示有关 iis-site-windows 的信息。
创建具有 Windows 节点的 Kubernetes 集群
对于这个练习,你将创建一个区域 GKE 集群。这个集群将只包含单个区域内的节点,与具有多个控制平面和多个区域节点的区域 GKE 集群不同。
在创建 GKE 集群之前,请确保项目 ID 设置为你的项目,并设置 compute/zone 为你想要的区域(将 [项目 ID] 和 [首选区域] 替换为你首选的区域):
gcloud config set project [project id]
export ZONE=[preferred zone]
gcloud config set compute/zone ${ZONE}
在 GKE 中使用 Windows 节点创建 Kubernetes 集群分为 2 步:
-
创建具有 IP 别名和 1 个 Linux 节点的 GKE 集群。在将 Windows 节点添加到集群之前,至少需要 1 个 Linux 节点。
-
向 GKE 集群添加 Windows 节点池。
使用以下命令创建 GKE 集群。将 [集群名称] 替换为你想要的集群名称。
export CLUSTER_NAME=[cluster name]
gcloud container clusters create ${CLUSTER_NAME} \
--enable-ip-alias \
--num-nodes=2
一旦你的 GKE 集群启动,你可以向其中添加一个包含 Windows 节点的节点池:
gcloud container node-pools create windows-node-pool \
--cluster=${CLUSTER_NAME} \
--image-type=WINDOWS_LTSC \
--no-enable-autoupgrade \
--machine-type=n1-standard-2
注意,我们正在禁用自动节点升级。Windows 容器版本需要与节点操作系统版本兼容。为了避免意外的工作负载中断,建议用户禁用 Windows 节点池的节点自动升级。
对于 GKE 中的 Windows Server 容器,你已为底层的 Windows 主机 VM 获得了许可 - 容器不需要额外的许可。
为你的 GKE 集群配置 kubectl
你将使用 Kubernetes 命令行工具 kubectl 与你的集群交互。要配置 kubectl,请运行以下命令:
gcloud container clusters get-credentials ${CLUSTER_NAME}
在使用集群之前,等待几秒钟,直到 windows.config.common-webhooks.networking.gke.io 创建。此 webhook 为使用 kubernetes.io/os: windows(或 beta.kubernetes.io/os: windows)节点选择器创建的 Pods 添加调度容忍度,以确保它们可以在 Windows Server 节点上运行。它还验证 Pod,以确保它只使用在 Windows 上受支持的功能。
你可以通过使用以下命令输出 webhook 配置信息来确认已创建 webhook:
kubectl get mutatingwebhookconfigurations
在 GKE 中以 pod 的形式运行你的 Windows 容器
Kubernetes 对运行容器采用声明式方法。用户使用 yaml 文件定义他们希望的状态,Kubernetes 使用这些文件来创建和维护对象,以匹配期望状态。
要将您的 IIS 容器作为 Kubernetes 中的 pod 运行,您需要创建一个名为 iis-site-windows.yaml 的文件,包含以下行。请确保将[项目 ID]替换为您的项目 ID。
iis-site-windows.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: iis-site-windows
labels:
app: iis-site-windows
spec:
replicas: 2
selector:
matchLabels:
app: iis-site-windows
template:
metadata:
labels:
app: iis-site-windows
spec:
nodeSelector:
kubernetes.io/os: windows
containers:
- name: iis-site-windows
image: gcr.io/${PROJECT_ID}/iis-site-windows
ports:
- containerPort: 80
注意,此 yaml 将创建两个运行您之前发布到 GCR 的镜像的副本 pod。此 yaml 还确保您的 pod 将在带有 nodeSelector 标签的 Windows 节点上运行。
要创建 iis-site-windows.yaml 文件中定义的部署,请运行:
kubectl apply -f iis-site-windows.yaml
几分钟后,您应该看到创建的部署和正在运行的 pod。运行以下命令以确认:
kubectl get deployment,pods
您应该看到类似于图 F.14 的输出。

图 F.14 “kubectl get”命令用于显示 Kubernetes 对象的高级信息。在本例中,默认命名空间中的部署和 pod 被显示。
创建 Kubernetes 服务
您的应用程序现在正在 Kubernetes 中运行。为了确认 IIS 网站已启动,您需要创建一个 Kubernetes 服务,以便外部世界可以访问创建的 pod。
运行以下 kubectl 命令以创建一个类型为 LoadBalancer 的服务,可以用来访问您的 IIS Web 服务器。
kubectl expose deployment iis-site-windows --type="LoadBalancer"
您可以通过运行以下命令来确认服务是否启动:
kubectl get service
注意,服务启动并运行可能需要几分钟。一旦“kubectl get service”命令输出的“EXTERNAL-IP”部分被填充,您就可以访问该 IP 来查看 IIS 提供的页面。尽管是通过不同的 IP 访问,但网站应该与之前相同,如图 F.15 所示。

图 F.15 当您输入负载均衡器类型 Kubernetes 服务的外部 IP 时,应该显示一个宣称“Windows 容器很酷!”的网页。
当您进入负载均衡器类型 Kubernetes 服务的外部 IP 时,应该显示与第一部分中看到的相同的网页。现在最大的不同之处在于 Kubernetes 正在管理应用程序。如果运行应用程序的 pod 或 pod 所在的节点出现错误,Kubernetes 将为我们重新创建和重新调度 pod。这对于弹性来说非常好。
清理
一旦您完成了对在 GKE 上运行的容器化应用的探索,删除集群是一个好主意,以避免因闲置资源而产生额外费用。如果您完成了本教程中使用的资源,请按照以下步骤删除它们。
要清理您的环境,首先删除服务和部署。这将自动删除为该服务创建的外部负载均衡器:
kubectl delete service,deployment iis-site-windows
然后,删除您的 GKE 集群:
gcloud container clusters delete windows-cluster
您还应该删除用于创建 Windows 容器的虚拟机。
这可以在控制台或通过命令行完成。要通过 Google Cloud Console 删除虚拟机,请转到计算引擎虚拟机实例页面,并选择您要删除的虚拟机的“删除”菜单,如图 F.16 所示:

图 F.16 点击 VM 信息行最右侧的点,应该会提供通过 Google Cloud 控制台删除该 VM 的选项。
在 Anthos On-Premises 上运行 Windows 容器
在 Anthos 或 GKE 上运行 Windows 容器的用户体验在这两个平台上相当一致。然而,一些额外的设置和安装要求是针对本地环境中 Anthos 集群特定的,本节将突出这些要求。本地环境中的一般 Anthos 架构如图 F.17 所示。

图 F.17 Windows Server 和 Linux 容器在同一 Anthos 本地 VMware 集群中并行运行的示意图
在本地环境中,差异主要源于两个原因。首先,Anthos 用户必须在本地环境中获取他们的许可证(BYOL)。在 BYOL 模型中,Google 无法将 Windows Server 操作系统镜像与 Anthos 组件一起发货。因此,用户需要额外步骤从 Microsoft 下载 OS ISO 镜像,并为节点池创建创建 VM 模板。此外,当 Microsoft 为操作系统镜像发布安全补丁时,Google 将测试和验证最新的安全补丁版本,并发布结果。用户需要使用带有安全补丁的新 VM 模板,并在他们的 Windows 节点池上执行滚动更新。
第二,在 Anthos On VMware 环境中,管理员集群和底层 VMware 结构发挥作用,因此确保满足这些先决条件至关重要。Windows 节点仅支持作为用户集群工作节点运行,控制平面节点和管理集群节点继续基于 Linux。
具体来说,除了上述先决条件外,用户还需要确保以下事项:
-
在您创建 Windows 节点池之前,必须有一个管理员集群,因为 Windows 节点池仅支持在用户集群中。
-
vSphere 环境是 vSphere 6.7,更新 3 或更高版本。
-
具有 Windows 节点池的用户集群必须在用户集群配置文件中将 enabledataplanev2 字段设置为 true。这将在该集群的 Linux 节点上启用 Dataplane V2。另外,如果您希望 Windows 节点池中的 Windows Dataplane V2 被启用,用户集群配置文件中必须将 enableWindowsDataplaneV2 字段设置为 true。
将 Windows 节点池添加到 Anthos On-Prem 集群的高级步骤包括:
-
在 VMware 上为 Anthos 集群创建 Windows VM 模板。
-
如果使用私有注册表,将 Windows 容器镜像上传到私有注册表。
-
如果您的集群位于代理服务器后面,允许代理服务器 URL 列表。
-
将 Windows 节点池添加到用户集群配置文件中。
-
最后,创建 Windows 节点池。
一旦完成这些,您就可以像部署到 GKE 一样部署您的 Windows 容器。有关详细信息,请参阅 Google Cloud 文档页面“Windows Server OS 节点池用户指南”中的分步说明。
F.4.2 Anthos 和 Google Kubernetes Engine (GKE) Windows 环境的独特存储、网络和身份考虑因素
存储和网络对于在分布式计算环境中运行工作负载(如 Kubernetes 集群)至关重要。Kubernetes 以其在无状态工作负载领域的功能而闻名,但它也可以成为有状态工作负载的绝佳家园。Kubernetes 通过将容器连接在一起,无论是在单个机器内部还是在机器集群之间,涉及从硬件到各种软件级别的抽象层。本节探讨了 Anthos 和 GKE Windows 环境共有的存储和网络独特考虑因素。
F.4.3 存储
简而言之,Kubernetes 在 Windows 中管理存储的方式与 Linux 类似。包括树内和 CSI(在附录 Anthos、数据和 Analytics 中提及)的卷插件为存储供应商提供了一个抽象层,以支持为容器提供、附加和挂载存储。最终用户以与 Linux 相同的方式与持久卷(PV)、持久卷声明(PVC)和 StorageClass 对象交互。
Windows 存储限制
然而,与 Linux 相比,Windows 存储支持在撰写本文时有一些限制。以下列出了一些。(有关更多详细信息,请参阅文档)
-
Docker 运行时只能支持针对目录的卷挂载,而不是文件。然而,containerd 运行时不再有此限制,并且强烈建议使用 containerd 运行时而不是 Docker 运行时。
-
Windows 存储目前不支持以下功能
-
内存作为临时存储的存储介质。因此,如果您定义了一个 emptyDir 卷,您不能将其 emptyDir.medium 设置为内存
-
原始块卷(Windows 无法将原始块设备附加到 pods。)
-
支持双向传播的卷挂载
-
-
对于 Windows,支持只读卷,但不支持只读文件系统。
-
对于卷,不支持用户掩码和权限。权限而是在容器中解析。
Windows CSI 支持
在过去,存储供应商必须创建插件才能通过 Kubernetes 启用他们的存储。然而,存储插件被视为“树内”组件,这意味着它们必须成为核心 Kubernetes 代码的一部分才能使用。这种模式存在问题,因为它使 Kubernetes 的核心代码变得臃肿,并使存储供应商创建和维护插件的过程变得具有挑战性。
由于其缺陷和限制,插件系统在 Kubernetes 版本 1.13 时被替换,当时容器存储接口(CSI)成为通用可用(GA)。从那时起,存储提供商创建了与 CSI 兼容的插件,允许他们的用户通过 Kubernetes 消费存储。
Kubernetes 中的 Windows 支持是在 Kubernetes 版本 1.19 中引入的。然而,最初的版本不支持 HostProcess 容器(Linux 中特权容器的等效物),这是 CSI 卷插件部署为容器所必需的。截至 Kubernetes 1.22,HostProcess 容器支持目前处于 Alpha 阶段,Beta 版本计划与 Kubernetes 1.23 一起发布。
一个临时的解决方案是使用开源软件(OSS)项目 CSI-Proxy。CSI-proxy 提供了一种将节点插件作为非特权 pod 部署的机制,并使用代理在节点上执行特权存储操作。CSI Proxy API 包括磁盘、文件系统、SMB 和卷 API 组,这些在 2021 年毕业到 v1。它还包括 iSCSI 和系统 API,这些在撰写本文时仍处于 Alpha 阶段。
Anthos 旨在在各种环境中提供一致的经验。然而,并非所有环境都以相同的速度前进。请务必检查 Anthos 文档(cloud.google.com/anthos/docs/concepts/overview),以了解每个环境中可用的存储驱动程序类型。
Windows Google Cloud 存储驱动程序的实际应用
以下示例展示了在 Google Cloud 的 Anthos 中使用 StorageClass、PV/PVC 和 pod 访问持久存储的示例。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-gce-pd-windows
parameters:
type: pd-balanced
provisioner: pd.csi.storage.gke.io
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: podpvc-csi
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-gce-pd-windows
resources:
requests:
storage: 20Gi
---
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
tolerations:
- operator: Exists
nodeSelector:
kubernetes.io/os: windows
containers:
- name: web-server
imagePullPolicy: Always
image: k8s.gcr.io/e2e-test-images/agnhost:2.32
volumeMounts:
- mountPath: /www/html
name: mypvc
volumes:
- name: mypvc
persistentVolumeClaim:
claimName: podpvc-csi
readOnly: false
使用 SMB 在 Linux 和 Windows 之间共享数据
在 Linux 节点上运行的 pod 和在 Windows 节点上运行的 pod 之间需要共享数据的场景有几个。以下示例说明了可能需要数据共享的场景:
-
假设一个应用程序正在从 Windows 上的 .NET 框架迁移到 Linux 上的 .NET core,一些部分已经迁移,而应用程序的其他部分仍在使用 Windows 容器。
-
需要捕获由 Windows pod 编写的日志并将其发送到公共搜索和分析引擎,并且日志传输程序是用 Linux 编写的。
-
假设一个使用 Windows Server 容器运行的遗留 .NET 应用正在获得新功能,这些新功能作为在 Linux 上使用 .NET Core 运行的独立、新的微服务进行开发。让我们假设应用程序的旧部分和新部分针对同一个数据库进行操作。
在这种场景下,您可以使用服务器消息块(SMB)协议。SMB 是 Windows 用户最受欢迎的网络文件共享协议之一。CSI Windows 社区已启动一个开源 SMB CSI 驱动程序,并支持 Linux 和 Windows 集群。我们建议使用此驱动程序访问 SMB 卷,无论是自管理的 samba 服务器还是云卷服务(CVS)在 GKE 上。您可以检查 Google Cloud 文档,其中包含如何使用开源 SMB CSI 驱动程序访问 Google Kubernetes Engine(GKE)集群上 Windows 服务器节点的 NetApp Cloud Volumes Service SMB 卷的示例。
F.4.4 网络
与 Linux 网络一样,Windows 网络依赖于容器网络接口(CNI)将 Kubernetes pods 连接到集群网络。对于 GKE 和 Anthos,Windows 网络实现有两种模式:
-
基于 win-bridge(L2bridge 网络模式)的传统 Windows Dataplane
-
更新的基于 Open vSwitch(OVS)和 Antrea 的 Windows Dataplane V2
传统 Windows Dataplane
在 GKE 和 Anthos on-prem(在 VMware 上),使用 win-bridge 网络模式将 pods 连接到底层网络 - 它利用 Hyper-V 虚拟交换机(vSwitch)。GKE 和 Anthos on-prem(VMware)在跨节点连接性方面存在细微差异。
-
在 GKE 的 VPC 原生集群中,pods 使用辅助 IP 地址范围内的真实 VPC IP 地址,因此 pod IP 在 VPC 内是原生可路由的。跨不同节点的 pods 是原生支持的。
-
在 Anthos on-prem(在 VMware 上),没有 VPC 支持。Flannel 用于在 Windows 节点之间交换路由。Linux 节点上的 Dataplane v2 用于在 Linux 和 Windows 节点之间交换路由。
GKE/Anthos Windows Dataplane V2
更新的 Dataplane V2 是一个更可编程的 Dataplane,针对 Kubernetes 网络进行了优化,可以在不牺牲性能的情况下执行 Kubernetes 意识的包操作。虽然 Linux 的 Dataplane V2 基于 eBPF(扩展伯克利包过滤器)和 Cilium,但 Windows 解决方案基于 Open vSwitch 和 Antrea(一个实现 CNI 的开源项目)。
Dataplane V2 有助于克服传统实现的一些限制,并启用网络策略等特性。它向集群添加了新组件 - antrea-agent 和 antrea-controller。虽然 Antrea-agent 在每个节点上运行并编程 Open vSwitch 数据路径,但 Antrea-controller 在每个集群上运行一个实例。Antrea-controller 监视 Kubernetes API 服务器以获取更新,并为 antrea-agent 提供查询每个节点策略规则的 API。
GKE Dataplane V2 为所有 Anthos 和 GKE 环境提供一致的联网用户体验,提供网络活动的实时可见性,并具有更简单的架构,使得故障排除更加容易。此外,大多数新功能将仅支持 Dataplane V2。因此,强烈建议使用 Dataplane V2 进行容器联网。有关联网的更多详细信息,请参阅联网环境章节。
要使用 GKE Dataplane V2 创建新的集群,请使用以下命令:
gcloud container clusters create CLUSTER_NAME \
--enable-dataplane-v2 \
--enable-ip-alias \
--release-channel CHANNEL_NAME \
--region COMPUTE_REGION
F.4.5 活动目录集成
活动目录(AD)集成是 Windows 网络中最常用的身份验证和授权机制。活动目录在数据存储中跟踪网络中的对象,并使授权用户能够轻松发现和访问资源。Windows 容器不能直接加入域。尽管如此,您可以为在 Windows 容器中运行的应用程序配置和使用组托管服务帐户(gMSA)来利用 AD 功能。Anthos 和 GKE 支持组托管服务帐户——您可以在集群中配置 gMSA 凭证规范作为自定义资源。然后,Windows Pod 可以配置为使用 gMSA 来访问和交互其他资源和服务。有关更多详细信息,请参阅文档(cloud.google.com/kubernetes-engine/docs/how-to/creating-a-cluster-windows#using_gmsa)和教程。
F.5 摘要
-
与 Linux 容器一样,Windows 容器具有多项好处——更好的灵活性、改进的可伸缩性和可靠性,通过装箱节省成本等。
-
Windows 容器有两种运行时隔离模式——进程隔离和 Hyper-V 隔离。进程隔离模式更类似于原生 Linux 容器,而 Hyper-V 隔离提供了更多的安全性和隔离性,更适合敌对的多租户场景。
-
现代化现有.NET Framework 应用程序有两种流行的选择——应用程序可以被容器化到 Windows Server 容器中并在 Windows 节点上运行,或者应用程序可以被移植到.NET Core/.NET 5+并在 Linux 节点上作为 Linux 容器运行。
-
Anthos/GKE 允许您在同一集群中并行运行 Linux 和 Windows 容器,从而实现一致的用户体验和操作效率,以及其他多项好处。
-
对于以进程隔离模式部署的 Windows Server 容器,容器的基础镜像操作系统版本必须与主机版本匹配。
-
在不同的 Anthos 环境中运行 Windows 容器的体验相当一致。然而,也有一些需要考虑的差异,例如 Windows 节点的操作系统许可模式。
-
Kubernetes 在 Windows 中管理存储和网络的方式与 Linux 类似。卷插件(树内和 CSI)提供了一个抽象层,最终用户以与 Linux 相同的方式与持久卷(PVs)、持久卷声明(PVCs)和 StorageClass 对象交互。Windows 的传统数据平面基于 win-bridge,而较新的 Windows 数据平面 V2 基于 Open vSwitch (OVS) 和 Antrea。
-
Active Directory (AD) 集成是 Windows 基础网络中最常见的身份验证和授权方法。Anthos 和 GKE 支持基于 AD 的 gMSA。






























浙公网安备 33010602011771号