为StatefulSet配置云盘持久化存储

对于数据库、消息队列等有状态应用,StatefulSet 可通过 volumeClaimTemplates 为每个 Pod 动态创建并绑定独立的云盘持久卷。Pod 被重建或重新调度时,能够自动挂载回原有的存储卷,从而实现数据持久化,保障业务连续性。

配置示例如下:

apiVersion: apps/v1
kind: StatefulSet
# ...
spec:
  # ...
  volumeClaimTemplates:
  - metadata:
      name: data-volume                        # PVC 模板名称
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "alicloud-disk-essd"   # 指定存储类型
      resources:
        requests:
          storage: 20Gi                        # 申请的存储空间大小

工作原理

  • 创建与扩容

    初始创建或扩容时,StatefulSet控制器会通过volumeClaimTemplates模板,为每个Pod副本(如web-0web-1)创建并绑定一个名称唯一的PVC(如disk-essd-web-0disk-essd-web-1,名称格式遵循[模板名]-[Pod名])。这一机制确保了Pod与其存储之间稳定的映射关系。

    CSI 会根据模板中的参数配置 (storageClassNamestorageaccessModes),自动创建类型、大小和访问模式匹配的PV,完成绑定与挂载。

  • 缩容

    缩容时,控制器仅删除 Pod 本身,其关联的 PVC 及后端 PV 仍会保留,以确保数据安全。

  • 再次扩容与故障恢复

    基于缩容时的留存数据,再次扩容(调高副本数)或故障恢复(Pod删除后重建)时,控制器会自动查找并复用此前保留的同名 PVC。

    • 若存在,新的同名 Pod 会自动挂载此前的 PV,实现数据和状态的快速恢复。

    • 若不存在(如扩容操作超过了历史副本数峰值),则会新建 PVC和对应的PV。

准备StatefulSet

  1. 创建statefulset.yaml

    该示例将创建一个Service 和一个包含2个副本的 StatefulSet,StatefulSet通过volumeClaimTemplates为每个副本自动创建一个 20 GiB 的云盘。

    volumeClaimTemplates中的参数说明如下。

    参数

    说明

    accessModes

    存储卷的访问模式。ReadWriteOnce表示该卷一次只能被一个节点以读写方式挂载。

    storageClassName

    待使用的StorageClass名称。

    alicloud-disk-essdACK默认提供的StorageClass,用于创建ESSD云盘,默认PL等级为PL1。

    云盘采用按量付费,请参见块存储计费块存储价格

    storage

    云盘存储卷的容量大小。

    展开查看示例YAML

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      # clusterIP 设置为 "None" 表明这是一个 Headless Service
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx
      # serviceName 需与上面定义的 Headless Service 的名称匹配
      serviceName: "nginx"
      replicas: 2
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            ports:
            - containerPort: 80
              name: web
            # 将持久卷挂载到容器内的指定路径
            volumeMounts:
            - name: disk-essd
              mountPath: /data
      # PVC 的模板,StatefulSet 会根据此模板为每个 Pod 创建一个 PVC
      volumeClaimTemplates:
      - metadata:
          name: disk-essd
        spec:
          # 定义卷访问模式
          accessModes: [ "ReadWriteOnce" ]
          # 指定用于动态供应 PV 的 StorageClass
          storageClassName: "alicloud-disk-essd"
          resources:
            requests:
              # 定义为每个 PVC 申请的存储空间大小
              storage: 20Gi
  2. 部署StatefulSet。

    kubectl create -f statefulset.yaml
  3. 确认 Pod 处于 Running 状态。

    kubectl get pod -l app=nginx
  4. 查看PVC,确认系统已经为每个 Pod 自动创建并绑定(Bound)了对应的 PVC。

    kubectl get pvc

    预期输出:

    NAME              STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS         VOLUMEATTRIBUTESCLASS   AGE
    disk-essd-web-0   Bound    d-m5eb5ozeseslnz7zq54b   20Gi       RWO            alicloud-disk-essd   <unset>                 3m31s
    disk-essd-web-1   Bound    d-m5ecrvjrhqwehgzqpk5i   20Gi       RWO            alicloud-disk-essd   <unset>                 48s

通过扩缩容验证存储生命周期管理

通过扩容、缩容、再到扩容的流程,观察关联 PVC 的创建、保留和复用情况。

应用扩容

  1. 增加StatefulSet副本数至3个。

    kubectl scale sts web --replicas=3
  2. 确认 Pod 处于 Running 状态。

    kubectl get pod -l app=nginx
  3. 查看PVC,确认系统已自动创建了Pod web-2 以及对应的PVC disk-essd-web-2

    kubectl get pvc

    预期输出:

    NAME              STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS         VOLUMEATTRIBUTESCLASS   AGE
    disk-essd-web-0   Bound    d-m5eb5ozeseslnz7zq54b   20Gi       RWO            alicloud-disk-essd   <unset>                 4m1s
    disk-essd-web-1   Bound    d-m5ecrvjrhqwehgzqpk5i   20Gi       RWO            alicloud-disk-essd   <unset>                 78s
    disk-essd-web-2   Bound    d-m5ee2cvzx4dog1lounjn   20Gi       RWO            alicloud-disk-essd   <unset>                 16s

应用缩容

  1. 减少StatefulSet副本数至2个。

    kubectl scale sts web --replicas=2
  2. 确认 Pod 处于 Running 状态。

    kubectl get pod -l app=nginx
  3. 查看PVC。

    kubectl get pvc

    预期输出:

    NAME              STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS         VOLUMEATTRIBUTESCLASS   AGE
    disk-essd-web-0   Bound    d-m5eb5ozeseslnz7zq54b   20Gi       RWO            alicloud-disk-essd   <unset>                 4m21s
    disk-essd-web-1   Bound    d-m5ecrvjrhqwehgzqpk5i   20Gi       RWO            alicloud-disk-essd   <unset>                 98s
    disk-essd-web-2   Bound    d-m5ee2cvzx4dog1lounjn   20Gi       RWO            alicloud-disk-essd   <unset>                 36s

    此时,Pod web-2 已被删除,但 PVC disk-essd-web-2 仍然存在,以确保数据持久性。

应用再次扩容

  1. 再次增加StatefulSet副本数至3个。

    kubectl scale sts web --replicas=3
  2. 确认 Pod 处于 Running 状态。

    kubectl get pod -l app=nginx
  3. 查看PVC。

    kubectl get pvc

    预期输出:

    NAME              STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS         VOLUMEATTRIBUTESCLASS   AGE
    disk-essd-web-0   Bound    d-m5eb5ozeseslnz7zq54b   20Gi       RWO            alicloud-disk-essd   <unset>                 4m50s
    disk-essd-web-1   Bound    d-m5ecrvjrhqwehgzqpk5i   20Gi       RWO            alicloud-disk-essd   <unset>                 2m7s
    disk-essd-web-2   Bound    d-m5ee2cvzx4dog1lounjn   20Gi       RWO            alicloud-disk-essd   <unset>                 65s

    此时,新建的Pod web-2 已自动绑定并使用此前遗留的PVC disk-essd-web-2

通过模拟Pod故障验证持久化存储

通过“写入数据 -> 删除 Pod -> 检查数据”的流程,来验证存储在云盘上的数据在 Pod 重建后是否仍然存在。

  1. 在 Pod 中写入测试数据。

    Pod web-1为例,在其挂载的云盘路径 /data下创建一个test文件。

    kubectl exec web-1 -- touch /data/test
    kubectl exec web-1 -- ls /data

    预期输出:

    lost+found
    test
  2. 模拟 Pod 故障,删除 Pod。

    kubectl delete pod web-1

    再次执行kubectl get pod -l app=nginx,可以发现已自动创建一个同名的Pod web-1

  3. 验证新 Pod 中的数据。

    在新Pod web-1中再次检查 /data 目录。

    kubectl exec web-1 -- ls /data

    预期输出中,此前创建的 test 文件依然存在,表明即使 Pod 被删除重建,数据也实现了持久化存储。

    lost+found
    test

应用于生产环境

  • 成本与资源管理:StatefulSet 缩容或删除后,其关联的 PVC 和云盘默认会被保留,存留资源会持续产生费用。请及时清理无需使用的 PVCPV,并释放云盘。

  • 数据安全与备份:持久化存储仅解决 Pod 重建后的高可用问题,但不提供数据备份能力。对于核心业务,建议使用备份中心进行数据的备份和恢复。

  • 高可用与容灾:云盘是可用区级别资源,不支持跨可用区挂载。建议选用支持多可用区容灾的云盘类型,将数据实时同步写入同一地域的不同可用区,实现跨可用区的故障恢复,请参见使用ESSD同城冗余云盘

相关文档

使用云盘存储卷如遇问题,可参见云盘存储卷FAQ排查。