导读:本期聚焦于风铃创作的《Kubernetes StatefulSet 怎么用?有状态服务部署实战教程详解》,敬请观看详情。部署数据库或消息队列到 Kubernetes 集群时,用普通 Deployment 往往会出现 Pod 重建后数据丢失、网络标识变化的问题,这时候就需要 StatefulSet。本文详细讲解 StatefulSet 的核心特性,包括稳定网络标识、有序部署与扩缩容、配合 Headless Service 实现服务发现,以及通过 PersistentVolumeClaim 模板实现存储持久化的原理。文中还会给出完整的 YAML 示例,演示如何部署一个高可用的 MySQL 或类似有状态应用,并分析更新策略、扩容缩容顺序等容易踩坑的细节,帮助你真正掌握有状态服务在 K8s 中的正确用法。

StatefulSet 是 Kubernetes 中专门用于管理有状态应用的工作负载控制器。与 Deployment 不同,它为每个 Pod 提供稳定的网络标识、持久的存储以及有序的部署和扩缩容能力,非常适合部署 MySQL、Redis Cluster、ZooKeeper、Kafka 这类对身份和数据一致性敏感的服务。本文将从核心概念、YAML 编写、部署验证到更新策略,完整讲解 StatefulSet 的使用方法。

Kubernetes StatefulSet 怎么用?有状态服务部署实战教程详解

一、StatefulSet 与 Deployment 的核心区别

要理解 StatefulSet,先要明白它和 Deployment 的差异。Deployment 管理的 Pod 是完全等价的:名字随机生成、IP 地址随时可能变化、Pod 可以被任意一个新副本替换,这对无状态的 Web 服务毫无影响。但有状态应用就不一样了,比如 MySQL 主从集群中,主节点和从节点承担的角色不同,如果从节点 Pod 被替换后丢失了自己的身份,整个集群的复制关系就会混乱。

StatefulSet 针对这些问题提供了三个核心保证。第一是稳定的网络标识:每个 Pod 拥有一个基于序号的稳定主机名,格式为 pod名称-序号,例如 mysql-0mysql-1,无论 Pod 被调度到哪个节点、重建多少次,这个名字都不会变。第二是稳定的存储:通过 volumeClaimTemplates 为每个 Pod 绑定独立的 PersistentVolumeClaim,Pod 重建后依然挂载同一块持久卷。第三是有序性:Pod 的创建、删除、滚动更新都严格按照序号顺序执行,默认从 0 号开始逐个创建,删除时则从最大序号开始倒序执行。

另外需要注意,StatefulSet 必须配合 Headless Service 使用。Headless Service 即 clusterIP: None 的 Service,它不为集群提供负载均衡 IP,而是直接将 Service 名称解析到各个 Pod 的 DNS 记录上,这样其他服务就能通过 pod-name.service-name.namespace.svc.cluster.local 这样的域名精准访问到某个特定实例。

二、编写 StatefulSet 的完整 YAML 示例

下面以部署一个三节点的 MySQL 集群为例,展示 StatefulSet 的典型写法。完整资源包含三部分:Headless Service、ConfigMap 和 StatefulSet 本体。

apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
  labels:
    app: mysql
spec:
  clusterIP: None          # Headless Service,关键配置
  selector:
    app: mysql
  ports:
    - name: mysql
      port: 3306
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  my.cnf: |
    [mysqld]
    log-bin=mysql-bin
    server-id=1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-headless   # 必须指定 Headless Service 名称
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          ports:
            - containerPort: 3306
              name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "Root@123456"
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
            - name: config
              mountPath: /etc/mysql/conf.d
  volumeClaimTemplates:          # 存储模板,每个 Pod 生成独立 PVC
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: standard
        resources:
          requests:
            storage: 10Gi

这份配置中有几个关键点需要理解。serviceName 字段是 StatefulSet 特有的必填项,指向前面定义的 Headless Service。volumeClaimTemplates 定义了存储模板,控制器会为每个 Pod 自动创建一个独立的 PVC,命名为 data-mysql-0data-mysql-1data-mysql-2,这些 PVC 与 Pod 序号一一对应,Pod 重建后仍然挂载原来的卷,数据得以保留。

删除 Pod 时也要注意,StatefulSet 的 PVC 不会被自动删除。即使缩容把副本数从 3 降到 1,被删掉的 data-mysql-2 这条 PVC 依然存在,再次扩容时新 Pod 会重新绑定它并恢复原有数据。这是数据安全的保护机制,但也会带来存储浪费,长期不用时需要手动清理不再需要的 PVC。

三、部署验证与 Pod 间通信方式

执行 kubectl apply -f mysql-statefulset.yaml 后,可以用 kubectl get pods -w 观察创建过程。你会看到 Pod 是严格按顺序创建的:先启动 mysql-0,等它完全 Ready 之后才会创建 mysql-1,最后是 mysql-2。这个特性对于需要先启动主节点、再启动从节点的集群化应用非常重要。如果某个 Pod 一直无法 Ready,后面的 Pod 都不会被创建,排查时要重点检查卡住的序号最小的那个 Pod。

验证网络标识也很简单。进入任意一个测试 Pod,执行 DNS 查询即可确认:

# 查看某个具体 Pod 的 DNS 解析
nslookup mysql-0.mysql-headless.default.svc.cluster.local

# 查看整个服务的所有 Pod 地址
nslookup mysql-headless.default.svc.cluster.local

# 通过稳定域名直接连接指定实例
mysql -h mysql-0.mysql-headless.default.svc.cluster.local -uroot -p

第一条命令返回单个 Pod 的 IP,第二条返回所有 Pod 的 IP 列表。这种 DNS 机制让应用层可以自己实现服务发现逻辑,例如 MySQL 从节点在配置复制时可以固定指向 mysql-0 作为主库地址,而不依赖任何写死的 IP。此外,StatefulSet 的 Pod 还支持一条 DNS 记录格式简化写法:pod-name.service-name,在同一命名空间内可以直接用 mysql-0.mysql-headless 访问,非常方便。

四、更新策略与扩缩容实战技巧

StatefulSet 默认的更新策略是 RollingUpdate,滚动更新时从最大序号的 Pod 开始倒序逐个更新,并且会保证前一个 Pod 已经 Ready 才继续下一个。这种顺序保证了数据库类应用的更新安全。你还可以设置 partition 参数进行灰度发布:

spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 2   # 只有序号大于等于 2 的 Pod 会更新

上面的配置表示只有 mysql-2 会使用新镜像,序号 0 和 1 的 Pod 保持不变。验证新版本稳定后,逐步降低 partition 值即可完成全量升级。如果不想自动更新,可以把 type 改为 OnDelete,只有手动删除 Pod 时才会触发重建并使用新配置,适合需要精确控制更新时机的场景。

扩缩容方面,执行 kubectl scale statefulset mysql --replicas=5 扩容时,新 Pod 按序号递增顺序创建,并自动生成对应的新 PVC。缩容则是倒序删除,从最大序号开始。这里有一个常见的坑:如果集群中有节点 NotReady,StatefulSet 可能出现 Pod 卡在 Terminating 状态无法正常删除,此时可以用强制删除命令 kubectl delete pod mysql-2 --force --grace-period=0 处理,但要谨慎使用,强制删除前应确认该节点上的数据已经不再需要写入,否则可能造成数据分裂。

总结一下,使用 StatefulSet 的正确姿势是:始终搭配 Headless Service 提供稳定网络标识,用 volumeClaimTemplates 保证存储持久化,利用有序性保证集群类应用的启动顺序,并通过 partition 策略降低发布风险。掌握这些要点后,无论是部署 MySQL、Redis 还是 Kafka,都能在 Kubernetes 上稳定运行有状态服务。

KubernetesStatefulSet有状态服务修改时间:2026-09-05 17:21:00

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260905/51036.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。