恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

StatefulSet与Deployment的选型对比:有状态应用的关键差异

  • 首页
  • 资讯中心
  • /
  • StatefulSet与Deployment的选型对比:有状态应用的关键差异

相关资讯

Flutter + OpenHarmony 跨端实践:地图攻略页面的适配与性能优化全记录 2026/9/30 15:06:34
从登录到鉴权:图库管理平台的Token、RBAC与中间件实战 2026/9/30 15:06:34
SolidWorks多用户远程共用工作站:10人挤一台机器的完整部署指南 2026/9/30 15:06:34

最新资讯

别再用Word硬扛了:aigcbiye期刊论文功能,把“投稿”这件事拆成了三个可执行的决策
在家辅导孩子英语总吵架?六条原则加一份每日20分钟安排,家长不再焦虑
Agentic Coding 智能体编程工具对比:从 Cline 配置 TaoToken 到最佳实践落地
UltraEdit 打开大文件翻页卡屏?用 TaoToken 统一 Key 通道排查配置与性能瓶颈
UC Berkeley 开源 LWM 世界模型:多模态大模型接入 TaoToken 的 config.toml 配置骨架与验证
文献综述的检索式怎么定才找得全

今日推荐

模型优化器实战:从FP32到INT8的推理加速与精度平衡
LangGraph+FastAPI构建可审计AI编码助手
基于图像预处理与几何特征的人脸脸型发型搭配系统实现

本周热门

从像素到笔画:srt-whiteboard-animation骨架笔迹追踪实现(Zhang-Suen细化+8邻接追踪)
网站建设的英语怎么说?别只背单词,看完这套安全完整流程才敢上线
新手入门看这篇:建设网站加盟避坑指南与SEO实操

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

StatefulSet与Deployment的选型对比:有状态应用的关键差异

发布时间:2026/9/30 15:11:35
StatefulSet与Deployment的选型对比:有状态应用的关键差异 StatefulSet 和 Deployment 的区别是我做了快十年容器平台架构和排障之后被问到的频率最高的一个问题。这个问题表面上是两个 Kubernetes 对象的对比实际上背后是有状态应用怎么上云原生这个更大的话题。我见过把 MySQL 直接挂在 Deployment 上跑的生产集群遇到节点宕机后数据库连不回来最后整个项目组花了两个通宵处理数据也见过把所有 Web 应用都改成 StatefulSet 的团队结果一次发布更新要等大半天因为每个 Pod 都在排队。两种方式没有绝对的对错关键是搞清楚你到底在管理什么样的应用。这篇文章里我会用实际踩坑的经验和完整的例子把这两个工作负载在设计上的差异讲清楚。1. 先搞清楚两类工作负载管理的 Pod本质差在哪1.1 DeploymentPod 是流水线上的耗材Deployment 面向的是无状态应用。它底下真正干活的是 ReplicaSetDeployment 只负责声明我要多少个副本副本数、版本、Pod 模板都由它统一管理。你创建一个 Deployment实际运行起来的 Pod 名字长这样web-7d8f9cbf74-abc12 web-7d8f9cbf74-def34 web-7d8f9cbf74-ghi56前缀的web-后面跟着 ReplicaSet 的哈希和一段随机字符串。注意这个随机字符串它是 Deployment 对 Pod 态度的直观体现Pod 只是个临时冒出来的实例名字不重要身份不重要IP 也不重要。任意一个 Pod 挂了ReplicaSet 马上拉起一个新的名字、IP 全变了但只要总数维持正确就行。一个很典型的场景Deployment 管理的 Nginx 如果从节点 A 被重新调度到节点 B客户端通过 Service 访问它完全感知不到变化。因为 Service 本身是个负载均衡入口后面一堆 Pod 都是等价的请求打到哪个 Pod 都行。这就是无状态的核心所有副本对请求等价数据要么不落到本地要么落到外置共享存储。所以 Deployment 下面挂一些共享 NFS 或云盘也是常见的但那是所有副本共用一份数据而不是每个副本各管各自的数据。从这段描述你应该能感觉到Deployment 的设计哲学是把 Pod 用完即弃。1.2 StatefulSetPod 带着编号和档案StatefulSet 恰恰相反。它的 Pod 名字是固定的、有规律的mysql-0 mysql-1 mysql-2编号从 0 开始依次递增。每个编号不仅仅是个数字而是这个 Pod 的永久身份Pod 被删除后重新创建出来的 Pod 还叫mysql-0不会变成别的名字这个 Pod 挂的存储卷也是固定的数据不会丢集群里的其他组件可以通过固定的主机名找到它不用关心它跑到哪台节点上。这个设计的意义在分布式系统里极其明显。以 MySQL 主从集群来说从节点初始化时需要知道主节点的地址节点重启后集群里其他成员需要知道它还是不是原来那个节点复制关系建立起来了不能因为一次重启就断掉。如果所有节点都像 Deployment 那样随机命名、随机调度一旦某个节点换了身份整个集群的拓扑就乱了。用生活化的类比Deployment 管理的 Pod 像是流水线上的临时工走了一个随便补人工号不需要固定StatefulSet 管理的 Pod 则是有工牌、有档案的正式员工走了要留档回来还是原来的工号他手里的纸质档案也跟着他。所以处理数据库、消息队列、配置中心这类应用时你需要的恰恰是后者这种认身份的能力。2. 网络身份那点事固定 IP 是谣言稳定 DNS 才是真本事2.1 为什么说 StatefulSet 不提供固定 IP很多文章和视频在讲 StatefulSet 的时候都会说提供稳定的网络标识于是有人直接理解成Pod 有固定 IP。这个理解是错的而且会带来两个隐患一是排查问题的时候总按着 IP 去找结果发现 IP 变了二是在设计内部通信时把 IP 硬编码进配置节点一重启就全断。实际上StatefulSet 里的 Pod 每次重建IP 都是重新分配的。它保证的不是 IP 不变而是主机名也就是 Pod 名不变以及基于主机名生成的 DNS 记录不变。这一点我建议每个用 StatefulSet 的人都先记住能省掉后面很多排查时间。那稳定的网络标识到底是怎么实现的Kubernetes 里的 Pod 默认没有对外可达的稳定主机名访问一个 Pod 一般是走 Service。普通 Service 用一个 ClusterIP 做负载均衡Pod 的 IP 变化对客户端不可见。但 StatefulSet 的场景里客户端往往需要直连某一个具体节点这时候就需要另一种 Service。2.2 Headless Service 与每个 Pod 独一无二的 DNSStatefulSet 的 spec 里有个必填字段叫serviceName它要求你提供一个 Service通常是一个 Headless Service。所谓 Headless就是把clusterIP设为NoneapiVersion: v1 kind: Service metadata: name: mysql-headless spec: clusterIP: None selector: app: mysql ports: - port: 3306这个 Service 不提供统一的 ClusterIP 负载均衡入口而是把域名直接解析到各个 Pod 的 IP。配合 StatefulSet 的命名规则每个 Pod 会得到一条独有的 DNS 记录mysql-0.mysql-headless.default.svc.cluster.local mysql-1.mysql-headless.default.svc.cluster.local mysql-2.mysql-headless.default.svc.cluster.local格式是pod-name.headless-service-name.namespace.svc.cluster.local。也就是说只要通过这个域名访问不管 Pod 换了多少个 IP都能准确找到那个人。你可以在集群里随便找个 Pod 用nslookup或者dig验证返回的不是一个 VIP而是一串 Pod 的 A 记录。2.3 稳定 DNS 在分布式组件里到底解决什么问题举几个我实际部署过的例子。ZooKeeper 的配置里要写每个节点的地址节点启动后会根据配置里的主机名互相建立会话Etcd 集群启动参数里也是用 peer 地址互相发现Kafka 的 broker 注册到元数据服务之后客户端和其他 broker 要能按同一个地址找到它。这些组件如果跑在 Deployment 里Pod 每次重启名字都变集群的一致性和成员列表就得靠额外的服务发现机制来维护维护成本极高。StatefulSet 的做法等于把谁是谁这件事固化了下来。节点从机器 1 搬到机器 2主机名不变DNS 指向新 IP其他成员重新连接时还是按老名字找连接关系不中断。这是分布式系统最需要的一条底层能力。注意稳定 DNS 不是说 Pod 永远不宕机而是说它宕机重建之后身份不会变。这两件事有本质区别。当然稳定 DNS 不是没有代价。它要求你的应用开发时就支持主机名配置而不是硬编码 IP而且如果应用自身不做成员发现你依然需要手写初始节点列表。StatefulSet 只是给了你地基盖什么样的房子还得看应用自己。3. 存储绑定volumeClaimTemplates 才是 StatefulSet 的杀手锏3.1 Deployment 为什么做不到每个副本一块独立盘从名字就能看出来Deployment 关心的是部署这个动作它不关心每个副本的状态。所以 Deployment 的 Pod 模板里存储卷一般是下面两种情况之一所有副本共享同一个 PVC或者每个副本挂同一个只读配置卷。共享一个 PVC 没问题但你要想清楚数据语义如果三个副本同时往一个 RWOReadWriteOnce卷上写数据绝大多数存储后端会直接报错。而改成 RWXReadWriteMany共享卷又会面临并发写入的一致性问题。所以 Deployment 里跑数据库要么单副本硬扛要么就得在应用层面自己搞定多副本数据同步Kubernetes 层面帮不了你。StatefulSet 提供了volumeClaimTemplates翻译过来是卷声明模板apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql-headless replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: [ReadWriteOnce] resources: requests: storage: 10Gi这里声明了一个名为data的 PVC 模板。StatefulSet 控制器会为每个编号的 Pod 自动生成对应的 PVC名字是>spec: persistentVolumeClaimRetentionPolicy: whenDeleted: Retain whenScaled: RetainwhenScaled可以设成Delete这样缩容时对应 PVC 会被自动清理避免残留一堆没人用的云盘持续收费whenDeleted控制 StatefulSet 删除时 PVC 是否跟随删除。这两个策略建议在测试环境先验证一遍再上生产因为Delete意味着数据直接消失配置错了代价很大。4. 扩缩容、更新、删除顺序性才是最有争议的行为差异4.1 创建和缩容要排队Deployment 扩缩容的时候ReplicaSet 是并行创建或销毁 Pod 的用户几乎感受不到先后顺序。StatefulSet 默认的podManagementPolicy是OrderedReady意思非常直白必须等序号小的 Pod 进入 Ready 状态才会创建下一个。所以创建一个 3 副本的 StatefulSet你执行kubectl get pods观察会看到mysql-0先 Running 并 Ready然后mysql-1才开始创建mysql-1Ready 之后mysql-2才会出现。缩容则是反着来先删编号最大的一个等一个。这种排队的意义在于很多有状态应用强依赖启动顺序。比如一主两从的 MySQL 集群主节点必须先起来客户端和从节点才能知道往哪连Etcd 启动时也需要有初始成员先就位。如果你确定自己的应用不依赖任何启动顺序可以把podManagementPolicy改成Parallel让所有 Pod 同时创建能省下不少等待时间。我做过一个 Kafka 集群就是这样三个 broker 之间没有严格的启动依赖改用 Parallel 策略之后整体拉起时间缩短了一半还多。4.2 滚动更新策略和 Partition 灰度Deployment 的滚动更新有maxSurge和maxUnavailable两个参数控制节奏可以一次多起几个新副本再逐步替换旧的。StatefulSet 的默认更新策略RollingUpdate则没有这种多副本同时切换的灵活性它按编号从大到小一次只更新一个 Pod更新完一个并确认 Ready才继续下一个。这种一次一个的行为对于数据类应用是必要的因为数据库节点不能同时全部替换总得有节点在对外服务。但也带来了代价如果副本数多整个更新周期会很长。我见过一个 Elasticsearch 集群 15 个节点一次版本升级跑了接近一小时。如果你只想灰度更新部分节点StatefulSet 支持partition参数spec: updateStrategy: type: RollingUpdate rollingUpdate: partition: 2设置partition: 2之后控制器只会更新序号大于等于 2 的 Pod。也就是说序号 0、1 保持旧版本序号 2 及以上的节点先升级。这在数据库这类需要先升级从库、观察一段时间、再升级主库的场景下非常实用。等从库验证没问题再把partition改成 1 或 0让剩下的节点陆续跟上。还有OnDelete策略更新时不自动替换 Pod只有你手动删除某个 Pod控制器才会按新模板重建。适合那种想完全控制变更节奏的团队但日常用得少我一般只在需要配合外部数据迁移工具时才用。4.3 Pod 被删、节点宕机后会发生什么先说主动删 Pod你执行kubectl delete pod mysql-0StatefulSet 控制器会立即创建一个新的mysql-0名字不变网络标识不变重新挂上原来的 PVC。这在很多场景下可以当作重启单个节点来用比如某个从库连接数异常删掉让它重新初始化挺管用的。再说节点宕机。如果承载mysql-0的节点失联默认情况下 kubelet 会对该节点上的 Pod 打上终止标记但不会立刻让 Pod 离开节点因为需要等待节点恢复以确认 Pod 是否还活着。如果节点长时间不恢复mysql-0会一直处于 Terminating 状态而且由于 StatefulSet 默认同一个编号在同一时间只能有一个 Pod新 Pod 也无法创建整个集群的副本数就缺了。遇到这种情况常规操作是确认节点确实回不来之后对这个 Pod 执行强制删除kubectl delete pod mysql-0 --force --grace-period0然后控制器会用新 Pod 接管这个名字和 PVC。注意强制删除有风险如果原 Pod 还活着可能产生两个同名 Pod 短暂并存、同时访问同一块存储的情况。对数据库来说两个进程写同一块数据盘是大忌所以执行前一定要确认那个节点彻底失联或者已经从集群中移除。这个风险我在文章开头提到的那个 MySQL 事故里就踩过提醒各位格外小心。5. 选型判断到底什么业务该用 StatefulSet5.1 三个判断标准经过前面几轮的对比选型其实可以收敛成三个问题数据丢了能重建吗如果你的服务挂了之后数据可以从外部源重新同步、可以重新生成、可以从备份恢复且业务能接受短暂不可用那不一定要用 StatefulSet。每个副本需要独立的持久化存储吗如果每个实例都必须有一块自己的数据盘而且实例间不能共享那 Deployment 帮不了你StatefulSet 的volumeClaimTemplates几乎是唯一直接支持的方式。实例之间是否需要稳定的网络身份分布式组件之间要互相发现、要建立固定连接需要每个节点有稳定主机名那 StatefulSet 就很有必要。三个问题里只要有两个回答是基本就该认真考虑 StatefulSet 了。如果全是否Deployment 完全够用。5.2 典型场景对照表应用场景有独立存储需求有稳定身份需求推荐工作负载备注Web 前端 / API 网关否否Deployment无状态随便扩缩容批处理一次性任务否否Job / CronJob不需要常驻MySQL 主从 / PostgreSQL 集群是是StatefulSet典型数据集群Redis 哨兵 / 集群是是StatefulSetAOF/RDB 需要独立盘ZooKeeper / Etcd是是StatefulSet配置中心、协调服务Kafka / Pulsar是是StatefulSet分区数据需要独立盘Mongo 副本集 / Elasticsearch是是StatefulSet分片副本各管各的盘MinIO 单节点是否看架构多数建议 StatefulSet列这么多是想提醒你别光记住数据库用 StatefulSet这一句结论。缓存、队列、协调服务、对象存储这类中间件只要满足有独立存储 有稳定身份两个条件都应该往 StatefulSet 上靠。5.3 从 Deployment 迁到 StatefulSet 的经验如果你现在有一个重要应用正跑在 Deployment 上而它其实应该有状态怎么平滑迁移我说几个自己用过的思路。如果只有单副本迁移成本很低。先把应用停掉确保数据盘没有被占用然后把原来的 PVC 改一下标签装进 StatefulSet 的 selector新建同名的 StatefulSet让控制器认领这个 PVC。只要 PVC 的名字符合templateName-stsName-ordinal的规则且标签匹配控制器会直接接手不需要重新拷数据。这个方法我在多个单实例应用上验证过。如果是多副本集群就不能只靠改名了。稳妥的做法是新的 StatefulSet 先用一套新的 PVC 和存储类建起来通过备份恢复或从旧集群同步数据跑一段时间确认数据一致后再把流量切过去。整个过程可以做成蓝绿发布前提是两套集群之间有足够的网络和存储带宽。把迁移时间安排在业务低峰给数据同步留足余量。最后提醒一个迁移中容易踩的坑StatefulSet 的selector是写在 spec 里不可变的创建之后不能改。所以创建前务必想清楚标签怎么写尤其别为了图省事把selector写成空匹配规则否则控制器会把集群里一堆无关的 PVC 全认领过来后面的问题会非常难排查。我当初就是因为这个吃了亏在几个环境的共享集群里差点把别人的存储卷抢走。最后说一个我现在一直保持的习惯每次新建 StatefulSet我都会在验收清单里加一项——把 PVC 的reclaimPolicy手动确认一遍并在测试环境跑一次完整的缩容、扩容、删 StatefulSet、再重建的演练。这套流程走完心里才有底。有状态应用出事往往不是配置写错而是没提前验证过异常路径。有空的话建议你也找个周末把你的 StatefulSet 在测试环境里故意折腾一遍这比看十篇文档都管用。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号