StatefulSet 比 Deployment 多了什么?Pod 的名字、DNS 和数据在重建后到底哪些不变?为什么有序创建会“卡住”?这篇用一个带 PVC 的 StatefulSet,把有序创建与终止、名字与 IP、存储与 PVC 的保留策略,以及 podManagementPolicy 的差别都实测一遍。
web-0:创建于 + 0.0s;Ready 于 + 7.0s;所在节点 worker3 web-1:创建于 + 7.0s;Ready 于 +14.0s;所在节点 worker2 web-2:创建于 +14.0s;Ready 于 +21.0s;所在节点 worker4 (就绪探针 initialDelaySeconds=3,加上调度、绑定 PVC 和拉起容器,每个 Pod 要 6~7 秒才 Ready;下一个 Pod 在上一个 Ready 之后才创建) 缩到 1 个副本(Pod 的 terminationGracePeriodSeconds=5,sleep 不处理 SIGTERM,每个要 5 秒才结束):web-2 在 +0.2s 开始终止,web-1 在 +5.8s 才开始终止(web-2 完全结束之后才轮到 web-1:从大序号往小序号逐个删)
OrderedReady(默认)下,web-0 创建于 +0.0 秒、Ready 于 +7.0 秒;web-1 在 web-0 Ready 的同一刻才创建,+14.0 秒 Ready;web-2 +14.0 创建、+21.0 秒 Ready。缩容反过来:web-2 先终止,等它完全结束(这里 Pod 要 5 秒),web-1 才在 +5.8 秒开始终止。需要按序号初始化、按序号下线的数据库集群靠的就是这个。
web-0 的 Pod IP 10.244.2.106;hostname=web-0;DNS web-0.web.k43.svc.cluster.local → 10.244.2.106 删掉 web-0 重建之后:名字仍是 web-0,uid 变了,Pod IP 10.244.2.107;DNS web-0.web.k43.svc.cluster.local → 10.244.2.107 headless Service 的 DNS 返回所有 Pod:web.k43.svc → 10.244.3.75 10.244.1.83 10.244.2.107
Pod 的名字是 <sts名>-<序号>,hostname 也是它,配合 headless Service 得到稳定的 DNS 名 web-0.web.k43.svc.cluster.local。删掉 web-0 重建:名字不变、uid 变了、Pod IP 从 10.244.2.106 变成 10.244.2.107,DNS 名字跟着解析到新 IP;web.k43.svc 本身返回所有 Pod 的 IP。所以客户端要用名字找成员,不能缓存 IP。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE data-web-0 Bound pvc-6baed74f-164c-4872-9770-17b9f57e6cc1 10Mi RWO standard <unset> 56s data-web-1 Bound pvc-0c67d43c-a622-4f9e-a883-1bf8d2916d13 10Mi RWO standard <unset> 49s data-web-2 Bound pvc-b9fb68c7-4bda-4e14-8a72-2a92a0192246 10Mi RWO standard <unset> 42s web-1 写入的文件:web-1;往 /data/note 写 hello-1 删掉 web-1 重建之后:/data/note=hello-1;PVC 绑定的 PV 没变:True(pvc-0c67d43c…) 缩到 1 个副本之后 PVC:persistentvolumeclaim/data-web-0 persistentvolumeclaim/data-web-1 persistentvolumeclaim/data-web-2(data-web-1、data-web-2 没有随 Pod 删除) 再扩回 3 个:web-1 的 /data/note=hello-1(旧数据还在) persistentVolumeClaimRetentionPolicy whenScaled: Delete 的 StatefulSet wd 缩到 1 个副本之后 PVC:persistentvolumeclaim/data-wd-0(data-wd-1 随 Pod 一起被删了) 删除 StatefulSet(whenDeleted: Delete)之后 PVC:(没有)
volumeClaimTemplates 为每个 Pod 创建 data-web-0、data-web-1、data-web-2。web-1 在 /data/note 里写了 hello-1,删掉重建后文件还在,PVC 绑定的 PV 也没变;缩到 1 个副本之后三个 PVC 仍在,扩回 3 个旧数据依然在。默认的保留策略是为了不丢数据;设置 persistentVolumeClaimRetentionPolicy: {whenScaled: Delete, whenDeleted: Delete} 后,缩容时对应的 PVC 随 Pod 一起删除,删除 StatefulSet 时所有 PVC 也跟着没了。
ord(podManagementPolicy=OrderedReady),就绪探针要求 /data/ready 存在(没人去创建):18 秒后已创建的 Pod ['ord-0'];Ready 的 [] par(podManagementPolicy=Parallel),就绪探针要求 /data/ready 存在(没人去创建):18 秒后已创建的 Pod ['par-0', 'par-1', 'par-2'];Ready 的 [] 只给 ord-0 创建 /data/ready 之后(ord-1 被创建,但它自己没有这个文件):ord 的 Pod ['ord-0', 'ord-1']
就绪探针要求一个没人创建的文件。OrderedReady 的 StatefulSet 18 秒后只创建了 ord-0(它不 Ready,后面的就不创建);podManagementPolicy: Parallel 的 3 个 Pod 同时创建。给 ord-0 创建了文件之后 ord-1 才出现。一个 Pod 起不来会让整个 StatefulSet 停在原地,排查时要先看序号最小的那个不就绪的 Pod。