使用 Config Sync 进行安全发布

本文档向集群运维人员和平台管理员介绍了如何使用 Config Sync 在多个环境中安全地发布更改。此方法有助于避免同时影响所有环境的错误。

借助 Config Sync,您可以使用存储在 Git 代码库中的文件来管理单个集群、多租户集群和多集群 Kubernetes 配置。

配置可以表示若干内容,包括:

Config Sync 特别适合用于部署运行基于 Google Kubernetes Engine (GKE) 企业版构建的平台所需的配置、政策和工作负载,例如安全代理、监控代理和证书管理器。

虽然您可以使用 Config Sync 部署面向用户的应用,但我们不建议将其发布生命周期与前面提到的管理工作负载的发布生命周期相关联。相反,我们建议您使用专用于应用部署的工具(如持续部署工具),以便应用团队可以负责其发布时间表。

Config Sync 是一款强大的产品,可以管理许多元素,因此您需要采取措施来避免产生重大影响的错误。本文档介绍了创建保护措施的几种方法。第一部分介绍分阶段发布,第二部分重点介绍测试和验证。第三部分介绍如何监控部署。

使用 Config Sync 实现分阶段发布

在多集群环境中(这是 GKE Enterprise 用户的常见情况),我们不建议同时在所有集群中应用配置更改。分阶段发布(按集群划分)更安全,因为这样可以降低任何错误的潜在影响。

您可以通过多种方式使用 Config Sync 实现分阶段发布:

  • 使用 Git 提交或标记来手动将所需的更改应用到集群。
  • 在合并更改时,使用 Git 分支自动应用更改。您可以将不同的分支用于不同的集群组。
  • 使用 ClusterSelectorNamespaceSelector 对象选择性地将更改应用于集群或命名空间的子组。

分阶段发布的所有方法都各有利弊。下表显示了您可以同时使用这些方法中的哪些方法:

兼容性 Git 提交或标记 Git 分支 集群选择器 命名空间选择器
Git 提交或标记 不兼容 兼容 兼容
Git 分支 不兼容 兼容 兼容
集群选择器 兼容 兼容 兼容
命名空间选择器 兼容 兼容 兼容

以下决策树可帮助您确定何时使用某种分阶段发布方法。

适用于发布方法的决策树。

使用 Git 提交或标记

与其他分阶段发布方法相比,使用 Git 提交或标记提供最大的控制,这是最安全的。您可以使用控制台中的 Google Cloud 控制台中的“Config Sync”页面同时更新多个集群。如果要逐个对集群应用更改,并精确控制发生更改的时间,请使用此方法。

在此方法中,您可以将每个集群“固定”到代码库的特定版本(提交或标记)。此方法与使用 Git 提交作为容器映像标记类似。您可以通过在 RootSyncRepoSync 自定义资源spec.git.revision 字段中指定提交、标记或哈希来实现此方法。

如果您使用 Kustomize 等工具管理 RootSyncRepoSync 自定义资源,则可以减少发布所需的手动工作量。使用此类工具时,您只需在一个位置更改 revision 参数,然后按照您选择的顺序、选择性地将新的 RootSyncRepoSync 自定义资源应用于集群即可。

此外,您还可以使用 Google Cloud 控制台同时更新属于同一舰队的多个集群的 revision 参数。但是,如果您有可以更新配置的自动化系统,则不建议使用 Google Cloud 控制台进行配置更改。

例如,以下 RootSync 定义将 Config Sync 配置为使用 1.2.3 标记:

apiVersion: configsync.gke.io/v1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-sync-system
spec:
  sourceType: git
  sourceFormat: unstructured
  git:
    repo: git@example.com:gke/config-sync.git
    revision: 1.2.3
    auth: ssh

如果您将此配置应用于集群,Config Sync 将使用 example.com:gke/config-sync.git 代码库的 1.2.3 标记。

如需更新集群,请将 spec.git.revision 字段更改为集群的新值。这让您可以定义更新哪些集群以及何时更新。如果需要回滚更改,请将 spec.git.revision 字段更改回其原值。

下图展示了此方法的发布过程。首先,将更改提交到 Config Sync 代码库,然后更新所有集群上的 RootSync 定义:

Git 提交和标记的发布流程。

我们建议您执行以下操作:

  • 使用 Git 提交 ID,而非标记。由于 Git 运行的方式,可以保证其永远不会更改。例如,git push --force 无法更改 Config Sync 正在使用的提交内容。此方法适合用于审核目的,并可以跟踪日志中正在使用的提交。此外,与标记不同,提交 ID 还无需执行额外的步骤。
  • 如果您更喜欢使用 Git 标记而不是 Git 提交 ID,则如果您使用的是支持保护的 Git 解决方案,则可以保护您的标记。
  • 如果要同时更新多个集群,您可以在 Google Cloud 控制台中执行此操作。如需同时更新多个集群,这些集群必须属于同一舰队(并且属于同一项目)。

使用 Git 分支

如果您希望在集群合并到 Git 代码库中后立即将更改应用于集群,请将 Config Sync 配置为使用 Git 分支,而不是提交内容或标记。在此方法中,您将在 Git 代码库中创建多个长期存在的分支,并在不同的集群中配置 Config Sync,以从不同的分支读取其配置。

例如,一个简单的模式有两个分支:

  • 非生产集群的 staging 分支。
  • 生产集群的 main 分支。

对于非生产集群,请创建 RootSyncRepoSync 对象,并将 spec.git.branch 字段设置为 staging。对于生产集群,请创建 RootSyncRepoSync 对象,并将 spec.git.branch 参数设置为 main

例如,以下 RootSync 定义将 Config Sync 配置为使用 main 分支:

apiVersion: configsync.gke.io/v1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-sync-system
spec:
  git:
    repo: git@example.com:gke/config-sync.git
    branch: main
    auth: ssh

下图展示了此方法的发布过程:

Git 分支的发布过程。

您可以使用两个以上的分支,或者使用映射到环境之外的其他分支,调整此模式以满足特定的需求。如果需要回滚更改,请使用 git revert 命令在同一分支上创建一个新的提交,该分支将从以前的提交中恢复更改。

我们建议您执行以下操作:

  • 处理多个集群时,请至少使用两个 Git 分支来帮助区分生产集群和非生产集群。
  • 大多数 Git 解决方案都可让您使用受保护的分支功能以防止这些分支的删除或未经审核的更改。如需了解详情,请参阅 GitHubGitLabBitbucket 的文档部分。

使用 ClusterSelector 和 NamespaceSelector 对象

Git 分支是跨多个集群进行分阶段发布更改的好方法,这些集群最终都将拥有相同的政策。但是,如果您只想对部分集群或命名空间发布更改,请使用 ClusterSelectorNamespaceSelector 对象。这些对象具有类似的目标:通过这些对象,您可以将其仅应用于具有特定标签的集群或命名空间。

例如:

  • 通过使用 ClusterSelector 对象,您可以根据群集所在的国家/地区,针对不同的合规性制度将不同的政策应用于群集。
  • 通过使用 NamespaceSelector 对象,您可以将不同的政策应用于内部团队和外部承包商使用的命名空间。

此外,您还可以使用 ClusterSelectorNamespaceSelector 对象实现高级测试和发布方法,例如:

  • Canary 版本的政策,可让您将新政策部署到一小部分集群和命名空间,以长期研究该政策的影响。
  • A/B 测试,可让您将同一政策的不同版本部署到不同的集群,从而研究政策版本的影响的差异,然后选择最佳版本在所有位置进行部署。

例如,假设一个组织有多个生产集群。平台团队已使用 ClusterClusterSelector 对象创建了两类生产集群,分别名为 canary-prodprod(请参阅使用 ClusterSelector)。

平台团队希望使用 Policy Controller 发布一项政策,以强制在命名空间上存在团队标签,从而识别每个命名空间所属的团队。我们已经在试运行模式下推出了此政策的一个版本,现在希望在少数集群上执行此政策。通过使用 ClusterSelector 对象,它们可以创建两个不同的 K8sRequiredLabels 资源,这些资源将应用于不同的集群。

  • K8sRequiredLabels 资源适用于类型为 prod 的集群,并将 enforcementAction 参数设置为 dryrun

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sRequiredLabels
    metadata:
      name: ns-must-have-team
      annotations:
        configmanagement.gke.io/cluster-selector: prod
    Spec:
      enforcementAction: dryrun
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Namespace"]
      parameters:
        labels:
          - key: "team"
    
  • K8sRequiredLabels 资源适用于类型为 canary-prod 的集群,而不使用 enforcementAction 参数,这意味着政策实际上会被强制执行:

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sRequiredLabels
    metadata:
      name: ns-must-have-team
      annotations:
        configmanagement.gke.io/cluster-selector: canary-prod
    spec:
      match:
        kinds:
          - apiGroups: [""]
        kinds: ["Namespace"]
      parameters:
        labels:
          - key: "team"
    

configmanagement.gke.io/cluster-selector 注解允许团队仅在类型为 canary-prod 的集群中强制执行政策,从而防止任何意外副作用传播到整个生产环境。如需详细了解政策控制器的试运行功能,请参阅创建限制条件

我们建议您执行以下操作:

  • 如果您需要对集群或命名空间的一部分无限期地或很长一段时间应用配置更改,请使用 ClusterSelectorNamespaceSelector 对象。
  • 如果您使用选择器来发布更改,请务必小心。如果您使用 Git 提交,则任何错误一次仅影响一个集群,因为您是逐个发布集群的。但如果使用 Git 分支,则任何错误都可能会影响使用该分支的所有集群。如果使用选择器,错误可能会立即影响所有集群。

实施审核、测试和验证

Config Sync 的一个优势是,能够以声明方式管理所有内容,如 Kubernetes 资源、云资源和政策。这意味着源代码控制管理系统中的文件表示资源(如果是 Config Sync,则为 Git 文件)。借助此特性,您可以实现已用于应用的源代码的开发工作流:审核和自动化测试。

实施审核

由于 Config Sync 基于 Git,因此您可以使用首选 Git 解决方案来托管 Config Sync 代码库。您的 Git 解决方案可能具有代码审核功能,您可以使用该功能查看对 Config Sync 代码库所做的更改。

审核代码库更改的最佳实践与常规代码审核的最佳实践相同,如下所示:

鉴于 Config Sync 代码库的敏感性,我们还建议尽可能在您的 Git 解决方案中进行以下配置:

通过使用这些不同的功能,您可以对代码库的每个更改请求强制执行审批。例如,您可以确保每个更改都至少由平台团队的成员(负责运行集群群的成员)以及安全团队的成员(负责定义并实现安全政策的成员)批准。

我们建议您执行以下操作:

  • 在您的代码库上强制执行同行评审,并保护您的集群使用的 Git 分支。

实施自动化测试

对代码库进行操作时,通常的最佳做法是实施持续集成。这意味着您要将自动化测试配置为在创建或更新更改请求时运行。在人工审核更改请求之前,自动化测试可以捕获许多错误。这样可以加强开发者的反馈环。您可以使用相同的工具为 Config Sync 代码库实现相同的想法。

例如,一个不错的起点是在新更改上自动运行 nomos vet 命令。此命令会验证您的 Config Sync 代码库的语法是否有效。您可以按照验证配置教程来使用 Cloud Build 实现此测试。您可以将 Cloud Build 与以下选项集成:

  • Bitbucket(使用构建触发器)。
  • GitHub。构建触发器也可用于 GitHub,但 GitHub 应用是首选的集成方法。

正如验证配置教程中所示的,测试是使用容器映像完成的。因此,您可以在运行容器的任何持续集成解决方案中实现测试,而不仅限于 Cloud Build。

为了进一步缩小反馈环,您可以要求用户以 Git 预提交钩子运行 nomos vet 命令。需要注意的是,某些用户可能无权访问由 Config Sync 管理的 Kubernetes 集群,并且可能无法在其工作站上运行完整验证。运行 nomos vet --clusters "" 命令,将验证限制为语义和语法检查。

我们建议您执行以下操作:

  • 在持续集成流水线中实现测试。
  • 对所有建议的更改至少运行 nomos vet 命令。

监控发布

即使您实施了本文档涵盖的所有安全措施,也仍然可能出现错误。以下是两种常见的错误类型:

  • 不会导致 Config Sync 本身出现问题,但会妨碍工作负载正常运行的错误,例如因过于限制 NetworkPolicy 会阻止工作负载的组件进行通信。
  • 导致 Config Sync 无法将更改应用到集群的错误,例如无效的 Kubernetes 清单或准入控制器拒绝的对象。之前介绍的方法应该可以捕获大多数此类错误。

在 Config Sync 级别上几乎不可能检测到上述第一个项目符号中所述的错误,因为这需要了解每个工作负载的状态。因此,最好通过现有监控系统来检测这些错误,以便在应用出现异常时收到提醒。

检测前面的第二项目符号(如果您已实施所有的保护措施,这应该很少见)中所述的错误需要特定的设置。默认情况下,Config Sync 会将错误写入其日志(默认情况下,您可以在 Cloud Logging 中找到这些日志)。Config Sync Google Cloud 控制台页面也会显示错误。日志和控制台通常都不足以检测错误,因为您可能不会一直监视它们。自动错误检测的最简单方法是运行 nomos status 命令,该命令说明了集群中是否出现错误。

您还可以设置更高级的解决方案,并针对错误自动发出提醒。Config Sync 以 Prometheus 格式公开指标。如需了解详情,请参阅监控 Config Sync

在监控系统中添加 Config Sync 指标后,您可以创建提醒,以便在 gkeconfig_monitor_errors 指标大于 0 时收到通知。如需了解详情,请参阅 Cloud Monitoring 的管理提醒政策或 Prometheus 的提醒规则

使用 Config Sync 的安全发布机制摘要

下表总结了本文档前面描述的各种机制。这些机制都不是互斥的。您可以选择使用其中的少部分或全部用于不同目的。

机制 适合的场景 不适合的场景 用例示例
Git 提交 ID 和标记 使用特定的 Git 提交 ID 或标记来精确控制集群更改的应用。 请勿对集群之间长期存在的差异使用 Git 提交 ID 或标记。使用集群选择器。 所有集群都配置为应用 12345 Git 提交。使用要测试的新提交 abcdef 进行更改。您可以更改单个集群的配置,以使用此新提交来验证更改。
Git 分支 如果要将相同的更改发布到多个环境,请依次使用多个 Git 分支。 请勿对集群之间长期存在的差异使用多个 Git 分支。分支将出现明显分化,并且很难合并回去。 首先在暂存分支中合并更改,然后由暂存群集在其中进行选择。
然后在主分支中合并更改,生产集群将在其中进行选择。
集群选择器和命名空间选择器 针对集群和命名空间之间长期存在的差异使用选择器。 请勿将选择器用于跨多个环境的分阶段发布。如果您想在暂存时先测试修改,然后再将其部署到生产环境中,请使用单独的 Git 分支。 如果应用团队需要对开发集群的完整访问权限,但对生产集群只需要只读权限,请使用 ClusterSelector 对象将正确的 RBAC 政策仅应用于相关集群。
对等审核 使用对等审核,确保相关团队批准更改。 人工审核者并非能发现所有错误,尤其是语法错误等内容。 您的组织要求安全团队必须审核会影响多个系统的配置更改。让安全团队成员审核更改。
持续集成流水线中的自动化测试 使用自动化测试来发现建议的更改中出现的错误。 自动化测试无法完全替代人工审核者。同时使用 对所有建议更改运行 nomos vet 命令可确认代码库是有效的 Config Sync 配置。
监控同步错误 请确保 Config Sync 确实将更改应用于集群。 仅当 Config Sync 尝试应用无效的代码库或 Kubernetes API 服务器拒绝某些对象时,才会发生同步错误。 用户绕过了您的所有测试和审核,并向 Config Sync 代码库提交无效的更改。此更改无法应用于您的集群。如果您监控的是同步错误,则会在发生错误时收到提醒。

发布策略示例

此部分使用本文其余部分中介绍的概念,帮助您为组织中的所有集群创建端到端发布策略。此策略假设您拥有单独的开发、预演和生产队列(如队列示例 1 - 方法 1 中所示)。

在这种情况下,您使用特定的 Git 提交将每个集群配置为使用 Git 代码库同步。将更改部署到给定队列分为 4 个步骤:

  1. 更新队列中的一个(“Canary 版”)集群,使其首先使用新提交。
  2. 您可以通过运行测试和监控发布情况来验证一切是否按预期运行。
  3. 更新队列中的其他集群。
  4. 您可以再次验证一切是否按预期运行。

如需在所有集群中部署更改,请为每个队列重复此过程。从技术上讲,您可以从任何分支与任何 Git 提交应用此方法。不过,我们建议您采用以下流程,在审核流程中尽早找出问题:

  1. 当有人在 Config Sync Git 代码库中打开更改请求时,将该更改部署到某个开发集群。
  2. 如果更改请求被接受并合并到主分支,请按照前文所述在所有队列中运行完整部署。

虽然某些更改可能仅针对特定的队列,但我们建议您最终将所有更改部署到所有队列。此策略可消除跟踪哪些队列应与哪个提交同步的问题。请特别留意仅应用于生产队列的更改,因为在之前的队列中无法进行适当的测试。例如,这意味着,等待部署到 Canary 版集群和其余集群之间会增加问题等待时间。

总而言之,完整的端到端部署如下所示:

  1. 有人打开更改请求。
  2. 自动运行验证和验证,并且完成手动审核。
  3. 您可以手动触发作业,以将更改部署到开发队列中的 Canary 版集群。此集群中运行自动端对端测试。
  4. 如果一切正常,请将主分支上的更改请求合并到一起。
  5. 合并会触发自动化作业,将新的主要分支提示提交部署到开发队列中的 Canary 版集群。在此集群中运行自动端到端测试(以检测已创建和合并的大约两个更改请求之间的潜在不兼容问题)。
  6. 以下作业一个接一个地运行(您手动触发它们,或在预定义的时间之后触发以允许用户报告回归):
    1. 部署到开发队列的所有集群。
    2. 在开发队列的集群中运行测试和验证。
    3. 部署到预演队列的 Canary 版集群。
    4. 在预演队列的 Canary 版集群中运行测试和验证。
    5. 部署到预演队列的所有集群。
    6. 在预演队列的集群中运行测试和验证。
    7. 部署到生产队列的 Canary 版集群。
    8. 在生产队列的 Canary 版集群中运行测试和验证。
    9. 部署到生产队列的所有集群。
    10. 在生产队列的集群中运行测试和验证。

全面推出流程。

后续步骤