DevOps-工程师的谷歌云指南-全-
DevOps 工程师的谷歌云指南(全)
原文:
annas-archive.org/md5/45a4d079d9c890f75258e11a8461175f译者:飞龙
前言
本书是一本全面介绍站点可靠性工程(SRE)基础知识的指南,它是 Google 的 DevOps 方法论。此外,本书还深入探讨了 Google Cloud 中的一些关键服务,帮助实现持续集成/持续部署(CI/CD),并专注于通过 Kubernetes 实现容器化部署。本书还作为 Google Cloud Professional Cloud DevOps Engineer 认证的备考材料,包含基于章节的测试和模拟测试。
本书的适用人群
本书非常适合那些希望解决基于云的操作问题的云系统管理员和网络工程师。那些希望在 Google Cloud 服务管理领域提升职业发展的 IT 专业人士将从中受益。想要学习如何应用 SRE 原则,并专注于在Google Cloud Platform(GCP)中实施 DevOps 的用户也会受益。建议具备基本的云计算和 GCP 服务知识,了解 CI/CD,且有 Unix/Linux 基础架构的实践经验。那些有意通过 Professional Cloud DevOps Engineer 认证的读者将会发现本书非常有用。
专业云 DevOps 工程师认证具有一定的进阶性质。为了更好地准备此认证,建议先准备或通过 Associate Cloud Engineer 认证或 Professional Cloud Architect 认证。尽管这些认证不是 Professional Cloud DevOps Engineer 认证的前提条件,但它们有助于更好地准备并熟悉 GCP 上的服务。
本书内容简介
第一章,DevOps、SRE 和 Google Cloud 服务用于 CI/CD,讲解了 DevOps,它是一套可重复、迭代地构建、测试和发布代码的实践。这些实践旨在打破开发团队和运维团队之间的隐形壁垒。SRE 是 Google 推出的实施 DevOps 的规定方法,它使开发和运维团队的激励机制对齐,从而共同构建和维护可靠的系统。此外,Google 提倡一种云原生开发范式,在该范式中,复杂系统被分解为多个服务,采用微服务架构进行管理。
本章将涵盖的内容包括 DevOps 生命周期、SRE 的发展、关键技术和文化的 SRE 实践介绍,以及使用云原生开发范式的好处。本章还将介绍 GCP 上的服务,帮助实现云原生开发并应用 SRE 概念。
第二章,SRE 技术实践 – 深度剖析,讲述了可靠性,这是服务最关键的特性,应与业务目标保持一致。SRE 提出了特定的技术实践,用于衡量定义和跟踪可靠性的特征。这些技术实践包括服务级别协议(SLA)、服务级别目标(SLO)、服务级别指标(SLI)、错误预算以及通过自动化消除无意义工作。
本章深入探讨了 SRE 技术实践。内容将包括制定明确 SLA 的蓝图、通过 SLO 定义可靠性期望、理解可靠性目标及其影响、对用户旅程进行分类、衡量 SLI 的来源、通过跟踪错误预算探索提升服务可靠性的方法,以及通过自动化消除无意义工作。本章最后将通过两个场景展示 SLA、SLO 和错误预算的影响,相关于所测量的 SLI。
第三章,理解监控与告警以针对可靠性,讨论了实施 SRE 技术实践的关键在于确保 SLA、SLO 和 SLI 永不被违反。这样做可以实现平衡新功能发布和保持系统可靠性,因为错误预算不会被消耗殆尽。监控、告警和时间序列是跟踪 SRE 技术实践的基础概念。
本章深入探讨了监控、告警和时间序列。内容将包括监控来源、监控类型、监控策略、建议测量和监控的黄金信号、定义告警策略的潜在方法和关键属性,以及时间序列的结构和基数。
第四章,构建 SRE 团队并应用文化实践,讲述了 Google 长期以来如何将 SRE 视为确保系统可靠性的秘密武器,同时保持新功能发布的速度。Google 通过实施一套既定的文化实践,如事件管理、值班和心理安全,达成了这一目标。SRE 文化实践是实施 SRE 技术实践的必要条件,Google 强烈推荐希望开始 SRE 之旅的组织采纳这些文化实践。此外,Google 提出了建立 SRE 团队的关键因素,并提出了参与模型。
本章深入探讨了构建 SRE 团队,包括关于 SRE 团队不同实施方式、SRE 工程师的人员配置细节,以及 SRE 参与模式的见解。本章还将讨论 SRE 文化实践,其中包括有效的事件管理方面、值班时需要考虑的因素,以及促进心理安全需要克服的因素。本章最后介绍了一种旨在通过共享愿景和知识、促进协作来减少组织壁垒的文化实践。
第五章,使用云源代码库管理源代码,讨论了源代码管理是持续集成(CI)流程中的第一步。代码存储在源代码库中,例如 GitHub 或 Bitbucket,以便开发人员可以持续进行代码更改,并将修改后的代码集成到库中。云源代码库(CSR)是 Google Cloud 提供的服务,通过私人 Git 仓库提供源代码管理。
本章深入探讨了 CSR。本章将涵盖包括 CSR 关键特性、创建和访问仓库的步骤、如何将代码从 GitHub/Bitbucket 一次性同步到 CSR,以及 CSR 中的常见操作,如浏览仓库、执行通用代码搜索和检测安全密钥等内容。本章最后通过实践实验,展示了如何通过从 CSR 拉取代码将代码部署到云函数中。
第六章,使用 Cloud Build 构建代码并推送到容器注册表,讨论了代码检查到像 CSR 这样的源代码管理系统后,CI 流程中的下一个合逻辑步骤是构建代码、创建构建产物并推送到一个可以存储生成的构建产物的注册表。Cloud Build 是 Google Cloud 提供的服务,可以构建源代码,而容器注册表是存储创建的构建产物的目标位置。
本章深入探讨了 Cloud Build 和容器注册表。本章将涵盖包括理解自动化需求、构建和创建容器镜像的过程、Cloud Build 的关键要点、优化构建速度的策略、容器注册表的关键要点、容器注册表的结构以及容器分析等内容。本章最后通过实践实验,展示了如何使用 Cloud Build 触发器构建、创建、推送并将容器部署到 Cloud Run。本实验还展示了一种构建 CI/CD 管道的方法,因为它包括持续集成(CI)和将容器自动部署到 Cloud Run 的过程,Cloud Run 是一个运行容器的 GCP 计算选项。
第七章,理解 Kubernetes 基础以部署容器化应用程序,介绍了Kubernetes,或称K8s,它是一个开源的容器编排系统,能够运行容器化应用程序,但在设置和持续维护方面需要付出大量的努力。Kubernetes 起源于谷歌内部的集群管理工具;谷歌在 2014 年将其作为开源项目捐赠给了云原生计算基金会(CNCF)。
本章深入讲解了 K8s。内容涵盖 K8s 的关键特性,集群结构的详细说明,包括主控制平面组件、节点组件,Kubernetes 关键对象如 Pods、Deployments、StatefulSets、DaemonSet、Job、CronJob 和 Services,以及在调度 Pods 时需要考虑的关键因素。本章最后深入探讨 Kubernetes 中可能的部署策略,包括 Recreate、Rolling Update、Blue/Green 和 Canary。
第八章,理解 GKE 基础以部署容器化应用程序,介绍了Google Kubernetes Engine(GKE),它是 K8s 的托管版本;即一个开源的容器编排系统,用于自动化应用程序部署、扩展和集群管理。与创建集群和持续维护相比,GKE 需要更少的努力。
本章深入讲解了 GKE。内容包括 GKE 核心特性,如 GKE 节点池、GKE 集群配置、GKE 自动扩展、GKE 网络,包括 Pod 和服务的网络、GKE 存储选项,以及 GKE 的云操作。本章有两个实践实验。第一个实践实验位于本章开头,演示了使用标准模式创建集群、部署工作负载以及将 Pod 暴露为服务。本章最后有一个与第一个实验相似的实践实验,但集群创建模式是 Autopilot。
第九章,使用 GKE 安全构建保护集群,介绍了如何保护 Kubernetes 集群,这是部署过程中的一个关键部分。原生 Kubernetes 提供了一些基本的安全特性,重点关注如何验证和授权发送到集群的请求。理解如何保护主控制平面组件以及运行应用程序的 Pod 同样重要。此外,GKE 提供了对于增强集群安全性至关重要的安全功能。
本章深入讲解 GKE 安全功能。本章将涵盖 Kubernetes 中的基本安全模式、控制平面安全性和 Pod 安全性等内容。本章最后讨论 GKE 特有的安全功能,如 GKE 私有集群、容器优化操作系统、加固的 GKE 节点、通过网络策略限制 Pod 之间的流量、通过二进制授权部署时间安全服务,以及使用工作负载身份从 GKE 集群内部访问 GCP 服务。
第十章,探索 GCP 云操作,探讨了在应用程序部署后,DevOps 生命周期的下一个关键阶段是持续监控,因为它提供了一个反馈循环,以确保服务或系统的可靠性。如第二章,SRE 技术实践深入剖析中所讨论,SRE 推荐使用特定的技术工具或实践,帮助衡量定义和跟踪可靠性的特征,如 SLA、SLO、SLI 和错误预算。SRE 提倡使用可观察性来跟踪技术实践。在 GCP 上的可观察性是通过 Cloud Operations 实现的。
本章深入讲解 Cloud Operations。本章将涵盖 Cloud Monitoring 基础知识,包括工作空间、仪表板、Metrics Explorer、正常运行时间检查、配置警报、监控代理的需求,以及 Cloud Monitoring 特定的访问控制。 本章还将介绍 Cloud Logging 基础知识,包括审计日志及其分类、跨日志桶汇总日志特征、基于日志的度量、Cloud Logging 特定的访问控制、基于网络的日志类型,以及日志代理的使用。本章最后讨论与 Cloud Debugger、Cloud Trace 和 Cloud Profiler 相关的各种基础知识。
为了最大限度地发挥本书的作用
推荐你具备以下领域的基础知识,包括 Docker、Kubernetes 原生介绍、Git 的基本知识、Google Cloud 上的关键服务(如 Cloud Operations、计算服务)的实际操作经验,以及 Google Cloud SDK 或 Cloud Shell 的使用经验。此外,选择性编程语言(如 Python、Java 或 Node.js)的实践经验也将非常有帮助。然而,本书中的代码示例是使用 Python 编写的。

如果你正在使用本书的电子版,我们建议你自己输入代码,或通过 GitHub 仓库访问代码(链接将在下一部分提供)。这样做可以帮助你避免因复制和粘贴代码而导致的潜在错误。
无论你是否正在为专业云 DevOps 工程师认证而努力,建议在完成所有章节后尝试模拟考试。这将是评估从书中内容吸收的知识的一个好方法。
下载示例代码文件
本书的代码包也托管在 GitHub 上,网址为 github.com/PacktPublishing/Google-Cloud-Platform-for-DevOps-Engineers。如果代码有更新,它将在现有的 GitHub 仓库中更新。
我们还有其他来自我们丰富书籍和视频目录的代码包,欢迎访问 github.com/PacktPublishing/。快来看看吧!
下载彩色图像
我们还提供一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。你可以在此下载:www.packtpub.com/sites/default/files/downloads/9781839218019_ColorImages.pdf。
使用的约定
本书中使用了若干文本约定。
文本中的代码:表示文本中的代码词汇、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名。举个例子:“你可以使用 my-first-csr 仓库。”
一段代码设置如下:
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/builder-myimage', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/builder-myimage']
- name: 'gcr.io/cloud-builders/gcloud'
当我们希望引起你对代码块中特定部分的注意时,相关的行或项目会设置为粗体:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-vpa
任何命令行输入或输出均按以下方式书写:
gcloud builds submit --config <build-config-file> <source-code-path>
粗体:表示一个新术语、一个重要的单词或你在屏幕上看到的词语。例如,菜单或对话框中的词语会像这样出现在文本中。举个例子:“在 GCP 中导航到源代码库,并选择开始使用选项。”
提示或重要注意事项
如此显示。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果你对本书的任何方面有疑问,请在邮件的主题中提到书名,并通过 customercare@packtpub.com 与我们联系。
勘误:虽然我们已尽最大努力确保内容的准确性,但错误还是难免发生。如果你发现本书中的错误,我们将感激你向我们报告。请访问 www.packtpub.com/support/errata,选择你的书籍,点击“勘误提交表单”链接,并输入详细信息。
盗版:如果你在互联网上发现任何我们作品的非法副本,无论其形式如何,我们将不胜感激如果你能提供该副本的地址或网站名称。请通过 copyright@packt.com 与我们联系,并提供该材料的链接。
如果你有兴趣成为一名作者:如果你在某个领域具有专业知识,并且有兴趣撰写或为书籍做贡献,请访问 authors.packtpub.com。
评论
请留下评论。在你阅读并使用了本书后,为什么不在你购买书籍的网站上留下评论呢?潜在的读者可以看到并参考你的客观意见来做出购买决策,我们 Packt 能够了解你对我们产品的看法,而我们的作者也能看到你对他们书籍的反馈。谢谢!
欲了解更多关于 Packt 的信息,请访问 packt.com。
第一部分:站点可靠性工程 – 实现 DevOps 的规范性方法
本节的核心内容是站点可靠性工程(SRE)。本节从 DevOps 的演变及其生命周期开始,介绍了 SRE 作为实现 DevOps 的一种规范性方法。重点在于定义服务的可靠性以及如何衡量它。在本节中,介绍并进一步阐述了 SRE 技术实践,如服务级别协议(SLA)、服务级别目标(SLO)、服务级别指标(SLI)、错误预算以及消除繁琐工作。此外,本节还探讨了与监控、警报和时间序列相关的基础知识和关键概念,以便跟踪 SRE 技术实践。然而,SRE 技术实践在组织内的实施离不开文化变革。Google 提出了包括事件管理、值班、心理安全以及促进协作等一套 SRE 文化实践。本节还探讨了构建 SRE 团队的关键方面,并提供了关于 SRE 参与模型的见解。值得注意的是,本节开始时介绍了 Google Cloud 中的服务,旨在通过 SRE 原则实现 DevOps;然而,这些服务的具体细节将在下一节中深入探讨。
本书的这一部分包括以下章节:
-
第一章**,DevOps、SRE 和 Google Cloud 服务用于 CI/CD
-
第二章**,SRE 技术实践 – 深入探讨
-
第三章**,理解监控与警报,针对可靠性进行定位
-
第四章**,构建 SRE 团队并应用文化实践
第一章:DevOps、SRE 和 Google Cloud CI/CD 服务
DevOps 是一种思维方式的转变,试图平衡发布速度与系统可靠性。它旨在提高一个组织相较于传统软件开发流程时,持续交付可靠应用和服务的能力,并保持较高的速度。
关于 DevOps 的一个常见误解是它是一种技术。实际上,DevOps 是一组支持性实践(例如构建、测试和部署),它将软件开发和 IT 运维结合在一起。这些实践建立了一种文化,打破了开发人员(旨在将新功能推向生产环境)与系统管理员或运维人员(旨在保持代码在生产环境中正常运行)之间的隐喻性壁垒。
站点可靠性工程 (SRE) 是 Google 用来对齐开发和运维之间激励机制的方法,这对构建和维护可靠的工程系统至关重要。SRE 是一种规范化的方式来实施 DevOps 实践和原则。通过这些实践,目标是提高整体可观察性并减少事件发生的频率。引入 持续集成/持续交付 (CI/CD) 流水线支持关键的 SRE 定义,如繁重工作、可观察性和事件管理,从而实现强大的反馈循环。
CI/CD 是实现这一思维转变的关键 DevOps 实践。CI/CD 强调自动化,以 更快速地构建可靠软件(在交付/部署到生产环境方面)。这种类型的软件交付需要敏捷性,而敏捷性通常是通过拆解现有组件来实现的。
云原生开发范式是一种将复杂系统分解为多个服务(如微服务架构)的方法。每个服务可以独立测试并部署到隔离的运行时环境中。Google Cloud Platform (GCP) 提供了明确的服务来实现云原生开发,并应用 SRE 概念以实现 更快速地构建可靠软件 的目标。
本章将涵盖以下主要内容:
-
DevOps 101 – 演变与生命周期
-
SRE 101 – 演变;技术和文化实践
-
GCP 实现 DevOps 的云原生方法
理解 DevOps 及其演变和生命周期
本节重点介绍 DevOps 的演变,并列出了构成 DevOps 生命周期的阶段或关键实践。
重访 DevOps 演变
让我们退后一步,思考一下 DevOps 是如何演变的。敏捷软件开发方法论 是一套基于迭代开发的实践,要求通过跨职能团队与最终用户之间的合作,构建需求和解决方案。DevOps 可以被视为 Agile 的逻辑延伸,有些人甚至认为 DevOps 是 Agile 的产物。这是因为 DevOps 从 Agile 逻辑上停止的地方开始。让我们详细探讨一下这意味着什么。
敏捷作为一种端到端的软件交付方法被引入。其核心原则在《敏捷宣言》中定义(agilemanifesto.org/),特别强调与流程和工具的互动、提升协作、增量和迭代开发,以及对固定计划变化的灵活应对。最初的敏捷团队主要由开发人员组成,但很快扩展到了产品管理、客户和质量保证。如果我们考虑到增加的迭代测试和用户验收测试的影响,结果是可以更快地将软件交付到生产环境。
然而,敏捷方法论带来了一个新的问题,导致需要新的演变。一旦软件交付到生产环境,运维团队的主要任务是确保系统的稳定性和维护。同时,开发团队继续为已交付的软件添加新特性,以满足客户不断变化的需求,并跟上竞争的步伐。
运维人员总是小心谨慎,担心引入问题。开发人员则坚持推动更改,因为这些更改已在本地环境中经过测试,而且开发人员总认为确保更改在生产环境中正常运行是运维人员的责任。但从运维人员的角度来看,他们对代码库几乎没有了解。同样,开发人员对运维实践也知之甚少。所以,实际上,开发人员专注于更快地发布新特性,而运维人员则专注于稳定性。这迫使开发人员在将新特性推向生产环境时变得更加缓慢。这种不协调常常导致组织内部的紧张局势。
Patrick Debois,一位 IT 顾问,在 2007 年参与一个大型数据中心迁移项目时,遇到了与开发人员和运维人员合作时的类似挑战。他创造了“DevOps”这一术语,并与 Andrew Shafer 一起推动了这一运动。他们认为 DevOps 是敏捷的延伸。事实上,当他们为 DevOps 创建第一个 Google 群组时,他们称其为敏捷系统管理。
DevOps 运动促进了软件开发与 IT 运维之间的更好沟通,并有效地提升了软件质量,持续性成为了稳定环境运营、持续交付、改进协作和增强运维实践的核心主题,重点是创新。这导致了 DevOps 生命周期的演变,具体内容将在接下来的子章节中详细说明。
DevOps 生命周期
DevOps 包括一些阶段或实践,这些阶段或实践共同构成了 DevOps 生命周期。在本节中,我们将详细讨论这些阶段,如下图所示:

图 1.1 – DevOps 生命周期的各个阶段
DevOps 生命周期中有六个主要阶段。具体如下:
-
计划和构建
-
持续集成
-
持续交付
-
持续部署
-
持续监控与操作
-
持续反馈
这里的关键词是持续。如果代码持续开发,接下来就需要持续地进行测试、提供反馈、部署、监控和操作。这些阶段将在后续部分介绍。
第一阶段 – 计划和构建
在规划阶段,核心关注点是理解愿景并将其转化为详细的计划。计划可以拆分为多个阶段,通常被称为史诗(在敏捷术语中)。每个阶段或史诗可以被划定为实现一组特定功能,这些功能可以进一步细化为一个或多个用户故事。这需要各方利益相关者之间大量的沟通与协作。
在构建阶段,代码使用选择的编程语言编写,并创建适当的构建产物。代码会保存在像 GitHub、Bitbucket 等源代码仓库中。
第二阶段 – 持续集成
持续集成(CI)是一种软件开发实践,开发人员频繁地将其代码更改集成到共享代码库的主分支中。最好是在一天内进行多次集成,从而进行多次合并。
重要提示
代码更改被认为是软件开发的基本单位。由于开发是渐进式的,开发人员会不断修改他们的代码。
理想情况下,每次集成都由自动化构建触发,并且自动化单元测试也会随之启动,以尽快发现任何问题。这可以避免集成地狱,换句话说,确保通过将代码更改或增量引入主分支,不会破坏应用程序。
第三阶段 – 持续交付
持续交付是一种软件开发实践,其目标是构建软件,使得一组代码更改可以随时交付或发布到生产环境中。它可以看作是 CI 的扩展,其核心关注点是自动化发布过程,以实现无需人工干预或一键部署。
核心目标是确保代码库是可发布的,并且没有回归性的问题。新添加的代码可能并不一定能正常工作。交付代码到生产环境的频率非常依赖于组织,可能是每日、每周、每两周等。
第四阶段 – 持续部署
持续部署是一种软件开发实践,其核心关注点是将自动化部署发布到生产环境中,而无需用户干预。其目的是最小化从开发人员编写新代码到这些新代码被生产环境中的活跃用户使用之间的时间间隔。
本质上,持续部署包含了强大的测试框架,并鼓励在持续交付阶段后将代码部署到测试/预发布环境中。自动化测试可以作为流水线的一部分,在测试/预发布环境中运行。如果没有问题,代码可以自动部署到生产环境中。这消除了正式发布日的需求,并建立了一个反馈循环,确保新增的功能对最终用户有用。
第 5 阶段 – 持续监控与运营
持续监控 是一种利用分析信息来识别应用程序或其基础设施问题的实践。监控可以分为两种类型:服务器监控 和 应用程序监控。
持续运营 是一种实践,其核心关注点是减轻、减少或消除计划停机的影响,例如计划中的维护,或在发生意外停机时,例如事故。
第 6 阶段 – 持续反馈
持续反馈 是一种实践,其核心关注点是收集改进应用程序/服务的反馈。一个常见的误解是,持续反馈仅在 DevOps 循环的最后阶段发生。
在 DevOps 流水线的每个阶段都会有反馈循环,例如当由于特定代码提交而导致构建失败、单元/集成测试或功能测试在测试部署中失败,或者客户在生产环境中发现问题时,都会传递反馈。
GitOps 是实现持续反馈的一种方法,在这种方法中,版本控制系统具备管理操作工作流的能力,例如 Kubernetes 部署。工作流中任何一个环节的失败都可以直接在源代码管理中跟踪,从而创建一个直接的反馈循环。
DevOps 的关键支柱
DevOps 可以分为五个关键支柱或领域:
-
减少组织壁垒:通过鼓励团队合作,共同朝着公司愿景努力,缩小团队之间的差距。这减少了团队之间的摩擦,增加了沟通与协作。
-
接受失败为常态:在 DevOps 的持续方面,失败被视为持续改进的机会。系统/服务注定会失败,特别是在添加更多功能以改进服务时。从失败中学习可以减少再次发生的可能性。将失败作为常态文化来培养,将使团队成员更加积极主动。
-
实施渐进变化:实施渐进变化符合 DevOps 的持续方面。小的、渐进的变化不仅更容易审查,而且在生产中发生问题时,回滚更为简便,可以通过恢复到最后一个已知的正常工作状态来减少事件的影响。
-
利用工具和自动化:自动化是实现 CI/CD 管道连续性关键的一环,这对于 DevOps 至关重要。识别手工工作并通过自动化来实现,最终提高速度并为日常流程带来一致性,是非常重要的。
-
衡量一切:衡量是成功的关键指标。监控是一种衡量和观察的方式,帮助获取重要的反馈,以便持续改进系统。
这完成了我们对 DevOps 的介绍,我们讨论了它的发展历程、生命周期阶段和关键支柱。归根结底,DevOps 是一套实践方法。接下来的章节将介绍站点可靠性工程(SRE),这本质上是 Google 实现 DevOps 关键支柱的实际方法。
SRE 的发展;技术和文化实践
本节追溯了 SRE 的发展历程,定义了 SRE,讨论了 SRE 如何通过阐述 DevOps 关键支柱与 DevOps 相关,详细解释了关键术语,并介绍了 SRE 的文化实践。
SRE 的发展历程
在 2000 年代初,Google 正在构建庞大复杂的系统来运行搜索和其他关键服务。它们面临的主要挑战是可靠地运行服务。那时,许多公司通常由系统管理员部署软件组件作为服务。系统管理员,或称为sysadmin方法,主要通过响应事件或更新来运行服务。这意味着,如果服务的流量或复杂性增加,事件和更新也会相应增加。
sysadmin 方法有其缺陷,这些缺陷体现在两类成本中:
-
直接成本:使用一组系统管理员来运行服务需要手动干预。大规模的手动干预是变更管理和事件处理的一个主要缺点。然而,由于没有被认可的替代方法,这种手动方法被多家公司采用。
-
间接成本:系统管理员和开发人员在技能、描述情况的词汇和激励机制上有很大的不同。开发团队总是希望推出新功能,他们的激励是推动采用。系统管理员或运维团队则希望确保服务的可靠运行,并常常有不要更改已经正常工作的东西的思维方式。
Google 不希望采取手动方法,因为在其规模和流量下,任何需求的增加都会使扩展变得不切实际。定期向用户推出更多功能的愿望最终会导致开发人员和运维人员之间的冲突。Google 希望减少这种冲突,并消除关于期望结果的混淆。掌握了这一点,Google 考虑了一种替代方法。这种新方法最终成为了 SRE。
理解 SRE
SRE 就是当你要求一名软件工程师来设计一个运维团队时所发生的事情。
(Betsy Beyer, Chris Jones, Jennifer Petoff, & Niall Murphy, 网站可靠性工程, O'REILLY)
上述内容摘自 Ben Treynor Sloss 的引用,他在 2003 年与七名软件工程师一起成立了谷歌的第一个 SRE 团队。在那之前,Ben 自己也是一名软件工程师,并于 2003 年加入谷歌,成为网站可靠性负责人,领导谷歌的生产软件基础设施、网络和面向用户的服务的开发和运维工作,目前是谷歌的工程副总裁。在 2003 年时,Ben 和谷歌都没有正式定义 SRE。
SRE 是一种面向 IT 运维的软件工程方法。SRE 是谷歌文化的内在组成部分。它是运行谷歌复杂系统和服务规模化的关键。在其核心,SRE 的目标是结束开发和运维之间的长期斗争。本节介绍了 SRE 的思维方式,接下来的章节将深入探讨 SRE 如何实现其目标。
谷歌构建 SRE 实践或团队的一个主要区别在于 SRE 团队的组成。一个典型的 SRE 团队由 50-60%的谷歌软件工程师组成。其余的 40-50%是具备软件工程技能的人员,除此之外,还具有与 UNIX/Linux 系统内部结构和网络专家相关的技能。团队的组成促使了两种行为模式,这些模式推动了团队的前进:
-
团队成员很快对手动执行任务或响应事件感到厌倦。
-
团队成员具备编写软件的能力,并能提供工程解决方案,以避免重复的手动工作,即使该解决方案很复杂。
简单来说,SRE 实践是在一群软件工程师通过使用工程实践,可靠地运行服务并自动化系统时逐步发展起来的。这引出了几个关键问题。SRE 与 DevOps 有何不同?哪一个更好?这些问题将在接下来的子章节中讨论。
从谷歌的角度来看,DevOps 是一种哲学,而非开发方法论。它旨在缩小软件开发与软件运维之间的差距。DevOps 的关键支柱阐明了如何实现协作、凝聚力、灵活性、可靠性和一致性。
SRE 对 DevOps 关键支柱的做法
DevOps 没有提出一个明确的路径或机制来说明如何实现这一点。谷歌的 SRE 方法是解决 DevOps 哲学所关注问题的具体或规定性方法。谷歌使用类比来描述 SRE 与 DevOps 之间的关系:
如果你把 DevOps 看作编程语言中的一个接口,那么类 SRE 实现了 DevOps。
(谷歌云, SRE 与 DevOps:竞争标准还是亲密朋友?, cloud.google.com/blog/products/gcp/sre-vs-devops-competing-standards-or-close-friends)
让我们来看一下 SRE 如何实现 DevOps,并接近 DevOps 的关键支柱:
-
减少组织壁垒:SRE 通过共享开发人员和运维人员之间的所有权来减少组织壁垒。两支团队从一开始就参与产品/服务的生命周期。它们共同定义服务级目标(SLOs)、服务级指标(SLIs)和错误预算,并共同承担确定可靠性、工作优先级和新特性发布节奏的责任。这促进了共同的愿景,并改善了沟通与协作。
-
将失败视为正常:SRE 通过进行无责事后分析,将失败视为正常,其中包括不涉及个人的详细分析。无责事后分析有助于了解失败的原因,识别预防措施,并确保同样的失败不会再次发生。目标是找出根本原因和过程,而不是关注个人。这有助于促进心理安全。在大多数情况下,失败是由于缺少 SLO 或目标,事件通过特定指标作为时间或 SLI 的函数来追踪。
-
实施渐进式变更:SRE 通过有限的金丝雀发布来实施渐进式变更,并最终减少失败的成本。金丝雀发布指的是在生产环境中将变更发布给一小部分用户,在广泛推向所有用户之前。这可以确保影响仅限于少数用户,并为我们提供捕捉新发布反馈的机会。
-
利用工具和自动化:SRE 利用工具和自动化来减少劳累工作(指手动重复性工作),并最终促进速度和一致性。自动化是一个倍增器。然而,这可能会对变更产生很大的抵触情绪。SRE 建议通过理解变革心理来应对这种抵触情绪。
-
衡量一切:SRE 倡导数据驱动的决策制定,鼓励通过衡量和监控与系统健康和可靠性相关的关键因素来设定目标。SRE 还衡量手动重复性工作的量。衡量一切是设定 SLO 和服务级协议(SLA)以及减少劳累工作的关键。
这就总结了我们对 SRE 方法与 DevOps 关键支柱的介绍;我们提到了 SLI、SLO、SLA、错误预算、劳累工作和金丝雀发布等术语。接下来我们将在下一个小节中详细介绍这些概念。
引入 SRE 的关键概念
SRE 通过几个关键概念来实现 DevOps 理念,如 SLI、SLO、SLA、错误预算和劳累工作。
熟悉 SLI、SLO 和 SLA
在深入了解 SRE 术语的定义之前——具体来说是 SLI、SLO 和 SLA——这一小节试图通过一个易于理解的例子来介绍这些术语。
假设你是一个付费的视频流媒体服务用户。作为付费用户,你会对该服务有一定的期望。这个期望的一个关键方面是,服务需要是可用的。这意味着,当你通过任何允许的方式(如移动设备或桌面)访问视频流媒体服务的网站时,网站应该是可以访问的,并且服务应该始终可用。
如果你在访问该服务时经常遇到问题,不论是由于服务流量过大,还是服务提供商正在添加新功能,或是其他任何原因,你都不会是一个快乐的消费者。现在,有可能某些用户在某一时刻能够访问该服务,而另一些用户则无法在同一时刻访问。那些能够访问的用户是快乐的用户,而那些无法访问的用户是悲伤的用户。
可用性
一个服务应该提供的第一个也是最关键的功能是可用性。服务的可用性也可以称为其正常运行时间。可用性是指一个应用程序或服务在需要时能够运行的能力。如果系统未运行,则系统将失败。
假设你是一个快乐的用户,你可以访问该服务。你可以创建个人资料、浏览标题、筛选标题、查看特定标题的评论、将视频添加到观看列表、播放视频,或将观看过的视频添加评论。你作为用户执行的每个动作都可以被归类为用户旅程。对于每个用户旅程,你会有一定的期望:
-
如果你尝试浏览特定类别下的标题,比如喜剧,你会期望服务能够没有任何延迟地加载这些标题。
-
如果你选择了一个想要观看的标题,你会期望观看视频时没有任何缓冲。
-
如果你想观看直播,你会期望直播内容尽可能新鲜。
让我们探讨第一个期望。当你作为用户尝试浏览喜剧类别下的标题时,什么速度才算足够快?
一些用户可能期望在 1 秒内显示结果,一些用户可能期望在 200 毫秒内显示结果,另一些用户则期望在 500 毫秒内显示。因此,期望值需要是可量化的,为了能够量化,它还需要是可衡量的。期望值应该设置为大多数用户会感到满意的一个数值。它还应当在一个特定的时间段内(例如 5 分钟)进行衡量,并且在一段时间内(例如 30 天)得以满足。这不应当是一次性事件。如果期望值在用户期望的时间内没有得到满足,服务提供商需要承担一定责任,并通过退款或添加额外的服务积分来解决用户的投诉。
为了使服务可靠,服务需要具备根据用户旅程期望的关键特性。在这个例子中,用户期望的关键特性是 延迟、吞吐量 和 新鲜度。
可靠性
可靠性 是指应用程序或服务在特定时间内执行特定功能而不发生故障的能力。如果系统无法执行其预定功能,那么系统就会失败。
所以,总结一下视频流服务的例子,作为用户,你会期望以下内容:
-
服务是可用的。
-
服务是可靠的。
现在,让我们根据前面的例子介绍 SRE 术语,然后再深入了解它们的正式定义:
-
期望服务可用,或者期望服务满足特定的延迟、吞吐量、新鲜度,或其他对用户旅程至关重要的特性,这些都称为 SLI。
-
期望服务在特定时间段内可用或可靠,达到某一目标水平,这就是 SLO。
-
期望服务满足预定义的客户期望,若未能满足,导致退款或积分补偿,这就是 SLA。
让我们从对这些概念的一般理解出发,进一步探索 Google 如何看待它们,并介绍 SRE 的技术实践。
SRE 的技术实践
SRE 特别规定使用特定的技术工具或实践,帮助定义、衡量和跟踪服务特性,例如可用性和可靠性。这些被称为 SRE 技术实践,专门指代 SLI、SLO、SLA、错误预算和无谓劳动。这些内容将在接下来的章节中进行深入介绍。
服务级别指标(SLI)
Google SRE 对 SLI 有以下定义:
SLI 是一个经过精确定义的定量衡量标准,用于衡量所提供服务的某些方面。
(Betsy Beyer, Chris Jones, Jennifer Petoff, & Niall Murphy, Site Reliability Engineering, O'REILLY)
大多数服务将延迟或吞吐量视为服务的关键方面,这些方面基于相关的用户旅程。SLI 是这些方面的具体测量,其中原始数据会在测量窗口中汇总或收集,并表示为比率、平均值或百分位数。
现在让我们来看看 SLI 的特点:
-
它是对服务性能或行为的直接测量。
-
指的是随着时间推移的可衡量指标。
-
可以进行汇总并转化为比率、平均值或百分位数。
-
用于确定可用性的水平。SRE 认为可用性是成功的前提。
SLI 可以用公式表示:

对于通过 HTTPS 提供请求的系统,有效性通常由请求参数决定,例如主机名或请求路径,以将 SLI 范围限定到特定的服务任务集或响应处理程序。对于数据处理系统,通常由输入的选择来决定有效性,以将 SLI 范围限定到数据的子集。良好的事件是指来自服务或系统的期望。
让我们看看一些 SLI 的例子:
-
请求延迟:请求返回响应的时间应少于 100 毫秒。
-
故障率:失败请求与所有收到的请求的比例应大于 99%。
-
可用性:指检查服务在特定时间点是否可用的正常运行时间。
服务级目标(SLO)
Google SRE 使用以下 SLO 定义:
服务级目标(SLO)指定了服务可靠性的目标水平。
(Betsy Beyer, Chris Jones, Jennifer Petoff, & Niall Murphy, 网站可靠性工程, O'REILLY)
客户对服务有具体期望,这些期望通过特定指标或 SLI 进行表征,通常根据用户旅程定制。SLO 是衡量客户满意度和期望的一种方式,通过确保 SLI 始终得到满足,并在客户察觉问题之前可能就进行报告。
现在让我们来看看 SLO 的特点:
-
确定服务是否足够可靠。
-
与 SLI 直接相关。实际上,SLO 是通过使用 SLI 来进行测量的。
-
可以是单一目标,也可以是一个范围值,用于收集 SLI。
-
如果 SLI 指的是随时间变化的度量,详细描述了服务的健康状况,那么 SLO 就是关于 SLI 必须满足的频率范围的约定。
让我们看看它们是如何作为公式表示的:
目标 或 
SLO 可以最好地表示为特定目标值,也可以表示为服务的特定方面(例如延迟或吞吐量)的 SLI 范围值,表示在特定期间内有效的可接受的下限和可能的上限。鉴于 SLI 用于衡量 SLO,SLI 应在目标值内或处于可接受值的范围之间。
让我们看看一些 SLO 的例子:
-
请求延迟:所有请求的 99.99%应在 1 个月内少于 100 毫秒,或所有请求的 99.9%应在 1 个月内介于 75 毫秒和 125 毫秒之间。
-
故障率:所有请求的 99.9%在一年内的故障率应为 99%。
-
可用性:应用程序在 24 小时内应可用 99.95%的时间。
服务级协议(SLA)
Google SRE 使用以下 SLA 定义:
SLA 是与用户之间的明确或隐含的契约,其中包括满足(或未满足)SLO 时的后果。
(Betsy Beyer, Chris Jones, Jennifer Petoff, & Niall Murphy, 网站可靠性工程, O'REILLY)
SLA 是一种面向外部的协议,提供给服务的消费者。该协议明确列出了消费者可以期望从服务中获得的最低期望,并指出如果违反协议,服务提供商需要承担的后果。这些后果通常是以退款或额外积分的形式提供给服务消费者。
现在让我们来看一下 SLA 的特点:
-
SLA 基于 SLO。
-
标志着将客户与服务提供商绑定在一起的商业因素。
-
表示当可用性或客户期望未能实现时的后果。
-
相比 SLO,SLA 在触发早期警报时更宽松,因为这些是服务应满足的最低期望。
相对于 SLO,SLA 的优先级可以表示如下:

让我们看一些 SLA 的例子:
-
延迟:每天 99% 的请求应在 150 毫秒内响应,否则将退还 10% 的每日订阅费用。
-
可用性:服务应保证在 30 天内的正常运行时间为 99.9%;否则,将向用户账户添加 4 小时的额外积分。
错误预算
Google SRE 将错误预算定义如下:
产品团队和 SRE 团队之间共享的定量度量,以平衡创新与稳定性。
(Betsy Beyer, Chris Jones, Jennifer Petoff, & Niall Murphy, 网站可靠性工程, O'REILLY)
虽然服务需要保持可靠性,但也应注意,如果不向服务中添加新特性,用户可能不会继续使用该服务。一个 100% 可靠的服务意味着该服务不会出现任何停机时间。这意味着,通过新特性进行创新,以吸引新客户并增加收入,将变得越来越困难。达到 100% 可靠性既昂贵又复杂。因此,建议找到一个服务可靠性的独特价值,使客户感到该服务已经足够可靠。
不可靠的系统会迅速削弱用户的信任。因此,减少系统故障的可能性至关重要。SRE 的目标是平衡不可用性风险与快速创新和高效服务运营的目标,以优化用户在功能、服务和性能方面的整体满意度。
错误预算基本上是可用性的倒数,它告诉我们服务被允许多不可靠。如果你的 SLO 说在一个季度内 99.9% 的请求应该是成功的,那么你的错误预算允许 0.1% 的请求失败。这种不可用性可能是由于产品团队的错误推送、计划的维护、硬件故障等原因造成的:

重要提示
错误预算与服务实际允许停机时间之间的关系如下:
如果 SLO = 99.5%,那么错误预算 = 0.5% = 0.005
每月允许停机时间 = 0.005 * 30 天/月 * 24 小时/天 * 60 分钟/小时 = 216 分钟/月
下表表示在特定时间段内,为实现特定可用性水平所允许的停机时间。有关计算特定可用性水平(除下文提到的)停机时间信息,请参考availability.sre.xyz/:

定义错误预算有其优点:
-
在保持系统可靠性的同时发布新功能。
-
推出基础设施更新。
-
计划应对网络及其他类似事件中的不可避免故障。
尽管有错误预算的规划,但有时系统会超出预算。在这种情况下,会发生一些情况:
-
新功能的发布暂时停止。
-
增加对开发、系统和性能测试的关注。
劳动
Google SRE 将劳动定义如下:
劳动是与运行生产服务相关的工作,通常是手动的、重复的、可自动化的、战术性的、没有持久价值的,并且随着服务的增长而线性扩展。
(Betsy Beyer, Chris Jones, Jennifer Petoff, & Niall Murphy, 网站可靠性 工程, O'REILLY)
以下是劳动的特点:
-
手动:手动启动自动化任务脚本的行为。
-
重复性:多次重复的任务。
-
可自动化:由人类执行的任务,而非机器执行,尤其是当机器能以同样的效果执行时。
-
战术性:从中断(例如呼叫警报)中产生的反应性任务,而非策略驱动的主动任务,视为劳动。
-
无持久价值:执行后的任务不会改变服务的有效状态。
-
线性增长:任务随着流量或服务需求的增加而线性增长。
劳动通常与开销混淆。开销与劳动不同。开销是指与运行服务无关的行政工作,而劳动指的是可以通过自动化减少的重复性工作。自动化有助于减少疲劳,提高团队士气,提升工程标准,改善技术技能,标准化流程,并减少人为错误。代表开销而非劳动的任务例子包括电子邮件、通勤、费用报告和会议。
金丝雀发布
SRE 建议通过金丝雀发布实施渐进式变更,其中概念是将变更引入一小部分用户,以检测潜在的危险。
进一步说明,当需要维持一个大规模服务时,最好先对一小部分进行生产变更,未知的影响可以帮助发现潜在问题。如果发现问题,可以回滚变更,且其影响或成本远小于将变更推向整个服务时的影响。
选择金丝雀群体时应考虑以下两个因素:
-
金丝雀群体的规模应该足够小,以便在出现问题时能够迅速回滚。
-
金丝雀群体的规模应该足够大,以至于它能够代表整个群体的子集。
这结束了 SRE 重要技术实践的高级概述。接下来的部分将详细介绍 SRE 文化实践,这些文化实践是推动整个组织接受 SRE 的关键,并且对高效处理变更管理至关重要。
SRE 的文化实践
为服务定义 SLI、SLO 和 SLA,使用错误预算平衡变更速度(将更改交付到生产环境的速度)和可靠性,识别重复劳动,并利用自动化消除重复劳动,构成了 SRE 的技术实践。除了这些技术实践外,理解并建立某些文化实践同样重要,这些文化实践最终将支持技术实践。文化实践对减少 IT 团队内部的孤岛效应同样重要,因为它们可以减少团队成员之间不兼容的做法。接下来讨论的第一个文化实践是统一愿景的需求。
统一愿景的需求
每个公司都需要有愿景,团队的愿景需要与公司的愿景保持一致。公司的愿景是核心价值观、目标、使命、战略和目标的结合:
-
核心价值观:价值观指团队成员对个人/组织目标的承诺。它还反映了成员如何在团队内运作,通过建立信任和心理安全。这创造了一种文化,使团队乐于学习并愿意冒险。
-
使命:团队的使命指的是团队存在的核心原因。每个团队都应该在组织的更大背景下有一个使命。
-
使命:团队的使命指的是一个明确的、清晰的、具有吸引力的和统一的目标。
-
战略:一个团队的战略是指团队如何实现其使命的计划。
-
目标:团队的目标提供了更详细和具体的见解,说明团队希望实现的内容。Google 推荐使用目标与关键成果(OKRs),这是大型公司常用的目标设定工具。
一旦为公司和团队建立了愿景声明,下一步的文化实践是确保团队内部以及跨职能团队之间的高效协作与沟通。接下来将讨论这一点。
协作与沟通
鉴于服务的复杂性以及这些服务需要全球可访问,沟通与协作至关重要。这也意味着 SRE 团队应该是全球分布的,以有效支持服务。以下是一些 SRE 的建议性指南:
-
面向服务的会议:SRE(站点可靠性工程)团队经常回顾服务的状态,识别改进机会并提高利益相关者的意识。这些会议对团队成员是强制性的,通常持续 30-60 分钟,议程明确,包括讨论最近的警报事件、故障以及任何必要的配置更改。
-
平衡的团队组成:SRE 团队分布在多个国家和时区,这使他们能够支持全球可用的系统或服务。SRE 团队的组成通常包括技术负责人(提供技术指导)、经理(负责绩效管理)和项目经理,他们跨时区进行协作。
-
贯穿服务生命周期的参与:SRE 团队积极参与服务生命周期的各个阶段,如架构与设计、积极开发、有限可用性、一般可用性和弃用。
-
建立互动规则:SRE 团队应清楚地描述在不同情况下应使用哪些渠道来达到什么目的,这样能带来明确感。SRE 团队应使用一套通用工具来创建和维护工件。
-
鼓励无责后审:SRE 鼓励无责后审文化,主题是从失败中学习,重点是识别问题的根本原因,而不是指责个人。一个撰写良好的后审报告可以作为推动积极组织变革的有效工具,因为报告中提到的建议或改进可以帮助调整现有流程。
-
知识共享:SRE 团队通过特定方式促进知识共享,如鼓励交叉培训、创建志愿者教学网络,以及分享事件的后审报告,方式是促进协作和知识共享。
之前的指导方针,比如通过创建一套通用工具来减少警报事件或故障的知识共享目标,可能会增加个人和团队成员的抵抗情绪。这也可能引发不安全感。接下来的文化实践将详细说明如何鼓励心理安全并减少对变化的抵抗。
鼓励心理安全并减少对变化的抵抗
SRE 强调自动化是应用工程原则并减少手工操作(如苦差事)的核心。尽管通过自动化消除苦差事是一项技术实践,但执行自动化将面临巨大的阻力。有些人可能比其他人更抵制自动化。个人可能会感到自己的工作处于危险之中,或者他们可能不同意某些任务不需要自动化。SRE 提出了一种文化实践,通过建立心理安全的环境来减少对变化的抵抗。
为了建立心理安全的环境,首先需要传达特定变更的重要性。例如,如果变更是自动化今年的工作,以下是自动化如何创造价值的一些原因:
-
提供一致性。
-
提供一个可以扩展并应用于更多系统的平台。
-
常见故障可以更容易地被识别并更快地解决。
-
通过尽早识别生命周期中的问题,而不是在生产环境中发现它们,从而降低成本。
一旦变更的原因得到清晰的沟通,以下是一些额外的建议,有助于建立心理安全的环境:
-
让团队成员参与到变更中来。了解他们的顾虑,并在需要时进行共情。
-
鼓励批评者公开表达他们的担忧,因为这为团队成员提供了自由表达意见的空间。
-
设定现实的期望值。
-
允许团队成员适应新的变更。
-
为他们提供有效的培训机会,并确保培训富有吸引力并具有回报。
这部分介绍了实施 SRE 技术实践所需的关键 SRE 文化实践。接下来,这也完成了关于 SRE 的部分,我们介绍了 SRE,讨论了它的发展,并详细说明了 SRE 如何成为实践性地实现 DevOps 关键支柱的规定性方式。下一部分讨论了如何使用 Google Cloud 服务来实现 DevOps。
使用 Google Cloud 实现 DevOps 的云原生方法
本节详细讲解了如何使用 Google Cloud 服务实现 DevOps,重点介绍了云原生方法——一种以云计算为核心来构建高可用、可扩展和具有弹性的应用程序的方法。
专注于微服务
单体应用具有紧耦合的架构,并在单一代码库和数据库中实现所有可能的功能。尽管单体应用可以通过模块化组件来设计,但这些组件仍然会在部署时一起打包并作为一个单独的单元进行部署。从 CI/CD 的角度来看,这可能会导致一个单一的构建管道。修复问题或添加新功能是一个非常耗时的过程,因为它会影响整个应用程序。这会降低发布速度,本质上对于处理服务中断的生产支持团队来说是一个噩梦。
相比之下,微服务应用程序基于面向服务的架构。微服务应用程序将大型程序分解为若干较小、独立的服务。这使得这些组件可以由更小的团队进行管理,因为这些组件本质上是更加隔离的。团队和服务都可以独立扩展。微服务从根本上支持增量代码更改的概念。在微服务中,单独的组件是可部署的。由于微服务具有特定的功能,因此一旦出现问题,故障检测和隔离会更加容易,从而可以快速高效地处理服务中断。这也使其更加适合 CI/CD 流程,并与更快构建可靠软件的主题非常契合!
考试小贴士
谷歌云提供多种计算服务,便于将微服务部署为容器。这些服务包括 App Engine 灵活环境、Cloud Run、谷歌计算引擎(GCE)和谷歌 Kubernetes 引擎(GKE)。从谷歌云 DevOps 考试的角度来看,核心主题是构建容器并使用 GKE 部署容器。GKE 将是一个主要关注领域,并将在接下来的章节中详细讨论。
云原生开发
谷歌推动并推荐使用以下云原生原则进行应用开发:
-
使用微服务架构模式:如前一小节所讨论的,核心是构建较小的独立服务,这些服务可以单独管理并且实现精细化扩展。
-
将一切视为代码:这一原则使得追踪代码、在需要时回滚代码以及查看变更版本变得更加容易。包括源代码、测试代码、自动化代码和基础设施即代码。
-
将一切构建为容器:一个容器镜像可以包含应用程序所需的软件依赖项、特定语言的运行时以及其他软件库。容器可以在任何地方运行,使得开发和部署变得更加容易。这使得开发人员能够专注于代码,运维团队则能减少调试和诊断环境差异的时间。
-
为自动化设计:自动化流程可以比人工更快地修复、扩展和部署系统。作为关键的第一步,需要一个全面的 CI/CD 流水线,它可以自动化构建、测试和部署过程。此外,作为容器部署的服务应根据流量的变化进行动态扩展或收缩。实时监控和日志记录应作为自动化的基础,因为它们提供了可能出现的问题的洞察,这些问题可以通过构建主动的措施来缓解。自动化的思想还可以扩展到通过 基础设施即代码(IaC)等技术自动化整个基础设施。
-
尽可能设计无状态组件:无状态组件易于扩展或缩减,通过优雅终止和潜在替换修复失败的实例,在出现问题时可以回滚到旧的实例,并使负载均衡更简单,因为任何实例都可以处理任何请求。任何需要存储持久数据的需求应发生在容器之外,例如使用 Cloud Storage 存储文件,通过 Redis 或 Memcached 存储用户会话,或者使用持久磁盘进行块级存储。
Google Cloud 提供了两种云原生开发方式——无服务器和Kubernetes。选择的关键在于关注基础设施与业务逻辑:
-
无服务器(通过 Cloud Run、Cloud Functions 或 App Engine):通过提供更高层次的基础设施抽象,使我们能够专注于应用程序的业务逻辑。
-
Kubernetes(通过 GKE):提供更高的粒度和控制,能够决定多个微服务如何部署、服务之间如何相互通信,以及外部客户端如何与这些服务进行交互。
托管与无服务器服务
托管服务使得与更新、网络、补丁、高可用性、自动备份和冗余相关的操作由云服务提供商管理。托管服务并非无服务器架构,因为需要指定机器的大小,并且服务要求至少有一个最小数量的 VM/节点。例如,在创建 Cloud SQL 实例时,需要定义机器大小,但更新和补丁可以配置为由 Google Cloud 进行管理。
无服务器服务是托管的,但不需要预留服务器或保持其运行。重点是应用程序的业务逻辑,仅在需要时执行或运行代码。示例包括Cloud Run、Cloud Storage、Cloud Firestore和Cloud Datastore。
GCP 中的持续集成
持续集成构成了 CI/CD 流程中的CI部分,其核心在于频繁提交较小的变更单元。较小的变更能最小化风险,帮助快速解决问题,提升开发速度,并提供频繁的反馈。以下是构成 CI 流程的基础模块:
-
进行代码更改:通过使用所选的 IDE 和可能的云原生插件
-
管理源代码:通过使用单一共享代码库
-
构建并创建制品:通过使用自动化构建过程
-
存储制品:通过将制品(如容器镜像)存储在仓库中,以便未来的部署过程
Google Cloud 为每个构建模块提供了适当的服务,使我们能够构建一个 GCP 原生的 CI 流水线(参见图 1.2)。以下是这些服务的总结,详细内容将在后续章节中讨论:

图 1.2 – GCP 中的 CI
让我们详细了解这些阶段。
Cloud Code
这是 GCP 服务,用于编写、调试和部署云原生应用程序。Cloud Code 为Visual Studio Code和JetBrains 套件的 IDE 提供扩展,允许在 Kubernetes 和 Cloud Run 上快速迭代、调试和运行代码。主要功能包括以下内容:
-
加速开发并简化本地开发
-
扩展到 GKE 或 Cloud Run 上的生产部署,并允许调试已部署的应用程序
-
与 Cloud Source Repositories 和 Cloud Build 的深度集成
-
轻松地通过内建的库管理器添加和配置 Google Cloud APIs
Cloud Source Repositories
这是 GCP 服务,用于管理源代码。它提供 Git 版本控制,支持任何应用程序或服务的协同开发。主要功能包括以下内容:
-
完全托管的私有 Git 仓库
-
提供与 Bitbucket 和 GitHub 源代码仓库的单向同步
-
与 GCP 服务如 Cloud Build 和 Cloud Operations 的集成
-
包括跨仓库的通用代码搜索
Cloud Build
这是 GCP 服务,用于根据对源代码仓库(如 GitHub、Bitbucket 或 Google 的 Cloud Source Repositories)进行的提交构建和创建产物。这些产物可以是容器产物或非容器产物。GCP DevOps 考试的主要关注点将是容器产物。主要功能包括以下内容:
-
完全无服务器平台,无需预先配置服务器或为额外容量预付费用。将根据负载自动扩展或缩减
-
包括 Google 和社区构建的镜像,支持多种语言和工具
-
包括自定义构建步骤和预创建的第三方应用扩展,企业可以轻松将其集成到构建流程中
-
通过漏洞扫描并能够定义策略来阻止漏洞图片的部署,专注于安全性
容器/产物注册表
这是 GCP 的构建,用于存储包含容器(Docker 镜像)和非容器产物(如 Java 和 Node.js 包)的产物。主要功能包括以下内容:
-
与 Cloud Source Repositories 和 Cloud Build 无缝集成,支持将构建产物上传到容器/产物注册表。
-
能够在 Google Cloud 上设置安全的私有构建产物存储,并具备细粒度的访问控制。
-
在一个 Google Cloud 项目中创建多个区域性仓库。
在 GCP 中实现持续交付/部署
持续交付/部署构成了 CI/CD 过程中的CD部分,其核心是持续交付生产就绪代码或将代码部署到生产环境的文化。这使我们能够以高速度发布软件,同时不牺牲质量。
GCP 提供多种服务来部署代码,如Compute Engine、App Engine、Kubernetes Engine、Cloud Functions和Cloud Run。本书将重点介绍 GKE 和 Cloud Run。这与 Google Cloud DevOps 考试目标一致。
下图从适当的 GCP 服务视角总结了持续交付/部署的不同阶段:

图 1.3 – GCP 中的持续交付/部署
让我们详细看看这两种基于容器的部署方式。
Google Kubernetes Engine(GKE)
这是 GCP 服务,用于部署容器。GKE 是谷歌云对CNCF Kubernetes 项目的实现。它是一个托管环境,使用谷歌的基础设施来部署、管理和扩展容器化应用程序。其主要特点包括:
-
自动配置并管理集群的主基础设施,且无需单独的主节点
-
自动扩展集群的节点实例数量
-
集群节点软件的自动升级
-
节点自动修复以维持节点的健康
-
与 Google 的 Cloud Operations(用于日志记录和监控)的本地集成
Cloud Run
这是一个由 GCP 管理的无服务器平台,可部署和运行 Docker 容器。这些容器可以部署在 Google 管理的 Kubernetes 集群中,也可以通过Cloud Run for Anthos部署到本地工作负载。其主要特点包括:
-
通过自动扩展来抽象化基础设施管理
-
只对实际消耗的资源收费
-
与 Google Cloud 服务如 Cloud Code、Cloud Source Repositories、Cloud Build 和 Artifact Registry 的本地集成
-
通过 Google Cloud 服务(如 Cloud Scheduler、Cloud Tasks 和 Cloud Pub/Sub)支持基于事件的调用。
在 GCP 上的持续监控/操作
持续监控/操作构成了 CI/CD 流程的反馈环路,其核心是持续监控或观察服务/应用性能的文化。
GCP 提供一套服务,涵盖持续监控/操作的不同方面,称为Cloud Operations(前身为Stackdriver)。Cloud Operations 包括Cloud Monitoring、Cloud Logging、错误报告和应用程序性能管理(APM)。APM 还包括Cloud Debugger、Cloud Trace和Cloud Profiler。参见下图:

图 1.4 – 持续监控/操作
让我们详细了解这些与操作和监控相关的服务。
Cloud Monitoring
这是 GCP 服务,用于收集来自 Google Cloud 及其他提供商的指标、事件和元数据。其主要特点包括:
-
提供许多 GCP 服务的开箱即用默认仪表板
-
支持运行时间监控并向各种类型的渠道发送警报
-
提供便捷的导航功能,能从警报、仪表盘、日志和跟踪中深入分析,快速识别根本原因
-
使用代理支持非 GCP 环境
云日志
这是 GCP 服务,它允许我们存储、搜索、分析、监控并对来自Google Cloud和Amazon Web Services的日志数据和事件进行警报。主要功能包括以下内容:
-
一项完全托管的服务,在规模化时能以亚秒级的延迟、每秒数 TB 的吞吐量运行
-
从一个地方分析跨多云环境的日志数据
-
能够从成千上万的虚拟机中摄取应用程序和系统日志数据
-
能够从流式日志中创建指标,并使用 BigQuery 实时分析日志数据
错误报告
这是 GCP 服务,它聚合、计数、分析并显示从运行云服务中产生的应用程序错误。主要功能包括以下内容:
-
专用的错误详细信息视图,包括时间图、出现次数、受影响的用户数、首次和最后一次出现的日期,以及清理后的异常堆栈跟踪
-
在清晰的仪表盘中列出最常见或最新的错误
-
持续分析异常并将其聚合成有意义的组
-
可以将罕见错误的发生转化为警报,以便立即处理
应用性能管理
这是 GCP 服务,它结合了 Cloud Logging 和 Cloud Monitoring 的监控与故障排除能力,并与 Cloud Trace、Cloud Debugger 和 Cloud Profiler 集成,帮助减少延迟和成本,并使我们能够更高效地运行应用程序。主要功能包括以下内容:
-
一种分布式跟踪系统(通过 Cloud Trace),它收集来自应用程序的延迟数据,以识别性能瓶颈
-
通过 Cloud Debugger 实时检查生产应用程序状态快照,无需停止或减慢应用程序,并提供在调试过程中注入日志消息的能力
-
通过统计技术实现低影响的生产分析(通过 Cloud Profiler),以交互式火焰图呈现相关功能的调用层次结构和资源消耗
整合所有内容 – 在 GCP 中构建 CI/CD 流水线的构建块
下图表示在 GCP 中构建 CI/CD 流水线所需的构建块:

图 1.5 – 表示 DevOps 生命周期的 GCP 构建块
在前述图表中,持续反馈/分析部分代表了 GCP 服务,用于分析或存储在持续监控/操作过程中获取的信息,这些信息来自事件驱动或合规视角。这完成了关于 Google Cloud 服务概览的部分,这些服务可以通过云原生方法实施 DevOps 生命周期的关键阶段,强调将复杂系统分解为微服务,从而可以独立测试和部署。
总结
在本章中,我们了解了 DevOps 实践,它打破了开发人员(他们总是希望将功能推向生产)与运维人员(他们希望可靠地运行服务)之间的隐喻性壁垒。
我们学习了 DevOps 生命周期、DevOps 的关键支柱、Google Cloud 如何通过 SRE 实现 DevOps 以及 Google 的云原生方法来实施 DevOps。我们了解了 SRE 的技术和文化实践,并且介绍了帮助构建 CI/CD 管道的关键 GCP 服务。在下一章中,我们将深入探讨 SRE 的技术实践,如 SLI、SLO、SLA 和错误预算。
需要记住的要点
以下是一些重要的要点:
-
如果 DevOps 是一种哲学,SRE 是实现这种哲学的规定性方法:类 SRE 实现 DevOps。
-
SRE 平衡开发特性的速度与可靠性风险。
-
SLA 代表外部协议,违反时会导致后果。
-
SLO 是衡量客户满意度和客户期望的方式。
-
SLI 最好以所有成功事件与有效事件的比例来表示。
-
错误预算是可用性的倒数,表示服务可以容忍的不可用程度。
-
Toil 是与生产系统相关的手动工作,但与开销不同。
-
统一愿景、沟通与协作的需求,强调无责后期分析(blameless postmortems),并需要鼓励心理安全,减少对变化的抵制,都是 SRE 文化实践的关键内容。
-
Google 强调使用微服务和云原生开发来进行应用程序开发。
-
无服务器服务是托管的,但托管服务不一定是无服务器的。
深入阅读
要了解 GCP 对 DevOps 方法的更多信息,请阅读以下文章:
-
DevOps:
cloud.google.com/devops -
Google Cloud 上的 CI/CD:
cloud.google.com/docs/ci-cd
实践测试
请回答以下问题:
-
以下哪项代表的是与用户体验密切相关并且对服务至关重要的一系列任务?
a) 用户故事
b) 用户旅程
c) Toil
d) 开销
-
如果某个服务的 SLO 设置为 99.95% 的正常运行时间,可能的 SLA 目标是什么?
a) 99.99
b) 99.95
c) 99.96
d) 99.90
-
以下哪项准确描述了 SLI 的公式?
a) 好事件 / 总事件
b) 好事件 / 总事件 * 100
c) 好事件 / 有效事件
d) 好事件 / 有效事件 * 100
-
以下哪项表示对某些服务级别方面的量化度量的精确定义?
a) SLO
b) SLI
c) SLA
d) 错误预算
-
选择用于计算错误预算的选项。
a) (100 – SLO) * 100
b) 100 – SLI
c) 100 – SLO
d) (100 – SLI) * 100
-
哪组 Google 服务准确地描绘了持续反馈循环?
a) 监控、日志记录、报告
b) Bigtable、Cloud Storage、BigQuery
c) 监控、日志记录、跟踪
d) BigQuery、Pub-Sub、Cloud Storage
-
以下哪种“持续”过程是自动将变更部署到生产环境,而无需手动干预?
a) 交付
b) 部署
c) 集成
d) 监控
-
选择一个选项,将计算服务按从最需要管理、最具自定义能力的服务到最少管理需求、最低自定义能力的服务进行排序。
a) Compute Engine、App Engine、GKE、Cloud Functions
b) Compute Engine、GKE、App Engine、Cloud Functions
c) Compute Engine、App Engine、Cloud Functions、GKE
d) Compute Engine、GKE、Cloud Functions、App Engine
-
Awesome Incorporated 计划将其本地 CI 流水线迁移到云端。以下哪项服务提供了托管在 GCP 上的私有 Git 仓库?
a) Cloud Source Repositories
b) Cloud GitHub
c) Cloud Bitbucket
d) Cloud Build
-
你的目标是将 SRE 文化实践引入组织中。选择两个可以帮助实现此目标的选项。
a) 启动并迭代。
b) 启动每日文化会议。
c) 临时团队组成。
d) 创建并传达清晰的信息。
答案
-
(b) – 用户旅程
-
(d) – 99.90
-
(d) - 好事件 / 有效事件 * 100
-
(b) - SLI
-
(c) – 100 – SLO
-
(d) – BigQuery、Pub-Sub、Cloud Storage
-
(b) – 部署(形成持续部署)
-
(b) – Compute Engine、GKE、App Engine、Cloud Functions
-
(a) – Cloud Source Repositories
-
(a) 和 (d) – 启动并迭代。创建并传达清晰的信息。
第二章:SRE 技术实践——深入解析
可靠性是服务或系统最关键的特性,应该与业务目标对齐。这种对齐需要不断追踪,也就是说,对齐情况需要通过度量来跟踪。站点可靠性工程(SRE)规定了特定的技术工具或实践,帮助衡量定义和跟踪可靠性的特征。这些工具包括服务级别协议(SLA)、服务级别目标(SLO)、服务级别指标(SLI)和错误预算。
SLA 代表与客户达成的关于服务可靠性的外部协议。如果违反 SLA(即服务未能满足可靠性期望),应该会有相应的后果,这些后果通常是金钱上的惩罚。为了确保 SLA 不会被违反,重要的是设置阈值。设置这些阈值可以确保在类似或相同事件重复发生之前,及时发现并处理事故,从而避免违反 SLA。这些阈值被称为 SLO。
SLO 是定义系统可靠性的特定数值目标,SLO 是通过 SLI 来衡量的。SLI 是衡量一段时间内提供的服务水平的量化指标。错误预算是基于 SLO(基于 SLI)计算的,实质上是可用性的逆指标,表示服务可能不可靠的量化目标。所有这些工具或技术实践需要协同工作,并且每个工具都依赖于其他工具。SRE 使用这些技术实践来维持创新与系统可靠性之间的平衡,从而实现最终目标——更快地构建可靠的软件。
第一章,DevOps、SRE 和 Google 云服务在 CI/CD 中的应用,介绍了 SRE 的技术实践——SLA、SLO、SLI 和错误预算。本章将深入探讨这些技术实践。在本章中,我们将涵盖以下主要内容:
-
定义 SLA
-
通过 SLO 定义可靠性期望
-
探索 SLI
-
理解错误预算
-
通过自动化消除繁琐工作
-
阐述 SLA、SLO 和错误预算相对于 SLI 的影响
定义 SLA
SLA 是对服务用户的承诺,表示服务的可用性和可靠性应达到一定的期望水平。SLA 详细说明了服务的某个性能或期望水平。
关键术语
在定义哪些协议可以视为 SLA 时,有一些特定的组成部分。它们使用特定的术语,并将在以下部分中详细说明。
服务提供者和服务消费者
代表服务提供方和服务消费者的方根据服务的背景和性质可能会有所不同。对于面向消费者的服务,如视频流媒体或网页浏览,服务消费者指的是使用服务的最终用户,服务提供方指的是提供该服务的组织。另一方面,对于像 人力资源(HR)规划系统这样的企业级服务,服务消费者指的是使用服务的组织,服务提供方指的是提供该服务的组织。
服务性能或期望
消费服务的组织或最终用户会对服务行为有一定的期望,例如 可用性(或 正常运行时间)、响应性、耐久性 和 吞吐量。
协议 —— 隐式或显式
协议或合同可以是隐式或显式的。例如,隐式合同的一个例子是 Google 搜索这样的非商业服务。Google 的目标是为所有用户提供流畅的搜索体验,但并未与最终用户签署明确的协议。如果 Google 未能实现其目标,用户将不会有良好的体验。此类事件的重复发生将影响 Google 的声誉,因为用户可能会选择使用其他搜索引擎。
一个明确合同的例子是像 Netflix 这样的商业服务,或像 Workday 这样的付费企业级服务。在这种情况下,会有法律协议,规定如果服务期望未能达成,将会有相应后果。常见的后果包括财务影响或服务积分。
这部分介绍了与 SLA 相关的关键术语。下一节将详细讲解明确定义的 SLA 的蓝图。
明确定义的 SLA 蓝图
拥有一个明确定义的 SLA 对于其成功至关重要。以下是一些可以作为明确定义的 SLA 蓝图的因素:
-
涉及相关方:SLA(服务级别协议)通常由与服务实施无直接关系的人编写,因此可能导致一些难以衡量的承诺。SLA 应由业务和产品负责人之间设定。然而,SRE(站点可靠性工程)建议,在设定 SLA 之前,产品负责人应与开发团队和 SRE 团队合作,识别服务能够实现的期望阈值。这可以确保产品负责人与实施团队密切合作,了解从服务的角度来看,什么是可以接受的,什么是不可实现的。
-
期望需要可衡量:服务期望,如可用性或可靠性特征,应该以稳定性、响应性和耐久性等方面进行量化和衡量。服务期望应通过配置监控系统并跟踪特定指标来进行监控,并应配置告警系统,在期望被违反时触发告警。
-
避免歧义:在定义 SLA 时使用的行业术语有时可能不明确。例如,考虑一个承诺在X小时内解决客户发起的事件的 SLA。如果客户或客户提供的详细信息是在事件首次报告后很久才提供的,或者根本没有提供详细信息,则可能服务提供商将无法解决该事件。在这种情况下,SLA 应清楚地说明不符合 SLA 的资格条件,并应排除这类情况。这提供了更清晰的方法。
SLI 驱动 SLO,进而确定 SLA。
SLA 应关注服务应达到的最低目标水平,以保持客户满意。然而,SLA 严格来说是外部目标,不应作为实施团队的内部目标。
为了确保不违反 SLA,实施团队应具有反映用户对服务期望的目标目标。实施团队的目标目标被用作内部目标,这些目标通常比产品团队潜在设置的外部目标更为严格。内部目标被称为 SLO,并被用作平衡发布速度和系统可靠性的优先信号。这些内部目标需要在特定时间点具体测量和量化。测量应使用反映用户期望的特定指标进行,这些指标被称为 SLI。
总结来说,为了确保服务的可靠性,需要满足以下几个标准:
-
应满足特定条件——由 SLI 表示。
-
特定条件应在特定目标范围内的特定时间段内得以满足——由 SLO 表示。
-
如果达到,客户会感到满意,否则将会有后果——由 SLA 表示。
让我们看一个假设的例子。考虑一个要求用户请求/响应时间在最短时间段内的要求。延迟度量可以用来表示用户的期望。在这种情况下,此场景中的样本 SLA 可以规定,每位客户将在 1,000 毫秒(ms)内得到响应。在这种情况下,此 SLA 的 SLO 必须更为严格,可以设定为 800 ms。
这完成了关于 SLA 的部分。我们看了 SLA 的关键结构,可能影响良好定义的 SLA 的因素,以及它对设定内部目标或 SLO 的影响,使用特定指标或影响客户满意度的 SLI。
通过 SLO 定义可靠性期望
服务消费者(用户)需要服务的可靠性,服务的可靠性可以通过多种特征来衡量,如可用性、延迟、时效性、吞吐量、覆盖率等。从用户的角度来看,如果服务符合他们的期望,那么服务就是可靠的。SRE 的一个关键目标是以定量的方式衡量一切。因此,为了进行衡量,需要定量表示用户期望。
SRE 推荐了一种特定的技术实践,叫做 SLO,用于指定一个目标水平(数值),以表示这些期望。每个服务消费者可能有不同的期望。这些期望应该是可衡量的,并且需要在一段时间内量化。SLO 帮助定义一致的用户期望水平,其中衡量的用户期望应当位于目标水平内或位于一个值的范围内。此外,SLO 被称为内部协议,通常比承诺给最终用户的 SLA 更为严格。这确保了在潜在问题出现之前得到解决,从而避免了重复发生时违反 SLA 的情况。
SLO 是推动业务决策的关键,它提供了一种可量化的方式来平衡服务功能的发布节奏与服务可靠性之间的关系。这个重点将在接下来的小节中讨论。
SLO 驱动业务决策
收入增长的需求使企业不断面临压力,要求增加新功能并吸引新用户。因此,产品经理通常会向开发团队下达这些新功能的需求。开发团队构建这些需求并交给运维团队以稳定服务。开发团队继续专注于为服务添加新功能,而不是稳定现有功能。运维团队往往会过载,因为他们不仅要处理现有服务的可靠性问题,还要推出新功能。所以,最重要的问题是:如果可靠性是系统的一个功能,那么你如何在发布其他功能的同时平衡可靠性?
SLO(服务水平目标)是如何在可靠性和发布速度之间保持平衡的答案。SLO 使我们能够为可靠的服务定义目标水平。这些目标水平应该由组织内的所有利益相关者共同决定,包括工程团队(开发和运维)以及产品团队。达成一致的目标水平应当反映用户在使用服务时的体验。这使得监控系统能够在用户提出投诉之前识别现有问题。SLO 应该更多地作为优先级信号来处理,而不是运营问题。
SLO 应该作为决策的主要驱动力。SLO 代表了所有可靠性对话的通用语言,它基于实际指标。这将使企业能够决定何时发布新功能,何时继续专注于现有服务的可靠性。它还将使运营团队拥有一套简化的目标,防止为运行服务而采取临时行动,最终避免操作过载。
操作过载是一个描述持续的维护任务的术语,这些任务保持系统和服务在最佳性能下运行。如果一个团队不断被操作负载打断,无法向其关键优先事项推进,那么该团队就处于操作过载状态。
团队处于操作过载状态的主要原因是对服务应支持的可靠性水平缺乏共识。这种共识的缺乏可以从开发团队专注于为服务添加新功能,而非稳定现有功能中看出。
SLO 必须得到执行团队的强力支持。如果未达到 SLO 目标,应有充分的文档记录后果,优先将工程工作集中于稳定服务的可靠性,而不是开发或发布新功能。SLO 是消除组织壁垒的关键,并创建共享责任感和所有权感。SLO 驱动着激励机制,能够自然而然地激发开发者开始关注服务的可靠性,运营者开始关注尽快推出新功能。设置 SLO 的推荐指南将在接下来的小节中详细介绍。
设置 SLOs – 指南
确定服务正确的 SLOs 的过程非常复杂。有多个方面或指导方针需要考虑。每个方面对设置或定义服务的 SLO 至关重要。
幸福测试
SLO 目标总是由可量化和可衡量的用户期望驱动,这些期望称为 SLI。幸福测试是设置服务 SLO 目标的一个良好起点。根据此测试,服务应具有满足用户可用性和可靠性期望的目标 SLO,正如以下所示:
-
如果服务满足目标 SLO,则用户会感到高兴。
-
如果服务未能达到目标 SLO,则用户会感到悲伤。
平均响应时间的目标 SLO 定义为 600 到 800 毫秒之间的范围。如果平均响应时间小于 800 毫秒,则服务满足目标 SLO,用户会感到高兴。如果平均响应时间大于 800 毫秒(即使它低于 SLA 规定的限制),则服务未能达到目标 SLO,用户会感到悲伤。以下图示说明了一个例子,其中关于请求的平均响应时间的 SLA 设置为 1,000 毫秒:

图 2.1 – 基于目标 SLO 的用户满意与不满意对比
100%的可靠性是错误的目标
可靠性是服务最重要的特性,它反映了用户的满意度。然而,将 100%设定为 SLO(服务级目标)或可靠性目标并不是一个现实且合理的目标,原因如下:
-
无法改善或添加新功能到服务:维持客户满意度是一项棘手的任务。客户总是期待新功能集的出现,但同时也希望现有服务的稳定性不受影响。在运行中的服务上添加新功能可能会引入一定的风险或不可靠性。如果服务的 SLO 目标设定为 100%,这意味着服务始终可靠,停机时间为零。因此,服务无法容忍任何停机风险,并且本质上不能向服务中添加新功能。如果无法向服务添加新功能,用户会感到不满,并转向提供类似服务且功能更多的竞争对手。
-
在技术上不可行:运行一个服务包括多个组件和依赖关系。其中一些是内部的,而一些是外部的。尽管这些组件可以通过冗余设计来实现高可用性,但这些依赖关系带来的复杂性可能会导致潜在的停机。此外,外部组件也会影响服务的可用性——例如,如果移动网络提供商在特定位置有死区,那么移动用户无法访问该服务。
-
呈指数增长的费用:每增加九个可靠性级别,成本就增加 10 倍。让一个可靠的系统变得更加可靠是非常昂贵的。选择足够可靠才是更明智的选择。
理解可靠性目标及其影响
由于 100%可靠性是错误的目标,因此寻找一个最佳的可靠性目标是很重要的,这个目标可以确保服务对用户足够可靠,同时也能提供更新或添加新功能的机会。
另一个观察服务可靠性目标的角度是服务能够容忍的不可靠性程度。服务的不可靠性也被称为停机时间。
我们来考虑一些可靠性目标,如下所示:
-
在 30 天的时间段内,99.9%的可靠性目标(也称为三九可靠性)将导致最大可能的停机时间为 42 分钟。这段时间足够监控系统检测到问题,也足够让人工介入并可能缓解或解决问题。
-
在 30 天的时间段内,99.99%的可靠性目标(也称为四九可靠性)将导致最大可能的停机时间为 4.2 分钟。这段时间足够让监控系统检测到问题,但不够让人工介入,不过可能足够让系统自行修复完全的故障。
-
99.999%(即五个九的可靠性)在 30 天内的可靠性目标意味着最大停机时间为 24 秒。这种极短的时间不足以检测问题,甚至无法尝试自我修复。
下表总结了基于 30 天内可靠性目标,检测问题的可能性以及自愈的可能性:

总结来说,可靠性目标应该设定为一个现实的水平,在该水平下问题可以被检测并解决。推荐使用自动化的自愈过程,而不是人工干预——例如,在现有的可用区(AZ)发生故障时,将流量重定向到新的可用区。
设置过低的可靠性目标意味着问题可能频繁发生,导致长时间的停机,客户将经常受到影响。将可靠性目标设置得过高,比如 99.999% 或甚至 100%,意味着系统几乎无法失败,这使得难以向服务或应用程序添加新特性。
设置 SLO 是一个迭代过程。
可靠性是服务最重要的特性,设置 SLO 可以让监控系统捕获服务的表现。在首次设置 SLO 时,可以基于过去的表现设定 SLO,假设用户一开始是满意的。这些 SLO 的 SLI 基于现有的监控系统,并被视为必须达到的初始基线。这类 SLO 被称为可实现的 SLO,任何低于初始基线的偏差应当引导工程工作集中在恢复可靠性到初始基线。
如何开始设置可实现的 SLO
用于设置可实现 SLO 的指标可以从负载均衡器获取,或者从日志中反向填充。这两种方法都能提供对历史性能的洞察。
如果在没有历史数据的情况下需要设置 SLO,或者历史数据无法准确反映用户期望,建议设置一个可实现的目标,然后根据用户期望和业务需求精细化目标。这类 SLO 被称为期望的 SLO。监控系统随后将使用这些指标来跟踪这些 SLO。
一旦设定了可实现或期望的 SLO,服务可能会引入新特性,但服务不可靠的概率也会增加。这可能导致即便满足了 SLO,客户依然不满意。这表明监控指标需要重新审视。SLO 需要进行迭代设置并定期重新评估。这些指标在最初设置时可能有效,但现在可能不再适用。
以下是一些可能需要重新评估 SLO 的情况:
-
新特性在指标计算中未被考虑。
-
服务的使用已从桌面扩展到移动设备。
-
服务的使用现已扩展到多个地区。
SLO 应该多久回顾或重新评估一次?
建议每 6 至 12 个月回顾或重新评估 SLO,以确保已定义的 SLO 继续与业务变化和用户期望保持一致。
除了定期回顾 SLO 外,当预期流量激增时,还可以使用不同的 SLO——更精确地说,是更严格的 SLO。例如,在假日购物期间,许多企业预期流量会显著激增,在这种情况下,企业可以制定一个临时策略,将 SLO 从 99.9% 收紧到 99.99%。这意味着系统可靠性被优先考虑,而不是急于发布新功能。当正常流量恢复时,SLO 目标将恢复到原始值(在本例中为 99.9%)。
这一部分完成了关于 SLO 的讨论,深入探讨了可靠性的需求、设置可靠性目标以及 SLO 如何通过 SLIs 推动业务决策。下一小节介绍了为什么 SLO 需要 SLIs,也为深入探讨 SLIs 做了铺垫。
SLO 需要 SLI
SLO 是定义系统可靠性的具体数值目标。SLO 也是一种优先级信号,用来平衡创新和可靠性之间的关系。SLO 还帮助区分快乐用户和不满用户。但引人深思的问题是:我们如何衡量 SLO?
SLO 通过 SLI 来衡量。SLI 定义为可量化的服务可靠性指标,具体显示服务在特定时刻的表现。服务消费者对服务有一定的期望,SLI 直接与这些期望挂钩。可量化的 SLI 示例包括 延迟、吞吐量、新鲜度 和 正确性。SLI 以有效事件中的良好事件百分比表示。SLO 是在一段时间内汇总的 SLI 目标。
我们将在下一节中深入探讨 SLIs,探索 SLIs。这包括按用户旅程类型对 SLIs 进行分类,并详细说明如何衡量 SLIs。
探索 SLIs
SLI 是一种定量衡量服务可靠性某一方面的指标。服务的各个方面直接依赖于潜在的用户旅程,而每个用户旅程可以有不同的 SLI。确定每个用户旅程的 SLI 后,下一步关键是确定如何衡量 SLI。
本节介绍了如何通过对用户旅程进行分类来识别合适的衡量指标或 SLI、衡量 SLI 的公式以及衡量 SLIs 的方法。
分类用户旅程
服务的可靠性是基于用户的视角。如果服务提供多个功能,则每个功能都将涉及一组用户交互或一系列任务。定义为用户旅程的服务提供的用户体验的关键任务序列。
使用视频流服务时的一些用户旅程示例如下:
-
在特定类别下浏览标题——例如,小说
-
查看用户库中现有的标题
-
购买点播节目或直播流
-
查看直播流
每个用户旅程都可能有不同的期望。这些期望可以从服务响应用户请求的速度、数据处理速度、显示数据的新鲜程度,以及数据存储的持久性等方面变化。
可能存在许多跨多个服务的用户旅程。为简单起见,用户旅程可以分为两个流行类别,如下所示:
-
请求/响应 用户旅程
-
数据处理/流水线-基于用户旅程
每个类别定义了特定的特征。每个特定特征可以代表一种 SLI 类型,用于定义服务的可靠性。这些在以下各节中指定。
请求/响应用户旅程
可用性、延迟和质量是请求/响应用户旅程作为 SLI 的具体方面或特征,需要进行评估。
可用性
可用性 定义为成功服务有效请求的比例。服务的可用性对满足用户期望至关重要。
要将可用性 SLI 定义转换为实施,需要做出一个关键选择:如何将服务成功的请求分类?
要将成功服务的请求分类,可以使用错误代码反映用户对服务的体验——例如,搜索不存在的视频标题不应导致500系列错误代码。然而,无法执行搜索以检查视频标题是否存在,应导致500系列错误代码。
延迟
延迟 定义为在阈值以下提供有效请求的比例。在服务用户交互请求时,及时响应是可靠性的重要指标。
对于给定请求的延迟是在计时器启动和停止之间的时间差。要将延迟 SLI 定义转换为实施,需要做出一个关键选择:如何确定将响应分类为足够快?
要确定将响应分类为足够快的阈值,首先要识别不同类别的用户交互,并相应地设定阈值。有三种方式来对用户交互进行分桶,具体如下:
-
交互式——指用户在点击元素后等待系统响应的交互。也可称为读取,典型的阈值为 1,000 毫秒。
-
写入——指对底层服务进行更改的用户交互。典型的阈值为 1,500 毫秒。
-
后台——指用户的异步交互。典型的阈值为 5,000 毫秒。
质量
质量被定义为无服务降级地提供的有效请求的比例。这是一个重要的指标,用于判断当服务的依赖不可用时,服务如何优雅地失败。
要将质量 SLI 转换为实现,必须做出一个关键选择:如何判断响应是否因质量下降而被服务?要对质量下降的响应进行分类,考虑一个拥有多个后端服务器的分布式系统。如果传入的请求由所有后端服务提供,那么请求将不受服务降级的影响。然而,如果传入的请求仅由所有后端服务器中的一个处理,则表示响应质量下降。
如果请求在服务降级的情况下处理,则应将响应标记为降级,或者应使用计数器增加降级响应的计数。因此,质量 SLI 可以表示为 坏事件 与 总事件 的比率,而不是 好事件 与 总事件 的比率。
如何将请求分类为有效的
要将请求分类为有效的,可以使用不同的方法。一个方法是使用 400 错误作为客户端错误,在衡量服务可靠性时应被丢弃。500 错误是服务器端错误,应从服务可靠性角度视为失败。
基于数据处理/管道的用户旅程
新鲜度、正确性、覆盖率和吞吐量是 SLIs 需要评估的特定方面或特征,作为数据处理/管道基础的用户旅程的一部分。这同样适用于基于批处理的作业。
新鲜度
新鲜度被定义为比某个阈值更近期更新的有效数据的比例。新鲜度是处理一批数据时可靠性的一个重要指标,因为随着时间的推移,输出可能变得不再相关。主要是因为新的输入数据会被生成,如果数据没有定期处理或通过小的增量持续重建处理,那么系统输出将无法有效反映新的输入。
要将新鲜度 SLI 转换为实现,关键的选择是:何时开始和停止计时器来衡量数据的新鲜度?为了将已处理的数据分类为有效的 SLI 计算,必须考虑正确的输入数据来源或正确的数据处理管道任务。例如,若要计算天气流内容的新鲜度,则无法考虑来自体育流管道的数据。这种级别的决策可以通过实现代码和规则处理系统来完成,从而映射适当的输入源。
为了确定何时开始和结束计时以衡量数据的新鲜度,生成和处理数据时包含时间戳是非常重要的。在批处理系统的情况下,如果下一批数据尚未处理和生成,则数据被视为新鲜。换句话说,新鲜度是自上次批处理系统完成以来经过的时间。
在增量流式系统中,"新鲜度"指的是已完全处理的最新记录的年龄。提供过时的数据是常见的质量下降方式。将过时的数据作为质量下降进行衡量是一种有效的策略。如果没有用户访问过时数据,则不会错过任何关于数据新鲜度的期望。为了实现这一点,一个选择是与生成数据一起包含时间戳。这允许服务基础设施检查时间戳,并准确判断数据的新鲜度。
正确性
正确性被定义为生成正确输出的有效数据的比例。它是可靠性的一个重要指标,其中处理一批数据将得到正确的输出。将正确性 SLI 转换为其实现时,一个关键的选择是:如何确定输出记录是否正确?
要判断输出记录是否正确,常见的策略是使用黄金输入数据,也称为一组始终产生相同输出的输入数据。通过这种方式,生成的输出可以与黄金输入数据的预期输出进行比较。
强烈建议采用主动测试实践——包括手动和自动化测试——来判断正确性。
覆盖率
覆盖率被定义为成功处理的有效数据的比例。它是可靠性的一个重要指标,其中用户期望数据将被处理,并且随后也可以获得输出结果。
要将覆盖率 SLI 转换为实现,需要做出的选择是:如何判断特定数据是否已成功处理?判断特定数据是否成功处理的逻辑应内置于服务中,并且服务应跟踪成功和失败的计数。
挑战出现在本应处理的一组记录被跳过时。可以通过识别应该处理的记录总数来了解未被跳过的记录比例。
吞吐量
吞吐量定义为数据处理速率高于某个阈值的时间比例。它是数据处理系统可靠性的重要指标,准确代表了用户的满意度,并且在数据流或小批量数据上持续运行。
要将吞吐量 SLI 转换为实施,一个关键选择是:数据处理的度量单位是什么? 数据处理最常见的度量单位是每秒字节数(B/s)。
并不是所有输入集都需要具有相同的吞吐量。一些输入需要更快地处理,因此要求更高的吞吐量,而另一些输入通常会被排队,稍后处理。
针对基于数据存储的用户旅程推荐的 SLI
数据处理系统还可以进一步分类为仅负责存储数据的系统。因此,数据存储用户旅程是另一种可能的用户旅程分类,在这种分类中,可用性、耐久性和端到端延迟是其他推荐的 SLI。可用性指的是可以按需从存储系统访问的数据。耐久性指的是写入的记录在需要时能够成功地从存储系统读取的比例。端到端延迟指的是处理数据请求的时间,从数据摄取到完成。
下表总结了具体特征,以表示不同类型的 SLI,按用户旅程类型分组:

鉴于可以选择的 SLI 种类繁多,Google 根据系统类型推荐以下特定的 SLI:
-
面向用户的服务系统:可用性(是否能够响应请求?)、延迟(响应需要多长时间?)和吞吐量(能够处理多少请求?)
-
存储系统:延迟(读取或写入数据需要多长时间?)、可用性(数据可以按需访问吗?)和耐久性(数据在需要时是否仍然可用?)
-
大数据系统:吞吐量(可以处理多少数据?)和端到端延迟(数据从摄取到完成需要多长时间?)
鉴于我们已经看到了影响确定特定用户旅程 SLI 的各种因素,接下来的小节将重点讨论测量 SLI 的方法论和来源。
SLI 方程
一个 SLI 方程被定义为良好事件的有效比例,如下所示:

该方程具有以下属性:
-
SLI 以百分比表示,范围在 0%到 100%之间。 100%表示一切正常,0%表示一切故障。
-
SLI 始终转化为百分比可靠性、SLO 和错误预算,并且也是警报逻辑的关键输入。
-
SLI 允许我们构建通用工具来反映服务或系统的可靠性。
-
有效事件的确定方法如下:对于与HTTP Secure(HTTPS)相关的请求,有效事件是基于请求参数或响应处理程序来确定的。 请求参数可以包括主机名或请求路径。 对于与数据处理系统相关的请求,有效事件是指选择特定输入,范围限定为数据的一个子集。
这完成了我们对 SLI 方程及其相关属性的总结。 下一小节详细介绍了衡量 SLI 的各种流行来源。
衡量 SLI 的来源
识别服务的潜在用户旅程是识别 SLI 的第一步。 一旦确定了要衡量的 SLI,下一步是衡量 SLI,以便可以设置相应的警报。 这个过程中的关键问题是:如何衡量以及在哪里衡量?
有五个流行的来源或方式来衡量 SLI,具体如下:
-
服务器端日志
-
应用服务器
-
前端基础设施
-
合成客户端
-
遥测
服务器端日志
以下是如何利用服务器端日志中的信息来衡量 SLI 的细节:
-
日志捕获多个请求-响应交互,跨越一个长时间运行的会话。 存储的日志提供了获取服务历史性能洞察的选项。
-
如果开始设置 SLO(SLO 需要 SLI)以进行服务,日志数据可以用来分析历史事件、重建用户交互并追溯填充 SLI 信息。
-
可以将复杂的逻辑添加到代码本身,其中良好的事件被清楚地标识,并且信息会被记录到日志中。 (这需要大量的工程工作。)
以下是使用服务器端日志衡量 SLI 的局限性详情:
-
如果 SLI 需要触发紧急响应,事件发生和事件实际被衡量之间的时间应最小化。 考虑到日志需要被摄取和处理,从日志中捕获 SLI 会增加显著的延迟。
-
基于日志的 SLI 无法捕获未到达应用服务器的请求。
应用服务器
以下是如何利用应用服务器中的信息来衡量 SLI 的细节:
-
在应用服务器上捕获的指标被称为应用层指标。 这些指标有助于诊断与应用相关的问题。
-
应用指标可以捕获单个请求的性能,而不会增加衡量延迟。 此外,这些事件可以随时间汇总。
以下是使用应用服务器衡量 SLI 的局限性详情:
-
应用程序指标无法捕捉复杂的多请求用户旅程。
-
基于应用的 SLI 无法捕捉到未到达应用服务器的请求。
什么是复杂的多请求用户旅程?
一个复杂的多请求用户旅程将包括一系列请求,这是用户消费服务的核心部分,例如搜索产品、将产品添加到购物车并完成购买。应用程序指标无法捕捉用户旅程的度量,但可以捕捉与单个步骤相关的度量。
前端基础设施
以下是如何使用前端基础设施的信息来测量 SLI 的详细信息:
-
前端基础设施是指负载均衡器。这可以是基于供应商的负载均衡器(例如F5)或基于云服务提供商的负载均衡器(例如Google Cloud Load Balancer)。
-
大多数分布式应用程序使用负载均衡器,这是用户请求发送到实际应用程序之前的第一个交互点。这使得负载均衡器成为最接近用户的点,且较少的请求会被遗漏度量。
-
云服务提供商通常会为负载均衡器接收到的请求捕捉多个度量,这些信息可能是现成可用的,包括历史数据。如果由于某种原因未配置数据捕捉,则可以轻松配置。无论如何,这些信息将是可用的,无需投入工程精力(与从应用日志捕捉度量相比)。
-
负载均衡器捕捉到的度量与未到达应用服务器的请求相关。
以下是使用前端基础设施测量 SLI 的限制的详细信息:
-
负载均衡器可以是有状态的或无状态的。如果是无状态的,那么负载均衡器无法追踪用户会话,因此无法用于捕捉与用户交互相关的度量。
-
鉴于负载均衡器通常充当交通警察,将用户请求路由到能够处理请求的应用服务器,负载均衡器本身并不控制由应用程序返回的响应数据。相反,负载均衡器依赖于应用程序在响应信封上准确地设置元数据。
-
依赖应用程序在响应信封上设置正确的元数据是一个利益冲突,因为生成度量的正是这个应用程序。
合成客户端
以下是如何使用合成客户端的信息来测量 SLI 的详细信息:
-
合成客户端提供合成监控,这是一种通过模拟或仿真基于一组已记录的事务的用户交互来监控应用程序的监控技术。
-
合成客户端可以模拟构成用户旅程的用户交互,这些交互发生在基础设施之外,因此可以验证响应。
以下是使用合成客户端测量 SLI 的限制的详细信息:
-
合成客户端模拟用户的行为,因此它是一种近似值。
-
合成客户端需要复杂的集成测试,覆盖多个边缘情况,因此需要大量的工程工作。
-
如果出现新的用户行为模式,合成客户端需要维护以添加新的用户模拟,而这些行为模式之前并未考虑到。
遥测
遥测是指来自多个数据源的远程监控,不仅限于捕获与应用程序健康相关的指标,还可以扩展到捕获安全分析,如可疑的用户活动、不寻常的数据库活动等。以下是遥测信息如何用于衡量 SLI 的细节:
-
为客户端添加遥测指标有助于衡量第三方集成系统的可靠性,例如内容分发网络(CDN)。
-
OpenTelemetry 是最流行的仪表机制,用于捕获跟踪和指标。它取代了OpenTracing 和 OpenCensus,这两个项目分别专注于捕获跟踪和指标。
什么是 OpenTelemetry?
OpenTelemetry 是一种统一的服务仪表标准。它提供了一套应用程序编程接口(API)/库,具有供应商中立性,并标准化了如何收集和发送数据到兼容的后端。OpenTelemetry 是一个开源项目,属于云原生计算基金会(CNCF)。
以下是使用遥测来衡量 SLI 的限制细节:
-
从不同来源获取指标会增加延迟,并且会遇到捕获处理日志时所遇到的相同问题,因此这不适合用于触发紧急响应。
-
如果遥测是内部实现的,它需要大量的工程工作。然而,也有供应商提供相同的能力,但存在供应商锁定的风险。
以上完成了衡量 SLI 的五个不同来源的详细说明。由于每个来源都有其自身的限制,因此没有最佳来源来衡量 SLI。在大多数情况下,始终推荐使用多个来源的组合。例如,如果一个组织刚开始进行 SRE 实践,可以使用服务器端日志来回填 SLI,并使用前端基础设施直接从负载均衡器获取指标,作为起步的好方法。稍后可以扩展到从应用服务器捕获指标,但考虑到它不支持复杂的多请求用户旅程,组织可以根据需求转向使用遥测或合成客户端。下一小节总结了 Google 推荐的几条 SLI 最佳实践。
SLI 最佳实践(Google 推荐)
对于希望开始 SRE 之旅的组织来说,这是一项繁琐的任务,旅程的关键部分是识别、定义和衡量 SLI。以下是 Google 推荐的最佳实践:
-
优先考虑用户旅程:选择反映服务所提供特性和用户对这些特性亲和力的用户旅程。
-
优先考虑选定列表中的用户旅程:购买或观看流媒体事件的用户旅程比给视频评分更为重要。
-
限制 SLI 的数量:每个用户旅程保持三到五个 SLI。更多的 SLI 会使运维人员管理起来更复杂。
-
通过前端基础设施收集数据:在负载均衡器级别收集数据更接近用户的体验,且需要的工程工作较少。
-
汇总相似的 SLI:在一段时间内收集数据。将捕获的度量信息转换为比率、平均值或百分位。
-
保持简单:复杂的度量需要大量工程工作,但也可能增加响应时间。如果响应时间增加,那么该度量将不适用于紧急情况。
这完成了对 SLI 的全面深入分析,重点是分类用户旅程、识别影响用户旅程的具体因素、各种度量来源以及定义 SLI 的推荐最佳实践。总结来说,选择 SLI 有四个关键步骤,列举如下:
-
根据合适的用户旅程选择一个 SLI 规范。
-
将规范细化为详细的 SLI 实现。
-
跟踪用户旅程并识别实现差距。
-
根据业务需求设定有远见的 SLO 目标。
接下来的章节聚焦于错误预算,它们用于通过保持发布速度的平衡来实现可靠性。
理解错误预算
一旦基于特定用户旅程的 SLI 设定了 SLO,这些 SLO 通过量化用户的期望来定义系统的可用性和可靠性,就需要理解服务允许的不可靠程度。这个可接受的不可靠性或不可用性水平被称为错误预算。
服务的不可用或不可靠可能由多种原因造成,如计划维护、硬件故障、网络故障、错误修复和在引入新特性时出现的新问题。
错误预算为可追踪的不可用量设定了量化目标。它们在开发和运维团队之间创造了共同的激励。这一目标用于平衡推动新特性(从而为服务添加创新)的冲动与确保服务可靠性之间的关系。
错误预算基本上是可用性的反面,它告诉我们服务允许的不可靠程度。如果 SLO 规定在一个季度内 99.9%的请求应成功,那么错误预算允许 0.1%的请求失败。这种不可用性可能是由于产品团队的不当推送、计划维护、硬件故障和其他问题引起的:

这是一个示例。如果 SLO 规定在一个季度内 99.9%的请求应成功,那么 0.1%就是错误预算。
让我们计算错误预算,如下所示:
如果 SLO = 99.9%,则错误预算 = 0.1% = 0.001
每月允许的停机时间 = 0.001 * 30 天/月 * 24 小时/天 * 60 分钟/小时 = 43.2 分钟/月
这引入了错误预算的概念。下一小节将介绍错误预算政策的概念,并详细说明高层支持在遵守错误预算政策方面的重要性。
错误预算政策和高层支持的必要性
如果可靠性是系统最重要的特性,那么错误预算政策代表了企业如何在可靠性与其他特性之间进行平衡。这样的政策有助于企业在服务可靠性面临风险时采取适当的行动。定义错误预算政策的关键是实际确定服务的 SLO。如果服务未达到 SLO 目标,意味着错误预算政策被违反,那么就应该有相应的后果。这些后果应通过高层支持来执行。运营团队应当影响开发团队实践的结果,如果服务接近耗尽错误预算或已超出错误预算,应暂停发布新功能。
错误预算可以被看作是计划在给定时间段内支出的资金。这些资金可以用于发布新特性、推出软件更新或管理事件。错误预算本质上是可用性的逆向概念,它告诉我们服务可以容忍的不可用程度。如果你的 SLO 规定在某个季度 99.9%的请求应该是成功的,那么你的错误预算允许 0.1%的请求失败。这种不可用性可能是由于产品团队的错误推送、计划中的维护、硬件故障等原因造成的。下一小节列出了有效错误预算政策的特征。
有效错误预算政策的特征
一个错误预算政策应具有以下特征:
-
服务概述
-
预期目标列表
-
非目标列表;也称为被特别排除的潜在需求
-
根据服务是否超出或未达 SLO,列出应该做的和不应该做的事项
-
当服务未能达到其 SLO 时的后果列表
-
详细的停机政策,定义何时称为事件以及需要跟进以确保该事件不再发生
-
明确的升级政策,识别在出现分歧时的决策者
前述特性列表清楚地指出,拥有良好的 SLO 文档对于定义有效的错误预算政策是极其必要的。这个问题将在下一小节讨论。
错误预算需要有良好的 SLO 文档
定义错误预算的关键在于实际决定服务的 SLO(服务级别目标)。SLO 清晰地区分了可靠服务和不可靠服务,从而扩展到区分高兴的用户和不高兴的用户。SLO 应该被清晰地定义,不应有任何模糊性,并且应该得到产品负责人、开发人员、SRE 和高管的一致同意。
除了实施 SLO 并配置监控系统来对 SLO 进行警报外,以下是推荐的 SLO 元数据文档特性:
-
SLO 的需求以及制定具体 SLO 目标的思考过程
-
SLO 的所有者列表
-
SLO 未达成时的影响
-
与 SLO 相关联的 SLIs(服务级别指标)
-
包括或排除在计算中的特定事件
-
SLO 文档的版本控制(这可以洞察 SLO 在一段时间内精炼过程中的变更原因)
下一小节将讨论设置错误预算的多种选项。
设置错误预算
错误预算可以被视为计划在给定时间段内使用的资金。这些资金可以用来发布新功能、推出软件更新或处理事件。但这也引发了几个问题,例如:
-
花费错误预算的最佳时机是什么?是月初还是月末?
-
如果错误预算用尽且发生了紧急情况,会怎样?
-
如果错误预算没有用尽,会怎样?可以转移到下一个周期吗?
可以使用不同的策略来确定在一个时间周期内花费错误预算的最佳时机。假设时间周期是 28 天。以下是三种潜在选项:
-
选项 #1 是在周期开始时(28 天的开始)花费部分错误预算来推动新功能或更新,并将剩余的错误预算用于可能的可靠性维护,以应对潜在事件。
-
选项 #2 是在经过一半时间周期(比如 14 天)后,使用错误预算来推动新功能或更新,因为这样可以了解在前半段时间里,为了维持系统可靠性所使用的错误预算。
-
选项 #3 是在时间周期的后半段,使用剩余的错误预算来推动新功能或更新,以确保在此之前,系统的可靠性得到关注。
任何上述选项或三者的组合都可以用于定义一个动态发布过程,具体取决于开发人员和运营团队基于当前业务需求和过去表现达成的共识。可以通过根据错误预算的耗尽速率设置警报来实现动态发布过程。
如果服务的错误预算用尽,但开发团队需要作为例外情况推动新功能,SRE 将使用 银弹 来处理这个例外。
将银弹视为可给予运营团队的令牌,用以在超过错误预算的情况下允许发布新功能。这些令牌由高级利益相关者持有,开发团队需要向利益相关者陈述使用银弹的必要性。一定数量的银弹令牌交给利益相关者,并且这些令牌不可以转移到下一个时间周期。除了使用银弹之外,SRE 还建议使用备用资金,即在处理意外事件时提供一定量的错误预算。
错误预算不能转移到下一个时间周期。因此,实际上,目标是要在当前时间周期结束之前花完错误预算。不断耗尽错误预算和重复使用银弹应当引起审查,工程团队应当投入精力通过改进服务代码和添加集成测试来提升服务的可靠性。
动态发布节奏、错误预算耗尽率、银弹策略和备用资金等方法是 SRE 提出的先进技术,用于管理错误预算。这完成了关于有效错误预算策略定义特征的小节,列出了文档完善的 SLO(服务水平目标)的特征,并讨论了设置错误预算的选项。接下来的小节详细介绍了确保服务保持可靠并避免耗尽错误预算的关键因素。
提高服务可靠性
当服务耗尽其错误预算或反复接近耗尽时,工程团队应将重点放在提高服务可靠性上。这引出了下一个显而易见的问题:工程团队如何才能提高服务的可靠性,以满足用户的期望?
为了深入了解这一点,必须考虑以下关键因素,这些因素对确定服务潜在影响至关重要:
-
检测时间(TTD)—定义为从问题首次发生到问题首次被观察或报告的时间差。例如:如果一个问题发生在上午 10 点,但在上午 10:30 被报告或观察,那么此情况下的 TTD 为 30 分钟。
-
解决时间(TTR)—定义为从问题首次观察或报告到问题解决的时间差。例如:如果一个问题在上午 10:30 被首次观察或报告,但在上午 10:45 解决,那么此情况下的 TTR 为 15 分钟。
-
故障时间(TTF)—定义为服务预期发生故障的频率。TTF 也被称为故障间隔时间(TBF)。
-
影响百分比(Impact %)—表示受影响用户或受影响功能区域的百分比。
-
预期的影响与以下公式成正比:

通过实施以下选项可以提高可靠性:
-
缩短检测时间:减少 TTD
-
减少修复时间:减少 TTR
-
减少影响百分比:减少受影响的用户/功能区域
-
减少频率:增加 TTF
-
操作性改进
接下来,让我们详细讨论每个选项。
减少检测时间(TTD)
可以通过以下方法减少 TTD:
-
添加自动化警报,提醒用户,而不是让用户通过注意到度量仪表板上的异常来手动检测问题。
-
添加监控以衡量 SLO 合规性。这有助于了解错误预算消耗的速度,或服务是否在目标 SLO 内运行。
减少修复时间(TTR)
TTR 可以通过以下方法减少:
-
制定一本操作手册,简化服务器调试日志的解析和汇总。这将帮助现场工程师快速解决当前的问题。如果检测到新模式,应更新操作手册。
-
自动化手动任务,例如将磁盘空间增加到当前磁盘空间的可接受百分比,清理区域或重新路由流量。
-
收集特定场景的相关信息,这将为值班团队节省时间,并帮助他们在调查时抢占先机。
减少影响百分比
影响百分比可以通过以下方法减少:
-
通过基于百分比的发布将新功能推送给有限数量的用户,并在规定的时间内逐步增加。这会将影响百分比限制在特定的用户组。发布百分比可以从 0.1%的用户逐步增加到 1%,然后到 10%,最终达到 100%。通过这种方式,发布是分阶段进行的。
-
在故障发生时,使服务以降级模式运行,例如切换到只允许读取操作而不允许写入,从而减少影响。
减少频率
可以通过以下方法减少频率:
-
在多个区域或区域内运行服务或应用程序。将流量从故障的区域或区域引导到另一个正常工作的区域或区域。
-
创建一个自愈的自动化脚本,减少影响和频率,但也报告问题,以便以后解决。
操作性改进
以下是从操作角度来看,确保服务可靠性的一些选项:
-
通过增加冗余来提高可用性,从而消除单点故障。
-
确定失败之间的共同类别,这可以指向特定区域或一组客户,这些客户消耗了大部分的错误预算。
-
标准化基础设施或最小化差异,以便在测试服务与在生产中运行服务时获得相似的结果。
-
使用设计模式,使服务在出现问题时可以回滚。
-
通过跟踪错误预算消耗率来创建警报。
-
使用事后分析(post-mortem)来识别当前的问题,并创建可操作的事项来解决这些问题。
这完成了对需要考虑的潜在因素的深入探讨,以及可实施的可行选项,以确保服务的可靠性,从而不消耗错误预算。下一小节总结了错误预算的部分内容。
总结错误预算
错误预算可以通过以下关键要点进行总结:
-
错误预算帮助开发和 SRE 团队平衡发布速度和稳定性。管理层认同 SLO,并给予执行支持。
-
错误预算需要 SLO,而 SLO 需要 SLIs 来监控服务的可靠性。
-
通过计算实际与目标 SLO 之间的差异,来确定是否低于错误预算,如果是的话,可以允许发布新特性。
-
如果没有,工程工作应集中在服务的可靠性上。
-
错误预算政策是一种有效实施错误预算概念的方法。
这完成了关于错误预算的部分,深入探讨了多个方面,包括如何定义有效的错误预算政策、如何设定错误预算、管理层的支持如何帮助使服务更可靠,以及如何有效平衡新特性的发布速度。
通过自动化消除重复性工作
重复性工作在第一章中介绍,《DevOps、SRE 和 Google Cloud 服务用于 CI/CD》,并定义为与生产服务相关的工作,其特点是手动、重复、可自动化、战术性、缺乏持久价值,并且随着服务的增长而线性增加。重复性工作常常与管理性工作混淆,但管理性工作指的是包括电子邮件、通勤、报销报告和开会等行政事务。重复性工作既可以是好的,也可以是坏的——这取决于重复性工作的数量。
以下是执行重复性工作的积极方面,但必须在非常短且有限的时间内进行:
-
产生满足感或成就感
-
可以作为一种低压力或低风险的活动
-
可用于培训新员工,尤其是提供他们通过亲自操作系统来学习内部工作原理的机会
然而,过多的重复性工作可能导致以下问题或困扰:
-
职业停滞:解决生产问题令人满足,但以重复的手动方式解决相同问题对职业发展没有帮助。这剥夺了 SRE 工程师的学习时间和意图,导致职业停滞。
-
倦怠和无聊:过多的重复性工作会导致倦怠和无聊。SRE 工程师每天做同样的任务会感到厌倦。有时,手动任务也可能枯燥且费力,最终导致倦怠。
-
低特性发布速度:如果 SRE 团队从事大量重复性工作,他们将会减少用于发布新特性的时间,从而导致特性发布速度变慢,发布频率降低。
-
错误的优先级:如果 SRE 团队承担的重复劳动超过了必要的范围,开发团队可能会让 SRE 团队做更多的重复劳动,特别是对于那些开发团队真正需要处理的问题,而不是仅仅消除根本原因。这将导致 SRE 工程师的角色产生混淆。
所有上述问题或挑战可能会导致人员流失,因为 SRE 工程师可能对日常工作不满意,并可能寻求其他地方的更好工作和挑战。SRE 建议将重复劳动限制在一定范围内,SRE 工程师应避免超过 50%的时间用于重复劳动。超过 50%将模糊 SRE 工程师和系统管理员之间的界限。建议 SRE 工程师将剩余的 50%时间用于支持工程团队实现服务可靠性目标。
消除重复劳动使 SRE 工程师能够添加服务功能,以提高服务的可靠性和性能。此外,可以继续关注消除已识别的重复劳动,从而清除任何手动重复工作的积压。SRE 鼓励使用工程概念来消除手动工作。这还允许 SRE 工程师比开发或运维团队更好地扩展和管理服务。
SRE 建议通过自动化消除重复劳动。自动化提供了一致性,并消除了疏忽和错误的发生。自动化帮助比人工更快地执行任务,并且可以按计划进行。自动化还确保了在问题重新发生之前加以预防。自动化通常是通过代码实现的,这也为 SRE 工程师提供了一个使用工程概念来实现所需逻辑的机会。
本节总结了重复劳动的特点、利与弊,以及使用自动化消除重复劳动的优势。接下来的部分将说明基于 SLI 表现,SLA、SLO 和错误预算如何受到影响。
说明 SLAs、SLOs 和错误预算相对于 SLI 的影响
本节我们将通过两个实际场景,说明如何基于 SLI 表现来达成或未达成 SLO 目标。SLO 的表现将直接影响 SLA 和错误预算。错误预算的变化将特别决定新功能发布与服务可靠性之间的优先级。为了便于说明,这里采用 7 天作为时间度量(理想情况下,建议使用 28 天的周期)。
场景 1 – 引入新服务功能;功能可靠;SLO 达成
以下是该场景的期望:
-
预期 SLA—95%
-
预期 SLO—98%
-
测量的 SLI—服务可用性或正常运行时间
-
测量时长—7 天
考虑到服务的预期 SLO 为 98%,以下是如何计算允许的停机时间或错误预算(您可以参考此停机时间计算器:availability.sre.xyz):
-
错误预算 = 100% - SLO = 100% - 98% = 2%
-
7 天内允许的停机时间(98%的可用性) = 3.36 小时 = 3.36 * 60 = 201.6 分钟
因此,如果 7 天内的总停机时间少于 201.6 分钟,则服务符合 98%的 SLO 合规性,否则服务不符合 SLO 合规性。
现在,让我们说明如何基于 SLI 测量来影响 SLO。假设在服务中引入了新功能(在 7 天期间),且这些功能稳定,问题最小。
下表表示了基于 SLI 表现的可用性 SLI 测量、相应的停机时间以及每天减少的错误预算:

下图表示了基于前述表格中的数值,服务正常运行时间的 SLI 表现(上方)和错误预算消耗率(下方):

图 2.2 – SLI 表现和错误预算消耗率的说明
这里有一些关键观察点:
-
剩余的错误预算为 84.95 分钟,少于 201.6 分钟。因此,SLO 符合合规性,SLA 也达成。
-
SLO 表现可以根据剩余的错误预算来计算。由于剩余的错误预算为 84.95 分钟,因此 SLO 表现为 99.25%。
-
新功能的引入并没有不均匀或突然地减少错误预算。
这完成了基于 7 天期间 SLI 表现的 SLO 达成情况的详细说明。下一个场景说明了相反的情况,即基于 SLI 表现未能满足 SLO 的情况。
场景 2 – 引入新功能;功能不可靠;未达成 SLO
这里是该场景的预期:
-
预期 SLA—95%
-
预期 SLO—98%
-
测量 SLI—服务可用性或正常运行时间
-
测量时长—7 天
正如在场景 1中计算的,98% SLO 的允许停机时间为 201.6 分钟。因此,如果 7 天内的停机时间超过 201.6 分钟,则 SLO 不符合合规性。
现在,让我们说明如何基于 SLI 测量来影响 SLO。假设在服务中引入了新功能(在 7 天期间),但这些功能不稳定,导致出现重大问题,造成较长的停机时间。
下表表示了基于 SLI 表现的可用性 SLI 测量、相应的停机时间以及每天减少的错误预算:

下图表示了基于前述表格中的数值,服务正常运行时间的 SLI 表现(左侧)和错误预算消耗率(右侧):

图 2.3 – SLI 表现和错误预算消耗率的说明
这里有一些关键观察点:
-
剩余错误预算 = 第 4 天 0 分钟。因此,SLO 不符合规定。
-
在 7 天期间的总停机时间为 253.44 分钟。
-
对应的 SLO 性能大约为 97.48,低于 98%。
-
由于 SLO 不符合要求,SLA 被违反。这将导致后果。
-
SRE 团队在第 3 天之后不应添加新功能,而应专注于系统可靠性。
这标志着场景 2的详细总结结束。我们已经完成了对基于 SLI 性能如何影响 SLA、SLO 和错误预算的说明。这也意味着我们已经到达了本章的结束部分。
总结
在本章中,我们详细讨论了关键的 SRE 技术实践:SLA、SLO、SLI、错误预算以及消除工作负担。这包括了一些关键概念,如用于定义清晰 SLA 的因素、提供设置 SLO 的指南、分类用户旅程、详细描述测量 SLI 的来源及其局限性、阐述错误预算、详细说明可以使服务可靠的因素、理解工作负担的后果,以及阐明自动化如何有助于消除工作负担。这些概念使我们能够实现 SRE 的核心原则,即在创新与系统可靠性之间保持平衡,从而实现最终目标:更快地构建可靠的软件。
在下一章中,我们将重点介绍跟踪 SRE 技术实践所需的概念:监控、告警和时间序列。这些概念将包括将监控作为反馈循环、监控来源、监控策略、监控类型、告警策略、告警系统的理想特性、时间序列结构、时间序列基数,以及时间序列数据的指标类型。
需要记住的要点
以下是一些重要的要点:
-
100% 的可靠性目标是不现实的。
-
基于日志的 SLIs 和获取遥测数据会增加延迟。
-
应用程序指标不适用于复杂的使用旅程。
-
SLO 必须根据与工程和产品团队的讨论来设置。
-
如果没有剩余的错误预算,重点应该放在可靠性上。
-
TTD 是识别问题存在或被报告的时间。
-
TTR 是解决问题所需的时间。
-
为了提高服务的可靠性,减少 TTD、减少 TTR、减少影响百分比并增加 TTF/TBF。
-
SLIs 应该与用户幸福感有可预测的关系,并且应随着时间的推移进行汇总。
-
用户期望与过去的表现密切相关。
-
为 SLIs 和 SLOs 设置值应该是一个迭代过程。
-
管理错误预算的高级技术包括动态发布节奏、设置错误预算耗尽率、备用基金和使用“银弹”。
-
识别那些导致工作负担的重复性任务并进行自动化处理。
进一步阅读
有关谷歌云平台(GCP)在 DevOps 方面的方法,请阅读以下文章:
-
SRE 基础知识:
cloud.google.com/blog/products/gcp/sre-fundamentals-slis-slas-and-slos -
SRE YouTube 播放列表:
www.youtube.com/watch?v=uTEL8Ff1Zvk&list=PLIivdWyY5sqJrKl7D2u-gmis8h9K66qoj
实践测试
回答以下问题:
-
以下哪个表示不与生产服务相关的工作?
a) 琐事
b) 手动
c) 开销
d) 自动化
-
以下哪个选项表示与用户的明确或隐含合同,包括达成或未达成 SLO 的后果?
a) SLI
b) SLO
c) SLA
d) 错误预算
-
以下哪种组合表示通常作为请求/响应过程一部分跟踪的指标?
a) 可用性、延迟和持久性
b) 延迟、覆盖率、吞吐量和可用性
c) 覆盖率、正确性和质量
d) 可用性、延迟和质量
-
选择一个选项,表示在 SRE 工程师允许花费时间来处理琐事的建议:
a) 25%-55%
b) 45%-60%
c) 50%-75%
d) 30%-50%
-
以下哪个选项是最不现实的(首选)服务可靠性目标作为 SLO?
a) 99.9%
b) 99.99%
c) 99.999%
d) 100%
-
就最佳实践而言,关于每个用户旅程推荐的 SLI 数量,哪项选项是正确的?
a) 2 到 3
b) 无具体限制
c) 3 到 5
d) 5 到 7
-
一个电子商务 Web 应用程序正在通过请求处理客户购买,并将销售交易存储在数据库中。目标是确保预测的销售数据基于最新的销售数据。以下哪些应选择为电子商务应用程序的 SLI(选择两个)?
a) 数据库—可用性。
b) 数据库—持久性。
c) 数据库—新鲜度。
d) Web 应用程序—可用性。
e) Web 应用程序—持久性。
f) 数据库和 Web 应用程序应该始终可用。生产环境的应用程序应具备完全的可用性。
-
以下哪个选项表示系统可用性的精确数值目标?
a) SLA
b) SLO
c) SLI
d) 错误预算
-
以下哪个选项表示服务行为的直接测量?
a) SLA
b) SLO
c) SLI
d) 错误预算
-
以下哪个是最适合用于填充 SLI 的数据源?
a) 应用服务器
b) 前端基础设施
c) 合成客户端
d) 以上都不是
答案
-
(c) 开销。
-
(c) SLA。
-
(d) 可用性、延迟和质量。
-
(d) 30%-50%。建议的琐事工作量不应超过 50%。
-
(d) 100%。
-
(c) 3 到 5。
-
(a) 和 (d):数据库和 Web 应用程序应该保持可用,因为这些是生产应用程序。
-
(b) SLO。
-
(c) SLI。
-
(d) 以上都不是。准确的答案是服务器端日志。
第三章:理解监控和告警以针对可靠性
可靠性是服务或系统最关键的特性。站点可靠性工程(SRE)规定了帮助衡量特性、定义和跟踪可靠性的特定技术工具或实践,如SLA、SLO、SLI和错误预算。第二章,SRE 技术实践 – 深入分析,深入探讨了这些 SRE 技术实践,涵盖多个主题,包括制定明确 SLA 的蓝图、为实现 SLA 而需要 SLO、设定 SLO 的指南、为实现 SLO 而需要 SLI、基于用户旅程分类的不同 SLI 类型、测量 SLI 的不同来源、错误预算的重要性以及如何设定错误预算以保证服务的可靠性。
SLA(服务水平协议)是对客户的外部承诺,而 SLO(服务水平目标)是需要满足的内部承诺,以确保 SLA 不会被违反。这引发了一系列重要问题:
-
如何观察服务的 SLA,以满足用户或客户的期望
-
如何观察 SLO,以确保服务可靠并满足 SLA
-
如何观察 SLI,以确保 SLO 可靠并满足 SLA
以上问题至关重要,因为它不仅影响用户对服务的期望,还可能导致在开发新功能的速度与系统可靠性之间的不平衡。这最终会影响承诺的 SLA,从而导致财务或忠诚度方面的后果。因此,简单来说,主要目标是识别如何跟踪 SRE 技术实践,以针对系统可靠性。
为了跟踪 SRE 技术实践,需要三个基本概念:监控、告警和时间序列。监控是监测代表系统可靠性的关键指标的过程。告警是当监测的关键指标低于可接受阈值或条件时触发告警或报告的过程。监控和告警是基于时间来配置的。这意味着数据需要在连续、等间隔的时间点上收集,代表一系列离散时间数据。这一系列离散时间数据也称为时间序列。
本章将探讨以下主题及其在目标系统可靠性方面的作用:
-
监控:反馈环路、监控类型和黄金信号?
-
告警:告警策略的关键属性和方法是什么?
-
时间序列:结构、基数和度量类型?
理解监控
监控被 Google SRE 定义为收集、处理、汇总和显示系统的实时定量数据的行为,例如查询次数和类型、错误次数和类型、处理时间和服务器生命周期。
简单来说,监控的本质是验证一个服务或应用程序是否按预期行为运行。客户期望服务是可靠的,而将服务交付给客户只是第一步。但确保服务的可靠性应是目标。为了实现这一目标,重要的是探索关键数据,也就是所谓的指标。某些指标的例子可以与正常运行时间、资源使用、网络利用率和应用性能相关。
监控是探索指标数据并提供系统健康状况的整体视图的手段,系统的健康状况反映了其可靠性。除了指标数据,监控还可以包括来自文本日志、事件日志和分布式追踪的数据。下一个主题将详细说明监控如何作为一个持续的反馈循环,对通过持续反馈不断改进系统可靠性至关重要。
监控作为反馈循环
最终目标是建立一个可靠的系统。为了让系统具备可靠性,需要持续地观察系统,根据其外部输出理解系统的内部状态。这个过程称为可观察性。
可观察性有助于识别性能瓶颈或调查请求失败的原因。但为了使系统具备可观察性,重要的是收集和追踪多个与应用健康状况相关的输出。这些输出提供了应用健康状况的洞察,并识别任何潜在问题。这就是所谓的监控。因此,监控提供了有助于系统可观察性的输入。简单来说,监控表明何时出现问题,而可观察性则帮助展示问题发生的原因。
一旦应用程序部署完成,应用需要在四个主要领域中进行检查或监控:
-
验证应用程序的性能是否符合应用目标,并通过提出相关问题来识别性能偏差。
-
分析应用程序在一段时间内收集的数据。
-
当通过洞察或数据分析识别出关键问题时,及时通知相关人员。
-
调试捕获的信息以理解已识别问题的根本原因。
这些领域或类别提供了持续反馈循环,作为监控系统的一部分。这个反馈有助于通过识别问题、分析根本原因并解决问题来持续改进系统。本章将详细阐述这四个类别,提供更深入的洞察。
监控的关键方面之一是提出与系统健康相关的问题。这个内容将在下一个主题中进行讨论。
提出相关问题
在部署后,提出相关问题来监控系统健康至关重要。这些问题提供了关于系统性能的反馈。以下是一些问题,帮助定义如何通过监控服务/系统来有效提供反馈循环:
-
数据库的大小是否比预期增长得更快?
-
系统在更新了特定系统组件的最新软件后是否变得更慢?
-
新技术的使用是否能帮助提升系统性能(例如使用Memcached来提高缓存性能)?
-
为确保服务/系统能够接受来自新地理位置的流量,需要做哪些更改?
-
交通模式是否指向潜在的服务/系统攻击?
解答前面问题的关键是分析手头的数据。接下来的主题介绍了数据分析带来的可能性。
长期趋势分析
数据分析总是会导致一组趋势或模式。监控这些趋势可能会导致以下一种或多种可能性:
-
指向一个现有的问题。
-
发现潜在问题。
-
提升系统性能以应对突发的流量增长。
-
影响新系统功能的实验,以主动避免问题。
数据分析是确保系统按预期运行的关键,并有助于识别任何潜在的突出问题。数据分析可以由人工手动完成,也可以通过系统编程自动完成。在发生事件后识别根本原因的过程称为调试,这是本次讨论关于反馈循环的下一个关键主题。
调试
调试允许通过分析数据收集的信息进行临时的回顾性分析。它有助于回答诸如“在事件发生的同时,还有哪些其他事件发生”的问题。
任何软件服务或系统都难免会遇到不可预见的事件或情况。这些事件可能是由于停机、数据丢失、监控失败或需要人工干预等原因触发的。然后,自动化系统或人工将对这些主动事件作出响应。然而,响应是基于通过监控系统传来的信号数据的分析。这些信号评估影响,并在需要时提升问题,并帮助制定初步响应。
调试也是有效事后分析技术的关键,包括根据需要更新文档,进行根本原因分析,跨团队沟通事件细节以促进知识共享,并列出预防措施。
关于反馈循环的下一个主题集中在警报上。警报对于在事件发生之前或事件发生后尽快通知至关重要。
警报
警报是数据分析的关键后续步骤,并能够告知当前问题。实时或接近实时的警报对于缓解问题至关重要,并且有可能帮助识别根本原因。
警报规则可能在反映复杂的业务场景时变得复杂,当这些规则被违反时,可以发送通知。常见的通知方式包括:
-
一封电子邮件(表明发生了某些事情)
-
一页(要求立即关注)
-
一张票(提示需要尽快处理问题)
在 第二章,SRE 技术实践 - 深度剖析 中,我们讨论了设定可靠性目标的影响。例如,如果可靠性目标设定为 4 个 9(即 99.99%),那么这就意味着在 30 天期间最多允许 4.38 分钟的停机时间。这段时间对于人类来说不足以通知并干预。然而,系统可以接收到通知,并且有可能采取措施来修复当前问题。这是通过警报实现的。
这些主题试图阐述为什么监控可以作为一个反馈环路。这在 SRE 中至关重要,因为 SRE 的目标是保持新功能发布和系统可靠性之间的平衡。监控有助于及时识别问题(当问题发生时),提供警报(当问题发生时),并提供调试数据。这对于理解如何在一段时间内跟踪错误预算至关重要。更多的问题会导致错误预算更快地消耗,因此在此时,稳定系统比发布新功能更为重要。然而,如果监控提供的信息表明当前系统是稳定的,那么将会有相当多的错误预算剩余,从而可以将新功能优先于系统稳定性。
鉴于我们已经将监控确立为提供持续反馈以实现持续改进的必要元素,同样重要的是理解需要避免的常见误解。下一主题将讨论这一点。
需要避免的监控误解
在为服务或系统设置监控时,存在一些常见的误解。以下是应避免的这些误解的列表:
-
监控应被视为一种专业技能,要求对相关组件具有技术理解,并需要对应用程序甚至领域有功能性理解。这项技能需要在负责维护监控系统的团队中培养。
-
没有一种万能工具可以监控服务或系统。在许多情况下,监控是通过组合多个工具或服务来实现的。例如,API 调用的延迟可以通过Grafana等工具进行监控,但特定方法的 API 调用详细分解,包括数据库查询所用的时间,可以使用Dynatrace等工具进行监控。
-
监控不应局限于一种视角,而应涵盖多种视角。最终消费者关心的事情可能与企业关心的不同,也可能与服务提供商的视角不同。
-
监控从来不局限于单一服务。它可以扩展到一组相关或不相关的服务。例如,需要监控与 Web 服务器相关的缓存服务。同样,监控与之直接无关的服务也很重要,例如托管 Web 服务器的机器或集群。
-
监控不一定总是复杂的。可能有需要通过规则组合来检查的复杂业务条件,但在许多情况下,监控应该遵循保持简单傻瓜(KISS)原则。
-
为分布式系统建立监控应重点关注构成系统的各个服务,而不应仅仅关注整体运作。例如,请求的延迟可能比预期的更长。重点应该放在那些共同导致请求延迟的元素或底层服务上(包括方法调用和查询响应)。
-
“单一玻璃窗”这个短语通常与有效的监控相关联,其中“玻璃窗”比喻地指的是一个管理控制台,该控制台从多个来源收集数据,代表所有可能的服务。但仅仅显示来自多个来源的信息并不能提供数据之间关系的整体视图,也无法了解可能出现的问题。相反,单一玻璃窗应该通过建立监控信号之间的关联,将多个服务逻辑性地组合成一个工作区。
监控不应该仅仅关注症状,还应关注其原因。让我们来看一些例子:

本质上,监控的重点不应该是收集或显示数据,而应关注建立问题和可能原因之间的关系。监控数据可以从多个来源收集或捕获。这个话题将在下一部分讨论。
监控源
监控数据在监控系统中至关重要。监控数据有两个常见来源。第一个来源是度量指标:
-
指标代表资源使用或行为的数值度量,这些度量可以跨系统在多个数据点上定期收集并观察。收集指标的典型时间间隔可以是每秒一次、每分钟一次,等等。
-
指标可以从操作系统提供的低级指标中收集。在大多数情况下,低级指标是现成可用的,因为它们是特定于某一资源的,例如数据库实例、虚拟机和磁盘。
-
指标也可以通过与特定组件或应用程序相关的更高层次数据类型来收集。在这种情况下,应该创建自定义指标并通过仪器化过程进行暴露。
-
指标用作输入,显示仪表板中较少粒度的实时数据,或触发实时通知的警报。
下一个源是日志:
-
日志代表数据的细粒度信息,通常以大量写入的形式存在。
-
日志不是实时的。日志总是存在固有的延迟,即事件发生后,直到它在日志中可见之间存在时间差。
-
日志用于找出问题的根本原因,因为分析所需的关键数据通常不是以指标的形式存在。
-
日志可以用于生成详细的非时间敏感报告,使用日志处理系统进行处理。
-
可以通过使用批处理系统对日志流运行查询,将日志转换为指标。
日志记录与监控
日志记录提供了关于应用程序执行的洞察。日志记录可以捕获事件记录和最微小的细节,以及可以转换为警报的可操作错误。日志本质上描述了可能发生的情况,并提供了调查问题的数据。
监控则提供了在问题发生时检测并根据需要进行警报的能力。事实上,监控需要日志作为关键信息来源。而且,反之亦然,日志也需要监控。这是因为,只有拥有出色日志记录但没有监控的应用程序,并不会帮助最终用户。
总结来说,指标和日志都是常见的监控来源。它们用于不同的情况,在大多数情况下,推荐同时使用两者的组合。如果有内部或外部组件提供有关事件和性能的信息,那么指标是一个很好的选择。日志则最适合跟踪应用程序经历的各种事件。指标也可以从日志中创建。接下来的主题讨论了几种推荐的监控策略。
监控策略
选择监控系统时,以下是一些推荐的策略:
-
数据不应过时:当查询大量数据时,数据检索的速度变得至关重要。如果检索速度慢,数据就会变得过时,可能被误解,进而可能基于错误的数据采取行动。
-
仪表板应可配置并包含强大的功能:监控系统应包括具备在不同格式下显示时间序列数据的能力的界面,例如热图、直方图、计数器或分布。应具备使用多种选项汇总信息的可配置功能。
-
如果需要,警报应进行分类并抑制:监控系统应具备设置不同严重级别的能力。此外,一旦警报被通知,如果能够在一定时间内抑制相同的警报,从而避免可能分散值班工程师注意力的不必要噪音,这将极为有用。
这些推荐策略被应用于两种类型的监控。该分类将在下一个主题中讨论。
监控类型
监控可以分为两种最常见的类型:
-
黑盒监控
-
白盒监控
黑盒监控
黑盒监控是指基于用户角度测试系统外部可见行为的监控。这种监控不涉及对系统技术细节、构建或配置的任何访问。监控严格基于测试可见行为,这些行为反映了最终用户如何访问系统。它被比喻为黑盒监控,因为系统的内部不透明,无法控制或看到系统内部的发生情况。它也被称为服务器或硬件监控。
黑盒监控最适合在事件发生后或事件正在进行时进行分页通知。黑盒监控是对当前问题的表示,面向系统,重点关注系统负载和磁盘/内存/CPU 的使用情况。其他示例包括对网络交换机和网络设备的监控,如负载均衡器和虚拟机监控层级资源使用。
白盒监控
白盒监控通常被称为应用监控,基于系统内部收集和暴露的指标。例如,白盒监控可以通过捕获总 HTTP 请求数、错误总数或每个请求的平均请求延迟,提供有关应用程序或端点性能的洞察。相比之下,黑盒监控只能捕获端点是否返回了成功的响应。白盒监控既面向症状,也面向原因,这取决于系统内部的可见信息量。白盒监控还可以提供对未来问题的洞察,因为从一个内部收集的信息可能是另一个内部问题的原因。白盒监控从三个关键组件收集信息——指标、日志和追踪,具体如下:
-
度量:这些是现成的或自定义创建的度量,用来以可度量的方式表示系统的状态,通常以计数器、仪表和分布的形式出现。
度量必须是SMART的:
a) S:具体的(例如,自动化结果至少应该达到 99%,而不是“高质量”)
b) M:可度量的(例如,结果应该在 200 毫秒内返回,而不是“足够快”)
c) A:可达成的(例如,服务的可用性为 99.99%,而非 100%)
d) R:相关的(例如,观察延迟,而不是浏览视频标题的吞吐量)
e) T:有时间限制的(例如,服务在 30 天内可用 99.99%,而不是“长期可用”)
-
日志:这些表示在某一时刻单一线程的工作。日志反映了应用程序的状态,并且是在应用程序开发时由用户创建的。日志可以是结构化或半结构化的,通常包括时间戳和消息代码。日志条目是通过客户端库(如 log4j 和 sl4j)来编写的。日志处理是生成统计信息的可靠来源,也可以实时处理生成基于日志的度量。
-
追踪:这些由跨度(spans)组成。跨度是分布式追踪的主要构建块,代表分布式系统中一个特定事件或用户操作。一个跨度表示请求在一个服务器上的路径。然而,可能会有多个跨度同时存在,其中一个跨度可以引用另一个跨度。这使得多个跨度能够汇聚成一个共同的追踪,本质上是请求在分布式系统中传递的可视化。
黑箱监控与白箱监控——哪个更为关键?
这两种监控方式同样至关重要,具体使用哪种方式建议根据情况和受众类型来决定。黑箱监控提供的是运维团队通常会关注的信息,例如磁盘使用情况、内存利用率和 CPU 利用率,而白箱监控则提供系统内部的更多细节,这些细节可能反映出黑箱监控产生的指标的原因。例如,像高 CPU 利用率这样的黑箱指标会表明存在问题,但像活跃数据库连接数或长时间运行的查询等白箱指标,则能指出可能会发生的潜在问题。
总结来说,系统的可靠性可以通过监控特定的度量来追踪。然而,可能存在多个需要追踪的度量,有时在优先排序这些度量时也会导致困惑。接下来的内容列出了 Google 推荐的用于用户面对面系统的最重要的度量,这些度量被称为黄金信号。
黄金信号
系统可靠性通过 SLO 跟踪。SLO 需要 SLIs 或特定的度量来进行监控。监控的度量类型取决于与服务相关的用户旅程。强烈建议每个服务/系统都应度量一组明确且有限的 SLI。因此,如果有可能为服务定义多个度量,则建议优先考虑要测量和监控的度量。
Google 提出了使用四个黄金信号的建议。黄金信号指的是应当为用户面向的系统测量的最重要的指标:
-
延迟:这是处理请求所需时间的指标,反映了用户体验。延迟能够指示潜在问题。示例指标包括 页面加载/事务/查询持续时间,首次响应时间,以及 完整数据持续时间。
-
流量:这是当前系统需求的指标,也是计算基础设施支出的基础。流量历史上用于容量规划。示例指标包括 # 写入/读取操作,# 事务/检索/每秒 HTTP 请求,以及 # 活跃请求/连接。
-
错误:这是请求失败率的指标,实际上表示单个服务和整个系统的错误率。错误表示显式或隐式失败的请求率,或由于策略导致的失败。示例指标包括 # 400/500 HTTP 状态码,以及 # 异常/堆栈跟踪/丢失的连接。
-
饱和度:这是服务整体容量的指标,实际上代表服务的“满”度,反映出性能下降。饱和度也可以指示 SLO,从而触发告警。示例指标包括 磁盘/内存配额,# 内存/线程池/缓存/磁盘/CPU 使用率,以及 # 可用连接/系统用户数。
本部分完成了关于监控的内容,涵盖了监控系统的理想特性,这些特性有助于创建反馈循环,潜在的监控源,监控的类型,以及 Google 推荐的黄金信号,这些信号代表了应当为用户面向系统测量的四个关键指标。下一部分将概述告警以及如何将监控系统中的信息作为输入。
告警
SLI 是在某一时刻的定量度量,SLO 使用 SLI 来反映系统的可靠性。SLI 通过度量的形式捕获或表示。监控系统依据一组特定的策略来监控这些度量。这些策略表示在一段时间内的目标 SLO,称为告警规则。
警报是处理警报规则的过程,这些规则跟踪 SLO,并在规则被违反时通知或执行某些操作。换句话说,警报使得 SLO 可以转化为有关重要事件的可操作警报。然后,这些警报可以发送到外部应用程序、票务系统或某个个人。
触发警报的常见场景包括(但不限于)以下情况:
-
服务或系统出现故障。
-
未满足 SLO 或 SLA。
-
需要立即人工干预以进行更改。
如前所述,SLO 代表可实现的目标,而错误预算代表可接受的不可用性或不可靠性的水平。SRE 强烈建议使用警报来跟踪错误预算的消耗速率。如果错误预算消耗速率过快,在预算完全耗尽之前设置警报可以作为警告信号,使团队能够将焦点转向系统可靠性,而不是推动具有风险的功能。
警报的核心概念是跟踪事件。这些事件通过时间序列进行处理。时间序列定义为一系列事件数据点,这些数据点被分割成连续且间隔相等的时间窗口。可以配置每个窗口的持续时间以及应用于每个窗口内成员数据点的数学运算。有时,重要的是汇总事件,以防止误报,这可以通过时间序列来实现。最终,错误率可以持续计算,监控设定目标,并在合适的时机触发警报。
警报策略——关键属性
配置服务或系统警报的关键是设计有效的警报策略。为了衡量某一警报策略的准确性或效果,在设计过程中应考虑以下关键属性。
精确度
从效果角度来看,警报应分为相关警报和无关警报。精确度定义为检测到的事件中重要事件的比例。
以下是计算精确度的数学公式:

换句话说,如果精确度需要达到 100%,则无关警报的数量应该为 0。精确度是准确性的衡量标准,通常会受到误报或假警报的不利影响。这种情况通常发生在低流量期间。
召回率
警报需要捕捉每一个重要事件。这意味着不应漏掉任何警报。召回率定义为检测到的重要事件的比例。
以下是计算召回率的数学公式:

换句话说,如果召回率需要达到 100%,则每一个重要事件都应触发一个警报,且不应漏掉任何警报。召回率是完整性的衡量标准,通常会受到漏报的负面影响。
检测时间
检测时间 被定义为系统察觉警报条件所需的时间。它也被称为检测时间。较长的检测时间可能会对错误预算产生负面影响。因此,在问题发生时尽快通知或触发警报是至关重要的。然而,警报触发过快会导致误报,从而最终影响精确度。
重置时间
重置时间 被定义为在问题解决后触发警报的时间长度或持续时间。较长的重置时间会产生不利影响,因为警报会在已修复的系统上触发,导致混乱。
这部分介绍了在定义有效警报策略时至关重要的关键属性。接下来的主题将详细阐述一种定义有效警报策略的潜在方法。
警报策略 – 潜在方法
SRE 推荐了六种不同的方法来配置重要事件的警报。每种方法都解决了不同的问题。这些方法还在精确度、召回率、检测时间和重置时间等关键属性之间提供了一定的平衡。其中一些方法可以同时解决多个问题。
方法#1 – 目标错误率 >= 错误预算(使用较短的警报窗口)
在此方法中,选择较短的警报窗口或较小的窗口长度(例如 10 分钟)。较小的窗口通常会带来更快的警报检测和更短的重置时间,但也倾向于降低精确度,因为它们容易产生误报或错误警报。
根据此方法,如果目标错误率在定义的较短警报窗口内等于或超过错误预算,则应触发警报。
考虑一个具有以下输入参数的示例:
-
预期的 SLO 为 30 天内达到 99.9%,因此错误预算为 0.1%。
-
检查的警报窗口:10 分钟。
因此,潜在的警报定义如下:
如果 SLO 为 30 天内 99.9%,且过去 10 分钟内的错误率>=0.1%,则触发警报。
在方法#1 中,较短的时间窗口会导致警报更频繁地触发,但往往会降低精确度。
方法#2 – 目标错误率 >= 错误预算(使用较长的警报窗口)
在此方法中,选择较长的警报窗口或较大的窗口长度(例如 36 小时)。较大的窗口往往能获得更好的精确度,但会有更长的重置时间和检测时间。这意味着,在问题被检测到之前,消耗的错误预算部分也较高。
根据此方法,如果目标错误率在定义的较大时间窗口内等于或超过错误预算,则应触发警报。
考虑一个具有以下输入参数的示例:
-
预期的 SLO 为 30 天内 99.9%:因此错误预算为 0.1%
-
检查的警报窗口:36 小时
因此,潜在的警报定义如下:
如果 SLO 在 30 天内为 99.9%,并且过去 36 小时内的错误率>=0.1%,则触发警报。
在方法 #2 中,较长的时间窗口能提高精度,但警报触发的频率较低,可能导致较长的检测时间。
方法 #3 – 添加持续时间以提高精度
在这种方法中,可以将持续时间参数添加到警报标准中,这样警报只有在该值超过阈值并持续一段时间后才会触发。阈值的选择也变得非常重要,因为如果阈值设得过高,有些警报可能会错过。例如,如果持续时间窗口为 10 分钟,而信号数据在 9 分钟时已经恢复正常,那么错误预算虽然已经消耗,但警报将不会被触发或被遗漏。通过正确选择持续时间参数和阈值,该方法能快速发现错误,但直到达到持续时间才会将其视为异常:
-
这种方法的优点是,在定义的持续时间后触发的警报通常对应于一个重大事件,从而提高了精度。
-
这种方法的缺点是,错误会在更长的时间窗口内持续发生,因此会导致召回率下降。
推荐使用较长的警报窗口或较长的时间窗口(例如,36 小时)。较大的窗口通常能提供更好的精度,但会有更长的重置和检测时间。
根据该方法,如果目标错误率等于或超过定义的较大时间窗口内的错误预算,则应触发警报。
考虑以下输入参数的示例:
-
期望的 SLO 为 30 天内 99.9%:因此错误预算为 0.1%
-
查看警报窗口:36 小时
相应地,潜在的警报定义可能如下:
如果 SLO 在 30 天内为 99.9%,并且过去 36 小时内的错误率>=0.1%,则触发警报。
在方法 #3 中,较长的持续时间窗口也意味着在问题被检测到之前,已经消耗的错误预算比例较高,但很可能会指示一个重大事件。
方法 #4 – 关于燃尽速率的警报
在这种方法中,警报应根据燃尽速率定义。燃尽速率定义为相对于 SLO,服务消耗错误预算的速度。
例如,如果 30 天内错误预算为 0.1%,并且错误率在 30 天内保持恒定为 0.1%,那么预算将平均消耗,且在第 30 天结束时剩余 0 预算。在这种情况下,燃尽速率为 1。如果错误率为 0.2%,那么耗尽的时间为 15 天,燃尽速率为 2。
当基于燃尽速率进行警报时,以下是两种可能的警报策略:
-
快速消耗警报:因错误预算消耗发生突然而大的变化而触发警报。如果未得到通知,错误预算将比正常情况更快耗尽。对于快速消耗警报,回溯期应较短(例如 1 到 2 小时),但警报的消耗速率阈值应远高于回溯期的理想基线(例如是基线的 10 倍)。
-
慢速消耗警报:直到条件持续被违反较长时间后,才会触发警报。这类警报在发生时只消耗错误预算的一小部分,并且比快速消耗警报的紧急程度要低。对于慢速消耗警报,回溯期应较长(例如 24 小时),但阈值应略高(例如是基线的 2 倍)。
因此,按照方法#4,如果消耗速率在任何时刻超过期望的消耗速率,警报将被触发。该方法在较短的时间窗口内提供更好的精度和较好的检测时间。
方法#5 – 多种消耗速率警报
同样的警报策略并不总是适用于某项服务。这可能取决于流量量、变化的错误预算或高峰期与低谷期等因素。例如,在假期购物季节,服务的 SLO 通常会高于正常水平。这意味着高峰期的错误预算较低,而在非高峰期时,错误预算则会变得稍微宽松一些。
在这种方法中,警报策略中可以定义多个条件,以便获得更好的精度、召回率、检测时间和重置时间。每个条件可以有不同的严重级别,并根据严重性采用不同的通知渠道来通知警报。
例如,可以定义一个包含以下多个条件的警报策略:
-
当预算的 10%在 3 天内被消耗时触发警报,并通过创建工单进行通知。
-
当预算的 5%在 6 小时内被消耗时触发警报,并通过页面进行通知。
-
当预算的 2%在 1 小时内被消耗时触发警报,并通过页面进行通知。
在方法#5 中,可以为单个警报策略定义多个条件。每个条件可能导致不同的行动,这些行动可能代表警报的严重级别。
方法#6 – 跨多个窗口的多种消耗速率警报
这是方法#5 的扩展,其中主要区别在于使用多个窗口来检查错误率是否超过错误预算,而不是仅用单个窗口来检查单一条件。这将确保触发的警报始终具有重要性,并且在收到通知时,错误预算正在被积极消耗。
这有助于创建一个灵活的告警框架,能够根据事件的严重性显示直接影响。灵活的窗口强调或确认告警条件是否在最后指定的时间段内处于活动状态。这有助于在收到告警时立即进行故障排除。反过来,这些条件也涉及多个变量,可能会在长期内增加维护工作。
例如,可以定义一个包含多个条件的告警策略:
-
如果预算的 10%在 3 天内被消耗,并且在过去 6 小时内正在被消耗,则触发告警。通过创建工单通知。
-
如果预算的 5%在 6 小时内被消耗,并且在过去 30 分钟内正在被消耗,则触发告警。通过页面通知。
-
如果预算的 2%在 1 小时内被消耗,并且在过去 5 分钟内正在被消耗,则触发告警。通过页面通知。
方法 #6 可能是方法 #5 的扩展,其中可以为告警策略定义多个条件,每个条件被触发时,可能会导致不同的行动或通知。不同之处在于方法 #6 强调指定一个告警窗口,以确认触发的告警可能是有效的。
这些方法非常适合需要告警策略的多种情况。然而,可能会有一种特殊情况,即服务接收到的流量较少或很低。接下来的主题讨论了如何处理此类情况的方法。
处理低流量服务
如果服务接收到的流量较少,则单个或少量的失败请求可能会导致更高的错误率,从而表明错误预算的显著消耗。SRE 推荐几种处理低流量服务的选项:
-
生成人工流量:此选项提供更多的信号或请求进行处理。然而,需要大量的工程工作来确保人工流量的行为与真实用户的行为尽可能相似。
-
合并服务:此选项建议将相似的低请求服务按功能合并为一个组。这将提高精度并减少误报。然而,在将服务合并为一个组时需要谨慎考虑。因为单个服务的故障不一定会导致整体功能的故障,因此也不会触发重大事件的告警。
-
修改客户端:此选项用于处理暂时性故障,特别是当生成人工流量或将服务组合成一个组不切实际时。通过修改客户端并实施指数退避,可以减少单个请求失败的影响。此外,应该设置回退路径,以便在退避后捕获请求并最终执行。
-
降低 SLO 或增加窗口:此选项是处理低流量服务的最简单方法。这将减少单个故障对错误预算的影响。然而,降低 SLO 也是降低对服务行为期望的一种方式。
鉴于我们已经了解了有关创建有效警报策略的特定主题,下一步是了解建立 SLO 警报策略所需的步骤。
建立 SLO 警报策略的步骤
以下是建立 SLO 警报策略的步骤顺序:
-
选择要监控的 SLO:选择适合该服务的 SLO。建议一次只监控一个 SLO。
-
构建适当的条件:警报策略可以有多个条件,其中针对缓慢故障和快速故障的条件不同。
-
确定通知通道:可以同时为警报策略选择多个通知通道。
-
包括文档:建议包含有关警报的文档,以帮助解决潜在的根本问题。
-
创建警报策略:应在所选的监控系统中创建该策略,可以通过配置文件、CLI 或控制台(取决于监控系统支持的功能)来实现。
这标志着建立 SLO 警报策略蓝图的完成。接下来的主题介绍了警报系统的理想特性。
警报系统 – 理想的特性
警报系统应控制值班工程师接收到的警报数量。以下是警报系统应具备的一些理想特性的简要清单:
-
在其他警报处于活动状态时,抑制某些警报。
-
删除或静音来自多个来源、具有相同标签集的重复警报。
-
当多个具有相似标签集的警报触发时,基于其标签集进行扇入或扇出警报。
这部分总结了警报,并提供了定义有效警报策略所需的构建块,包括可能的方法和关键属性,如精准度、召回率、检测时间和重置时间。下一部分将概述时间序列、其结构、基数和指标类型。
时间序列
时间序列数据是代表系统行为随时间变化的数据。实质上,应用程序传递的是一种数据形式,用来衡量事物随时间的变化。时间不仅仅是一个被捕捉的变量;时间是主要的焦点。时间序列数据的现实世界例子包括以下内容:
-
不断收集数据的自动驾驶汽车,以捕捉不断变化的驾驶条件或环境
-
捕捉事件的智能家居,例如温度变化或运动
度量与事件
度量是按固定间隔收集的时间序列测量值。事件是按不规则时间间隔收集的时间序列测量值。
以下是一些符合时间序列数据标准的特征:
-
到达的数据始终作为新条目记录。
-
数据按时间顺序到达。
-
时间是主要的轴。
向数据集添加时间字段并不等同于时间序列数据
与传感器相关的数据被存储在非时间序列数据库中。如果传感器收集到一组新的数据,那么写入这些数据将会用更新的时间覆盖数据库中先前存储的数据。数据库最终会返回最新的读数,但无法追踪一段时间内数据的变化。因此,非时间序列数据库将系统的变化记录为更新(UPDATES),而时间序列数据库则将系统的变化记录为插入(INSERTS)。
下一部分将讨论时间序列的结构。
时间序列结构
监控数据存储在时间序列中。每个独立的时间序列数据包含三部分信息(参见图 3.1):
-
点:指的是一系列(时间戳,值)对。值是测量结果,时间戳是测量发生的时间。
-
度量:指示如何解释数据点的度量类型的名称。它还包括度量标签的值组合。
-
监控资源:指的是作为时间序列数据源的监控资源,以及该资源标签的值组合。
以下截图展示了时间序列数据的结构:

图 3.1 – 时间序列数据的结构
让我们看一个例子:
以下截图展示了如何表示时间序列数据的示意图,适用于具有示例值的度量类型:storage.googleapis.com/api/request_count:

图 3.2 – GCP Cloud 存储度量的示意图,包含示例值
前面的截图展示了随着时间推移,作为度量的一部分捕捉到的各种事件。例如,以下信息可以从图 3.2中提取:
-
在
2:00 pm到2:10 pm之间,1234号桶中总共有八个注册事件。 -
这包括六个成功事件(三个读取和三个写入,具有不同的时间戳)以及三个失败的写入尝试。
下一主题介绍了与时间序列数据相关的基数概念。
时间序列基数
每个时间序列与特定的度量类型和监控资源类型的配对相关联,但每个配对可以有多个时间序列。时间序列的数量由该配对的基数决定:标签的数量以及每个标签可以取的值的数量。
例如,时间序列度量由两个标签的组合表示:zone 和 color。每个区域有两个(东区和西区),每个区域有三种颜色(红色、绿色和蓝色)。因此,该度量的基数为六。以下是可能的时间序列数据:
Request_by_zone_and_color{zone="east",color="red"}
Request_by_zone_and_color{zone="east",color="green"}
Request_by_zone_and_color{zone="east",color="blue"}
Request_by_zone_and_color{zone="west",color="red"}
Request_by_zone_and_color{zone="west",color="green"}
Request_by_zone_and_color{zone="west",color="blue"}
关于度量基数,有几点关键要点需要记住:
-
度量基数是影响性能的关键因素。如果基数过高,意味着时间序列数据量很大,从而导致查询响应时间较长。
-
对于自定义度量,度量类型中可以定义的最大标签数为 10 个。
下一主题介绍了与时间序列数据相关的常见度量类型。
时间序列数据 – 度量类型
每个时间序列包含一个度量类型,用于表示其数据点。度量类型定义了如何相互解释这些值。最常见的三种度量类型如下:
-
计数器:计数器是一种累计度量,表示一个单调递增的函数,其值只能增加(但不能减少),或者在重启时重置为零;例如,表示请求处理次数、完成任务数或在特定时间点观察到的错误数的计数器。
-
仪表:仪表度量表示一个单一的数值,该值可以随意上升或下降。它适用于监控有上限的事物。
仪表的例子包括集合或映射的大小,或者运行状态下的线程数量。仪表也通常用于测量值,如温度或当前内存使用情况,也可以用于计数,如并发请求的数量,且这些计数可以上下波动。
-
分布:分布度量用于跟踪事件在可配置桶中的分布;例如,衡量请求到达服务器时的负载大小。
这部分关于时间序列的内容已经结束,概述了与时间序列结构、基数以及可能的度量类型相关的关键概念。本章也到此结束。
总结
在本章中,我们讨论了与监控、警报和时间序列相关的概念,这些概念对追踪 SRE 技术实践至关重要,例如 SLO 和错误预算。我们还讨论了黑盒监控与白盒监控之间的区别。此外,我们考察了 Google 推荐的四个黄金信号,这些信号被认为是面向用户的系统的理想 SLI 指标。
在下一章中,我们将重点关注构建 SRE 团队所需的结构,并应用文化实践,例如处理事件管理的各个方面、值班、避免心理安全、促进沟通与协作以及知识共享。
需要记住的要点
以下是一些需要记住的重要要点:
-
黑盒监控基于测试外部可见行为。
-
白盒监控基于系统内部收集并暴露的指标。
-
指标必须是具体的、可衡量的、可实现的、相关的和有时间限制的。
-
推荐的四个黄金信号是延迟、流量、错误和饱和度。
-
延迟可能指示潜在问题,流量通常用于容量规划。
-
错误代表明确或隐式失败的请求率,或者由策略导致的失败率。
-
饱和度表示服务的满载程度,并反映出性能下降。
-
精度定义为检测到的重要事件的比例。
-
召回率定义为检测到的重要事件的比例。
-
检测时间定义为系统发现警报条件所需的时间。
-
重置时间定义为在问题解决后触发警报的持续时间或时间长度。
-
单个时间序列数据包含三个关键元素——数据点、指标和监控资源。
进一步阅读
有关 GCP DevOps 方法的更多信息,请阅读以下文章:
-
SRE 基础知识:
cloud.google.com/blog/products/gcp/sre-fundamentals-slis-slas-and-slos -
SRE Youtube 播放列表:
www.youtube.com/watch?v=uTEL8Ff1Zvk&list=PLIivdWyY5sqJrKl7D2u-gmis8h9K66qoj -
指标、时间序列和资源:
cloud.google.com/monitoring/api/v3/metrics
实践测试
回答以下问题:
-
选择基于系统内部暴露的指标工作的监控选项。
a) 基于警报的监控
b) 白盒监控
c) 基于日志的监控
d) 黑盒监控
-
选择一个不提供近实时信息的监控来源。
a) 日志
b) 指标
c) 两者都包括
d) 以上都不是
-
从快速触发警报策略的角度,选择相对于基线的适当阈值,用于定义的回顾时间间隔。
a) 阈值 = 基线。
b) 阈值 < 基线。
c) 阈值显著高于基线。
d) 阈值略高于基线。
-
选择适当的选项来发送警报
a) 电子邮件
b) 页面
c) 文本
d) 以上所有
-
选择最适合用于分页事件的监控。
a) 基于警报的监控
b) 白盒监控
c) 基于日志的监控
d) 黑盒监控
-
以下哪项不是谷歌推荐的黄金信号的一部分?
a) 流量
b) 吞吐量
c) 饱和度
d) 错误
-
以下哪项警报策略建议使用更长的回顾窗口?
a) 快速触发
b) 慢燃
c) 两者都有
d) 无
-
以下哪项表示收集、处理、聚合并显示与系统相关的实时定量数据的操作,例如查询计数和类型、错误计数和类型、处理时间和服务器生命周期?
a) 警报
b) 监控
c) 调试
d) 故障排除
-
以下哪项表示在不规则时间间隔收集的时间序列测量?
a) 指标
b) 事件
c) 日志
d) 跟踪
-
以下哪项不是白盒监控的适用数据源?
a) 指标
b) 负载均衡器
c) 日志
d) 跟踪
答案
-
(b) 白盒监控。
-
(a) 日志。
-
(c) 阈值显著高于基线。推荐的级别为 10 倍。
-
(d) 以上所有,包括电子邮件、页面和短信。
-
(d) 黑盒监控。
-
(b) 吞吐量。四个黄金信号是延迟、错误、流量和饱和度
-
(b) 慢燃警报策略
-
(b) 监控
-
(b) 事件。事件是在不规则时间间隔收集的时间序列测量。指标是以规则时间间隔收集的时间序列测量。
-
(b) 负载均衡器。它最适合作为黑盒监控的数据源。白盒监控从三个关键组件收集信息:指标、日志和跟踪。
第四章:构建 SRE 团队与应用文化实践
最后三章介绍了 网站可靠性工程(SRE)的基础知识,追溯了它的起源,阐明了 SRE 与 DevOps 的不同,介绍了 SRE 行话及其关键技术实践,如 服务水平协议(SLAs)、服务水平目标(SLOs)、服务水平指标(SLIs)和 错误预算,并专注于监控和警报概念,以确保可靠性。
本章将重点介绍构建 SRE 团队所需的基础知识,并应用诸如处理事件管理各个方面、值班、实现心理安全、促进沟通、协作和知识共享等文化实践。这些基础知识和文化实践可以作为那些希望开始 SRE 之旅的团队或组织的蓝图。
本章我们将涵盖以下主要主题:
-
构建 SRE 团队 - 配置、创建 SRE 团队并与团队互动
-
事件管理 - 事件生命周期及其处理构建
-
值班 - 需要解决的挑战、操作过载和有效的故障排除
-
心理安全与促进协作 - 实现心理安全的因素、统一的愿景、沟通、协作和知识共享
构建 SRE 团队
Google 通过将软件工程的概念应用于系统运维,定义了 SRE 的原则。Google 在 “DevOps” 一词出现之前就已实施这些原则。随着时间的推移,他们开发了最佳实践,并基本上将 SRE 视为高效运行产品的“秘密武器”。随着 Google Cloud Platform (GCP) 的出现,Google 对 SRE 原则变得更加公开,强调这些原则对那些在 GCP 上维护、运行和操作分布式系统的客户成功的重要性。
鉴于 SRE 是一种规范化的 DevOps 实践,越来越多的组织(包括非 GCP 客户)目前倾向于实施 SRE 原则,以寻找服务可靠性与开发速度之间的平衡。这些组织将面临以下挑战:
-
如何配置 SRE 团队?
-
如何实施或运营 SRE 团队?
-
SRE 团队在服务生命周期中何时以及多频繁地参与?
以下子章节根据 Google 的最佳建议回答这些问题。
配置 SRE 工程师(SREs)
一个 SRE 团队由 SRE 工程师或 SREs 组成。最初,SREs 也需要负责运维。寻找经验丰富的 SRE 非常困难。然而,建立 SRE 团队的一种方式是招聘那些有运维经验并具备脚本/编码经验的系统管理员。这些人员可以进一步培训,掌握软件工程技能。
以下是推荐的技能列表,招聘为 SRE 工程师或 SRE 的人员应该具备这些技能,或最终经过相关培训:
-
运维与软件工程:SRE 应具备运行生产系统的经验,并且了解需要支持的软件或应用程序。
-
监控系统:SLO(服务水平目标)对于维持服务的可靠性至关重要,SRE 需要了解监控系统的运作,以便追踪 SLO 及其相关的构件,如 SLI(服务水平指标)和错误预算(Error Budgets)。
-
生产自动化:SRE 可以通过确保不再手动执行同一任务,而是通过自动化来有效地扩展运维。这要求理解如何自动化这一过程。
-
系统架构:SRE 能够有效地扩展应用程序或服务,这要求对系统架构有深入的理解。
-
故障排除:SRE 经常需要随时待命,解决各种类型和复杂度的问题。这需要一种好奇且分析的思维方式来解决手头的问题。
-
信任文化:SRE 与开发人员通过错误预算的概念共享服务的所有权。这要求 SRE 通过有效的沟通与开发团队建立信任。
-
事件管理:故障或问题是不可避免的,而 SRE 的关键职能之一就是处理事件。这需要具备技术性故障排除能力,并建立一个专门用于事件管理的沟通框架。
除了推荐的技能外,SRE 工程师或 SRE 还应具备一些个人特质,如韧性、果断和灵活性。这些特质将帮助他们应对困难情境,在模糊不清的情况下使用推理,并在开发速度与可靠性之间找到平衡。接下来的主题将深入探讨 SRE 团队实施的类型。
SRE 团队实施 – 程序与策略
推荐的六种 SRE 团队实施方式:
-
万能型/全能型 SRE 团队
-
基础设施 SRE 团队
-
工具 SRE 团队
-
产品/应用 SRE 团队
-
嵌入式 SRE 团队
-
咨询 SRE 团队
每种实施类型都适合特定的组织,具体取决于组织所提供服务的复杂性、组织的规模、开发团队的数量及其范围,以及组织在应用 SRE 原则方面的接受程度。一些组织还可以根据需求实施多个类型。我们将详细探讨不同的团队实施方式。
万能型/全能型 SRE 团队
厨房水槽/全能 SRE 团队最适合那些希望开始 SRE 之旅的组织。在大多数情况下,组织倾向于从一个 SRE 团队开始。这种团队的范围是无限的。厨房水槽/全能 SRE 团队推荐给那些当前范围有限的组织,因为应用程序较少,导致用户路径较少。
鉴于只有一个 SRE 团队,这种类型的团队可以作为开发团队之间的纽带,还可以跨项目发现模式,以便在发生事故时提供有效的解决方案。同时,选拔具备所需技能的工程师来组成 SRE 团队是相当具有挑战性的。此外,由于范围可能不断变化,厨房水槽式团队的实施可能会因为团队目标不明确而导致缺乏清晰度,并最终导致运营过载。
基础设施 SRE 团队
基础设施 SRE 团队最适合那些拥有多个开发团队,且开发团队的范围、复杂性和基础设施需求各不相同的组织。基础设施团队的核心关注点是幕后任务,帮助开发团队更轻松、更快速地完成工作。基础设施 SRE 团队更少关注面向客户的代码,更关注维护与稳定基础设施相关的共享服务和组件。
基础设施 SRE 团队的主要优势在于为开发团队提供同样高度可靠的基础设施,以模拟可能在生产环境中发生的行为。此外,基础设施团队还通过最小权限原则和遵循所需的合规标准来建立访问这些环境的结构。
另一方面,鉴于基础设施 SRE 团队并不直接与客户合作,而是与内部团队合作,因此在为开发团队定义标准时,往往会有过度工程化的倾向。此外,它们的使用行为可能与真实世界的情况有所不同。
有时,根据公司或其产品线的规模,可能会有多个基础设施团队。这可能导致在基础设施提供方式上的重复工作。这是需要密切关注的问题,并且可以通过跨基础设施团队的聚会和定期更新来避免。
工具 SRE 团队
工具 SRE 团队最适合那些拥有多个开发团队的组织,在这些组织中,开发团队需要一种标准化的方法来构建或实施软件,以衡量、维护和改进服务的系统可靠性。例如,实施一个通用框架,允许开发团队在其服务中实施自定义的度量指标仪器,从而最终帮助衡量服务的可靠性。
工具 SRE 团队旨在构建高度专业化的可靠性相关工具,并最终定义生产标准。一个主要的缺点是,很难明确区分工具 SRE 团队和基础设施 SRE 团队,因为它们的目标是为开发团队提供集中的帮助,但它们的核心焦点不同。工具 SRE 团队更加关注提高单个服务的可靠性,而基础设施 SRE 团队则更多地关注提高支撑基础设施的可靠性。
产品/应用 SRE 团队
产品/应用 SRE 团队最适合那些已经拥有厨房池、基础设施或工具 SRE 团队,并且拥有一个关键的面向用户的应用程序,其中包含多个关键服务,每个服务都需要高可靠性的组织。多个可靠服务的需求要求有一组专注于产品的 SRE 团队。这种方法有助于为团队制定清晰的使命,并与业务优先级直接相关。
另一方面,随着服务或产品的发展,始终需要添加更多的 SRE 团队。这也增加了在产品/应用 SRE 团队之间可能出现重复工作的机会。
嵌入式 SRE 团队
嵌入式 SRE 团队最适合那些只需要在特定时间段或专注于特定功能实现的组织。在这种 SRE 设置中,SRE 工程师实际上与开发团队嵌入在一起,这种参与通常是有范围限制的,或是时间有限的。
SRE 工程师在日常工作中与代码和所需配置直接接触。嵌入式 SRE 团队还可以有效地推动基础设施或工具 SRE 团队提出的提案或更改的采纳。其主要优点是能够为特定关注领域建立 SRE 专业知识。然而,另一方面,由于每个 SRE 团队将与不同的开发团队合作,可能会缺乏统一的标准化实践。
咨询型 SRE 团队
咨询型 SRE 团队最适合那些复杂性较高且现有 SRE 团队无法满足客户不断增加需求的组织。咨询型 SRE 团队与嵌入式 SRE 团队相似,但它们专注于最终客户,通常不会更改任何客户代码或配置。不过,它们可能会编写代码为自己或开发团队的同行构建内部工具,类似于工具 SRE 团队。
如果现有 SRE 团队需要额外支持,而这种支持仅是暂时性的,咨询型 SRE 团队是一个不错的选择,但另一方面,SRE 工程师可能没有足够的背景信息来做出平衡的决策。
这完成了关于各种 SRE 团队实施类型的部分。实际上,并没有推荐特定的 SRE 团队实施方式。组织通常会实施这些团队的组合,具体决策取决于多个因素,如组织的规模、SRE 采纳的成熟度以及当前的重点。
总结来说,如果一个组织的目标是开始实施 SRE,那么从全能型实施可能是最好的起点。如果开发组织规模较小,但有一个关键的面向用户的应用程序,可以从全能型实施过渡到产品/应用程序 SRE 团队实施。
然而,如果有许多开发团队具有不同的基础设施需求,那么可以从一个全能型的基础设施 SRE 团队开始,逐步实施。工具型 SRE 团队最适合那些试图通过引入常见框架来实现软件开发流程标准化的组织。工具型 SRE 团队可以与基础设施 SRE 团队互补。
嵌入式 SRE 团队更专注于特定的项目,在该项目中,开发团队和 SRE 团队紧密合作,可靠地实现服务。根据项目的关键性,这种合作模式可以出现在小型和大型团队中。最后,咨询团队最适合那些已经实施了其他类型 SRE 团队但仍然需要支持快速扩展客户需求的复杂组织。
下一个话题将详细阐述 SRE 工程师如何在服务或应用程序的生命周期中参与其中。
SRE 参与模式
SRE 的核心原则专注于在保持可靠性的同时最大化开发速度。随着服务经历其生命周期的各个阶段,SRE 团队可以持续贡献,以优化服务,并且这些团队可以在不同的阶段(如下所述)以不同的方式参与其中。
架构与设计
让我们来探索一下这个阶段对于 SRE(SRE 工程师)意味着什么:
-
在这个阶段,SRE 的参与程度非常深(且高),因为 SRE 团队可以带来他们的生产经验,提供各种见解,并有效地共同设计服务。
-
SRE 通过审视设计选择和验证所有假设来验证设计和架构。这有助于避免潜在的重新设计。
-
SRE 在设计阶段提出最佳实践,例如通过识别单点故障来增强系统的韧性。
-
SRE 根据以往经验和预估负载对比潜在的资源需求,推荐最佳的基础设施系统。
-
SRE 在设计过程中识别有效的用户旅程。
下一个阶段是积极开发。
积极开发
让我们来探索一下这个阶段对于 SRE(SRE 工程师)意味着什么:
-
一旦设计完成,SRE(SRE 工程师)可以帮助开发团队确保服务从生产的角度来进行开发。这包括容量规划、识别负载需求以及为冗余添加资源。
-
SRE 帮助规划流量激增和过载的应对策略。应对的一种方式是使用负载均衡器,同时评估需要配置的容量。在开发环境中尽早设置负载均衡器是一个好的开始,可以在初步评估行为后,在模拟生产环境的性能测试中进一步加固。
-
SRE 会思考已识别的用户旅程,并与开发团队(以及其他相关方)合作,提出满足 SLI 和 SLO 要求的方法。
-
SRE 负责添加可观测性,包括配置监控、告警和性能调优。这有助于设置所需的基础设施来跟踪 SLI 和 SLO。
开发完成后,服务会在下一个阶段向有限数量的用户开放。
有限可用性
让我们来探讨一下有限可用性阶段对于 SRE(SRE 工程师)意味着什么:
-
有限可用性指的是在正式发布之前的 Alpha(一个部分完成或仍在开发中的版本)和 Beta(一个在开发完成后首次提供给有限用户使用的版本)发布阶段。在有限可用性期间,与开发阶段相比,用户数量、潜在的使用案例、复杂性和性能需求都会发生显著变化。
-
SRE 专注于基于变化的需求来衡量性能,并通过定义 SLO 来评估可靠性。
-
SRE 让开发团队参与制定类似于实时生产环境的操作实践。这有助于模拟内部团队在生产中应期待的经验。
-
SRE 通过分配专业角色、开展模拟事件演练并为真实场景做好准备来建立事件响应团队。
下一个阶段是正式可用性。这是服务已达到稳定状态并可以被更广泛的用户或其他服务使用的阶段。
正式可用性
让我们来探讨一下正式可用性阶段对于 SRE(SRE 工程师)意味着什么:
-
服务只有通过生产准备评审(PRR)后才能进入正式可用性阶段。这是 SRE 参与并负责的最长阶段。
-
SRE 执行大部分的运维工作并负责事件响应,开发团队会提供一些帮助。
-
可能开发团队成员会与 SRE 轮换合作,这样开发团队就能深入了解运维负载。
-
SREs 将专注于跟踪服务的操作负载及相关的 SLO(服务级别目标)。这确保了错误预算没有被耗尽,并且新功能可以推出。
当当前版本的服务即将被替换时,它将进入下一个阶段,称为折旧阶段。
折旧
让我们探索一下折旧阶段对 SREs(SRE 工程师)意味着什么:
-
这指的是系统的新版本即将投入使用并取代当前版本的阶段。因此,不再添加新用户或改进功能。重点转向通过工程手段将用户从现有系统过渡到新系统。
-
SREs 继续支持现有系统直到其生命周期结束,并与开发团队并行工作,进入新服务的架构与设计阶段。
最后的阶段是废弃阶段。该阶段解释了折旧阶段过后,服务会发生什么。
废弃
让我们探索一下废弃阶段对 SREs(SRE 工程师)意味着什么:
-
一旦服务达到生命周期终点,该服务便会被废弃,SREs 对该服务的参与也随之结束。当服务不再受到开发团队的支持或不再被客户需求时,就会进入生命周期结束。
-
开发团队恢复操作支持,SREs 在力所能及的基础上支持服务事件。
这一部分完成了关于 SRE 参与模型的描述,强调了 SRE 工程师在服务生命周期中的重大影响,从服务的概念化到结束生命周期的全过程。接下来的部分将详细介绍 SRE 文化实践中的一个关键环节——事件管理。
事件管理
事件管理是 SRE 工程师的关键角色之一。事件被定义为表明服务或应用程序可能存在问题的事件。问题的性质在最好的情况下可能是轻微的,或者在最坏的情况下是停机事件。事件可以通过作为服务或应用程序监控的一部分设置的警报触发。
警报是指示与服务相关的 SLO 目标被违反或即将违反的信号。有时,尤其是对于面向外部的应用程序,事件可能是由于最终用户通过社交媒体平台的投诉引发的。这类事件包含了对当前警报系统未能识别事件的反思。
有效的事件管理是 SRE 文化实践中的关键,它对于限制事件引起的干扰至关重要,并且对尽早恢复正常业务运营至关重要。事件管理包括两个主要部分:
-
技术故障排除方面(重点是要么减轻问题,要么解决问题)
-
有效沟通方面(强调确保正确的人在正确的角色中参与,并及时告知服务消费者的相关利益相关者)
组织在处理事件管理时采用不同的方式,但如果没有采取正确的方法,就会导致事件无法得到有效管理。以下是未管理事件的两个主要特点:
-
过于侧重技术问题:一个操作问题通常会产生级联效应,尤其是在复杂的系统中。因此,在试图从单一视角解决技术问题时,常常会忽视大局。
-
沟通不畅:在试图解决当前事件时,可能没有足够关注沟通方面的问题。这将带来内部和外部的影响。从内部来看,沟通不畅会导致资源利用效率低下。有时还可能导致临时介入,多个人可能会同时处理同一个问题,甚至在同一时间对系统进行更改(这并不是理想的情况)。从外部来看,沟通不畅会导致客户感到沮丧,进而失去对服务或应用提供者的信任。
本节的下一部分将详细介绍有效实施事件管理所需的概念,从事件生命周期的主题开始。
事件生命周期
在制定有效的事件管理策略之前,了解事件的生命周期非常重要。以下是一个状态图,它提供了对事件不同状态的洞察:

图 4.1 – 事件生命周期
总结来说,基于配置的警报或社交媒体上的投诉,事件被识别。识别出的事件会被验证,以检查是否符合条件。如果符合条件,则启动事件缓解。在事件缓解后,启动根本原因分析。事件的细节会被记录,创建工单,然后事件会进入已解决状态。接下来的主题将介绍与有效事件管理相关的重要概念。
有效事件管理的要素
有效的事件响应需要多个要素的结构化管理,这是事件管理的关键。这些要素使我们能够专注于核心的 SRE 文化实践,如沟通、协作、学习、知识共享、信息流的有序管理和有效的客户通知。这有助于团队处理不同的情况,并尽快做出反应。结构化的事件响应有助于减少重复劳动,并且使团队内每个人的活动都能得到可视化。
以下是有效事故管理的一些关键要素。
声明事件
在事件导致事故的情况下,SRE 或操作人员在决定何时声明该事故时通常会面临两难。如果他们等待较长时间再声明事故,可能很难减轻事故对最终用户造成的负面影响。然而,如果过早声明,可能会导致误报。
以下是一些在决定何时声明事故时起到关键作用的指南,从定义阈值开始。
定义阈值
每个组织都应该定义一套明确的阈值,以便将事件声明为事故。这些阈值可以通过设置警报来定义。一个特定的事件可以通过单一警报或多个警报的组合来触发。也可以根据活跃警报的总数或警报的持续时间来触发事件。
下一个需要评估的指南是评估影响。
评估影响
一旦设定了指南并定义了阈值,随着警报的触发,评估事件的影响变得至关重要。评估影响时涉及多个方面,例如事件的性质、对最终用户的影响、对业务的最终影响、风险中的相关利益方或对业务的财务损失。
以下是基于可能影响如何对事件进行分类的参考模板:
-
微不足道:对产品影响很小或没有影响,但可能需要后续的行动项
-
轻微:对内部用户的影响,但外部用户可能没有察觉
-
重大:对外部用户产生影响,且有明显的收入损失,但服务仍在正常运行
-
重大/灾难性/有害:中断严重影响用户和业务,并造成重大收入损失
从高层次来看,以下问题有助于确定事件是否属于事故。如果以下任何问题的答案是是,则可以声明为事故:
-
故障对用户是否可见?
-
SRE 是否需要其他团队的专业知识来评估该事件?
-
该问题是否在一小时后仍然存在?
一旦事件被确定为事故并且其严重性级别已确认,SRE 或操作人员应通过发布声明正式宣布事故,声明中应包括严重性级别、受影响服务的列表以及可能的恢复时间估算。总结了与声明事故相关的主题,并附带一些基本指南。接下来需要讨论的有效事故管理的关键元素是职责分离。
职责分离
一旦声明了事件,应组建事件响应团队,其主要任务是缓解或解决事件。事件响应团队的成员应有明确的职责。SRE 为团队中应指定的角色提供了一组特定的角色。规定的角色如下:
-
事件指挥官(IC)
-
通信负责人(CL)
-
操作负责人(OL)
-
主要/次要响应者
-
规划负责人(PL)
每个前述角色应有明确的职权和自主性,相关内容将在接下来的子节中详细说明,首先是 IC。
事件指挥官(IC)
IC 的职责如下:
-
IC 领导指挥链,并为团队中的特定成员指定特定角色。事件响应团队的每个成员都需要向 IC 汇报。
-
IC 应当了解事件响应过程中重大事件的发生,积极协调响应过程,决定优先级并委派任务。
-
IC 的核心目标是确保问题得到缓解并最终解决。然而,IC 并不会亲自或单独修复问题。
-
IC 在事件得到缓解或解决后启动事后分析报告。
-
根据团队规模,IC 还可以承担 CL 的角色。
下一节将详细介绍 CL 的职责。
通信负责人(CL)
CL 的职责如下:
-
CL 是事件响应的对外代表,领导与外界的沟通,提供及时的更新,并且回答与事件相关的问题。
-
CL 充当屏障,避免客户/客户与事件响应团队的其他成员直接沟通。
-
CL 维护实时事件状态文档,该文档稍后用于事后分析。
下一节将详细介绍 OL 的职责。
操作负责人(OL)
OL 的职责如下:
-
OL 制定并执行事件响应计划,从而负责技术和战术工作。
-
OL 负责操作团队,该团队由主要响应者和(可选)次要响应者组成。
-
OL 始终与 IC 和 CL 保持联系。如有需要,OL 会根据事件的具体性质,向操作团队或主题专家请求额外资源。
下一节将详细介绍主要/次要响应者的职责。
主要/次要响应者
主要/次要响应者的职责如下:
-
主要响应者和(可选)次要响应者是操作团队的成员,并向 OL 汇报。他们的主要目标是执行 OL 的技术响应计划。
-
次要响应者协助主要响应者,或根据 OL 的安排被指定特定任务或职能。
下一节将详细介绍 PL 的职责。
计划负责人(PL)
PL 的责任如下:
-
PL 与运维团队合作,跟踪系统变更,并根据需要安排交接。
-
PL 安排团队之间的交接,并报告故障以跟踪长期变化。
图 4.2 展示了上述角色如何进行结构化:

图 4.2 - 说明事件管理角色
明确的角色定义使得 SRE 工程师能够专注于特定领域,并防止外部临时干预。建立一个通信岗位至关重要,这可以是一个物理位置,例如会议室,或者一个通信渠道,例如 Slack。此外,强烈建议在班次结束或一天结束时实施清晰的实时交接,确保事件能够明确地交接给另一个事件指挥官。
总结事件响应的原则
核心原则包括:保持明确的指挥链,指定清晰的角色,维护一个实时事件状态文档,确保及时向受影响方通报事件状态,执行实时交接以避免操作过载,准备事后分析报告以确定根本原因,根据需要更新操作手册,并计划尽可能频繁地进行灾难恢复(DR)演练。
关于有效事件管理,接下来需要讨论的关键元素是推荐的最佳实践。
推荐的最佳实践
以下是事件管理过程中推荐的最佳实践总结:
-
制定并记录程序。
-
优先考虑损害并恢复服务。
-
信任指定角色的团队成员。
-
如果不堪重负,寻求帮助。
-
考虑响应替代方案。
-
定期练习程序。
-
在团队成员之间轮换角色。
在下一个话题中,我们将讨论如何在事件发生后恢复服务,并防止类似事件未来发生。
恢复服务并避免重复发生
一旦宣布发生事件,事件响应团队的重点应该是排查事件。这可以通过思考服务运行过程中涉及的各种步骤并深入细节来启动。事件可能由内部或外部因素引起,应当检查这两种因素。
在检查内部因素时,应重点分析受影响领域的近期代码或配置更改。在大多数情况下,代码或配置更改可以回滚,从而恢复服务。但也会出现无法从部署角度回滚多个代码或配置更改的情况,唯一的解决办法是提供代码级修复,以便回滚这些更改。与内部因素不同,检查或处理外部因素更为复杂,因为在大多数情况下,我们对它们的控制非常有限。
无论问题的性质如何,主要目标是找到解决或减轻问题的方法。一旦问题得到减轻或解决,应该进行事后分析,目的是找出根本原因。整个过程应以无责备的方式进行,唯一目的是找到可以防止类似事故在未来再次发生的方法。
事后分析过程应产生一份事后分析报告,该报告本质上概述了事故的事件,并包含有关影响性质、可能的根本原因、触发事件、帮助识别事件的指标以及行动项列表的详细信息。此外,事后分析报告还应提供有助于未来减轻风险的清晰信息,并可作为事故后使用的案例场景。这有助于促进团队之间的学习。
本节完成了对事故管理的深入讲解。我们从尝试概述事故生命周期(图 4.1)开始,然后详细阐述了有效事故管理的关键构成,绘制了事故生命周期图,详细介绍了可能的角色及其各自的责任,并推荐了一套最佳实践。
本质上,重要的是区分何时需要报告事故,识别受影响的各方(内部或外部用户),评估影响程度,若发生事故时要有预定义的角色,并尽量遵循章程。这能避免沟通和协作中的模糊性。这样你可以专注于关键目标,即尽早减轻问题并恢复服务。同时,调查、识别并解决根本原因也至关重要,以防止问题再次发生。
下一部分将重点介绍值班过程(另一种 SRE 文化实践)以及需要考虑的关键因素。
值班
值班职责是指在工作和非工作时间内,为了支持服务或应用程序的可靠运行而进行的特定操作活动。值班职责是 SRE(站点可靠性工程师)的关键职责之一,并且从服务角度来看,它对于保持服务的可用性和可靠性也非常重要。SRE 团队(如前所述)不同于常规的操作团队,因为它的目标是强调利用工程技术来解决操作问题,并防止这些问题在大规模中发生。在值班期间,通常会涉及产品/应用程序 SRE 团队。如果是专门的服务,嵌入式 SRE 团队会参与值班工作。
当事故发生时,从启动事故管理过程到解决或缓解问题的响应时间是关键,这决定了是否能够满足所需的 SLO(服务水平目标),从而满足承诺的 SLA(服务水平协议)。在实施值班过程中,有多个因素需要考虑。以下是三项需要考虑的因素:
-
呼叫事件与非呼叫事件
-
主值班与副值班轮换
-
单站点与多站点生产团队
下一个主题讨论了呼叫事件与非呼叫事件,这是实施值班过程中的关键因素之一。
呼叫事件与非呼叫事件
呼叫事件是指需要立即关注或修复的高优先级警报,尤其是在面向用户的应用程序中。呼叫事件的例子可能包括服务健康检查失败,或者与服务相关的数据库无法接受更多连接的情况。
非呼叫事件是指低优先级警报,可能并不指示服务故障,而是指出需要解决的问题,以防这些问题发展成更大的事故。非呼叫事件的例子包括由于特定地区新功能发布导致的流量激增,或由于磁盘使用率上升至 80% 但随后通过自动化过程增加了额外 10% 的磁盘空间后自动解决的较低优先级工单。这为值班工程师提供了足够的时间,去调查磁盘使用率激增的根本原因。
呼叫事件始终是 SRE 团队的最高优先级。在这种情况下,第一步是验证该事件是否为事故,并采取适当的步骤启动事故管理流程。此外,SRE 团队还会审查非生产类呼叫事件,并根据操作负载在工作时间内处理这些事件。在配置警报规则时,区分呼叫事件与非呼叫事件非常重要,否则会导致警报疲劳。警报疲劳会让团队成员倾向于忽视重要警报。
下一个主题讨论了主值班与副值班轮换,这是实施值班过程中的关键因素之一。
主要与次要值班轮换
在某一时刻,可能会有多个 SRE 团队在值班。由于值班 SRE 团队的主要责任是通过处理分页和非分页事件(包括处理警报、工单和操作任务)来可靠地运行服务,因此通常会将 SRE 团队分为主要团队和次要团队。
将团队划分为主要团队和次要团队,实际上有助于分配任务和组织优先级。不同组织实施 SRE 的方式可能会导致团队之间的任务分配有所不同。一种实现方式是将次要团队部署为主要值班团队无法处理的分页事件的接替者,可能是因为主要值班团队正在积极处理其他事务。本质上,次要团队作为主要团队的应急团队,在出现比主要团队当前能够处理更多的分页事件时发挥作用。另一种实现方式是将主要值班团队始终指派处理分页事件,而次要值班团队则可以处理非分页的生产活动。
下一部分讨论单站点与多站点生产团队,这是实施值班流程的关键因素之一。
单站点与多站点生产团队
单站点生产团队指的是一个或多个 SRE 团队支持来自单一地点的运营。尽管团队之间的沟通和信息交流较为便利,但问题在于,特定团队必须参与夜班,从健康角度来看,长期进行夜班可能会带来不利影响。
多站点生产团队指的是来自多个地点的一个或多个 SRE 团队支持运营。典型的方法是确保这些地点位于地理上不同的区域,并采用跟随太阳轮换模式,这使得团队可以完全避免夜班。
跟随太阳轮换模式是一个常用术语,用于描述一种服务与支持方法,其中面向用户的应用程序由多个团队支持,这些团队分布在全球各地,以提供 24/7 支持,而不是迫使某个特定地点的支持团队加班,直到问题解决。在这种模式下,如果一个未解决的问题超出了特定团队的班次时间,该问题将转交给下一个班次的团队处理,同时提供之前团队的详细分析和已采取的步骤。多站点生产团队的缺点包括沟通挑战和协调开销。
下一部分讨论值班期间的推荐实践。
值班期间的推荐实践
以下是一些 SRE 在值班期间的推荐实践:
-
处理值班时的事务完全取决于方法。虽然思考需要理性和专注,但存在行动可能过于直觉和启发式的风险。应该避免这种风险。
-
直觉性的行为往往是错误的,且缺乏数据支持。直觉可能会导致值班 SRE(SRE 工程师)从一开始就走上错误的推理路径,可能浪费时间。
-
启发式方法会导致值班 SRE 在面对问题时可能采取基于假设和先前经验的方法,但这种方法可能并非最优或理性。
-
在值班时最重要的方面是拥有清晰的升级路径、明确的事件管理流程和无责文化的事后分析,以及在操作过载和操作不足之间找到平衡。
-
通过试图从根本上理解系统是如何构建、设计和应该如何工作的,培养有效的故障排除文化。这样的专业知识可以通过调查系统无法正常工作时的情况来获得。此外,还应持续关注提问,使用如什么、哪里、为什么和如何等构造,可能会引导出下一组相关的问题或答案,最终有助于故障排除。
-
避免常见的陷阱,如关注与问题无关的症状、对配置错误的影响缺乏理解、以及通过画出关联或使用不准确的假设来尝试将问题与过去的问题联系起来。
操作过载与操作不足
操作过载是一种由配置错误的监控系统或不正确的警报规则选择引起的状态,导致疲劳和压力。这通常会导致工单数量、警报页面和持续的操作支持增加。处理高优先级的工单和警报页面会导致紧张的局面,造成压力,并可能限制站点可靠性工程师继续从事工程工作。通过暂时将一位经验丰富的 SRE 借调给过载的团队作为专门帮助,可以缓解这种情况,为团队提供喘息空间,允许他们解决问题或让团队成员专注于工程项目。
操作不足是指站点可靠性工程师长时间未参与生产系统的状态。这可能会导致显著的知识差距和在突然处理生产问题时缺乏信心。如果 SRE 团队的人员配置合理,确保每个工程师每季度至少值班一次或两次,这种情况是可以避免的。
本节完成了与值班相关的过程、实施过程时可能产生的影响因素以及推荐的最佳实践。下一节将重点讨论心理安全的文化 SRE 实践及实现该目标的相关因素。
心理安全
SRE 的一个关键支柱是将失败视为正常现象。这意味着失败是不可避免的,但关键在于从失败中学习,并确保下次不会重复同样的错误。因此,SRE 促进团队内部以及团队成员与领导之间的开放沟通,以确保从过程角度客观评估失败,而不是从个人角度评估。核心理念是提供心理安全感,这对于实施无责事后分析实践至关重要。
SRE 将心理安全定义为一种信念,即经理或个人贡献者不会因以下情况而被单独挑出来、羞辱、嘲笑或惩罚:
-
犯错可能导致潜在的事件或问题
-
提出与决策相关的担忧,涉及设计、实施或流程方面的问题,这些问题可能会在未来产生不利影响
-
提出问题以进一步澄清,帮助个人或团队中的多个成员有效地执行任务或协作
-
提出可以促进创新的新想法,以进一步改进过程或服务
低心理安全的缺点
一个心理安全感较低的工作场所或团队,最终会压制学习和创新。团队成员会对澄清问题、发声或发起对话感到忧虑。这种情况会导致自我怀疑,影响能够促进创新的思想交流。
心理安全在事件管理中也非常重要。在接下来的主题中,我们将讨论一些确保心理安全的因素。
为了促进心理安全,需要克服的因素
一种无责思维促进心理安全,以下两个因素应该克服,以避免首先归咎于他人:
-
后见之明偏差:指的是一种自以为是的态度,认为某件事情最终会失败,尽管在当时并不明显。因此,往往有倾向责怪领导者,认为他们没有采取必要的措施预见问题并避免失败。
-
不适排解:指的是一种人们通过指责来排解不适的倾向。这会导致团队成员倾向于隐瞒信息、事实或不进行沟通,因担心惩罚或可能对个人或团队产生负面影响的后果。
总结来说,心理安全对团队成员至关重要,它能够让团队成员在当时最佳可用信息的基础上自由地做出决策或选择。此外,创新往往需要承担风险,这也意味着可能会面临失败的机会。无论是哪种情况,如果出现问题,重点应放在导致失败的过程上,而不是事件中涉及的人员。这样可以进行客观分析,并为团队提供自由表达想法的空间,从而促进开放的沟通和持续的改进。
头脑、心灵与行动模型
头脑、心灵与行动模型是一种促进心理安全、减少对变化恐惧的方法。头脑代表理性,重点必须放在为什么变化发生上,并应包含战略使命和愿景。心灵代表情感,重点应放在变化如何带来积极影响上。行动代表行为,重点应放在实现变化所需提供的知识、技能和资源上。
下一节将深入探讨另一组 SRE 文化实践,旨在促进分享愿景和知识,推动协作。
分享愿景与知识,促进协作
SRE 的关键支柱之一是减少组织内的孤岛现象,这可以通过创建统一愿景、分享知识和促进协作来实现。
统一愿景
组织通常会有愿景声明,用于指导其工作或代表的目标。团队的愿景应与组织的愿景一致,通常该愿景包含以下构成要素:
-
核心价值观:帮助团队建立信任与心理安全,创造承担风险和愿意学习的氛围。
-
目的:指团队存在的具体意图。
-
使命:指向团队努力实现的明确且令人信服的目标。
-
战略:指实现或达成团队使命的路径;这包括识别相关资源、能力、威胁和机会的过程。
-
目标:指团队定义的一组目标。SRE(Site Reliability Engineering)建议使用 OKRs(目标与关键结果)来设定具有挑战性的目标,推动团队完成超出预期的成就;OKRs是指目标与关键结果,一种由个人和团队使用的协作目标设定框架,旨在设定雄心勃勃的目标并在过程中衡量成果。
OKRs(目标和关键成果)可以帮助团队集中精力进行重要的任务,完成团队原本认为不可能的目标,即使他们没有完全实现预定目标。通过清晰地定义目标,并定量地分类关键成果,确保目标的达成。设定 OKRs 的目标是确保至少达到那些定义的关键成果(如果不是全部)。OKRs 可以鼓励人们尝试新事物,优先处理工作,并从成功和失败中学习。虽然团队可能无法达到每个 OKR,但它为团队提供了共同努力的目标,推动大家朝着统一的愿景前进。
沟通与协作
团队之间的沟通与协作对于实施 SRE(站点可靠性工程)至关重要。这可能包括组织内多个 SRE 团队之间的沟通,或 SRE 团队与各自产品/开发团队之间的沟通。这有助于识别共同的解决问题的方法,消除模糊性,并提供解决更复杂问题的可能性。以下是 SRE 团队提出的一些选项。
面向服务的会议
让我们了解这些会议的目的:
-
这些是强制性的会议,旨在审查服务状态并增加所有相关方的意识。
-
推荐的时长约为 30-60 分钟,并应由指定的负责人主导,且有明确的议程。
接下来,我们将讨论团队构成。
有效的团队构成
让我们来看一下如何实现有效的团队构成:
-
SRE 建议每个 SRE 团队都应该有一个有效的团队构成——特别是某些角色,如技术负责人、经理和项目经理。
-
技术负责人设定团队的技术方向。经理负责团队的绩效管理,并是团队的第一联系人。项目经理负责设计文档的审核。
另一种沟通与协作的方法是知识共享。
知识共享
这就是该方法的核心内容:
-
跨职能培训、员工对员工的网络和工作影随是最推荐的选择。
-
跨职能培训可以通过在其他领域的培训提高团队成员的能力,从而鼓励员工不断学习和成长。
-
员工对员工的网络鼓励员工通过内部信息分享会议分享他们的知识和学习。
-
工作影随是指通过观察并可能协助专家领域内的人员进行在职培训。
这部分完成了关于 SRE 文化实践的最终章节,重点是分享统一的愿景和知识,并促进沟通与协作。这也标志着本章的结束。
总结
在本章中,我们讨论了构建 SRE 团队所需的关键要素。此外,我们还讨论了帮助实施技术实践的关键文化实践。本书的第一部分(第 1-4 章)已经结束,接下来的章节(第 5-10 章)将重点介绍实施 DevOps 所需的核心 Google Cloud 服务,从第五章,使用 Cloud Source Repositories 管理源代码开始。
需要记住的要点
以下是一些需要记住的重要要点:
-
IC:负责事件响应,指定责任,并可选择承担未指定的角色,如 CL。
-
OL:负责解决或处理事件——技术和战术;通过与主要和次要响应者合作执行行动计划。
-
CL:事件响应的公共面孔;负责与所有利益相关者沟通。
-
PL: 跟踪系统变更,通过报告错误来识别长期变更,并安排交接工作。
-
指挥中心:指的是一个会议室或 Slack 频道,沟通在这里进行。
-
现场事件状态文档:由 CL 维护,记录事件及其更新,随后用于事后分析。
-
如果需要特定的专业知识,或者如果故障可见,或在一个小时左右的努力后问题仍未解决,则应报告为事件或故障。
-
为了促进心理安全,需要克服的因素:事后偏差和不适的情绪释放。
-
团队的愿景涵盖了所有驱动其工作的因素,包括核心价值观、使命、战略和目标。
-
团队的使命是一个清晰而有说服力的目标,是团队希望实现的目标。
进一步阅读
欲了解更多关于 GCP 如何实施 DevOps 的信息,请阅读以下文章:
-
SRE 基础知识:
cloud.google.com/blog/products/gcp/sre-fundamentals-slis-slas-and-slos -
SRE YouTube 播放列表:
www.youtube.com/watch?v=uTEL8Ff1Zvk&list=PLIivdWyY5sqJrKl7D2u-gmis8h9K66qoj
练习测试
请回答以下问题:
-
根据 SRE 参与模型,SRE 在哪个阶段定义 SLOs?
a) 架构与设计
b) 活跃开发
c) 限制可用性
d) 一般可用性
-
以下哪位负责在事件发生后启动事后分析报告?
a) 事件指挥官 (IC)
b) 通信负责人 (CL)
c) 运营负责人 (OL)
d) 规划负责人 (PL)
-
根据 SRE 参与模型,SRE 的参与最深或最广泛的阶段是哪个?
a) 架构与设计
b) 活跃开发
c) 限制可用性
d) 一般可用性
-
根据 SRE 参与模型,在哪个阶段 SRE 开始为生产做好服务准备?
a) 架构与设计
b) 积极开发
c) 限制可用性
d) 一般可用性
-
以下哪个角色负责响应中断或事件?
a) 事件指挥官 (IC)
b) 通讯负责人 (CL)
c) 运营负责人 (OL)
d) 计划负责人 (PL)
-
以下哪个角色负责执行中断或事件的技术响应?
a) 事件指挥官 (IC)
b) 通讯负责人 (CL)
c) 运营负责人 (OL)
d) 主要响应者 (PR)
-
选择具有以下特征的事件严重性分类:该中断对用户可见,导致明显的收入损失,但没有持久的损害。
a) 可忽略
b) 次要
c) 重大
d) 有害
-
以下哪个角色负责管理事件响应的立即、详细的技术和战术工作?
a) 事件指挥官 (IC)
b) 通讯负责人 (CL)
c) 运营负责人 (OL)
d) 计划负责人 (PL)
-
以下哪个角色负责协调响应团队的工作,以应对当前的中断或事件?
a) 事件指挥官 (IC)
b) 通讯负责人 (CL)
c) 运营负责人 (OL)
d) 计划负责人 (PL)
-
选择具有以下特征的事件严重性分类:对生产几乎没有影响,但可能需要后续低优先级的可操作项。
a) 可忽略
b) 次要
c) 重大
d) 有害
答案
-
(c) 限制可用性
-
(a) 事件指挥官
-
(a) 架构与设计
-
(b) 积极开发
-
(a) 事件指挥官
-
(d) 主要响应者
-
(c) 重大;由于收入损失,但没有持久的损害
-
(c) 运营负责人
-
(a) 事件指挥官
-
(a) 可忽略
第二部分:通过 CI/CD 实现 DevOps 的 Google Cloud 服务
本节的核心重点是深入研究 Google Cloud 服务,这些服务对于使用 Cloud Source Repositories 管理源代码、构建代码并创建构建工件、将工件推送到注册表、将工件作为容器化应用程序进行部署、通过托管计算服务在集群中编排这些应用程序、保护集群以及最后通过一系列专注于操作的服务实现已部署应用程序的可观察性至关重要。
本节介绍了与每个核心服务相关的关键特性,并根据需要提供了动手实验。所有实验都相互连接,以便提供一个全面的理解。该节最后介绍了 SLO 监控,这是 Cloud Operations 中的一个功能,允许跟踪部署到 Google Kubernetes Engine(GKE)的应用程序的 SRE 技术实践。
本节包含以下章节:
-
第五章**,使用 Cloud Source Repositories 管理源代码
-
第六章**,使用 Cloud Build 构建代码,并推送到容器注册表
-
第七章**,理解 Kubernetes 基础以部署容器化应用程序
-
第八章**,理解 GKE 基础以部署容器化应用程序
-
第九章**,使用 GKE 安全构造保护集群
-
第十章**,探索 GCP Cloud Operations
第五章:使用 Cloud Source Repositories 管理源代码
本书的第一部分(由四章组成)深入探讨了站点可靠性工程(SRE)的概念。内容包括 SRE 的技术实践、理解监控和警报以提高可靠性,以及通过应用 SRE 文化实践来建立 SRE 团队的见解。
本书的第二部分深入探讨了 GCP 的构件,以实现一个 CI/CD 流水线,重点关注以下核心领域:
-
使用 Cloud Source Repositories 管理源代码
-
使用 Cloud Build 构建和创建容器镜像
-
使用容器注册表推送容器镜像和工件
-
使用 Google Kubernetes Engine 编排容器并部署工作负载
源代码管理是持续集成(CI)流程的第一步。代码存储在源代码仓库中;常见的源代码仓库用于存储代码,允许开发者在必要时进行孤立修改,并将多个贡献者的更改合并到一个共同的代码流中。源代码仓库的常见例子包括 GitHub 和 Bitbucket。Cloud Source Repositories(CSR)是 Google Cloud 提供的一项服务,通过私有 Git 仓库提供源代码管理功能,并能轻松集成到多个 Google Cloud 服务中,例如 Cloud Build、Cloud Monitoring 和 Cloud Logging。
本章将涵盖以下主要主题:
-
关键功能:托管的私有 Git 仓库、与外部仓库的一向同步、通用代码搜索和与其他Google Cloud Platform(GCP)服务的原生集成。
-
第一步:通过控制台或命令行界面(CLI)创建第一个仓库,并向仓库中添加文件。
-
从 GitHub/Bitbucket 到 CSR 的一向同步:通过连接到外部仓库并执行近实时的一向同步来添加仓库的选项。
-
常见操作:浏览仓库、浏览文件、执行通用代码搜索、检测安全密钥,并分配适当的访问控制。
-
实践实验:逐步指导如何将 CSR 与 Cloud Functions 集成。
技术要求
主要技术要求有四个:
-
一个有效的 GCP 帐户,用于体验 GCP 服务:
cloud.google.com/free。 -
安装 Google Cloud SDK: https://cloud.google.com/sdk/docs/quickstart。
-
安装 Git:
git-scm.com/book/en/v2/Getting-Started-Installing-Git。 -
或者,可以跳过前两步,改为安装 Cloud Shell,其中包含 Google Cloud SDK 和 Git:
cloud.google.com/shell。
介绍关键功能
CSR 是 Google Cloud 提供的一个源代码管理服务。CSR 提供 Git 版本控制,并支持任何应用程序或服务的协同开发。其主要特性包括:
-
完全托管的私有 Git 仓库:此功能意味着无需管理托管源代码仓库所需的基础设施。开发人员可以将精力集中在代码的构建、测试、部署和调试上。
-
提供与 GitHub 和 Bitbucket 的单向同步:在开发者将 GitHub 或 Bitbucket 作为主要的云源代码库时,启用与其他 GCP 服务(如 App Engine、Cloud Functions、Cloud Monitoring 和 Cloud Logging)的集成相比于使用 GCP 的 CSR 要稍显复杂。例如,从 CSR 直接将代码部署到 GCP 中的无服务器服务(如 Cloud Functions)要比从 GitHub 或 Bitbucket 部署更加简便。此外,单向同步功能执行单向镜像,实质上是将 GitHub 或 Bitbucket 中的代码库实时复制到 GCP 的 CSR 中。这有助于实现与 GCP 服务的原生集成。
-
包括通用代码搜索:此功能允许在源代码仓库或跨多个仓库中进行代码搜索。搜索也可以限定在特定项目、仓库,甚至特定目录中。
-
与 GCP 服务的集成:此功能允许与多个 GCP 服务(如 Cloud Build、Cloud Operations、Cloud Functions 和 Cloud Run)进行原生集成。例如,涉及 CSR 操作的日志会自动发送到 Cloud Logging。然而,用户需要相应的 身份访问管理(IAM) 角色才能访问 Cloud Logging,以查看与 CSR 相关的日志。
身份访问管理(IAM)
IAM 是一套角色和策略框架,确保用户和应用程序能够根据最小权限原则访问所需的资源。
本章后续将详细讨论上述每个功能。接下来的部分将详细介绍创建和访问 CSR 仓库的逐步过程。
第一步 – 在 CSR 中创建和访问仓库
在使用 CSR 时,执行的第一步是实际创建一个仓库并向其中添加文件。由于 CSR 是一个托管仓库,用户无需管理用于托管仓库的空间或用于维护或执行仓库操作的计算能力。
在本节中,我们将展示如何通过 Google Cloud Console 和命令行在 CSR 中创建一个仓库。此外,我们将学习如何向空仓库中的分支添加文件并将其合并到主分支。让我们开始吧。
通过 Google Cloud Console 创建仓库
以下是通过 Google Cloud Console 在 CSR 中创建我们的第一个仓库的逐步过程:
-
启用 CSR API(图 5.1),通过在API 与服务部分下的库子部分中进行导航:
![图 5.1 – 启用 CSR API]()
图 5.1 – 启用 CSR API
-
在 GCP 中导航到源仓库并选择开始使用选项。系统将显示提示(图 5.2),并提供创建仓库的选项。如果仓库已在 CSR 中存在,请跳至步骤 3,并使用添加仓库选项:
图 5.2 – 创建您的第一个仓库的选项
-
系统将提示添加仓库,提供两种选项(图 5.3)—可以选择创建新仓库或连接到外部仓库。在这种情况下,选择创建新仓库的选项:
![图 5.3 – 创建新仓库的选项]()
图 5.3 – 创建新仓库的选项
-
通过输入仓库名称来创建一个仓库。此外,选择一个项目,该仓库应该在其下创建(图 5.4):

图 5.4 – 创建新仓库
这将通过控制台创建一个新仓库。然而,某些情况下需要通过脚本创建仓库,即通过命令行。这在自动化为核心目标并旨在消除重复劳动时特别推荐。接下来的主题将详细说明如何通过 CLI 创建仓库。
通过 CLI 创建仓库
要通过命令行或 CLI 创建一个云源仓库,请执行以下命令。必须安装 Google Cloud SDK 或使用 Google Cloud Shell:
# Enable the Cloud Source Repository API
gcloud services enable sourcerepo.googleapis.com
# Create a repository
gcloud source repos create my-first-csr --project $GOOGLE_CLOUD_PROJECT ops-2021
上述步骤将通过 CLI 创建一个新仓库。从本质上讲,通过控制台或 CLI 在 CSR 中创建的新仓库将是一个空仓库。接下来的主题将详细说明如何向 CSR 中的仓库添加文件。
向 CSR 中的仓库添加文件
一旦创建了仓库,开发人员可以创建一个分支并在该分支中进行更改。然后,在确认更改后,可以将这些更改合并到主分支中。这是一个多步骤的过程(如下面的操作步骤所示),可以通过用户的终端窗口执行,前提是安装了 Google Cloud SDK,或者通过用户选择的浏览器使用 Google Cloud Shell:
-
将仓库克隆到本地 Git 仓库:
gcloud source repos clone my-first-csr --project=$GOOGLE_CLOUD_PROJECT -
切换到新的本地 Git 仓库:
cd my-first-csr -
创建一个新分支:
git checkout -b my-first-csr-branch -
将文件添加到新分支:
touch hello.txt git add hello.txt -
提交新文件的更改到分支:
git commit -m "My first commit!!" -
推送更改到分支:
git push --set-upstream origin my-first-csr-branch -
创建一个主分支(因为这是第一次检查进入
master):git checkout -b master -
将分支合并到
master:git push --set-upstream origin master
这部分完成后,您可以创建一个空的仓库,并随后将文件添加到工作分支,然后检查到主分支。然而,也会有一些情况,用户可以选择使用 GCP 的 CSR 中的现有仓库,或 GitHub/Bitbucket 中的外部源仓库。无论哪种方式,克隆现有仓库的过程都是相同的。此外,CSR 允许从外部仓库(如 GitHub/Bitbucket)进行单向同步。所有这些细节将在下一部分中介绍。
从 GitHub/Bitbucket 到 CSR 的单向同步
CSR 提供了一种通过连接外部仓库来添加仓库并执行近实时单向同步的选项。目前,GitHub 和 Bitbucket 是唯一支持的外部源仓库。
以下是通过连接到外部 GitHub 仓库在 CSR 中创建仓库的逐步过程(类似的步骤也适用于基于 Bitbucket 的仓库):
-
在 Google Cloud Console 中导航到 Source Repositories 并选择 Add Repository 选项。
-
选择连接外部仓库的选项(图 5.5):
![图 5.5 – 连接外部仓库的选项]()
图 5.5 – 连接外部仓库的选项
-
选择一个适当的项目和外部 Git 提供商(本例中为GitHub),并授权选定的 GCP 项目存储第三方身份验证凭证,以启用连接的仓库服务(图 5.6):
![图 5.6 – 连接到 GitHub]()
图 5.6 – 连接到 GitHub
-
输入您的 GitHub 凭据,并授权 GCP 访问提供的 GitHub 账户(图 5.7):
![图 5.7 – 授权 GCP 访问 GitHub]()
图 5.7 – 授权 GCP 访问 GitHub
-
授权后,选择需要与 CSR 同步的 GitHub 仓库,然后选择 Connect selected repository 操作(图 5.8):
![图 5.8 – 连接 GCR 到选定的 GitHub 仓库]()
图 5.8 – 连接 GCR 到选定的 GitHub 仓库
-
一旦 GitHub 仓库和 GCP 的 CSR 之间建立了连接,以下提示(图 5.9)将显示。第一次同步可能需要一些时间,但随后的同步是近实时的:
![图 5.9 – 确认已与 GitHub 建立单向同步]()
图 5.9 – 确认已与 GitHub 建立单向同步
-
GitHub 仓库的内容最终将与 CSR 同步,其中也包括提交历史和任何其他可用的元数据(图 5.10):
![图 5.10 – 新添加的 GitHub 仓库的内容]()
图 5.10 – 新添加的 GitHub 仓库的内容
-
如果用户向 GitHub 仓库添加新文件,则 CSR 将执行近实时单向同步。提交和最近的更改将反映在 CSR 中的相关项目中。图 5.11 突出了新的提交历史记录:
![图 5.11 – 更新提交历史记录后进行近实时单向同步]()
图 5.11 – 更新提交历史记录后进行近实时单向同步
-
如果需要从外部仓库强制同步到 CSR 或断开与外部仓库的连接,可以导航到 GCP 中的仓库设置,找到相应选项(图 5.12):

图 5.12 – 仓库设置以强制同步或断开与 GitHub 的连接
这完成了与外部仓库(如 GitHub/Bitbucket)建立单向同步的详细步骤。下一节将介绍用户在 CSR 中可以执行的一些常见操作,如浏览仓库和文件,以及执行通用代码搜索。
CSR 中的常见操作
本节详细介绍了在 CSR 中可以执行的常见操作。选项包括以下内容:
-
浏览仓库。
-
浏览文件。
-
执行通用代码搜索。
-
检测安全密钥。
-
分配访问控制。
让我们从浏览仓库选项开始,详细介绍它们。
浏览仓库
浏览仓库有两种特定视图。这些视图分布在两个标签中:
-
所有仓库
-
我的源
所有仓库
CSR 显示了当前用户可以访问的所有可用仓库的汇总视图。仓库名称和项目 ID 的组合形成一个唯一的元组。
用户还可以通过星标标记选择的仓库(通常是最重要或最常用的)。所有被星标的仓库将出现在 我的源 标签下,方便快速访问特定仓库(图 5.13):

图 5.13 – 在所有仓库下列出的仓库列表
用户可以针对 所有仓库 标签下显示的任何仓库执行三种特定操作(参见 图 5.13 中绿色方框,按以下顺序):
-
设置:此选项允许用户编辑设置。
-
克隆:此选项提供了克隆仓库所需的详细信息。
-
权限:此选项允许您控制对仓库的访问权限,可以是用户、组或服务帐户级别。
用户可以通过从列表视图中选择一个仓库,或者从树状视图中选择一个(通过 所有仓库 的下拉控制)来访问仓库。
我的源
在所有仓库部分中,星标的仓库会列出,以便快速访问用户选择的子集。此外,最近查看的仓库(可能已经或未被星标)也会列出,并可以通过点击访问(图 5.14):

图 5.14 – 我的源的内容,显示了星标和最近查看的仓库
这就介绍了用户如何浏览 CSR 中的仓库的详细信息。接下来的主题将重点介绍如何在特定仓库中浏览文件。
浏览文件
一旦用户选择了要浏览的仓库,默认视图会切换到主分支。用户可以通过树状结构(左侧)查看文件列表,选择任何文件将显示该文件的内容(右侧)。用户还可以通过使用在云端 Shell 中编辑代码选项来编辑文件。此时,文件将在云端 Shell 编辑器中打开(图 5.15),并使用与项目关联的凭证进行身份验证。身份验证会自动进行,无需额外登录:

图 5.15 – 查看/编辑文件内容的选项
用户还可以通过选择所需的分支来切换到现有的分支(图 5.16)。此外,用户还可以按特定的标签或提交来查看文件:

图 5.16 – 切换分支或按标签或提交浏览文件的选项
如果用户想查看特定文件的历史更改信息,可以通过Blame面板(右上方)或历史子部分(图 5.17)来查看更改记录:

图 5.17 – 查看特定文件的历史更改信息(CSR)
这就介绍了用户如何在特定仓库中浏览文件的详细信息。接下来的内容将重点介绍用户如何在 CSR 中执行跨仓库或单一仓库的通用代码搜索。
执行通用代码搜索
CSR 提供通过 CSR 控制台上的搜索框搜索代码片段或文件的功能。用户可以通过输入文本(最好用双引号括起来)或使用正则表达式进行搜索。
搜索范围可以设置为四个可能的级别之一(图 5.18):
-
所有内容:搜索用户有权限访问的所有仓库。
-
此项目:搜索当前项目中的所有仓库。
-
此仓库:在当前仓库中进行搜索。
-
此目录:在当前目录中进行搜索:

图 5.18 – 执行通用代码搜索的可能范围
下一个主题涵盖了基于不同过滤条件执行代码搜索的可能方式及其相应的语法。
搜索过滤器
下表列出了一些可以用于搜索代码的搜索过滤器:

这部分详细介绍了用户如何执行通用代码搜索。接下来的主题将重点介绍 CSR 中的一个特定功能,该功能能够在用户尝试进行代码提交时,强制执行策略以检测安全密钥。
检测安全密钥
CSR 提供了检测代码库中是否存储安全密钥的选项。如果启用了此功能,当用户尝试将代码推送到代码库中的分支或主分支时,CSR 会强制执行此检查。如果文件内容包含安全密钥,则代码将无法推送,并且用户将收到通知。
当前,CSR 可以设置检查以下类型的安全密钥:
-
JSON 格式的服务账户凭据
-
PEM 编码的私钥
以下命令将提供启用、禁用或覆盖安全密钥检测的功能:
# To enable security key detection
gcloud source project-configs update --enable-pushblock
# To disable security key detection
gcloud source project-configs update --disable-pushblock
# To override security key detection at a commit level
git push -o nokeycheck
这部分详细介绍了如何在代码提交过程中检测安全密钥。下一个主题将关注在 CSR 中执行操作所需的访问控制。
分配访问控制
对代码库的访问可以在项目级别或代码库级别进行分配。如果用户在项目级别分配了特定角色,则该角色将应用于该项目中所有代码库的用户。然而,如果用户为某个特定代码库分配了角色,则该角色仅适用于该代码库。
下表总结了访问 CSR 或在 CSR 上执行操作所需的关键 IAM 角色:

下一个主题提供了有关如何设置跨账户项目访问的信息。
跨账户项目访问
如果用户属于项目 A,但需要访问项目 B 中的特定代码库,则应根据用户在项目 A 中的预期作用域,将 Source Repository Reader/Writer/Admin 角色分配给该用户,适用于项目 B 中的特定代码库。这可以通过代码库设置中的权限部分来实现。
这部分详细介绍了 CSR 特定的访问控制。也意味着我们已经完成了一个关于用户可以在 CSR 中执行的常见操作的主要部分。接下来的部分是一个实践实验,其中将使用托管在云源代码库中的代码部署云功能。
实践实验 – 与云功能集成
本实践实验的目标是演示 GCP 计算服务(如云功能)与 CSR 之间的集成。目的是说明如何通过拉取托管在 CSR 中的代码来部署代码到云功能。以下是高层次的步骤总结:
-
通过 Cloud Shell 编辑器向现有代码库添加代码。
-
从 Cloud Shell 编辑器(本地代码库)将代码推送到 CSR。
-
创建云函数并从 CSR 中的代码库部署代码。
通过 Cloud Shell 编辑器向现有代码库添加代码
本小节专门介绍了如何向现有代码库添加代码。开发者通常使用其喜爱的编辑器进行代码更改。以下是使用 GCP 的 Cloud Shell 编辑器的示例,这是一个在线开发环境,通过 Cloud Code 插件支持云原生开发,并提供对 Go、Java、.NET、Python 和 Node.js 的语言支持。
-
在 GCP 控制台中导航至源代码库。
-
导航至您希望添加代码的代码库。您可以使用之前创建的
my-first-csr代码库。 -
选择在 Cloud Shell 中编辑操作。这会在 Cloud Shell 编辑器中打开代码,并将代码从 CSR 克隆到 Cloud Shell 控制台下的本地代码库。
-
添加名为
main.py的新代码文件。从github.com/PacktPublishing/Google-Cloud-Platform-for-DevOps-Engineers/blob/main/cloud-build/main.py复制此文件的内容。 -
保存代码文件。
代码编辑和添加完成后,下一步是将代码推送到 CSR。这将作为下一个主题进行讨论。
从 Cloud Shell 编辑器(本地代码库)将代码推送到 CSR
本小节专门介绍如何将代码从 Cloud Shell 编辑器的本地代码库推送到 CSR。可以在 Cloud Shell 内打开终端,提供命令行指令。下面详细描述了推送代码的命令行方法:
-
切换到 Cloud Shell 编辑器中的控制台窗口。
-
执行 Git 操作以添加新文件并提交更改:
# Add new code file to the repository git add main.py # Commit the changes to the repository git commit -m "Adding main.py" -
使用 Cloud Shell 编辑器将包含新更改的本地代码库推送到托管在 CSR 中的代码库中。在
/p后指定适当的项目,并在/r后指定 CSR 中目标代码库:# Add local repository in Cloud Shell Editor as remote git remote add google \ https://source.developers.google.com/p/gcp-devops-2021/r/my-first-csr # The above will create a remote repository with changes from the local repository # Push code to Cloud Source Repositories git push --all google # The above git push command will push the changes in the remote repository with specific project and repository name to google cloud source repositories -
在 CSR 中导航至目标代码库(例如
my-first-csr),以查看新添加的 Python 文件,main.py。
一旦代码从远程分支推送到 CSR,代码将在主分支中可用,现在可以部署到任何计算选项中。下一个主题说明了从 CSR 下载源代码并将其部署到 GCP 无服务器计算选项(Cloud Functions)的步骤:
创建云函数并从 CSR 中的代码库部署代码
本小节特别说明了 CSR 如何与其他 GCP 计算选项(例如 Cloud Functions)集成:
-
在 GCP 控制台中导航至Cloud Functions。
-
选择创建函数的选项(如果在项目中首次创建函数,则此操作将启用 Cloud Functions API)。
-
输入一个你选择的函数名称,并选择区域、触发类型和身份验证方式。保存选项并继续。以下是示例:
a)
my-first-csrb)
us-central1c)
HTTPd)
允许未经身份验证的调用 -
设置运行时为 Python 3.8,源代码选项设置为 Cloud Source Repository。
-
输入与需要部署代码的仓库相关的详细信息,并选择
hello_world作为值。b)
my-first-csr作为值。c)
master作为值。d)
/作为值:![图 5.19 – 配置云源代码库作为源代码选项]()
图 5.19 – 配置云源代码库作为源代码选项
-
函数将成功部署(图 5.20)。可以通过列表页面中 操作 下的 测试函数 选项,或通过云函数的 详细信息 部分中指定的触发 URL 来测试该函数:

图 5.20 – 云函数成功部署
这完成了一个详细的实验,用户使用 GCP 的 Cloud Shell Editor 进行代码更改,通过 GCP 的 CSR 推送到一个仓库,并将代码部署到 GCP 的计算选项之一,如 Cloud Functions。
摘要
在本章中,我们讨论了 Google Cloud 提供的服务,用于管理源代码并提供 Git 版本控制,以支持协作开发。这是建立 CI/CD 流程中的第一个关键构建模块。此外,我们还讨论了可以在 CSR 中执行的各种操作,并通过动手实验演示了 CSR 与 Cloud Functions 的原生集成。下一章将重点介绍构建代码、创建镜像工件和管理工件所需的 Google Cloud 服务。这些服务包括 Cloud Build 和 Container Registry。
需要记住的要点
以下是一些需要记住的重要事项:
-
CSR 是一个完全托管的私有 Git 仓库。
-
CSR 提供与 GitHub 和 Bitbucket 的单向同步。
-
CSR 提供了一个功能,可以进行通用的代码搜索,搜索可以设置为特定项目、特定仓库、特定目录或全部。
-
CSR 可以设置为检测安全密钥。目前支持的类型包括 JSON 格式的服务账户凭证和 PEM 编码的私钥。
-
CSR 提供了一个功能,可以在提交级别覆盖安全密钥检测。
-
支持的访问控制包括 Source Repository Reader/Writer/Admin。
进一步阅读
有关 GCP 的 Cloud Source Repositories 的更多信息,请参阅以下内容:
- Cloud Source Repositories:
cloud.google.com/source-repositories
实践测试
回答以下问题:
-
选择可以通过 CLI 创建名为
my-first-csr的新仓库的命令:a)
gcloud create source repos my-first-csrb)
gcloud source repos create my-first-csrc)
gcloud create source repos my-first-csrd)
gcloud source repo create my-first-csr -
以下哪个选项允许与 CSR 进行单向同步?
a) GitHub
b) Bitbucket
c) 以上都不是
d) 选项 a 和 b
-
选择从支持的仓库类型到 CSR 的单向同步频率:
a) 每 5 分钟
b) 可配置
c) 实时
d) 接近实时
-
以下哪个不是 CSR 支持的搜索过滤器?
a) 搜索文件内容
b) 按语言搜索
c) 按功能搜索
d) 通过包含关键词进行搜索
-
如果是
git addc)
git pushd)
git commit -
选择覆盖提交级别安全密钥检测的命令:
a)
git push -o keycheckb)
git push -o nokeycheckc)
git push -o anykeycheckd)
git push -o nonekeycheck -
选择两条命令来启用和禁用安全密钥检测:
a)
gcloud source project-configs update --enable-codeblockb)
gcloud source project-configs update --enable-pushblockc)
gcloud source project-configs update --disable-codeblockd)
gcloud source project-configs update --disable-pushblock -
以下哪个不是 CSR 的有效访问控制?
a) 源仓库读取者
b) 源仓库写入者
c) 源仓库编辑者
d) 源仓库管理员
-
以下哪个访问控制可以更新仓库,但不能创建仓库?
a) 源仓库读取者
b) 源仓库写入者
c) 源仓库编辑者
d) 源仓库管理员
-
以下哪些访问控制可以更新仓库配置?
a) 源仓库读取者
b) 源仓库写入者
c) 源仓库编辑者
d) 源仓库管理员
答案
-
(b) –
gcloud source repos create "my-first-csr" -
(d) – 选项 a 和 b
-
(d) – 接近实时
-
(d) – 通过包含关键词进行搜索
-
(d) –
git commit -
(b) –
git push -o nokeycheck -
(b) –
gcloud source project-configs update --enable-pushblock和 (d) –gcloud source project-configs update --disable-pushblock -
(c) – 源仓库编辑器
-
(b) – 源仓库写入者
-
(d) – 源仓库管理员
第六章:使用 Cloud Build 构建代码,并推送到容器注册表
上一章集中讲解了如何使用Cloud Source Repositories(CSR)管理源代码。CSR 提供了一个完全托管的私有 Git 仓库,支持与 GitHub 和 Bitbucket 的单向同步,并与 GCP 服务集成。这是持续集成(CI)流程的第一步。
本章将重点介绍构建代码、使用 Cloud Build 创建镜像工件以及使用 GCP 的容器注册表管理工件所需的构造。这构成了 CI 工作流的核心,因为代码不断构建,工件不断创建并存储在注册表中,应用程序代码也在不断地作为容器进行部署。
在本章中,我们将涵盖以下主要内容:
-
关键术语 – Docker 和容器相关术语的快速概述
-
理解自动化的必要性 – 通过探索 Docker 生命周期来理解自动化的必要性
-
构建和创建容器镜像 – Cloud Build 必备内容,如云构建器和构建配置文件、构建代码、存储和查看构建日志、管理访问控制以及优化构建速度的最佳实践
-
管理容器工件 – CSR 必须掌握的内容,包括推送和拉取镜像、管理访问控制、配置身份验证方法,以及与 CSR 的 CI/CD 集成。
-
实践实验 – 当代码更改推送到主分支时,逐步指导如何将应用程序部署到 Cloud Run
技术要求
有三个主要的技术要求:
-
拥有有效的Google Cloud Platform(GCP)账户以便进行 GCP 服务的实际操作:
cloud.google.com/free。 -
安装 Google Cloud SDK:
cloud.google.com/sdk/docs/quickstart。 -
安装 Git:
git-scm.com/book/en/v2/Getting-Started-Installing-Git。
关键术语(前提条件)
在尝试构建、部署和维护一个运行在容器上的分布式应用程序时,有几个关键术语是非常重要的。以下是一些处理容器时需要理解的关键术语的快速概述:
-
操作系统 – 操作系统(OS)是控制计算机硬件和软件需求的系统软件,涉及多个应用程序,如内存、CPU、存储等。操作系统协调任务,以确保每个应用程序能够获得其成功运行所需的资源。操作系统由内核和软件组成。内核负责与硬件交互,而软件则负责运行 UI、驱动程序、文件管理器、编译器等。
-
虚拟化 – 虚拟化是通过创建计算、存储、网络等的虚拟或软件版本来以更少的资源做更多的事情。它允许在同一物理硬件上运行多个应用程序。每个应用程序及其关联的操作系统可以在单独的、完全隔离的、基于软件的机器上运行,这种机器被称为虚拟机或VM。
-
虚拟机监控器 – 虚拟机监控器是一种软件,用于创建和运行虚拟机(VM),并实现虚拟化的概念。虚拟机监控器允许一台主机计算机支持多个客户虚拟机,通过虚拟化共享内存、存储、处理能力等资源,并负责为每个虚拟机提供所需的资源以达到最佳性能。
-
容器 – 容器是一种软件单元,打包了代码及其所有依赖项,包括库和配置文件。这使得应用程序能够在各种计算环境中快速且可靠地运行。容器使用低级操作系统构造,允许你指定独特的系统用户、主机名、IP 地址、文件系统段、内存和 CPU 配额。
-
Docker – Docker 是一个开源平台,用于开发、构建、部署和管理容器化应用程序。Docker 使用操作系统级虚拟化技术,将软件打包成容器,从而提供在任何地方运行的灵活性。Docker 也可以运行任何操作系统,只要底层操作系统内核是 Linux。例如,容器可以运行不同版本的 Linux 操作系统,如 Debian、CentOS、Fedora 等等。
-
Docker 守护进程 – Docker 守护进程表示运行一个或多个容器的服务器。它是运行主机操作系统的服务。此外,命令行界面(CLI)表示客户端,CLI 与 Docker 守护进程的结合形成了客户端-服务器架构。
-
Dockerfile – Dockerfile 是一个文本文件,包含一系列可以从命令行执行的命令,用于可能地构建镜像。Dockerfile 是 Docker 用来构建镜像的输入文件。该过程自动化了执行一系列指令或命令。
-
Docker 层 – Docker 层表示通过执行 Dockerfile 中的每个指令创建的中间镜像。指令与中间镜像之间的关联存储在构建缓存中。Docker 容器本质上是一个镜像,其上建立了一个可读/写的 Docker 层,且基于多个只读镜像。
-
Docker 镜像 – Docker 镜像由多个 Docker 层组成,这些层用于在一个或多个容器中执行代码。本质上,Docker 镜像代表着一个需要执行的计划,或者换句话说,是需要部署的计划。
下一节将说明 Docker 生命周期,并强调网站可靠性工程(SRE)的一个关键目标,即通过投资自动化来消除繁琐工作。
理解自动化的必要性
一旦代码提交到源代码仓库,CI 流程中的下一步是根据运行应用程序的需求构建代码并创建工件。一旦工件创建完成,它们将进一步存储在仓库中,并由持续部署/交付(CD)过程在后续运行应用程序。鉴于本书的主题是与容器一起工作,Docker 作为操作系统级虚拟化平台,在容器中部署应用程序时起着关键作用。
以下是 Docker 生命周期的示意图,突出显示了从创建容器镜像到实际部署运行应用程序的容器所涉及的多个步骤:
-
开发者将代码托管在源代码仓库中。代码可以在开发或增强过程中进行更改。
-
可以设置源代码仓库,以便在特定触发点,如提交拉取请求或将代码合并到特定分支时触发。这些触发点可以与代码构建过程挂钩。
-
代码构建过程会查找一个 Dockerfile,它本质上是一组指令,用于创建应用程序及其依赖项。
-
使用 Dockerfile 创建构建工件——容器镜像,命令是
docker build。 -
创建的镜像可以推送到工件仓库中存储容器镜像,例如 Docker Hub 或 GCP 的容器注册表等。
-
应用程序是通过将容器镜像从仓库下载到计算环境中并随后构建一个容器来创建的,该容器本质上是一个包含代码、库和依赖项的包。
如果将上述步骤转换为实际命令,它将如下所示:
#Build code using the Dockerfile
docker build -t <image-name> .
#Tag the locally created image with the destination repository
docker tag <image-name> <host-name>/<project-id>/<image-name>
#Push the tagged image to the choice of repository
docker push <host-name>/<project-id>/<image-name>
# Note that hostname refers to the location where image is stored. 'gcr.io' refers that by default the images are stored in Cloud Storage; specifically US location
#To deploy the application, pull the image from the repository as a pre-requisite
docker pull <host-name>/<project-id>/<image-name>
#To deploy or run the application
docker run –name <container-name> <host-name>/<project-id>/<image-name>
Docker 工作流中提到的步骤是需要按顺序执行的步骤。如果需要修复代码或进行增量代码更改,那么必须重复这些步骤,以便重新构建、推送和部署代码。这就形成了一个重复或甚至是无限循环,给开发者带来了很多痛苦和困扰。这是因为手动步骤越多,出错的机会就越大。这符合繁琐工作的定义,因为这些步骤是手动的、重复性的、没有价值的,并且可以自动化。
鉴于 SRE 的目标是通过自动化消除繁琐工作,这构成了一种可行的方法来消除痛苦和困扰的无限循环。此外,上述步骤需要在一个需要特别关注或设置的环境中执行。例如,需要设置 Docker 来执行上述命令。此外,机器需要具备足够的计算能力和存储要求,以便以重复的方式运行这些步骤。如果同时发起多个并行构建,机器还需要进行扩展。
GCP 提供了一项名为 Cloud Build 的服务,它是一个自动化引擎,在 CI/CD 工作流中扮演着关键角色。Cloud Build 可以导入源代码,在受管理的工作区中构建,并创建如 Docker 镜像、Java 包、二进制文件等工件。Cloud Build 实际上可以将构建、标记和推送容器镜像的步骤合并为一个配置文件。由 Cloud Build 创建的容器工件可以被推送并存储在另一个 GCP 服务——容器注册表(Container Registry) 中。在容器部署时,容器镜像可以从容器注册表中拉取。Cloud Build 能够将所有这些步骤自动化为声明式语法;也称为构建配置文件,可以根据需要有效地多次执行。
接下来的部分将详细介绍以下内容:
-
Cloud Build 作为 GCP 服务来构建和创建容器镜像
-
容器注册表作为 GCP 服务来管理容器工件
构建和创建容器镜像 – Cloud Build
Cloud Build 是一个基于源代码库提交构建和创建工件的服务。Cloud Build 生成的工件可以是容器或非容器工件。Cloud Build 可以与 GCP 的 CSR 以及流行的外部代码库如 GitHub 和 Bitbucket 集成。Cloud Build 的主要特点包括以下几点:
-
无服务器平台:Cloud Build 消除了预先配置服务器或为构建代码和生成工件所需的计算能力或存储付费的需求。根据并行提交的数量,扩展或缩减是一个内建的过程,不需要人工干预。
-
访问构建器镜像的能力:Cloud Build 提供了云构建器,它们是预先配置好的、可以立即使用的容器镜像,支持多种常见语言和工具。例如,Docker Cloud Builders 运行 Docker 工具。
-
添加自定义构建步骤的能力:Cloud Build 需要一个构建配置文件,用户可以在其中明确指定步骤的列表。用户还可以指定执行顺序,并根据需要包含任何依赖关系。
-
专注于安全性:Cloud Build 支持漏洞扫描,并提供定义策略的能力,可以阻止有漏洞的镜像被部署。
这些 Cloud Build 特性所基于的基础是一些关键要素,接下来的子部分将会讨论这些要素。
Cloud Build 基础知识
关于 Cloud Build,有两个关键的基本概念,分别是云构建器和构建配置。
Cloud 构建器
云构建器是运行构建过程的容器镜像。云构建器中的构建过程本质上是一组预定义的构建步骤。此外,云构建器还可以包括自定义构建步骤。云构建器镜像包含了常见的编程语言和工具。Cloud Build 可用于在云构建器的构建容器内运行特定命令。云构建器可以是 Google 管理的、社区贡献的,或是公共的 Docker Hub 镜像。
Google 管理的构建器
Google 提供了可以用于执行一个或多个构建步骤的托管预构建镜像。这些预构建镜像存储在 Google 的容器注册表中。常见的示例包括 docker builder(执行 docker build、docker tag 和 docker push 命令)、gcloud builder(执行 docker run 命令以部署到 Google 服务,如 Cloud Run)、gke-deploy builder(在 GKE 集群中进行部署)等。Google 管理的构建器完整列表可以在 github.com/GoogleCloudPlatform/cloud-builders 查找。
社区贡献的构建器
社区贡献的构建器是开源构建器,由 Cloud Build 开发者社区管理。这些不是预构建的镜像,而是由开发者社区提供源代码。个别适配者需要构建源代码并创建镜像。常见示例包括 Helm(用于管理 Kubernetes 包)、Packer(用于自动化创建镜像)等。社区贡献构建器的完整列表可以在 github.com/GoogleCloudPlatform/cloud-builders-community 查找。
公共 Docker Hub 构建器
公共 Docker Hub 构建器指的是可以用来执行一组构建任务的公开可用的 Docker 镜像。从思维方式角度来看,这些构建器与 Google 管理的构建器非常相似,但这些镜像不存储在 Google 容器注册表中,而是存储在 Docker Hub 中。公共 Docker Hub 构建器的完整列表可以在 hub.docker.com/search?q=&type=image 查找。
构建配置
构建配置是一个配置文件,封装了执行与构建相关任务的步骤。构建配置文件可以采用 JSON 或 YAML 格式编写。配置步骤特别使用云构建器,这些构建器可以是预构建的镜像(由 Google 管理或公共 Docker 镜像)或由开发者社区维护的代码构建的镜像,基本上代表了可以重用的模板化步骤,并且可以选择传递显式参数。这些模板化步骤可以用来获取依赖项、执行单元和集成测试,以及使用构建工具(如 Docker、Gradle、Maven、Bazel 和 Gulp)创建工件。例如,一个构建配置文件可能包含构建、打包并将 Docker 镜像推送到选定容器注册表的指令。该文件的结构将在下一小节中详细介绍。
结构
一个构建配置文件包含多个字段或选项。其中最重要的是构建步骤(参见 图 6.1)。可以定义一个或多个构建步骤,以反映构建过程中所需的任务。每个构建步骤本质上执行一个 Docker 容器,并提供灵活性以包含多个选项:
-
Name:指定一个云构建器,它是一个运行常用工具的容器镜像。
-
args将用作该入口点的参数;如果未指定,args中的第一个元素将用作入口点,其余部分将用作参数。 -
Env:接受一个以键值对形式列出的环境变量列表。
-
/workspace)或特定的绝对路径。 -
id:用于为构建步骤设置唯一标识符。
-
waitFor:如果需要某个特定的构建步骤先于其他步骤运行,则使用此选项。如果未指定,则需要完成所有前置步骤后,当前构建步骤才能执行。
-
entrypoint:用于覆盖云构建器提供的默认入口点。
-
secretEnv:允许您定义由 Cloud KMS 加密的环境变量列表。
-
volumes:表示一个 Docker 容器卷,该卷被挂载到构建步骤中,以便在构建步骤之间持久化工件。
-
timeout:指定构建可以运行的时间。默认值为 10 分钟,最大允许值为 24 小时。时间应以秒为单位指定。
图 6.1 显示了一个构建配置文件的骨架结构,该文件可能由一个或多个构建步骤组成:

图 6.1 – 构建配置文件中的构建步骤
除了构建配置文件中构建步骤所包含的选项外,更多的可能选项及其详细信息可以在cloud.google.com/cloud-build/docs/build-config找到。
使用 Cloud Build 构建代码
云构建器和构建配置文件的结合构成了 Cloud Build 的核心。当 Cloud Build 启动时,后台会执行以下步骤:
-
将应用代码、Dockerfile 和其他资源压缩成一个文件。
-
压缩后的代码然后会被上传到 Cloud Storage 存储桶,这可以是 Cloud Build 在每个项目基础上创建的默认存储桶,也可以是用户提供的 Cloud Storage 存储桶。
-
构建以上传的文件作为输入启动,构建的输出是一个带有提供的镜像名称的容器镜像。
-
然后,容器镜像会被推送到容器注册表或选择的目标注册表。
有多种方法可以通过 Cloud Build 手动调用构建过程,并使用触发器进行自动构建。
Cloud Build – 通过 gcloud CLI 手动调用
有两种方法可以通过 gcloud 命令行工具手动启动 Cloud Build,这基本上使用了 Cloud Build API:
-
使用 Dockerfile
-
使用 Cloud Build – 构建配置文件
以下小节将详细介绍通过 Cloud Build 启动构建的两种方法。
Cloud Build – 使用 Dockerfile 进行手动构建
Dockerfile 应包含使用 Cloud Build 构建 Docker 镜像所需的所有信息。以下命令将手动启动构建过程。此命令应从包含应用代码、Dockerfile 和任何其他所需资源的目录运行:
# Format to invoke the build manually using Dockerfile
gcloud builds submit --tag <host-name>/<project-id>/<image-name> <app-code-directory-path>
#Example (. Indicates current directory)
gcloud builds submit –tag gcr.io/gcp-devops-2021/manual-dockerfile-image .
一旦构建完成,构建 ID 将显示在终端或 shell 中,build 命令从中被调用。该构建 ID 可以用于过滤 Cloud Build 控制台中显示的构建,并且后续可以用于查看构建日志。此外,新的镜像将根据前面的示例推送到容器注册表。
Cloud Build – 使用构建配置文件手动构建
另一种通过 Cloud Build 启动手动构建的方法是使用构建配置文件。构建配置文件使用云构建器,这些构建器在模板化规格文件中至关重要,能够最小化手动步骤。
以下是一个示例构建配置文件,使用 docker 云构建器来构建代码并将镜像推送到容器注册表。这里使用的容器镜像名称是 builder-myimage,配置文件的名称是 cloudbuild.yaml:
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/builder-myimage', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/builder-myimage']
- name: 'gcr.io/cloud-builders/gcloud'
以下命令将使用构建配置文件(在本例中是 cloudbuild.yaml)以及源代码路径作为输入,启动 Cloud Build 过程:
# Format to invoke the build manually using the build configuration file
gcloud builds submit --config <build-config-file> <source-code-path>
#Example 1 (Source code is located in the current directory)
gcloud builds submit --config cloudbuild.yaml .
#Example 2 (Source code is located in a cloud storage bucket)
gcloud builds submit --config cloudbuild.yaml gs://my-cloud-build-examples/cloud-build-manual.tar.gz
Cloud Build – 使用触发器自动构建
手动调用 Cloud Build 不适用于 CI/CD 工作流,因为它增加了额外的工作量。推荐的方法是每当检测到合适的事件时自动构建代码。Cloud Build 通过触发器选项来支持此功能。
用户可以创建一个触发器,该触发器可以在以下合格事件之一发生时被触发:
-
推送到一个分支。
-
推送一个新的标签。
-
拉取请求(仅限 GitHub 应用)。
该触发器持续监控配置的仓库中的事件。如果该事件发生,触发器将使用 Dockerfile 或 Cloud Build 配置文件(如触发器上所配置的)启动构建过程,随之而来的是生成构建工件。本章节末尾将展示一个逐步的实操实验。
Dockerfile 与 cloudbuild.yaml
Dockerfile 允许你使用 docker build 命令构建和组合 Docker 容器镜像。Dockerfile 还允许你通过 bash 命令将构建步骤合并在一起;这些步骤可以包括特定于 Google Cloud 的命令;例如,在某个步骤中指定安装 Google Cloud SDK。
与使用 Dockerfile 相反,Cloudbuild.yaml 也允许你构建和组合 Docker 容器镜像,并利用 Google 管理的或社区管理的构建工具,这些工具带有预构建的镜像,并提供更多定制化选项。选择两者之间的区别在于用途、所选云平台和定制化的便利性。
这部分内容讲解了如何通过 Cloud Build 发起构建。接下来的小节将关注存储和查看构建日志的相关细节。
存储和查看构建日志
Cloud Build 会为作为构建过程一部分执行的操作创建日志记录。这些日志信息会存储在 Cloud Logging 中。此外,Cloud Build 还会将日志信息存储在 Cloud Storage 存储桶中。实际上,在启用 Cloud Build API 后,会为每个项目创建一个默认的 Cloud Storage 存储桶。该存储桶的命名格式为<project-id_cloudbuild>。与每个构建相关的日志会被压缩并存储在存储桶中。
因此,存储 Cloud Build 日志的默认选项是同时存储在 Cloud Logging 和 Cloud Storage 存储桶中。不过,你可以在构建配置文件中通过使用logging字段明确选择这两者之一。
-
如果设置为
CLOUD_LOGGING_ONLY,则日志只会写入 Cloud Logging。 -
如果设置为
GCS_ONLY,则日志只会写入 Cloud Storage 存储桶。除非显式指定 Cloud Storage 存储桶,否则将使用默认存储桶,方法是使用logsBucket选项。
用户可能会选择除默认选项以外的其他选项,可能是由于成本限制,或者可能是将日志引入到另一个日志框架中,而 Cloud Storage 存储桶则作为数据源。
以下是一个代码示例,演示了在构建配置文件中使用logging选项的方法:
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/myproject/myimage', '.']
options:
logging: GCS_ONLY
logsBucket: 'gs://mylogsbucket'
可以通过 Cloud Logging 控制台查看日志。如果需要查看单个构建级别的日志,建议通过 Cloud Build 控制台查看日志。Cloud Build 控制台中的信息将来源于 Cloud Storage 存储桶(无论是默认存储桶还是显式存储桶)。为了查看日志,用户应该拥有Storage Object Viewer 角色或 Project Viewer 角色。
查看构建日志,请按照以下步骤操作:
-
在 GCP 控制台中导航到Cloud Build(默认情况下,用户将被带到构建历史页面)。
-
选择一个构建以查看其相应的日志(成功的构建会显示为绿色,否则为红色)。
-
用户可以查看每个构建步骤的构建日志。此外,执行详细信息和任何相关构建工件的存储位置也会显示。可选地,还会显示云日志的来源(请参见图 6.2):

图 6.2 – 来自 Cloud Build 的构建日志
如果需要删除构建日志,则无法从 Google 创建的日志存储桶中删除日志。但是,可以从用户创建的日志存储桶中删除日志,或者通过删除包含一个或多个构建日志的用户创建的存储桶来删除日志。这需要用户具有访问 Cloud Storage 的权限以删除文件——通过 Cloud Storage,具体来说是需要具有 Storage Admin 或 Storage Object Admin 角色(具体取决于删除整个用户创建的存储桶还是删除特定的构建日志文件)。
管理访问控制
构建可以由用户或应用程序触发。根据 Google 的推荐做法,如果应用程序需要访问某项服务,则可以通过服务账户进行访问。因此,准确来说,Cloud Build 的访问控制可以通过终端用户 IAM 角色或Cloud Build 服务账户来管理。
终端用户 IAM 角色
Cloud Build 提供了一组预定义的 IAM 角色,可以提供精细的访问控制,并且可以与特定的工作角色对齐。这可以防止不必要的访问,并允许你实施最小权限原则。
以下表格总结了访问或执行 Cloud Build 操作所需的关键 IAM 角色:

Cloud Build 服务账户
Google 推荐在任务需要由应用程序执行或代表用户执行时使用服务账户(SA)。服务账户是一种特殊类型的账户,应用程序或虚拟机(VM)可以使用它来进行授权的 API 调用,但个人用户不能使用。在这种情况下的常规做法是创建一个 SA,并为该 SA 分配必要的权限,以便拥有该 SA 的应用程序可以执行必要的操作。
Cloud Build 会在启用 Cloud Build API 时为项目创建一个特定的 Cloud Build SA。此 Cloud Build SA 被分配了最小权限,例如 Cloud Storage。如果您希望使用其他服务,则需要更新 SA 以反映所需的权限。
为 Cloud Build SA 预先分配的权限集将基本允许 Cloud Build 代表用户执行以下操作:
-
创建、列出、获取或取消构建。
-
创建、修补、删除或运行构建触发器。
-
从 CSR 中拉取源代码。
-
在 Container Registry 中存储镜像并获取镜像。
-
在 Cloud Storage 中存储工件并获取工件。
-
在 Artifact Registry 中存储工件并获取工件。
-
在 Cloud Logging 中创建构建日志。
-
将构建日志存储在用户创建的日志存储桶中。
-
将构建更新推送到 Pub/Sub。
-
获取项目信息并列出项目。
本文结束了关于访问控制管理的主题,提供了所需的 IAM 角色的见解。接下来的主题将专注于执行构建过程时的最佳实践,旨在有效减少构建执行时间。
Cloud Build 最佳实践 – 优化构建
减少构建时间有助于优化构建过程。考虑到重点是处理容器,提升构建速度有两种常见策略:
-
构建更精简的容器:作为该策略的一部分,如果不将构建时依赖相关文件和任何中间文件包含在容器镜像中,则可以减少容器的大小。
-
--cache-from参数可以作为后续构建的起点使用。缓存的镜像将从注册中心检索。缓存的 Docker 镜像仅支持 Docker 构建,不支持云构建器。
除了构建更精简容器的通用策略来优化构建速度,Cloud Build 特别推荐以下最佳实践,这些实践也可以进一步提升构建速度:
-
Kaniko 缓存
-
用于缓存目录的 Cloud Storage
-
自定义 VM 大小
-
忽略不需要的文件
以下是上述最佳实践的详细信息。
Kaniko 缓存
Kaniko 缓存基于开源工具 Kaniko,并且也是 Cloud Build 的一个特性,其中中间容器镜像层会直接写入到 Google 的 Container Registry,而无需显式的推送步骤。
要启用 Kaniko 缓存,作为构建配置文件 cloudbuild.yaml 的一部分,以下是一个可以包含它的代码片段:
steps:
- name: 'gcr.io/kaniko-project/executor:latest'
args:
- --destination=gcr.io/$PROJECT_ID/image
- --cache=true
- --cache-ttl=XXh
以下是实施 Kaniko 缓存时应考虑的建议,通过 kaniko-project 云构建器实现:
-
使用
kaniko-project/executor替代cloud-builders/docker。 -
destination标志应指向目标容器镜像。 -
cache标志应设置为true。 -
cache-ttl标志应设置为所需的缓存过期时间。
或者,可以通过 gcloud CLI 启用 Kaniko 缓存,方法是运行以下命令:
gcloud config set builds/use_kaniko True
Kaniko 缓存通过在容器镜像注册表中存储和索引中间层,加速了构建执行时间,并最终节省了构建执行时间,因为它可以被后续构建重用。
用于缓存目录的 Cloud Storage
从概念上讲,这就像是一个缓存的 Docker 镜像。可以通过从 Cloud Storage 存储桶中复制上一个构建的结果来重用这些结果,同时新的结果也可以写回到 Cloud Storage 存储桶中。这个概念不仅限于 Docker 构建,还可以扩展到 Cloud Build 支持的任何构建器。
此外,Cloud Build 使用一个名为 /workspace 的默认工作目录,所有构建过程中的步骤都可以访问该目录。通过将步骤结果保存在默认工作目录中,可以将一个步骤的结果传递给下一个步骤。也可以通过在构建步骤中使用 dir 字段显式设置工作目录。
以下是一个构建配置文件的示例片段,其中使用了 Cloud Storage 来缓存目录:
steps:
- name: gcr.io/cloud-builders/gsutil
args: ['cp','gs://mybucket/results.zip','previous_results.zip']
dir: 'my-cloud-build/examples'
# operations that use previous_results.zip and produce new_results.zip
- name: gcr.io/cloud-builders/gsutil
args: ['cp','new_results.zip','gs://mybucket/results.zip']
dir: 'my-cloud-build/examples'
上述示例还展示了如何在构建步骤中通过 dir 字段指定一个特定的工作目录 my-cloud-build/examples。与 Kaniko 缓存类似,云存储可以通过使用上一个构建的结果来优化构建速度。
自定义虚拟机大小
Cloud 构建是通过一个标准大小的托管虚拟机执行的。然而,Cloud Build 提供了一个选项,通过使用更高 CPU 配置的虚拟机来提高构建速度,这本质上是加速构建过程。通过指定 --machine-type 参数可以实现这一点。Cloud Build 特别提供了两种虚拟机类型,分别为 8 核和 32 核。具体选项如下:
-
N1_HIGHCPU_8 -
N1_HIGHCPU_32 -
E2_HIGHCPU_8 -
E2_HIGHCPU_32
以下是启动 Cloud Build 过程时指定虚拟机类型的 CLI 命令:
gcloud builds submit --config=cloudbuild.yaml \
--machine-type=N1_HIGHCPU_8
忽略不需要的文件
Cloud Build 将代码目录上传到 Cloud Storage 位置。通过忽略与构建过程无关的文件,可以加速上传过程。这些文件可能包括第三方依赖项、编译后的代码、二进制文件或用于本地开发的 JAR 文件。此外,文档和代码示例对构建过程没有要求。这些文件可以作为 gcloudignore 文件的一部分来指定,以优化上传时间。
这完成了我们对 Cloud Build 及其关键构件的深入讲解,包括云构建器和构建配置、启动构建过程的可用选项、通过触发器自动化可用选项、查看存储在 Cloud Storage 中的构建结果、定义访问控制,以及推荐最佳实践来优化构建。
下一部分专注于制品管理的概念以及在与容器一起工作时使用 Container Registry 管理构建制品。
管理构建制品 – Container Registry
源代码管理是 CI 过程的第一步。接着是构建代码。代码可以根据各种触发点构建;可以是针对开发分支,也可以是在将 PR 合并到主分支时。代码构建过程可能会生成一个或多个制品。根据构建的代码性质,生成的制品可以是二进制文件、包、容器镜像或它们的组合。这些制品存储在注册表中,然后部署到计算环境中,并形成 CD 过程。在 CI 和 CD 过程之间,还有一个中间过程,其中构建制品被存储,然后随后部署。这被称为 制品管理。
制品管理充当单一真相源和 CI 与 CD 之间的关键集成点。许多制品管理系统提供版本控制、漏洞扫描能力、一致的配置以及统一的访问控制。
鉴于本书的主题是与容器一起工作,这种情况下的关键构建制品将是容器镜像。镜像通常存储在中央注册表中。最常见的容器注册表是 Docker Hub,用于存储公共 Docker 镜像。然而,在企业内部工作时,通常需要确保访问企业特定构建的容器镜像。在这种情况下,私有注册表比公共注册表更可取,因为私有注册表可以提供基于角色的访问控制,提供更多的安全性和治理。
Container Registry 是 GCP 的私有容器镜像注册表服务,支持 Docker 镜像清单 V2 和 OCI 镜像格式,包括 Docker。可以通过安全的 HTTPS 端点访问 Container Registry 服务,并允许用户从任何可能的计算选项推送或拉取镜像。
Artifact Registry
制品注册表 是 GCP 的托管服务,类似于 Container Registry,但还提供存储非容器制品(如 Java 包、Node.js 模块等)的选项。目前不是 GCP DevOps 专业考试的一部分。
Container Registry – 关键概念
Container Registry 是 Google 的一种制品管理方法之一。与任何其他服务一样,它具有某些关键的结构和概念。以下子部分深入探讨这些细节。
启用/禁用 Container Registry
可以通过 GCP 控制台的 APIs & Services 部分启用或禁用 Container Registry 服务。此外,也可以通过以下命令在 CLI 中启用或禁用该服务:
# To enable container registry
gcloud services enable containerregistry.googleapis.com
# To disable container registry
gcloud services disable containerregistry.googleapis.com
Container Registry 服务账户
与 Cloud Build 一样,当启用容器注册表时,会为当前项目创建一个 Google 管理的 SA(服务账户)。该 SA 允许容器注册表访问项目中的关键 GCP 服务,如 Pub/Sub 和 Cloud Storage。Google 通过将容器注册表服务代理角色分配给容器注册表 SA 来实现这一点。
容器注册表的结构
容器注册表服务中可能有一个或多个注册表。每个注册表由主机名、项目 ID 和镜像(标签或镜像摘要)标识。以下是两种可能的格式:
-
HOSTNAME / PROJECT_ID / IMAGE:TAG -
HOSTNAME / PROJECT_ID / IMAGE@IMAGE-DIGEST
在前面的代码中,我们有以下内容:
-
HOSTNAME:指镜像存储的位置。镜像存储在 Cloud Storage 存储桶中。如果主机名是gcr.io,则默认镜像存储在美国。此外,用户还可以指定特定的主机,如us.gcr.io、eu.gcr.io或asia.gcr.io,其中每个主机都与特定的地理区域相关联,镜像存储于该区域。 -
PROJECT_ID:指特定的 GCP 项目 ID。 -
IMAGE:指镜像名称。在容器注册表中,注册表是按镜像名称列出的。单个注册表可以保存不同版本的镜像。添加:TAG或@IMAGE-DIGEST有助于区分具有相同镜像名称的镜像。如果未指定,则镜像会被标记为最新版本。
示例:
以下是特定镜像的注册表示例,其中镜像的版本通过添加标签或镜像摘要进行区分:
# Add image tag:
gcr.io/PROJECT-ID/my-image:tag1
# Add image digest:
gcr.io/PROJECT-ID/my-image@sha256:4d11e24ba8a615cc85a535daa17 b47d3c0219f7eeb2b8208896704ad7f88ae2d
这完成了关于容器注册表结构的主题了解,掌握这一点对于将容器镜像上传或下载到/从容器注册表至关重要。相关细节将在后续主题中详细介绍。
将镜像上传到容器注册表
构建过程完成后,会生成容器镜像作为构建工件。这些工件通常会在执行构建过程的本地目录中创建。这些本地 Docker 镜像需要上传到私有注册表,如容器注册表。上传镜像到容器注册表的过程,也可称为将镜像推送到容器注册表。
简而言之,将镜像推送到容器注册表有两个主要步骤:
-
将本地镜像标记为注册表名称(如以下代码片段所示):
docker tag SOURCE_IMAGE HOSTNAME/PROJECT_ID/IMAGE #Example docker tag my-local-image gcr.io/gcpdevops-2021/my-gcr-image -
将带标签的镜像推送到容器注册表(如以下代码片段所示):
docker push HOSTNAME/PROJECT-ID/IMAGE #Example docker push gcr.io/gcpdevops-2021/my-gcr-image
容器镜像可以推送到新的注册表或现有的注册表:
-
如果推送到一个新的注册表,即一个具有新主机名的注册表,则容器注册表会创建一个多区域存储桶。
-
如果推送到现有的注册表,则会使用镜像标签或镜像摘要创建新版本的镜像。如果两者都没有,则镜像会被标记为
latest。指定容器注册表的位置
容器注册表的位置可以在主机名下指定。如果使用
gcr.io,则默认位置是美国。如果需要使用特定的位置,则可以将主机指定为eu.gcr.io。
新创建的镜像可以使用以下 gcloud CLI 命令列出:
gcloud container images list –repository=HOSTNAME/PROJECT-ID
#Example
gcloud container images list –repository=gcr.io/gcpdevops-2021
这完成了将容器镜像上传或推送到 GCP 容器注册表的主题。现在,任何应用程序都可以通过从容器注册表下载镜像来部署新推送的镜像。下一个主题将涵盖此内容。
从容器注册表下载镜像
CD 过程依赖于 CI 过程的输出,CI 过程的输出本质上以 OCI 镜像的形式存储在像容器注册表这样的注册表中。因此,为了使 CD 过程能够继续进行,需要从容器注册表下载 Docker 镜像。从容器注册表下载镜像的过程与从容器注册表拉取镜像是同义的。
可以通过镜像标签或镜像摘要从容器注册表拉取镜像。如果两者都未指定,则会下载标签为latest的镜像(如下所示的代码片段):
# Pull based on Image Tag
docker pull HOSTNAME/PROJECT-ID/IMAGE:TAG
# Pull based on Image-Digest
docker pull HOSTNAME/PROJECT-ID/IMAGE@IMAGE_DIGEST
# Pull without Image Tag or Image-Digest
docker pull HOSTNAME/PROJECT-ID/IMAGE
这完成了从容器注册表下载镜像的主题。要上传或下载镜像到容器注册表,用户或应用程序必须具有必要的访问控制权限。这将在下一个主题中详细讲解。
容器注册表访问控制
容器注册表是一个用于存储容器镜像的仓库。这些镜像物理上存储在 Cloud Storage 存储桶中。因此,为了从容器注册表推送或拉取镜像,用户或服务账户应被授予以下角色:

如果应用程序是使用 GCP 提供的计算选项进行部署的,例如 Compute Engine、App Engine 或 GKE,那么这些服务将拥有具有预定义角色集的默认服务账户。然而,不建议使用默认服务账户,因为这种做法不符合最小权限原则。作为替代方案,也可以让计算选项使用具有最小所需权限的自定义服务账户。无论哪种方式,了解这些服务账户的范围及其在 CD 过程中的影响都非常重要。接下来的主题将详细讨论这一点。
通过容器注册表的持续交付/部署集成
如前所述,制品管理是 CI 和 CD 之间的桥梁。GCP 提供了多种计算选项,可以将代码或应用程序作为 CD 过程的一部分进行部署。GCP 的每个计算选项都有与容器注册表交互和集成的方式,以下子节将详细介绍。
计算引擎
计算引擎 服务使用服务帐号或访问范围来识别身份并提供对其他服务的 API 访问。以下是成功推送或拉取源自计算引擎实例的镜像的可能性或潜在更改的总结:
-
默认的计算引擎服务帐号或默认访问范围提供对存储和服务管理的只读访问权限。这允许你从同一项目中的容器注册表下载或拉取镜像。
-
要推送镜像,应该使用读写存储访问范围,或者将默认的计算引擎服务帐号配置为具有存储对象管理员角色。
-
如果虚拟机实例使用的是非默认的计算引擎服务帐号,或者虚拟机实例位于不同于容器注册表的项目中,则应为服务帐号授予适当的权限,以访问容器注册表使用的存储桶。
Google Kubernetes Engine
Google Kubernetes Engine(GKE)集群本质上是由代表节点池的 Google 计算引擎虚拟机组成的集合。这也意味着 GKE 使用在虚拟机实例上配置的服务帐号。因此,最终,GKE 对容器注册表的访问是基于授予虚拟机服务帐号的访问权限。因此,请参考之前关于 计算引擎 的小节,了解成功推送或拉取源自 GKE 中计算实例的镜像的可能性或潜在更改。
App Engine flexible
App Engine flexible 支持 Docker 容器的部署。与 App Engine flexible 关联的默认服务帐号具有从容器注册表推送和拉取镜像所需的权限,前提是两者位于同一项目中。
如果应用引擎与容器注册表在不同的项目中,或者应用引擎使用的服务帐号与默认的应用引擎服务帐号不同,则应为与应用引擎关联的服务帐号授予适当的权限,以访问由容器注册表使用的存储桶。
本文完成了关于 GCP 计算选项如何与容器注册表集成的主题。在 GCP 提供的计算选项之外,还有几种用例,其中持续交付系统使用的计算选项并非 GCP 本地的。
下一部分将讨论第三方客户端如何访问 GCP 容器注册表中的工件的详细信息。
容器注册表身份验证方法
也有一些 Google Cloud 之外的计算选项,可能会通过从 Google Cloud 的容器注册表中拉取容器镜像来部署应用程序。此类计算选项被称为第三方客户端。Red Hat Enterprise Linux (RHEL) 集群是一个第三方客户端的示例,它是 Red Hat 提供的计算选项,可以从容器注册表中下载容器镜像。
除了确保第三方客户端具有拉取或推送镜像所需的访问控制外,第三方客户端必须在尝试推送或拉取镜像之前先对容器注册表进行身份验证。以下是第三方客户端可以使用的身份验证方法:
-
gcloud 凭证助手
-
独立凭证助手
第三方客户端如何与容器注册表进行身份验证的详细内容将在接下来的子章节中展开。
gcloud 凭证助手
这是推荐的身份验证方法,并且要求安装 Google Cloud SDK 或使用 GCP 的 Cloud Shell。此方法基本上使用 gcloud 工具来配置身份验证。以下是使用此身份验证方法所需的步骤:
-
以将执行 Docker 命令的 IAM 用户身份登录到 gcloud:
# To configure authentication with IAM user credentials: gcloud auth login -
如果目标是以服务帐号(SA)身份登录 gcloud,则运行以下 Docker 命令。此命令使用包含 SA 信息的 JSON 密钥文件,并检索一个有效期为 60 分钟的访问令牌:
# To configure authentication with service account credentials: gcloud auth activate-service-account <service-account-name> --key-file=<key-file-name> -
使用以下命令配置 Docker,这将允许 Docker 进行容器注册表身份验证:
gcloud auth configure-docker
下一小节详细说明了如何将 Docker 独立凭证助手作为第三方客户端与 GCP 容器注册表交互的授权方法。
独立凭证助手
docker-credential-gcr 是 GCP 容器注册表的独立凭证助手。当未安装 Google Cloud SDK 或未使用 GCP Cloud Shell,但需要将 Docker 配置为与 GCP 容器注册表进行身份验证时,使用此身份验证方法。此凭证助手实现了 Docker 凭证存储 API,并支持更高级的身份验证方案,以便使用 GCP 容器注册表。它允许从应用程序默认凭证中获取凭证,并且还能够在没有明确登录操作的情况下生成凭证。有关 docker-credential-gcr 的更多细节,请参阅 github.com/GoogleCloudPlatform/docker-credential-gcr。
以下是将独立凭证助手用作身份验证方法所需的步骤:
-
以将执行 Docker 命令的用户身份登录到机器。
-
从 GitHub 发布页面下载
docker-credential-gcr:github.com/GoogleCloudPlatform/docker-credential-gcr/releases。 -
使用以下命令配置 Docker。在内部,凭证助手将使用一个通过 JSON 密钥文件提供的服务帐号(SA):
docker-credential-gcr configure-docker
容器分析
容器分析 是容器注册表和工件注册表的一个构件。这个构件的目的是分析推送到 GCP 容器注册表的镜像,以寻找可能存在的安全漏洞。漏洞扫描的元数据会被存储,并通过 API 提供供后续使用。该元数据随后会在授权过程中使用。
容器分析提供元数据存储和漏洞扫描的两个特定 API:
-
容器分析 API:启用元数据存储。元数据存储包括有关漏洞或构建信息的内容,也称为 注释。
-
容器扫描 API:启用跨项目的漏洞扫描。该过程包括扫描和持续分析,以发现可能导致系统故障的恶意活动或潜在漏洞。
以下是配置容器分析作为容器注册表一部分的步骤:
-
启用容器分析 API:导航到
Container Analysis API,选择 启用 选项。 -
启用容器扫描 API:导航到
Container Scanning API,选择按需扫描 API并启用它。 -
导航到 容器注册表,在 设置 下,验证是否启用了 漏洞扫描。如果启用,设置 屏幕将类似于 图 6.3。如果没有启用,请启用它:
![图 6.3 – 在容器注册表中启用漏洞扫描]()
图 6.3 – 在容器注册表中启用漏洞扫描
-
现在,当镜像被推送到容器注册表时,容器分析和漏洞扫描将自动执行。结果将在 容器注册表 的 镜像 部分显示。图 6.4 表示容器分析的摘要:
![图 6.4 – 新创建镜像的容器分析摘要]()
图 6.4 – 新创建镜像的容器分析摘要
-
所有扫描到的漏洞及其分类的详细信息,可以通过点击摘要查看。图 6.5 表示详细报告:

图 6.5 – 通过容器分析进行漏洞扫描的详细信息
这一部分完成了与 GCP 计算选项以及其他第三方 CD 系统如何与 GCP 容器注册表集成的多个子章节的内容。这也结束了对容器注册表相关几个关键因素的深入探讨。
下一部分是一个实操实验,旨在结合本章各节所学的多个概念。
实操实验 – 使用 Cloud Build 触发器构建、创建、推送和部署容器到 Cloud Run
该实践实验的目标是通过逐步演示如何自动构建、推送和部署代码到名为 Cloud Run 的计算选项。
Cloud Run
Cloud Run 是 GCP 提供的托管无服务器计算选项,它可以部署容器并抽象化基础设施管理。Cloud Run 可以根据流量从零扩展或收缩,并按按需付费模式收费。
该实践实验涵盖了 Cloud Build 和 Container Registry 的概念。以下是步骤的高层次拆解,每个步骤进一步细分为多个子步骤:
-
在 Source Repositories 中创建一个空仓库
-
创建一个 Cloud Build 触发器
-
添加代码并推送到主分支
-
代码演示:构建、创建、推送和部署容器镜像
-
在 Cloud Build、Container Registry 和 Cloud Run 中查看构建结果
让我们详细了解这些步骤。
在 Source Repositories 中创建空仓库
以下是创建一个空仓库到 GCP 的 Source Repositories 所需的步骤:
-
在 GCP 控制台中,导航到Source Repositories。
-
使用
my-cloud-build-trigger创建一个新仓库。
创建 Cloud Build 触发器
以下是创建一个针对特定仓库的 Cloud Build 触发器所需的步骤,触发器将在特定仓库事件发生时被调用(参见图 6.6):
-
在 GCP 控制台中,导航到Cloud Build下的触发器部分。
-
选择创建触发器选项。
-
输入触发器的适当名称,例如
build-on-push-to-master。 -
输入适当的描述。
-
选择一个事件选项。可用的选项有推送到分支、推送新标签或拉取请求。在这个具体的示例中,选择推送到分支选项。
-
选择一个源仓库。在这个具体的示例中,选择新创建的仓库,即
my-cloud-build-trigger。 -
选择一个分支。可以是
*或特定的分支。在这个具体的示例中,输入选项为^master$。 -
选择构建配置的来源。它可以是 Cloud Build 配置文件或 Dockerfile。在这个具体的示例中,选择
/cloudbuild.yaml。 -
创建 Cloud Build 触发器(参见图 6.6):
![图 6.6 – 用于说明创建 Cloud Build 触发器的步骤]
图 6.6 – 用于说明创建 Cloud Build 触发器的步骤
添加代码并推送到主分支
我们已经创建了一个仓库并设置了一个针对该仓库的触发器。当代码推送到主分支时,触发器会构建代码。接下来的步骤是将代码添加到仓库并推送到主分支。以下步骤将演示这一过程:
-
克隆空的仓库到本地 Git 仓库:
gcloud source repos clone my-cloud-build-trigger --project=$GOOGLE_CLOUD_PROJECT #$GOOGLE_CLOUD_PROJECT is an environment variable that refers to the current project -
切换到新的本地 Git 仓库:
cd my-cloud-build-trigger -
创建远程分支:
git checkout -b feature/build-trigger -
从
github.com/PacktPublishing/Google-Cloud-Platform-for-DevOps-Engineers/tree/main/my-cloud-build-trigger复制my-cloud-build-trigger文件夹。 -
添加文件、提交更改并推送到远程分支:
git add * git commit -m "Adding files!" git push --set-upstream origin feature/build-trigger -
切换到主分支并修复上游:
git checkout -b master git branch --unset-upstream -
将远程分支与主分支合并:
git push –set-upstream origin git push -u master
代码讲解
一旦代码在前一步推送到主分支,配置的触发器就会生效,最终会构建代码、创建容器镜像、将容器镜像推送到容器注册表,并最终提供容器镜像部署的可行性。
my-cloud-build-trigger 仓库包含三种类型的文件:
-
应用程序代码
-
Dockerfile
-
构建配置文件
应用程序代码
应用程序代码代表运行应用程序的核心代码。在这个特定的案例中,代码位于app/main.py,是用 Python 编写的,并使用 FastAPI 框架创建了一个 Web 应用程序。以下是代码片段:
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
Dockerfile
Dockerfile 代表了使用基础镜像构建应用程序代码并随后创建容器镜像所需的指令。以下是代码片段:
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
COPY ./app /app
EXPOSE 8080
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
构建配置文件
构建配置文件代表启动构建过程的配置。此外,它可以包括将容器镜像推送到容器注册表并随后进行部署的步骤。以下是代码片段:
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/cloud-build-trigger', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/cloud-build-trigger']
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'cbt-cloud-run', '--image', 'gcr.io/$PROJECT_ID/cloud-build-trigger', '--region', 'us-central1', '--platform', 'managed', '--allow-unauthenticated']
在这个特定的示例中,配置文件有三个具体步骤:
-
使用 Docker Cloud Builder 构建代码。代码从指定的目录中获取。在这种情况下,它是当前目录。
-
在第一步中构建的代码创建了一个对云构建器本地的容器镜像。然后使用 Docker Cloud Builder 标记该镜像并将其推送到容器注册表。该容器镜像会推送到特定的仓库。
-
在步骤 2中推送的镜像将在此步骤中用于部署到 Google 的 Cloud Run。
查看结果
在代码推送到主分支后,配置的触发器将启动构建过程。要查看构建结果,请导航到 GCP 控制台中Cloud Build的历史记录部分,并查找特定源代码库的构建结果(参见图 6.7):

图 6.7 – 特定于 Cloud Build 触发器的构建历史摘要
要查看构建的详细信息,点击特定的构建。详情将显示执行 Dockerfile 和创建推送到容器注册表的容器镜像的步骤(参见图 6.8):

图 6.8 – 构建容器镜像并推送到容器注册表的日志
新创建的容器可以在容器注册表中找到(参考图 6.9):

图 6.9 – 在容器注册表中查看容器镜像
构建日志的末尾将显示将容器镜像部署到 Cloud Run 的信息。这还包括访问应用程序的新增服务 URL(参考图 6.10):

图 6.10 – 将容器日志部署到 Cloud Run
导航到高亮显示的服务 URL,查看在 Cloud Run 中部署的应用程序(参考图 6.11):

图 6.11 – 部署在 Cloud Run 中的容器镜像
这完成了动手实验,我们在开发人员更改代码并将其推送到主分支时,自动将应用程序部署到 Cloud Run。这演示了一个使用 GCP 原生构件(如 Cloud Build 和 Container Registry)构建的自动化 CI/CD 流程。
总结
在本章中,我们讨论了 Google CI/CD 工作流建设中的两个关键服务。这些服务是 Cloud Build 和 Container Registry。Cloud Build 对于构建应用程序代码并将容器镜像输出作为构建工件至关重要。Container Registry 使用工件管理的概念来管理这些构建工件。本章深入讨论了每个服务的关键构件,并以一个动手实验作为结尾,用户可以在检测到代码更改时通过配置的触发器自动部署代码到 Cloud Run。
Google 强烈建议使用容器部署应用程序,特别是针对 GKE,这是除 App Engine 灵活环境和 Cloud Run 之外的一个关键容器部署选项。GKE 的关键概念将在接下来的三章中讨论,其中包括了解原生 Kubernetes 的核心功能、学习 GKE 特定功能以及有关加强 GKE 集群的主题。
需要记住的要点
以下是一些需要记住的重要点:
-
Cloud Build 可以从 Google Cloud Storage、CSR、GitHub 或 Bitbucket 导入源代码。
-
Cloud builders 是运行构建过程的容器镜像。
-
Google 管理的 builders 是预构建镜像,可用于执行一个或多个构建步骤。
-
社区贡献的 builders 是开源的构建器,但不是预构建镜像,只有源代码可用。
-
构建配置是一个配置文件,封装了执行构建相关任务的步骤,写成
yaml或json格式。 -
手动调用和通过触发器进行自动构建是通过 Cloud Build 调用构建过程的两种主要选项。
-
与 Cloud Build 相关的日志存储在 Cloud Storage 和 Cloud Logging 中。
-
Cloud Build 编辑器提供对 Cloud Build 资源的完全控制。
-
启用 Cloud Build API 后,Cloud Build 为项目创建一个特定的 Cloud Build 服务账户(具有最小权限)。
-
提高构建速度的两种常见策略是构建更精简的容器和使用缓存的 Docker 镜像。
-
Kaniko 缓存是 Cloud Build 的一项功能,其中中间容器镜像层直接写入 Google 的容器注册表。
-
Cloud Build 提供了一种通过使用更高 CPU 的虚拟机来加速构建速度的选项。
-
在 Cloud Build 过程中,可以使用
gcloudignore文件忽略不需要的文件。 -
容器注册表是 GCP 的私有容器镜像注册服务,支持 Docker 镜像清单 V2 和 OCI 镜像格式。
-
如果使用
gcr.io,则默认位置被视为美国。 -
存储管理员提供将镜像推送和拉取到与容器注册表关联的 Cloud Storage 存储桶中的能力。
-
gcloud 凭据助手和独立凭据助手是第三方客户端可以用来与容器注册表进行身份验证的可能身份验证方法。
-
容器分析是一个提供软件制品的漏洞扫描和元数据存储的服务。
-
容器分析 API 使元数据存储成为可能,而容器扫描 API 使漏洞扫描成为可能。
深入阅读
有关 Cloud Build 和容器注册表的更多信息,请阅读以下文章:
-
Cloud Build:
cloud.google.com/cloud-build
实践测试
请回答以下问题:
-
选择 Cloud Build 可以从哪些来源导入源代码的所有可能选项(多选):
a) GitHub 和 Bitbucket
b) Google Cloud Storage
c) CSR
d) 上述都不是
-
Cloud Build 需要一个构建配置文件。选择表示此文件的选项:
a)
cloudbuild.json,cloudbuild.xmlb)
build.json,build.yamlc)
cloudbuild.json,cloudbuild.yamld)
build.json,build.xml -
选择将配置 Cloud Build 在构建过程中将镜像存储到容器注册表中的命令:
a)
push命令b)
docker put命令c)
put命令d)
docker push命令 -
以下哪些选项可以用来存储容器镜像?
a) 容器分析
b) Cloud Build
c) 容器注册表
d) CSR
-
选择存储在授权过程中稍后使用的受信任元数据的选项:
a) 容器注册表
b) 容器分析
c) 容器扫描
d) 容器制品库
-
选择代表通过执行 Dockerfile 中的每个指令创建的中间镜像的选项:
a) Docker 镜像
b) Dockerfile
c) Docker 层
d) Docker 守护进程
-
选择允许您在同一物理硬件上运行多个应用程序的选项:
a) 操作系统
b) 虚拟化
c) 虚拟机监控程序
d) 上述都包括
-
选择所有适用于 Cloud Build 的选项:
a) 托管服务
b) 无服务器
c) 既有(a)也有(b)
d) 以上都不是
-
以下哪个选项不是用户在构建步骤中可以提供的有效选项(选择一个):
a)
nameb)
argsc)
envd)
uniqueid -
构建配置文件可以配置为存储 Cloud Build 日志。选择适当的选项来存储日志:
a) Cloud Storage
b) Cloud Logging
c) 既有(a)也有(b)
d) 以上都不是
答案
-
(a) – (b) 和 (c)。
-
(c) –
cloudbuild.json,cloudbuild.yaml。 -
(d) –
docker push命令。 -
(c) – 容器注册表。
-
(b) – 容器分析。
-
(c) – Docker 层。
-
(b) – 虚拟化。
-
(c) – 托管服务和无服务器。每个无服务器服务都是托管服务。
-
(d) –
uniqueid。正确选项是id。 -
(c) – Cloud Storage 和 Cloud Logging。
第七章:理解 Kubernetes 基础以部署容器化应用
最后的两章(第五章,使用云源代码库管理源代码,以及 第六章,使用 Cloud Build 构建代码并推送到容器注册表)集中讨论了通过 Google Cloud 服务来管理源代码、使用 Cloud Build 构建代码以及通过容器注册表创建镜像文件。鉴于本书的重点是部署容器化应用,接下来的三章(从 第七章,理解 Kubernetes 基础以部署容器化应用,一直到 第九章,使用 GKE 安全构造保护集群)围绕通过 Kubernetes 部署容器化应用的核心概念、通过 Google Kubernetes Engine(GKE)轻松管理集群,以及 GKE 中一些关键的安全功能,旨在加强 Kubernetes 集群的安全性。
Kubernetes,或 K8s,是一个开源的容器编排系统,可以运行容器化的应用程序。Kubernetes 起源于 Google 内部的集群管理工具,后来于 2014 年捐赠给 Cloud Native Computing Foundation(CNCF)作为开源项目。本章将重点介绍容器化部署所需的 Kubernetes 基础知识,包括理解集群结构,并了解 Kubernetes 对象,特别是与工作负载、部署策略和应用程序调度约束相关的内容。Google 将 Kubernetes 开源并捐赠给 CNCF。本章并未深入探讨如何设置 Kubernetes 集群,搭建开源版本的 Kubernetes 需要付出较大努力并进行手动干预。
Google 提供了一个托管版本的 Kubernetes,称为 Google Kubernetes Engine,简称 GKE。本质上,Kubernetes 的基础知识同样适用于 GKE。然而,GKE 使得设置 Kubernetes 集群变得更容易,并且包括了一些促进集群管理的附加功能。下一章将重点介绍 GKE 的核心功能,并包括创建集群的步骤。然而,本章主要关注并详细阐述了 Kubernetes 的基础知识,这也是 GKE 的核心内容,有助于让过渡到 GKE 更加顺利。
本章介绍了 Kubernetes 作为容器编排工具的优势,并提供了以下主题的详细信息:
-
Kubernetes:简要介绍
-
Kubernetes 集群解剖:深入探讨构成 Kubernetes 集群的结构以及构成主控平面的组件
-
Kubernetes 对象:提供一个关于用于部署工作负载的关键 Kubernetes 对象的高级概述。
-
调度和与 Pods 交互:详细说明了在 Kubernetes 上调度应用程序时评估的约束和涉及的交互。
-
Kubernetes 部署策略:详细说明了潜在的部署策略,从本质上重新创建应用程序的选项,到确保零停机时间的部署选项,再到将特定流量转移到新应用程序的选项。
技术要求
有四个主要的技术要求:
-
一个有效的Google Cloud Platform(GCP)账户,以便动手操作 GCP 服务:
cloud.google.com/free。 -
安装 Google Cloud SDK:
cloud.google.com/sdk/docs/quickstart。 -
安装 Git:
git-scm.com/book/en/v2/Getting-Started-Installing-Git。 -
安装 Docker:
docs.docker.com/get-docker/。
Kubernetes – 简介
容器是一个软件单元,封装了代码及其依赖项,如库和配置文件。与在物理或虚拟机上运行应用程序相比,容器使得应用程序能够更快、更可靠地在不同计算环境中运行。容器使得构建使用微服务设计模式的应用程序变得更容易。它们对持续开发、集成和部署概念至关重要,因为可以对容器镜像进行增量更改,并迅速部署到支持进程隔离的计算环境中。
由于容器轻量且易于部署,组织可能会将其应用程序部署为多个容器。这带来了挑战,因为一些应用程序可能需要彼此交互。此外,应用程序的生命周期也应该得到监控和管理。例如,如果一个应用程序因资源限制而崩溃,则应提供该应用程序的另一个实例。同样,如果流量突然激增,应用程序应横向扩展,而当流量恢复正常时,应用程序应随之缩减。
扩展操作(向上或向下)应自动进行,而不是手动进行。这就需要容器编排,接下来将讨论这一主题。
容器编排
容器编排涉及管理容器的生命周期,特别是在大型动态环境中。容器编排可以控制和自动化诸如资源配置、部署、维持冗余、确保可用性以及通过根据需要上下扩展来处理变化流量等任务。
此外,容器编排还可以处理以下场景:
-
在主机节点故障时,将容器从一个主机节点迁移到另一个主机节点。
-
如果容器消耗的资源超过预期,设置驱逐策略。
-
提供持久存储卷的访问权限,以防容器重启。
-
通过存储密钥/秘密来确保容器之间的安全交互。
-
监控容器的健康状态。
Kubernetes 源自 Borg——一个内部的 Google 项目,实际上是一个集群管理器,用于运行大规模的容器化工作负载,以支持 Google 搜索等核心 Google 服务。Kubernetes 是 Borg 的下一代集群管理器。Kubernetes 中最流行的概念来自 Borg,例如 Pods、服务、标签和每个 pod 的 IP 地址。
替代容器编排选项
Docker Swarm、Apache Mesos、OpenShift 等是 Kubernetes 之外的一些容器编排替代选项。Docker Swarm 易于入门并设置集群,但在扩展方面功能有限。Mesos 是一个集群管理器,最适合大规模系统,并以最大冗余设计。它在功能和配置上较为复杂,适用于 Hadoop 和 Kafka 等工作负载,但不适用于中小型系统。
接下来的部分总结了 Kubernetes 的主要特点。
Kubernetes 特性
以下是 Kubernetes 中的一些关键特点:
-
声明式配置:Kubernetes 以声明性方式管理基础设施,换句话说,Kubernetes 监控当前状态并采取必要的措施,确保当前状态与期望状态一致。
-
自动化:Kubernetes 的声明式配置实现本身就支持自动化。此外,Kubernetes 允许广泛的用户偏好和配置。因此,Kubernetes 可以根据多种条件自动扩展或缩减容器化应用程序,资源利用率或资源限制只是其中的一些条件。
-
有状态与无状态:Kubernetes 支持有状态和无状态应用程序。在有状态应用程序的情况下,用户的状态可以持久存储。此外,Kubernetes 还支持批处理任务和守护进程任务。
-
容器管理:Kubernetes 支持基础设施即服务的功能,如日志记录、监控和负载均衡。
下一部分概述了 Kubernetes 部署的结构,并深入探讨其关键组件及其功能。
Kubernetes 集群结构
Kubernetes 集群是具有计算能力的机器集合。这些机器可以是实际的物理计算机,甚至可以是 虚拟机 (VMs)。
关于云部署,Kubernetes 集群将是虚拟机的集合。每个虚拟机被称为一个节点。集群中的节点被分类为主节点或工作节点。工作节点运行在容器中部署的应用程序。主节点运行控制平面组件,负责协调工作节点之间的任务。
为了方便参考,本章中运行控制平面组件的节点将称为主节点,而工作节点将称为节点。
主节点有以下职责:
-
它跟踪集群中所有节点的信息,例如节点正在运行的应用程序或容器。
-
它通过根据要求(如资源、亲和性或反亲和性约束)识别节点来调度应用程序到节点上。
-
它确保始终按照部署规范运行所需数量的实例,并协调集群中的所有操作。
图 7.1 显示了一个 Kubernetes 集群的示意图,该集群包括主节点和节点,这些节点由具备计算能力的机器组成:

图 7.1 – Kubernetes 集群概述
主节点通过一组关键组件执行其职责,这些组件构成了Kubernetes 控制平面,将在接下来的主题中详细介绍。
主节点组件 – Kubernetes 控制平面
Kubernetes 控制平面由一组组件组成,这些组件负责在集群内进行操作决策并响应集群特定的事件。事件可能包括但不限于,当平均 CPU 利用率超过特定配置的阈值时,按应用程序的需求扩展实例数量。
以下是 Kubernetes 控制平面的关键组件:
-
kube-apiserver:Kubernetes 的前端,用于集群交互
-
etcd:用于存储集群特定信息的分布式键值存储
-
kube-scheduler:负责在节点之间分配工作负载
-
kube-controller-manager:跟踪节点或应用程序是否出现故障
-
cloud-controller-manager:嵌入云特定的控制逻辑
图 7.2 显示了在主节点上运行并组成 Kubernetes 控制平面的组件示意图:

图 7.2 – 主节点上的 Kubernetes 控制平面
控制平面组件可以在集群中的任何机器上运行,但建议运行在相同的机器上并避免使用任何特定于用户的容器。构建高可用集群时,也可以拥有多个控制平面。每个关键组件将在接下来的子章节中介绍。
kube-apiserver
HTTP、gRPC 和 kubectl)。控制平面的所有其他组件都可以视为 kube-apiserver 的客户端。此外,kube-apiserver 还负责认证、授权和管理准入控制。
认证、授权和准入控制
从集群的角度来看,认证是关于谁可以与集群交互(这可以是用户或服务账户);授权是关于哪些特定操作被允许,准入控制表示一组插件,这些插件可以限制创建、删除、修改或连接代理的请求。ResourceQuota 是一个准入控制器的例子,其中一个命名空间可以被限制只使用一定容量的内存和 CPU。
任何对集群的查询或更改都由 kube-apiserver 处理。它还通过部署多个实例来水平扩展,以处理对集群的传入请求。
etcd
etcd 是一个分布式键值存储,Kubernetes 使用它来存储管理集群所需的信息,例如集群配置数据。这些数据包括节点、Pods、配置、密钥、账户、角色和绑定。当对集群发出 get 请求时,信息将从 etcd 中检索。对集群发出的任何 create、update 或 delete 请求,只有当更改反映在 etcd 中时,才算完成。
kube-scheduler
kube-scheduler 考虑多个因素,例如应用程序的资源需求、节点可用性、亲和性和反亲和性规范。亲和性和反亲和性规范是政策定义,允许将某些应用程序部署到特定节点,或防止将应用程序部署到特定节点。
kube-controller-manager
kube-apiserver 确保集群的当前状态与期望状态匹配。kube-controller-manager 负责集群的实际运行,并通过使用多个控制器功能来完成这项工作。例如,节点控制器在节点离线时监视并响应。其他示例包括复制控制器、命名空间控制器和端点控制器。
cloud-controller-manager
cloud-controller-manager 包含控制器功能,使 Kubernetes 能够与云提供商的服务进行集成。控制器功能负责处理与云提供商特定的构造,如网络、负载均衡器和存储卷。
主控接收到执行特定操作的请求后,控制平面中的组件调度、计划并管理将在节点上执行的操作。Kubernetes 本身并没有开箱即用的集成(比如与 Google 或 AWS 的集成)。节点上的操作由一组组成节点控制平面的组件执行,接下来的子章节将详细介绍这些组件。
节点组件
节点从主节点接收指令,特别是从kube-apiserver。节点负责运行部署在容器中的应用程序,并在集群内建立服务间的通信。节点通过使用一组关键组件来执行这些职责。这些组件如下:
-
kube-apiserver并根据 Pod 规范运行容器 -
kube-proxy:一个网络代理,允许服务之间的通信
-
容器运行时:负责运行容器的软件
图 7.3展示了构成节点控制平面的组件示意图:

图 7.3 – 节点控制平面组件
节点组件在集群中的每个工作节点上运行,并提供 Kubernetes 运行时环境。每个工作节点的关键组件将在接下来的主题中介绍。
kubelet
kube-apiserver通过kubelet(节点的代理)与节点连接。kubelet监听指令,并在接收到指令时部署或删除容器。kubelet不管理那些不是由 Kubernetes 创建的容器。
kube-proxy
kube-proxy在集群中的每个节点上运行。
容器运行时引擎
containerd和 CRI-O。
Kubernetes 弃用 Docker 作为容器运行时引擎
根据 Kubernetes v1.20 的发布说明,dockershim将被弃用,并且从 v1.22 开始无法使用。dockershim是kubelet中的一个模块,是 Kubernetes 社区提出的临时解决方案,用于将 Docker 作为容器运行时。由于维护负担,dockershim将被弃用,Kubernetes 社区将只维护 Kubernetes 的containerd和 CRI-O,它们是符合 CRI 标准的运行时示例。
这完成了对 Kubernetes 集群结构的深入探讨,具体包括来自主控制平面和节点控制平面的组件。主控制平面内部的通信由kube-api服务器驱动,kube-api服务器将指令发送到相应节点的kubelet。kubelet执行kube-api服务器发送的指令。图 7.4展示了整个集群结构的示意图:

图 7.4 – Kubernetes 集群结构
需要理解的是,任何针对 Kubernetes 对象的操作,如创建、修改或删除,只能通过 Kubernetes API 来执行。这些操作也可以通过 CLI 使用kubectl命令执行。接下来的主题将详细介绍如何使用kubectl命令。
使用 kubectl
kubectl 通常由管理员使用。kubectl 使得可以对特定对象类型及其对象名称执行操作,如获取或删除,并支持请求参数。kubectl 与主节点上的 kube-apiserver 通信,并将 CLI 发出的命令转换为 API 调用。kubectl 可用于创建 Kubernetes 对象、查看现有对象、删除对象以及查看/导出配置。kubectl 的语法结构如下:
#kubectl syntax
kubectl [command] [type] [name] [flags]
#Example – Command to get specification of a specific pod called 'my-pod' in yaml format
kubectl get pod my-pod -o=yaml
使用 kubectl 命令的第一步是配置集群的凭证,例如集群名称和位置。kubectl 将此配置存储在一个名为 config 的文件中,并将文件保存在主目录下的隐藏文件夹 .kube 中。可以使用 view 命令检索当前配置:
# Get current config
kubectl config view
集群上的操作是通过 Kubernetes 对象执行的。每个对象都有特定的用途和功能。Kubernetes 中有许多这样的对象。接下来的部分介绍了 Kubernetes 对象的概念,并详细介绍了最常用的对象。
Kubernetes 对象
Kubernetes 对象是一个持久化实体,表示意图的记录。对象可以使用 YAML 配置定义。它将具有两个主要字段——spec 和 status。spec 表示规范,status 表示期望的状态。对象创建后,Kubernetes 系统将确保该对象按指定的声明式配置存在。
Kubernetes 支持多种对象类型。每种对象类型都有其特定的用途。以下是本章将使用的一些关键 Kubernetes 对象,这并不是一个详尽无遗的列表:
-
Pods – Kubernetes 中最小的原子单位
-
部署(Deployment)– 为 Pods 和 ReplicaSets 提供声明式更新
-
有状态集(StatefulSet)– 管理有状态的应用,并保证顺序
-
守护进程集(DaemonSet)– 在每个节点上运行 Pod 的副本
-
任务(Job)– 创建一个或多个 Pod,并会继续重试执行,直到指定数量的 Pod 成功终止
-
CronJob – 一个基于 cron 表达式的定时任务
-
服务(Services)– 暴露运行一个或多个 Pod 的应用
部署(Deployment)、副本集(ReplicaSet)、有状态集(StatefulSet)、守护进程集(DaemonSet)、任务(Jobs)和定时任务(CronJobs)被专门分类为 工作负载资源(Workload Resources)。所有这些工作负载资源都运行一个或多个 Pod。本章将详细介绍上述 Kubernetes 对象。请注意,提供的信息从对象功能的角度并不全面,而是提供了对象目的的深入回顾。
Pod
Pod 是一个 Kubernetes 对象,是 Kubernetes 集群中最小的可部署计算单元。应用程序代码存在于容器镜像中,容器镜像通过容器运行,容器在 Pod 内运行。Pod 存在于节点内部。
一个 Pod 可以包含一个或多个容器。Pod 提供了一个规范,说明如何运行这些容器。Pod 中的容器共享文件系统、命名空间和网络资源。Pod 还分配了一组端口或端口范围。Pod 中的所有容器具有相同的 IP 地址,但端口不同。Pod 内的容器可以通过本地主机上的端口号进行通信。以下是一个声明式的 Pod 规范,用于运行一个 nginx 容器:
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
containerPort:80
以下是一个等效的命令式命令,用于创建类似的 Pod:
kubectl run my-nginx –image=nginx
什么是 CrashLoopBackOff?
在某些情况下,Pod 尝试启动、崩溃、再次启动,然后再次崩溃;本质上,这是一个 Pod 报告的情况,表示 Pod 中的容器在多次尝试后未能启动。
在 Kubernetes 平台上,Pod 是最小的单位,并运行一个或多个容器。如果多个容器形成一个服务的整体单元,则 Pod 包含多个容器。Sidecar 模式是一个常见的实现方式,Pod 中有多个容器。此模式广泛应用于 ETL 特定的用例。例如,hello-world 容器的日志需要实时分析。logs-analyzer 是一个专门用于分析日志的应用程序。如果每个容器分别运行在其各自的 Pod 中,名为 pod-hello-world 和 pod-logs-analyzer,那么 logs-analyzer 容器可以通过 GET 请求获取 hello-world 容器的日志。参考 图 7.5:

图 7.5 – 不同 Pods 中容器之间的通信
然而,由于这两个容器位于不同的 Pod 中,网络延迟会最小化。如果这两个容器都属于同一个 Pod,形成一个 Sidecar 模式,即 pod-hello-world-etl,那么该 Pod 将包含两个容器——logs-analyzer 作为侧车容器,将分析来自另一个容器 hello-world 的日志。然后,这些容器可以在本地主机上进行通信,因为它们共享相同的网络接口,实现实时通信。参考 图 7.6:

图 7.6 – Sidecar 模式中容器之间的通信
使用单个包含多个容器的 Pod,可以让应用程序作为一个整体运行,并减少网络延迟,因为容器之间在相同的网络接口上进行通信。以下是一个声明式的 Pod 规范,运行多个容器,并按照 图 7.6 中所示的特定示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-hello-world-etl
spec:
containers:
- name: hello-world
image: hello-world
ports:
- containerPort:8059
- name: logs-analyzer
image: custom-logs-analyzer:0.0.1
ports:
- containerPort:8058
Job 和 CronJob
Job 和 CronJob 是工作负载资源。Job 代表执行 Pod 的任务。如果任务执行成功,Job 就完成了,换句话说,Pod 会成功运行并完成指定次数。如果删除一个 Job,则与该 Job 相关的 Pod 也会被删除。如果 Job 被挂起,则活动 Pod 会被删除。多个 Job 可以并行运行。CronJob 是一种工作负载资源,实际上是一个通过 cron 表达式设置了调度的 Job。
图 7.7 汇总了与单容器 Pod my-nginx 和多容器 Pod pod-hello-world-etl 相关的示例,并说明了这些 Pod 如何在节点内潜在地连接:

图 7.7 – 节点内的 Pod 连接性
Pods 本质上是短暂的,Pod 关联的存储也是如此。因此,Pods 更适合无状态应用程序。然而,Pods 也可以用于有状态应用程序,但在这种情况下,Pods 应该附加到持久存储或卷上。Pods 也旨在运行单个应用程序实例。要进行水平扩展,应使用多个 Pod 实例。这被称为复制。因此,Pods 不能单独进行扩展。
活跃性、就绪性和启动探针
活跃性探针用于检查应用程序是否按预期运行,如果没有,容器将被重启。就绪性探针用于检查应用程序是否已启动并准备好接收流量。启动探针指示容器应用程序何时启动。如果配置了启动探针,则在启动探针成功之前,将禁用活跃性和就绪性检查。有关更详细的信息,请参阅kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/。
Kubernetes 使用特定的工作负载资源来创建和管理多个 Pods。最常见的资源是 Deployment、StatefulSet 和 DaemonSet,接下来的子章节将详细介绍这些资源。
部署
Deployment 是一个 Kubernetes 对象,它提供了 Pod 和 ReplicaSet 的声明式更新。Deployment 是 Kubernetes API 组中的一部分,属于应用程序组。
API 组
API 组是一种扩展 Kubernetes API 的方式。所有支持的 API 请求或未来的请求都被放置在特定的组中以便于分类,并包括版本控制。最常见的组是核心组,也称为传统组。核心组通过 apiVersion 指定为 v1。Pods 属于核心组。Deployment 属于应用程序组,并通过 apiVersion 指定为 apps/v1。
部署提供了一种声明性方式来管理一组 Pod 副本。部署规范包括 Pod 模板、Pod 规范和所需的 Pod 副本数。集群将有控制器不断监视并工作以保持所需状态,并根据需要创建、修改或删除副本 Pods。部署控制器根据匹配的标签选择器来识别 Pod 副本。以下是一个声明性规范,封装了三个 nginx Pod 副本的部署:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deploy
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app:nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
以下是一组等效的命令,用于创建类似的部署:
kubectl create deployment my-deploy --image=nginx
kubectl scale –replicas=3 deployments/my-deploy
部署支持使用 HorizontalPodAutoscaler(HPA)概念进行自动扩缩,基于 CPU 使用率等指标。以下是实现 HPA 的命令。HPA 将在 第八章 中详细讨论,理解 GKE 基础知识以部署容器化应用程序,该部分重点介绍 GKE:
kubectl autoscale deployment my-deploy --cpu-percent=80 --min=5 --max=10
部署可以使用滚动更新策略进行更新。例如,如果镜像版本被更新,则会创建一个新的 ReplicaSet。滚动更新将确保部署将 Pods 从旧的 ReplicaSet 逐步迁移到新的 ReplicaSet,从而确保 0% 的停机时间。如果在执行滚动更新时发生错误,新的 ReplicaSet 将永远无法达到 Ready 状态,而旧的 ReplicaSet 不会终止,从而实现 0% 的停机时间。部署和 Pods 通过标签连接。每个 Pod 都会被分配一个标签。部署具有标签选择器。因此,任何部署的更新都会按标签匹配的 Pods 进行推广。
部署非常适合无状态应用程序,其中请求可以由任一副本 Pod 以相似方式处理。然而,还有一种资源是有状态的,称为 StatefulSets。下一个主题将介绍这一内容。
StatefulSets
sample,则 Pod 的名称将是 sample-0。如果有三个副本,则会创建名为 sample-1 和 sample-2 的额外 Pods。这与部署完全不同,在部署中,所有 Pods 共享相同的卷。
以下是具有三个副本的 StatefulSet 的声明性规范:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sample
spec:
selector:
matchLabels:
app: nginx
serviceName: nginx
replicas: 3
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ...
ports:
- containerPort: 80
volumeMounts:
- name: nginx-stateful-volume
mountPath: ...
volumeClaimTemplates:
- metadata:
name: nginx-stateful-volume
annotations:
...
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
如果 StatefulSet 被缩减,那么 StatefulSet 中的最后一个 Pod 将被删除(换句话说,按照逆序)。在前面的例子中,如果副本数从三减少到两,则 sample-2 Pod 将被删除。如果有任何变更,StatefulSet 支持滚动更新。特定副本的旧版本 Pod 会在该副本的新版本 Pod 启动时被替换。例如,sample-0 将被新的 sample-0 版本替换。下一个主题将概述 DaemonSets。
DaemonSets
kube-proxy 是一个 DaemonSet,因为它的副本会在集群中的每个节点上运行,作为节点控制平面的一部分。其他示例包括以下内容:
-
在每个节点或某些子集节点上运行日志收集守护进程
-
在每个节点或某些子集节点上运行集群存储守护进程
-
在每个节点或某些子集节点上运行节点监控守护进程
进一步解释,在日志收集守护进程的情况下,日志通过像 fluentd 这样的日志收集器从每个节点导出。这可以通过一个 fluentd Pod 来完成,并且应该在集群中的每个节点上运行。以下是一个声明式的日志收集 DaemonSet 配置:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector-daemon
labels:
app: daemon
spec:
selector:
matchLabels:
app:log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: fluentd
image: quay.io/fluent/fluentd-kubernetes-daemonset
ports:
- containerPort: 9200
与 Deployments 类似,DaemonSet 也支持滚动更新。因此,当 DaemonSet 被更新时,会创建一个新的 Pod,并且当新 Pod 启动后,当前的 Pod 将被删除。
接下来的主题将讨论一个名为 Service 的 Kubernetes 对象。它对于在集群内部和集群外部建立与应用程序的通信至关重要。
服务
如前所述,Pods 本质上是短暂的。Pods 的 IP 地址不是长期有效的,可能会不断变化。如果需要通过 IP 地址向 Pod 的容器发送 API 请求,这会带来挑战。
Kubernetes 为一组 Pods 提供了一个稳定的抽象点,称为 Service。每个 Service 都有一个固定的 IP 地址,不会改变,并且会注册到集群的内建 DNS 中。Service 使用标签选择器来识别关联的 Pods。
此外,当创建 Service 对象时,Kubernetes 会创建另一个名为 EndPoint 的对象。EndPoint 对象会维护所有符合标签选择器的 Pods 的 IP 地址列表,并在 Pods 被删除和创建时不断更新。Service 对象会从 EndPoint 对象获取当前活动的 Pods 列表。
图 7.8 展示了基于匹配标签选择器,Service 对象、endpoint 对象与关联 Pods 之间的交互:

图 7.8 – 基于匹配标签选择器的 Service 对象交互
以下是一个声明式配置,它将一组 Pods 暴露为一个 Service。这样,Pod 就可以通过 Service 进行访问,因为 Service 不是短暂的,并且会有一个固定的 IP 地址:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 8080
以下是一个等效的命令,它可以将 Pods 暴露为 Service:
#Syntax
kubectl create <cluster-type> NAME [--tcp=port:targetPort]
kubectl create service clusterip nginx --tcp=80:80
有四种类型的 Service,每种类型的 Service 暴露 Pods 的方式不同:
-
ClusterIP
-
NodePort
-
LoadBalancer
-
ExternalName
上述配置表示一个 ClusterIP 类型的 Service,因为这是默认的 Service 类型。接下来将介绍这个内容。
ClusterIP
ClusterIP 是默认的 Service 类型。每个 Service 会获得一个只能在集群内的其他服务访问的 IP。这本质上是一个内部 IP,因此 Pods 中的应用程序无法被公共流量或外部集群中的 Service 访问。如果没有指定,默认的 Service 类型为 ClusterIP。前面的声明性规范是一个 ClusterIP Service 的示例。
NodePort
NodePort 是一种 Service 类型,Service 获得一个内部 IP,可以被集群内的其他服务访问。此外,NodePort Service 会获得一个全局端口。只有当请求发送到节点的 IP 地址并携带全局端口时,外部集群中的 Service 才能访问这个端口。任何发送到全局端口的流量都会被重定向到与 Service 关联的 Pods。以下是一个声明性规范,公开了一个节点端口服务,用于一组 Pods:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
nodePort: 30200
port: 80
targetPort: 8080
LoadBalancer
LoadBalancer 是一种 Service 类型,Service 获得一个内部 IP,可以被集群内的其他服务访问。此外,Service 还会获得一个外部 IP 地址,允许应用程序接收来自外部集群的 Service 的流量。这是通过附加在 Service 上的公共云负载均衡器来实现的。以下是一个声明性规范,公开了一个负载均衡器服务,用于一组 Pods:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 8080
ExternalName
ExternalName 类型:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ExternalName
externalName: hello.com
因此,来自内部客户端的请求将会发送到 my-service.default.svc.cluster.local,然后请求被重定向到 hello.com。
这完成了对 Kubernetes 中最常见的 Service 类型的概述。使用服务时需要考虑的一个因素是将服务映射到 Pods,也称为服务解析。Kubernetes 有一个附加功能,叫做 kube-dns,它是一个 DNS 服务器,本质上是一个将 IP 地址与易记的名称及记录类型进行映射的目录:
kube-dns 服务器会监视 API 服务器以检测新的 Service 创建。当新服务创建时,kube-dns 服务器会创建一组 DNS 记录。Kubernetes 配置为使用 kube-dns 服务器的 IP 来解析 Pods 的 DNS 名称。Pods 可以通过查询 kube-dns 服务器,使用 Service 名称、Pod 的命名空间和默认集群域来解析它们的 Service IP:
-
如果 Pod 和 Service 在同一个命名空间中,那么 Pod 可以通过直接使用 Service 名称查询
kube-dns服务器来解析 Service 的 IP。 -
如果 Pod 和 Service 不在同一个命名空间中,那么 Pod 可以通过查询
kube-dns服务器,使用 Service 名称和 Service 命名空间来解析 Service 的 IP。 -
在其他命名空间中的 Pod 可以通过使用完全限定域名
foo.bar.svc.cluster.local来解析 Service 的 IP 地址。
kube-dns 为 Pods 和服务维护以下类型的 DNS 记录:
-
集群中定义的每个 Service 都会分配一个 DNS A 记录。
-
集群中每个命名 Pod 都会分配一个 DNS SRV 记录。
以下表格表示kube-dns记录,其中主机名为foo,命名空间为bar:

这部分内容总结了特定 Kubernetes 对象的概述,并为下一章讨论 GKE 提供了良好的基础。还有其他一些对象,如作业、CronJob、卷和持久卷,但对这些对象的深入探讨超出了本书的范围。
下一节将详细介绍与 Pod 调度和交互相关的几个概念。
调度和与 Pod 交互
Pod 是 Kubernetes 集群中最小的部署单元,运行容器化的应用程序。kube-scheduler主控平面组件负责为 Pod 找到合适的节点,并与其他控制平面组件进行交互。此外,kube-scheduler还需要考虑多个配置选项,如 NodeSelector、NodeAffinity 和 PodAffinity,以找到适合 Pod 的节点。本节详细描述了 Pod 创建过程中发生的交互,并详细介绍了调度 Pod 时需要考虑的因素。
总结 Pod 创建时主控平面交互
Pod 是需要在 Kubernetes 集群中部署的工作负载。Pod 需要在节点上运行,并托管一个应用程序。Pod 可以处于不同的阶段。以下是有效 Pod 阶段的总结:
-
待定:Pod 已被 Kubernetes 集群接受,但正在等待调度。
-
运行中:Pod 已经绑定到某个节点,并且 Pod 中的容器正在运行。
-
成功或已完成:Pod 中的所有容器都已成功终止,并且不会重新启动。
-
失败:Pod 中的所有容器都已终止,并且至少一个容器以非零状态或失败退出。
-
未知:由于 Pod 应该运行的节点之间发生通信错误,无法获取 Pod 的状态。
从接收到创建 Pod 的请求到 Pod 被创建完成,主控平面各个组件之间会有一系列的交互,这些组件将会在工作节点上创建 Pod。交互的顺序如下所示。这反映了一个 Pod 正在创建的场景。其他交互(如列出或删除 Pod),或者其他工作负载(如作业或部署),也遵循相同的模式:
-
kube-apiserver接收到创建 Pod 的请求。该请求可以来自kubectl命令或直接的 API 交互。 -
kube-apiserver对传入请求进行身份验证和授权。 -
在成功验证后,
kube-apiserver创建 Pod 对象,但不会将新创建的 Pod 对象分配给任何节点。 -
kube-apiserver会更新关于新创建的 Pod 对象的信息到etcd数据库,并向原始请求返回响应,表示 Pod 已创建。 -
kube-scheduler持续监控并发现有新的 Pod 对象,但没有分配节点。 -
kube-controller确定合适的节点以放置 Pod,并将此信息传回kube-apiserver。 -
kube-apiserver会更新 Pod 对象在etcd数据库中的节点信息。 -
kube-apiserver将指令传递给节点上的kubelet(工作节点),以物理创建 Pod 对象。 -
kubelet在节点上创建 Pod,并指示容器运行时引擎部署应用程序镜像。 -
kubelet将状态更新回kube-apiserver,并且kube-apiserver更新etcd数据库。
这是通过 kubectl 或 Kubernetes 客户端向 Kubernetes 集群发送请求时,主控平面组件之间的交互总结。下一节将重点讨论在将 Pod 调度到节点时需要考虑的重要因素。
调度 Pod 时需要考虑的关键因素
kube-scheduler 在调度 Pod 到节点时会考虑多个因素。一个常见的因素是资源请求和最大限制。Pod 可选地允许指定 CPU/内存请求,并在容器级别设置相应的最大限制。这些容器级别的请求和限制会汇总到 Pod 中,并由 kube-scheduler 用来确定适合的节点。kube-scheduler 会将 Pod 调度到一个节点,该节点的资源请求和限制在节点的可用容量范围内。
Pod 提供了额外的属性,以便在某些条件满足时,强制 kube-scheduler 只调度这些 Pod。节点也提供了一些在调度时会被考虑的属性。以下是这些属性:
-
NodeSelector:将 Pod 调度到具有匹配标签值的节点上
-
节点亲和性:将 Pod 调度到具有匹配灵活条件的节点上;还会考虑反亲和性条件,避免将 Pod 调度到特定节点。
-
Pod 间亲和性和反亲和性:将 Pod 调度到具有匹配属性的节点上的 Pod;还会考虑反亲和性条件,避免将 Pod 调度到具有特定属性的 Pod 所在的节点。
-
NodeName:将 Pod 调度到一个特定的节点上。
-
污点和容忍:避免将 Pod 调度到已打上污点的节点上,但如果 Pod 上定义了容忍规则,则可以做例外处理。
接下来的子章节将详细介绍上述属性。
节点选择器
kube-scheduler 只将 Pod 调度到具有匹配标签和值的节点上。
例如,考虑一个集群,其中集群中的节点属于不同的 CPU 平台。这些节点通过标签选择器和一个适当的值标记,指示节点的 CPU 平台。如果需要在特定 CPU 平台的节点上运行一个 Pod,则可以使用 Pod 属性 nodeSelector。kube-scheduler 会查找与 Pod 上的 nodeSelector 规范匹配的节点,并与节点上的匹配标签进行比较。如果没有找到符合条件的节点,则该 Pod 不会被调度。
图 7.9 显示了在 Pod 中使用 nodeSelector 以及它与节点规范匹配的相关性:


在前面的例子中,kube-scheduler 将把 Pod 调度到标签为 cpuPlatform 且对应值为 Skylake 的节点上。
节点亲和性和反亲和性
nodeSelector,其中只能指定标签匹配的精确值。这些偏好只会在调度时考虑,在执行时会被忽略。这意味着,一旦 Pod 被调度到某个节点,尽管节点的标签发生了变化,Pod 仍会继续在该节点上运行。
此外,节点亲和性和反亲和性偏好可以设置为两种属性,这两种属性可以作为硬性或软性约束。以下是这两种属性:
-
requiredDuringSchedulingIgnoredDuringExecution:这是一个硬性限制,只有满足条件时才会调度 Pod。
-
preferredDuringSchedulingIgnoredDuringExecution:这是一个软性限制,调度器会尝试将 Pod 部署到符合指定条件的节点上。如果找不到匹配的节点,Pod 仍然会部署到节点上。
以下是一个涉及使用 nodeAffinity 的 Pod 规范。该 Pod 规范指示该 Pod 不应该调度到具有特定 CPU 平台的节点上:
apiVersion: v1
kind: Pod
metadata:
name: pod-node-anti-affinity
spec:
containers:
- name: my-pod
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cpuPlatform
operator: Not In
values:
- Skylake
- Broadwell
在前面的例子中,kube-scheduler 不会将 Pod 调度到 CPU 平台为 Skylake 或 Broadwell 的节点上。
Pod 之间的亲和性和反亲和性
这是对节点亲和性(Node Affinity)的扩展,基本原理相同。该规范允许根据已经在节点上运行的 Pod 上的标签,将 Pod 调度到节点上。同样,反亲和性(Anti-Affinity)将确保,如果节点上已经运行了具有特定标签的其他 Pod,则不会将一个 Pod 调度到该节点。
Pod 亲和性和反亲和性的规则可以如下所示:
-
pod-affinity:仅当节点 N 上运行有与规则 A 匹配的其他 Pod 时,Pod P 才应该调度到节点 N 上。
-
pod-anti-affinity:如果节点 N 上有其他与规则 B 匹配的 Pod 运行,则 Pod P 不应该调度到节点 N 上。
图 7.10 显示了一个带有 Pod 亲和性和反亲和性定义的 Pod 规范:

图 7.10 – 带有 Pod 间亲和性和反亲和性的 Pod 定义
在前面的示例中,kube-scheduler 会在其他已在节点上运行的 Pod 标签与 app 匹配且为 webserver 或 elasticserver 的节点上调度 Pod。另一方面,kube-scheduler 不会在其他已在节点上运行的 Pod 标签与 app 匹配且为数据库的节点上调度 Pod。简而言之,这个 Pod 定义试图将 Pod 调度到不运行数据库应用程序的节点上。
节点名称
nodeName 是在 Pod 定义文件中可以指定的属性,也是指定节点选择约束的最简单方式。这种指定方式的最大局限性在于它是一个全有或全无的方案。
例如,如果节点可用于调度,则 Pod 可以在该特定节点上调度。然而,如果节点不可用,则 Pod 不会有其他节点可选。只有当节点能够处理更多工作负载时,Pod 才能被调度。此外,节点可以是临时的,尤其是当节点是虚拟机时。因此,指定节点名称可能不是一个好的设计方案,因此这种方法是最不推荐的。以下是带有 nodeName 属性的 Pod 定义:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: nginx
image: nginx
nodeName: node01
在前面的示例中,kube-scheduler 会尝试将 Pod 调度到节点名称为 node01 的节点上。
污染与容忍
节点亲和性和 Pod 亲和性是 Pod 用于寻找节点集合的属性。污点是节点的一个属性,可以排斥一个或多个 Pod。节点根据定义的键、操作符以及可选的值属性与特定效果一起被污点化。以下是可能指示节点被污染的情况:
-
NoSchedule:表示不能再在该节点上调度 Pod。
-
NoExecute:表示不能再在该节点上运行 Pod,且现有 Pod 应该被终止。
-
PreferNoSchedule:表示一个软限制,即不能再在该节点上调度更多 Pod。
容忍是一个功能,允许 Pod 在具有匹配污点的节点上进行调度。因此,容忍是抵消污点影响的一种方式。
以下是污染节点的 CLI 命令:
# Taint a node
kubectl taint nodes node01 sky=blue:NoSchedule
以下是一个定义容忍已污染节点的 Pod 规范,使得 Pod 仍然能够被调度到该节点:
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "sky"
value: "blue"
operator: "Equal"
effect: "NoSchedule"
这是一个分为两部分的例子,用于污染一个节点:
-
CLI 命令通过指定不调度具有匹配标签键值对
sky=blue的 Pod 来污染node01。 -
然而,Pod 定义为
node01定义了一个容忍。
因此,kube-scheduler 可能会在 node01 上调度 Pod。这就完成了在调度 Pod 到节点时需要考虑的关键因素的深入探讨。
在 Kubernetes 部署中,新的功能或 bug 修复通过部署更新的容器镜像来反映。更改部署或应用新部署有几种策略。这些将在接下来的章节中讨论。
Kubernetes 部署策略
如果需要通过增加副本数量来水平扩展应用程序,或者需要通过更新容器镜像来更改应用程序,则需要更改 Kubernetes 中的部署规范。这将导致自动更新,可能是通过部署额外的 Pods 来水平扩展,或部署新的 Pod 来更新镜像并替换当前运行的 Pod。
部署的更改可以通过应用更新的部署规范、编辑现有部署或专门更新部署中的镜像来完成。所有这些操作都可以通过 kubectl 命令进行。然而,执行部署所使用的策略对最终用户的影响非常大。部署策略有四种,每种策略有不同的使用场景。以下将详细说明这些策略,并在接下来的子章节中进行详细阐述:
-
Recreate
-
滚动更新
-
蓝绿部署
-
金丝雀发布
第一个详细介绍的部署策略将是 Recreate 策略。
Recreate 策略
Recreate 策略是一种基本策略,相比其他策略,它也是最直接的。基本上,当前运行的 Pods 会被销毁或关闭,然后根据新的 ReplicaSet 启动所需数量的 Pods。
以下是一个示例代码片段,说明了一个 Recreate 更新:
[...]
kind: deployment
spec:
replicas: 4
strategy:
type: Recreate
[...]
根据前面的示例代码片段,Kubernetes 将首先关闭当前 ReplicaSet 上的所有四个运行中的 Pods。然后,Kubernetes 会创建一个新的 ReplicaSet,并启动四个新的 Pods。请参见 图 7.11:

图 7.11 – 说明 Kubernetes 部署中的 'Recreate' 策略
Recreate 策略会导致停机,因为应用程序将暂时不可用。这将导致中断,因此对于拥有活跃用户群的应用程序,建议避免使用该策略。然而,在某些场景中,旧版本和新版本的应用程序无法或不应该在同一时间为用户提供服务时,仍然会使用该策略。
这就完成了 Recreate 策略。明显的缺点是不可避免的停机。这个缺点可以通过另一种部署策略来解决,称为滚动更新策略,下一小节将介绍该策略。
滚动更新策略
滚动更新(Rolling update)策略允许应用程序进行增量部署而不会导致停机。当前运行的 Pod 实例将逐渐被新的 Pod 实例替代,直到所有实例都被替换。应用程序始终保持可用。滚动更新策略是 Kubernetes 的默认部署策略。然而,这种策略并不会控制新 Pod 实例与旧 Pod 实例之间流量的分配。
部署过程会随着时间推移而逐步更新,这个过程是耗时且渐进的。有特定字段控制滚动更新策略,具体内容如下,从最大不可用(Max unavailable)开始。
最大不可用(Max unavailable)
.spec.strategy.rollingUpdate.maxUnavailable是一个可选字段,表示在部署过程中,最多可以不可用的 Pods 数量。这个值可以作为一个绝对数值或所需 Pods 数量的百分比来指定。如果未明确指定此字段,则默认值为 25%。此外,如果该字段被明确指定为0,则始终认为使用默认值。
举个例子。如果所需的 Pods 数量是 5,而maxUnavailable为 2,这意味着在任何时刻,旧版本和新版本的 Pods 总数的最小值应该为 3。
下一小节将介绍最大突增(Max surge)。这表示在当前和新的副本集之间,任何时候最多可以存在的 Pods 数量。
最大突增(Max surge)
.spec.strategy.rollingUpdate.maxSurge是一个可选字段,表示在部署过程中,除了所需 Pods 数量外,最多可以创建的 Pods 数量。这个值可以作为一个绝对数值或所需 Pods 数量的百分比来指定。如果未明确指定此字段,则默认值为 25%。此外,如果该字段被明确指定为0,则始终认为使用默认值。
举个例子。如果所需的 Pods 数量是 5,最大突增为 3,这意味着部署过程可以通过先推出三个新 Pods 来开始,并确保总的运行 Pods 数量不会超过 8(所需 Pods + 最大突增)。如果最大突增以百分比形式指定,且值设为 20%,则新旧部署中总的运行 Pods 数量不会超过 6(所需 Pods + 所需 Pods 的 10%)。
下一小节将介绍最小就绪时间(Min Ready)。这表示容器应该运行的最小时间,以确保 Pod 准备就绪。
最小就绪时间(Min ready)
.spec.minReadySeconds 是一个可选字段,表示新创建的 Pod 在就绪状态下应持续的最少秒数,即容器运行且没有任何失败或崩溃。如果未指定该值,默认值为 0,表示 Pod 在创建后即视为就绪。然而,如果指定了 10 秒,例如,Pod 必须在就绪状态下持续 10 秒,且没有任何容器失败,才会被视为可用。
下一小节将介绍进度截止时间;这是判断部署是否没有进展的最小等待时间。
进度截止时间
.spec.progressDeadlineSeconds 是一个可选字段,表示在报告部署失败进展之前的等待时间。如果未明确指定,默认值为 600(秒)。如果明确指定,则此值必须大于 .spec.minReadySeconds。
在滚动更新策略中,始终会创建一个新的副本集。新 Pods 会在新的副本集中创建,当前正在运行的 Pods 会逐步从旧副本集中移除。以下是一个示例片段,展示了滚动更新策略,并包含了影响滚动更新执行方式的关键字段:
[...]
kind: deployment
spec:
replicas: 8
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 4
maxUnavailable: 50%
[...]
根据前面的示例片段,以下是用于说明该示例的具体值:
-
期望的 Pods 数量 = 8 个 Pods。
-
最大突增 = 4。在任何时刻,旧副本集和新副本集中的 Pods 总数不能超过 12。
-
最大不可用 = 期望的 50% = 4。在任何时刻,旧副本集和新副本集中应该至少有 4 个 Pods 正在运行。
Kubernetes 会创建一个新的副本集,并启动 4 个新的 Pods。然后,Kubernetes 会在 Pods 创建后等待 5 秒,以判断这些 Pods 是否可用。因此,此时,旧副本集和新副本集中的 Pods 总数为 12,这是允许的最大值。这在图 7.12中得到了说明:

图 7.12 – 滚动更新;在新副本集中创建最多突增的 Pods
现在,鉴于在此示例中,最少有 4 个 Pods 正在运行,跨旧副本集和新副本集,Kubernetes 有可能会终止所有 8 个旧副本集中的 Pods,因为它会在新副本集中保留 4 个。因此,核心值仍然没有违反。这在图 7.13中得到了说明:

图 7.13 – 滚动更新;在当前副本集中删除最多不可用的 Pods
现在,Kubernetes 将在新的 ReplicaSet 中启动四个新的 Pods,并将达到期望的 Pods 数量。这在 图 7.14 中得到了说明。这完成了滚动更新,整个过程中满足了指定的限制:

图 7.14 – 滚动更新;在新的 ReplicaSet 中创建新的 Pods 直到达到期望的数量
滚动更新策略确保零停机,但缺点是无法控制部署完成所需的时间,也无法控制流量在旧版本和新版本之间的切换时间。下一个策略解决了这一特定缺点。
蓝绿策略
在 蓝绿 策略中,将有两个版本的部署在运行。这意味着有两个副本集,每个部署一个副本集。然而,每个副本集会有一组不同的标签来区分 Pods。流量通过服务发送到 Pods。服务最初会有标签,将流量发送到第一个部署或副本集。第二个部署也会运行,但不会处理任何流量。当服务被打补丁,并且服务上的标签被更新以匹配第二个部署中 Pods 的标签时,流量将被切换到第二个部署,而不会发生任何停机。
以下是 Kubernetes 集群中两个运行中的部署示例。在此示例中,部署的名称为 demo-app。这两个部署都在运行相同的应用程序,但使用不同版本的应用镜像。部署中的差异也通过 Pod 标签选择器得以体现,其中当前版本的部署有一个标签选择器,版本为 blue,而新部署的标签选择器则是版本为 green。
示例如 图 7.15 所示。服务最初指向版本为蓝色的部署。这是因为服务的标签选择器将版本设置为 blue,并与当前部署中的 Pod 标签选择器匹配。因此,流量仅由 blue 部署中的 Pods 处理。虽然 green 部署中的 Pods 正在运行,但它们没有处理任何流量:

图 7.15 – 蓝绿部署;仅由蓝色版本处理流量
图 7.16 显示了一个反映服务规范更新的片段,其中服务的标签选择器被更新为将版本从蓝色改为绿色:

图 7.16 – 更新服务规范以切换到新部署版本
图 7.17 反映了更新服务标签选择器后流量如何分配。在这种情况下,传入的流量将由绿色部署中的 Pods 提供,因为 Pod 标签选择器与服务的匹配。蓝色部署中的 Pods 将不再提供传入流量,尽管这些 Pods 可以继续运行:

图 7.17 – 蓝绿部署;流量仅由绿色版本提供
部署的推出就像更新服务的标签,将流量指向匹配蓝色部署的 Pods 一样简单。
蓝绿部署也被称为红黑部署,或 A/B 部署。虽然蓝绿部署能够控制流量发送到特定部署或回滚到哪个部署,但缺点是总是有两倍数量的应用程序在运行,这显著增加了基础设施成本。此外,它是一种全有或全无的场景,应用程序与更新部署相关的 bug 或问题会影响所有用户。这一缺点通过使用下一个部署策略——金丝雀部署来解决。
金丝雀部署
金丝雀部署提供了更多的控制,能够决定向新部署发送多少流量。这确保了应用程序的更改只会影响部分用户。如果更改效果不如预期,那么它也只会影响一小部分活跃用户,从而控制客户的感知。金丝雀部署在持续部署过程中被越来越多地使用,因为它是一种渐进式变化,新的功能可以持续添加到活跃用户中,但以受控的方式进行。
图 7.18 展示了金丝雀部署的情况,其中只有 10% 的流量被发送到新的部署(版本=绿色),而剩余的 90% 流量则发送到当前的部署(版本=蓝色):

图 7.18 – 金丝雀部署;流量根据加权百分比发送到两个版本
金丝雀部署是真正可靠的持续部署模型的体现,因为对应用程序的更改可以通过 CI/CD 管道流动,并可以部署到生产环境。此外,部署也可以仅针对特定用户群体或用户基础进行。这确保了新功能会被实际用户(如 beta 用户)测试,同时也能确保新功能的故障不会对整个用户基础产生负面影响。金丝雀部署在现实世界中通常通过使用 Istio 这类资源来实现。Istio 可以根据预定义的权重在两个版本之间拆分和路由流量。随着新版本变得更加稳定,流量可以通过改变加权百分比逐渐转移到新部署。
这完成了对 Kubernetes 中可能的部署策略的详细说明。也总结了这一章,主要关注理解 Kubernetes 中用于容器化部署的关键构造。
总结
在这一章中,我们详细讨论了 Kubernetes 工作负载,并将 Kubernetes 作为部署容器化应用程序的选项。我们了解了 Kubernetes 集群的构造,特别是关注理解构成主控制平面和节点控制平面的关键组件。此外,我们重点学习了对在集群中部署应用至关重要的 Kubernetes 对象,以及可能的部署策略。最后,我们深入探讨了主平面组件在执行针对对象(如 Pod)操作时如何交互,并讨论了调度 Pod 到 Kubernetes 节点上的各种因素。
下一章将重点介绍 Kubernetes 的托管版本,称为 GKE 或 GKE。我们在本章中研究的 Kubernetes 基本构造,例如集群构造或 Kubernetes 对象,对于 GKE 来说基本相同。然而,GKE 使得集群创建变得更容易,此外,GKE 还提供了额外的集群管理功能。本章将详细介绍与 GKE 特定的主题,例如节点池、集群配置选项和自动扩展。
需要记住的要点
以下是一些需要记住的重要事项:
-
Kubernetes 集群中的节点被分类为主节点或工作节点。主节点运行控制平面组件。
-
Kubernetes 控制平面的关键组件包括
kube-apiserver、etcd、kube-scheduler、kube-controller-manager和cloud-controller-manager。 -
建议将控制平面组件运行在同一节点上,并避免在该节点上运行任何用户特定的容器。
-
高可用集群可以有多个控制平面。
-
kube-apiserver处理对集群的任何查询或更改,并且可以进行水平扩展。 -
etcd是一个分布式键值存储,用于 Kubernetes 存储集群配置数据。 -
kube-scheduler选择一个合适的节点来部署应用程序。 -
kube-controller-manager运行多个控制器功能,确保集群的当前状态与期望状态一致。 -
cloud-controller-manager包括控制器功能,使 Kubernetes 能够与云提供商的服务进行集成。 -
工作节点的关键组件包括
kubelet(一个 Kubernetes 代理,监听来自kube-apiserver的指令,并根据 Pod 规范运行容器)、kube-proxy(一个网络代理,用于启用服务之间的通信)以及容器运行时(负责运行容器的软件)。 -
Deployment、ReplicaSet、StatefulSet、DaemonSet、Jobs 和 CronJobs 被归类为工作负载资源,每个资源运行一个或多个 Pod。
-
Pod 是 Kubernetes 集群中最小的可部署单元,可以包含一个或多个共享文件系统、命名空间和网络资源的容器。
-
部署提供了一种声明性方式来管理一组 Pod,这些 Pod 是副本。
-
StatefulSets 管理有状态应用程序,可以扩展一组 Pod,但每个副本是独特的,并具有自己的状态。
-
DaemonSets 确保 Pod 的副本在集群的每个节点或某些子集节点上运行。
-
EndPoint 对象将维护与标签选择器匹配的 Pod 所有 IP 地址的列表,并会随着 Pod 的删除和创建而不断更新。
-
ExternalName 是一种服务类型,其中服务使用 DNS 名称而非标签选择器。
-
调度 Pods 时需要考虑的关键因素包括 NodeSelector、NodeAffinity、Pod 间亲和性与反亲和性、污点与容忍度以及 NodeName。
-
Kubernetes 部署的可能策略包括重建、滚动更新、蓝绿发布和金丝雀发布。
进一步阅读
有关 GCP 在 DevOps 方面的方法,阅读以下文章:
- Kubernetes:
kubernetes.io/docs/home/
实践测试
回答以下问题:
-
用户更改 Kubernetes 集群中运行的 Pod 中容器的镜像,并更新部署规范。选择描述准确行为的选项:
a) 与部署绑定的 Pod 的容器镜像会立即更新,运行中的 Pods 会使用新的容器镜像。
b) 将创建一个新的 ReplicaSet,新的镜像会在新的 Pod 中运行,并与旧的 ReplicaSet 中的旧镜像并行运行。
c) 当前运行的 Pod 会立即停止,新的 Pod 会使用新的镜像创建,并会有一些停机时间。
d) 将创建一个新的 ReplicaSet,新的镜像会在新的 Pod 中运行,并会逐渐替换旧的 ReplicaSet 中的 Pods。
-
选择 Kubernetes 中最小的部署单元:
a) 部署
b) 容器
c) Pod
d) ReplicaSet
-
选择对象以及服务对象指引流量的依据:
a) 服务对象根据元数据将流量发送到部署。
b) 服务对象根据标签选择器将流量发送到 Pods。
c) 服务对象根据标签选择器将流量发送到容器。
d) 服务对象根据 Pod 和 Service 使用相同名称来将流量发送到 Pods。
-
Pod 虽处于就绪状态,但在启动时进行一些内部操作,因此无法提供传入流量。来自服务的流量失败。选择可能的解决方案:
a) 配置启动探针。
b) 配置存活探针。
c) 配置就绪探针。
d) 以上都不是。
-
需要在 GKE 集群中部署多个可以根据需求独立扩展的应用程序。这些应用程序中有一些是内存密集型的,有些是 I/O 密集型的,还有些是 CPU 密集型的。选择表示最合适集群设计的选项:
a) 选择应用程序所属的主要类别,并创建一个集群,该集群使用 CPU 密集型、内存密集型或 I/O 密集型的机器类型。
b) 创建一个节点具有最大 CPU 和内存的集群。
c) 创建一个具有多个节点池的集群。每个节点池可以用来运行具有特定 CPU、内存或 I/O 要求的特定类型的应用程序。
d) (b) 和 (c)。
-
哪个特定的部署选项允许在生产环境中以少量实际流量测试应用程序的新版本?
a) 百分比部署
b) 滚动更新
c) 金丝雀部署
d) 蓝绿部署
-
选择适当的服务类型,服务获取一个内部 IP 地址:
a) ClusterIP
b) NodePort
c) 负载均衡器
d) 以上所有选项
-
以下哪个部署选项可以在备用状态下运行最后一个成功的部署,以便如果最新的部署出现问题时可以使用?(选择所有适用选项)
a) 滚动更新
b) A/B 部署
c) 金丝雀部署
d) 红黑部署
-
以下哪个控制器允许多个开发团队使用同一个集群,但对 CPU 和内存的使用进行特定控制?
a) 授权控制器
b)
kube-controller-managerc) ResourceQuota 准入控制器
d)
cloud-controller-manager -
DaemonSet 的功能是什么?
a) 它在集群的每个节点上运行特定的 Pod。
b) 它在集群的每个节点上运行特定 Pod 的多个副本。
c) 它在集群的每个节点或选定节点的子集上运行特定的 Pod。
d) 它在集群的每个节点或选定节点的子集上运行 Pod 的多个副本。
-
有一个特定的需求,如果容器 C1 当前使用的内存或 CPU 是指定请求限制的三倍,则应终止容器 C1。选择所有符合指定要求的选项并应添加到 Pod 规范中:
a) 请求:CPU=1000m, 内存=500Mi
限制:CPU=3000m, 内存=1250Mi
b) 限制:CPU=3000m, 内存=1500Mi
请求:CPU=1000m, 内存=500Mi
c) 请求:CPU=750m, 内存=1000Mi
限制:CPU=2250m, 内存=3000Mi
d) 限制:CPU=1200m, 内存=500Mi
请求:CPU=3600m, 内存=1500Mi
-
一个名为
log-collector的 StatefulSet 包含三个副本。假设 Pods 被标记为log-collector-0、log-collector-1和log-collector-2。现在副本数缩减到两个副本。以下哪个 Pod 将被删除?a) 按顺序创建的第一个 Pod 将被删除(
log-collector-0)。b) 随机删除一个 Pod。
c) 最后创建的 Pod 将被删除(
log-collector-2)。d) 无法缩减 StatefulSet 的规模。
-
选择描述 CrashLoopBackOff 错误原因的选项:
a) 在对 Pod 进行更新时,容器将被终止。
b) Pod 中的一个容器在多次尝试后未能成功启动。
c) 在对部署进行更新时,容器将被终止。
d) 以上都不是。
-
选择描述所有容器在 Pod 中成功终止并且不会被重启的状态的选项:
a) 未知
b) 等待中
c) 已完成
d) 失败
-
选择适当的服务类型,其中服务获得集群范围内的端口:
a) ClusterIP
b) NodePort
c) LoadBalancer
d) 以上所有
答案
-
(d) – 将创建一个新的 ReplicaSet,并在新的 Pod 中运行新的镜像,逐步替换旧 ReplicaSet 中的 Pods。
-
(c) – Pod。
-
(b) – 服务对象根据标签选择器将流量发送到 Pods。
-
(c) – 配置就绪探针。
-
(c) – 创建一个包含多个节点池的集群。
-
(c) – 金丝雀部署。
-
(d) – 以上所有。
-
(b) 和 (d) – A/B 和 Red/Black 与 Blue/Green 相同。
-
(b) – ResourceQuota 是一种入驻控制器的示例,其中一个命名空间可以被限制为仅使用一定容量的内存和 CPU。每个开发团队可以在自己的命名空间中独立工作。
-
(c) – 它会在集群中的每个节点或选定节点的子集上运行一个特定的 Pod。
-
(b) 和 (c)。
-
(c) – 最后创建的 Pod 将被删除(
log-collector-2)。 -
(b) – Pod 中的一个容器在多次尝试后未能成功启动。
-
(c) – 已完成。
-
(b) – NodePort。
第八章:理解 GKE 基础知识以部署容器化应用
Kubernetes 或 K8s 是一个开源的容器编排系统,用于自动化应用程序的部署、扩展和管理运行容器化应用程序的集群。前一章介绍了 K8s 的基础知识,包括集群结构、主平面组件、Kubernetes 对象(如 Pods 和 Services)、工作负载(如 Deployments、StatefulSets、DaemonSets 等),并深入探讨了部署策略。然而,搭建一个开源的 Kubernetes 集群涉及大量基础设施层面的工作,并且需要花费大量时间来设置。此外,还包括后期的维护活动,如更新、升级或修复集群。GCP 提供了一个计算服务,提供一个托管的 Kubernetes 或 K8s 环境,称为 Google Kubernetes Engine (GKE)。
本章介绍了作为 GCP 中托管 Kubernetes 选项的 Google Kubernetes Engine,并使用在 第七章 中介绍的概念,理解 Kubernetes 基础知识以部署容器化应用,来创建一个托管的 GKE 集群,将容器化应用程序部署到集群中,并使该应用程序可供外部客户端访问。本章随后详细介绍了 GKE 的关键特性,包括以下内容:
-
Google Kubernetes Engine (GKE) – 介绍
-
GKE – 核心特性
-
GKE 自动驾驶模式 – 实操实验
技术要求
有四个主要的技术要求:
-
一个有效的 Google Cloud Platform (GCP) 账户,以便使用 GCP 服务:
cloud.google.com/free -
安装 Google Cloud SDK:
cloud.google.com/sdk/docs/quickstart -
安装 Git:
git-scm.com/book/en/v2/Getting-Started-Installing-Git -
安装 Docker:
docs.docker.com/get-docker/
Google Kubernetes Engine (GKE) – 介绍
GKE 是一个托管的 K8s,能够从用户的角度抽象出管理主平面组件的需求。创建 GKE 集群比创建 K8s 集群要简单得多。这是因为 GKE 集群创建过程中无需手动创建节点、配置节点和证书、以及建立节点间的网络通信。GKE 还提供了自动扩展和管理集群节点软件自动升级的选项。
以下是 GKE 集群的关键特性,这些特性使 GKE 与开源 Kubernetes 或 K8s 区别开来:
-
完全托管,抽象出用户无需提供底层资源的需求。
-
使用一种容器优化的操作系统,这是一种由 Google 维护的操作系统,专为快速扩展且资源需求最小化而设计。
-
支持自动升级,并提供选项,可以选择获取最新的功能,或是选择更稳定的版本,而无需手动干预。
-
提供自动修复节点的功能,通过持续监控节点的状态。如果节点不健康,会优雅地将其排空并重新创建。
-
根据需要自动扩展集群,添加更多的节点。
除了前述功能,以下是一些 K8s 中可用的关键功能,这些功能需要作为附加组件添加并显式维护。而这些功能在 GKE 中是标准配置,使得 GKE 相比 K8s 更加可行和优选:
-
负载均衡器——GKE 提供了一个 HTTP(S) 负载均衡器。
-
DNS——GKE 实现了服务发现,并提供了托管 DNS。
-
日志、监控和仪表板——由于与 Google Cloud 操作的集成,GKE 提供了这些内置功能。
直到最近,GKE 只提供了一种操作模式,称为 标准 模式(也称为默认模式)。标准模式允许用户选择运行工作负载所需的配置,例如节点的机器类型。此模式还允许选择安全配置功能,提供将运行相似工作负载的节点分组的能力,提供配置网络的选项等。总的来说,通过 GKE 标准模式创建集群比在开源 K8s 中要容易,但仍然有学习曲线。
GKE 最近引入了一种新的操作模式,称为 Autopilot。Autopilot 预先选择了许多配置,基本上创建了一个从安全角度强化的生产级集群。虽然有一些配置选项,但最重要的是,只有在工作负载部署时才会配置节点。Autopilot 模式将在本章后面通过动手实验详细讨论。
重要提示
当前章节重点讲解 标准 模式,除非明确说明。本章将帮助你了解在创建 GKE 集群时可用的选项,并提供 GKE 功能的洞见。后续章节会详细介绍 Autopilot 模式,强调标准模式和 Autopilot 模式之间的主要区别,并附带一个动手实验。
GKE 与 GCP 的多项服务提供无缝集成。GKE 提供选项,通过使用 Cloud Build 构建存储在源代码仓库中的代码自动化部署,从而生成可以存储在 Google 容器注册表中的私有容器镜像。此外,通过 Google 的身份和访问管理(IAM)可以控制访问集群的权限和配置 GKE 集群选项。GKE 与 GCP 的网络服务集成,因为 GKE 集群作为 Google 的虚拟私有云(VPC)的一部分创建。GCP 提供对 GKE 集群及其资源的洞察,GKE 与 Google 的 Cloud operations 集成,Cloud operations 是 Google 提供的一套旨在提供与监控和日志相关的集成服务的工具。
我们将通过逐步过程创建一个 GKE 集群,这将提供对可能配置选项的洞察。集群创建完成后,用户将能够通过 Deployment 的概念部署应用,并通过 Service 的概念暴露应用。应用运行在由 Pod 包裹的容器中。Deployment 规格将管理 Pod。Pod 随后通过 Service 的概念进行暴露。Pod、Deployment 和 Service 这些概念是 K8s 基础知识,已经在第七章《理解 Kubernetes 基础知识以部署容器化应用》中讨论过,这些概念将在实际的 GKE 集群中付诸实践。
创建 GKE 集群
创建 GKE 集群有多种方式——Cloud Console、CLI 或 REST。要创建集群,用户或服务帐户应具备以下预定义角色之一:Kubernetes 引擎管理员或 Kubernetes 引擎集群管理员。
以下是通过 Google Cloud Console 创建 GKE 集群的逐步过程。此示例中的操作模式为标准模式:
-
导航至 GCP 控制台并选择计算服务 – Kubernetes 引擎。
-
选择创建集群的选项并选择标准模式。
-
输入集群名称为
my-first-cluster。 -
保留其余选项的默认选择。请参见 图 8.1:
图 8.1 – 从 GCP 控制台创建 GKE 集群
-
选择创建集群的选项。这将启动集群创建过程。
-
新创建的集群将在集群主页显示。请参见 图 8.2:

图 8.2 – GKE 集群列表页面显示新创建的集群
新创建的集群使用了默认选项。除集群名称外,集群创建过程中没有进行任何实际更改。以下是使用默认选项创建 GKE 集群时需要了解的一些重要事项。列表中提到的每个默认选项都可以在集群创建过程中显式更改:
-
集群的默认位置类型为区域性。位置类型指的是基于可用性要求的集群类型。可选项有区域性和区域级别。
-
默认值为
us-central1-c。这表示控制平面组件的创建区域。 -
默认值为
us-central1-c。这表示节点创建的位置。可以选择区域内的多个位置来形成一个集群,其中位置类型是多区域集群。 -
默认控制平面版本为发布通道。控制平面版本提供了指示集群版本的选项。集群版本代表了在稳定性方面首选的功能集。
-
3,表示工作节点的数量。集群默认只有 1 个节点池。需要注意的是,集群大小不包括主节点的数量。客户仅需为工作节点付费。主节点及其相关的主平面组件完全由 GKE 管理。 -
default-pool。节点池是虚拟机的集合。 -
默认节点池由 3 个节点组成,节点的机器类型为
e2-medium(2 个 vCPU,4 GB 内存)。 -
默认维护窗口为随时。这意味着 GKE 维护可以在集群上的任何时间进行。这不是在运行生产工作负载时的首选选项。
-
基于网络的默认集群类型为公共集群,默认VPC 网络为default。这表示客户端如何访问控制平面,以及集群中的应用程序如何彼此之间以及与控制平面进行通信。
-
高级网络选项,如VPC 原生流量路由和HTTP 负载均衡,默认是启用的。这些选项将在本章稍后的子章节GKE 中的网络中详细讨论。
-
110。 -
安全功能Shielded GKE 节点已启用。该功能为加入集群的节点提供强加密身份,并将在第九章中详细讨论,章节标题为使用 GKE 安全构件保护集群。
-
GKE 的云操作已启用,并设置为系统、工作负载日志记录和监控。此功能会聚合基础设施和应用级工作负载的日志、事件和指标。
也可以通过命令行界面(CLI)创建集群。以下是使用默认选项创建集群的 CLI 命令。CLI 中使用的默认选项与之前从控制台创建集群时使用的默认选项相同。一个显著的区别是,在通过 CLI 执行时,必须显式指定一个区域。然而,在 UI 中,区域会自动填充,除非进行了修改:
# Create a GKE cluster with default options
gcloud container clusters create my-first-cli-cluster --zone us-central1-c
该 CLI 命令可以从本地计算机的终端窗口运行,该计算机已经安装并配置了 Google Cloud SDK。或者,也可以通过 Google Cloud Console 激活 Google Cloud Shell 来执行该命令。
在 GKE 集群创建后,下一步是将应用程序部署到 GKE 集群,并将其公开给外部客户端。接下来将讨论这一主题。
GKE 集群 – 部署并公开应用程序
在第六章中,使用 Cloud Build 构建代码并推送到容器注册表,我们创建了一个容器镜像,并使用 Cloud Run 部署了该容器镜像。在本章及本小节中,我们将重用此镜像,并通过创建适当的工作负载将其部署到新创建的 GKE 集群中。应用程序部署后,将通过服务公开,以便外部客户端(如网页浏览器)可以访问该应用程序。
重要提示
为了保持示例的连续性,我们将使用在第六章中创建的容器镜像,使用 Cloud Build 构建代码并推送到容器注册表 – gcr.io/gcp-devops-2021/cloud-build-trigger。建议使用你有权限访问的适当容器镜像。例如,如果你按照第六章中的逐步说明,使用 Cloud Build 构建代码并推送到容器注册表,并最终在你的项目中创建了一个容器镜像,你可以在本章中重用相同的镜像。
我们将以两种不同的方式部署并公开应用程序:
-
GKE 控制台
-
通过 Cloud Shell 的 CLI 方法
需要注意的是,在大多数情况下,集群通常通过命令行部署。然而,我们将首先探索 GKE 控制台的方法,因为这将使我们深入了解可用的配置选项。接下来将讨论这一主题。
GKE 控制台
第一步是通过 GKE 控制台将应用程序部署到 GKE 集群中。
将应用程序部署到 GKE 集群
以下是在 GKE 控制台中部署应用程序的逐步过程:
-
在 GCP 控制台的 Kubernetes Engine 部分,导航到 Clusters 页面。
-
选择之前创建的集群 –
my-first-cluster。 -
在左侧面板中,选择工作负载部分。从 GKE 的角度来看,工作负载指的是 Deployments、StatefulSets、DaemonSets、Jobs 和 CronJobs。目前没有工作负载,当前状态如下所示,参见图 8.3:
![图 8.3 – 新创建集群的工作负载部分]()
图 8.3 – 新创建集群的工作负载部分
-
通过选择部署选项来创建工作负载。此操作允许您通过两步过程创建 Deployment 对象。
-
创建 Deployment 的第一步是定义 Deployment 所需的容器。选择在第六章中创建的容器镜像,使用 Cloud Build 构建代码并推送到容器注册表。对于这个示例,选择容器镜像
gcr.io/gcp-devops-2021/cloud-build-trigger。参见图 8.4。可选地,添加容器的环境变量,并点击完成:![图 8.4 – 在定义 Deployment 容器时选择容器镜像]()
图 8.4 – 在定义 Deployment 容器时选择容器镜像
-
可选地,可以通过使用添加容器选项将多个容器添加到 Pod 中。请参阅图 8.5:
![图 8.5 – 向 Deployment 添加多个容器的选项]()
图 8.5 – 向 Deployment 添加多个容器的选项
-
创建 Deployment 的第二步是配置 Deployment。这包括指定应用程序名称、命名空间、标签以及应用程序应该部署到的集群。对于这个具体示例,设置
hello-world、default、app和hello-world,并选择名为my-first-cluster的集群。参见图 8.6:![图 8.6 – 通过指定所需属性来配置 Deployment]()
图 8.6 – 通过指定所需属性来配置 Deployment
-
在选择部署选项之前,可以通过选择查看 YAML选项来查看配置的 YAML,如图 8.6所示。默认情况下,副本数定义为 3。这可以根据需要更改为所需的副本数量。
-
通过选择部署选项来启动部署创建过程。
-
新创建的 Deployment –
hello-world– 将如下所示显示。此 Deployment 创建了三个副本,使用相同的镜像。请参阅图 8.7:

图 8.7 – 新创建的 Deployment 的详细信息
需要注意的是,新创建的部署 – hello-world – 不能被外部客户端(如 Web 浏览器或通过 ping 命令)访问,因为该部署没有被暴露为 Service。然而,仍然可以通过使用 port-forward 选项进行测试。执行此选项所需的 CLI 命令如下所示。这些命令可以通过 Google Cloud Shell 执行:
# Connect to the cluster – 'my-first-cluster'
gcloud container clusters get-credentials my-first-cluster --zone us-central1-c --project gcp-devops-2021
# Find the list of pods for the deployment hello-world
kubectl get pods
# For a specific pod, create a port-forward option to access the application running inside the pod
kubectl port-forward hello-world-6755d97c-dlq7m 10080:8080
一旦执行上述 port-forward 命令,来自 127.0.0.1:10080 的流量将被转发到端口 8080。端口 8080 是与 hello-world 部署相关的容器端口。参见 图 8.8:

图 8.8 – 将流量转发到 Pod 内部的容器
为了测试流量是否被转发,打开另一个 Cloud Shell 窗口并运行如下 curl 命令。这将对在 Pod 容器内运行的应用进行 REST 调用。参见 图 8.9:

图 8.9 – 通过端口转发访问 Pod 中应用的结果
或者,你也可以在 Cloud Shell 中使用 10080 端口的 Web 预览选项来查看应用。由于应用已经部署并按预期工作,下一步是将该应用暴露为 Service。
将应用暴露为 Service
以下是通过 GCP 控制台将应用暴露为 Service 的逐步过程:
-
导航到 GCP 控制台中 Kubernetes Engine 部分的 Clusters 页面。
-
选择之前创建的集群 –
my-first-cluster。 -
选择之前创建的部署 –
hello-world。 -
在部署详情页面的 Actions 菜单下,选择 EXPOSE 选项。这将打开一个弹出窗口,需要选择 端口、目标端口、协议 和 Service 类型。
-
输入
80(表示 Service 监听传入流量的端口)、8080(表示容器监听的端口)、TCP和负载均衡器。选择 EXPOSE 选项。参见 图 8.10:![图 8.10 – 指定端口映射,将 Pod 暴露为负载均衡器类型的 Service]()
图 8.10 – 指定端口映射,将 Pod 暴露为负载均衡器类型的 Service
-
一旦 Pod 被暴露,就会创建一个 Service,如下图所示。由于该 Service 是 LoadBalancer 类型,Service 将具有一个外部端点。参见 图 8.11:
![图 8.11 – 通过暴露 Pod 创建的 LoadBalancer Service]()
图 8.11 – 通过暴露 Pod 创建的 LoadBalancer Service
-
选择外部端点。这将在浏览器中打开应用程序,如下图所示。这基本上是将应用程序部署到 GKE 集群后的输出。输出与在 第六章,使用 Cloud Build 构建代码并推送到容器注册表 中,使用相同的容器镜像部署到 Cloud Run 时的输出相同。参见 图 8.12:

图 8.12 – 通过负载均衡器服务访问应用程序的输出
这完成了将应用程序部署到 GKE 集群并通过 GKE 控制台将应用程序暴露为负载均衡器服务的主题。下一个子章节基本上是一个类似的示例,但提供了如何通过 Cloud Shell 使用 CLI 方法完成相同任务的见解。
通过 Cloud Shell 使用 CLI 方法
在这个子章节中,我们将通过 CLI 使用 Cloud Shell 部署应用程序并将其暴露为负载均衡器服务。我们将使用之前创建的相同集群 — my-first-cluster。同时,建议使用作为练习一部分创建的容器镜像,位于 第六章,使用 Cloud Build 构建代码并推送到容器注册表。在本示例中,将使用容器镜像 gcr.io/gcp-devops-2021/cloud-build-trigger。
将应用程序部署到 GKE 集群
以下是通过 Cloud Shell 部署应用程序的逐步过程:
-
打开 Cloud Shell 并使用以下 CLI 命令连接到集群:
# Connect to the cluster gcloud container clusters get-credentials my-first-cluster --zone us-central1-c --project gcp-devops-2021 -
创建一个名为
hello-world-cli.yaml的新文件,内容如下。这个文件本质上创建了一个包含容器及其对应镜像的部署。还指定了副本数,在本例中为 1:apiVersion: "apps/v1" kind: "Deployment" metadata: name: "hello-world-cli" namespace: "default" labels: app: "hello-world-cli" spec: replicas: 1 selector: matchLabels: app: "hello-world-cli" template: metadata: labels: app: "hello-world-cli" spec: containers: - name: "cloud-build-trigger-sha256-1" image: "gcr.io/gcp-devops-2021/cloud-build-trigger:latest" -
通过运行以下命令创建部署:
kubectl apply -f hello-world-cli.yaml
一旦部署创建完成,可以通过 CLI 查询该部署及其相应的 Pod。请注意,此部署将只创建一个 Pod。参见 图 8.13:

图 8.13 – 通过 CLI 查询部署情况
部署的应用程序无法通过外部客户端访问。然而,在前一个子章节中解释的端口转发方法也可以在此上下文中完全适用。鉴于应用程序已经部署,下一步是将应用程序暴露为服务。
将应用程序暴露为服务
以下是通过 Cloud Shell 将应用程序暴露为服务的逐步过程:
-
创建一个名为
hello-world-cli-service.yaml的新文件,定义如下。这将创建一个负载均衡器服务,将暴露带有匹配标签选择器的 Pod:apiVersion: v1 kind: Service metadata: name: hello-world-cli-service spec: type: LoadBalancer selector: app: hello-world-cli ports: - protocol: TCP port: 80 targetPort: 8080 -
通过运行以下命令创建负载均衡器服务:
kubectl apply -f hello-world-cli-service.yaml -
一旦创建了服务,负载均衡器将被创建并分配一个外部端点。根据服务定义,该服务将在
80端口监听流量,并将流量转发到8080端口的容器。可以通过如下方式查询服务来获取服务的外部端点。请参见图 8.14:![图 8.14 – 查询负载均衡器服务以获取外部端点]()
图 8.14 – 查询负载均衡器服务以获取外部端点
-
通过浏览器窗口访问外部端点。输出将与第六章《使用 Cloud Build 构建代码并推送到容器注册表》中的输出或通过控制台在 GKE 中部署的应用程序的输出相同。这是因为我们使用的是相同的镜像。请参见图 8.15:

图 8.15 – 通过外部端点查看负载均衡器服务的输出
本节结束,介绍了 GKE 并深入探讨了创建 GKE 集群、将应用程序部署到集群并将已部署的应用程序公开为外部客户端可访问的服务的步骤。实际上,这种方法的输出与控制台方法的输出相同。目标是理解通过 CLI 创建集群、部署工作负载并通过服务暴露工作负载的过程。
在创建集群或部署应用程序时使用的概念与构成 K8s 基础的概念相同(在第七章《理解 Kubernetes 基础以部署容器化应用》中已学习)。然而,集群创建的性质更加简单,因为主控平面组件的维护已完全抽象化,不再是用户的责任。接下来的部分将重点介绍 GKE 的核心功能和可能的集群类型,并介绍 GKE 中与网络和云操作的集成。
GKE – 核心功能
本节涵盖以下主题。这些主题将提供大量信息,帮助您构建对 GKE 的良好理解和操作知识。这些 GKE 概念大多是 Kubernetes 部分学习的主题的扩展。将要覆盖的主题如下:
-
GKE 节点池
-
GKE 集群类型
-
GKE 中的自动扩展
-
GKE 中的网络
-
GKE 的云操作
接下来小节将详细介绍的第一个 GKE 构建块是 GKE 节点池。
GKE 节点池
Kubernetes 集群中的节点(即工作节点)部署工作负载。分布在所有节点上的工作负载性质可能不同。有些工作负载可能是 CPU 密集型的,有些可能是内存密集型的,还有些可能需要特定版本的 CPU 平台。工作负载还可能是容错的批处理任务,或者需要特定类型的存储,如 SSD。
nodeConfig 规范。所有符合 nodeConfig 规范的节点将使用节点标签标记,其中键为 cloud.google.com/gke-nodepool,值为节点池的名称。
以下是一个包含特定机器类型、OAuth 范围和磁盘类型的 nodeConfig 规范示例:
nodeConfig: {
machineType: "n2-highmem-32",
oauthScopes: [
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring"
],
diskType: "pd-ssd"
}
集群总是与默认节点池一起创建,默认节点池具有特定数量的节点和特定的机器类型(以及其他属性)。可以根据各自的 nodeConfig 和工作负载需求添加额外的自定义节点池。
以下是节点池的一些关键特性:
-
新创建的节点池默认运行最新的稳定 Kubernetes 版本。
-
现有节点池上的 Kubernetes 版本可以配置为自动升级,也可以手动升级。
-
可以单独调整节点池的大小、升级或删除,而不影响其他节点池。对节点池的任何更改都会影响池中的所有节点。
以下是一些 CLI 命令,可以对节点池执行操作。这些命令可以在本章之前创建的集群 my-first-cluster 上执行。
以下 CLI 命令会创建一个特定机器类型的节点池:
gcloud container node-pools create my-high-mem-pool --machine-type=n1-highmem-8 --cluster=my-first-cluster --num-nodes=2 –zone=us-central1-c
创建的节点池将在 GKE 控制台中反映出来,显示在集群对应位置(参见图 8.16):

图 8.16 – 新建自定义节点池 – 创建了 my-high-mem-pool
以下是其他 CLI 命令,用于调整节点池大小、升级到特定版本或删除节点池:
# Resize node pool
gcloud container clusters resize my-first-cluster --node-pool=my-high-mem-pool --num-nodes=1 –zone=us-central1-c
# Upgrading node pool to specific cluster version
gcloud container clusters upgrade my-first-cluster --cluster-version="1.17.17-gke.3000" --node-pool=my-high-mem-cluster --zone=us-central1-c
# Delete a node pool
gcloud container node-pools delete my-high-mem-pool --cluster=my-first-cluster --zone=us-central1-c
在区域性或多区域集群中的节点池会被复制到多个区域。此外,可以通过明确指定节点池名称使用 nodeSelector,或者找到满足工作负载资源请求的节点池,来将工作负载部署到特定节点池中。
如果节点池名称通过 nodeSelector 属性明确指定,则 kube-scheduler 会将工作负载部署到指定的节点。否则,kube-scheduler 会找到符合工作负载资源请求的节点池。
这完成了 GKE 节点池的概述。接下来的主题将深入探讨 GKE 中的各种集群配置。
GKE 集群配置
GKE 提供多种集群配置选择,基于集群可用性类型、集群版本、网络隔离和 Kubernetes 特性。以下子章节将详细讨论这些配置选项。
集群可用性类型
GKE 允许你根据工作负载的可用性要求创建集群。根据可用性类型,有两种集群配置——区域集群(单区域或多区域)和区域集群。这些将在以下子章节中讨论。
区域集群
区域集群将拥有一个在单一区域运行的控制平面副本。节点(即工作节点)可以运行在单一区域,也可以跨多个区域运行。如果节点与控制平面运行在同一区域,则表示为单区域集群。然而,如果节点跨多个区域运行,则表示为多区域集群。请注意,GKE 允许每个区域最多创建 50 个集群。
多区域集群将仅有一个控制平面的副本。选择单区域集群还是多区域集群取决于应用程序所需的可用性级别。对于多区域集群,如果发生集群升级或区域故障,节点上运行的工作负载将继续运行,但直到集群控制平面可用之前,无法配置新的节点或工作负载。
以下是创建区域集群(单区域和多区域)的 CLI 命令:
#Syntax
gcloud containers clusters create CLUSTER_NAME \
--zone COMPUTE_ZONE \
--node-locations COMPUTE_ZONE, COMPUTE_ZONE, [..]
#Single Zone Cluster
gcloud containers clusters create single-zone-cluster \
--zone us-central1-a
#Multi Zonal Cluster
gcloud containers clusters create single-zone-cluster \
--zone us-central1-a \
--node-locations us-central1-a,us-central1-b, us-central1-c
与区域相关的输入参数是指控制平面的位置。节点位置指的是工作节点的所在位置,对于单区域集群来说并不需要指定,因为它与主控制平面的位置相同。
这就是 GKE 区域集群的简要概述。下一个主题将概述 GKE 区域集群。
区域集群
区域集群提供了在工作节点和控制平面方面的高可用性。区域集群在多个区域内运行多个控制平面副本。工作节点也跨多个区域进行复制,并且工作节点与控制平面在同一区域内共同运行。区域集群不能转换为区域集群。
以下是创建区域集群的 CLI 命令:
#Syntax
gcloud containers clusters create CLUSTER_NAME \
--region COMPUTE_REGION \
--node-locations COMPUTE_ZONE, COMPUTE_ZONE, [..]
#Regional Cluster
gcloud containers clusters create single-zone-cluster \
--region us-central1 \
--node-locations us-central1-a,us-central1-b, us-central1-c
与 region 相关的输入参数是指控制平面的位置。节点位置指的是工作节点的位置。对于多区域集群,这是必需的,因为节点位置可能分布在多个区域。
这就是基于集群可用性类型的 GKE 集群配置的简要概述。下一个主题将概述基于集群版本的 GKE 集群配置。
集群版本
GKE 允许你选择集群版本。集群版本可以是非常特定的版本、当前默认版本,或者基于发布渠道,发布渠道是基于早期可用性和稳定性的功能组合。这些集群版本配置将在以下子章节中讨论。
特定版本
可以通过指定特定版本来创建 GKE 集群。在从控制台创建集群时,这些信息可以作为静态版本选择的一部分提供给用户。用户将获得集群版本的选择,并可以选择一个可用的版本。
发布渠道
开源 Kubernetes 或 K8s 持续发布新版本。这些版本可能出于以下目的而需要:
-
修复已知问题
-
添加新功能
-
解决任何安全风险/问题
运行 Kubernetes 集群上应用程序的 Kubernetes 用户,更倾向于控制发布的频率或采用新功能的速度。Google 通过发布渠道的概念为客户提供这一选择。
每个发布渠道都提供普遍可用(GA)功能,但功能的成熟度会根据其最初发布的日期在不同渠道之间有所不同。此外,Google 还可以根据发布渠道的类型添加最新的 GKE 特定功能。这确保了某个特性或修复程序在一段时间内经过了验证,并确保其正确性和一致性。
GKE 提供三个发布渠道:
-
快速:与其他发布渠道相比,这个发布渠道包括最新的 Kubernetes 和 GKE 特性,但这些特性距离它们各自的开源 GA 版本发布仍有几周的时间。
-
常规:这是默认的发布渠道,包括 Kubernetes 和 GKE 特定的功能,这些功能相对较新,但稳定性较好。这些功能在快速发布渠道发布后至少已有 2-3 个月的历史,且距离开源 GA 版本发布已经有几个月。
-
稳定:这是最稳定的发布渠道,因为添加到此渠道的功能是在加入常规渠道后至少 2-3 个月添加的。实际上,这些功能经过充分验证和测试,以提供极致的稳定性。
以下是将集群注册到发布渠道的 CLI 命令:
#Syntax
gcloud containers clusters create CLUSTER_NAME \
--zone COMPUTE_ZONE \
--release-channel CHANNEL \
ADDITIONAL_FLAGS
# Release Channel Example
gcloud containers clusters create my-cluster \
--zone us-central1-a \
--release-channel rapid
总结一下,新版本的 Kubernetes 和 GKE 特性会从快速发布渠道、常规发布渠道到稳定发布渠道依次推广,提供用户在使用新特性和稳定特性之间的选择。一旦集群被加入到发布渠道,GKE 会处理版本的可用性和升级节奏。每个发布渠道都会继续接收关键的安全更新。
默认版本
如果没有指定特定的版本或发布渠道,则 GKE 会创建一个使用当前默认版本的集群。GKE 会根据使用情况和实际性能选择默认版本,并定期更改默认版本。历史上,Kubernetes 的新版本每三个月发布一次。
这完成了基于集群版本的 GKE 集群配置的简要概述。下一个主题将提供基于网络隔离选择的 GKE 集群配置概述。
网络隔离选择
有两个与网络隔离相关的特定选择——公有集群或私有集群。公有集群是默认配置。然而,这并不强制执行网络隔离,集群可以从任何公共端点访问。这使得集群在安全性方面存在漏洞。配置公有集群的缺点可以通过私有集群来解决,私有集群将在以下小节中介绍。
私有集群
GKE 提供了创建私有集群的选项,在该集群中,节点只有内部 IP 地址。这意味着节点和运行在节点上的 Pods 与互联网隔离,因此天然不会与公共互联网进行进出连接。
私有集群将拥有一个包含私有端点的控制平面,此外还有一个公共端点。可以通过多种选项来控制对公共端点的访问。此外,控制平面将在 Google 拥有的项目中的 VPC 网络中的虚拟机上运行。有关私有集群的详细信息将在 第九章,使用 GKE 安全构件保护集群 中进行深入讨论。
Kubernetes 功能——alpha 集群
Kubernetes 中的新功能通常通过发布渠道推广到 GKE。发布渠道包括快速、常规和稳定的选择。然而,alpha 功能仅在特殊的 GKE alpha 集群中提供。以下小节将讨论这一点。
Alpha 集群
Alpha 集群是 GKE 的一个特定功能,旨在用于采用那些尚未准备好投入生产或尚未普遍开放源代码的新功能。GKE 创建的 alpha 集群是短期存在的集群,并将在 30 天后自动删除。
以下是创建 alpha 集群的 CLI 命令:
#Syntax
gcloud container clusters create cluster-name \
--enable-kubernetes-alpha \
[--zone compute-zone] \
[--cluster-version version]
#Alpha Cluster Example
gcloud container clusters create my-cluster \
--enable-kubernetes-alpha \
--region us-central1
这些集群不会接收安全更新,不能自动升级或自动修复,且不受任何 GKE 特定的 SLA 保障。因此,永远不建议将 alpha 集群用于生产工作负载。
这完成了基于网络隔离选择的 GKE 集群配置的简要概述。这也结束了关于 GKE 集群配置的一般小节。下一个主题将详细介绍 GKE 中可能的自动扩展选项。
GKE 中的自动扩展
在 GKE 中有三种潜在的自动扩展选项。这些选项适用于特定的需求和场景:
-
集群自动扩展器:用于调整 GKE 集群中节点池大小的扩展选项
-
水平 Pod 自动扩展器(HPA):一个选项,用于根据当前利用率指示何时应自动扩展应用实例
-
垂直 Pod 自动缩放器 (VPA): 一种选项,根据当前利用率为 Pod 建议推荐资源。
接下来的话题详细说明了先前的自动缩放机制,从集群自动缩放器开始。
集群自动缩放器
集群自动缩放器是自动调整 GKE 集群中节点池大小的机制。缩放基于节点池内部署的工作负载的需求。这允许您实现云计算的核心概念,称为弹性,从而消除了过度或不足提供节点的需要。
集群自动缩放器基于节点池的基础工作,并基于资源请求(作为 Pod 规范的一部分定义)而非实际资源利用率。当需要部署新的 Pod 时,Kubernetes 调度器根据 Pod 的资源请求来寻找节点进行部署。如果没有节点满足 Pod 的资源需求以及可用容量,那么 Pod 将处于挂起状态,直到现有的 Pod 终止或者添加新节点。
集群自动缩放器会跟踪处于挂起状态的 Pod,并随后尝试增加节点的数量。同样,如果节点未充分利用,集群自动缩放器也会减少节点的数量。可以为集群自动缩放器定义最小或最大节点数,以使其在指定的限制内运行。
当集群缩小规模时,可能需要新的工作负载等待新节点的添加。这可能导致潜在的中断。GKE 配置文件类型提供了在平衡和激进缩小规模之间进行选择的选项:
-
平衡: 默认的配置选项,性质不激进。
-
优化利用率: 缩小比较激进,更快地移除未充分利用的节点。
以下是一些与集群自动缩放器相关的 CLI 命令:
# Create cluster with autoscaler limits
gcloud container clusters create my-autoscaler-cluster \
--zone us-central1-b \
--num-nodes 3 --enable-autoscaling --min-nodes 1 --max-nodes 5
# Update autoscaling profile to optimize-utilization
gcloud beta container clusters update my-autoscaler-cluster \
-autoscaling-profile optimize-utilization
在使用集群自动缩放器时需要考虑的一些限制如下:
-
在将 Pod 重新调度到不同节点之前,对原始节点进行强制终止之前会进行 10 分钟的优雅终止。
-
节点池缩放限制由区域可用性决定。如果集群跨越 4 个区域拥有 3 个节点(
min_nodes=1和max_nodes=5),那么如果其中 1 个区域失败,集群的大小可以从每个集群的 4-20 个节点变为 3-15 个节点。
这里结束了对集群自动缩放器的概述。下一个主题关注水平 Pod 自动缩放器 (HPA)。
水平 Pod 自动缩放器
HPA 是一个 Kubernetes 控制器对象,根据观察到的 CPU 或内存利用率自动调整复制控制器、Deployment、ReplicaSet 或 StatefulSet 中 Pod 的数量。HPA 指示需要对其进行缩放的 Deployment 或 StatefulSet。HPA 不适用于 DaemonSets。
要实现 HPA,需要考虑以下因素:
-
每个 Deployment 或 StatefulSet 需要定义一个 HPA 对象。
-
--horizontal-pod-autoscaler-sync-period属性允许您将 HPA 实现为控制循环。默认值为每周期 15 秒。 -
kube-controller-manager(按周期获取)从资源管理器 API 或自定义指标 API 获取指标,并将其与每个 HPA 定义中指定的指标进行比较。
以下是一些可以定义 HPA 配置的关键参数:
-
--horizontal-pod-autoscaler-initial-readiness-delay:一个可配置的窗口,确保 Pod 成功过渡到就绪状态。 -
--horizontal-pod-autoscaler-cpu-initialization-period:一个可配置的窗口,用于设置 Pod 转变为就绪状态后的 CPU 初始化时间。默认值为 5 分钟。 -
--horizontal-pod-autoscaler-downscale-stabilization:一个可配置的窗口,自动扩展器在当前扩展操作完成后需要等待多长时间才能启动缩减操作。默认值为 5 分钟。这样可以防止频繁波动。
以下是基于 CPU 利用率的 HPA 对象示例定义:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-nginx
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 75
在上述示例中,kube-controller-manager将根据 HPA 对象规范扩展 Deployment,如果目标 CPU 利用率超过 75%,最大可扩展至 5 个实例。这是 HPA 概述的总结,接下来的主题将重点讲解垂直 Pod 自动扩展器(VPA)。
垂直 Pod 自动扩展器(VPA)
集群自动扩展器基于工作负载的 CPU 和内存请求限制进行操作。如果这些限制没有适当定义,则始终存在过度配置或配置不足的风险,因为参考值将不准确。
VPA 是一个 Kubernetes 资源,推荐 CPU 和内存请求/限制的值。此外,如果 VPA 的updateMode属性设置为开启,VPA 还可以自动更新工作负载。这可能会驱逐现有 Pod,因为需要更改 Pod 的资源请求,并且会生成一个具有更新推荐值的新 Pod。
这确保了集群节点得到最佳利用,并可能不再需要运行基准测试来确定 CPU 和内存请求的正确值。VPA 与集群自动扩展器进行通信,以便在与节点池相关的节点上执行适当的操作。
以下是一个 VPA 对象的示例定义:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-nginx
updatePolicy:
updateMode: "On"
上述代码片段中的kind属性指示 Kubernetes 资源是 VPA 对象。updateMode属性指示 VPA 建议的推荐值会自动应用于正在运行的工作负载。
以下是一些特定于 VPA 的 CLI 命令:
# To view recommendations of VPA is updateMode was set to Off
kubectl get vpa my-vpa --output yaml
# To disable VPA
gcloud container clusters update my-cluster --no-enable-vertical-pod-autoscaling
如果配置了一个 HPA 对象来评估 CPU 或内存的指标,建议 HPA 不应与 VPA 一起使用。
多维 Pod 自动扩展(MPA)
这是一个新的自动扩展选项,目前处于预 GA 阶段。根据该选项,可以配置自动扩展以基于 CPU 进行横向扩展,并同时基于内存进行纵向扩展。MPA 支持 1.19.4-gke.1700 或更高版本的集群。
这一部分总结了 GKE 中的自动扩展,详细介绍了多种机制。接下来的部分将重点介绍与 GKE 相关的网络构建。将涵盖有关 Pod 网络、服务网络的详细信息,并深入探讨使用 GKE 负载均衡器来暴露服务以供外部使用。
GKE 中的网络
应用程序作为容器部署在 Kubernetes 中。Pods 运行容器。Pods 的期望状态由 Deployments 控制,应用程序通过 Services 暴露供内部和外部网络使用。已部署的 pods 在 GKE 的节点上运行。GKE 中的节点由虚拟机或 VM 表示。这些节点部署在虚拟私有云(VPC)中。
VPC 定义了一个虚拟网络拓扑,类似于传统网络。它是一个逻辑隔离的网络,并提供已部署资源之间的连接。VPC 还提供了启动资源、选择 RFC 1918 地址范围、创建子网等方面的完全控制。
GCP 中的 VPC 为每个 GCP 区域预分配了一个 IP 子网。当在 VPC 中部署 GKE 集群时,可以选择特定的区域或区域。在 GKE 节点由计算引擎虚拟机(VM)组成且这些虚拟机需要 IP 地址时,IP 地址范围将从分配给区域的 IP 子网中分配。GCP 中的 VPC 被视为全球资源,因为单一的 Google Cloud VPC 可以跨多个区域而无需通过公共互联网进行通信。并不要求在每个区域都建立连接。
GCP 提供了配置别名 IP 范围的选项。这使得虚拟机可以拥有额外的二级 IP 地址。因此,虚拟机可以在独立的 IP 地址上运行多个服务。这些二级 IP 地址可以在 VPC 内进行路由,而无需配置额外的路由。
GKE 集群可能需要运行集群范围的服务。GCP 建议将 GKE 集群部署为VPC 原生集群。VPC 原生集群使用三个独特的子网 IP 地址范围:
-
用于节点 IP 地址的子网主 IP 地址范围
-
所有 Pod IP 地址的二级 IP 地址范围
-
用于所有服务 IP 地址的附加二级 IP 地址范围
GKE 提供了灵活性,允许配置集群中节点的数量和每个节点的最大 pod 数。接下来的话题详细介绍了当 pods 在 GKE 集群中部署时,如何为 pod 分配 IP 地址。
Pod 网络
当 Pod 被调度到某个节点时,Kubernetes 会在该节点的 Linux 内核中为 Pod 创建一个网络命名空间,并通过虚拟网络接口将该节点的物理网络接口连接到 Pod,从而允许同一节点内的 Pod 之间进行通信。
Kubernetes 会将一个 IP 地址(即 Pod 的 IP 地址)分配给 Pod 的网络命名空间中的虚拟网络接口,这些 IP 地址来自为节点上的 Pod 保留的地址范围。此地址范围是集群为 Pod 分配的 IP 地址范围的一个子集,创建集群时可以配置此范围。
GKE 会自动配置 VPC 以识别这一 IP 地址范围为授权的次级子网地址范围。因此,Pod 的流量可以通过网络上的防伪过滤器。同时,由于每个节点为其 Pod 保持独立的 IP 地址库,节点不需要对 Pod 的 IP 地址进行网络地址转换。下一个主题将详细讲解服务网络,特别是如何通过使用 GKE 负载均衡器有效地接收来自外部源的流量。
服务网络
服务是一个 Kubernetes 资源,它创建一个名为端点的动态 IP 地址集合。这些 IP 地址属于与服务标签选择器匹配的 Pod。Kubernetes 通过分配一个静态虚拟 IP 地址来创建服务,这个 IP 地址从集群为服务保留的 IP 地址池中分配。
在可用的服务类型中,LoadBalancer 服务类型通过 GCP 的 LoadBalancer 在 GKE 中实现,该负载均衡器是在 GKE 集群内创建的。随后,GCP 会分配一个静态的 LoadBalancer IP 地址,该地址可以从集群外部以及项目中访问。
对于发送到 GCP NLB 的流量,图 8.17 展示了 NLB 与 GKE 集群内节点之间的交互。这些交互按步骤列出如下:

图 8.17 – NLB 与 GKE 集群在 VPC 中的交互
逐步交互:
-
NLB 会从集群中随机选择一个节点并转发流量(例如根据 图 8.17,选择 Node 2)。
-
服务可能会绑定到多个分布在集群节点上的 Pod。节点上的
kube-proxy服务接收客户端请求,并会随机选择一个匹配该服务的 Pod。所选的 Pod 可能在同一节点或不同节点上。 -
如果选择的 Pod 位于不同的节点(例如 Pod 8),则客户端请求将从原节点(Node 2)发送到其他节点(Node 4)。响应将返回到接收请求的原节点(Node 2),然后再返回给客户端。
前面的过程提供了一种通过外部客户端访问服务的方式,并保持与 Pod 使用的平衡。然而,在 Kubernetes 集群中,响应可能需要经过多个节点,因为请求从一个节点被引导到另一个节点,这就可能导致双重跳跃问题。
为了避免externalTrafficPolicy。如果设置为本地,kube-proxy 将选择本地节点上的一个 Pod(无论是Pod 3还是Pod 4),并且不会将客户端请求转发到另一个节点。然而,这会导致负载不平衡,用户必须在更好的负载均衡和低延迟通信之间做出选择。GKE 通过使用容器原生负载均衡的概念解决了这个问题。
容器原生负载均衡
容器原生负载均衡的核心思想是,流量不再被引导到节点,而是直接发送到 Pod,从而避免了额外的跳跃。连接直接在负载均衡器与 Pods 之间建立。GKE 通过利用 GCP HTTP(S) Load Balancing 和称为 Network Endpoint Group(NEG)的数据模型实现这一点。GKE 需要在 VPC 原生模式下运行,才能使用容器原生负载均衡功能。
NEG 是一组表示 IP 到端口对的网络端点。因此,负载均衡流量不再使用节点 IP,而是使用 Pod IP 和端口的组合作为元组。此信息在 NEG 中进行维护。图 8.18 展示了 GKE 容器原生负载均衡与 GKE 节点中的 Pods 之间的交互,通过 NEG 实现。如 图 8.18 所示,发往容器原生负载均衡器的请求会转发到 NEG,NEG 根据请求选择特定的 Pod,并直接将流量转发到与 Pod 关联的节点,实现单跳转发,从而避免了双重跳跃问题:

图 8.18 – 使用容器原生负载均衡解决双重跳跃问题
除了建立与 Pod 的直接连接外,容器原生负载均衡还允许直接查看 Pod,从而实现准确的健康检查。源 IP 地址得以保留,从而可以获得客户端与负载均衡器之间的往返时间信息。
本文总结了 GKE 特定的网络构造的高级概述。下一节将总结 GKE 中容器化应用可用的存储选项。
GKE 的存储选项
Kubernetes 提供了以卷(Volumes)和持久卷(Persistent Volumes)形式的存储抽象。这些被用作存储选项,提供直接可供在 Kubernetes 集群中运行的应用程序访问的文件系统容量。持久卷的存在超出了容器的生命周期,且可以进一步作为耐久性文件存储或数据库后端存储使用。
在 GKE 中,Compute Engine 持久磁盘用作持久卷。GKE 还提供了各种托管后端存储服务,如 Cloud SQL、Cloud Datastore 等,这样就不需要在 GKE 集群内运行数据库应用程序,而是将 GKE 集群中的应用程序连接到托管的数据存储。例如,GKE 集群中的前端应用程序可以连接到 Cloud SQL,而不是将前端应用程序连接到运行 MySQL 服务器的其他应用程序。更具体地说,前端应用程序可以通过 Cloud SQL 代理连接到 Cloud SQL 以满足数据库需求。该代理可以作为一个 side-car 容器运行在前端应用程序的 Pod 内。
这抽象了基础设施需求并减少了维护,让您可以专注于应用程序。GCP 提供了跨关系型、非关系型和缓存服务的托管服务,供在 GKE 集群中运行的应用程序连接。
除了可能需要后端数据存储的应用程序外,GKE 集群中可能还会有需要对象存储的应用程序。Google Cloud Storage(GCS)是一个对象存储服务。对象存储指的是存储一组有序字节的方式,其中这些字节的结构和语义并不重要。它可用于各种应用程序,例如以下几种:
-
为网站提供图像服务
-
流式传输音乐、视频和媒体托管
-
为分析和机器学习工作负载构建数据湖
GKE 集群中的应用程序可以通过 Cloud Storage API 访问 Cloud Storage。这是 GCP 中为部署在 GKE 中的应用程序提供的存储选项的总结。接下来的部分总结了从 GKE 角度出发的云操作细节。
GKE 的 Cloud 操作
Google Kubernetes Engine(GKE)提供与 Google Cloud 操作的本地集成——一套工具,允许您监控工作负载、收集应用程序日志、捕获指标并在关键指标上提供警报或通知选项。Cloud 操作及其相关服务套件将在第十章《探索 GCP 云操作》中详细阐述。
GKE 的 Cloud 操作在创建集群时默认启用。然而,用户可以选择在 GKE 集群配置中禁用 Cloud Monitoring 或 Cloud Logging。GKE 的 Cloud 操作监控 GKE 集群并提供一个量身定制的开箱即用仪表板,包含以下功能:
-
查看按基础设施、工作负载或服务分类的集群资源
-
检查命名空间、节点、工作负载、服务、Pod 和容器
-
查看 Pod 和容器的应用日志
-
查看与集群相关的关键指标,例如 CPU 利用率、内存利用率等
日志记录和监控是可靠运行 GKE 集群中的服务或应用程序的两个关键方面。这些内容将在后续的 Cloud Operations 相关主题中进行详细介绍。
GKE 日志记录
GKE 部署应用程序并在集群内协调多个操作或事件。这会产生各种日志,如应用日志、系统日志、事件日志等。日志提供了对各种操作的可见性,也被认为是一种被动的监控方式。
查看 GKE 集群日志有两种方式:
-
Kubernetes 原生日志
-
GKE Cloud Logging
Kubernetes 原生日志
Kubernetes 支持将日志原生输出到标准输出和标准错误流。在 Kubernetes 中,容器引擎 可以将容器的标准输入/输出和标准错误流重定向到日志驱动程序。该驱动程序被配置为将容器日志以 JSON 格式写入并存储在节点级别的 /var/log 目录中。这包括来自容器的日志和来自节点控制平面组件(如 kubelet 和 kube-proxy)的日志。这些日志可以通过 kubectl logs 命令检索。
kubectl logs 命令可用于检索 Pod 或 Pod 中特定容器的日志。该命令还提供了检索特定时间段日志的选项,或者你可以使用 tail 选项检索日志的某一部分。以下是一些示例:
# Stdout container logs; pod has a single container
kubectl logs <pod-name>
# Stdout container logs; pod has multiple containers
kubectl logs <pod-name> -c <container-name>
# Stdout container logs – most recent 50 lines
kubectl logs --tail=50 <pod-name>
# Stdout most recent container logs in the last 1 hour
kubectl logs --since=1h <pod-name>
# Stream pod logs
kubectl logs -f <pod-name>
Kubernetes 原生日志可能导致节点饱和,因为日志文件会持续增长,最终占满节点存储目录的空间。GKE 通过运行 Linux 日志轮转工具来清理日志文件,从某种程度上解决了这一问题。任何超过一天或者大小超过 100 MB 的日志文件会被自动压缩并复制到归档文件中。
GKE 只会在节点上存储最近的五个归档日志文件,并会删除之前的归档日志文件。尽管这样可以确保节点在磁盘空间方面不至于饱和,但如果需要分析或研究旧的应用日志,仍然会带来一定问题。
默认情况下,开源 Kubernetes 或 K8s 会在删除容器或与容器相关联的 Pod 被删除时删除相关日志。GKE 解决了与节点饱和相关的问题,并通过将日志流式传输到 Cloud Logging,为分析与已删除 Pods/Containers 相关的日志提供了能力,作为 Cloud Operations 的一部分。应用日志、系统日志和日志事件可以被流式传输到 Cloud Logging,相关内容将在后续章节中讨论。
GKE Cloud Logging
开源 Kubernetes 或 K8s 并未提供集群级别日志存储解决方案。GKE 通过将日志事件流式传输到 Cloud Logging 来处理此问题。Cloud Logging 是一个集中式日志管理工具,且为完全托管的服务。Cloud Logging 可以自动扩展,且每秒可摄取数 TB 的日志数据。
GKE 使用 FluentD 日志代理将日志流式传输到 Cloud Logging。FluentD 代理作为 DaemonSet 实现,因为它需要在集群中的每个节点上运行。
日志代理已预安装在每个节点上作为 DaemonSet,并预配置为将日志数据推送到 Cloud Logging。FluentD 收集来自节点的容器日志和系统日志。FluentD 汇总日志,附加额外的元数据,并将其推送到 Cloud Logging。
图 8.19 说明了通过集群中每个节点上的 FluentD DaemonSet Pod 将日志从 GKE 发送到 Cloud Logging 的交互过程:

图 8.19 – FluentD 代理捕获日志并发送到 Cloud Logging
事件日志也会流式传输到 Cloud Logging。事件日志指的是集群中发生的操作日志,如 Pod 的创建/删除、部署的扩展等。事件作为 API 对象存储在 Kubernetes 主控或控制平面上。GKE 在集群主控中使用事件导出器来捕获事件,并自动将它们推送到 Cloud Logging。
Cloud Logging 提供了从流式日志中捕获指标并根据需要创建告警策略的能力。集群操作(如自动扩展)可以根据自定义指标进行配置。默认情况下,与集群相关的 GKE 特定日志会在 Cloud Logging 中保存 30 天。对于更长时间的保留,Cloud Logging 提供了通过日志接收器将日志导出到 Cloud Storage 或 BigQuery 的选项。第十章, 深入探索 GCP Cloud Operations,详细阐述了与 Cloud Logging 相关的主题。
GKE 监控
监控提供了有关应用程序或服务功能的见解,基于与 GKE 集群相关的关键内部指标。此外,监控还从用户的角度提供见解,基于用户与服务的互动。前几章关于站点可靠性工程的内容(第一章, DevOps、SRE 和 Google Cloud 服务用于 CI/CD,以及 第四章, 建立 SRE 团队和应用文化实践)明确指出服务可靠性是关键方面之一。监控是确保服务可靠运行的基础输入。
监控提供了对决策至关重要的数据,帮助你做出有关应用程序的决策。这些数据还可以进一步用于解决正在进行的事件并执行无责后分析,你还可以使用它进一步改进现有的测试套件,并为产品和开发团队提供改进或微调的建议。
云监控是谷歌提供的托管解决方案,它使用关键参数(如延迟、吞吐量等)来监控服务状态,并识别性能瓶颈。从 GKE 的角度来看,监控可以分为两个领域:
-
kube-apiserver、etcd和其他基础设施元素。 -
Pod 级监控:这包括使用容器特定的指标监控资源、跟踪特定部署的系统指标、跟踪实例、监控正常运行时间检查以及监控由应用程序开发者设计的应用程序特定指标。
Kubernetes 使用标签的概念来对资源进行分组或跟踪。这个概念可以扩展,资源可以通过标签在云监控中进行筛选。云监控提供了跟踪所有相关指标并将其展示在定制仪表板上的方式,从而实现对 GKE 集群的可视化。图 8.20 展示了来自云监控的内置 GKE 仪表板(以折叠模式显示的选项)。GKE 仪表板总结了有关集群、命名空间、节点、工作负载、Kubernetes 服务、Pods 和容器的信息:

图 8.20 – 来自云监控的内置 GKE 仪表板
这部分内容涵盖了 GKE 的云操作,并结束了关于 GKE 的部分,其中详细讨论了许多关键概念和核心功能。接下来的部分将详细介绍 GKE 中的最新操作模式 —— 自动驾驶模式。
GKE 自动驾驶 – 动手实验
GKE 自动驾驶或自动驾驶模式是 GKE 支持的两种操作模式之一。另一种模式是标准模式(在本章开头有详细说明)。自动驾驶模式消除了在集群创建过程中执行 DIY(自助)操作的需求,取而代之的是根据行业标准的网络和安全建议创建集群。此外,自动驾驶模式还消除了配置节点池或预估集群大小的需求。节点会根据已部署工作负载的类型自动配置,用户基本上是根据运行中的工作负载来收费。
自动驾驶模式不仅是托管的,而且是 GKE 提供的无服务器 K8s 解决方案。然而,自动驾驶模式并未提供标准模式下的所有集群配置选项。下表展示了自动驾驶模式与标准模式在配置选项方面的对比:

以下是创建 GKE 集群的逐步指南,采用自动驾驶模式:
-
访问 GCP 控制台并选择计算服务 – Kubernetes 引擎。
-
选择创建集群的选项,并选择 自动驾驶 模式。请参见 图 8.21:
![图 8.21 – 在集群创建期间选择自动驾驶模式]()
图 8.21 – 在集群创建期间选择自动驾驶模式
-
输入集群名称为
my-autopilot-cluster。其余选项保持默认选择,并选择创建操作。参见图 8.22:![图 8.22 – 在自动驾驶模式下创建集群]()
图 8.22 – 在自动驾驶模式下创建集群
-
这将启动集群创建过程,但以自动驾驶模式进行。一旦集群创建完成,该集群将在集群列表页面上列出,如图 8.23所示:

图 8.23 – 在自动驾驶模式下创建的新集群
以下是从新创建的自动驾驶集群中观察到的一些情况。这些观察结果将自动驾驶集群与标准模式集群区分开来:
-
自动驾驶集群创建时不会预先分配任何节点。
-
自动驾驶集群始终作为区域集群创建。
-
自动驾驶集群的发布通道是常规通道。
-
默认情况下启用了节点自动配置和垂直 Pod 自动扩展。
-
默认情况下启用了高级网络选项,如节点间可见性、NodeLocal DNSCache 和 HTTP 负载均衡。
-
安全选项,如工作负载身份和受保护的 GKE 节点,默认启用。这些安全选项在第九章《使用 GKE 安全结构保护集群》中有讨论。
一旦在自动驾驶模式下创建了集群,工作负载可以以与在标准模式下部署工作负载完全相同的方式部署到自动驾驶集群中。图 8.24指的是在自动驾驶集群上创建的部署:

图 8.24 – 自动驾驶集群中的部署细节
运行工作负载所需的资源被分配给自动驾驶集群。图 8.25显示了分配给my-autopilot-cluster的资源。在这个特定的案例中,分配了 0.5 vCPU 和 2 GB 内存来运行一个 Pod。因此,用户只需为这个工作负载付费:

图 8.25 – 部署工作负载后自动驾驶集群的资源分配
本实验完成了与 GKE 自动驾驶相关的实践内容。本实验提供了关于自动驾驶配置的见解,以及工作负载部署后如何将资源分配给集群。这也标志着本章的结束。
总结
由于开源 Kubernetes 或 K8s 涉及大量的设置和维护,我们深入研究了 Google Kubernetes Engine(GKE),这是 Google Cloud Platform(GCP)的一项计算服务,专门用于运行容器化应用。第七章 中学到的 Kubernetes 基础知识——理解 Kubernetes 基础以部署容器化应用——同样适用于 GKE。我们还探索了 GKE 的核心特性,如 GKE 节点池、GKE 集群配置、自动缩放以及 GKE 与其他 GCP 服务在网络和操作方面的集成。下一章将重点介绍与 Google Kubernetes Engine 相关的安全特性,目的是加强集群的安全性。
记住要点
以下是一些重要的记住要点:
-
GKE 是完全托管的,使用优化的容器操作系统,并支持自动缩放、节点自动修复和自动升级。
-
GKE 支持两种操作模式——标准模式和自动驾驶模式。
-
GKE 标准模式支持 VPC 原生流量路由和 HTTP 负载均衡作为默认选项。
-
GKE 的云操作默认启用。
-
私有 Kubernetes 引擎集群无法公开访问。
-
节点池代表具有相同配置的节点组。
-
默认情况下,新的节点池运行最新的 Kubernetes 版本,可以配置为自动升级,也可以手动升级。
-
区域集群或多区域集群中的节点池会复制到多个区域。
-
多区域集群将仅有一个控制平面副本。
-
区域集群在多个区域中运行多个控制平面副本。
-
发布渠道用于修复已知问题、添加新功能或解决安全风险和关注点。
-
如果没有指定特定版本或发布渠道,GKE 会使用默认版本创建集群。
-
Alpha 功能仅在特定的 GKE alpha 集群中可用,不能作为发布渠道的一部分使用。
-
GKE 中的自动缩放选项包括集群自动缩放器、HPA、VPA 和 MPA(预发布阶段)。
-
集群自动缩放器会自动调整 GKE 集群中节点池的大小。
-
HPA 根据当前的资源利用情况指示何时应该扩展应用实例。
-
HPA 不支持 DaemonSets。
-
VPA 根据当前的资源利用情况建议 Pod 的推荐资源配置。
-
如果
updateMode属性设置为 On,VPA 可以自动更新工作负载。 -
MPA 允许同时基于 CPU 水平扩展和基于内存垂直扩展。这是预发布功能。
-
自动缩放器提供两种缩小的配置选项:平衡型和优化利用率型。
-
Kubernetes 的原生选项避免双跳的方法是将
externalTrafficPolicy设置为local。 -
GKE 使用 GCP HTTP(S) 负载均衡器和 NEG 避免双跳。
-
NEG 是一组网络端点,表示 IP 与端口的配对。
-
GKE 运行 Linux 的日志旋转工具来清理日志文件。任何超过一天或超过 100MB 的日志文件将自动压缩并复制到归档文件中。
-
GKE 只在节点上存储最近归档的五个日志文件,并会删除之前归档的日志文件。
-
GKE 通过使用 FluentD 日志代理将流式数据传输到 Cloud Logging。
-
事件日志是指来自集群上发生的操作的日志。
-
事件作为 API 对象存储在集群主节点上。GKE 使用事件导出器将事件推送到 Cloud Logging。
-
GKE 特定的集群日志在 Cloud Logging 中保留 30 天。
-
对于较长时间的日志保存,Cloud Logging 可以通过日志接收器导出日志。
-
GKE 自动驾驶模式支持以下集群配置:可用性类型为区域性,版本为发布渠道,网络隔离为私有或公共,Kubernetes 功能为生产。
进一步阅读
有关 GCP 在 DevOps 方面的更多信息,请阅读以下文章:
-
Kubernetes:
kubernetes.io/docs/home/ -
Google Kubernetes Engine:
cloud.google.com/kubernetes-engine
练习测试
回答以下问题:
-
如何在 GKE 中创建控制平面组件?
a) 创建工作节点,然后在工作节点上创建控制平面组件。
b) GKE 集群不要求创建控制平面组件。
c) 在名为
master的节点组上创建控制平面组件,工作节点放在名为worker的节点组中。d) 控制平面组件由 GKE 自动创建并由 GKE 代表用户管理。
-
Pod
p1包含三个容器——c1、c2和c3。用户希望查看容器c2的日志。请选择表示适当 CLI 命令的选项来查看日志:a)
kubectl logs -p p1 -c c2b)
kubectl logs p1 -c c2c)
kubectl logs pod=p1 container=c2d)
kubectl logs p1 container=c2 -
公司Alpha即将推出一款无状态的 Web 应用程序,提供全新的电子商务服务。该 Web 应用程序将有稳定的流量,并在宣布特别优惠时出现高峰流量。请选择适合此情况的集群设计选项:
a) 部署一个标准集群,并使用带有 HPA 的 Deployment。
b) 部署一个带有自动扩展的集群,并使用带有 HPA 的 Deployment。
c) 部署一个标准集群,并使用带有 VPA 的 Deployment。
d) 部署一个带有自动扩展的集群,并使用带有 VPA 的 Deployment。
-
选择一个能够承受 GCP 区域丢失的集群配置:
a) 创建一个区域性集群。
b) 创建一个 Redis 集群,用于缓存集群资源所在区域的资源信息。
c) 在不同区域创建两个集群,并在它们之间创建负载均衡器。
d) 以上都不是。
-
选择可以使用 Docker 镜像的 Google Cloud 服务,私有 GKE 集群可以使用:
a) Cloud Source Repositories
b) 容器注册表
c) Cloud Build
d) 以上全部
-
选择每个区域允许的最大集群数:
a) 25
b) 50
c) 100
d) 无限
-
选择获取与名为
my-cluster的集群交互的身份验证凭据的命令:a)
gcloud containers clusters get-credentials my-clusterb)
gcloud container clusters get-credentials my-clusterc)
gcloud container cluster get-credentials my-clusterd)
gcloud containers cluster get-credentials my-cluster -
选择可以检索集群中 Pod 的命令:
a)
gcloud get podsb)
kubectl list podsc)
gcloud list podsd)
kubectl get pods -
公司 Real World 决定使用第三方监控解决方案来监控部署在 GKE 集群中的应用程序。选择部署第三方监控解决方案的最佳方法:
a) 无法在 GKE 中使用第三方监控解决方案。
b) 从 Cloud Marketplace 下载监控解决方案。
c) 将监控解决方案部署为 Pod,作为 DaemonSet。
d) 将监控解决方案部署为 Pod,作为 ReplicaSet。
-
Google Cloud 上的 VPC 是:
a) 区域资源
b) 全球资源
c) 区域资源
d) 多区域资源
-
在 GKE 中名为 my-app 的应用程序需要访问一个托管的 MySQL 数据库。请选择最合适的选项:
a) 在集群中将 MySQL 作为应用程序运行。my-app 应用程序将通过 ClusterIP 服务连接到 MySQL 应用程序。
b) 使用 Cloud SQL 运行 MySQL 数据库。将 Cloud SQL 代理作为应用程序 Pod 内的边车容器运行。
c) 在集群中将 MySQL 作为应用程序运行。my-app 应用程序将通过
LoadBalancer服务连接到 MySQL 应用程序。d) 使用 Cloud SQL 运行 MySQL 数据库。将 Cloud SQL 代理作为 ClusterIP 服务运行。
-
Google 网络负载均衡分配以下流量:
a) TCP
b) UDP
c) TCP 或 UDP
d) 以上皆非
-
从可用性角度来看,Autopilot 模式下创建的集群是:
a) 区域
b) 多区域
c) 区域
d) 区域和区域
-
选择一个在 GKE 中不受支持的发布通道:
a) 常规
b) Alpha
c) 快速
d) 稳定
-
选择基于网络隔离的可能集群配置:
a) 标准和私有
b) 标准和公共
c) 标准和默认
d) 私有和公共
答案
-
(d) – 控制平面组件,如
kube-api服务器、调度器等,构成集群主控,并由 GKE 设置和管理。 -
(b) –
kubectl logs p1 -c c2 -
(b) – 创建一个具有自动扩展的集群,并使用带 HPA 的 Deployment。
-
(a) – 创建一个区域集群,因为工作负载分布在一个区域内的多个区域中。
-
(b) – 容器注册表
-
(b) – 50
-
(b) -
gcloud container clusters get-credentials my-cluster -
(d) -
kubectl get pods -
(c) - 将监控解决方案部署为 Pod,作为 DaemonSet。
-
(b) – 全球资源
-
(c)
-
(c) – TCP 或 UDP
-
(c) – 区域
-
(b) – Alpha
-
(d) – 私有和公共
第九章:使用 GKE 安全构造保护集群
Kubernetes(或 K8s)是一个开源的容器编排系统,用于运行容器化应用程序,但它需要大量的工作来设置和维护。Google Kubernetes Engine(GKE)是 K8s 的增强版本,具有托管性质,将主控组件从用户中抽象出来,提供自动升级功能,并支持如 DNS、日志记录和监控仪表板等内建功能,而不是将这些功能作为外部插件进行维护。Kubernetes 包含许多关键概念、术语和对象。最后两章(第七章,理解 Kubernetes 基本知识以部署容器化应用,和 第八章,理解 GKE 基本知识以部署容器化应用)专注于原生 Kubernetes 的功能,如集群结构,详细讲解了 Kubernetes 的关键对象,并讨论了应用程序如何在集群中调度。此外,还扩展了对特定 GKE 功能的学习,例如节点池、集群配置、自动扩展工作负载的选项,并理解 GKE 如何与其他 GCP 服务交互。
本章特别专注于理解 Kubernetes 中的基本安全构造及其应用,然后是 GKE 中的特定安全功能,这些功能对于加固集群的安全性至关重要。这里的关键是使用 GKE 特定的功能来保护运行在集群中的应用程序。
本章将涵盖以下主题:
-
Kubernetes 中的基本安全模式:本节深入探讨了原生 Kubernetes 中的基本安全构造,如身份验证、授权、控制平面安全性和 Pod 安全性。我们还将查看每个安全构造及其在 GKE 中的实现。
-
加固集群安全性:本节深入探讨了 GKE 特定的安全功能,这些功能为在 GKE 集群中运行的应用程序提供了安全选项。包括私有集群、二进制授权、容器优化操作系统等功能。
技术要求
本章有两个主要的技术要求:
-
一个有效的Google Cloud Platform(GCP)账户,以便实际操作 GCP 服务:
cloud.google.com/free -
安装 Google Cloud SDK:
cloud.google.com/sdk/docs/quickstart
Kubernetes 中的基本安全模式
一个 Kubernetes 集群可以运行多种类型的工作负载。这包括有状态应用程序、无状态应用程序、作业和 DaemonSets。然而,保护这些工作负载免受潜在安全攻击是至关重要的。原生 Kubernetes 提供了一些基本的安全构建模块,专注于基础内容,包括请求发送到集群的方式以及如何对请求进行身份验证和授权。此外,了解如何确保主控平面组件的安全,以及如何确保运行应用程序的 Pod 也能得到保护是非常重要的。我们将从原生 Kubernetes 的角度探讨这些内容,但在 GKE 中的实现也会进行讨论。我们将深入探讨的第一个安全构建模块是身份验证。
身份验证
身份验证 是确定用户身份的过程。它本质上确认用户是否如其所说的那样,并且在身份验证成功后,最终会提供对合格资源的访问权限。
Kubernetes 支持两种类别的身份验证或用户:
-
用户账户
-
Kubernetes 服务账户
让我们详细看一下这些。
用户账户
默认情况下,Kubernetes 没有任何支持普通用户账户的对象。因此,这些账户不能通过 API 调用创建。在 Kubernetes 中,普通或常规用户可以通过以下方式创建:
-
由管理员分发私钥
-
使用包含用户名及其关联密码列表的文件
-
通过外部身份服务提供商
在 GKE 的情况下,普通的 用户账户 可以由 Cloud IAM 用户提供。这些用户账户被称为成员。成员也可以作为 G Suite 域或 Cloud Identity 域的一部分进行定义。也可以通过 Google Cloud Directory Sync 将成员或用户链接到现有的活动目录,从而将其添加到 Cloud IAM。除了 Cloud IAM 用户外,GCP 服务账户也被视为成员,类似于用户。这些与 Kubernetes 服务账户不同。
GCP 服务账户 由 Google Cloud IAM 管理,专门用于当 GCP 资源需要与应用程序或虚拟机绑定身份,而非人类时。与此不同,Kubernetes 服务账户为运行在 Pod 内的进程提供身份,并提供对集群的访问权限。
Kubernetes 服务账户
Kubernetes 服务账户是由 Kubernetes API 管理的用户。这意味着与常规用户账户不同,服务账户可以通过 API 调用进行创建和管理。事实上,Kubernetes 中的每个命名空间都有一个默认的 Kubernetes 服务账户。这些账户由 API 服务器自动创建。服务账户接纳控制器将创建的服务账户与运行的 Pod 关联。实际上,服务账户作为秘密存储,并在 Pod 创建时挂载到 Pod 上。这些秘密由运行在 Pod 内部的过程使用,用于访问集群内的 API 服务器。
此外,Kubernetes 服务账户用于为需要与 Kubernetes API 通信的长期运行的任务创建身份,例如运行 Jenkins 服务器。您可以使用以下 CLI 命令创建 Kubernetes 服务账户:
# Create kubernetes service account
kubectl create serviceaccount jenkins
上述命令会创建一个 serviceaccount 对象,为服务账户生成一个令牌,并创建一个秘密对象来存储该令牌。可以使用以下 CLI 命令检索包含令牌的秘密:
# Get the definition of the service account
kubectl get serviceaccounts jenkins -o yaml
上述命令将产生以下输出:
apiVersion: v1
kind: ServiceAccount
metadata:
# ...
secrets:
- name: jenkins-token-78abcd
在秘密部分显示的秘密将包含 API 服务器的公共 证书颁发机构(CA – 一个颁发数字证书的实体)、特定的命名空间和一个签名的 JSON Web 令牌(JWT)。该签名的 JWT 可以用作持有账户来验证提供的服务账户。这个服务账户最终可以用于集群内通信,甚至用于从集群外部进行身份验证,例如在 Jenkins 服务器的情况下。
每个对 Kubernetes 的请求在被处理之前需要经过身份验证。传入请求由 kube-api 服务器处理,它通过监听端口 443 并使用 HTTPS 协议进行身份验证。身份验证可以通过多种方式完成。GKE 支持以下身份验证方法:
-
OpenID Connect 令牌
-
x509 客户端证书
-
使用静态密码的基本身份验证
OpenID Connect 是建立在 OAuth 2.0 协议之上的一层,它允许客户端通过查询授权服务器来验证最终用户的身份。x509 客户端证书和静态密码相比 OpenID,呈现了更大的攻击面。在 GKE 中,默认情况下禁用了 x509 和静态密码身份验证,特别是在 Kubernetes 1.12 及更高版本创建的集群中。这有助于提高默认安全态势,因为在发生攻击时,影响的范围大大减少或降低。
这完成了关于 Kubernetes 中身份验证的主题。下一个主题将介绍 Kubernetes 中的授权。
授权
授权是确定用户是否有权限访问特定资源或执行特定功能的过程。在 Kubernetes 中,用户必须先进行身份验证或登录,并获得授权才能访问或使用特定资源。通常建议作为安全最佳实践,执行最小权限原则,因为这确保用户仅根据访问要求拥有访问资源所需的最低权限。
特定于 GKE,用户通过 Cloud Identity 进行身份验证后,可以使用两种方法进行授权。实际上,GKE 推荐同时使用这两种方法来授权访问特定资源:
-
Cloud 身份与访问管理 (IAM)
-
Kubernetes 基于角色的访问控制 (RBAC)
Cloud IAM 是用于管理 GCP 资源的访问控制系统。Google 账户、服务账户和 Google 群组是 Cloud IAM 中具有身份的实体。Cloud IAM 允许用户在项目级别(例如列出项目中的所有 GKE 集群)或集群级别(例如查看集群)执行操作,但主要是在集群外部进行操作。这包括向现有集群或新集群添加特定的 GKE 安全配置选项。然而,Kubernetes RBAC 提供了对集群内部的访问,甚至可以细化到命名空间级别。RBAC 允许您微调规则,以便为集群内的资源提供精细化的访问控制。
总结一下,Cloud IAM 定义了谁可以查看或更改 GKE 集群的配置,而 Kubernetes RBAC 定义了谁可以查看或更改特定 GKE 集群内的 Kubernetes 对象。GKE 将 Cloud IAM 和 Kubernetes RBAC 集成在一起,根据用户是否拥有必要的权限来授权用户在资源上执行操作。现在,让我们从通过 Cloud IAM 授权 GKE 开始,了解这两种授权方法。
通过 Cloud IAM 授权 GKE
Cloud IAM 访问控制由三个主要元素组成,具体如下:
-
谁:指的是身份验证;具体来说,是发出请求的成员的身份。
-
什么:指的是授权;具体来说,是授权请求所需的权限集。权限不能直接分配给成员;而是通过一组权限组成角色,然后将角色分配给成员。
-
哪个:指的是请求已通过身份验证和授权可以访问的资源。在 GKE 中,这指的是 GKE 资源,如集群或集群内部的对象。
GKE 提供了多个预定义的 Cloud IAM 角色,这些角色为 Kubernetes 引擎资源提供细粒度访问权限。下表总结了授权或执行 GKE 操作所需的关键预定义 IAM 角色:

你始终可以使用自定义角色并指定最小所需的权限集。这在 GKE 预定义角色权限过于宽松或不适合当前用例时尤为重要,以确保符合最小权限原则。
接下来,我们将了解 Kubernetes RBAC。
Kubernetes RBAC
Kubernetes RBAC 是一种授权机制,可以基于分配给个别用户的角色限制对特定资源的访问。RBAC 是 Kubernetes 的本地安全功能,提供了管理用户帐户权限的选项。Kubernetes RBAC 可以作为 Cloud IAM 的补充。如果 Cloud IAM 可以定义操作集群及集群内 API 对象的角色,则可以使用 RBAC 来定义对集群内特定 API 对象的精细访问权限。
Kubernetes RBAC 主要有三个元素,具体如下:
-
主体:指一组可以向 Kubernetes API 发出请求的用户或流程(包括 Kubernetes 服务帐户)。
-
资源:指一组 Kubernetes API 对象,例如 Pod、Deployment、Service 等。
-
操作符:指可以对资源执行的一组操作,例如获取(get)、列出(list)、创建(create)、观察(watch)、描述(describe)等。
上述元素通过两个 RBAC API 对象连接:
-
角色:连接 API 资源和操作符
-
RoleBindings:将角色与主体连接
角色和 RoleBindings 可以应用于集群级别或命名空间级别。接下来的子章节将讨论这些内容,首先是 角色。
角色
角色 连接 API 资源和操作符(verbs)。RBAC 中有两种类型的角色。RBAC 角色在命名空间级别定义,而 RBAC ClusterRole 在集群级别定义。我们将在接下来的子章节中详细介绍这些内容,首先从 RBAC 角色开始。
RBAC 角色
以下是为特定命名空间定义的 RBAC 角色:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
namespace: production
rules:
apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
该定义表示一个 viewer 角色,该角色将资源 pod 与特定操作符(get 和 list)连接,在 production 命名空间中定义。每个角色只能定义一个命名空间。对于核心组,apiGroups 部分是可选的。但是,apiGroups 应该为非核心组指定。此外,还可以定义一个更精细的角色,其中还会指定特定的资源名称。
可以向角色添加多个规则。规则是累加的。RBAC 角色不支持拒绝规则。以下是对先前 RBAC 角色的扩展,现在包括多个规则并指定资源名称:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
namespace: production
rules:
apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
apiGroups: [""]
resources: ["ConfigMap"]
resourceNames: ["prodEnvironmentVariables"]
verbs: ["get", "list"]
在上述规范中,viewer RBAC 角色现在可以对 Pods 和 ConfigMap 执行 get 和 list 操作。但是,对 ConfigMap 的操作严格限制为名为 prodEnvironmentVariables 的特定 ConfigMap。
这完成了关于 RBAC Role 的这一小节,这是两种可能的 RBAC 角色之一。另一个——RBAC ClusterRole——将在接下来的小节中详细介绍。
RBAC ClusterRole
RBAC ClusterRole 在集群级别授予权限,因此你无需定义特定的命名空间。其余元素及其用法与 RBAC Role 相同。
命名空间范围与集群范围
有些资源是按命名空间级别作用的,有些则是按集群级别作用的。Pods、Deployments、Services、Secrets、ConfigMaps、PersistentVolumeClaim、Roles 和 RoleBindings 是命名空间级别的资源。Nodes、PersistentVolume、CertificateSigningRequests、Namespaces、ClusterRoles 和 ClusterRoleBindings 是集群级别的资源。
以下是 RBAC ClusterRole 的定义,目的是定义一个可以对集群中的节点执行 list、get、create 和 delete 操作的角色:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-administrator
rules:
apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "create", "delete"]
这完成了关于角色的这一小节。接下来的小节将解释如何通过 RoleBindings Kubernetes API 对象将角色与用户绑定。
RoleBindings
RoleBindings 通过 Kubernetes API 对象将主题与角色连接。RBAC 中有两种类型的 RoleBindings。RBAC RoleBindings 定义在命名空间级别,而 RBAC ClusterRoleBindings 定义在集群级别。两者将在接下来的子节中讨论。
RBAC RoleBindings
以下是为特定命名空间定义的 RBAC RoleBinding 的定义,用于将用户与 RBAC 角色连接:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: viewer-rolebinding
namespace: production
subjects:
- kind: User
name: joe@organization.com
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: viewer
apiGroup: rbac.authorization.k8s.io
上述 RBAC RoleBinding 已为生产命名空间定义,并将主题部分下定义的元素与 roleRef 下定义的元素连接起来。具体来说,RBAC RoleBinding 将用户 joe@organization.com 连接到 viewer RBAC 角色。
需要注意的是,主题部分下的 kind 可以是 User、Group 或 ServiceAccount 类型。从 GKE 的角度来看,这些值可以来自 Cloud IAM 用户、Cloud IAM 服务账户或 Kubernetes 服务账户。
RBAC ClusterRoleBindings
RBAC ClusterRoleBindings 将主题与集群级别的 RBAC ClusterRole 绑定,并且不受命名空间级别的限制。你只能绑定集群范围的资源,而不能绑定命名空间范围的资源。
以下是 RBAC ClusterRoleBindings 的定义,目的是将特定的管理员用户绑定到名为 node-administrator 的 RBAC ClusterRole,以便对 GKE 节点执行操作:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-administrator-clusterrolebinding
subjects:
- kind: User
name: theadmin@organization.com
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-administrator
apiGroup: rbac.authorization.k8s.io
这完成了关于 RoleBindings 的这一小节,其中解释了两种类型的 RoleBindings。总体而言,这也结束了关于 Kubernetes RBAC 和 Kubernetes 授权的这一小节。接下来的小节将讨论另一个关键的 Kubernetes 安全构件——控制平面安全——它专注于保护主控制平面组件。
控制平面安全
根据 GCP 的共享责任模型,GKE 的 etcd 数据库、控制器管理器等由 Google 管理。因此,Google 负责保护控制平面,而最终用户负责保护节点、容器和 Pod。
每个 GKE 集群都有自己的根证书颁发机构(CA)。这个 CA 代表一个发行受信证书的实体。这个受信证书用于保护机器之间的连接。CA 的根密钥由 Google 的内部服务管理。集群中的主节点与节点之间的通信是基于由 CA 颁发的证书所提供的共享信任根来进行加密的。默认情况下,GKE 使用单独的集群 CA 来为集群内的 etcd 数据库提供证书。由于每个集群使用不同的 CA,一个集群中的 CA 被破坏时无法用来破坏另一个集群。
Kubernetes API 服务器和 kubelet 使用安全的网络通信协议,如 TLS 和 SSH。它们通过使用集群根 CA 颁发的证书来实现这一点。当集群中创建一个新节点时,该节点会在创建时注入一个共享密钥。然后,kubelet 使用这个密钥向集群根 CA 提交证书签名请求。这使得 kubelet 能够在节点创建时获取客户端证书,并在需要更新或轮换时获得新证书。kubelet 使用这些客户端证书与 API 服务器进行安全通信。
您必须定期轮换证书或凭证,以减少泄露的影响。但有时,可能很难平衡凭证应轮换的频率。这是因为集群 API 服务器会在短时间内不可用。请注意,API 服务器和客户端使用的凭证可以进行轮换,除了 etcd 证书,这些由 Google 管理。
以下是您应遵循的逐步凭证轮换过程:
-
轮换过程从为集群主节点创建一个新的 IP 地址开始,同时保留现有的 IP 地址。
-
在轮换过程中,
kube-apiserver将不可用,但现有的 Pod 会继续运行。 -
由于新 IP 地址的结果,新的凭证会被颁发给控制平面。
-
一旦 GKE 重新配置了主节点,节点会自动由 GKE 更新为使用新的 IP 地址和凭证。此外,节点版本也会更新为最接近的支持版本。
-
每个 API 客户端必须更新为新地址。轮换过程必须完成,集群主节点才能开始使用新的 IP 地址和新的凭证,并移除旧的 IP 地址和旧的凭证。
-
主节点将停止提供旧的 IP 地址。
-
如果轮换过程已开始但在 7 天内未完成,则 GKE 会自动完成轮换。
Pod 运行在节点上,默认情况下,Pod 可以访问它们所在节点的元数据。这包括节点的密钥,用于节点配置。因此,如果 Pod 被攻破,节点密钥也会被攻破,从而对整个集群产生负面影响。为防止这种事件发生并保护集群元数据,应该采取以下步骤:
-
绑定到节点的服务帐户不应包括
compute.instance.get权限。这样可以阻止对这些节点的计算引擎 API 调用。 -
传统的计算引擎 API 端点应禁用(版本 0.1 和 v1-beta-1),因为这些端点支持直接查询元数据。
-
使用工作负载身份从运行在 GKE 中的应用程序访问 Google Cloud 服务。这可以防止 Pod 访问计算引擎元数据服务器。
这完成了本小节关于如何在 GKE 中保护主控平面组件的内容。接下来,我们将通过查看 Pod 安全性来了解如何保护集群中运行的 Pod。
Pod 安全性
一个或多个容器运行在 Pod 内。默认情况下,这些容器可以部署为特权提升。它们也被称为特权容器。特权容器具有主机机器的 root 权限,可以访问普通容器无法访问的资源。以下是特权容器的一些使用场景:
-
在 Docker 容器内运行 Docker 守护进程
-
需要直接硬件访问容器
-
在开源自动化服务器(如 Jenkins)上自动化 CI/CD 任务
运行特权容器很方便,但从安全角度来看是不可取的,因为它允许对主机资源的关键访问。如果被网络犯罪分子利用,这种特权可能会成为一个缺点。攻击者将获得 root 访问权限,这意味着他们可以识别和利用软件漏洞以及可能的配置错误,例如没有身份验证或最低强度凭据的容器。对于加密货币矿工来说,基本上这是一个可以利用这种特权进行未经授权需求的游乐场。
有两种可能的方式来定义对 Pod 中容器操作的限制。它们如下:
-
Pod 安全上下文
-
Pod 安全策略
让我们更详细地了解这些选项。
Pod 安全上下文
Pod 的安全设置可以通过 Pod 规格中的securityContext字段进行指定。这适用于 Pod 内的所有容器,并强制执行特定的安全措施。它们可以定义是否可以运行特权容器,以及容器中的代码是否可以提升到 root 权限。
安全上下文可以在 Pod 级别和容器级别定义。容器级别的安全上下文优先于 Pod 级别的安全上下文。以下是securityContext的 Pod 清单 YAML 摘录:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
securityContext:
runAsUser: 3000
containers:
- name: nginx
image: nginx
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
- name: hello
image: hello-world
上述规范表示一个包含两个容器的 pod:nginx 和 hello。pod 中的 securityContext 定义指定容器内的进程以用户 ID 3000 运行。重要的是要指定一个非零的数字,因为在 Linux 中,0 表示特权用户的用户 ID。不指定 0 会去除容器内运行代码的 root 特权。pod 上的 securityContext 适用于 pod 内的所有容器,除非每个单独的容器定义了可选的 securityContext。在这种情况下,容器上的 securityContext 优先。因此,在上面的例子中,hello 容器将在其容器内以 3000 作为用户 ID 运行进程,而 nginx 容器则以 1000 作为用户 ID 运行进程。
在容器中使用 allowPrivilegeEscalation
我们可以以多种方式使用这个字段。一种情形是,当 pod 层没有定义 securityContext,但需要在特定容器层面避免权限提升时,可以显式地使用此字段。
安全上下文允许你控制主机命名空间、网络、文件系统和卷类型的使用。安全上下文可以用来控制其他安全设置:
-
NET_ADMIN允许你执行与网络相关的操作,例如修改路由表、启用多播等。SYS_TIME允许你设置系统时钟:. . . spec: containers: - name: security-context-example image: gcr.io/demo/security-context-example securityContext: capabilities: add: ["NET_ADMIN", "SYS_TIME"] -
启用 seccomp:阻止容器中的代码进行系统调用。
-
启用 AppArmor:使用安全配置文件限制单个程序的操作。
为每个 pod 甚至每个容器配置 securityContext 的缺点是它需要大量的工作,尤其是在集群中涉及成百上千个 pod 时。这可以通过使用 Pod 安全策略 来解决。
Pod 安全策略
Pod 安全策略 是一个集群级别的资源,基于定义的策略管理创建和更新 pod 的访问权限。策略是一组需要满足的条件。Pod 安全策略使得定义和管理安全配置变得更容易。这允许你将安全限制应用于多个 pod,而不需要在每个 pod 定义中指定和管理这些细节。
Pod 安全策略可以强制执行以下内容:
-
禁用特权容器:可以禁用特权容器,并且可以选择性地针对特定的命名空间和特定的服务账户应用。
-
readOnlyRootFilesystem可以设置为true。 -
MustRunAsNonRoot标志设置为true。 -
对特定目录使用
hostpath,而不是整个文件系统。
定义 Pod 安全策略时需要的两个元素是:
-
PodSecurityPolicy对象代表一组限制、要求和默认值,这些值的定义类似于 Pod 内的安全上下文。此对象还指定了需要满足的所有安全条件,以便 Pod 能够被接纳到集群中。这些规则在 Pod 创建或更新时会被特别应用。 -
PodSecurityPolicy控制器是一个准入控制器。准入控制器根据一个或多个 Pod 安全策略验证和修改请求。该控制器实质上决定 Pod 是否可以创建或修改。
创建 PodSecurityPolicy 对象
如果您需要创建一个PodSecurityPolicy对象,以便在特定命名空间和特定服务账户中不能运行特权容器,您应该遵循以下步骤:
-
使用
pod-security-policy.yaml文件定义一个PodSecurityPolicyKubernetes 对象。以下是一个示例规范:PodSecurityPolicy resource using the following CLI command:创建 Pod 安全策略
kubectl apply -f pod-security-policy.yaml
-
要授权特定的
PodSecurityPolicy,请定义一个 ClusterRole,其资源设置为podsecuritypolicies,并且针对特定策略的资源名称。以下是my-cluster-role.yaml的ClusterRole示例:apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: my-cluster-role rules: - apiGroups: - policy resources: - podsecuritypolicies verbs: - use resourceNames: - my-pod-security-policy -
使用以下 CLI 命令创建您的
ClusterRole:# Create ClusterRole kubectl apply -f my-cluster-role.yaml -
要授权已创建的 ClusterRole 针对特定主体(可以是服务账户),并且可选地在特定命名空间中定义一个
RoleBinding。以下是my-role-binding.yaml的示例规范,其中将 RoleBinding 应用于特定服务账户:# Bind the ClusterRole to the desired set of service accounts apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: my-role-binding namespace: my-namespace roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: my-cluster-role subjects: - kind: ServiceAccount name: sa@example.com namespace: my-namespace -
使用以下 CLI 命令创建您的
RoleBinding:# Create RoleBinding kubectl apply -f my-role-binding.yaml -
在集群创建时或更新现有集群时启用
PodSecurityPolicy控制器。以下是这两种选项的 CLI 命令:# To enable at the time of cluster creation gcloud beta container clusters create <cluster-name> --enable-pod-security-policy # To enable on an existing cluster gcloud beta container clusters update <cluster-name> --enable-pod-security-policy -
如果您需要禁用
PodSecurityPolicy控制器,请使用以下 CLI 命令:To disable PodSecurityPolicy controller gcloud beta container clusters update <cluster-name> --no-enable-pod-security-policy
在 GKE 中,PodSecurityPolicy控制器在集群创建时默认是禁用的,或者没有启用。因此,您需要显式启用它。然而,控制器应该仅在定义了所有相关的PodSecurityPolicy对象及其授权要求之后启用。如果有多个 Pod 安全策略,这些策略将按字母顺序进行评估。
本节内容已结束,讨论了控制平面(身份验证)、工作节点和部署(授权)中的基本安全概念。本节还参考了 GKE 及这些概念如何在 GKE 中实现。接下来的部分将重点讨论 GKE 在加固集群安全方面的具体建议,以确保在集群内运行的应用程序安全。GKE 提供了一些功能来支持这些建议,所有这些功能将详细列出。
在 GKE 中加固集群安全
在保护集群内部运行的应用程序时,确保 Kubernetes 集群的安全应当是首要任务。GKE 提供了许多功能来强化集群的安全性。例如,GKE 控制平面会根据共享责任模型自动打补丁和升级。此外,新的 GKE 集群还会启用节点自动升级功能。
以下是一些可用于保护和强化集群的 GKE 关键功能。这些功能中的部分会在创建 GKE 集群时默认启用:
-
GKE 支持一种名为私有集群的集群类型,它提供了限制控制平面和节点访问的选项。需要在集群创建时指定此配置。
-
GKE 支持容器优化操作系统镜像。这是一个为运行容器量身定制、优化和强化的容器优化操作系统。
-
GKE 支持受保护的 GKE 节点,通过使用可验证的节点身份和完整性来增强集群安全性。此功能可以在集群创建时启用,也可以更新现有集群来启用。
-
GKE 允许在新建或现有集群上强制使用网络策略。网络策略可以限制集群内 pod 之间的通信,从而在发生安全事件时减少影响范围。
-
GKE 推荐使用二进制授权,这是一种确保供应链软件安全的过程。通过此方法,您可以控制只部署集群中受信任的镜像。
-
GKE 可以通过工作负载身份与其他 Google 服务和 API 进行身份验证。这是推荐的做法,应该避免在节点级别使用服务账户密钥。
-
GKE 通过与 Google Secret Manager 集成,为敏感数据(如机密信息)提供额外的保护层。Secret Manager 是一个 GCP 服务,用于保护 API 密钥、密码、证书和其他敏感数据。GKE 还支持使用第三方密钥管理工具,如 HashiCorp Vault。
以上每个 GKE 特性将在各自的章节中进行详细讲解。我们将从 GKE 私有集群开始。
GKE 私有集群
GKE 私有集群是 GKE 中的一种可能的集群配置,特别是在网络隔离方面。这种集群配置隔离了节点与公共互联网的连接,包括集群的入站流量和出站流量。因为集群中的节点将没有公开的 IP 地址,仅拥有内部 IP 地址。
如果节点需要外部互联网访问,可以使用托管的 NodePort 或 LoadBalancer 类型。如果服务是 LoadBalancer 类型,则可以使用 GCP 的 HTTP(S) 负载均衡器,并将提供一个外部 IP 地址,以允许流量进入集群。GKE 私有集群的关键在于其控制平面的功能,因为这是与非私有集群的主要区别。我们接下来会详细讨论这一点。
私有集群中的控制平面
在 GKE 中,kube-apiserver 由控制平面管理。Google 在 Google 自有项目中的 VPC 网络上运行控制平面。对于私有集群,主控制平面位于 Google 自有的 VPC 网络中,并通过 VPC 网络对等连接到你的集群的 VPC 网络。节点和控制平面之间的流量通过内部 IP 地址进行路由。
你可以通过端点访问控制平面。一般来说,端点有两种类型:
-
kubectl工具通过公共端点访问。 -
私有端点:这表示控制平面 VPC 网络中的内部 IP 地址。这个设置非常特定于私有集群。私有集群中的节点通过内部 IP 地址与控制平面中的组件进行通信。
总结来说,公共集群控制平面具有面向互联网的端点,而私有集群控制平面可以通过私有端点和公共端点进行访问。此外,私有集群只能在 VPC 本地模式下创建(参见 第八章,理解 GKE 基础知识以便部署容器化应用程序)。可以通过以下三种配置之一来控制通过端点访问私有集群的级别:
-
已禁用公共端点访问
-
已启用公共端点访问;已启用授权网络以进行有限访问
-
已启用公共端点访问;已禁用授权网络
接下来的子章节将详细讨论每种配置,从 已禁用公共端点访问 开始。
已禁用公共端点访问
此配置表示一个没有公共端点访问权限的私有 GKE 集群。这非常安全,因为没有通过公共互联网访问控制平面的方式。集群只能从子网以及用于 pod 的次要范围进行访问。可以通过更新主授权网络并使用虚拟机的私有 IP(CIDR 格式)将同一区域的虚拟机添加到集群中。
如果需要从外部访问集群,则可以通过 Cloud VPN 或 Cloud Interconnect 连接到 GKE 私有集群的 VPC 网络。连接通过内部 IP 地址建立。可以通过使用 master-authorized-networks 来限制可以访问控制平面的内部 IP 地址列表。这不包括公共 IP 地址,因为公共端点的访问已被禁用。
如果你需要创建一个不允许客户端访问公共端点的私有 GKE 集群,请使用以下 CLI 命令:
# For Standard Clusters
gcloud container clusters create my-private-cluster \
--create-subnetwork name=my-subnet \
--enable-master-authorized-networks \
--enable-ip-alias \
--enable-private-nodes \
--enable-private-endpoint \
--master-ipv4-cidr 172.20.4.32/28
上述 CLI 命令中的关键标志如下:
-
--enable-master-authorized-networks:集群控制平面的访问仅限于内部 IP 地址列表。不能包含外部 IP 地址。 -
--enable-private-nodes:表示集群节点没有外部 IP 地址。 -
--enable-private-endpoint:表示该集群仅由主 API 端点的私有 IP 地址管理。
下一部分聚焦于一个配置,其中启用了公共端点访问,但访问受限。
启用公共端点访问;授权网络启用以进行有限访问
该配置表示一个私有 GKE 集群配置,其中对控制平面的访问既受内部也受外部 IP 地址的限制。可以将特定的内部和外部 IP 地址作为授权网络的一部分进行指定。因此,只有当外部 IP 地址包含在授权网络中时,具有外部 IP 地址的机器才能与 GKE 私有集群通信。
如果你需要创建一个仅对公共端点提供有限访问的私有 GKE 集群,请使用以下 CLI 命令:
# For Standard Clusters
gcloud container clusters create my-private-cluster-1 \
--create-subnetwork name=my-subnet-1 \
--enable-master-authorized-networks \
--enable-ip-alias \
--enable-private-nodes \
--master-ipv4-cidr 172.20.8.0/28
请注意,这些标志大部分与前一部分相同,唯一不同的是省略了 --enable-private-endpoint 标志。省略此标志意味着集群控制平面既可以通过私有端点也可以通过公共端点访问,但访问仅限于作为主授权网络的一部分的允许 IP 地址。
下一部分聚焦于一个配置,其中启用了公共端点访问,且访问没有受到限制。
启用公共端点访问;禁用授权网络
这是创建私有 GKE 集群时的默认配置选项。本质上,集群可以从任何 IP 地址访问控制平面。这是最不限制的选项。
如果你需要创建一个允许不受限制访问公共端点的私有 GKE 集群,请使用以下 CLI 命令:
# For Standard Clusters
gcloud container clusters create my-private-cluster-2 \
--create-subnetwork name=my-subnet-2 \
--no-enable-master-authorized-networks \
--enable-ip-alias \
--enable-private-nodes \
--master-ipv4-cidr 172.20.10.32/28
请注意,这些标志大部分与启用了公共端点访问但未启用主授权网络的配置中的标志相同。因此,在通过私有端点或公共端点访问私有 GKE 集群的控制平面时,不会有 IP 地址访问限制。
这一部分结束了关于私有集群的讨论,私有集群中的节点可能会被隔离或限制访问公共互联网。接下来的主题将重点介绍容器优化操作系统,它通过强化容器镜像并添加关键的安全特性,从而保护应用程序。此功能在 GKE 中可用。
容器优化操作系统
cos_containerd 镜像是一个基于 Linux 的内核,经过 Google 定制,基于 Chromium OS。它可以持续扫描内核级别或操作系统任何包的漏洞。在发现漏洞时,可以修补和更新任何包。它特别针对生产环境中的容器运行进行优化和加固。以下是其一些关键特性:
-
最小化操作系统占用空间:不包含不必要的包,从而减少操作系统的攻击面。
-
不可变根系统和验证启动:根文件系统始终以只读方式挂载。这可以防止攻击者在文件系统上进行更改。校验和也会在构建时计算,并在每次启动时由内核进行验证。
-
/etc/。这很有用,因为您可以在运行时允许写入配置,例如向文件系统添加用户。然而,这些更改在重启后不会持久化。 -
安全加固内核:支持 seccomp 和 AppArmor 等功能,以强制执行精细化的安全策略。
-
自动更新:支持自动更新以获取新的安全功能或运行中的 GCE 虚拟机的安全补丁。
-
22。
容器优化操作系统确保用于容器化应用程序的基础镜像是安全的并且具有最小的占用空间,但同样重要的是,这些容器需要在同样安全或受保护的节点上运行。我们将在下一个主题中讨论这一点。
受保护的 GKE 节点
受保护的 GKE 节点是一个 GKE 功能,通过提供强大且可验证的节点身份和完整性来增强集群的安全性。这些节点基于计算引擎受保护的虚拟机(Shielded VMs)。
受保护的虚拟机
受保护的虚拟机是 GCP 的一项功能,确保虚拟机实例在启动或内核级别不会被攻破。GCP 通过使用安全启动和 虚拟受信平台模块(vTPM)来实现这一点。受保护的虚拟机会在启动过程中强制执行并验证所有组件的数字签名,在失败时停止启动过程。
受保护的 GKE 节点功能可防止攻击者在 Pod 漏洞被利用时伪装成集群中的节点。如果启用了受保护的 GKE 节点功能,GKE 控制平面将通过加密方式验证以下内容,并限制攻击者伪装集群中节点的能力:
-
GKE 集群中的每个节点都是在 Google 数据中心运行的 GCE 虚拟机。
-
每个节点都是集群提供的托管实例组的一部分。
-
kubelet使用集群提供的证书与节点进行身份验证。
您可以使用以下 CLI 命令在新的/现有集群中启用受保护的 GKE 节点,验证是否启用了受保护的 GKE 节点,并禁用受保护的 GKE 节点:
# Enable Shielded GKE nodes on new cluster
gcloud container clusters create <cluster-name> --enable-shielded-nodes
# Enable Shielded GKE nodes on existing cluster
gcloud container clusters update <cluster-name> --enable-shielded-nodes
# Verify that Shielded GKE nodes are enabled (check for enabled under shieldedNodes as true)
gcloud container clusters describe <cluster-name>
# Disable Shielded GKE nodes (This will recreate the control plane and nodes thus leading to downtime)
gcloud container clusters update <cluster-name> --no-enable-shielded-nodes
运行受保护的 GKE 节点不会产生额外费用。然而,它们比常规节点产生更多的日志,从而导致 Cloud Logging 的总体费用增加。下一个主题将解释另一个 GKE 安全功能,该功能通过限制集群中 pod 之间的流量,在发生安全威胁时减少攻击面。
网络策略——限制 pod 之间的流量
Kubernetes 集群中的所有 pod 可以相互通信。然而,Kubernetes 提供了在 pod 之间的流量需要在 IP 地址或端口级别进行控制时的选项。强烈建议采取这种思路,以确保整个集群不会受到攻击,并且在发生安全攻击时可以控制攻击面。Kubernetes 网络策略帮助你限制集群内 pod 之间的流量。
网络策略在 Kubernetes 中允许你根据具有匹配标签选择器的 pod、具有匹配标签选择器的命名空间,或具有特定 IP 地址和端口组合的网络实体,指定 pod 如何与这些网络实体进行通信(包括能够指定例外 IP 地址)。这可以为入口或出口流量在两个方向上进行定义。
GKE 提供了在创建集群时强制使用网络策略的选项,如下所示:
# Enforce network policy for a new GKE cluster
gcloud container clusters create <cluster-name> --enable-network-policy
可选地,我们可以通过使用以下 CLI 命令在现有集群上强制执行此操作:
# Enable add-on to enforce network policy on existing cluster
gcloud container clusters update <cluster-name> --update-addons=NetworkPolicy=ENABLED
# Enforce network policy after enabling add-on for existing cluster. This will recreate the cluster node pools
gcloud container clusters update <cluster-name> --enable-network-policy
可以在kubernetes.io/docs/concepts/services-networking/network-policies/找到一个示例网络策略。
除了指定具体的策略外,Kubernetes 还允许你定义默认的网络策略。以下是一些支持的默认策略:
-
默认拒绝所有入口流量
-
默认拒绝所有出口流量
-
默认拒绝所有入口和所有出口流量
-
默认允许所有入口流量
-
默认允许所有出口流量
如果没有定义特定的网络策略或默认策略,则集群将允许 pod 之间的所有入口和出口流量。
下一个主题详细介绍了另一个关键的 GKE 功能——二进制授权,它可以控制确保仅受信任的镜像被部署到 GKE 集群中。
二进制授权
二进制授权是 Google 提供的一个部署时安全服务。它通过部署策略确保只有受信任的容器被部署到 GKE 集群中。该策略的目标是确定允许哪些镜像,哪些镜像可以豁免。为了实现这一目标,二进制授权与容器分析(Container Analysis)集成——这是一个 GCP 服务,用于扫描存储在容器注册表中的容器镜像的漏洞。此外,容器分析还存储了在授权过程中使用的受信任元数据。
二进制授权策略是安全导向的,并包括一个或多个规则。规则是在图像部署到 GKE 集群之前需要通过的约束条件。已认证的图像是已由签名者验证或保证的图像。最常见的规则之一是需要数字签名的验真书来验证图像是否已经被认证。当通过 Cloud Build 构建容器图像时,图像的摘要会由签名者进行数字签名,从而创建验真书。在部署时,二进制授权会强制使用签名者来验证验真书。二进制授权仅允许已认证的图像部署到集群中。任何未经授权的图像如果不符合二进制授权策略将被拒绝。此外,如果没有找到有效的并由签名者信任的键签名的验真书,还可能返回由签名者拒绝错误。要解决由签名者拒绝错误,请创建一个验真书并提交给二进制授权。
以下是一些包含验真书的常见用例:
-
构建验证:验证容器图像是否由特定的构建系统构建,或者是否来自特定的持续集成(CI)流水线。
-
漏洞扫描:验证 CI 构建的容器图像是否已通过 Container Analysis 进行漏洞扫描,并且结果已定义在可接受的水平上。
配置二进制授权是一个多步骤的过程。以下是涉及的步骤的高级摘要:
-
启用所需的 API。这包括 GKE、Container Analysis 和二进制授权的 API。
-
创建启用了二进制授权的 GKE 集群。
-
设置一个注释。这是与一个签名者相关联的 Container Analysis 存储中的元数据。
-
使用 PKIX 密钥设置加密密钥,以安全地验证签名者的身份;仅强制验证方可以授权容器图像。公钥基础设施(PKIX)密钥是指在 X.509 标准中定义的公钥证书。
-
创建一个签名者;也就是说,一个可以证明图像真实性的人或过程。
-
创建一个二进制授权策略。默认策略是允许所有图像。其他选项包括拒绝所有图像或拒绝特定签名者的图像。
-
可选地,可以配置图像以使其免于二进制授权策略。
正如我们之前提到的,二进制授权(Binary Authorization)可以拒绝部署违反策略条件或未满足的镜像。然而,您可以在 Pod 部署中指定一个名为“break-glass”的标志作为注释,这样即使镜像违反了策略,也允许创建 Pod。这个“break-glass”注释标志会被记录下来,审计日志中的事件响应团队可以通过它在查看或调试部署时识别出来。以下是包含“break-glass”标志注释的 Pod 规格片段:
apiVersion: v1
kind: Pod
metadata:
name: my-break-glass-pod
annotations:
alpha.image-policy.k8s.io/break-glass: "true"
本节内容已结束,接下来的主题详细介绍了另一个关键的 GKE 安全功能,该功能通过工作负载身份允许将 Google Cloud IAM 服务账户作为 Kubernetes 服务账户使用,从而为在 GKE 集群内运行的应用程序提供更安全的 GCP 服务访问。
工作负载身份
GKE 集群可以运行可能需要访问 Google 特定 API 的应用程序,如计算 API、存储 API、数据库 API 等。GKE 推荐使用 工作负载身份 来从在 GKE 内运行的应用程序访问 GCP 服务。工作负载身份允许您将 Kubernetes 服务账户作为 Google 服务账户使用。这使得每个应用程序能够拥有独立的身份和细粒度的授权。
工作负载身份使用集群工作负载身份池的概念,该池允许 Google Cloud IAM 信任并理解 Kubernetes 服务账户凭据。集群的工作负载身份池将设置为 PROJECT_ID.svc.id.goog,并在项目级别自动创建。在这种情况下,Cloud IAM 将通过以下成员名称对 Kubernetes 服务账户进行身份验证:
serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/KSA_NAME]
# PROJECT_ID.svc.id.good - workload identity pool on the cluster
# KSA_NAME Kubernetes - service account making the request
# K8S_NAMESPACE Kubernetes - namespace with Kube SA is defined
由于集群的工作负载身份池、服务账户名称和 Kubernetes 命名空间的关系,前述成员的名称是唯一的。因此,具有匹配的三元组的多个服务账户将映射到相同的成员名称。
启用工作负载身份
按照以下步骤在 GKE 集群上启用工作负载身份:
-
导航到
IAM 服务账户凭据API 并启用它。 -
使用以下 CLI 命令创建一个启用了工作负载身份的新集群:
# Create cluster with workload identity enabled gcloud container clusters create <CLUSTER_NAME> \ --workload-pool=<PROJECT_ID>.svc.id.goog -
使用以下 CLI 命令更新启用了工作负载身份的现有集群:
# Update existing cluster with workload identity enabled gcloud container clusters update <CLUSTER_NAME> \ --workload-pool=<PROJECT_ID>.svc.id.goog
本节关于工作负载身份的内容已经结束,同时也结束了关于 GKE 安全功能的这一主要部分,Google 推荐这些功能来强化集群的安全性。
总结
在本章中,我们讨论了一些从原生 Kubernetes 或 K8s 角度出发的基本安全概念。我们还扩展了这些概念,探讨了它们在 GKE 中的等效用法或实现方式。随后,我们深入探讨了某些 GKE 特有的安全功能,这些功能对于加强集群安全至关重要。这包括使用节点自动升级,确保节点运行最新版本的 Kubernetes,或使用 Google 的容器优化操作系统,而不是通用的 Linux 发行版系统。我们还探讨了使用私有集群,其中可以限制访问集群主节点的权限以增强安全性,或者可以控制只允许从授权网络访问。我们还讨论了二进制授权(Binary Authorization),它确保只有受信任的镜像可以部署到集群中,以及工作负载身份(Workload Identity),它允许我们将 Cloud IAM 服务账户作为 Kubernetes 服务账户使用,从而在 GKE 集群中的应用程序与其他 GCP 服务(如 Cloud Storage、Secret Management 等)之间提供更多灵活性。
在下一章中,我们将介绍与云操作相关的服务,以及 Google Cloud 中为跟踪服务可靠性而引入的特定功能:服务监控。这个特定的功能/选项将 SRE 技术实践(SLI、SLO 和错误预算)与 Google Cloud Operations 中可用的功能联系起来,从而让我们能够监控服务并在服务的可靠性出现问题时发出警报。
需要记住的要点
以下是一些需要记住的重要要点:
-
如果 GCP 资源必须有一个与应用程序或虚拟机相关联的身份,则使用 GCP 服务账户。
-
Kubernetes 服务账户是由 Kubernetes API 管理的用户。
-
Cloud IAM 定义了谁可以查看或更改 GKE 集群的配置,而 Kubernetes RBAC 定义了谁可以查看或更改特定 GKE 集群内的 Kubernetes 对象。
-
工作负载身份(Workload Identity)用于从 GKE 内运行的应用程序访问 Google Cloud 服务。这防止了 pod 访问计算引擎元数据服务器。
-
在 RBAC 中,角色连接 API 资源和动词。RBAC 角色是集群范围的,而 RBAC ClusterRole 是命名空间范围的。
-
在 RBAC 中,RoleBindings 将角色与主体连接。RoleBinding 是集群范围的,而 ClusterRoleBinding 是命名空间范围的。
-
每个 GKE 集群都有自己的根 CA。
-
Pod 安全上下文和 Pod 安全策略是我们可以定义容器在 pod 内可以执行的操作限制的两种方式。
-
GKE 私有集群允许您限制对控制平面和节点的访问。
-
break-glass 标志用于部署时作为注解;它允许创建 pod,即使镜像违反了策略。
-
enable-private-nodes:节点没有外部 IP 地址。 -
enable-private-endpoint:集群通过主节点的私有 IP 地址进行管理。 -
enable-master-authorized-networks:对集群的公共端点访问仅限特定的源 IP 地址集。 -
容器分析是一个提供漏洞扫描和软件工件元数据存储的服务。
-
容器分析存储在授权过程中使用的受信元数据。
-
二进制授权根据您配置的策略,允许或阻止镜像部署到 GKE。
-
一个容器优化的操作系统或
cos_containerd镜像是一个基于 Linux 内核的系统,可以持续扫描内核级别的漏洞。 -
受保护的 GKE 节点通过使用可验证的节点身份和完整性提高集群安全性。可以使用
--enable-shielded-nodes选项启用此功能。 -
您可以使用网络策略来限制 Pods 之间的流量。
-
您可以配置与 GKE 集群集成的秘密管理器。
-
您可以使用准入控制器来强制执行 Pod 安全策略。
-
就工作负载身份而言,您可以使用 K8 的服务帐户和命名空间作为 GCP 服务帐户来认证 GCP API。
进一步阅读
有关 GCP 在 DevOps 中的应用方法,请阅读以下文章:
-
Kubernetes:
kubernetes.io/docs/home/ -
Google Kubernetes Engine:
cloud.google.com/kubernetes-engine
实践测试
回答以下问题:
-
网络策略用于限制以下哪个项之间的流量?
a) 部署
b) 容器
c) Pods
d) 容器镜像
-
选择连接用户和角色的 RBAC 选项:
a) 用户角色绑定
b) 角色绑定
c) 角色
d) 角色用户绑定
-
在私有集群中,哪项 Google 服务可以下载 Docker 镜像?
a) Cloud Build
b) Cloud Source Repository
c) 弹性容器注册表
d) 容器注册表
-
如果凭证轮换的过程开始了,但从未完成,会发生什么?
a) GKE 将不会完成集群轮换。
b) GKE 将暂停集群轮换。
c) GKE 将在 7 天内完成集群轮换。
d) GKE 将立即完成集群轮换。
-
以下哪项策略会禁用特权容器?
a) 网络策略
b) Pod 安全策略
c) 网络安全策略
d) Pod 策略
-
选择允许您管理集群(包括创建、删除、获取、列出或更新集群)的 GKE 角色。此角色不授予访问集群资源或 API 对象的权限:
a) GKE 管理员
b) GKE 集群管理员
c) GKE 开发者
d) GKE 集群开发者
-
关于Pod 安全策略(PSP),请选择操作顺序:
a) 启用 PSP 控制器,创建 PSP,定义授权要求
b) 创建 PSP,启用 PSP 控制器,定义授权要求
c) 创建 PSP,定义授权要求,启用 PSP 控制器
d) 启用 PSP 控制器,定义授权要求,创建 PSP
-
如果没有定义特定的网络策略或默认策略,则以下哪项是正确的?
a) 拒绝所有的入口流量和出口流量。
b) 允许所有入口流量和所有出口流量。
c) 拒绝所有的入口流量并允许所有出口流量。
d) 允许所有入口流量并拒绝所有出口流量。
-
选择强制执行 GKE 部署时策略的选项:
a) 云 IAM 策略
b) AppArmor
c) Cloud Armor
d) 二进制授权
-
服务帐户准入控制器将创建的服务帐户与正在运行的 Pods 关联。服务帐户是如何存储和访问的?
a) 作为纯文本存储,并作为环境变量在运行时访问
b) 作为 Kubernetes 密钥存储,通过密钥管理服务访问
c) 作为 Kubernetes 密钥存储,作为环境变量在运行时访问
d) 作为纯文本存储,通过密钥管理服务访问
答案
-
(c): Pods
-
(b): 角色绑定
-
(d): 容器注册表
-
(c): GKE 将在 7 天内完成集群轮换。
-
(b): Pod 安全策略
-
(b): GKE 集群管理员
-
(c): 创建 PSP,定义授权要求,启用 PSP 控制器
-
(b): 允许所有入口流量和所有出口流量。
-
(d): 二进制授权
-
(c): 作为 Kubernetes 密钥存储,作为环境变量在运行时访问
第十章:探索 GCP Cloud Operations
可靠性是服务或系统最关键的特性。站点可靠性工程(SRE)规定了一些特定的技术工具或实践,帮助衡量定义并跟踪可靠性的特征,如SLAs、SLOs、SLIs和错误预算。
在第二章中,SRE 技术实践深度剖析,我们详细讨论了 SLAs 的关键构成、实现 SLA 所需的 SLOs、设置 SLOs 的指南,以及实现 SLOs 所需的 SLIs。此外,我们了解了基于用户旅程分类的不同类型的 SLIs、用于衡量 SLIs 的不同来源、错误预算的重要性,以及如何设置错误预算以确保服务的可靠性。
这引出了一个系列的基础性问题:
-
我们如何观察服务的 SLIs,以确保不违反 SLOs?
-
我们如何跟踪我们的错误预算是否被消耗完了?
-
我们如何保持关键 SRE 技术工具之间的和谐?
SRE 对上述问题的回答是可观测性。在Google Cloud Platform(GCP)上,可观测性是通过运营来建立的。从 Google 的角度看,Cloud Operations 是关于在 Google Cloud 环境中监控、故障排除和提升应用性能。Cloud Operations 的关键目标如下:
-
从任何来源收集日志、指标和追踪。
-
查询捕获的指标并分析追踪。
-
在内置或可定制的仪表板上可视化信息。
-
建立性能和可靠性指标。
-
在可靠性指标未达到或遇到问题的情况下触发警报并报告错误。
Google 通过一组名为 Cloud Operations 的服务实现运营的关键目标。Cloud Operations 是一套 GCP 服务,包括 Cloud Monitoring、Cloud Logging、Error Reporting 和应用性能管理(APM)。此外,APM 包括 Cloud Debugger、Cloud Trace 和 Cloud Profiler。本章将探讨与 Cloud Operations 相关的服务。之后,我们将重点关注 Google Cloud 中引入的一项特性,用于通过服务监控来追踪服务的可靠性。这个特性/选项将 SRE 技术实践(SLIs、SLOs 和错误预算)与 Google Cloud Operations 中可用的监控服务功能相连接,从而告诉我们服务的可靠性。
本章我们将覆盖以下主要主题:
-
Cloud Monitoring:工作区、仪表板、指标探查器、正常运行时间检查和告警。
-
Cloud Logging:审计日志、日志摄取、日志探查器和基于日志的指标。
-
Cloud Debugger:设置、使用、调试日志点和调试快照。
-
Cloud Trace:追踪概述、追踪列表和分析报告。
-
Cloud Profiler:配置文件类型。
-
绑定 SRE 和云操作:我们将通过实践实验室将 SRE 技术实践与 Cloud Operations 结合,以衡量服务的可靠性。
云监控
云监控是一个 GCP 服务,能够实时收集来自多云和混合基础设施的度量、事件和元数据。云监控帮助我们了解资源的性能以及是否存在需要立即关注的问题。云监控是实施 SRE 最佳实践的途径,并确保应用程序达到其设定的 SLA。云监控包括开箱即用的仪表盘,这些仪表盘可用于可视化对影响 SLI 和 SLO 的关键因素的洞察,如延迟、吞吐量等。云监控对事件管理也至关重要,因为可以从关键指标中生成警报,并将这些警报作为通知发送到配置的通知通道。
本节深入探讨了云监控的几个关键领域/属性,如工作区、仪表盘、指标资源探索器、正常运行时间检查、警报、访问控制和监控代理。我们将从工作区开始。
工作区
Google 工作区是一个集中式的中心,用于组织和展示有关 GCP 和 AWS 资源的监控信息。工作区提供集中视图,并作为访问资源仪表盘、正常运行时间检查、组、事件、警报和图表的单一入口点。Google 将这种集中视图称为单一窗口(请参阅以下截图)。可以对工作区执行的操作包括查看内容,这些内容由身份与访问管理(IAM)控制:

图 10.1 – 云监控工作区概述
在详细说明工作区与项目之间的关系之前,以下是我们需要了解的一些关键术语:
-
主机项目:指的是创建工作区的项目。
-
监控项目:指的是工作区可以监控的 GCP 项目或 AWS 账户。
-
AWS 连接器项目:指的是将监控的 AWS 账户与工作区连接的 GCP 项目。
接下来的子章节将深入探讨工作区与项目之间的关系。
工作区/项目关系
以下是关于工作区/项目关系的一些关键要点:
-
一个工作区始终是在一个项目内创建的,这个项目被称为主机项目。
-
一个工作区是单个主机项目的一部分,并以主机项目命名。
-
一个工作区可以同时监控来自多个监控项目的资源。这可以包括大约 200 个 GCP 项目/AWS 账户。
-
一个工作区可以访问其他监控项目的度量数据,但实际数据存储在监控项目中。
-
每个被监控项目只能与一个工作区关联,并且一个被监控项目可以从一个工作区移动到另一个工作区。
-
多个工作区可以合并为一个工作区。
-
创建工作区本身没有费用。然而,与日志记录和指标数据获取相关的费用将由与被监控项目关联的账单账户承担。
提示 – 如何将 AWS 账户连接到工作区
需要一个 GCP 连接器项目。这个项目可以是一个现有的项目,或者是一个为此目的创建的空项目(优选)。GCP 连接器项目需要与工作区处于相同的父组织下。一个账单账户应该与连接器项目绑定,并且此账户将被用来监控 AWS 账户下的资源。
以下部分讨论了创建工作区的潜在策略。
工作区创建 – 策略
在实时场景中,可能会有多个项目,这些项目要么按客户区分,要么按环境类型(如开发、测试、预发布和生产)区分。由于一个工作区可以监控来自多个项目的资源,因此创建工作区时采用的策略/方法变得至关重要。我们可以遵循多种策略来创建工作区,具体策略将在以下部分详细介绍。
所有被监控项目的单一工作区
所有被监控项目资源的信息都可以从单一工作区中获取。下图展示了一个工作区,监控了一个应用程序app,该应用程序已部署到多个项目中,如app-dev、app-test和app-prod。这些项目按环境类型进行了分类。这种方法有其优缺点。
优点是,工作区为所有与应用程序相关的资源提供了一个统一视图,这些资源来自多个项目,代表了不同的环境类型。缺点是,非生产用户可以访问生产项目中的资源,这在大多数情况下可能是不可接受的。这种方法不适合那些在生产和非生产环境之间有严格隔离的组织:

图 10.2 – 所有相关项目的单一工作区
每组被监控项目的工作区
一个工作空间将监控一组特定的项目。可以有多个工作空间监控可用的项目。以下图表是与前面的图表所示的工作空间创建策略相比的另一种选择。具体来说,以下图表代表两个工作空间,其中一个工作空间监控非生产项目,而第二个工作空间监控生产项目。通过单个工作空间的主机项目控制对该特定组的访问控制,这允许我们区分跨环境类型(例如生产与非生产)或甚至跨客户的用户:

图 10.3 – 每组受监控项目一个工作空间
每个受监控项目一个单一工作空间
实质上,需要进行监控的每个项目都由同一项目中的一个工作空间托管。这可以在以下图表中看到。这意味着源和托管项目将是相同的。这种方法在提供对项目资源进行监控访问方面提供了最精细的控制。但是,如果应用程序跨多个项目分布,这也可能仅提供信息的一部分:

图 10.4 – 每个受监控项目一个单一工作空间
重要提示 – 工作空间管理
可以向工作空间添加或删除一个或多个 GCP 项目或 AWS 账户。此外,可以将所选工作空间中的所有项目合并到当前工作空间中,但所选工作空间中的配置将被删除。这些操作是通过 Cloud Monitoring 的设置页面执行的。只有当工作空间托管项目被删除时,才能删除工作空间。
这结束了关于工作空间创建策略的子节。首选策略取决于组织需求。工作空间的基本操作包括创建工作空间、将项目添加到工作空间、在工作空间之间移动项目以及合并工作空间。有关如何创建工作空间的详细说明,请参阅 cloud.google.com/monitoring/workspaces/create。接下来的子节将讨论 IAM 角色,这些角色用于确定谁有权限监控监控工作空间内的资源。
工作空间 IAM 角色
下面是可以应用于工作空间项目的 IAM 角色,以便我们可以查看监控数据或在工作空间上执行操作:
-
监控查看者:仅具有查看工作空间内指标的只读访问权限。
-
监控编辑者:监控查看者,以及编辑工作空间、创建警报、以及对监控控制台和监控 API 具有写访问权限的能力。
-
监控管理员:监控编辑者,以及管理工作空间的 IAM 角色的能力。
-
监控指标写入者:一种授予应用程序而非用户的服务帐户角色。这样,应用程序可以将数据写入工作区,但不提供读取权限。
这就是我们对工作区及其概念(如工作区创建策略)的简要了解。接下来,我们将关注仪表板。
仪表板
仪表板提供了关键信号数据(称为指标)的图形化表示方式,适合最终用户或运维团队使用。建议单个仪表板展示特定视角下的指标(例如,带有特定标签的无服务器资源)或特定资源(例如,持久磁盘、快照等)。仪表板有两种类型:预定义仪表板和自定义仪表板。
以下截图是 Cloud Monitoring 中的 仪表板概览 页面。该页面展示了可用仪表板的列表,按仪表板类型分类,并提供快速链接到最近使用的仪表板:

图 10.5 – Cloud Monitoring – 仪表板概览
Cloud Monitoring 同时支持预定义仪表板和自定义仪表板。接下来的小节将提供不同类型仪表板的概述,并介绍如何创建自定义仪表板的步骤。
预定义仪表板
Cloud Monitoring 提供了一组预定义的仪表板,这些仪表板按特定的 GCP 资源(例如防火墙或 GKE 集群)进行分组。这些仪表板按 类型 分类。该设置为 Google Cloud Platform,由 Google Cloud 维护。它们不需要任何显式的设置或配置工作。
然而,预定义仪表板是不可自定义的。这些仪表板以特定方式组织,并且具有一组预定义的过滤器,基于仪表板的上下文,用户不能更改视图内容或添加新的过滤条件。用户只能使用预定义的过滤器来控制显示的数据。
自定义仪表板
用户或运维团队可以创建 自定义仪表板,以展示特定的内容。这些仪表板按 类型 分类,设置为 自定义。通过配置一个或多个小部件来添加内容。小部件有多种类型。仪表板可以通过 Google Cloud Console 或 Cloud Monitoring API 创建。此外,Cloud Monitoring API 允许你从 GitHub 导入仪表板配置并根据需要进行修改。
自定义仪表板通过图表展示关于某个指标的信息。这个图表显示了来自一个在可配置时间窗口内对齐的指标的原始信号信息。每个图表都是特定的小部件类型。Cloud Monitoring 支持多种小部件类型,例如线形图、堆叠区域图、堆叠条形图、热图、仪表盘、记分卡和文本框。让我们简要了解一下不同类型的小部件:
-
折线图、堆叠区域图和堆叠条形图最适合用来显示时间序列数据。每种小部件类型都可以配置,以便在颜色/透视/统计/异常模式下显示,并且可以选择是否显示图例。
-
热力图图表用于表示具有分布值的指标。
-
仪表盘以数字形式显示最新的测量值。这通过仪表周围的粗线条表示。视觉上,这些数值被分类为良好区、警告区和危险区。
-
积分卡与仪表盘类似,也以数字形式显示最新的测量值,但它们可以使用不同的视图展示,而不仅限于仪表盘,例如火花线、火花条、图标或数值。
-
文本框允许我们添加任何自定义信息,如快速笔记或链接,关于相关资源。
接下来的子节将展示如何创建自定义仪表盘。
创建自定义仪表盘
按照以下步骤从 GCP 控制台创建自定义仪表盘:
-
导航到
VM Instance – Mean CPU Utilization。 -
选择图表类型或小部件。这将打开左侧窗格中的Metrics explorer,并将图表添加到仪表盘。
-
选择选项以选择资源类型、指标类型和分组标准。然后,保存仪表盘以添加图表类型。
-
重复上述步骤,将多个图表添加到同一仪表盘。
以下截图展示了一个自定义仪表盘,显示了所有虚拟机实例的平均 CPU 使用率,并包含七种可能的小部件类型:

图 10.6 – 自定义仪表盘,包含七种可能的小部件类型
本节结束后,我们将进入下一节,重点介绍如何使用Metrics explorer作为探索预定义和用户创建的指标的选项。
指标资源浏览器
指标是监控数据的关键来源之一。指标代表了资源使用或行为的数值测量,可以在系统中跨多个数据点以定期的时间间隔收集和观察。GCP 中大约有 1,000 个预创建的指标,包括 CPU 使用率、网络流量等。然而,一些更为精细的指标,如内存使用率,可以通过可选的监控代理进行收集。此外,用户可以通过内置的监控 API 或通过 OpenCensus(一种开源库)创建自定义指标。在创建自定义指标之前,始终建议先检查是否已存在默认或预创建的指标。
度量资源浏览器提供了探索现有度量的选项(包括预定义的或用户创建的),使用度量构建图表,向现有或新建的仪表盘添加图表,通过 URL 分享图表,或以 JSON 格式获取图表配置数据。度量资源浏览器是一个提供 DIY 方法的接口,您可以选择自己选择的度量来构建图表。
以下截图显示了度量资源浏览器部分,其中为虚拟机实例绘制了CPU 利用率度量,并按系统状态进行了分组。左侧显示配置区域,右侧显示所选度量的图表。配置区域有两个选项卡:
-
度量:此选项卡用于选择度量并进行探索。
-
查看选项:此选项卡用于更改图表的显示特性:

图 10.7 – 云监控 – 度量资源浏览器
以下部分讨论了使用度量资源浏览器配置度量的可用选项。
通过度量资源浏览器了解度量配置。
要为监控资源配置度量,我们可以使用以下选项。
资源类型和度量选项可以通过以下任一方式选择:
-
标准模式:选择特定的度量类型,或根据特定的 GCP 资源浏览可用的度量类型。
-
直接筛选模式:手动在文本框中输入度量类型和资源类型。
筛选器选项可用于根据筛选标准过滤结果。筛选标准可以使用可用操作符或正则表达式进行定义。筛选器有两种可能的类型:
-
project_id、instance_id和zone可作为可用的筛选选项。 -
按度量标签:指的是跨项目的用户创建标签。
按组选项可用于按资源类型和度量标签对时间序列数据进行分组。这将基于按组值的组合创建新的时间序列数据。
聚合器选项可用于描述如何对多个时间序列中的数据点进行聚合。常见的选项包括最小值、最大值、总和、计数和标准差。默认情况下,聚合结果会应用于所有时间序列,从而得到一条单一的线。如果选择了按组标签,聚合结果将为每个匹配标签组合生成一个时间序列。
周期选项可用于确定聚合发生的时间间隔。默认选择是 1 分钟。
对齐器选项可用于将每个单独时间序列中的数据点按相等的时间段对齐。
其他选项包括以下内容:
-
二级聚合器:用于包含多个度量的图表。
-
图例模板:为更好地阅读性。
可以使用多个查看选项来绘制度量图表,这些选项通过可用的图表模式进行区分,具体如下:
-
颜色模式:这是默认模式,其中图形线条以颜色显示。
-
X-Ray 模式:以半透明灰色显示图形线条,并在重叠区域中显示亮度。
-
统计模式:显示常见的统计值,如第 5 百分位数、第 95 百分位数、平均值、中位数等。
-
异常值模式:允许选择多个时间序列进行显示,并提供按升序或降序排列时间序列的选项。
此外,每种图表模式都支持指定特定的阈值,并允许比较过去的时间序列数据。此外,对于数据集中某些值远大于其他值的情况,可以将y轴应用对数刻度,以更好地区分较大的数值。
提示 - 监控查询语言(MQL)- 创建图表的高级选项
云监控支持MQL,这是一种使用基于文本的界面和表达性查询语言创建图表的高级选项,可以对时间序列数据执行复杂查询。潜在的用例包括选择时间序列的随机样本或计算请求比率,从而得出特定类别的响应代码。
本节介绍了指标浏览器,允许用户探索预定义和自定义指标。这些指标可以用于创建图表。与配置指标相关的选项也已详细讨论。接下来的部分将重点介绍在线检查——一种验证服务是否正常运行的选项。
在线检查
在线检查是一个云监控功能,通过定期请求监控资源,检查资源是否真正可用。在线检查可以检查 GCP 虚拟机、App Engine 服务、网站 URL 和 AWS 负载均衡器的可用性。在线检查也是跟踪服务错误预算的一种方式。在线检查本质上是在特定的超时区间内测试外部服务的可用性,确保服务的错误预算不会不必要地被耗尽。可以从一个或多个 GCP 地理区域发起这些测试,必须选择至少三个活跃的地理位置作为测试区域。或者,选择全球选项将从所有可用位置发起测试。
可以配置在线检查的执行频率,默认间隔为 1 分钟。在线检查支持多种协议选项,如 HTTP、HTTPS 和 TCP,并可针对以下资源类型进行定义:
-
URL:需要指定主机名和路径。
-
App Engine 服务:需要指定服务和路径。
-
实例:需要指定单个实例(GCP 或 EC2)或预定义组的路径。此组需要明确配置。
-
弹性负载均衡器:需要指定 AWS ELB 的路径。
创建正常运行时间检查的配置包括执行响应验证的选项。这些选项包括以下内容:
-
提供响应超时:这是请求完成所需的时间。必须在 1 到 60 秒之间,默认值为 10 秒。
-
启用响应内容:此选项允许您选择响应内容匹配类型,使用特定操作符来包含或不包含特定文本,或使用正则表达式匹配。
-
记录检查失败:此选项将保存与正常运行时间检查失败相关的所有日志到 Cloud Logging。
此外,在正常运行时间检查失败并持续一定时间的情况下,可以配置警报和通知。必须先存在警报策略,并且通知通道必须预先创建。下图显示了目标资源类型为 URL 的正常运行时间检查的汇总配置:

图 10.8 – 检查 URL 作为目标资源类型的正常运行时间
上述截图中使用的 URL 是作为 第八章的一部分创建的 hello-world-service 负载均衡器服务的 URL,理解 GKE 基础知识以部署容器化应用程序。配置的正常运行时间检查可能会导致失败。接下来的子章节列出了正常运行时间检查失败的潜在原因。
正常运行时间检查失败的潜在原因
以下是一些正常运行时间检查失败的潜在原因:
-
连接错误:找不到或没有响应的主机名/服务,或者指定的端口未打开或无效。
-
403(禁止访问服务),404(路径错误),和408(端口号错误或服务未运行)。 -
GoogleStackdriverMonitoring-UptimeChecks
这就是我们对正常运行时间检查的详细概述。接下来的主题将深入探讨警报——这是一个关键的云监控选项,适用于事件管理。警报提供了报告监控指标和适当地发送通知的选项。
警报
警报是处理警报规则的过程,这些规则跟踪 SLO(服务级别目标),并在规则违反时通知或执行某些操作。第三章,理解监控和警报以提高可靠性,深入探讨了警报,描述了警报如何将 SLO 转化为可操作的警报,讨论了关键的警报属性,并详细讲解了警报策略。Cloud Monitoring 中的警报 UI 提供了与当前触发的事件、已确认的事件、已配置的活动警报策略、开放和关闭的事件详情以及所有与事件相关的事件的信息。此外,警报还允许我们创建警报策略并配置通知通道。
配置警报策略
配置警报策略的步骤与使用 Metrics Explorer 创建图表的步骤非常相似。本质上,警报需要针对某个指标创建。配置警报包括通过 Metrics Explorer 添加指标条件并设置指标阈值条件。
指标阈值条件将定义具体的值。如果特定的指标值超过或低于阈值(根据策略定义的方式),则会触发警报,并通过配置的通知渠道通知我们。如果策略是通过控制台定义的,则使用策略触发字段;如果策略是通过 API 定义的,则使用组合器字段。
或者,要基于指标阈值条件定义警报策略,也可以基于指标缺失条件来定义警报策略。指标缺失条件定义为某个特定时间段内某个指标的时间序列数据不存在的条件。
重要说明 – 对齐周期是一个回顾间隔。
对齐周期是从某个特定时间点回顾的间隔。例如,如果对齐周期是 5 分钟,那么在下午 1:00 时,对齐周期包含了下午 12:55 到 1:00 之间接收到的样本。在下午 1:01 时,对齐周期滑动 1 分钟,并包含下午 12:56 到 1:01 之间接收到的样本。
下一节将描述用于发送与触发警报相关的特定信息的可用通知渠道。
配置通知渠道。
如果警报策略违反了指定的条件,则会创建一个状态为“打开”的事件。关于该事件的信息可以发送到一个或多个通知渠道。收到通知后,操作团队可以通过控制台确认该事件。这将把事件的状态更改为“已确认”。这表示事件正在被检查。如果在接下来的 7 天内条件不再被违反,或者该事件没有收到数据,则该事件最终将变为“已关闭”状态。
支持的通知渠道如下:
-
移动设备:应通过 Cloud Console 移动应用的事件部分注册移动设备。
-
PagerDuty 服务:需要一个服务密钥来进行身份验证和授权。
-
pagerduty.com及相应的 API 密钥用于身份验证和授权。 -
Slack:提示用户通过自定义 URL 进行身份验证和授权到 Slack 渠道,然后提示用户提供 Slack 渠道的名称。
-
Webhooks:需要端点 URL,并可选择使用 HTTP Basic Auth。
-
电子邮件:需要一个电子邮件地址,以便在创建新事件时接收通知。
-
短信:需要一个电话号码来接收通知。
-
service-[PROJECT_NUMBER]@gcp-sa-monitoring-notification.iam.gserviceaccount.com。应将pubsub.publisher角色添加到上述服务帐户,以通过 Cloud Pub/Sub 配置警报通知。
本节关于警报的内容到此结束,我们查看了如何配置警报策略和通知渠道。下一节介绍云监控代理。
监控代理
云监控提供许多默认指标,无需任何额外配置,例如 CPU 利用率、网络流量等。然而,更多细粒度的指标,如内存使用、网络流量等,可以通过可选的 collectd 守护进程(守护进程是指在后台运行的程序)从未管理的虚拟机或第三方应用程序收集,来收集来自操作系统、应用程序、日志和外部设备的系统统计信息。
监控代理可以安装在未管理的 GCE 虚拟机或 AWS EC2 虚拟机上。其他 Google 计算服务,如 App Engine、Cloud Run 和 Cloud Functions,内置支持监控,无需显式安装监控代理。GKE 也内置支持监控,并可以通过 Cloud Operations for GKE 启用,后者是一个集成的监控和日志记录解决方案,可以在新建或现有集群中启用。
从概念上讲,您必须遵循此过程,在未管理的虚拟机上安装/配置监控代理:
-
通过提供的脚本添加代理的包存储库,该脚本检测虚拟机上运行的 Linux 发行版并相应地配置存储库。
-
使用
stackdriver-agent代理安装监控代理以获取最新版本,或者使用stackdriver-agent-version-number安装特定版本。 -
重启代理以使已安装的代理生效。
在单个虚拟机/GCE 虚拟机/AWS EC2 实例上安装日志代理的逐步过程可以在 cloud.google.com/monitoring/agent/installation 中找到。至此,我们简要介绍了监控代理。下一小节提到了与云监控相关的可能访问控制。
云监控访问控制
以下表格总结了访问或执行云监控操作所需的关键 IAM 角色:

组 – 定义为监控组的资源集合
注意
云监控允许您创建监控组。这是查看 GCP 资源、事件、事故和可视化的关键指标的便捷方式,所有信息集中展示。监控组是通过定义一个或多个标准来创建的,这些标准可以是名称、资源类型、标签、安全组、云项目或区域。如果指定多个标准,则可以使用 OR/AND 运算符。
这部分内容总结了我们对云监控及其相关构件的深入探讨,如工作区、仪表板、指标探查器、正常运行时间检查、告警策略和访问控制。接下来的部分将详细介绍另一个属于云操作的 GCP 构件,专注于日志记录;即,云日志。
云日志
日志被定义为状态或事件的记录。日志记录本质上描述了发生了什么,并提供了数据,以便我们可以调查问题。在涉及多个服务和产品的分布式基础设施中,能够读取和解析日志至关重要。云日志是一个 GCP 服务,允许你存储、搜索、分析、监控以及针对来自 Google Cloud 和 AWS、第三方应用程序或自定义应用程序代码的日志数据和事件发送告警。日志条目中的信息以负载的形式结构化。该负载包含与时间戳、日志条目适用的资源以及日志名称相关的信息。日志条目的最大大小为 256 KB。每个日志条目都会指示资源的来源、标签、命名空间和状态码。云日志还是其他云操作服务(如云调试和云错误报告)的输入来源。
以下是云日志的主要特性:
-
审计日志:日志被捕获并分类为管理员活动、数据访问、系统事件和访问透明度日志,每个类别都有默认的保留期。
-
日志摄取:可以通过使用云日志 API 或通过日志代理从许多来源摄取日志,包括 GCP 服务、内部部署或外部云提供商。
-
日志探查器:可以通过引导式过滤配置或灵活的查询语言搜索和分析日志,从而实现有效的可视化。结果还可以以 JSON 格式保存。
-
基于日志的度量:可以从日志数据中创建度量,并通过指标探查器将其添加到图表/仪表板中。
-
日志告警:可以根据日志事件的发生以及基于日志创建的度量指标来创建告警。
-
日志保留:日志可以根据用户定义的标准保留自定义的保留期。
-
日志导出:可以将日志导出到云存储进行归档,导入到 BigQuery 进行高级分析,通过 Pub/Sub 进行基于事件的处理,使用 GCP 服务进行用户定义的云日志接收器,或启动外部第三方集成,以便通过 Splunk 等服务导出。
云日志的功能将在接下来的子章节中详细讨论,从审计日志开始。
审计日志
云审计日志是了解项目中某些部分的基础来源(谁做了什么,在哪里,何时做的?)。云审计日志为每个项目(包括文件夹和组织级别的信息)维护日志。云审计日志可以分为不同的类别。让我们来看一下。
管理活动日志
管理员活动日志特指任何修改资源配置或元数据的管理操作。管理员活动日志的示例包括但不限于以下内容:
-
设置或更改云存储存储桶的权限
-
分配/取消分配 IAM 角色
-
更改资源的任何属性,如标签/标签
-
创建/删除 GCE、GKE 或 Cloud Storage 资源
以下截图显示了创建 GCE VM 或存储桶时的管理员活动日志。访问这些活动日志的最简单方法是从 GCP 控制台首页的活动选项卡查看。这会拉取管理员活动日志的实时流,但默认不包括数据访问日志:

图 10.9 – 管理员活动日志
下一小节提供了与数据访问相关的审计日志类别概述。
数据访问日志
数据访问日志对于读取资源的配置或元数据非常有用。它还包括用户级别的 API 调用,这些调用会读取或写入资源数据。数据访问审计日志需要显式启用(Big Query 除外),并可以通过指定应捕获审计日志的服务来进行控制。此外,数据访问日志还可以针对由特定用户或用户组执行的操作进行豁免,从而提供细粒度的控制。数据访问日志可以进一步细分为三种子类型:
-
管理员读取:对服务元数据或配置数据的读取尝试。例如,列出可用的存储桶或列出集群中的节点。
-
数据读取:在服务内的数据读取尝试。例如,列出存储桶中的对象。
-
数据写入:向服务写入数据的尝试。例如,在存储桶中创建一个对象。
以下是通过 IAM 配置单个 GCP 服务的详细数据访问的截图 —— 审计日志 UI:

图 10.10 – 配置服务的 IAM 审计日志
上述截图还显示了配置豁免用户的选项。此选项允许您豁免某些用户的审计日志生成,具体取决于配置。数据访问日志可以通过 GCP 首页的活动选项卡查看,其中活动类型为数据访问,或者通过日志浏览器UI 查看(稍后会讨论)。下一小节提供了与系统事件相关的审计日志类别概述。
系统事件日志
系统事件日志在 Google 系统或服务对资源进行更改时使用。它们不是特定于用户对资源的操作。系统事件日志的示例包括但不限于以下内容:
-
自动重启或重置计算引擎
-
系统维护操作,例如迁移事件,由计算引擎执行,以将应用迁移到不同的主机。
下一小节提供了一个关于访问透明度的审计日志类别概述。
访问透明度日志
访问透明度日志是 Google 人员在访问用户/客户内容时使用的日志。通常这种情况发生在 Google 的支持团队在处理客户问题(例如某个服务未按预期工作或发生故障)时,因而需要访问客户的项目。如果你希望遵循法律和监管义务,这类日志至关重要。此外,你还可以追踪事件,回溯 Google 支持人员执行的操作。通过联系 Google 支持,你可以启用访问透明度日志,并且它们适用于客户支持级别,个人账户除外。一个例子是,支持人员在尝试解决 VM 实例的支持问题时访问的日志。
策略拒绝日志
策略拒绝日志是指当 Google Cloud 服务拒绝对某个用户或服务账户的访问时所捕获的日志。可以通过日志排除功能排除这些日志的摄取。
这一部分关于审计日志的内容已完成,我们提供了各种子类别的概述。在进入下一部分之前,先看一下下面的表格,表格列出了特定于访问日志的 IAM 角色:

下一部分将解释如何从多个源将日志摄取到 Cloud Logging 中。
日志摄取、路由和导出
Cloud Logging 支持从多个源摄取日志,例如审计日志、服务日志、应用日志、系统日志和平台日志。这些日志被发送到Cloud Logging API。Cloud Logging API 将传入的日志条目转发给一个名为日志路由器的组件。日志路由器的基本职能是将日志路由到其相应的目标。
这些目标可以分为四个可能的类别。日志路由器将检查传入的日志与现有规则,决定是否摄取(存储)、导出或排除这些日志,并将日志路由到四个目标类别中的一个。
这些目标类别如下:
-
_ 必需的日志存储桶 _:这是管理活动、系统事件和访问透明度日志的主要存储目标。这些日志不收费,并且该存储桶不能被修改或删除。
-
_ 默认日志接收器可以被禁用。 -
_Required日志桶和_Default日志桶。将日志写入用户管理的日志汇聚点的过程也可以被描述为 日志导出(如果目的是导出进行外部处理)或 日志保留(如果目的是从合规性角度导出以长期保留日志)。 -
_Default日志桶。换句话说,符合_Required日志桶条件的日志永远不能被排除。如果任何日志排除过滤器与符合_Default日志桶条件的条目匹配,则这些条目将被排除并且永远不会被保存。提示 – 什么是日志桶?
日志桶是 Google Cloud 项目中一种对象存储形式,用于通过 Cloud Logging 存储和组织日志数据。项目中生成的所有日志都存储在这些日志桶中。Cloud Logging 会在每个项目中自动创建两个桶:
_Required和_Default。_Required代表审核桶,其保留期为 400 天,而_Default代表其他所有桶,其保留期为 30 天。此外,用户还可以创建自定义日志桶,也称为用户管理的日志汇聚点。每个项目的日志桶可以通过 Logs Storage UI 在 Cloud Logging 中查看。也可以从 Logs Storage UI 发起其他操作,例如创建用户定义的日志桶和使用警报。
以下图示展示了如何通过 Cloud Logging API 从多个来源接收日志,并随后由日志路由器将其路由到可能的目标:

图 10.11 – 描述日志接收和日志路由
导出日志需要遵循三个步骤:
-
创建一个汇聚点。
-
创建一个表示导出日志筛选标准的过滤器。
-
创建目标 – Cloud Storage 桶、BigQuery 或 Pub/Sub 主题。
创建/修改/查看汇聚点的 IAM 角色
创建或修改汇聚点需要拥有 Owner 或 Logging/Logs Configuration Writer 角色。查看现有汇聚点需要拥有 Viewer 或 Logging/Logs Viewer 角色。Project Editor 角色无法创建或编辑汇聚点。
总结来说,日志可以来自多个来源,例如本地环境、Google Cloud 或第三方云服务。这些日志通过 Cloud Logging API 注入到 Cloud Logging,然后发送到 Logs Router。Logs Router 会根据配置的过滤器,将日志路由到日志存储桶(_Required 或 _Default 存储桶)。此外,基于配置的过滤器条件,日志的副本可以发送到用户管理的存储桶,目标可以是 Cloud Storage、BigQuery 或 Pub/Sub。日志导出可用于多种用途,如出于合规原因进行长期保留(使用 Cloud Storage)、大数据分析(使用 BigQuery),或将日志流式传输到其他应用程序(使用 Pub/Sub)。如果这些日志被发送到 Pub/Sub 消息服务,它们可以被导出到 Google Cloud 以外的第三方工具,如 Splunk、Elastic Stack 或 SumoLogic。需要注意的是,配置的日志存储桶只会捕获新日志,因为导出是新创建的,不会捕获之前的日志或补充日志。
如何跨文件夹/组织导出日志
可以从特定文件夹或组织中的所有项目导出日志。目前只能通过命令行使用 gcloud logging sink 的 create 命令来完成此操作。除了存储桶的名称、目标和日志过滤器外,命令还应包括 --include-children 标志,并且需要指定 --folder 或 --organization 属性及其相应的值。
本小节关于日志摄取、路由和导出的内容已完成。接下来的小节将以表格形式总结日志存储桶中的日志特性,便于理解。
总结日志存储桶中的日志特性
每种日志类型都会分配到特定的 Cloud Logging 存储桶。此外,每种日志类型在访问日志所需的最低 IAM 角色、默认保留期以及自定义保留期配置能力方面都有特定的特点。以下表格详细说明了相关信息:

所有其他日志
这指的是通过日志代理生成的用户日志,或由 GCP 服务、VPC 流量日志或防火墙日志生成的平台日志。
除了前面的表格外,还需要注意以下几点:
-
系统事件日志由系统发起,而管理员活动、数据访问和访问透明度日志由用户发起。
-
管理员活动日志和系统事件日志记录资源配置的更改,而数据访问日志记录的是记录内部所做的更改。
-
管理员活动、系统事件和访问透明度日志始终启用。
本节关于日志摄取的概述已完成。下一个主题聚焦于 Logs Explorer 用户界面,用户可以通过该界面探索摄取的日志。
Logs Explorer 用户界面
日志资源管理界面(Logs Explorer UI) 是查看通过 Cloud Logging API 导入到 Cloud Logging 中的日志的集中方式,最终通过 Cloud Router 路由到 Cloud Logging 存储桶或用户管理的接收端。该界面允许我们通过编写高级搜索查询来筛选日志,通过配置时间窗口来可视化时间序列数据,并执行关键操作来创建基于日志的指标或创建用户。该界面包含多个选项和部分,如下所示的屏幕截图所示:

图 10.12 – 日志资源管理界面
要通过日志资源管理界面筛选 Cloud 审计日志,请为 日志名称 字段选择以下选项:
-
cloudaudit.googleapis.com%2Factivity -
cloudaudit.googleapis.com%2Fdata_access -
cloudaudit.googleapis.com%2Fsystem_event
让我们来看看在日志资源管理界面中导航选项时的一些关键重要信息。
查询构建器
本部分构建查询以筛选日志。查询可以通过选择适当的字段和值组合,用查询构建器语言表示,如以下屏幕截图所示。用户可以通过两种方式提供输入:
-
通过选择有关 资源、日志名称 和 严重性 的下拉菜单中的选项。这是基本的查询界面。
-
通过从 日志字段 部分选择字段,开始时选择 资源 类型或 严重性 类型。这是高级查询界面:

图 10.13 – 日志资源管理界面下的查询构建器部分
查询结果
本部分显示与查询构建器中定义的筛选标准匹配的结果。如果匹配,则结果以一行或多行的形式显示。每一行代表一个日志条目,如下所示:

图 10.14 – 查询结果部分
日志条目
返回的每个查询结果都是一个日志条目,显示有时间戳和摘要文本信息。当展开时,日志条目会以 JSON 负载格式显示更多细节。JSON 负载有多个字段,并且可以通过 展开嵌套字段 选项进行详细说明。此外,用户可以将负载复制到剪贴板,或通过复制共享链接来共享特定的负载,如下所示:

图 10.15 – 查看日志条目的 JSON 负载
特定负载的操作
有多个选项执行操作,针对特定负载和字段,如下屏幕截图所示。具体如下:
-
显示匹配条目:将从 JSON 负载中选择的键值对添加到现有筛选条件中,并在配置的时间窗口内显示匹配的条目。
-
隐藏匹配条目:将选定的键值对从 JSON 负载添加到现有的过滤器条件中,以否定形式出现,并在配置的时间窗口内从用户显示中移除匹配条目。
-
将字段添加到摘要行:将选定的键添加到摘要部分:

图 10.16 – 针对特定字段的可能负载特定操作
页面布局
此选项允许用户配置页面布局,并可以选择包含 日志字段 和/或 直方图。查询构建器 和 查询结果 是必填部分,不能排除:

图 10.17 – 页面布局部分的选项
操作(执行查询过滤器)
操作允许用户在查询过滤器定义的潜在结果上进行操作。包括 创建度量、下载日志 和 创建接收器:

图 10.18 – 在查询过滤器上可以执行的操作
这完成了关于日志资源管理器和所有可能的 UI 选项用于过滤和分析日志的部分。下一部分将概述 基于日志的度量。
基于日志的度量
基于日志的度量 是基于日志条目内容创建的 Cloud Monitoring 度量。它们可以从包括和排除的日志中提取。当找到匹配的日志条目时,与度量相关的信息会随着时间的推移逐步构建。这形成了度量所需的时间序列数据,至关重要。基于日志的度量用于创建 Cloud Monitoring 图表,也可以添加到 Cloud Monitoring 仪表板中。
重要提示
使用基于日志的度量需要启用计费的 Google Cloud 项目。此外,基于日志的度量会在创建度量后记录匹配的日志条目。对于已经存在于 Cloud Logging 中的日志条目,不会回填度量。
基于日志的度量可以分为以下几种类型:
-
系统(基于日志的)度量
-
用户定义的(基于日志的)度量
这两种基于日志的度量将在接下来的子章节中介绍。
系统(基于日志的)度量
系统(基于日志的)度量 是 Google 提供的开箱即用的预定义度量,且非常特定于当前项目。这些度量记录在特定时间段内发生的事件数量。可以在 Cloud Operations 的 Logging 部分的 基于日志的度量 UI 中找到可用的系统(基于日志的)度量列表。示例如下:
-
byte_count:表示日志条目中接收的总字节数
-
excluded_byte_count:表示日志条目中排除的字节总数
用户可以从预定义的度量标准创建警报,或在度量标准资源管理器中查看度量标准的详细信息及其当前值:

图 10.19 – 系统(基于日志的)度量标准及其合格操作
下一部分将概述用户定义的度量标准。
用户定义(基于日志的)度量标准
用户定义(基于日志的)度量标准,顾名思义,是由用户定义的,且特定于用户配置这些度量标准的项目。这些度量标准可以是计数器或分布类型:
-
计数器:计算与查询匹配的日志条目的数量
-
分布:累积与查询匹配的日志条目的数值数据
用户可以通过基于日志的度量标准 UI的创建度量标准操作,或通过查询结果上方的操作菜单在日志浏览器 UI中创建用户定义的度量标准。一旦用户启动这些操作,他们可以在度量标准编辑器面板中选择度量标准的类型,即计数器或分布。
此外,用户还需要配置度量标准的名称、描述以及任何可选的标签和单位,例如s、ms等。

图 10.20 – 创建基于日志的度量标准
有关创建分布式度量标准的更多细节,请参考cloud.google.com/logging/docs/logs-based-metrics/distribution-metrics。
基于日志的度量标准的访问控制
下表展示了访问或执行与基于日志的度量标准相关的操作所需的关键 IAM 角色,以及它们的最小权限(根据最小权限原则):

以下部分将通过探索 Google Cloud 上可用的基于网络的日志类型,来结束这一部分的 Cloud Logging 介绍。
基于网络的日志类型
有两种基于网络的日志类型,主要捕获与网络交互相关的日志。它们如下:
-
VPC 流日志
-
防火墙日志
让我们详细了解它们。
VPC 流日志
VPC 流日志捕获启用子网上的 VPC 资源的实时网络活动(传入/传出)。流日志仅捕获 TCP/UDP 协议的活动,并且在 VPC 子网级别启用。流日志会生成大量收费的日志文件,但它们并不能捕获 100%的流量;相反,流量是按照 1/10 的数据包进行采样,且无法调整。流日志用于网络监控——以预测流量增长,以及用于取证——评估网络流量(进/出)的流量来源。流日志可以导出到 BigQuery 进行分析。在共享 VPC 的情况下——多个服务项目连接到一个公共 VPC——流日志流向主项目,而不是服务项目。
防火墙日志
防火墙日志捕获特定防火墙规则的效果,记录该规则允许或拒绝的流量。类似于 VPC 流日志,防火墙日志仅捕获 TCP/UDP 流量,主要用于审计、验证和分析已配置规则的效果。防火墙日志可以为单个防火墙规则进行配置。防火墙规则应用于整个 VPC,不能像流日志那样应用于特定子网。防火墙日志力求尽可能捕获每个防火墙连接尝试。防火墙日志也可以导出到 BigQuery 进行进一步分析。
每个 VPC 都有一组隐藏的预配置规则,最低优先级为65535。防火墙规则的优先级可以在0到65535之间(0表示最高,65535表示最低)。这些规则如下:
-
deny all ingress:默认情况下,这拒绝所有传入 VPC 的流量。 -
allow all egress:默认情况下,这允许所有从 VPC 发出的传出流量。
然而,防火墙日志无法为隐藏规则启用。因此,为了捕获被拒绝的传入流量或被允许的传出流量,建议显式配置一条适当优先级的防火墙规则,用于控制被拒绝/允许的流量,并在该规则上启用防火墙日志。
本节介绍了基于网络的日志类型,涵盖了 VPC 流日志和防火墙日志。
日志代理
fluentd —— 一种开源日志或数据收集器。日志代理可以安装在未管理的 GCE 虚拟机或 AWS EC2 虚拟机上。其他 Google 计算服务,如 App Engine、Cloud Run 和 Cloud Functions,已内置日志支持,无需显式安装日志代理。GKE 也有内置的日志支持,可以通过GKE 的 Cloud Operations启用,无论是新集群还是现有集群,都可以使用这一集成的监控和日志解决方案。
要配置日志代理,您必须配置一个额外的配置文件,但一个配置文件作为捕获所有类型日志的通用配置,包括操作系统日志和第三方应用程序日志(如 Apache、MySQL、Nginx、RabbitMQ 等)。然而,在某些场景下,代理的配置文件需要修改,以便我们可以修改日志。这些场景如下:
-
在重新格式化日志字段时,可以改变顺序或将多个字段合并为一个
-
在移除任何个人身份信息(PII)或敏感数据时
-
当使用
fluentd插件(例如filter_record_transformer)修改记录时,该插件用于在将日志发送到 Cloud Logging 之前,添加/修改/删除日志中的字段。
从概念上讲,以下是安装/配置代理在 GCE 虚拟机上的过程:
-
通过提供的脚本添加代理的包仓库,该脚本会检测虚拟机上运行的 Linux 发行版,并相应地配置仓库。
-
安装日志代理,并安装
google-fluentd-catch-all-config代理用于非结构化日志记录,安装google-fluentd-catch-all-config-structured代理用于结构化日志记录。 -
重启代理以使已安装的代理生效。
安装单个虚拟机/GCE 虚拟机/AWS EC2 实例上的日志代理的详细过程,请参考 cloud.google.com/logging/docs/agent/installation。
这完成了我们对日志代理的高级概述。接下来,这也完成了 Cloud Logging 部分,我们回顾了审核日志类型、日志采集、日志浏览器 UI、基于日志的指标和访问控制等功能。下一部分将深入探讨云调试器,这是 Cloud Operations 提供的一个 GCP 构造,可以通过拍摄应用程序快照来检查生产应用程序,而无需停止或减慢其速度。
云调试器
云调试器允许我们实时检查运行中应用程序的状态。云调试器不需要在此过程中停止应用程序,也不会让应用程序变慢。用户可以在源代码的任何位置捕获调用堆栈和变量。这本质上使用户能够分析应用程序状态,尤其是在复杂情况下,而无需添加额外的日志语句。
此外,云调试器可用于生产环境,而不限于开发或测试环境。当云调试器捕获应用程序状态时,它增加的请求延迟小于 10 毫秒,从实际角度来看,用户几乎不会察觉到。
Cloud Debugger 支持运行在 GCP 上的应用程序,如 App Engine、Compute Engine、GKE、Cloud Run 等,以及使用多种语言编写的应用程序,包括 Java、Python、Go、Node.js、Ruby、PHP 和 .NET。Cloud Debugger 需要访问应用程序代码,并支持从 App Engine、Google Cloud 源代码库或第三方代码库(如 GitHub、Bitbucket 等)读取代码。
设置 Cloud Debugger
启用/设置 Cloud Debugger 涉及以下基本步骤:
-
每个项目需要一次性启用 Cloud Debugger API。
-
提供适当的访问权限,确保 Cloud Debugger 将运行的 GCP 服务可以上传遥测数据或调用 Cloud Debugger。
-
App Engine 和 Cloud Run 必须已为 Cloud Debugger 配置。
-
运行在 Compute Engine、GKE 或外部系统中的应用程序需要拥有 Cloud Debugger Agent 角色的服务账户。
-
如果应用程序运行在 Compute Engine 虚拟机或集群节点,并且使用默认服务账户,则应将以下访问范围添加到虚拟机或集群节点:
www.googleapis.com/auth/cloud-platform和www.googleapis.com/auth/cloud_debugger。 -
选择源代码位置。如果无法访问源代码,可以拍摄一个调试快照,捕获调用堆栈和局部变量。
-
如果可以访问源代码,则 App Engine standard 会自动选择源代码。App Engine flex、GCE、GKE 和 Cloud Run 会根据应用程序根目录中的配置文件自动选择源代码;即
source-context.json文件。 -
或者,可以从可选的源代码位置中选择一个,包括本地文件、Cloud Source Repositories、GitHub、Bitbucket 和 GitLab。
-
要从应用程序代码启用 Cloud Debugger,必须遵循特定于应用程序编写语言的指令。以下是一个示例代码片段:
try: import googleclouddebugger googleclouddebugger.enable() except ImportError: pass
现在我们已经设置好了 Cloud Debugger,让我们学习如何使用它。
使用 Cloud Debugger
使用 Cloud Debugger 涉及了解调试快照、调试日志点和访问日志面板的功能。
调试快照
快照捕获应用程序源代码中特定位置的局部变量和调用堆栈。在拍摄快照之前的基本步骤是设置断点。断点生效大约需要 40 秒。Cloud Debugger 的断点不会停止代码执行。当执行流经过调试点时,会拍摄一个非侵入性的快照。可以添加额外的条件,只有在数据条件通过时,才会拍摄快照。捕获的快照将包含局部变量的详细信息和调用堆栈的状态。
在下面的截图中,断点被设置在特定文件的第 39 行。该断点有一个限定条件,如果条件满足,则会拍摄快照。变量的详细信息会显示在变量部分:

图 10.21 – 在云调试器中拍摄调试快照
在配置快照时,表达式也可以作为可选项包含在内。表达式可以作为特殊变量,在拍摄快照时评估值。在那些通常不会通过本地变量捕获的值场景中,表达式尤为有用。
在下面的截图中,我们可以看到在配置快照时定义了多个表达式,并在拍摄快照时捕获了这些表达式:

图 10.22 – 在配置快照时定义表达式
以下是与快照相关的一些关键指针:
-
快照只会拍摄一次。要捕获同一位置代码中的另一个应用程序数据快照,用户需要通过快照面板中的相机图标手动重新拍摄快照。
-
可以通过点击断点上的x图标手动移除快照位置。
-
云调试器会为每个拍摄的快照生成一个新的 URL,并且该 URL 从拍摄时间起有效期为 30 天。这个 URL 可以与项目中的其他成员共享。
下一个小节提供了调试日志点的概述,以及如何将它们注入正在运行的应用程序。
调试日志点
在解决复杂问题时,添加日志消息是一种常见做法。在这种情况下,开发人员通常会对生产环境中的代码进行更改,实质上是添加额外的日志语句来帮助分析。如果问题比较复杂,这个过程需要重复多次,这意味着生产代码需要进行多次更改,以包括日志语句。云调试器不同于传统的调试方法,提供了一种动态方式,通过调试日志点来添加日志消息。
调试日志点可以在不停止、编辑或重启应用程序的情况下将日志注入正在运行的应用程序。日志点按照开发者的需求,添加到指定的位置。当这部分代码被执行时,云调试器会记录一条日志消息,并将该日志消息发送到托管应用程序的相应服务中。因此,如果应用程序托管在 App Engine 上,日志消息可以在与 App Engine 相关的日志中找到。
在下图中,已添加带有条件的日志点,并将消息日志级别设置为信息。指定条件与日志点一起使用的概念称为日志点条件。这是一个应用语言中的表达式,必须评估为真,才能记录日志点。每次执行该特定行时,如果日志点有效,都会评估日志点条件:

图 10.23 – 通过 Cloud Debugger 添加调试日志点
以下是与日志点相关的一些关键提示:
- 即使无法直接访问源代码,仍然可以创建日志点。可以通过指定文件名、创建日志点的行号、日志级别、可选条件和适当的消息来创建日志点,如下所示:

图 10.24 – 配置没有源代码访问权限的日志点
-
日志点在创建后 24 小时变为不活跃,此后与这些日志点相关的消息将不会被评估或记录。
-
日志点会在创建后 30 天自动删除。用户还可以选择手动删除日志点。
下一子节展示了日志面板的使用和可用选项。
日志面板
Cloud Debugger 包括一个页面内的日志面板,显示当前正在检查的应用程序的运行日志。这样,开发人员可以在相应代码旁边查看日志。用户可以使用日志面板进行搜索变体,包括基于文本的搜索,还可以按日志级别、请求或文件进行过滤。搜索结果会在上下文中高亮显示,或显示在日志查看器中:

图 10.25 – 在 Cloud Debugger 中查看调试日志的日志面板
接下来的子节提供了对 Cloud Debugger 所需访问控制的概述。
Cloud Debugger 的访问控制
下表展示了访问或执行与 Cloud Debugger 相关操作所需的关键 IAM 角色及其最小权限(符合最小权限原则):

提示 – 如何在调试时隐藏敏感数据
Cloud Debugger 在 Pre-GA 中有一个功能,通过配置文件可以隐藏敏感数据。该配置文件包含一系列规则,这些规则可以表示为 黑名单 或 黑名单例外(以指定反向模式)。如果符合条件,则数据将被隐藏,并且调试器会将其报告为管理员屏蔽。此功能目前仅支持 Java 编写的应用程序。
本节介绍了 Cloud Debugger,我们学习了如何设置 Cloud Debugger,利用调试日志点添加日志消息,并创建快照以捕获调用堆栈及其本地值。我们查看了日志面板中可用的选项,并了解了执行与 Cloud Debugger 相关操作所需的访问控制。在下一节中,我们将查看 Cloud Trace,它是 Cloud Operations 的一部分,代表一个分布式跟踪系统,收集来自应用程序的延迟数据以识别瓶颈。
Cloud Trace
trace 是一组 spans 的集合。span 是一个对象,它将延迟特定的度量和其他上下文信息包裹在应用程序中的一项工作单元周围。Cloud Trace 是一个分布式跟踪系统,捕获来自应用程序的延迟数据,跟踪请求的传播,获取实时性能洞察,并在 Google Cloud Console 中显示结果。这些延迟信息可以是单个请求的,或者可以是整个应用程序的聚合信息。这些信息帮助我们识别性能瓶颈。
此外,Cloud Trace 还可以自动分析可能反映最近应用程序性能变化的应用程序 traces,识别来自延迟报告的性能下降,捕获来自容器的 traces,并根据需要创建警报。
Cloud Trace 提供了针对 Java、Node.js、Ruby 和 Go 的特定语言 SDK。这些 SDK 可以分析运行在虚拟机上的项目。这些虚拟机不一定必须仅在 Google Cloud 上运行。除了 SDK 之外,还可以使用 Trace API 提交和检索来自任何来源的 trace 数据。可以使用 Zipkin 收集器,允许 Zipkin 跟踪器将数据提交到 Cloud Trace。此外,Cloud Trace 还可以使用 OpenCensus 或 OpenTelemetry 工具生成 trace 信息。Cloud Trace 由三个主要部分组成:Trace Overview、Trace List 和分析报告。我们来详细看看它们。
Trace Overview
Trace Overview 页面提供跨多个信息窗格分布的延迟数据摘要:
-
洞察:显示性能洞察的列表(如果适用)
-
最近的 Traces:突出显示项目的最新 traces
-
频繁的 URI:显示过去 7 天内对应用程序最频繁的请求及其平均延迟的 URI 列表
-
频繁的 RPC:显示过去 7 天内最频繁调用的 RPC 及其平均延迟列表
-
可计费的 trace spans:总结了当前和前一个月由 Cloud Trace 创建和接收的 trace spans 数量:

图 10.26 – 从 Trace Overview 页面查看可计费的 trace spans
下一小节提供了追踪列表窗口的概览,可以用来详细检查追踪。
追踪列表
追踪列表窗口允许用户查找、筛选并详细检查单个追踪。这些追踪以热图的形式显示,如果希望查看特定窗口片段中的追踪,可以选择热图的特定部分:

图 10.27 – 过去 30 天内按 POST 方法筛选的所有追踪列表
点击单个追踪(由圆圈表示)可查看该追踪的详细信息。它以瀑布图的形式呈现:

图 10.28 – 单个追踪的瀑布图
下一小节提供了关于请求延迟的追踪分析报告概览。
分析报告
分析报告展示了所有请求或某一子集请求相对于应用程序的延迟的整体视图。这些报告分为每日报告或自定义分析报告。
每日报告
Cloud Trace 会自动为前三个端点创建每日报告。Cloud Trace 会将前一天的性能与前一周同一天的性能进行对比。报告内容无法由用户控制。
自定义分析报告
用户可以创建自定义分析报告,报告内容可以通过控制哪些追踪被包括来进行定制。报告可以包含延迟数据,以直方图或表格格式显示,并提供指向示例追踪的链接。报告还可以选择包含瓶颈面板,列出对延迟有重大影响的远程过程调用(RPCs)。
自动生成或手动创建追踪报告的条件
要使每日报告自动生成,或者用户在特定时间范围内创建自定义报告,必须确保在该时间段内至少有 100 个追踪可用,否则将无法生成追踪报告。
本节内容完成了关于 Cloud Trace 的介绍,Cloud Trace 是一个 GCP 构造,用于表示分布式追踪系统,收集应用程序的延迟数据并识别性能瓶颈。下一节将重点介绍 Cloud Profiler,这是 Cloud Operations 的一项服务。Cloud Profiler 是一个低影响的生产性能分析系统,通过交互式火焰图呈现调用层次和资源消耗。
Cloud Profiler
Cloud Profiler 提供低影响的持续性能分析,帮助用户了解生产系统的性能。它提供诸如 CPU 使用率、内存消耗等信息的见解。Cloud Profiler 允许开发人员分析运行在 Google Cloud、其他云提供商或本地部署的应用程序。
云性能分析器使用统计技术和极低影响的插桩方式,提供应用程序性能的完整图景,而不会拖慢其运行速度。云性能分析器可以在所有生产应用实例中运行,呈现调用层次结构,并通过交互式火焰图解释相关功能的资源消耗。这些信息对开发者至关重要,可以帮助他们了解哪些路径消耗了最多资源,并展示代码的实际调用方式。支持的编程语言包括 Java、Go、Node.js 和 Python。
云性能分析器支持以下类型的配置文件:
-
CPU 时间:CPU 执行一段代码所花费的时间。此时间不包括 CPU 等待或处理其他任务的时间。
-
堆:堆或堆使用量是指在收集配置文件时,分配给程序堆的内存量。
-
分配堆:分配堆或堆分配是指程序堆中分配的总内存量,包括已释放并不再使用的内存。
-
竞争:竞争提供了关于被卡住的线程和等待其他线程的线程的信息。理解竞争行为对代码设计至关重要,并提供了性能调优的依据。
-
线程:与线程相关的信息提供了关于已创建但未实际使用的线程的洞察。这为识别泄漏的线程奠定了基础,其中线程数量不断增加。
-
墙时间:墙时间是执行一段代码所需的时间,包括等待时间。墙时间永远不会少于 CPU 时间。
以下截图总结了按语言支持的配置文件类型:

图 10.29 – 按语言支持的配置文件类型
以下截图展示了性能分析器界面,描绘了CPU 时间配置文件类型的示例交互式火焰图。配置文件数据保留 30 天,并且配置文件信息可以下载以进行长期存储:

图 10.30 – 设置为 CPU 时间的交互式火焰图
接下来的子节将解释执行与云性能分析器相关的操作所需的访问控制。
云性能分析器的访问控制
下表展示了访问或执行与云性能分析器相关操作所需的关键 IAM 角色及其最小权限(遵循最小权限原则):

本节内容已结束,涵盖了云性能分析器支持的配置文件类型,并学习了如何使用交互式火焰图。
绑定 SRE 和云操作
第二章,SRE 技术实践 – 深入分析,介绍了 SRE 技术实践,如 SLA、SLO、SLI 和错误预算。总结来说,本章建立了这些实践之间的关系,并将它们直接与服务的可靠性挂钩。为了确保服务满足其 SLA,服务需要可靠。SRE 建议使用 SLO 来衡量服务的可靠性。SLO 需要 SLIs 来评估服务的可靠性。如果这些 SLIs 未达标,则 SLO 将无法达到目标。这将最终消耗错误预算,错误预算是计算可接受的不可用或不可靠水平的衡量标准。第三章,理解监控和警报以目标可靠性,介绍了与监控、警报、日志记录和跟踪相关的概念,并阐明了这些在跟踪服务可靠性中的关键作用。然而,这两章的内容更多是概念性内容。
本章的重点是云操作(Cloud Operations)。到目前为止,我们已经描述了 Google Cloud 如何捕获监控指标、日志信息和跟踪数据,并允许我们调试应用程序或服务。此外,Cloud Operations 提供了一项名为 SLO 监控的选项。该选项允许您定义并跟踪服务的 SLO(服务级别目标)。目前,该选项支持三种自动导入的服务类型:Anthos Service Mesh、GKE 上的 Istio 和 App Engine。不过,该选项也支持用户自定义微服务。下一小节将深入探讨 SLO 监控。
SLO 监控
鉴于 SLO 是使用 SLI 进行衡量的,且 SLO 被定义为衡量服务可靠性的可量化指标,且这些指标会随时间变化,定义 SLO 通过 SLO 监控有三个具体步骤。如下所示:
-
设置 SLI
-
定义 SLI 细节
-
设置 SLO
让我们更详细地看一下这些步骤。
设置 SLI
这是第一步,有两个具体目标:选择一个作为 SLI 的指标,并选择衡量该指标的评估方法。
选择一个指标
SLO 监控允许您选择 可用性 或 延迟 作为 Anthos Service Mesh、GKE 上的 Istio 和 App Engine 配置的服务的开箱即用的 SLI。这些选项不适用于未通过前述选项配置的 GKE 上的微服务,这些通常被称为自定义服务。然而,无论服务如何配置,您都有选择 其他 的选项。在这里,用户可以选择自己跟踪的指标作为 SLI。
基于请求或基于窗口
有两种评估方法可以选择,这将影响如何衡量与 SLI 的合规性。这些方法是基于请求的和基于时间窗口的。基于请求的选项计算单个事件,并评估服务在合规期内的表现,而不考虑负载如何分配。另一方面,基于时间窗口的选项则根据时间来衡量性能(良好时间与不良时间),而不管负载如何分配。
定义 SLI 细节
这是第二步,提供了供用户选择的性能指标选项。用户可以选择使用 Cloud Monitoring 中的预定义指标,或者使用通过日志(通过基于日志的指标)创建的任何用户自定义指标。一旦选择了某个指标,就需要定义该指标的性能标准。与 Anthos Service Mesh、GKE 上的 Istio 和 App Engine 相关的服务的性能标准是预定义的。然而,对于自定义服务,用户需要通过使用三个过滤器选项中的两个——Good(良好)、Bad(不良)和Total(总数)——手动定义。
设置 SLO
这是第三步也是最后一步,具有两个特定目标:设置合规期和设置性能目标。
合规期
合规期选项允许你设置一个时间段来评估 SLO。可以选择两种方式:
-
Calendar:性能从周期开始时开始测量,每个新周期开始时会进行硬重置。周期长度的可选项有:日历日、日历周、日历两周和日历月。
-
Rolling:性能是在固定的时间段内进行测量;例如,过去 10 天。用户可以指定固定的天数作为时间段。
现在,让我们来看一下如何设置性能目标。
性能目标
性能目标表示在合规期内设定的目标,即良好服务与需求服务的比例。随着系统行为信息的增多,这个目标可以进一步细化。
这完成了我们对 SLO 监控的概述,我们可以使用它来定义 SLO 以衡量服务的可靠性。下一小节提供了如何针对 GKE 服务(我们之前在第八章中创建的服务,理解 GKE 基础知识以部署容器化应用)配置 SLO 监控的实践演示。
实践实验 – 使用 SLO 监控跟踪服务可靠性
SLO 监控允许我们将 SRE 技术实践与 Google Cloud 中可用的实际选项联系起来。这些帮助我们监控服务的可靠性,并在服务未达到可靠性阈值时,提醒值班工程师。
本小节是一个动手实验,将展示如何使用 Cloud Monitoring 中的 SLO 监控选项。SLO 监控选项通过定义 SLO 来跟踪服务的可靠性。在本实验中,我们将使用hello-world-service,这是在第八章《了解 GKE 基本知识以部署容器化应用程序》中创建的my-first-cluster GKE 集群中的一个服务。这个实验有三个主要目标:
-
为服务定义 SLO
-
创建一个 SLO 烧录率警报策略
-
验证 SLO 监控
让我们更详细地了解这些目标。
为服务定义 SLO
按照以下步骤为hello-world-service定义 SLO:
-
从
my-first-cluster集群中的hello-world-service部分导航,如下图所示。将显示名称设置为hello-world-service。系统将创建需要监控的服务,并将用户导航到服务概览仪表板:![图 10.31 – 通过选择自定义服务来定义服务]()
图 10.31 – 通过选择自定义服务来定义服务
-
选择创建 SLO操作以定义 SLO。此操作将打开一个弹出窗口,如以下截图所示。请注意,正如在第二章《SRE 技术实践深入解析》中讨论的那样,SLO 需要一个 SLI。因此,要定义 SLO,我们必须先选择 SLI 指标,然后定义它。
-
由于本实验使用的服务不属于 Anthos Service Mesh、GKE 上的 Istio 或 App Engine,因此唯一可选项是选择其他。在这里,用户可以配置一个选择的指标来衡量服务的性能。此外,将评估方法设置为基于请求:
![图 10.32 – 作为 SLO 监控的一部分设置 SLI]()
图 10.32 – 作为 SLO 监控的一部分设置 SLI
-
要定义 SLI 的详细信息,请选择一个性能指标。在此案例中,我们将选择
kubernetes.io/container/restart_count指标。将过滤器设置为总计和坏,如图所示:![图 10.33 – 作为 SLO 监控的一部分定义 SLI 详细信息]()
图 10.33 – 作为 SLO 监控的一部分定义 SLI 详细信息
-
选择合规周期;即,选择
90%,如图所示:![图 10.34 – 作为 SLO 监控的一部分设置 SLO]()
图 10.34 – 作为 SLO 监控的一部分设置 SLO
-
审查配置并通过提供适当的显示名称保存它,例如
90% - 重启计数 - 日历日,如图所示:![图 10.35 – 审查并保存 SLO,作为 SLO 监控的一部分]()
图 10.35 – 审查并保存 SLO,作为 SLO 监控的一部分
-
保存后,SLO –
90% - 重启计数 - 日历天– 将在hello-world-service服务下创建,如下截图所示。此时,错误预算为 100%,因为没有容器被重启:

图 10.36 – 为服务创建的 SLO,作为 SLO 监控的一部分
通过此步骤,我们已经学习了为服务定义 SLO 所需的步骤。在下一个主题中,我们将探讨创建 SLO 燃烧速率警报策略的步骤。
创建 SLO 燃烧速率警报策略
本章之前讨论的 Cloud Monitoring 中的警报和通知渠道概念将用于创建警报。在我们查看相关步骤之前,让我们回顾一下在 第三章 中讨论的重要术语,了解监控与警报以确保可靠性。在通过 Cloud Monitoring 定义警报时,必须配置这些元素:
-
回溯时长指的是要回溯多长时间才能获取监控数据。
-
快速燃烧警报指使用较短的回溯时长来帮助快速检测问题。然而,这会导致警报触发更频繁,并且可能会出现误报。
-
慢燃警报指使用较长的回溯时长来确保问题存在的时间较长,避免误报。然而,缺点是警报会在更长时间后触发,尽管问题当前对服务造成了负面影响。
按照以下步骤设置当 SLO 的错误预算在指定时间内超过某一燃烧速率时触发警报:
-
点击
1分钟和10分钟。以下是我们为快速燃烧警报配置的内容:![图 10.37 – 设置 SLO 警报条件]()
图 10.37 – 设置 SLO 警报条件
-
选择一个已经预先配置好的通知渠道。在此案例中,选择电子邮件通知渠道,如下图所示:
![图 10.38 – 选择通知渠道以发送警报]()
图 10.38 – 选择通知渠道以发送警报
现在,创建 SLO 燃烧速率警报策略。可选择添加文档,指明在发生警报时,现场 SRE 工程师应检查或执行的操作。
-
配置完警报后,SLO 状态将如下所示,其中 错误预算 当前为 100%,且没有警报触发:

图 10.39 – 显示完整的 SLO 监控设置,包括其警报和初始错误预算
这样,我们创建了一个 SLO 燃烧速率警报策略。现在,让我们通过执行测试来验证 SLO 监控。
验证 SLO 监控
在本次关于 SLO 监控的实验的前两个子节中,我们为一个服务(之前在 第八章,理解 GKE 基础知识以部署容器化应用程序 中创建)创建了 SLO,并且创建了 SLO 燃烧速率警报策略。本节将展示如何测试配置,并验证我们的 SLO 监控选项是否验证我们服务的健康状况;也就是说,hello-world-service:
-
鉴于我们之前在定义 SLO 时选择了性能指标
kubernetes.io/container/restart_count,让我们重新启动容器,查看错误预算是否发生变化,并进一步检查警报是否触发。连接到集群后,使用以下命令重新启动容器。根据实际情况替换pod-name和container-name。pod-name可以通过服务找到,container-name可以通过pod-name找到:kubectl exec -it <pod-name> -c <container-name> -- /bin/sh -c "kill 1" -
一旦命令执行完成,
hello-world-service容器所在的 Pod 将重新启动。这意味着已定义的 SLI 将无法达到,从而 SLO 也无法满足。结果,错误预算将被消耗。如果错误预算被消耗的速率超过了定义的燃烧速率——即 1 分钟内 10 次——则也会触发警报。以下截图显示了hello-world-service的 SLO 状态更新。SLO 状态已更新为 不健康:![图 10.40 – 显示服务为“不健康”,触发警报,并减少的错误预算]()
图 10.40 – 显示服务为“不健康”,触发警报,并减少的错误预算
-
警报触发通知,将发送到配置的电子邮件地址,以下截图显示了这一点:

图 10.41 – 警报通知已设置为配置的电子邮件地址
这完成了我们关于 SLO 监控的详细实践实验,其中我们将 SRE 技术实践与 Google Cloud 操作中可用的选项相结合,以监控和警告用户服务的可靠性。这也完成了本章关于云操作的内容。
总结
在本章中,我们讨论了 Cloud Operations 工具套件。Cloud Operations 对于形成 CI/CD 过程的反馈循环至关重要,并且是建立 GCP 可观察性的基础。可观察性对于确保 SRE 的技术实践——特别是 SLIs、SLOs、SLAs 和错误预算——不被违反是关键。这是通过从多个来源收集日志、指标和跟踪信息,并通过仪表板将这些信息可视化来实现的。这些信息用于建立性能和可靠性指标。然后,这些指标可以通过可配置的警报进行跟踪。当存在潜在违规时,这些警报会触发,并通过可配置的通知渠道进行通知。Cloud Operations 还提供服务,使我们能够在不减慢速度的情况下调试应用程序并捕获跟踪信息。最终目标是确保服务的可靠性。本章的结尾提供了一个关于 SLO 监控的实践实验室,这是 Google Cloud 的一项功能,旨在通过结合 Cloud Operations 和 SRE 技术实践来跟踪服务的可靠性。
这是本书的最后一章。下一部分提供了关于准备成为专业云 DevOps 工程师的见解,以及总结了最后 10 章未涉及但可能出现在考试中的一些主题。我们还提供了一个模拟考试,它将作为准备资源非常有用。
需要记住的要点
以下是需要记住的一些重要要点:
-
Cloud Monitoring 是一项 GCP 服务,用于实时收集来自多云和混合基础设施的指标、事件和元数据。
-
一个工作区提供与 GCP 资源相关的单一视图。
-
一个工作区可以监控来自多个被监控项目的资源。
-
然而,一个被监控项目只能与一个工作区关联。
-
仪表板以适合最终用户或操作团队的方式提供关键信号数据(称为指标)的图形表示。
-
指标代表资源使用的数值度量,这些度量可以在系统中定期观察和收集。
-
MQL 可用于通过基于文本的界面创建图表,并使用表达式查询语言对时间序列数据执行复杂查询。
-
正常运行时间检查测试在特定超时时间间隔内外部服务的可用性。
-
连接错误、40x 客户端错误以及未配置防火墙规则是导致正常运行时间检查失败的潜在原因。
-
警报处理是处理跟踪 SLO 的警报规则的过程,当规则被违反时,警报规则会通知或执行某些操作。
-
对齐周期是从特定时间点回溯的时间间隔。
-
监控代理基于
collectd守护进程,用于从多个来源收集系统统计信息,包括操作系统、应用程序、日志和外部设备。 -
云日志是一个 GCP 服务,允许你存储、搜索、分析、监控以及对应用程序的日志数据和事件发出警报。
-
策略拒绝日志是指当 Google Cloud 服务拒绝访问用户或服务账户时捕获的日志。
-
基于日志的指标是基于日志条目内容创建的,可以从包含和排除的日志中提取。
-
VPC 流日志捕获启用子网中与 VPC 资源相关的实时网络活动(进站/出站)。
-
防火墙日志捕获特定防火墙规则所允许或拒绝的流量影响。
-
日志代理基于
fluentd,并捕获其他 VM 日志,如操作系统(OS)日志以及第三方应用程序日志。 -
监控和日志代理都可以安装在非托管的 GCE VM 上。
-
GKE 内置支持日志记录,可以通过 Cloud Operations for GKE 启用新集群或现有集群的日志记录。
-
Cloud Debugger 实时检查正在运行的应用程序的状态。
-
快照捕获应用程序源代码中特定位置的局部变量和调用堆栈。
-
快照仅会拍摄一次,用户需要手动重新拍摄,如有需要。
-
调试日志点可以在不中断、编辑或重新启动的情况下,将日志注入到正在运行的应用程序中。
-
即使没有直接访问源代码的权限,也可以创建日志点。
-
日志点在 24 小时后变为非活动状态,并在 30 天后自动删除。
-
Cloud Trace 是一组跨度(span)的集合。跨度是包装特定延迟指标的对象。Cloud Trace 是一个分布式追踪系统。
-
Cloud Trace 提供适用于 Java、Node.js、Ruby 和 Go 的特定语言 SDK。
-
Cloud Profiler 提供低影响的持续分析,帮助我们理解生产系统的性能。
-
Cloud Profiler 支持的编程语言包括 Java、Go、Node.js 和 Python。默认情况下,性能数据会保存 30 天。
深入阅读
欲了解更多 GCP 在 DevOps 方面的内容,请阅读以下文章:
-
Cloud Debugger:
cloud.google.com/debugger -
Cloud Trace:
cloud.google.com/trace -
Cloud Profiler:
cloud.google.com/profiler
实践测试
请回答以下问题:
-
用户执行了修改资源配置或元数据的管理操作。以下哪个选项最适合快速查看与管理操作相关的日志?
a) 转到错误报告并查看管理员活动日志。
b) 转到 Cloud Logging 并查看管理员活动日志。
c) 转到 Cloud Monitoring 并查看管理员活动日志。
d) 转到 Cloud Console 的“活动”选项卡,查看管理员活动日志。
-
数据访问审计日志的默认保留期限为 ___________。
a) 7 天
b) 30 天
c) 400 天
d) 无限
-
选择最适合通过单一工作空间监控多个 GCP 项目及其资源的选项。
a) 无法通过单一工作空间监控多个 GCP 项目。
b) 为 Cloud Monitoring 工作空间配置一个单独的项目作为
host项目。通过 Pub/Sub 将每个项目的度量和日志配置到主机项目。c) 为 Cloud Monitoring 工作空间配置一个单独的项目作为
host项目。使用该主机项目管理所有其他项目。d) 为 Cloud Monitoring 工作空间配置一个单独的项目作为
host项目。通过 Cloud Storage 为主机项目配置来自每个项目的度量和日志。 -
____________ 日志记录已重置的 Google Compute Engine 实例的操作。
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
日志条目的最大大小为 __________。
a) 64 KB
b) 128 KB
c) 256 KB
d) 512 KB
-
数据透明度日志的默认保留期限为 ___________。
a) 7 天
b) 30 天
c) 400 天
d) 无限
-
___________ 日志特定于 Google 人员在访问用户/客户内容时执行的操作。
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
SRE 团队在 GCP 中支持多个生产工作负载。SRE 团队希望通过将错误报告和堆栈跟踪发送到集中服务来更好地管理问题。以下哪个最适合实现这一目标?
a) 云错误日志
b) 云错误报告
c) 云跟踪
d) 云性能分析
-
___________ 日志记录分配/取消分配 IAM 角色时执行的操作。
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
_________ 日志分析应用程序的网络日志。
a) VPC 流量
b) 防火墙
c) 审计
d) 活动
-
选择表示从 Cloud Logging 中正确日志条目特征的选项:
a) 时间戳
b) 日志名称
c) 与日志条目相关联的资源
d) 以上所有
-
选择两个用户希望将一部分日志发送进行大数据分析的操作:
a) 在 Cloud Logging 中创建一个接收器,标识要发送的日志子集。
b) 将日志导出到 Cloud Storage。
c) 将日志导出到 BigQuery。
d) 将日志导出到 Pub/Sub。
-
管理员活动日志的默认保留期限为 ___________。
a) 7 天
b) 30 天
c) 400 天
d) 无限
-
以下哪项表示导出日志的正确步骤顺序?
a) 选择目标,创建接收器,创建过滤器
b) 创建接收器,创建过滤器,选择目标
c) 创建接收器,选择目标,创建过滤器
d) 选择目标,创建过滤器,创建接收器
-
___________ 日志将记录如何为 Google Compute Engine 创建资源:
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
选择管理对 Cloud Logging 中日志访问的选项:
a) 服务账户
b) 云 IAM 角色
c) (a) 和 (b) 两者
d) 以上都不是
-
选择允许我们管理监控工作区 IAM 角色的角色:
a) 监控查看器
b) 监控编辑器
c) 监控管理员
d) 监控指标写入者
-
选择表示具有分布值的指标的云监控小组件:
a) 折线图
b) 热图图表
c) 仪表盘
d) 记分卡
-
要执行正常运行时间检查,最少需要选择多少个作为地理区域的活动位置?
a) 二
b) 三
c) 四
d) 五
-
监控代理基于 _________,而日志代理基于 __________。
a)
fluentd,collectdb)
google-collectd,google-fluentdc)
collectd,fluentdd)
google-fluentd,google-collectd -
以下哪个不是数据访问日志的有效分类类型?
a) 管理员读取
b) 管理员写入
c) 数据读取
d) 数据写入
-
选择允许我们查看数据访问和访问透明度日志的角色:
a) 日志查看器
b) 私有日志查看器
c) 项目查看器
d) 项目编辑者
-
防火墙日志的默认保留期限是 ___________。
a) 7 天
b) 30 天
c) 400 天
d) 无限
-
每个 VPC 都有一组具有最低优先级的隐藏、隐含、预配置规则。选择两个有效的预配置规则:
a)
allow all ingressb)
deny all ingressc)
allow all egressd)
deny all egress -
系统事件审计日志的默认保留期限是 ___________。
a) 7 天
b) 30 天
c) 400 天
d) 无限
答案
-
(d): 转到 Cloud Console 的活动标签页查看管理员活动日志。
-
(b): 30 天。
-
(c): 配置一个单独的项目作为 Cloud Monitoring 工作区的
host项目。使用此主机项目来管理所有其他项目。 -
(b): 系统事件。
-
(c): 256 KB。
-
(c): 400 天。
-
(d): 访问透明度。
-
(b): 云错误报告。
-
(a): 管理员活动。
-
(a): VPC 流量。
-
(d): 以上所有。
-
(a) 和 (c)。
-
(c): 400 天。
-
(b): 创建接收器,创建过滤器,选择目标。
-
(a): 管理员活动。
-
(b): 云 IAM 角色。
-
(c): 监控管理员。
-
(b): 热图图表。
-
(b): 三。
-
(c):
collectd,fluentd。 -
(b): 管理员写入;这不是数据访问日志的有效分类。
-
(b): 私有日志查看器。
-
(b): 30 天。
-
(b) 和 (c):
deny all ingress和allow all egress。 -
(c): 400 天。
第十一章:附录:为专业云 DevOps 工程师认证考试做准备
本书是一本实用指南,旨在学习和理解网站可靠性工程(SRE),这是一种实施 DevOps 的规定性方法。书中还深入探讨了在 Google Cloud Platform 上实施 DevOps 所必需的 Google Cloud 服务。
此外,本书还帮助为专业云 DevOps 工程师认证考试做好准备。专业的云 DevOps 工程师负责高效的开发运维,并平衡服务的可靠性与交付速度。他们擅长使用 Google Cloud Platform 构建软件交付管道、部署和监控服务,并管理和学习事故。官方考试指南可以在cloud.google.com/certification/guides/cloud-devops-engineer找到。要注册认证考试,请访问cloud.google.com/certification/register。
高层次上,认证主要围绕 SRE、Google Kubernetes Engine(GKE)和 Google Cloud 的运维套件展开。这些话题可能占据认证考试的 80%以上。关于 SRE、GKE 和 Google Cloud 运维套件的章节广泛涵盖了在专业云 DevOps 工程师认证考试中评估的关键概念。记住要点部分以及本章节末尾的练习测试将帮助你复习本章的关键概念。
此外,还将高层次地覆盖可能出现在认证考试中的三个额外话题。部分话题与 Google 的其他认证考试有所重叠,例如专业云架构师认证或专业云开发者认证。
以下是将要总结的主题。请注意,这些主题在此处并没有完全详细展开,而是仅做介绍。建议查阅相关的具体文档以获取深入信息:
-
Cloud Deployment Manager
-
Cloud Tasks
-
Spinnaker
Cloud Deployment Manager
基础设施即代码(IaC)是通过代码管理和配置基础设施的过程,而不是手动创建所需资源。Cloud Deployment Manager是 Google Cloud 的一项服务,提供 IaC 功能。Cloud Deployment Manager 可以创建一组 Google Cloud 资源,并帮助将这些资源作为一个整体进行管理,通常称为部署。例如,可以通过配置文件使用声明性代码创建虚拟私有云(VPC),而不是通过控制台手动创建。以下是 Cloud Deployment Manager 的一些关键特性:
-
可以并行创建多个资源,例如多个虚拟机
-
可以提供输入变量,以创建具有特定用户定义值的资源。
-
可以获取新创建资源的返回值,例如新创建的 Google Compute Engine 实例的实例 ID。
-
可以创建依赖关系,其中一个资源定义可以引用另一个资源,并且一个资源可以在创建另一个资源后创建(使用
dependsOn)。
Cloud Deployment Manager 允许通过配置文件指定应用程序所需的所有资源。这是实现 Cloud Deployment Manager 的第一步。此配置文件以声明式格式编写,使用 YAML。
每个配置文件可以用来定义一个或多个资源。每个资源部分包含三个主要组件:资源的名称、资源类型和资源属性。需要使用的资源属性在大多数情况下是特定于资源类型的。配置文件中指定的资源是通过调用 API 创建的(这可能带来一定的风险,因为某些 API 可能在未来被弃用)。配置文件可以完全明确列出,或者 Cloud Deployment Manager 允许使用模板(模板更适合创建类似类型的资源)。
配置可以包含模板,这些模板引用了被抽象为单独构建块的配置文件部分。模板文件可以用 Python 或 Jinja2 编写。Python 模板功能更强大,提供了通过编程方式创建或管理模板的选项。Jinja2 是一种更简单但功能较弱的模板语言,使用与 YAML 相同的语法。可以使用预览模式(通过--preview标志)在应用之前验证资源的潜在操作。有关 Cloud Deployment Manager 的更多信息,请参见 cloud.google.com/deployment-manager。
Cloud Tasks
Cloud Tasks 是 Google Cloud 提供的完全托管服务,它允许你将可以独立执行并异步处理的工作单元从用户或服务到服务的请求中分离出去。一个独立的工作单元称为任务。Cloud Tasks 实际上用于当应用程序接受来自用户的输入,并需要相应地启动后台任务以执行自动化的异步操作时。
以下是 Cloud Tasks 的关键特性总结:
-
Cloud Tasks 旨在显式调用,其中发布者保留对执行的完全控制。
-
Cloud Tasks 最适用于任务生产者可以控制执行的场景。
Cloud Tasks 与 Pub/Sub 的核心区别在于显式调用与隐式调用的概念。如前所述,Cloud Tasks 旨在显式调用。而 Pub/Sub 支持隐式调用,其中发布者通过发布事件隐式地触发订阅者执行。有关 Cloud Tasks 的更多深入信息,请参考 cloud.google.com/tasks。
Spinnaker
Spinnaker 是一个开源的多云持续交付平台,最初由 Netflix 开发,后来由 Google 扩展。Spinnaker 不是一个官方的 Google Cloud 服务,也不是一个原生集成服务,目前 Google Cloud Platform 尚未推出用于持续部署的原生服务。Google 大力推荐 Spinnaker 用于在 Google Cloud Platform 上实现 CI/CD 管道。Spinnaker 有助于高效、可靠地发布软件变更。Spinnaker 由多个独立的微服务组成。Spinnaker 创建了一个 Cloud Storage 存储桶,并使用 Redis 数据库来维护其资源。Spinnaker 还创建了一个 Pub/Sub 主题。
Spinnaker 可被视为一个应用程序管理工具,允许查看和管理 GKE 组件,包括工作负载资源、服务和负载均衡器。Spinnaker 支持多种部署模型,包括滚动更新、蓝绿部署或金丝雀发布。
Spinnaker 将所有操作置于自动驾驶模式,无需人工干预,换句话说,无需手动执行 kubectl 命令。Spinnaker 可以创建和管理 YAML 文件,并可以执行自动化部署,甚至为负载均衡器作为服务创建/执行 YAML 文件。唯一需要手动操作的步骤是提供批准以完成部署。
以下图示展示了使用 Spinnaker 部署到 GKE 集群时的交互高层概述:

使用 Spinnaker 部署到 GKE 时的交互示意图
上图中的交互如下:
-
开发者通过创建 Git 标签并推送到云源代码库来更改代码。
-
云源代码库配置为检测新的 Git 标签。这会触发 Cloud Build 根据提供的规范执行构建过程,可能包括运行单元测试。完成后,生成构建产物,如 Docker 镜像。
-
创建的构建产物存储在容器注册表(Container Registry)或 Artifact Registry 中,一旦可用,如果已配置,会向 Cloud Pub/Sub 发送一条消息。
-
安装在 GKE 上的 Spinnaker 将监听 Pub/Sub 主题,以接收新创建的镜像。
-
一旦镜像可用,Spinnaker 将通过金丝雀发布方式将新容器部署到 QA/预生产环境中,从而确保只有少部分用户受到影响。
-
如果可用,会在金丝雀环境中运行功能测试,以验证部署的质量。如果部署符合预期的质量标准,在手动批准后,该镜像将部署到生产环境。
需要注意的是,无论是在执行蓝绿部署还是金丝雀部署时,Spinnaker 都可以在原地更新 ReplicaSet。当使用 Deployment 部署 ReplicaSet 且 Deployment 不存在时,Spinnaker 会先创建一个包含 0 副本的 ReplicaSet,然后再创建 Deployment,后者会调整 ReplicaSet 的大小。当 Deployment 已经存在时,Spinnaker 会执行相同的操作,但会直接编辑现有的 Deployment,而不是创建新的。
有关在 Google Cloud Platform 上安装和管理 Spinnaker 的更多信息,请参考 cloud.google.com/docs/ci-cd/spinnaker/spinnaker-for-gcp。
这部分总结了包括 Cloud Deployment Manager、Cloud Tasks 和 Spinnaker 等其他主题的内容。
你已阅读完本书内容。通过尝试模拟测试来检验你的知识。本书包括 2 次模拟测试,每次包含 50 道问题。这些测试可以作为参考。如果你正在参加认证考试,祝你好运!
第十二章:模拟考试 1
测试时长:2 小时
总问题数:50
回答以下问题:
-
以下哪种是合适的部署方案,具有最小的停机时间和基础设施需求?
a) 重新创建
b) 滚动更新
c) 金丝雀发布
d) 蓝绿部署
-
Cloud Pub/Sub 和 Cloud Tasks 是 Google Cloud 中的两个服务,提供与消息服务的异步集成能力。选择两个最适合 Cloud Tasks 的选项:
a) Cloud Tasks 旨在显式调用,其中发布者保留对执行的完全控制。
b) Cloud Tasks 最适用于任务生产者能控制执行的场景。
c) Cloud Tasks 旨在隐式调用,其中发布者保留对执行的完全控制。
d) Cloud Tasks 最适用于任务消费者能够控制执行的场景。
-
____________ 日志将记录计算引擎实例重置操作。
a) 管理活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
选择适当的服务类型,在此类型下,服务获取一个内部 IP 地址:
a)
ClusterIPb)
NodePortc)
LoadBalancerd) 以上所有
-
选择允许向工作空间写入监控数据但不允许通过控制台查看的角色:
a) 监控查看者
b) 监控指标编写者
c) 监控管理员
d) 监控编辑者
-
对于一个服务,如果 SLA 是 99.0%,SLO 是 99.5%,SLI 是 99.6%,那么错误预算是 ________。
a) 1%
b) 0.4%
c) 0.5%
d) 以上都不是
-
_________ 是 Cloud Build 的一项功能,其中中间容器镜像层直接写入 Google 的容器注册表,而无需显式推送步骤。
a) 弹性缓存
b) Kaniko 缓存
c) Redis 缓存
d) (a) 和 (c)
-
以下谁负责协调响应团队的工作,以应对正在进行的事件?
a) 事件指挥官 (IC)
b) 通讯负责人 (CL)
c) 运营负责人 (OL)
d) 规划负责人 (PL)
-
选择允许 Docker 使用
gcloud来认证请求 Container Registry 的命令:a)
gcloud auth configure dockerb)
gcloud auth configure-dockerc)
gcloud auth docker-configured)
gcloud auth docker configure -
请选择根据 SRE 参与模型,在某一阶段,SRE 工程师的参与度相较其他阶段较低的阶段:
a) 架构与设计
b) 活跃开发
c) 限制可用性
d) 通用可用性
-
你的应用部署在 GKE 中,并利用密钥保护敏感信息。以下哪种方法是推荐的?
a) 敏感信息不应存储在应用中。
b) 敏感信息应作为环境变量传递。
c) 敏感信息应存储在云的 DLP 服务中。
d) 敏感信息应存储在 Google Secrets Manager 中。
-
在 Google 计算引擎上安装了日志代理。然而,日志没有发送到云日志。接下来解决此问题的逻辑步骤是什么?
a) 重新安装日志代理。
b) 重启计算引擎。
c) 将数据访问日志配置为日志代理配置的一部分。
d) 验证与计算引擎绑定的服务账户是否具有将数据发送到云日志所需的角色。
-
SLI 的计算公式是良好事件 / 有效事件 * 100。在计算有效事件时,以下哪种响应计数会被丢弃?
a)
2xx状态码计数b)
3xx状态码计数c)
4xx状态码计数d)
5xx状态码计数 -
部署回滚仅在部署的 Pod 模板发生更改时触发。选择表示应更改的部署部分的选项:
a)
.specb)
.spec.templatec)
.template.specd)
.template -
根据 SRE 最佳实践,以下哪项不成立?
a) 错过 SLA 会带来后果。
b) 错过 SLO 不会带来任何后果。
c) 缺少 SLO 表示用户不满意。
d) 缺失 SLO 会导致错误预算消耗。
-
选择代表只执行只读操作而不修改任何数据的日志条目的日志类型:
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明性
-
在事件管理过程中,以下哪项不是推荐的最佳实践?
a) 制定并记录程序。
b) 事件指挥官应对所有事件管理决策进行签字确认。
c) 优先处理损害并恢复服务。
d) 信任指定角色的团队成员。
-
_____________ 表示服务行为的准确衡量。
a) SLI
b) 服务级目标(SLO)
c) 服务级协议(SLA)
d) 错误预算
-
App Engine Standard 中的应用程序生成了大量日志。选择适当的选项,快速访问应用程序生成的错误?
a) 进入云控制台,查看活动标签,并查看错误日志。
b) 进入云日志,过滤日志,查看错误日志。
c) 进入云错误报告,查看按发生次数聚合的错误日志。
d) 进入云监控,过滤日志并查看错误日志。
-
____________ 日志将记录计算引擎资源列表操作。
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明性
-
你计划采用 SRE 实践,并希望为你的应用设置 SLO。你该如何开始?
a) 将 SLO 设置为 100%。
b) 根据收集的历史数据在预 GA 阶段设置 SLO。
c) 根据对所有利益相关者的内部调查设置 SLO。
d) 将 SLO 设置略低于 SLA。
-
选择描述如何删除管理员活动日志的正确选项:
a) 进入云控制台的活动标签,过滤日志并选择删除操作。
b) 进入云日志的活动标签。过滤要删除的日志并选择删除操作。
c) 管理员活动日志不能被删除。
d) 转到 Cloud Monitoring 中的活动选项卡。过滤日志以删除,并选择删除操作。
-
如果 Cloud Build 需要与一个独立的 CD 工具通信,以告知其是否有新的可部署工件,哪个方法是首选?
a) Cloud Build 在 NoSQL 数据库中创建条目。CD 工具在数据库中查找事件。
b) Cloud Build 在云存储桶中创建条目。CD 工具在桶中查找事件。
c) Cloud Build 向 pub/sub 主题发布消息。CD 工具订阅该主题。
d) (a) 和 (b)。
-
选择所有可能的 Toil 特征(您可以选择多个):
a) 它是重复的。
b) 它提供持久价值。
c) 它与服务的规模成线性增长。
d) 战术。
-
_____________ 是一个过程/服务,数字化地检查软件供应链的每个组件,确保在部署应用程序之前软件的质量和完整性。
a) 容器注册表
b) 云存储
c) 容器分析
d) 二进制授权
-
Cloud Debugger 允许您在相同代码位置为应用数据拍摄多少次快照?
a) 无
b) 两次
c) 一次
d) 三次
-
选择关于审计安全日志的正确选项。
a) 保留期为 30 天,并且是可配置的。
b) 保留期为 400 天,并且是可配置的。
c) 保留期为 30 天,并且不可配置。
d) 保留期为 400 天,并且不可配置。
-
_______________ API 启用的软件工件元数据存储,在二进制授权过程中使用。
a) 容器扫描
b) 容器元数据
c) 容器证明
d) 容器分析
-
您创建了一个启用了二进制授权的 GKE 集群。您在尝试部署应用程序时遇到错误——被 Attestor 拒绝。请选择下一步合适的操作。
a) 更新集群并关闭二进制授权。重新部署应用程序。
b) 创建加密密钥并提交给二进制授权。
c) 创建证明并提交给二进制授权。
d) 为容器镜像创建二进制授权豁免。
-
选择在代码中使用的帐户,当一个 Google 云服务与另一个 Google 云服务交互时:
a) 用户帐户
b) 服务帐户
c) (a) 和 (b) 都是
d) 以上都不是
-
您的应用程序有一个 API,返回多种格式的响应,如 JSON、CSV 和 XML。您想知道最常请求的格式以便进一步分析。以下哪种方法最合适?
a) 创建日志过滤器,并通过日志接收器将日志导出到云存储中。在云存储中查询日志。
b) 创建日志过滤器,使用正则表达式创建自定义指标,并将每个请求的格式提取到单独的指标中。监控指标的数量并根据需要创建警报。
c) 创建日志过滤器,并通过日志接收器将日志导出到 BigQuery。在 BigQuery 中查询日志。
d) 创建日志过滤器,使用正则表达式创建自定义指标,并将请求的格式提取到标签中。监控该指标以查看按标签分组的请求计数。
-
选择具有以下特征的事件严重性分类:对内部用户有影响或造成不便,但外部用户可能没有注意到。
a) 微不足道
b) 小
c) 重大
d) 有害
-
选择表示对 Compute Engine 资源进行系统维护操作的日志条目的日志类型?
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明性
-
以下哪个是适合大数据系统的 SLI(选择两个)?
a) 可用性
b) 吞吐量
c) 质量
d) 端到端延迟
-
你需要部署两个应用程序,分别由 Alpha 和 Beta 两个部署表示。两个应用程序需要相互通信,但任何一个应用程序都不应从外部访问。你决定创建一个服务。选择适当的服务类型:
a)
Ingressb)
NodePortc)
ClusterIPd)
LoadBalancer -
期望审计特定 VPC 内的网络流量。以下哪个选项最合适?
a) 启用 VPC 防火墙级别日志
b) 启用 VPC 网络日志
c) 启用 VPC 流日志
d) 启用 VPC 审计日志
-
在 RBAC 中,
persistentvolume和certificatesigningrequests节点的作用范围是:a) 集群范围
b) 命名空间范围
c) 两者
d) 无
-
选择将应用程序代码和依赖项捆绑为一个单一单元的资源,从而将应用程序与基础设施抽象开来。
a) Docker
b) 微服务
c) 容器
d) 虚拟机
-
Google Cloud 中的 VPC 是一个 __________ 资源。
a) 区域
b) 区域
c) 全球
d) 多区域
-
在 GKE 集群中部署的应用程序遇到间歇性问题。每次发生问题时,应用程序都会发出一组非常特定的日志。你的目的是在问题发生时尽快调试应用程序或查看应用程序的状态。以下哪种方法是最佳选择?
a) 云监控:根据特定日志模式设置自定义指标,并在该模式的行数超过定义的阈值时,从该指标创建警报。
b) 云日志:在特定日志模式上创建日志过滤器,通过创建日志接收器将日志导出到 BigQuery,并通过在 BigQuery 中监控特定模式的数据来创建警报。
c) 云错误报告:根据特定日志模式设置自定义指标,并在该模式的行数超过定义的阈值时,从该指标创建警报。
d) 云日志:根据特定日志模式设置自定义指标,并在该模式的行数超过定义的阈值时,从该指标创建警报。
-
选择不符合 Google 关于云原生开发推荐的选项:
a) 使用微服务架构模式。
b) 尽可能设计有状态组件。
c) 设计自动化。
d) 将一切构建为容器。
-
你需要将容器镜像部署到 GKE 集群中。集群尚未创建。以下哪个选项展示了最合适的步骤顺序?
a) 使用
kubectl命令创建 GKE 集群,使用容器镜像创建部署规范,并使用kubectl创建部署。b) 使用
gcloud命令创建 GKE 集群,使用容器镜像创建部署规范,并使用kubectl创建部署。c) 使用
kubectl命令创建 GKE 集群,使用容器镜像创建部署规范,并使用gcloud创建部署。d) 使用
gcloud命令创建 GKE 集群,使用容器镜像创建部署规范,并使用gcloud创建部署。 -
虚拟化硬件的最小单元被称为 _____。
a) Pod
b) 节点
c) 作业
d) 容器
-
目标是创建一个 GKE 集群并使用第三方监控应用程序。以下哪种方法是实现这一目标的最合适方式?
a) 将监控应用程序作为
ReplicaSet对象进行部署。b) 将监控应用程序作为
DaemonSet对象进行部署。c) 将监控应用程序作为
StatefulSet对象进行部署。d) 将监控应用程序作为
LoadBalancer服务进行部署。 -
选择 Kubernetes 引擎用于有状态应用程序的控制器。
a) 无状态控制器
b) StatefulSet 控制器
c) DaemonSet 控制器
d) 复制控制器
-
由于分析需求,需要至少保留 3 年的日志。以下哪种方法是最优选择?
a) 云日志:日志可用时间可配置。
b) 云日志:创建日志接收器并导出到云存储。
c) 云日志:创建日志接收器并导出到 BigQuery。
d) 云日志:创建日志接收器并导出到 Pub/Sub。
-
_____________ 是系统可用性的精确数值目标。
a) SLI
b) SLO
c) SLA
d) 错误预算
-
Sam 需要查看访问透明日志。选择最适合此目的的角色?
a) 项目编辑
b) 项目查看者
c) 日志查看器
d) 以上都不是
-
以下谁负责响应中的通信部分?
a) 事件指挥官 (IC)
b) 通讯负责人 (CL)
c) 运营负责人 (OL)
d) 规划负责人 (PL)
-
公司 A 希望根据错误预算的燃烧率设置警报策略。根据 SRE 推荐的做法,以下哪项是最佳选择?
a) 创建一个具有较短回溯周期的警报策略。
b) 创建一个考虑较短回溯周期和较长回溯周期的警报策略。
(c) – 创建一个具有较长回溯周期的警报策略。
(d) – 每当违反已定义条件时立即创建一个警报策略。
答案
-
(b) – 滚动更新
-
(a) 和 (b)
-
(b) – 系统事件
-
(d) – 上述所有。每种服务类型都提供一个内部 IP 地址。
-
(b) – 监控指标编写器
-
(c) – 0.5%
-
(b) – Kaniko 缓存
-
(a) – 事件指挥官
-
(b) –
gcloud auth configure-docker -
(b) – 活跃开发
-
(d) – 敏感信息应存储在 Google Secrets Manager 中。
-
(d) – 验证与计算引擎绑定的服务账户是否具有发送到云日志所需的角色。
-
(b) 和 (c) –
3xx状态计数和4xx状态计数 -
(b) –
spec.template -
(b) – 缺失 SLO 不会带来任何后果。
-
(c) – 数据访问
-
(b) – 事件指挥官应在事件管理期间对所有决策进行签署确认。
-
(a) – 服务水平指标(SLI)
-
(c) – 转到云错误报告并查看按发生次数聚合的错误日志。
-
(c) – 数据访问
-
(b) – 根据在 GA 前期收集的历史数据设置 SLO。
-
(c) – 管理活动日志无法删除。
-
(c) – Cloud Build 向 pub/sub 主题发布消息,CD 工具订阅该主题。
-
(a) 和 (d) – 提供持久价值并具有战术性
-
(d) – 二进制授权
-
(c) – 一次
-
(d) – 保留期为 400 天且不可配置。
-
(d) – 容器分析
-
(c) – 创建证明并提交给二进制授权
-
(b) – 服务账户
-
(d)
-
(b) – 次要
-
(b) – 系统事件
-
(b) 和 (d) – 吞吐量和端到端延迟
-
(c) –
ClusterIP -
(c) – 启用 VPC 流日志
-
(b) – 命名空间范围
-
(c) – 容器
-
(c) – 全局
-
(d)
-
(b) – 尽可能设计为有状态的组件。
-
(b)
-
(b) – 节点
-
(b) – 将监控应用程序部署为
DaemonSet对象。 -
(b) – StatefulSet 控制器
-
(c) – 云日志:创建日志接收器并将其导出到 BigQuery。
-
(b) – 服务水平目标(SLO)
-
(d) – 以上都不是(私有日志查看器)
-
(b) – 通信负责人
-
(b) – 创建一个警报策略,考虑较短的回溯周期和较长的回溯周期。
第十三章:模拟考试 2
测试时长:2 小时
总问题数:50
回答以下问题:
-
以下哪个 Google Cloud 服务适用于存储 Docker 镜像?选择所有适当的选项。
a) Cloud Source Repositories
b) 容器注册表
c) 云构建
d) 工件注册表
-
公司 A 决定将一个容器化应用程序部署到 GKE 集群。GKE 集群由多个节点或计算机组成。需求是收集与部署相关的详细度量标准,包括节点和容器相关的度量标准。以下哪种方法是推荐的收集这些度量标准的方法?
a) 在 GKE 集群上安装监控代理。
b) 启用 GKE 集群的云操作。
c) 在 GKE 集群上安装日志代理。
d) (a) 和 (b)
-
在配置私有 GKE 集群时,以下哪项不是有效选项?
a) 禁用公共端点访问。
b) 启用公共端点访问;为有限访问启用授权网络。
c) 禁用公共端点访问;为有限访问启用授权网络。
d) 启用公共端点访问;禁用授权网络。
-
选择表示与设置或更改 Cloud Storage 存储桶权限相关的日志条目的日志类型:
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
你的团队决定通过 BigQuery 在 Cloud Logging 中分析日志。选择最适合实现团队目标的选项:
a) 通过创建日志接收器导出到 Cloud Storage,在 Cloud Storage 存储桶中创建事件,并将其推送到 BigQuery。
b) 通过创建日志接收器导出到 BigQuery。
c) 通过创建日志接收器将日志导出到 Pub/Sub,并将 BigQuery 配置为该主题的订阅者。
d) 无法导出到 BigQuery。
-
从以下选项中选择两个,Cloud Build 不支持作为有效的机器类型来启动 Cloud Build 过程。
a)
M1– 内存优化b)
N1– 通用型c)
C2– 计算优化d)
E2– 通用型 -
以下哪项是黑盒监控的特点?
a) 以症状为导向并以原因为导向
b) 收集来自度量标准、日志和追踪的信息
c) 最适用于事件发生后的事件分页
d) 系统内部暴露的度量标准
-
调试快照捕获 ____________________。
a) 本地变量
b) 特定位置的调用栈
c) (a) 和 (b) 都是
d) 以上都不是
-
____________ 日志将记录修改 Compute Engine 资源配置或元数据的操作。
a) 管理员活动
b) 系统事件
c) 数据访问
d) 访问透明度
-
_____________ 存储用于授权过程的可信元数据。
a) 容器注册表
b) Cloud Storage
c) 容器分析
d) 二进制授权
-
根据 SRE,服务在 ________ 时进入正式发布阶段。
a) 达到约定的 GA 数据
b) 生产准备审核已通过
c) 一位执行人员已使用他们的银色代币
d) 产品负责人已提出请求推动生产
-
_________ 不是日志路由器的功能。
a) 输入日志
b) 调试日志
c) 丢弃日志
d) 导出日志
-
以下哪项选项要求你安装日志代理?
a) 查看 Linux 系统日志
b) 查看管理活动日志
c) 查看 Windows 事件查看日志
d) (a) 和 (c)
-
____________ 日志将记录 Google Compute Engine 的自动重启操作。
a) 管理活动
b) 系统事件
c) 数据访问
d) 访问透明性
-
在 Autopilot 模式下创建 GKE 集群时,选择与网络隔离相关的可能配置选项:
a) 私有或公共集群
b) 仅限公共集群
c) 仅限私有集群
d) 无
-
选择最适合在 VPC 子网级别分析网络流量的选项:
a) 数据访问日志
b) 流日志
c) 管理日志
d) 防火墙日志
-
____________ 日志将记录更改资源属性(如标签/标签)操作,适用于 Google Compute Engine。
a) 管理活动
b) 系统事件
c) 数据访问
d) 访问透明性
-
一个应用程序接受用户输入,并需要相应地启动后台任务以执行自动化异步执行。选择适合的 Google Cloud 服务:
a) 云 Pub/Sub
b) 云任务
c) 云调度器
d) 云 Cron
-
容器分析使用 _________ 存储受信任的元数据。这些元数据用于二进制授权过程。
a) 云存储
b) 容器注册表
c) 云源代码库
d) 持久磁盘或持久卷
-
选择以下最受管理的计算选项:
a) Google Compute Engine
b) Google App Engine
c) Google Kubernetes Engine
d) Google Cloud Run
-
____________ 日志将记录设置或更改 Compute Engine 权限的操作。
a) 管理活动
b) 系统事件
c) 数据访问
d) 访问透明性
-
以下哪项与默认日志桶中存储的用户日志的默认保留期相关?
a) 这是 30 天,且不可更改。
b) 这是 400 天,且可以更改为 1 天至 10 年之间。
c) 这是 400 天,且不可更改。
d) 这是 30 天,且可以更改为 1 天至 10 年之间。
-
选择实施 CI/CD 的 Google Cloud 服务的顺序:
a) 云构建、云源代码库、容器注册表、GKE
b) 云源代码库、云构建、容器注册表、GKE
c) 云源代码库、容器注册表、云构建、GKE
d) 云构建、容器注册表、云源代码库、GKE
-
选择保留管理活动日志超过保留期的选项:
a) 管理活动日志永不过期。
b) 管理活动日志无法超过保留期进行保留。
c) 管理活动日志可以导出到云存储。
d) 已过期的管理活动日志可以通过 CLI 恢复。
-
选择与 SRE 中的 toil 相关的两个正确陈述:
a) Toil 用于跟踪错误预算。
b) 减少 toil 是 SRE 工程师的重要任务。
c) Toil 是不与生产系统相关的重复性任务。
d) Toil 是与生产系统相关的重复性任务。
-
选择最合适的 StatefulSet 定义:
a) 代表一组具有唯一、持久身份和稳定主机名的服务。
b) 代表一组具有唯一、持久身份和稳定主机名的集群。
c) 代表一组具有唯一、持久身份和稳定主机名的 pod。
d) 代表一组具有唯一、持久身份和稳定主机名的 Docker 镜像。
-
Cloud Trace 可以收集来自 ________________ 的延迟数据。
a) 负载均衡器
b) GKE 应用
c) 两者皆是
d) 无
-
目标是创建一个 GKE 集群,使节点配置支持韧性和高可用性,无需人工干预。以下哪个 GKE 特性最合适?
a) GKE 的节点自动升级功能
b) GKE 的节点自动修复功能
c) GKE 的节点自愈功能
d) (a) 和 (c)
-
以下哪个用于存储与管理事件相关的记录?
a) 跟踪
b) 日志记录
c) 错误报告
d) 调试
-
通过 Deployment Manager 部署了一个应用程序。你需要在最小停机时间内更新该部署。选择合适的命令:
a)
gcloud deployment-manager deployments updateb)
gcloud deployment manager deployment updatec)
gcloud deployment manager deployments updated)
gcloud deployment-manager deployment update -
在 Google Cloud Platform 上部署的应用出现延迟问题。选择可以近实时检查延迟数据的 Google Cloud 服务:
a) 云网络
b) Cloud Trace
c) Cloud Profiler
d) 云调试器
-
选择进行无责事后分析的最佳实践(选择多个):
a) 提供有助于未来缓解的清晰度。
b) 生成事件报告。
c) 概述事件的经过。
d) 确定负责事件的团队成员。
-
选择 GKE 支持的特性,通过可验证的节点身份来提高集群安全性:
a) 工作负载身份
b) 保护的 GKE 节点
c) 二进制授权
d) (a) 和 (b)
-
以下哪项不是将 AWS 账户连接到工作区时的有效选项?
a) 需要一个 GCP 连接器项目。
b) GCP 连接器项目需要与工作区位于不同的父组织。
c) GCP 连接器项目需要与工作区位于同一父组织下。
d) 计费账户应该与连接器项目绑定。
-
你负责为面向用户的系统选择 SLI。根据 Google Cloud 最佳实践,以下哪些不属于四大黄金信号(选择多个)?
a) 饱和度
b) 吞吐量
c) 流量
d) 正确性
-
选择处理 GKE 集群中意外流量激增的最佳选项:
a) 创建两个不同大小的集群。如果流量增加,将流量发送到较大的集群。
b) 限制 GKE 集群可以处理的流量量。
c) 启用 GKE 集群的自动扩展。
d) 增加集群的大小或更改集群中节点的机器类型。
-
根据最小权限原则,选择允许最终用户创建或修改 Cloud Logging 导出接收器的 IAM 角色:
a) 项目编辑者
b) 日志管理员
c) 日志配置写入者
d) 项目查看者
-
以下哪个是 Cloud Deployment Manager 的第一步?
a) 创建一个资源。
b) 创建一个模板。
c) 创建一个配置。
d) 创建一个部署。
-
一个应用程序运行在 GKE 上。希望使用 Spinnaker 执行蓝绿部署。请选择最合适的选项:
a) 使用 Kubernetes Deployment,然后使用 Spinnaker 在每次部署新版本时更新 Deployment。
b) 使用 Kubernetes ReplicaSet,然后使用 Spinnaker 在每次部署新版本时更新 ReplicaSet。
c) 使用 Kubernetes DaemonSet,然后使用 Spinnaker 在每次部署新版本时更新 DaemonSet。
d) 使用 Kubernetes StatefulSet,然后使用 Spinnaker 在每次部署新版本时更新 StatefulSet。
-
你需要为 UAT 创建一个独立的命名空间。这是隔离部署的一种方式。请选择最合适的命令:
a)
kubectl namespace create uatb)
kubectl create namespace uatc)
kubectl namespace uat created)
kubectl create uat namespace -
Cloud Deployment Manager 允许你使用 YAML 以声明性格式指定应用程序所需的资源。哪个标志可以在执行实际操作之前验证可能创建的资源?
a)
--dry-runb)
--previewc)
--snapshotd)
--verify -
_________ 不是被认为是 Kubernetes 工作负载资源。
a) 一个 Deployment
b) 一个 Service
c) 一个 Cronjob
d) 一个 DaemonSet
-
Cloud Deployment Manager 中的资源代表 ____________。
a) 一个 API 资源
b) 一个计算资源
c) 一个云数据库资源
d) 一个 Cloud Storage 资源
-
以下哪个命令用于在 Google Cloud Shell 上安装
kubectl?a)
gcloud components install kubectlb)
gcloud component kubectl installc)
gcloud components kubectl installd)
gcloud component install kubectl -
在标准模式下创建集群时,节点上的最大 Pod 数量默认为 _______。
a) 115
b) 100
c) 110
d) 105
-
选择可以手动增加 GKE 集群节点数量的命令:
a)
gcloud container clusters resizeb)
kubectl containers clusters resizec)
kubectl container clusters resized)
gcloud containers clusters resize -
目标是存储审计日志以便长期访问并允许外部审计员访问。以下哪些步骤是最合适的(选择两项)?
a) 通过创建日志接收器将审计日志导出到 Cloud Storage。
b) 通过创建日志接收器将审计日志导出到 BigQuery。
c) 将 IAM 角色分配给审计员,以便他们可以访问包含审计日志的 BigQuery 数据集。
d) 将 IAM 角色分配给审计员,以便他们可以访问包含审计日志的存储桶。
-
用户正在尝试将应用程序部署到 GKE 集群。该用户使用
kubectl执行一些命令,但kubectl无法连接到集群的kube-apiserver。以下哪个是该问题的可能原因及潜在解决方法?a) 防火墙入口规则未正确配置,阻止了用户向集群的传入流量。
b)
kubeconfig缺少连接和认证集群的凭据。运行gcloud container clusters auth login命令。c) 防火墙出口规则未正确配置,阻止了集群到用户的外出流量。
d)
kubeconfig缺少连接和认证集群的凭据。运行gcloud container clusters get-credentials命令。 -
__________ 是一个 GCP 服务,用于基础设施自动化。
a) Terraform
b) 云 Terraform
c) 云 Puppet
d) 云部署管理器
-
GKE 允许每个区域最多 _______ 个集群。
a) 50
b) 25
c) 55
d) 40
答案
-
(b) 和 (d) – 容器注册表和工件注册表。
-
(b) – 启用 GKE 集群的云操作功能。
-
(c) – 禁用公共端点访问;为有限访问启用授权网络。
-
(a) – 管理活动
-
(b) – 通过创建日志接收器导出到 BigQuery。
-
(a) 和 (c) – M1 – 内存优化型 和 C2 – 计算优化型
-
(c) – 最适合在事件发生后进行事件分页
-
(c) – (a) 和 (b) 都是
-
(a) – 管理活动
-
(c) – 容器分析
-
(b) – 生产就绪评审已通过
-
(b) – 调试日志
-
(d) – (a) 和 (c)
-
(b) – 系统事件
-
(a) – 私有或公共集群
-
(b) – 流日志
-
(a) – 管理活动
-
(b) – 云任务
-
(b) – 容器注册表
-
(d) – Google Cloud Run
-
(a) – 管理活动
-
(d) – 它是 30 天,可以更改为 1 天至 10 年之间。
-
(b) – 云源代码库、云构建、容器注册表、GKE
-
(c) – 管理活动日志可以导出到云存储。
-
(b) 和 (d) – 减少工作量是 SRE 工程师的关键任务,而工作量是与生产系统相关的重复任务。
-
(c) – 表示具有唯一持久身份和稳定主机名的一组 Pod
-
(c) – 两者
-
(b) – GKE 的节点自动修复功能
-
(b) – 日志记录
-
(b) –
gcloud deployment manager deployment update -
(b) – 云跟踪
-
(a)、(b) 和 (c) – 提供帮助未来缓解的清晰性,生成事件报告,并概述事件的过程。
-
(b) – 加固的 GKE 节点
-
(b) – GCP 连接器项目需要位于与工作区不同的父组织中。
-
(b) 和 (d) – 吞吐量和正确性(不是 4 个黄金信号的一部分——延迟、错误、流量、饱和度)
-
(c) – 在 GKE 集群上启用自动扩展。
-
(c) – 日志配置写入器
-
(c) – 创建配置。
-
(b) – 使用 Kubernetes ReplicaSet,然后使用 Spinnaker 更新每个新版本部署的 ReplicaSet。
-
(b) –
kubectl create namespace uat -
(b) –
--preview -
(b) – 一个服务
-
(a) – 单一 API 资源
-
(a) –
gcloud components install kubectl -
(c) – 110
-
(a) –
gcloud container clusters resize -
(a) 和 (d) – 通过创建日志接收器将审计日志导出到 Cloud Storage,并为审计员分配 IAM 角色,以便他们能够访问包含存储日志的审计存储桶。
-
(b) – kubeconfig 缺少与集群连接和认证所需的凭证。运行
gcloud container clusters auth login命令。 -
(d) – 云部署管理器
-
(a) – 50































浙公网安备 33010602011771号