16.3.5 StatefulSet与有状态应用

StatefulSet用于管理有状态应用,提供稳定的网络标识、持久化存储与有序部署/扩缩容,适合数据库、消息队列、分布式存储等需要固定身份与数据一致性的场景。

原理草图#

文章图片

核心特性#

  • 稳定网络标识:Pod名称固定为<sts-name>-<ordinal>,重建后名称保持一致。
  • 稳定存储:通过volumeClaimTemplates为每个Pod创建独立PVC,绑定稳定PV。
  • 有序部署与扩缩容:默认按序号升序创建、降序删除,可通过podManagementPolicy切换并行。
  • 有序滚动更新updateStrategy支持RollingUpdateOnDelete,按序号逐个更新。

关键资源与字段#

  • serviceName:通常指向Headless Service,为每个Pod提供独立DNS。
  • replicas:副本数,影响Pod数量与PVC数量。
  • selector/template:标签选择与Pod模板。
  • volumeClaimTemplates:为每个Pod自动创建PVC,命名为<claim-name>-<sts-name>-<ordinal>

安装与部署示例(Nginx有状态演示)#

目标:创建Headless Service + StatefulSet,并验证稳定Pod名、稳定PVC与DNS。

1) 创建Headless Service#

# /opt/k8s/sts/headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-hl
  namespace: default
spec:
  clusterIP: None
  selector:
    app: web-sts
  ports:
  - name: http
    port: 80
    targetPort: 80

2) 创建StatefulSet#

# /opt/k8s/sts/web-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: web-hl
  replicas: 2
  selector:
    matchLabels:
      app: web-sts
  podManagementPolicy: OrderedReady
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: web-sts
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

3) 应用资源并验证#

# 应用
kubectl apply -f /opt/k8s/sts/headless-svc.yaml
kubectl apply -f /opt/k8s/sts/web-sts.yaml

# 观察Pod创建顺序与名称
kubectl get pod -l app=web-sts -o wide

# 观察PVC/PV绑定
kubectl get pvc -l app=web-sts
kubectl get pv | grep data-web

# 观察DNS(在集群内执行)
kubectl run -it --rm dns-test --image=busybox:1.36 --restart=Never -- sh
nslookup web-0.web-hl.default.svc.cluster.local
nslookup web-1.web-hl.default.svc.cluster.local

4) 验证持久化(写入文件后重建Pod)#

# 往web-0写入文件
kubectl exec web-0 -- sh -c 'echo "hello-sts" > /usr/share/nginx/html/index.html'
kubectl delete pod web-0

# 等待重建后验证
kubectl exec web-0 -- sh -c 'cat /usr/share/nginx/html/index.html'
# 预期输出:hello-sts

运维关注点与命令解释#

  • 存储回收策略:PV回收策略影响删除Pod后的数据保留
    bash # 查看StorageClass默认回收策略 kubectl get sc -o wide # 查看PV回收策略字段 kubectl get pv -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.persistentVolumeReclaimPolicy}{"\n"}{end}'
  • 扩缩容风险:缩容会删除高序号Pod及其PVC
    bash # 扩容 kubectl scale sts/web --replicas=3 # 缩容(会删除web-2及其PVC) kubectl scale sts/web --replicas=1
  • 更新策略选择:关键业务可选OnDelete手动控制升级节奏
    bash # 修改更新策略为OnDelete kubectl patch sts/web -p '{"spec":{"updateStrategy":{"type":"OnDelete"}}}' # 手动删除Pod触发更新 kubectl delete pod web-0
  • 探针与启动顺序:有状态应用常依赖启动顺序与探针配置
    bash # 查看Pod是否Ready以及探针事件 kubectl describe pod web-0 | sed -n '/Events/,$p'

常见问题与排错流程#

1) PVC无法绑定#

kubectl describe pvc data-web-0
kubectl get sc
kubectl get pv

排查要点:StorageClass不存在、请求容量大于PV、访问模式不匹配。

2) DNS解析失败#

kubectl get svc web-hl
kubectl get endpoints web-hl
kubectl get pod -l app=web-sts --show-labels

排查要点:Headless Service未生效、Service selector与Pod标签不匹配、CoreDNS异常。

3) 更新卡住或Pod不Ready#

kubectl rollout status sts/web
kubectl describe pod web-0
kubectl logs web-0 --tail=100

排查要点:探针失败、容器启动慢、依赖服务不可达。

练习#

  1. podManagementPolicy改为Parallel,观察Pod创建顺序差异。
  2. updateStrategy改为OnDelete,并手动删除web-1观察滚动更新行为。
  3. 模拟PVC绑定失败:将volumeClaimTemplates中的storage改为一个极大值(如1000Gi),观察PVC事件并恢复。
  4. 使用kubectl exec web-0 -- hostname验证稳定主机名,并在重建后再次验证。