为生产准备 Google Kubernetes Engine 环境

本解决方案提供了一种蓝图和方法,能够将您的工作负载更安全可靠、更经济高效地传入 Google Kubernetes Engine。它提供了为集群配置管理和网络访问权限的指南。 本文假定您对 Kubernetes 资源和集群管理有一定的了解,并熟悉 Google Cloud 网络功能。

构建项目、Virtual Private Cloud (VPC) 网络和集群

下图展示了项目、VPC 网络、地区、子网、区域和集群的高可用性灵活结构示例。

项目、网络和集群结构。

项目

Google Cloud 在项目实体中创建其所有资源。项目是计费单位,管理员可通过它们将 Identity and Access Management (IAM) 角色与用户进行关联。在项目级应用角色时,角色将应用于项目中封装的所有资源。

您应使用项目来封装各种操作环境。例如,您的运营团队可能拥有 productionstaging 项目,而开发者可能拥有 test-dev 项目。您可以对包含最关键、最敏感的数据和工作负载的项目应用更精细、更严格的政策,同时为 test-dev 环境的开发者应用宽松灵活的政策以便他们开展实验。

集群

一个项目可能包含多个集群。如果要部署多个工作负载,可选择为这些工作负载使用一个共享集群或多个单独集群。为帮助您做出决定,请参考选择 GKE 集群的大小和范围中的最佳做法。

网络和子网

在每个项目中,您可以拥有一个或多个 VPC 网络,这些网络是物理网络的虚拟版本。每个 VPC 网络都是一个全局资源,包含其他与网络相关的资源,例如子网、外部 IP 地址、防火墙规则、路由、VPN 和 Cloud Router。在 VPC 网络中,您可以使用子网(地区性资源)来隔离和控制进出 GKE 集群间每个地区的流量。

每个项目都配有一个默认网络。您可以创建和配置其他网络以映射到现有的 IP 地址管理 (IPAM) 惯例。然后,您可以为此网络应用防火墙规则,以过滤进出 GKE 节点的流量。 默认情况下,系统会拒绝进入您的 GKE 节点的所有互联网流量。

如需控制子网之间的通信,您需要创建防火墙规则以允许流量在子网之间传递。在集群或节点池创建期间使用 --tags 标志适当地标记 GKE 节点,使防火墙规则生效。如果需要,您还可以使用标记在子网之间创建路由。

多区域和地区性集群

默认情况下,集群会在您创建时指定的单个地区中创建其集群主实例和节点。您可以通过创建多地区或区域性集群来提高集群的可用性和灵活性。 多地区和区域性集群在一个区域内的多个地区中分布 Kubernetes 资源。

多地区集群:

  • 在一个地区中创建单个集群主实例。
  • 在多个地区中创建节点。

区域性集群:

  • 跨三个地区创建三个集群主实例。
  • 默认情况下在三个地区创建节点,或根据需要在多个地区中创建节点。

区域性集群和多地区集群之间的主要区别在于区域性集群创建三个主实例,而多地区集群仅创建一个主实例。 请注意,在这两种情况下,您都需要为跨地区的节点到节点流量付费。

您可以在创建集群时选择创建多地区或区域性集群。您也可以将新地区添加到现有集群使其成为多地区集群。 但是,您无法将现有集群修改为区域性集群,也无法将地区性集群修改为非地区性集群。

Compute Engine 服务等级协议 (SLA) 涵盖 GKE 管理的集群中节点的服务可用性。此外,GKE 的 SLA 保证区域性集群和地区性集群的 Kubernetes 集群主服务器每月正常运行时间分别达到 99.5% 和 99.95%。

自 2020 年 6 月 6 日起,GKE 按每个集群每小时 $0.10 的价格收取集群管理费。有关详情,请参阅价格页面

如需详细了解多区域和地区性集群,请参阅 GKE 文档

主授权网络

您还可在集群中强制实施的额外的安全措施是启用主授权网络。此功能将限制只能从您指定的 CIDR 范围访问 API 服务器,并确保只有您网络中的团队才能管理您的集群。

启用此功能时,请注意以下事项:

  • 仅允许指定 50 个 CIDR 范围。
  • 如果您使用的是 CI/CD 流水线,则应允许您的 CI/CD 工具的 IP 地址或 CIDR 范围(即将它们列入白名单),从而确保这些工具能够访问集群的 API 服务器。

您还可以将此功能与 Cloud Interconnect 或 Cloud VPN 结合使用,以便仅从私有数据中心访问主节点。

专用集群

默认情况下,GKE 集群中的所有节点都具有公共 IP 地址。一个好的做法是创建专用集群,使所有工作器节点仅获得专用 RFC 1918 IP 地址。专用集群会强制执行网络隔离,从而降低集群面临的风险。使用专用集群意味着在默认情况下,只有网络中的客户端才能访问集群中的服务。为了允许外部服务访问集群中的服务,您可以使用 HTTP(S) 负载平衡器或网络负载平衡器。

如果要开放对 VPC 网络外部的主节点的访问,您可以将专用集群用于主授权网络。启用主授权网络后,集群主服务器端点将获得两个 IP 地址:一个内部(专用)地址和一个公共地址。内部 IP 地址可供同一地区中您网络内部的任何内容使用。主节点的公共 IP 地址可供您网络外部的任何用户或进程使用,这些用户或进程来自允许的 CIDR 范围或 IP 地址。专用节点没有外部 IP 地址,因此默认情况下,它们没有出站互联网访问权限。这也意味着在默认情况下,集群的容器运行时无法从外部容器注册表中拉取容器映像,因为这需要出站连接。您可以考虑在 Container Registry 中托管容器映像,并使用专用 Google 访问通道访问这些映像。或者,您也可以使用 Cloud NAT 或部署 NAT 网关,为专用节点提供出站访问权限。

此外,您还可以使用 VPC Service Controls 来帮助降低数据渗漏的风险。通过 VPC Service Controls,可定义用于访问这些服务的服务边界,从而帮助您保护一个或多个项目中的代管式 Google Cloud 服务。您可以设置适当的访问权限级别,向 GKE 集群中运行的应用授予访问这些代管式服务的权限。您还可以使用 VPC Service Controls 来保护 GKE 集群创建控制平面。

管理身份和访问权限

项目级层访问权限

上一部分指出您可以在项目级为用户绑定 IAM 角色。除了为单个用户授予角色之外,您还可以使用来简化角色的应用。

下图是一个 IAM 政策布局,它显示为 dev 项目和 prod 项目提供最小权限原则;其中第一个项目设置供开发者用来开发和测试他们即将推出的功能和问题修复,第二个项目用于处理生产流量:

身份和访问权限管理

如下表所示,组织中有 4 组用户,分别具有 2 个项目中不同级别的权限,这些权限通过 IAM 角色授予:

团队 IAM 角色 项目 权限
开发者 container.developer dev 可以为项目中的现有集群创建 Kubernetes 资源,但不允许创建或删除集群。
运维 container.admin prod 对项目中运行的集群和 Kubernetes 资源有完整的管理员权限。
安全 container.viewer
security.admin
prod 创建、修改和删除防火墙规则和 SSL 证书,以及查看在每个集群中创建的资源,包括正在运行的 pod 的日志。
网络 network.admin prod 创建、修改和删除网络资源,防火墙规则和 SSL 证书除外。

除了有权访问 prod 项目的 3 个团队之外,还有一个额外的服务帐号被授予了 prod 项目的 container.developer 角色,这样,该服务帐号就可以创建、列出和删除集群中的资源。服务帐号可用于为自动脚本或部署框架提供代表您执行操作的能力。 对生产项目和集群的部署应该通过自动化流水线进行。

dev 项目中,有多个开发者在同一个集群中处理同一个应用。集群用户可以通过创建命名空间来实现此操作。如此一来,每个开发者都可以在自己的命名空间中创建资源,从而避免命名冲突。此外,他们还可以为其部署重复使用相同的 YAML 配置文件,以使开发迭代期间的配置尽可能相似。不仅如此,命名空间还可用于为集群创建 CPU、内存和存储空间配额,确保一个开发者不会在集群中使用太多资源。下一部分介绍对用户在某些命名空间中的操作实施的限制。

基于角色的访问权限控制 (RBAC)

运行 Kubernetes 1.6 及更高版本的 GKE 集群可采用进一步的措施来限制用户在各集群中有权执行的操作。IAM 可以为用户提供对完整集群及其中资源的访问权限,但通过 Kubernetes 基于角色的访问权限控制 (RBAC),您可使用 Kubernetes API 进一步限制用户在其集群中可执行的操作。

通过 RBAC,集群管理员可以将精细政策应用于其集群中的各个命名空间或整个集群。Kubernetes kubectl 工具使用 gcloud 工具中的有效凭据,使集群管理员能够将角色映射到 Google Cloud 身份(用户、服务帐号和 Google 群组)作为 RoleBinding 中的主体。

借助 Google GKE 群组(Beta 版),您可以通过 Kubernetes RBAC 使用群组。要使用此功能,您需要配置 Google Workspace Google 群组,创建一个启用此功能的集群,并使用 RoleBinding 将群组与您要绑定到的角色关联。如需了解详情,请参阅基于角色的访问权限控制

例如,下图中有两名用户 user-auser-b,他们已在 app-a 命名空间中被授予 config-readerpod-reader 角色。

RBAC 授权。

还有一个例子是 Google Cloud 项目级的 IAM 角色,它使特定用户能够访问项目中的所有集群。此外,通过 RBAC 添加单独的命名空间和集群级层角色绑定,可以实现对特定集群或命名空间内的资源的精细访问。

IAM 角色绑定。

Kubernetes 包含一些默认角色,但作为集群管理员,您可以自行创建与您组织的需求更加贴合的角色。以下示例角色仅允许用户查看、修改和更新 ConfigMap,但由于不包含 delete 谓词,因此禁止删除:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: config-editor
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]

定义角色后,可以通过绑定将这些角色应用于集群或命名空间。绑定会将角色与其用户、组或服务帐号进行关联。以下示例展示了如何将先前创建的角色 (config-editor) 绑定到 bob@example.org 用户和 development 命名空间。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: config-editors
  namespace: development
subjects:
- kind: User
  name: bob@example.org
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: config-editor
  apiGroup: rbac.authorization.k8s.io

如需详细了解 RBAC,请参阅 GKE 文档

映像访问和共享

Container RegistryArtifact Registry(Beta 版)中的映像存储在 Cloud Storage 中。本部分介绍共享映像的两种方法。一种方法是公开映像,另一种方法是在项目间共享映像。

在 Container Registry 中公开映像

您可以通过公开对象和备份对象的存储分区来公开映像。如需了解详细说明,请参阅 Container Registry 访问权限控制文档

在 Container Registry 中跨项目访问映像

确保 Kubernetes 节点使用服务帐号后,您可以在项目间共享容器映像。与项目关联的默认服务帐号采用以下格式:

project-id-compute@developer.gserviceaccount.com

获得此标识符后,您可以向其授予要在其中使用 Container Registry 的项目的 storage.viewer 访问权限。使用具有受限权限的自定义服务帐号,因为默认服务帐号对整个项目拥有 Editor 访问权限

如需为集群使用其他服务帐号,请使用 --service-account 标志在创建集群或节点池时提供该服务帐号。例如,若要在项目 my-project 中使用 gke-sa 服务帐号,请执行以下命令:

gcloud container clusters create west --service-account \
    gke-sa@my-project.google.com.iam.gserviceaccount.com

如需了解如何将容器映像从 Container Registry 迁移到 Artifact Registry,请参阅从 Container Registry 转换

确定正确的映像拉取政策

imagePullPolicy 属性确定 Kubelet 是否会在启动 pod 时尝试拉取映像。您必须考虑为容器映像指定适当的 imagePullPolicy 设置。例如,您可以指定以下映像拉取政策:

imagePullPolicy: IfNotPresent

在这种情况下,Kubelet 仅当映像在节点的缓存中不可用时才检索映像的副本。

如需详细了解您可以指定的潜在映像拉取政策,请参阅 Kubernetes 文档中的容器映像

使用动态准入网络钩子来强制执行政策

动态准入网络钩子是 Kubernetes 控制平面的一部分。它们可以拦截向 API 服务器发出的传入请求。准入网络钩子是一款强大的工具,可帮助您在 GKE 集群中强制执行特定于企业的自定义政策。

Kubernetes 支持两种类型的准入网络钩子:更改准入网络钩子和验证准入网络钩子。

更改准入网络钩子会拦截准入请求,并且会更改请求。然后将请求传递到 API 服务器。

验证准入网络钩子可以检查请求,并根据您指定的规则确定请求是否有效。如果在集群中配置任何验证准入网络钩子,则会在 API 服务器验证请求后调用它们。验证准入网络钩子会拒绝请求,以确保符合网络钩子中定义的政策。

例如,您可使用更改准入网络钩子来强制实时映像拉取政策,确保无论提交 pod 创建请求的开发者指定的 imagePullPolicy 设置如何,该政策均设置为 Always

其他映像部署注意事项

最佳做法是使用私有容器注册表(例如 Container Registry)来保存组织的精选映像集。这有助于减少向部署流水线(并最终进入应用工作负载)引入漏洞的风险。如果可能,您还应启用容器分析(例如漏洞扫描),以帮助进一步降低安全风险。

如果必须使用公共映像,请考虑验证可部署到集群中的公共映像集。(如需了解详情,请参阅 Binary Authorization 部分。)您还可以考虑从 Google Cloud Marketplace 部署预封装的 Kubernetes 应用。Google Cloud Marketplace 上列出的 Kubernetes 应用已经过 Google 测试和审核,其中包括适用于维护和支持的漏洞扫描以及合作伙伴协议。

此外,请务必采用良好的映像版本控制做法:使用良好的标记惯例,并在适用的情况下考虑使用摘要(而不是标记)。

使用 Workload Identity 与 Google Cloud 服务 API 进行交互

通常,企业架构涉及跨云服务(云代管式服务和托管式服务)的架构组件。它是 GKE 应用或服务与 Google Cloud 代管式服务(如 Cloud Storage 和 BigQuery)通信的常用模式。例如,在通过 GKE 中的批量作业将客户记录处理到 BigQuery 中供后续分析之后,您可能需要存储这些记录。

Workload Identity 是一项 GKE 功能,可让您的 GKE 服务与更广的 Google Cloud 生态系统进行交互,而无需将服务帐号凭据存储为 Kubernetes 密钥。借助此功能,您可以通过 IAM 绑定将 Kubernetes 服务帐号映射到 Google Cloud 服务帐号。随后,当 pod 使用 Kubernetes 服务帐号运行时,它们可以假设访问 Google Cloud 服务所需的身份。请注意,这假设您已授予访问 Google Cloud 服务帐号所需的服务访问权限级别。

如需详细了解 Workload Identity,请参阅 GKE 文档

管理集群安全

安全是一项多方面的准则,在 GKE 集群的企业部署中至关重要。本部分介绍了可用于强化集群安全的几个因素。

映像的漏洞扫描

Container Registry 可扫描推送给它的映像,以查找基于 Ubuntu、Alpine、Debian、CentOS 和 RedHat 的映像的已知安全漏洞。我们建议您利用此功能扫描您计划在 Kubernetes 集群中使用的映像。

您可以在 Google Cloud Console 中或通过运行以下 gcloud 命令来查看映像的漏洞:

gcloud beta container images describe \
    hostname/project-id/image-id:tag  \
    --show-package-vulnerability

替换以下内容:

  • hostname:以下主机名位置之一:
    • gcr.io 目前用于在美国托管映像。
    • us.gcr.io 在美国托管映像,使用的存储分区与 gcr.io 托管的映像不同。
    • eu.gcr.io 在欧盟托管映像。
    • asia.gcr.io 在亚洲托管映像。
  • project-id:包含映像的项目的 ID。
  • image-id:要查看其漏洞的映像的 ID。
  • tag:要获取其相关信息的映像标记。

如果对 Container Registry 代码库进行更改,您的组织将能够从自动跟踪通知和接收通知中受益。例如,您可以在创建新映像或删除映像时收到通知。您可以构建流水线,其中应用侦听器可订阅 Container Registry 事件发布到的 Pub/Sub 主题。然后,您可以使用这些事件触发构建或自动部署。如需了解详情,请参阅 Container Registry 文档

Binary Authorization

使用 Kubernetes 时,您必须确定映像是否应以及何时可用于部署到集群。对于此任务,您可以使用 Binary Authorization。这是一种部署时构造,它让您定义一个工作流,该工作流必须强制执行签名,才能为您的集群部署签名(证明)。

工作流根据政策进行定义。当您通过 CI/CD 流水线移动代码并因此移动容器映像时,Binary Authorization 会对 Binary Authorization 政策中定义的每个阶段记录证明。这些证明用于验证映像已成功传递定义的里程碑。

Binary Authorization 与 GKE 部署 API 集成,并可确保映像的部署受拥有全部所需证明的映像的约束。系统会自动记录失败的部署尝试,而且集群管理员可以查看和审核。

如需查看教程了解如何使用 Cloud Build 为 GKE 实现 Binary Authorization,请参阅使用 Cloud Build 和 GKE 实现 Binary Authorization

在 GKE Sandbox 中使用 gVisor 安全访问

容器有一层安全和内核隔离,但可能仍然容易遭到攻击,进而导致攻击者获得对主机操作系统 (OS) 的访问权限。要在容器与其主机操作系统之间实现安全隔离,更灵活的一种方法是另外创建一个分离层。一种方法是使用 GKE Sandbox

GKE Sandbox 使用 gVisor,它是 Google 发布的开源容器运行时。gVisor 在内部创建容器与之互动的虚拟内核,即可抽象出容器与主机内核的覆盖率。此外,它还控制容器可以执行的文件操作和网络操作。

由于 GKE Sandbox 会产生额外的隔离层,因此可能会需要额外的内存和产生额外的 CPU 开销。在使用 GKE Sandbox 之前,您应该考虑哪些工作负载需要这种高级别的安全措施。通常情况下,最好选择基于外部映像的服务。

以下 gcloud 命令展示了如何创建启用了 GKE Sandbox 的节点池:

gcloud container node-pools create node-pool-name \
    --cluster=cluster \
    --image-type=cos_containerd \
    --sandbox type=gvisor \
    --enable-autoupgrade

替换以下内容:

  • node-pool-name:要创建的模式池的名称。
  • cluster:要在其中添加节点池的集群。

如需指定使用 GKE Sandbox 运行的应用 pod,请将 gVisor 纳入 pod 规范中,如以下示例所示:

apiVersion: v1
kind: Pod
metadata:
  name: sample-saas-app
  labels:
    app: saas-v1
spec:
  runtimeClassName: gvisor
  containers:
    - name: sample-node-app-v1
      image: [image]

如需详细了解 GKE Sandbox,请参阅 Google Cloud 博客中的 GKE Sandbox:深度防护您的 pod。如需详细了解您的应用是否适合 GKE Sandbox,请参阅 GKE 文档

审核日志记录

Kubernetes 审核日志记录会记录对 Kubernetes API 服务器发出的所有 API 请求。此日志记录有助于您检测异常情况以及异常的访问和配置设置模式。以下是您可能想要查看和提醒的示例:

  • 删除部署。
  • 附加或使用 exec 来访问具有特权访问权限的容器。
  • 修改 ClusterRole 对象或为集群角色创建角色绑定。
  • kube-system 命名空间中创建服务帐号。

GKE 将 Kubernetes 审核日志记录与 Cloud Logging 集成。访问这些日志的方式与访问 Cloud 项目中运行的资源的日志的方式相同。可以记录向 Kubernetes API 服务器发出的 API 请求,您可以使用这些请求来查看 API 活动模式。

Kubernetes API 服务器捕获的每个请求(事件)都会使用您定义的一个或多个政策进行处理。这些政策可以是 Kubernetes 审核政策(确定记录哪些事件),也可以是 Google Kubernetes Engine 审核政策(确定事件是记录在管理员活动日志中还是记录在数据日志中)。管理员活动日志默认启用。如果需要记录有关集群中读取或写入的元数据和数据的详细信息,您还可以启用数据访问日志记录。请注意,启用数据访问日志记录可能会产生额外费用。如需了解详情,请参阅价格文档。

PodSecurityPolicy

一种常见的攻击途径是部署拥有已升级特权的 pod 来试图访问 Kubernetes 集群。PodSecurityPolicy 定义了 pod 规范中的一组规则,它们概述了 pod 可执行的操作。您可以在 Kubernetes 中实施 PodSecurityPolicy 作为准入控制器资源。您可以使用它来限制对命名空间的使用方式、卷类型的使用方式以及底层操作系统功能的访问权限。

如需创建启用了 PodSecurityPolicy 的 GKE 集群,请使用以下命令。将 cluster-name 替换为要向其中添加 PodSecurityPolicy 的集群的名称。

gcloud beta container clusters create cluster-name \
    --enable-pod-security-policy

下例显示了一个 PodSecurityPolicy,它用于限制创建特权 pod 的能力:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: default-pod-security-policy
spec:
  privileged: false
  hostPID: false
  seLinux:
    rule: RunAsAny
  runAsUser:
    rule: MustRunAsNonRoot

容器安全注意事项

Kubernetes 服务的基础构件是容器。这使得容器安全在规划集群安全和政策时成为关键因素。请仔细注意下列各项:

  • 从中构建容器的映像。
  • 您分配给容器的特权。
  • 容器与主机操作系统和其他服务的交互方式。
  • 容器访问和记录敏感信息的方式。
  • 管理集群中容器的生命周期的方式。

如需了解详情和最佳做法,请参阅构建操作容器的文档。

配置网络

Kubernetes 提供了服务抽象,其中包含集群内多组 pod 以及集群外运行的旧系统之间的负载平衡和服务发现。以下部分介绍了在 Kubernetes pod 之间以及与其他系统(包括其他 Kubernetes 集群)之间进行通信的最佳做法。

VPC 原生集群与基于路由的集群的对比

根据 GKE 集群将流量从一个 pod 路由到另一个 pod 的方式,这些集群可以分为两类。第一类集群使用别名 IP 地址范围路由流量,这称为 VPC 原生集群。第二类集群使用 Google Cloud 路由,称为基于路由的集群

VPC 原生集群使用 pod 网络的别名 IP 地址范围。这意味着控制平面会自动管理 pod 的路由配置,而不是为 GKE 集群中的每个节点配置和维护静态路由。借助别名 IP 地址范围,您可以配置多个内部 IP 地址来表示虚拟机中托管的容器或应用,无需定义单独的网络接口。Google Cloud 将自动安装 VPC 网络路由,以便为主要网络接口的子网获得主要和别名 IP 地址范围。这大幅简化了 pod 之间的流量路由。

此外,VPC 原生集群不受路由配额的限制。在集群结构中利用别名 IP 地址范围可直接访问 Google 服务,例如 Cloud Storage 和 BigQuery;否则,只能通过 NAT 网关进行访问。

让 GKE 集群与本地的应用和服务生态系统安全地通信是企业采用的一种常见模式。别名 IP 地址范围允许这样做,因为别名 IP 地址可以通过 Cloud VPNCloud Interconnect 发现。这有助于为您的本地基础架构和 Google Cloud 基础架构提供安全连接。

您需要确定哪种集群类型最适合您的网络拓扑。主要因素是网络中 IP 地址的可用性、企业中的集群(节点)扩展计划,以及与生态系统中其他应用的连接性。VPC 原生集群在网络中往往会消耗更多的 IP 地址,因此您应考虑到这一点。请注意,您无法在创建并将基于路由的集群迁移到 VPC 原生集群后再将 VPC 原生集群迁移到基于路由的集群,因此请务必了解所选选项的影响,然后再实现它。

在同一集群中进行通信

服务发现

Kubernetes 允许您根据一组标签来定义对集群中运行的 pod 分组的服务。使用 DNS 可以在集群中发现此组 pod。如需详细了解 Kubernetes 中的服务发现,请转至连接应用和服务文档。

DNS

本地集群 DNS 服务器 kube-dns 部署在每个 GKE 集群中,用于将服务名称映射到运行状况良好的 pod IP 地址。默认情况下,Kubernetes DNS 服务器返回服务的集群 IP 地址。 此 IP 地址在服务的整个生命周期内是静态的。向此 IP 地址发送流量时,节点上的 iptables 将在与服务选择器匹配的就绪 pod 中对数据包进行负载平衡。这些 iptables 由每个节点上运行的 kube-proxy 服务自动编写。

如果您要使用服务发现和运行状况监控,但却要 DNS 服务返回 pod 的 IP 地址而不是虚拟 IP 地址,您可将 ClusterIP 字段设置为“无”,这会将该服务预配为无头服务。在这种情况下,DNS 服务器返回 A 记录列表,此列表将服务的 DNS 名称映射到与服务定义的标签选择器匹配的就绪 pod 的 A 记录。响应中的记录进行轮替以便在各个 pod 上传播负载。但请注意,某些客户端 DNS 解析器可能会缓存 DNS 应答,导致 A 记录轮替无效。如需了解使用 ClusterIP 的优点,请参阅 Kubernetes 文档

无头服务的一个典型使用场景是 StatefulSets。StatefulSets 非常适合运行必须为其副本提供稳定存储空间和网络连接的有状态应用。此类部署预配具有稳定网络标识的 pod,这意味着其主机名可以在集群中进行解析。虽然 pod 的 IP 地址可能会更改,但其主机名 DNS 条目将保持最新且可解析。

数据包流:ClusterIP

下图展示了标准 Kubernetes 服务的 DNS 响应和数据包流。虽然 pod IP 地址可从集群外部路由,但服务的集群 IP 地址只能在集群中访问。 这些虚拟 IP 地址通过在每个 Kubernetes 节点中执行目的网络地址转换 (DNAT) 来实现。 在每个节点上运行的 kube-proxy 服务使每个节点上的转发规则保持最新,以将集群 IP 地址映射到集群中运行状况良好的 pod 的 IP 地址。如果本地节点上运行了该服务的 pod,则使用该 pod,否则将随机选择集群中的某个 pod。

ClusterIP 服务。

如需详细了解如何实现 ClusterIP,请转到 Kubernetes 文档。如需深入了解 GKE 网络,请观看 YouTube 上的 Next 2017 讲座:

无头服务

以下是无头服务的 DNS 响应和流量模式的示例。通过默认 Google Cloud 子网路由表即可路由 Pod IP 地址,您的应用还可直接访问这些地址。

无头服务的 DNS 响应和流量模式示例

网络政策

您可以使用 GKE 网络政策强制执行功能来控制集群的 pod 与 Service 之间的通信。要在 GKE 上定义网络政策,可以使用 Kubernetes Network Policy API 创建 pod 级层的防火墙规则。这些防火墙规则确定了哪些 pod 和 Service 可以在集群内相互访问。

网络政策是一种深度防御机制,可增强集群上运行的工作负载的安全性。例如,您可以创建网络政策,以确保应用中被破解的前端服务无法直接与低了几个级层的计费或记帐服务进行通信。

网络政策还可用于隔离属于不同租户的工作负载。例如,您可以通过定义一个命名空间一个租户的模型来提供安全的多租户服务。在此类模型中,网络政策规则可确保给定命名空间中的 pod 和服务无法访问其他命名空间中的其他 pod 或服务。

如需详细了解网络政策,请参阅 GKE 文档

从 Google Cloud 内部连接到 GKE 集群

如需从集群外部但在 Google Cloud 网络的专用 IP 地址空间内连接到您的服务,请使用内部负载平衡。在 Kubernetes 中创建具有 type: Load Balancercloud.google.com/load-balancer-type: Internal 注释的服务时,系统会在您的 Google 项目中创建内部网络负载平衡器,并将其配置为在 pod 之间分配 TCP 和 UDP 流量。

从集群内部连接到外部服务

在许多情况下,有必要将在 Kubernetes 内运行的应用与集群外部的服务、数据库或应用连接起来。有 3 种方案供您选择,如下所述。

存根网域

在 Kubernetes 1.6 及更高版本中,您可以配置集群内部 DNS 服务 (kube-dns),将特定网域的 DNS 查询转发到外部 DNS 服务器。如果您拥有授权 DNS 服务器,并应从中查询 Kubernetes pod 要用的网域,这会非常有用。

外部名称服务

外部名称服务允许您将 DNS 记录映射到集群中的服务名称。在这种情况下,集群内服务的 DNS 查找会返回您选择的 CNAME 记录。如果您只有几条记录需要映射回现有的 DNS 服务,则应使用此方法。

无选择器的服务

您可以创建无选择器的服务,然后手动向其添加端点,以使用正确的值填充服务发现。此方案允许您为集群内的服务使用相同的服务发现机制,同时确保仍可通过 DNS 访问没有服务发现的系统。虽然这种方法最灵活,但从长远来看,它需要最多的配置和维护。

如需详细了解 DNS,请转到 Kubernetes DNS Pod 和服务文档页面。

在 Kubernetes 中配置服务以接收互联网流量

您可以使用 NodePort、ClusterIP 和 LoadBalancer 公开 Kubernetes 服务。

但是,如果您有许多面向外部的服务,则可以考虑使用 Kubernetes Ingress 资源。Ingress 为集群提供了入口点,并允许您定义路由规则,以将传入请求路由到集群中的一个或多个后端服务。在 GKE 中,GKE Ingress 控制器将 Ingress 资源实现为 Google Cloud HTTP(S) 负载平衡器,并根据 Ingress 资源及其关联服务中的信息对其进行配置。

只有在应用通过 HTTP(S) 处理流量时,才能使用 Kubernetes Ingress 资源。如果后端服务使用 TCP 或 UDP 协议,则必须改为使用网络负载平衡器。例如,如果您需要将数据库作为服务公开,可能就需要这样做。

后端配置

BackendConfig 是一种自定义资源定义,可以提供 Kubernetes Ingress 控制器使用的其他规范配置。在 GKE 集群中部署 Ingress 对象时,Kubernetes Ingress 控制器将配置 HTTP(S) 负载平衡器,以便将传入请求路由到您在 Ingress 清单中指定的后端服务。

您可以使用如下规范补充负载平衡器的配置:

  • 使用 Cloud CDN 启用缓存。
  • 使用 Google Cloud Armor 添加 IP 地址或 CIDR 许可名单(白名单)。
  • 使用 Identity-Aware Proxy (IAP) 控制应用级访问权限。
  • 为受集群中 Ingress 对象约束的服务配置服务超时和连接排空超时。

如需详细了解如何在 GKE 中配置 BackendConfig 自定义资源,请参阅 GKE 文档

使用服务网格

服务网格提供了一种统一的方式来连接、保护和管理 Kubernetes 集群中运行的微服务。例如,您可作为 GKE 插件添加的 Istio 服务网格可以管理服务到服务的身份验证和通信、强制执行访问政策,还能收集可用于审核和管理 GKE 集群的丰富的遥测数据点。

服务网格提供的主要功能包括:

  • 流量管理。借助服务网格,您可以定义精细的规则来确定流量的路由方式,并在若干服务之间或在同一服务的不同版本之间拆分流量。这样可以更轻松地发布 Canary 版部署和蓝绿部署。

  • 内置可观测性。网格以统一方式记录网络流量(第 4 层和第 7 层)指标,无需您编写代码来检测服务。

  • 安全。网格实现了服务之间的双向 TLS (mTLS)。它不仅为传输中的数据提供安全通道,还可帮助您管理网格中服务的身份验证和授权。

总之,通过 Istio 等服务网格,您可以将系统级任务委托给网格基础架构,这有助于提高 Kubernetes 集群中运行的服务的整体敏捷性、稳健性以及松散耦合。

如需了解详情,请参阅 Google Kubernetes Engine 上的 Istio

防火墙

GKE 节点在 Compute Engine 中配置为实例。因此,它们遵循与其他实例相同的有状态防火墙机制。这些防火墙规则通过使用标记在您的网络中应用于实例。每个节点池都将收到自己的一组标记,你可在规则中使用这些标记。默认情况下,属于节点池的每个实例都会收到一个标记,该标记标识此节点池所属的特定 Kubernetes Engine 集群。此标记用于 Kubernetes Engine 自动为您创建的防火墙规则。您可以使用 gcloud command-line tool 工具中的 --tags 标志在创建集群或节点池时添加自己的自定义标记。

例如,如需允许内部负载平衡器访问所有节点上的端口 8080,您可以使用以下命令:

gcloud compute firewall-rules create allow-8080-fwr \
    --target-tags allow-8080 \
    --allow tcp:8080 \
    --network gke \
    --source-range 130.211.0.0/22
gcloud container clusters create my-cluster --tags allow-8080

以下示例展示如何标记一个集群,以使互联网流量能够访问端口 30000 上的节点,同时另一集群被标记为允许来自 VPN 的流量访问端口 40000。当通过只能使用特权网络(如访问公司数据中心的 VPN)或从项目中的其他集群进行访问的 NodePort 公开服务时,这会非常有用。

以不同方式标记两个集群

连接到本地数据中心

有几种 Cloud Interconnect 方案可用于连接到本地数据中心。这些方案不是互斥的,因此您可以根据工作负载和需求来组合使用:

  1. 互联网,用于非数据密集型或延迟敏感型工作负载。 Google 拥有超过 100 个连接到世界各地服务提供商的接入点 (PoP)。
  2. 直接对等互连,用于需要专用带宽、对延迟时间敏感,且需要访问所有 Google 服务(包括全套 Google Cloud 产品)的工作负载。直接对等互连是第 3 层连接,通过交换 BGP 路由完成,因此需要已注册的 ASN。
  3. 运营商对等互连,与直接对等互连相同,但通过服务提供商完成。如果您没有已注册的 ASN,或者已与偏好的服务提供商建立关系,那么这会是一个绝佳方案。
  4. 如果需要 IPsec 加密,或者希望将专用网络扩展到专用 Compute Engine 网络,则可以通过第 3 层互连和互联网方案(1、2 和 3)来配置 Cloud VPN

管理集群可操作性

本部分介绍在管理和操作 GKE 集群时需要考虑的关键因素。

资源配额

Kubernetes 资源配额提供的限制条件会限制集群中每个命名空间的总体允许资源消耗量。如果您的集群具有隔离业务功能或开发阶段的 Kubernetes 命名空间,则可以使用配额来限制各种资源,例如 CPU 利用率、内存或可在命名空间内创建的 pod 数量和服务数量。为了确保 GKE 集群的控制平面的稳定性,Kubernetes 会自动将默认的不可替换的资源配额应用于任何具有 5 个或更少节点的 GKE 集群中的每个命名空间。

资源限制

您可以使用 Kubernetes LimitRange 对象对创建容器和 pod 的最小和最大资源边界实施精细限制。以下示例展示了如何使用 LimitRange:

apiVersion: v1
kind: LimitRange
metadata:
  name: sample-limits
spec:
  limits:
    - max:
        cpu: "400m"
        memory: "1Gi"
      defaultRequest:
        cpu: "200m"
        memory: "500Mi"
      type: Container

Pod 中断预算

Pod 中断预算 (PDB) 有助于防止您的团队自愿删除或意外删除 pod 或部署。PDB 无法防止由节点关闭或重启而导致的非自愿中断。通常,操作员为应用创建一个 PDB,用于定义应该为应用运行的 pod 的最小副本数。

如果在某家企业中开发者要处理多个应用,那么错误不可避免,而且开发者或管理员可能会意外运行用于删除 pod 或部署(也就是删除 Kubernetes 资源)的脚本。但是,通过定义 PDB,您可以始终确保为 Kubernetes 应用维持一组最低限度的有效资源。

GKE 升级期间会采用您为 GKE 集群配置的 PDB。这意味着,您可以在升级期间控制应用的可用性。以下示例展示了如何配置 PDB。

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: nginx-pdb
  spec:
    minAvailable: 4
    selector:
      matchLabels:
        app: nginx

管理 Kubernetes 升级

您应将 GKE 上的 Kubernetes 集群更新为符合您要求的最新版的 Kubernetes。这样,您就可以利用已推出的新功能,并确保集群节点的底层操作系统已得到修补且是最新的。

如果需要升级,您可以考虑以下类型:

  • 用于主节点和工作器节点的 GKE 集群的主要和次要 Kubernetes 版本升级。
  • 构成集群的虚拟机(节点)的操作系统补丁程序和升级。

升级 Kubernetes 版本

您可以通过两种方法升级 GKE 主节点。第一种方法是让 Google Cloud 自动升级您的 GKE 集群主服务器。第二种方法是在新版本推出时启动手动升级。

您可在控制台中查看通知,它们在有可用的升级时针对 GKE 集群显示。我们建议您在审核了发布内容,并在要升级到的版本上运行的沙盒集群中测试了应用后,再触发版本升级。

当区域级集群的主节点正在进行升级时,控制平面不可用。这意味着您无法与 API 服务器进行互动来在集群中添加或移除资源。如果您无法忍受升级区域性集群中主节点的停机时间,则可以通过部署地区性 GKE 集群来使主节点具有高可用性。通过这种方法,您可以跨区域分布多个主节点。当一个主节点升级时,对 API 服务器的任何控制平面请求都会路由到其他主节点。

与主节点一样,您同样可通过两种方法将 GKE 工作器节点升级到与集群主节点相同的版本:

  • 您可以让 GKE 为您管理工作器节点升级。为此,您可以为 GKE 集群中的节点池启用自动节点升级。
  • 您可以手动升级 GKE 工作器节点。当升级可用时,GKE 控制台会显示一条提醒。当您看到该提醒时,可以将升级应用于 GKE 工作器节点。

在这两种情况下,当应用升级时,GKE 都会对工作器节点应用滚动更新:当有新的替换节点可用于响应传入的请求时,它会系统地排空、关闭和升级一个节点。

节点自动修复

GKE 节点自动修复功能用于管理 GKE 节点的运行状况检查。如果发现任何节点运行状况不佳,GKE 会启动节点修复进程。

代管式节点修复进程需要排空和重新创建节点。如果 GKE 集群中的多个节点同时需要修复,则 Google Cloud 会在内部确定可并行修复的节点数量。

如果您在 Google Cloud Console 中创建集群,则自动修复功能会自动启用。对于使用 gcloud command-line tool 工具创建的 GKE 集群,您可以通过在集群创建命令中添加 --enable-autorepair 标志来明确启用自动修复。

如果您的 GKE 集群具有多个节点池,则自动修复功能可让您精确控制要为其启用节点自动修复功能的节点池。

自动扩缩 GKE 集群

对于在其 Kubernetes 集群中运行的应用,企业经常会遇到不同的传入负载。为了响应这些业务驱动的更改,您可以使 GKE 集群能够自动做出响应,并根据指标进行扩缩。

自动扩缩包括多个维度,如以下几个部分所述。

集群自动扩缩器

GKE 集群自动扩缩器会根据您的工作负载需求自动添加和移除集群节点。为单个节点池启用集群自动扩缩器。对于每个节点池,GKE 会检查是否有由于容量不足而等待调度的 pod。如果有,集群自动扩缩器会将节点添加到该节点池中。

很多因素结合起来共同影响 GKE 决定纵向缩容的方式。如果节点上运行的 pod 对该节点的利用率不到 50%,而且正在运行的 pod 可被安排到具有容量的其他节点上,那么利用率低下的节点会被排空并终止。

通过指定集群自动扩缩器可调节到的最小和最大节点数,您可以为节点池设置边界。

横向 Pod 自动扩缩 (HPA)

借助 Kubernetes,您可以创建横向 Pod 自动扩缩器 (HPA),用于配置 Kubernetes 部署或 ReplicaSet 扩缩的方式以及扩缩决策应依据的指标。默认情况下,HPA 控制器根据 CPU 利用率作出自动扩缩决策。然而,HPA 控制器还可以根据自定义指标(例如 HTTP 请求数)来计算 pod 应该如何扩缩。要让 HPA 响应自定义指标,通常还需要其他监控仪器。

如需了解详情,请参阅 KubernetesGKE 文档。

纵向 Pod 自动扩缩 (VPA)

借助 GKE 集群中的纵向 Pod 自动扩缩 (VPA) 功能,您可将为容器指定最佳 CPU 和内存请求的任务进行分流。必要时,VPA 会调整对集群中容器的资源分配量。借助 VPA,您可以通过在每个节点的容器级层进行优化来优化集群的资源利用率。此外,这还将为您节省维护资源所需的管理时间。

VPA 可与下一部分中介绍的节点自动预配功能配合使用。

由于 Kubernetes 的限制,pod 上的资源请求只能在 pod 重启时更改。因此,若要进行更改,VPA 会逐出 pod。如需了解详情,请参阅 GKEKubernetes 文档。

节点自动预配

通过节点自动预配功能,GKE 集群自动扩缩器能够在自动扩缩器确定需要其他节点池时自动预配这些节点池。如果这些节点池中没有节点,集群自动扩缩器也可以删除自动预配的节点池。

GKE 集群自动扩缩器会根据许多因素做出节点自动预配决策。这些因素包括 pod 请求的资源数量、您已指定的 pod 亲和性,以及 GKE 集群中定义的节点污点和容忍机制

如果您的 GKE 集群中运行各种工作负载,则节点自动预配功能非常有用。例如,如果您的 GKE 集群具有依赖于 GPU 的工作负载,则您可以在预配了支持 GPU 的节点的专用节点池中运行该集群。您可以指定最小和最大节点池大小来定义节点池扩缩边界。

如需详细了解节点自动预配功能以及启用时机,请参阅使用节点自动预配

后续步骤

  • 了解构建操作容器的最佳做法。
  • 如需了解如何使用 Istio 向 Cloud Run on GKE 验证最终用户身份,请参阅本教程
  • 试用其他 Google Cloud 功能。查阅我们的教程