选择器为什么不可变
在 apps/v1 下,Deployment、StatefulSet、DaemonSet 的选择器创建后不能修改。控制器靠选择器认领并管理 Pod,如果允许中途改标签匹配规则,新旧 Pod 的归属会立即错乱,甚至出现两个控制器争抢同一批 Pod。因此这项校验发生在写入阶段,修改直接被拒绝。
基本信息
| 适用平台 | Kubernetes 1.16+,apps/v1 为唯一可用版本 |
|---|---|
| 报错关键字 | field is immutable |
| 一致性要求 | 选择器必须匹配 Pod 模板标签 |
| 变更方式 | 导出清单改名改标签后新建对象并迁移 |
| 相关字段 | matchLabels 与 matchExpressions |
典型使用场景
- 新项目在设计阶段就规划标签体系,避免上线后再动选择器
- 合并两个服务的部署对象,需要统一标签维度
- 历史清单标签命名不规范,迁移时统一到新规范
- 在控制台直接编辑选择器字段被拒,需要找到可行的替代路径
- 多集群复制清单前先确认标签与目标集群现有对象不冲突
正确写法
正确写法
spec:
selector:
matchLabels:
app: web # 必须与下面的模板标签一致
template:
metadata:
labels:
app: web被拒现场与迁移做法
被拒现场与迁移做法
kubectl patch deploy/web -p '{"spec":{"selector":{"matchLabels":{"app":"web2"}}}}'
# 返回:field is immutable
kubectl get deploy web -o yaml > web.yaml # 导出当前清单
# 改名称与选择器后创建新对象
kubectl apply -f web-new.yaml
kubectl scale deploy/web --replicas=0 # 旧对象先缩容再删除错误类型对照
| 情况 | 表现 | 处理方式 |
|---|---|---|
| 选择器与模板标签不一致 | 提交即被拒绝,提示验证错误 | 改标签使两处一致后重新提交 |
| 就地修改选择器 | 返回字段不可变 | 导出清单改名并改标签,新建对象 |
| 匹配表达式写错 | 校验失败或匹配不到 Pod | 核对 key 与 values 的写法 |
| 两个对象选择器重叠 | 争抢同一批 Pod | 用互不重叠的标签维度区分 |
删除重建期间原有 Pod 会失去控制器保护,变成孤儿对象。稳妥顺序是先创建新对象、确认新副本就绪,再把旧对象副本降为零并删除。
选择器与模板标签不匹配属于提交阶段就能发现的错误,不会等到运行时才暴露,因此创建失败时优先检查这两处是否一致。