观看资源

在扩展 Kubernetes API 时,我们的目标是确保我们的解决方案与 Kubernetes 本身的行为一致。例如,考虑一个由控制器管理的 Deployment 资源。这个控制器负责响应集群中的变化——例如,当 Deployment 被创建、更新或删除时——通过触发调整以确保资源的状态与期望状态相匹配。

同样,在开发我们的控制器时,我们希望关注对我们解决方案至关重要的资源中的相关变化。这些变化——无论是创建、更新还是删除——都应该触发调整循环,以采取适当的行动并维护集群的一致性。

controller-runtime 库提供了多种方式来监视和管理资源。

主要资源

主要资源是你的控制器负责管理的资源。例如,如果你为 MyApp 创建了一个自定义资源定义(CRD),那么相应的控制器负责管理 MyApp 的实例。

在这种情况下,MyApp 是该控制器的 主资源,您的控制器的调整循环专注于确保这些主资源的期望状态得以维护。

当你使用 Kubebuilder 创建一个新的 API 时,以下默认代码会被生成,确保控制器监视所有相关事件——例如创建、更新和删除——以便于新的 API。

该设置确保每当创建、更新或删除 API 实例时,都会触发对账循环:

// 监视主要资源(例如,MyApp)的创建、更新、删除事件if err := ctrl.NewControllerManagedBy(mgr).
   For(&<YourAPISpec>{}). <-- See there that the Controller is For this API
   Complete(r); err != nil {
   return err
}

次要资源

您的控制器可能还需要管理辅助资源,这是集群中支持主要资源所需的资源。

对这些次级资源的更改可能会直接影响主要资源,因此控制者必须相应地监控和调整这些资源。

由控制者拥有的。

这些辅助资源,例如 ServicesConfigMapsDeployments,在被控制器拥有时,由特定控制器创建和管理,并通过 OwnerReferences主资源相关联。

例如,如果我们在集群中有一个控制器来管理 MyApp 类型的自定义资源(CR),这代表了我们的应用解决方案,那么确保 MyApp 以所需实例数正常运行所需的所有资源将被称为 次要资源。负责创建、删除和更新这些资源的代码将是 MyApp 控制器的一部分。我们将使用 controllerutil.SetControllerReference 函数添加适当的 OwnerReferences 以指示这些资源由相同的控制器所拥有,该控制器负责管理 MyApp 实例,这些实例将由 MyAppReconciler 进行调整。

此外,如果删除了主要资源,Kubernetes 的垃圾回收机制将确保所有关联的次要资源以层级方式自动删除。

哪些不是由控制器“拥有“的?

请注意,辅助资源可以是您项目中定义的 API/CRD,也可以是与 主要资源 相关的其他项目中的 API/CRD,但特定控制器并不负责创建或管理这些资源。

例如,如果我们有一个表示备份解决方案(即 MyBackup)的自定义资源定义(CRD),用于我们的 MyApp,它可能需要监视 MyApp 资源的变化,以便在 MyBackup 中触发对账,确保达到期望的状态。同样,MyApp 的行为也可能受到其他项目中定义的 CRD/API 的影响。

在这两种情况下,这些资源都被视为次级资源,即使它们不是由MyAppController“拥有”(即没有被创建或管理)。

在 Kubebuilder 中,未在项目中定义且不是 核心类型(即未在 Kubernetes API 中定义的类型)的资源称为 外部类型

外部类型是指在您的项目中未定义但您需要监视和响应的资源。例如,如果操作员 A管理一个用于应用程序部署的 MyApp CRD,而操作员 B处理备份,那么操作员 B可以将 MyApp CRD 视为外部类型,以便根据 MyApp 的变化触发备份操作。

在这种情况下,运维人员 B 可以定义一个 BackupConfig 自定义资源定义(CRD),该定义依赖于 MyApp 的状态。通过将 MyApp 视为 辅助资源运维人员 B 可以监视并调整 运维人员 AMyApp 中的变化,确保在 MyApp 更新或扩展时启动备份过程。

观看资源的一般概念

无论资源是在您的项目内定义的还是来自外部项目,主要资源次要资源的概念始终是相同的:

  • 主要资源是控制器主要负责管理的资源。
  • 次级资源是指为了确保主要资源按预期工作而必需的资源。

因此,无论该资源是由您的项目定义还是由其他项目定义,您的控制器都可以根据需要监视、对账和管理这些资源的变化。

观看二级资源有什么重要性?

在构建 Kubernetes 控制器时,关注 主要资源 是至关重要的,但同样重要的是监控 次要资源。未能跟踪这些资源可能导致您的控制器行为和整个集群状态的不一致。

次级资源可能并不直接由您的控制器管理,但对这些资源的更改仍然会对主资源和您的控制器的功能产生重大影响。以下是关注这些资源的重要原因:

  • 确保一致性

    • 二级资源(例如,子对象或外部依赖)可能与其预期状态发生偏离。例如,二级资源可能被修改或删除,从而导致系统不同步。
    • 观察辅助资源确保任何变化都能立即被检测到,这使得控制器能够对账并恢复所需状态。
  • 避免随机自我修复

    • 在没有查看二级资源的情况下,控制器可能只在重启后或在触发特定事件时“自我恢复“。这可能导致对问题的反应不可预测或延迟。
    • 监控二级资源可以确保及时处理不一致性,而不是等待控制器重启或外部事件来触发调整。
  • 有效的生命周期管理:

    • 次要资源可能并不直接由控制者拥有,但它们的状态仍然会影响主要资源的行为。如果不对这些进行监控,就可能导致孤儿资源或过时资源的存在。
    • 观看非拥有的二级资源使控制器能够对可能影响主资源的生命周期事件(创建、更新、删除)作出响应,从而确保系统行为的一致性。

请参阅观看未拥有的次级资源以获取示例。

为什么不在所有场景中都使用 RequeueAfter X 而不是监听资源呢?

Kubernetes 控制器本质上是 事件驱动 的。在创建控制器时,调整循环 通常是由对资源的 createupdatedelete 操作等 事件 触发的。这种事件驱动的方法相比于不断重新排队或轮询资源使用 RequeueAfter 更加高效和响应迅速。这确保了系统只在必要时采取行动,从而保持性能和效率。

在许多情况下,监视资源是确保Kubernetes资源保持在所需状态的首选方法。它更高效、更灵敏,并且与Kubernetes的事件驱动架构相一致。然而,在某些场景中,RequeueAfter是合适且必要的,特别是在管理不发出事件的外部系统或处理需要时间才能收敛的资源时,例如长时间运行的过程。仅依赖RequeueAfter处理所有场景可能导致不必要的开销和反应延迟。因此,至关重要的是优先考虑事件驱动的调整,通过在可能的情况下配置控制器以监视资源,并将RequeueAfter保留用于需要定期检查的情况。

RequeueAfter X 何时有用

虽然 RequeueAfter 不是触发调整的主要方法,但在某些特定情况下是必要的,例如:

  • 观察外部系统:在处理不生成事件的外部资源(例如,外部数据库或第三方服务)时,RequeueAfter 允许控制器定期检查这些资源的状态。
  • 基于时间的操作:一些任务,例如旋转密钥或更新证书,必须在特定的时间间隔内执行。RequeueAfter 确保这些操作按计划进行,即使没有其他更改发生。
  • 处理错误或延迟:在管理遇到错误或需要时间自我修复的资源时,RequeueAfter 确保控制器在再次检查资源状态之前等待指定的时间,从而避免不断尝试进行调整。

谓词的使用

对于更复杂的使用场景,可以使用 谓词 来精确调整您的控制器何时应该触发状态同步。谓词允许您根据特定条件筛选事件,例如对特定字段、标签或注释的更改,从而确保您的控制器仅对相关事件做出响应,并高效地运行。