DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Kubernetes apply 报 spec.selector field is immutable:保留已有 Deployment 的选择器

apps/v1 Deployment 更新被 spec.selector 不可变校验拒绝。对照服务器选择器,普通发布保留旧选择范围,需要迁移时安排新对象与流量回退。

更新 apps/v1 Deployment 时,kubectl apply 被拒绝,错误包含 spec.selector 和 field is immutable。本地清单中的标签看起来一致,也不能证明它与服务器上已经存在的选择器一致。

apps/v1 Deployment 创建以后不能修改 .spec.selector。如果此次只想更新镜像或配置,应保留已有选择器,修改 Pod 模板;确实需要改变管理范围时,则要安排新的 Deployment 与流量切换。

对照已存在的对象,而不是重新 create

以下为检查示例,名称、命名空间与文件按实际替换:

kubectl config current-context
kubectl get deployment example-app -n team-app -o yaml
kubectl diff -f deployment.yaml -n team-app

重点对照服务器对象的 .spec.selector 与待提交清单。多出的 matchLabels 条件、标签值变化、matchExpressions 改动,都可能触及不可变字段。diff 可能返回表示存在差异的退出状态,也可能遇到校验错误,应结合输出判断。

同时核对对象的名字和 namespace,避免比较另一个环境。kubectl create 返回 AlreadyExists 只说明同名对象已存在,不能用再次创建覆盖不可变字段。

kubectl apply should be used on resource created by ... 之类的管理提示,与选择器校验是不同事项。补充管理注解不会把不可变选择器变成可修改字段。

只更新版本时,让模板继续匹配旧选择器

例如,已经存在的选择器同时包含 app 和 component,提交的模板就必须继续满足它们:

spec:
  selector:
    matchLabels:
      app: example-app
      component: api
  template:
    metadata:
      labels:
        app: example-app
        component: api
        release: v2

这是局部结构示例,应合入原清单,不是完整可部署文件。这里保留两个已有选择条件,只在模板中增加不属于选择器的 release 标签;镜像等其他内容按实际版本更新。

修改 .spec.template 会触发新的 rollout,可能影响正在运行的 Pod。更新前保存审定清单,确认副本数、就绪检查、发布策略与可用容量。失败时按已验证的发布流程恢复旧模板,或在保留足够历史的前提下回退已完成的版本;不要为解决标签错误直接删除生产 Deployment。

真的要改选择器时,建立独立的替代对象

如果要把工作负载迁移到新的管理标签,采用不同名称、选择器互不重叠的 Deployment。新模板必须满足自己的新选择器,不能让两个控制器同时争夺同一批 Pod。

先确认新旧应用并行运行是否符合业务条件。单写者、数据库、后台任务或持有排他资源的应用,不能照搬并行副本方案。需要停机时应安排窗口,并保留原清单和数据恢复措施。

能并行的服务可以先部署替代对象,验证镜像、配置、就绪与依赖,再根据实际流量入口更新 Service 等配置。Service 按 Pod 标签选择后端,并不是填一个 Deployment 名称。切换时保留旧对象与原流量配置,验收不通过就恢复入口;确认新路径稳定后再清理旧对象。

删除旧 Deployment 后同名重建,也能重新指定选择器,但默认级联删除会影响它管理的工作负载,可能造成服务中断。它只适合已评估影响并允许停机的操作,不能作为普通滚动发布的捷径。

最终检查服务器上的选择器与审定清单一致,模板仍满足选择条件,rollout 完成,实际流量只到达计划的后端。仅让 apply 不再报错,不代表迁移、存储与业务可用性都已完成。