1、Statefulset控制器
StatefulSet是k8s中的一种控制器(Controller),用于管理有状态应用程序的部署。与Deployment控制器不同,StatefulSet为每个Pod实例分配了一个唯一的标识符,并确保这些标识符在Pod重新创建时保持不变。这为有状态应用程序提供了一些关键的功能和保证,例如稳定的网络标识符、有序的部署和扩展以及持久化存储。
1.1 唯一标识符
每个StatefulSet管理的Pod实例都被分配了一个唯一的标识符,通常是一个整数索引。这个标识符可以用于在网络中唯一地标识每个Pod实例。
1.2 稳定的网络标识符
StatefulSet中的每个Pod实例都有一个稳定的网络标识符,通常是一个DNS名称。这使得其他应用程序可以通过名称轻松地访问特定的Pod实例,而不需要关注其具体的IP地址变化。
1.3 有序的部署和扩展
StatefulSet控制器确保Pod实例按照定义的顺序逐个启动和关闭。这对于依赖先前实例状态的应用程序非常重要。此外,扩展StatefulSet时,新的Pod实例也会按照指定的顺序逐个创建。
1.4 持久化存储
StatefulSet允许每个Pod实例关联一个持久化卷(Persistent Volume),这使得有状态应用程序可以在Pod重新创建时保留其数据。这为应用程序提供了持久化存储的能力,使得数据不会丢失或重置。
1.5 StatefulSet VS Deployment
| 对比维度 | Deployment | StatefulSet |
|---|---|---|
| 适用场景 | 无状态应用 | 有状态应用 |
| Pod 身份 | 无稳定身份,副本可互换 | 每个 Pod 有稳定唯一身份,按序号 ordinal 标识 |
| Pod 名称 | <deployment>-<rs-hash>-<random> |
<statefulset>-0、<statefulset>-1、... |
| 网络标识 | 无稳定 per-Pod DNS,通常通过 Service 负载均衡 | 通常配合 Headless Service,提供稳定 DNS,如 <pod>.<svc>.<ns>.svc.cluster.local |
| Service | 普通 Service 即可 | 通常需要 Headless Service;也可额外用普通 Service 做统一入口 |
| 存储 | 无 volumeClaimTemplates,多副本通常共享 PVC 或不用持久化 |
通过 volumeClaimTemplates 为每个 Pod 创建独立 PVC,PVC 与 ordinal 绑定 |
| PVC 生命周期 | 取决于手动创建和保留策略 | 删除 StatefulSet 默认保留 PVC,需手动清理 |
| 启动顺序 | 无保证,可并行启动 | 默认 OrderedReady:0 → N-1,等待前一个 Ready |
| 停止/缩容顺序 | 无保证,可并行删除 | 默认 N-1 → 0,按逆序删除 |
| 扩缩容 | 任意并行扩缩 | 默认按序扩缩;可配置 podManagementPolicy: Parallel |
| 更新策略 | RollingUpdate(支持 maxSurge/maxUnavailable)或 Recreate |
RollingUpdate(支持 partition,默认逆序)或 OnDelete |
| 更新顺序 | 可不按序,多副本可能同时更新 | 默认逆序,通常逐个更新并等待 Ready |
| 版本与回滚 | 通过 ReplicaSet 管理版本,回滚方便 | 通过 ControllerRevision 管理版本,支持历史/回滚,但通常按序执行 |
| 服务发现 | Service 统一入口,Pod 一般不单独寻址 | 每个 Pod 可通过稳定 DNS 单独寻址,也可用普通 Service 统一入口 |
| 管理对象 | Deployment → ReplicaSet → Pod | StatefulSet → Pod |
| 删除 Pod 后 | 重建随机名称的新 Pod | 重建同名、同 ordinal 的 Pod |
| 典型场景 | Web 前端、API、无状态微服务 | MySQL、PostgreSQL、Redis Cluster、Kafka、ZooKeeper、etcd 等 |
一句话总结:无状态、副本可互换选 Deployment;有状态、需要稳定身份/独立存储/顺序启动选 StatefulSet。
2、部署StatefulSet
bash
# 创建statefulset.yaml
vi statefulset.yaml
# 填入以下内容
apiVersion: v1 # API 版本,Service 使用 v1
kind: Service # 资源类型:Service
metadata: # 元数据
name: nginx # Service 名称
labels: # Service 标签
app: nginx # 标签 app=nginx
spec: # Service 规格
ports: # Service 端口定义
- port: 80 # 暴露端口 80
name: web # 端口名称 web
clusterIP: None # 无头 Service,不分配 ClusterIP
selector: # Pod 选择器
app: nginx # 选择 app=nginx 的 Pod
--- # YAML 文档分隔符
apiVersion: apps/v1 # StatefulSet 的 API 版本
kind: StatefulSet # 资源类型:StatefulSet
metadata: # 元数据
name: web # StatefulSet 名称
spec: # StatefulSet 规格
selector: # Pod 选择器
matchLabels: # 匹配标签
app: nginx # 匹配 app=nginx
serviceName: "nginx" # 关联的 Headless Service 名称
replicas: 2 # Pod 副本数
template: # Pod 模板
metadata: # Pod 元数据
labels: # Pod 标签
app: nginx # Pod 标签 app=nginx
spec: # Pod 规格
containers: # 容器列表
- name: nginx # 容器名称
image: nginx # 容器镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略
ports: # 容器端口定义
- containerPort: 80 # 容器监听端口 80
name: web # 容器端口名称 web
bash
# 启动statefulset
kubectl apply -f statefulset.yaml
# 查看statefulset
kubectl get statefulset
# 查看pod
kubectl get pod

bash
#使用kubectlrun运行一个提供nslookup命令的容器的,通过对pod主机名执行nslookup,可以检查它们在集群内部的DNS地址
kubectl run busybox --image docker.io/library/busybox:latest --image-pull-policy=IfNotPresent --restart=Never --rm -it busybox -- sh
# 进入容器后执行
nslookup web-0.nginx.default.svc.cluster.local
nslookup nginx.default.svc.cluster.local


3、Statefulset管理pod:扩容、缩容、更新
如果我们觉得两个副本太少了,想要增加,只需要修改配置文件statefulset.yaml里的replicas的值即可,原来replicas: 2,现在变成replicaset: 3,如果要缩容也是修改这个值即可,修改之后,执行如下命令更新:
bash
kubectl apply -f statefulset.yaml
如果要实现对pod更新则修改statefulset.yaml

