# Pod 对象也能被淘汰么

原文：[Could Kubernetes Pods Ever Become Deprecated?](https://martinheinz.dev/blog/53)

作者：[Martin Heinz](https://martinheinz.dev/)

随着时间的推移，所有的软件项目都会加入新的功能和 API，与此相对地，也会有功能和 API 被移除。Kubernetes 这样的大型项目也并无不同，但是核心 API 的废弃和删除，始终有些含混，Kubernetes 中的核心对象或者说是 API，例如 Pod、Deployment 和 Service，是不是可以删除呢？如果答案是肯定的，那么该如何进行呢？

## 长话短说

GA 状态的核心 API，例如 `v1` API 中的对象也是可能淘汰的。Kubernetes 中的的淘汰话题需要分为 API、CLI 以及 FeatureGate 这三个方面，每方面又会有自己的成熟阶段，例如 Alpha、Beta 或者 GA，这些成熟度的定义，就代表了在什么时间、什么条件下进行淘汰操作—— Pod 这样的东西也不能例外。因此本文尝试对这一问题进行进一步的探讨，看看过往的例子和一些未来的假设。

## 分而治之

不同的对象或功能有不同的规则，所以在讨论淘汰规则之前，首先对这些淘汰目标进行分类：

- **REST 对象**：这是绝大多数人最多打交道的东西，因此也是最引人关注的方向，这里包括了 Pod 或者 Deployment 这样的顶层对象，也包含了它们的成员字段，例如 `containers`、`volumes` 或者 `env`；另外还有一些常量，例如 `imagePullPolicy` 使用的 `Always`、`IfNotPresent` 等。
- **CLI 和命令行参数**：这一部分内容是针对客户端的。最容易想到的可能就是 `kubectl`，其实还包含了 `kubelet`、`kube-apiserver` 或者 `kube-scheduler` 及其子命令和选项等。
- **功能和行为**：各种不同成熟度的试验特性是无法用 API 或者 CLI 来表达的，但是它们也应该有自己的淘汰过程和节奏。
- **指标**：最后 Kubernetes 的各个组件还在 `/metrics` 端点中提供了大量指标。这些指标可能会在监控等系统中使用，因此也不能直接删除，而需要有一定的淘汰规则。

## REST 对象

REST API 需要遵守一个普遍规则——官宣淘汰之时，API 版本至少要支持：

- GA：12 个月或者 3 次发版（取最长时间）
- Beta：9 个月或者 3 次发版（取最长时间）
- Alpha：0 次发版

看起来好像非常清晰，其实里面包含了很多其它（可能很难理解）的规则，所以我们先进入示例环节来进行澄清。假设有一个叫做 `Task` 的 API 对象（有趣的事实：这是 `Pod` 的原名，请参见 [First Commit of Kubernetes](https://github.com/boddumanohar/kubernetes-first-commit/blob/2c4b3a562ce34cddc3f8218a2c4d11c7310e6d56/pkg/client/client.go#L19)）。这个对象处于 GA 状态，其 API 版本为 `v1`，淘汰需要经过什么过程呢？

|Kubernetes 版本|API 版本|推荐|行为|
|---|---|---|---|
|X|`v1`|`v1`|此时 `Task` 对象处于 GA 状态，并没有进入淘汰周期|
|X+1|`v2alpha1`, `v1`|`v1`|引入 `v2alpha1`，宣布 `Task` 开始淘汰，此时 `v2alpha1` 中并不包含 `Task`|
|X+2|`v2alpha2`，`v1`|`v1`|用 `v2alpha2` 替代 `v2alpha1`|
|X+3|`v2beta1`, `v1`|`v1`|`v2alpha2` 被 `v2beta1` 替换|
|X+4|`v2beta2`、~~`v2beta1`~~、`v1`|`v1`|引入 `v2beta2`，`v2beta1` 依旧存在，但是开始淘汰|
|X+5|`v2`、~~`v2beta2`~~、~~`v2beta1`~~、~~`v1`~~|`v1`|引入 `v2`，包括首选使用的 `v1` 在内的所有其他版本进入淘汰周期|
|X+6|`v2`、~~`v2beta2`~~、~~`v2beta1`~~、~~`v1`~~|`v2`|没有移除任何 API，但是 `v2` 已经成为首选版本|
|X+7|`v2`、~~`v2beta2`~~、~~`v1`~~|`v2`|移除 `v2beta1`|
|X+8|`v2`、~~`v1`~~|`v2`|移除 `v2beta2`|
|X+9|`v2`、~~`v1`~~|`v2`|没有什么变化，按照规则，`v1` 必须继续存活一个版本|
|X+10|`v2`|`v2`|最终删除了 `v1`，其中的 `Task` 对象也宣告终结|

从上表来看，如果在 `v2alpha1` 开始淘汰 `Task` 对象，就需要 9 个版本才能最终完成。读者需要注意的是，根据[当下的发布节奏](https://github.com/kubernetes/enhancements/tree/master/keps/sig-release/2572-release-cadence)，每年发版三次，整个淘汰流程可能需要三年多。

有些对象虽然没进入 GA，但是用户已经将其视为 GA 并进行使用。例如 [1.19 中才进入 GA 的 Ingress](https://opensource.googleblog.com/2020/09/kubernetes-ingress-goes-ga.html)，或者 [1.21 的 CronJob](https://kubernetes.io/blog/2021/04/09/kubernetes-release-1.21-cronjob-ga/)。这种 `beta` 甚至是 `alpha` 的版本，淘汰节奏就不会这么宽松了。要检查资源所属的分类，可以运行 `kubectl api-resources | grep beta`，读取所有集群中的所有 `beta` API 对象类型。

REST 对象字段成员、常量以及对象结构，淘汰规则跟对象是一致的。也就是说，`imagePullPolicy` 中使用的 `Always`、`IfNotPresent` 和 `Never` 不会随机变化也不会从一节挪到另一节。

例如 `PodSecurityPolicy` 可能是近期的一个最大变化。这个 API 对象会从 `v1beta1` 转向 EOL，在 `v1.21` 中开始淘汰，在 `v1.25` 中被移除。详情可参见 [`KEP_2579`](https://github.com/kubernetes/enhancements/blob/master/keps/sig-auth/2579-psp-replacement/README.md/)。

另一个进行中的重要淘汰就是 `selfLink` 字段，这是 [`KEP-1164`](https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/1164-remove-selflink) 中的一部分，这一变更的过程记录在 [Github Issue](https://github.com/kubernetes/enhancements/issues/1164) 之中。

如果你有兴趣了解其它的淘汰过程，希望了解其中的逻辑关系以及整个流程，可以在 [kubernetes/enhancements repository](https://github.com/kubernetes/enhancements) 搜索包含 `deprecate` 关键字的 KEP。

## 客户端和参数

和 REST 对象类似，`kubectl` 和 `kubelet` 的子命令及其参数也是有自己的淘汰策略的。

这部分的规则比前面的案例要简单，对于 `kubectl` 这样的面对客户的组件来说：

- GA：12 个月或者两次发版（取最长时间）
- Beta：3 个月或者 1 次发版（取最长时间）
- Alpha：0 次发版

对于 `kubelet`、`kube-apiserver` 或者 `kube-scheduler` 这样的面向管理员的组件：

- GA：12 个月或者两次发版（取最长时间）
- Beta：3 个月或者 1 次发版（取最长时间）
- Alpha：0 次发版

近期这方面的最知名案例应该算是 `kubelet` 中的 `dockershim` 了。在 [`KEP-2221`](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2221-remove-dockershim) 中讲到，在 `v1.20` 中设置淘汰，在 `v1.24` 中进行删除。

这方面的另一个显著目标就是 `seccomp` Profile 即将 `GA`，这一过程在 [KEP-135](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/135-seccomp/README.md) 中进行跟进。这个特性并不会真正地对参数和 CLI 产生影响，但是它的 `GA` 过程会要求淘汰 `kubelet` 的 `--seccomp-profile-root`，详情请参见 [SIG Node 文档](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/135-seccomp/README.md#seccomp-root-path-configuration)。

所以这一节的淘汰过程是比较较宽松的，但是如果你正在自动化过程中使用 `kubectl alpha`，最好在升级集群和 CLI 之前检查一下它的淘汰情况。

## Feature Gate

Kubernetes 每个版本中都会包含很多的实验性功能。这些功能被称为 `Feature Gate`，它们使用 Key/Value 形式的开关进行控制。

这些特性既然是用于试验的，其淘汰策略自然和其它的 Kubernetes 对象有所不同。随着特性的逐步成熟，它的 Feature Gate 也会发生变化。Alpha 阶段的功能，其 Feature Gate 会被缺省关闭；而 Beta 阶段的功能则会缺省打开；如果该功能进入 GA，对应的 Feature Gate 就不再需要了，会被淘汰，无法操作。

Alpha 功能可能随时消失；Beta 功能可能会在 1 次发版以后删除；进入 GA 的功能则会在两次发版后删除。

这方面的最好例子就是[官方的 Feature Gate 列表](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/)。以其中包含的 `AffinityInAnnotations` 为例，它就是从 Alpha 淘汰的；而 `BlockVolume`、`DryRun` 或者 `EndpointSlice` 则已经进入了 GA。我还没有看到过有从 Beta 被淘汰的 Feature Gate。

如果打开了某些 Feature Gate，在集群升级之前一定要检查一下，防止一些特性因升级被删除。

## 指标

最后一个需要关注的就是监控指标，可能会有监控工具对指标进行聚合和消费，因此其淘汰过程也是需要多加小心的。和前面章节中的内容不同，指标只分成两类——稳定和 Alpha，声明淘汰之后，稳定指标可以在 3 次发版之后移除，Alpha 可以随时移除。

例如 [`rest_client_request_latency_seconds`](https://github.com/kubernetes/kubernetes/pull/83836) 就是一个值得观察的指标淘汰案例，这个过程在 [`v1.17` 的版本说明](https://v1-17.docs.kubernetes.io/docs/setup/release/notes/#deprecated-changed-metrics)里体现。

如果想要了解更多监控指标生命周期的问题，可以查看一下[系统指标的相关文档](https://kubernetes.io/docs/concepts/cluster-administration/system-metrics/)。

## 结论

现今很多项目会采用“有破坏性的快速演进”方法来进行淘汰工作，其中往往会包含繁杂的手工操作，所以 Kubernetes 这样的大项目提出了如此深思熟虑的启用过程，让用户有时间来进行有计划的迁移，这是让人非常愉快的。

那么这篇文章的要点在哪里：

- 所有东西都可能淘汰？是的？
- 需要担心吗？显然不用。

看看淘汰的时间线长度，就知道无需担心突然袭击了。但是为长远计，应该检查版本说明，注意其中是否有你正在使用的 Alpha 功能。还应该阅读 [淘汰 API 指南](https://kubernetes.io/docs/reference/using-api/deprecation-guide/)，其中会列出所有未来将要移除的 API 对象。最后要说明的是，外部供应商的 CRD 的生命周期是自行负责的，可能和官方策略并不一致。
