StatefulSet 2
答案是:
❌ StatefulSet 不使用 ReplicaSet 来创建 Pod。 ✅ StatefulSet Controller 直接创建并管理 Pod 对象,而且每个 Pod 都是有序的、具名的、不可替代的。
接下来我会详细讲清楚 StatefulSet 与 Deployment 的架构差异、实现机制、核心控制循环,让你能在实现 Operator 或高可靠应用时真正理解它的行为。
🧩 一、StatefulSet 与 Deployment 的根本区别
| 项目 | Deployment | StatefulSet |
|---|---|---|
| 控制下层对象 | ReplicaSet → Pod | 直接管理 Pod |
| Pod 命名 | 随机 | 固定命名(有序索引) |
| Pod 身份 | 可替换 | 唯一、持久身份(Stable Identity) |
| 更新策略 | 滚动更新(无序) | 有序更新(从 0 开始逐个) |
| 存储 | 通常无状态 | 绑定 PVC,数据与 Pod 一一对应 |
| 常见场景 | Web 服务、API、Job | 数据库、Zookeeper、Kafka、Etcd 等 |
⚙️ 二、StatefulSet 控制器工作原理
StatefulSet Controller 运行在 kube-controller-manager 中。
它同样是一个典型的 Controller + Informer + WorkQueue + Reconcile Loop 架构。
但是它的 核心循环逻辑 与 Deployment/ReplicaSet 明显不同:
1️⃣ Reconcile 流程概览
伪代码如下:
syncStatefulSet(set):
pods := listPodsMatching(set.selector)
sortPodsByOrdinal(pods)
for i in 0..set.spec.replicas-1:
ensurePodExists(set, ordinal=i)
ensurePodPVCExists(set, ordinal=i)
if updateRequired(set, pod[i]):
deletePodAndWaitForReplacement(set, ordinal=i)也就是说,StatefulSet controller 自己直接创建 Pod 和 PVC,并且顺序控制整个过程。
2️⃣ Pod 命名与序号机制
StatefulSet 会给每个 Pod 一个固定的命名模式:
<prefix>-<ordinal>例如:
web-0
web-1
web-2这些名字不是随机生成的 UID,而是根据序号确定的。 这让 Pod 可以拥有稳定的网络标识:
Pod DNS:
<podname>.<headless-service-name>.<namespace>.svc.cluster.local例如:
web-0.web.default.svc.cluster.local web-1.web.default.svc.cluster.local
这对 Zookeeper、MySQL 集群等“节点必须有固定身份”的应用至关重要。
3️⃣ 存储(PVC)绑定机制
每个 StatefulSet Pod 都可以声明一个 volumeClaimTemplate:
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10GiController 会为每个 Pod 创建一个独立的 PVC:
data-web-0
data-web-1
data-web-2即使 Pod 被删除,这个 PVC 也不会被清理(除非手动删除), 这就实现了状态持久化。
4️⃣ Pod 创建顺序与滚动更新顺序
StatefulSet 有严格的有序逻辑:
创建顺序
- 先创建
web-0; - 等
web-0变成Running + Ready; - 再创建
web-1; - 依次类推。
删除顺序
- 先删除最高序号 Pod;
- 依次向下。
更新顺序(滚动更新)
先更新最高序号 Pod;
等该 Pod Ready 后,再更新下一个;
可配置
podManagementPolicy:OrderedReady(默认,有序)Parallel(并行)
5️⃣ StatefulSet 更新控制逻辑
当你修改 StatefulSet 的模板(例如更换镜像),控制器会:
- 比较
spec.templatehash; - 找出需要更新的 Pod;
- 按序更新;
- 每个 Pod 更新完毕、Ready 后,再进行下一个。
伪代码示例:
for i = replicas-1 downTo 0:
if pod[i].template != set.template:
delete(pod[i])
waitUntilNewPodReady(i)📦 三、StatefulSet 与 PVC 的生命周期
| 对象 | 何时创建 | 何时删除 |
|---|---|---|
| Pod | 当 StatefulSet 第一次启动或扩容时 | 缩容时(最高序号先删) |
| PVC | Pod 第一次被创建时 | 不会自动删除(除非使用 StorageClass Retain 策略外的设置) |
这意味着:
StatefulSet 的 数据持久性是通过 PVC 与序号绑定实现的。
例如:
data-web-0 → 永远属于 web-0
data-web-1 → 永远属于 web-1🔁 四、StatefulSet 的控制链路(事件流)
| 步骤 | 执行者 | 说明 |
|---|---|---|
| 用户 | kubectl apply 创建 StatefulSet | |
| API Server | 写入 etcd | |
| StatefulSet Controller | 检测 StatefulSet 对象变化 | |
| Controller | 创建第一个 Pod + PVC(ordinal=0) | |
| Kubelet | 调度并运行容器 | |
| Controller | 检测 web-0 Ready 后,继续创建 web-1 | |
| 直到 | 所有 replicas Ready | |
| 更新 | 按序滚动更新 Pod |
🧠 五、StatefulSet 为什么不复用 ReplicaSet?
主要是因为 ReplicaSet 的特性与 StatefulSet 的设计目标相冲突:
| 功能 | ReplicaSet | StatefulSet |
|---|---|---|
| Pod 匿名性 | ✅ 所有 Pod 等价 | ❌ 每个 Pod 唯一 |
| 更新无序性 | ✅ 任意替换 | ❌ 必须有序 |
| PVC 管理 | ❌ 无 | ✅ 一一绑定 |
| 网络身份 | ❌ 无 | ✅ 稳定 DNS 名称 |
所以 Kubernetes 设计了专门的 StatefulSet Controller 来实现这一类“有状态副本控制”。
💡 六、StatefulSet 小结
| 特性 | 描述 |
|---|---|
| 控制对象 | 直接管理 Pod |
| Pod 命名 | 固定命名(带序号) |
| 更新策略 | 有序(OrderedReady)或并行(Parallel) |
| 持久化 | 通过 PVC 一对一绑定 |
| 典型场景 | 数据库、分布式存储、消息队列、协调服务等 |
| 优势 | 稳定网络身份、持久存储、严格更新顺序 |
| 缺点 | 扩缩容慢,调度受限,不适合无状态应用 |
🧭 七、视觉化理解(结构示意)
StatefulSet: kafka
│
├── Pod: kafka-0
│ ├── PVC: data-kafka-0
│ └── Hostname: kafka-0.kafka.default.svc
│
├── Pod: kafka-1
│ ├── PVC: data-kafka-1
│ └── Hostname: kafka-1.kafka.default.svc
│
└── Pod: kafka-2
├── PVC: data-kafka-2
└── Hostname: kafka-2.kafka.default.svc