StatefulSet 创建必须指定 serviceName 且指向已存在的 Headless Service,否则 Pod 卡在 Pending;volumeClaimTemplates 不可更新,需删重建;滚动更新默认逆序逐个进行,暂停需用 rollout pause。

StatefulSet 创建时必须设置 serviceName 字段
不填 serviceName 会导致 StatefulSet 创建失败,且错误提示非常隐蔽——API Server 不会直接报错,而是让 Pod 卡在 Pending 状态,kubectl describe pod 显示 FailedCreatePodSandBox 或 MissingServiceForStatefulSet 类似提示。
这是 StatefulSet 的硬性要求:它依赖 Headless Service 来提供稳定的网络标识(如 pod-0.my-sts.default.svc.cluster.local),而该 Service 必须由用户显式定义并关联。
-
serviceName必须指向一个已存在的 Headless Service(clusterIP: None) - Service 的
selector必须与 StatefulSet 的matchLabels完全一致 - StatefulSet 的
serviceName字段值不校验 Service 是否真实存在,但 Pod 启动时会校验 DNS 可达性
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: "my-headless-svc" # ← 必须匹配已有 Headless Service 名称
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: nginx
image: nginx:1.25更新 StatefulSet 时不能直接修改 volumeClaimTemplates
一旦 StatefulSet 创建完成,volumeClaimTemplates 被视为不可变字段。尝试 PATCH 或 PUT 更新(例如扩容 PVC 大小、改 storageClassName)会触发 Invalid value: "volumeClaimTemplates" 错误。
这不是 bug,是 Kubernetes 的设计约束:每个 Pod 对应的 PVC 是基于模板在创建时生成的,后续无法动态重写模板逻辑。
立即学习“go语言免费学习笔记(深入)”;
- 若需变更 PVC 模板,必须先删除 StatefulSet(加
--cascade=orphan保留 PVC 和 Pod) - 再用新模板重建 StatefulSet,确保
podManagementPolicy: OrderedReady(默认)以避免并发重建冲突 - 手动 patch 已有 PVC 的
resources.requests.storage是允许的(前提是底层 StorageClass 支持扩容)
用 client-go 列举 StatefulSet 并过滤特定 label
Golang 中通过 clientset.AppsV1().StatefulSets(namespace) 获取列表后,直接用 ListOptions.LabelSelector 最高效。别在 Go 层做二次遍历过滤,既慢又绕过服务端索引。
LabelSelector 支持 =、!=、in、notin 等语法,注意字符串需 URL 编码(client-go 内部自动处理)。
list, err := clientset.AppsV1().StatefulSets("default").List(ctx, metav1.ListOptions{
LabelSelector: "app in (my-app,backend-app),env!=staging",
})
if err != nil {
log.Fatal(err)
}
for _, sts := range list.Items {
fmt.Printf("Found StatefulSet: %s\n", sts.Name)
}滚动更新时如何控制 Pod 重启顺序和暂停时机
StatefulSet 默认按序号从大到小(pod-2 → pod-1 → pod-0)逐个删除重建,但你无法靠 updateStrategy.rollingUpdate.maxUnavailable 控制并发数(该字段对 StatefulSet 无效)。真正起作用的是 revisionHistoryLimit 和 podManagementPolicy。
- 设
podManagementPolicy: Parallel可并行更新所有 Pod,但失去有序性,不适合有主从依赖的场景 - 用
kubectl rollout pause statefulset/my-sts可中途暂停滚动更新,对应 API 中updateStrategy.rollingUpdate.pause字段(v1.27+) - 每次只更新一个 Pod 后暂停,需结合
scale临时缩容再恢复,或用 operator 自行实现分批逻辑
真正难处理的是更新中途出错:旧 revision 的 Pod 已被删,新 revision 卡住,此时只能回滚到上一版本(需提前保留 revisionHistoryLimit >= 2)或手动重建旧 Pod。










