K8s StatefulSet 详解:有状态应用的“身份证”与“固定住址”

K8s StatefulSet 详解:有状态应用的"身份证"与"固定住址"

前面我们聊了 Nacos 集群为什么用 StatefulSet,以及 Service 编排如何配合。但 StatefulSet 本身到底是什么?它和 Deployment 有什么本质区别?这篇文章把它讲清楚。

1. 一句话定义

StatefulSet 是 Kubernetes 中用于管理有状态应用的控制器。它保证一组 Pod 拥有稳定的身份、稳定的网络标识和稳定的存储。

如果用一个比喻:

  • Deployment 管的是一群"临时工":名字随机、工位不固定、走了就换人,适合无状态服务。
  • StatefulSet 管的是一组"正式员工":每个人都有工号、固定工位、专属储物柜,走了再回来还是同一个人,适合数据库、消息队列、Nacos 这类有状态集群。

2. 从 Deployment 的不足说起

在 K8s 里,Deployment 是最常用的工作负载控制器。它适合无状态服务:

  • Pod 名随机,如 my-app-7d9f8-abcde
  • Pod IP 不固定,重建就变;
  • 实例之间不需要互相认识;
  • Service 自动负载均衡;
  • 扩缩容只改 replicas 就够了。

但 Nacos 集群不行。Nacos 节点需要:

  • 知道彼此是谁;
  • 有固定地址写进 nacos.member.list
  • 能选主、同步数据、维持一致性;
  • 重建后还能以原身份加入集群。

这些需求,Deployment 满足不了。于是就需要 StatefulSet。

3. StatefulSet 的四大"稳定"

StatefulSet 的核心价值,可以概括为四个稳定。

3.1 稳定的 Pod 名

StatefulSet 创建的 Pod 名字不是随机的,而是:

复制代码
<statefulset-name>-<ordinal>

例如:

复制代码
nacos-cluster-0
nacos-cluster-1
nacos-cluster-2

即使 nacos-cluster-0 被删除重建,新 Pod 的名字仍然是 nacos-cluster-0。这就是"稳定身份"。

3.2 稳定的网络标识

StatefulSet 必须配合 Headless Service 使用。Pod 会获得稳定的 DNS 记录:

复制代码
<pod-name>.<serviceName>.<namespace>.svc.cluster.local

例如:

复制代码
nacos-cluster-0.nacos-cluster-hs.gateway-default.svc.cluster.local
nacos-cluster-1.nacos-cluster-hs.gateway-default.svc.cluster.local
nacos-cluster-2.nacos-cluster-hs.gateway-default.svc.cluster.local

注意:Pod 的 IP 可能变,但 DNS 名不变。所以 Nacos 的 member.list 可以写死这些 FQDN,节点启动时就能互相发现。

3.3 稳定的存储

StatefulSet 可以通过 volumeClaimTemplates 为每个 Pod 创建独立的 PVC:

yaml 复制代码
volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

每个 Pod 会得到自己的 PVC,命名规则是:

复制代码
<volumeClaimTemplateName>-<statefulsetName>-<ordinal>

例如:

复制代码
data-nacos-cluster-0
data-nacos-cluster-1
data-nacos-cluster-2

这样,nacos-cluster-0 重建后,仍然会挂载 data-nacos-cluster-0,数据不会丢。

默认情况下,删除 StatefulSet 不会删除 PVC,缩容也不会删除 PVC,需要手动清理。

3.4 稳定的顺序

StatefulSet 默认使用 OrderedReady 策略:

  • 创建时:按 0 → 1 → 2 顺序,前一个 Ready 后才创建下一个;
  • 删除时:按 2 → 1 → 0 顺序;
  • 滚动更新时:默认从最大序号到最小序号。

也可以设置为 Parallel,让所有 Pod 并行创建或删除。Nacos 配置里就用了:

yaml 复制代码
podManagementPolicy: Parallel

因为 Nacos 集群节点需要尽量一起启动,否则先启动的节点会一直等其他节点,拖慢集群组建。

4. StatefulSet 的核心字段

一个简化的 StatefulSet 示例:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web-hs
spec:
  clusterIP: None
  selector:
    app: web
  ports:
    - port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: web-hs
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx
          volumeMounts:
            - name: data
              mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi

关键字段:

字段 作用
serviceName 必须指向一个 Headless Service,用于提供稳定 DNS
replicas 副本数
selector 选择要管理的 Pod
template Pod 模板
volumeClaimTemplates 为每个 Pod 创建独立 PVC
podManagementPolicy OrderedReady(默认)或 Parallel
updateStrategy RollingUpdate(默认)或 OnDelete,支持 partition 金丝雀

这个例子会创建:

  • Pod:web-0web-1web-2
  • DNS:web-0.web-hs.default.svc.cluster.local
  • PVC:data-web-0data-web-1data-web-2

5. StatefulSet 与 Deployment 对比

维度 Deployment StatefulSet
适用场景 无状态服务 有状态应用
Pod 名 随机后缀 固定序号,如 web-0
网络标识 无稳定 DNS 稳定 FQDN
存储 共享或临时 每 Pod 独立 PVC
启动顺序 并行 默认有序,可并行
更新顺序 任意滚动 默认逆序滚动
扩缩容 只改 replicas 需考虑集群成员、存储、选主
典型应用 Web、API MySQL、Kafka、ZooKeeper、etcd、Nacos

6. StatefulSet 不做什么?

这一点非常重要:StatefulSet 只解决 K8s 层的有状态编排,不解决应用层的数据一致性。

它不负责:

  • 数据复制;
  • 选主;
  • 数据备份;
  • 高可用;
  • 网络直连;
  • 保证 Pod 永不重建;
  • 保证应用一定能组成集群。

这些仍然由应用自己实现。比如 Nacos 自己负责 Raft 选主、Distro 数据同步、服务注册表复制。StatefulSet 只是给 Nacos 节点提供了稳定身份、稳定 DNS 和稳定存储。

7. 回到 Nacos 集群

在你们的配置中:

yaml 复制代码
kind: StatefulSet
metadata:
  name: nacos-cluster
spec:
  serviceName: nacos-cluster-hs
  podManagementPolicy: Parallel
  replicas: 3

StatefulSet 扮演的角色是:

  • 创建 nacos-cluster-0/1/2 三个固定身份的 Pod;
  • 通过 nacos-cluster-hs Headless Service 提供稳定 DNS;
  • nacos.member.list 可以写死三条 FQDN;
  • Parallel 加快三节点启动;
  • 配合 PDB minAvailable: 2 保护多数派。

而 Nacos 自己负责:

  • 集群成员发现;
  • Raft 选主;
  • 配置和服务数据同步;
  • 客户端注册与健康检查。

所以,StatefulSet 是 Nacos 集群在 K8s 上的"身份与网络底座",不是 Nacos 集群本身。

8. 什么时候该用 StatefulSet?

适合:

  • 数据库:MySQL、PostgreSQL、MongoDB;
  • 消息队列:Kafka、RabbitMQ;
  • 分布式协调:ZooKeeper、etcd;
  • 注册配置中心:Nacos、Consul;
  • 搜索与存储:Elasticsearch、ClickHouse。

不适合:

  • 无状态 Web 服务;
  • API 网关;
  • 前端静态资源;
  • 任务队列 Worker。

这些用 Deployment 更简单、更灵活。

9. 总结

一句话:

StatefulSet 是给 Pod 发"身份证 + 固定住址 + 专属储物柜"的控制器。

它保证:

  • Pod 名字稳定;
  • 网络标识稳定;
  • 存储稳定;
  • 启动、扩缩、更新顺序可控。

但它不保证应用层的数据一致性、选主和高可用。真正的分布式逻辑,仍然由 Nacos、MySQL、Kafka 这些应用自己实现。

所以,Nacos 集群需要 StatefulSet,是因为它需要固定身份和固定地址 来组成集群;而普通无状态服务只需要 Deployment,因为它们的副本之间互不相识,改 replicas 就够了。

相关推荐
cg.family2 小时前
K8S集群手动巡检
k8s
九皇叔叔17 小时前
Kubernetes 资源管理方式详解:命令式与声明式管理
docker·容器·k8s
九皇叔叔2 天前
K8S 资源菜单
docker·容器·kubernetes·k8s
九皇叔叔2 天前
Kubernetes 命令式对象配置详解:使用 YAML 管理 Kubernetes 资源
docker·容器·k8s
小马同学-2 天前
crictl实战:K8s容器运行时排障工具
容器·k8s·crictl
富士康质检员张全蛋2 天前
Kafka Connect-Standalone 模式
k8s
九皇叔叔4 天前
Kubernetes 核心概念:集群架构、核心组件与资源对象
docker·容器·kubernetes·k8s
三8444 天前
云安全 · 05 · etcd 安全:未授权访问与数据泄露
云原生·k8s·etcd安全
Eminem896 天前
11、k8s控制器Replicaset
k8s