Kubernetes 的 API 弃用策略给每个升级周期都留出了缓冲窗口,但真正的风险往往发生在集群已经升级、旧版 API 已从 API Server 删除之后。如果这时 Helm Release、CI/CD 流水线或控制器仍然提交 extensions/v1beta1 这类清单,API Server 会直接返回 unknown object 错误,发布就会被阻断。迁移工作的核心不是简单替换一个版本字符串,而是先扫描出所有仍在使用旧 API 的对象,再根据资源类型的字段差异做适配,最后通过 dry-run 和灰度发布完成验证。

下面用 Deployment 与 Ingress 两个最常遇到的资源类型展开说明,因为这两类资源从弃用 API 切换到稳定版本时,不仅 apiVersion 会变,某些字段结构也必须同步调整。
一、先扫描集群中的弃用 API 调用
在动手修改任何 YAML 之前,需要先知道哪些资源仍指向已经弃用或即将移除的 API。很多团队只在升级集群前依赖 kubectl get 的输出,但默认情况下它不会主动提示某个对象正在使用旧版 API,除非对象所在的资源组已经彻底从 API Server 中消失。更可靠的做法是使用专门的扫描工具,比如 kubent、pluto 或 kube-no-trouble。这些工具会遍历目标命名空间中的资源,并对照 Kubernetes 的弃用时间表输出问题清单。
如果不想立刻引入额外工具,也可以先用 API 发现接口观察当前集群保留的 API 组。以下命令会列出与旧版 API 相关的分组,便于确认这些组是否仍然存在:
kubectl get --raw /apis | grep -E "extensions/v1beta1|networking.k8s.io/v1beta1|policy/v1beta1"
不过这条命令只能反映集群是否仍然注册了旧 API 组,不能告诉你哪些现有对象正在引用它们。kubent 更适合做库存盘点,因为它会直接读取每个对象的 apiVersion 字段,并按弃用状态分类。例如扫描结果中如果出现 Deployment 使用 extensions/v1beta1,就需要列入迁移清单。升级后即使 API 组已经被移除,kubent 也可能无法再读取旧对象,因此最好在升级前完成扫描,并把结果保存到迁移任务单里。
另一个容易忽略的点是 CustomResourceDefinition 的 apiextensions.k8s.io/v1beta1 也已经在很多版本中移除。若集群通过 Operator 或自定义控制器注册 CRD,升级后旧版 CRD 文件会直接失败。扫描时不能只看内置资源,还要把 CRD、APIService、MutatingWebhookConfiguration 等扩展资源纳入范围。
二、典型资源迁移:Deployment 与 Ingress 的字段差异
Deployment 的旧版 API 通常来自 extensions/v1beta1,稳定版为 apps/v1。二者在大部分字段上保持一致,但 apps/v1 对 spec.selector 有更严格的约束:它必须与 spec.template.metadata.labels 完全匹配,并且 selector 一旦创建后不可变更。旧文件中如果省略了 selector,在应用新版时会直接报错。因此迁移 Deployment 时,除了替换 apiVersion,还要显式补全 selector 匹配标签。
下面是一个旧版 Deployment 片段:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.23
迁移到 apps/v1 后需要写成:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.23
可以看到差异集中在 selector 显式声明。对于已经有 selector 的旧文件,只需替换 apiVersion 并用 kubectl apply --dry-run=client -f deployment.yaml -o yaml 校验即可。dry-run 模式会走 API 的字段校验逻辑,但不会真正写入集群,很适合放在本地或流水线里反复执行。
Ingress 的迁移更复杂一些。API 从 networking.k8s.io/v1beta1 升级到 networking.k8s.io/v1 后,backend 字段从扁平结构改成了嵌套对象。旧版使用 serviceName 和 servicePort,新版必须写成 service.name 与 service.port.number,并且每个 path 都需要显式指定 pathType。如果没有改造 backend 结构,一旦 API 移除,Ingress Controller 会一直无法同步配置,甚至可能出现入口路由中断。
旧的 Ingress 示例:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: web-ingress
spec:
rules:
- host: app.ipipp.com
http:
paths:
- path: /api
backend:
serviceName: web
servicePort: 80
新版对应写成:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
spec:
rules:
- host: app.ipipp.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: web
port:
number: 80
这里 pathType 的取值必须是 Prefix、Exact 或 ImplementationSpecific。对于原来只写了 serviceName 的场景,迁移时需要结合 Ingress Controller 的实现选择合适类型。多数七层网关使用 Prefix 能保持原有路径前缀匹配行为,但如果业务依赖精确匹配,应改成 Exact,否则可能出现路径冲突。
三、批量迁移策略与回归验证
大型集群中可能同时存在几十个命名空间使用旧 API,逐个手工修改效率低且容易漏项。推荐把所有 manifest 纳入 Git 仓库统一管理,然后用脚本或者 CI 工具批量扫描和替换。例如可以用 grep 找到所有包含旧 apiVersion 的文件,再按资源类型分批次提交,不要把所有资源混在一个 PR 里。这样一旦某个命名空间出现异常,可以快速定位回滚范围。
如果只是临时查看转换效果,可以执行下面的命令,让输出直接打印到终端。它不会修改任何资源,但由于 sed 不处理字段结构,结果只能作为迁移参考:
kubectl get deployment -A -o yaml | sed 's#extensions/v1beta1#apps/v1#g'
sed 替换只是把 apiVersion 字符串改掉,无法自动补充 selector,所以只适合批量查看哪些文件需要改,真正落地还是要结合模板或结构化工具处理。
回归验证至少包含两层。第一层是本地静态校验,使用 kubectl apply --dry-run=server -f manifests/ 可以直接把请求发送到 API Server 做 admission 校验。如果集群已经不再支持旧版 API,流水线会立刻失败,避免问题进入生产。第二层是运行时验证,迁移后要检查 Deployment 的 Ready 副本数、Ingress 的地址是否分配成功,以及实际访问路径是否返回预期状态码。可以通过 kubectl get ingress -o yaml 查看 controller 是否填充了新的 status.loadBalancer 字段。
回滚方面需要明确一点:如果 Kubernetes 集群已经删除了旧版 API,那么无法通过改回 extensions/v1beta1 或 networking.k8s.io/v1beta1 来回滚,因为 API Server 根本不会接受这种对象。真正可回滚的是业务改动而非 API 版本。因此迁移工作最好与业务镜像升级分开进行,保证发布历史清晰。若迁移后出现问题,可以快速恢复为迁移前的稳定镜像或配置,而不是纠结于旧 API 版本本身。
四、把校验固化到 CI 与准入链路
一次性迁移完成后,还要防止未来新代码重新引入弃用 API。最简单的方式是在 CI 流水线中加入 kubectl apply --dry-run=server 校验步骤,并将目标集群版本设置为升级后的版本。这样任何包含旧 apiVersion 的清单都会在合并请求阶段被打回,不会进入部署环境。
对于已经运行中的集群,可以用准入控制器做兜底。例如 Kyverno 或 OPA 可以配置规则,拦截 apiVersion 包含 beta 或指定弃用列表的写入请求。准入校验的优点是即使有人绕过 CI 直接执行 kubectl apply,也仍然会被 API Server 拒绝。需要注意的是,准入规则本身也需要跟随集群版本更新,否则可能出现误拦截正常的新 API 或者漏掉新弃用项。
最后一个容易忽略的迁移对象是 Helm Chart 自带的 CRD 和模板。许多老 Chart 将 Deployment 或 Ingress 写在 templates 目录下,并且硬编码了旧 apiVersion。升级 Chart 版本通常能解决,但如果团队自己维护 Chart,则要同步修改模板以及 Chart 的 kubeVersion 约束,确保 Chart 只安装到已经支持新 API 的集群。
总体来看,Kubernetes 弃用 API 迁移是一场结合扫描、改字段、校验和回滚的系统工程。先把库存清单摸清,再按 Deployment、Ingress、CRD 等类型分别处理,最后用 dry-run 和准入策略防止回退,迁移过程就能更平稳。
Kubernetes API 迁移弃用 API资源版本升级修改时间:2026-09-20 11:15:35