为 Client-Go 引入特性门控:增强灵活性和控制力

Kubernetes 组件使用称为功能门控的开关来管理添加新功能的风险。功能门控机制使得功能能够通过 Alpha、Beta 和 GA 阶段逐步升级。

诸如 kube-controller-manager 和 kube-scheduler 等 Kubernetes 组件使用 client-go 库与 API 进行交互。Kubernetes 生态系统中使用相同的库来构建控制器、工具、Webhook 等。client-go 现在包括其自身的功能门控机制,使开发人员和集群管理员可以更好地控制他们采用客户端功能的方式。

要了解有关 Kubernetes 中功能门控的更多信息,请访问功能门控

动机

在没有 client-go 功能门控的情况下,每个新功能都以自己的方式(如果存在)将功能可用性与启用分隔开来。某些功能通过更新到较新版本的 client-go 来启用。其他功能需要在每个使用它们的程序中主动配置。少数功能可以在运行时使用环境变量进行配置。使用 kube-apiserver 公开的功能门控功能有时需要客户端回退机制,以保持与由于其年龄或配置而不支持该功能的服务器的兼容性。如果在这些回退机制中发现问题,则需要更新到修复版本的 client-go 或回滚以进行缓解。

这些方法都不能很好地支持在某些(但不是所有)使用 client-go 的程序中默认启用功能。默认情况下,启用新功能最初仅针对单个组件,而默认设置的更改会立即影响所有 Kubernetes 组件的默认设置,从而显着扩大了影响范围。

client-go 中的功能门控

为了应对这些挑战,将使用新的功能门控机制逐步引入重要的 client-go 功能。它将允许开发人员和用户以熟悉 Kubernetes 组件中功能门控的方式启用或禁用功能。

开箱即用,只需使用最新版本的 client-go,即可带来以下好处。

对于使用 client-go 构建的软件的人员

  • 早期采用者可以在每个进程的基础上启用默认关闭的 client-go 功能。
  • 可以禁用行为异常的功能,而无需构建新的二进制文件。
  • 记录所有已知的 client-go 功能门控的状态,允许用户进行检查。

对于开发使用 client-go 构建的软件的人员

  • 默认情况下,client-go 功能门控覆盖是从环境变量中读取的。如果在 client-go 功能中发现错误,用户将能够禁用它,而无需等待新的版本发布。
  • 开发人员可以替换程序中基于环境变量的默认覆盖,以更改默认值、从其他源读取覆盖或完全禁用运行时覆盖。Kubernetes 组件使用此自定义功能来将 client-go 功能门控与现有的 --feature-gates 命令行标志、功能启用指标和日志记录集成。

覆盖 client-go 功能门控

注意:这描述了在运行时覆盖 client-go 功能门控的默认方法。特定程序的开发人员可以禁用或自定义此方法。在 Kubernetes 组件中,client-go 功能门控覆盖由 --feature-gates 标志控制。

可以通过设置前缀为 KUBE_FEATURE 的环境变量来启用或禁用 client-go 的功能。例如,要启用名为 MyFeature 的功能,请按如下方式设置环境变量

 KUBE_FEATURE_MyFeature=true

要禁用该功能,请将环境变量设置为 false

 KUBE_FEATURE_MyFeature=false

注意:环境变量在某些操作系统上区分大小写。因此,KUBE_FEATURE_MyFeatureKUBE_FEATURE_MYFEATURE 将被视为两个不同的变量。

自定义 client-go 功能门控

基于环境变量的默认功能门控覆盖机制对于 Kubernetes 生态系统中的许多程序来说可能足够了,并且不需要特殊的集成。需要不同行为的程序可以用它们自己的自定义功能门控提供程序替换它。这允许程序执行以下操作,例如强制禁用已知工作不佳的功能、直接从远程配置服务读取功能门控或通过命令行选项接受功能门控覆盖。

Kubernetes 组件使用现有 Kubernetes 功能门控提供程序的 shim 替换了 client-go 的默认功能门控提供程序。在所有实际用途中,client-go 功能门控的处理方式与其他 Kubernetes 功能门控相同:它们连接到 --feature-gates 命令行标志,包含在功能启用指标中,并在启动时记录。

要替换默认的功能门控提供程序,请实现 Gates 接口并在包初始化时调用 ReplaceFeatureGates,如这个简单的例子所示

import (
 k8s.io/client-go/features
)

type AlwaysEnabledGates struct{}

func (AlwaysEnabledGates) Enabled(features.Feature) bool {
 return true
}

func init() {
 features.ReplaceFeatureGates(AlwaysEnabledGates{})
}

需要完整定义的 client-go 功能列表的实现可以通过实现 Registry 接口并调用 AddFeaturesToExistingFeatureGates 来获得。有关完整示例,请参阅在 Kubernetes 中的用法

总结

随着 client-go v1.30 中功能门控的引入,推出新的 client-go 功能变得更加安全和容易。用户和开发人员可以控制他们自己采用 client-go 功能的速度。通过使用一个通用的机制来逐步升级跨越 Kubernetes API 边界的功能,Kubernetes 贡献者的工作得到了简化。

特别感谢 @sttts@deads2k 在塑造此功能方面提供的帮助。