通过动态存储卷使用云盘进行持久化存储

基于动态存储卷机制,可为每个应用副本自动创建并挂载一个独立的云盘,适用于数据库、中间件等等对 I/O 和延迟要求较高的场景,同时能够简化存储的生命周期管理。

工作原理

StatefulSet中使用云盘动态存储卷的流程如下:

  1. 定义模板
    新建或使用默认 StorageClass,作为动态创建云盘的模板,规定其类型、性能、回收策略等关键参数。

  2. 在应用中声明存储需求

    StatefulSet中定义 volumeClaimTemplates,并引用 StorageClass,声明Pod待使用的PVC的规格,如存储容量、访问模式等。

  3. 自动化创建并挂载存储卷
    StatefulSet 创建 Pod 时,系统会基于模板自动为其生成一个唯一的 PVC。CSI组件会根据 StorageClass 的规则创建 PV 并与 PVC 绑定,最终将该云盘挂载到 Pod 中。

适用范围

  • 可用区限制:除ESSD同城冗余云盘外,其他云盘类型无法跨可用区挂载,只能挂载到同一可用区下的Pod。

  • 实例规格族限制:部分云盘类型仅支持挂载到特定的实例规格族

  • CSI组件限制:已安装csi-plugin组件和csi-provisioner组件。

    CSI组件默认安装,请确保未手动卸载。可在组件管理页面查看安装情况。建议升级csi-plugincsi-provisioner至最新版本。
  • 虚拟节点限制:如需在虚拟节点上使用云盘,需遵循集群和kube-scheduler版本要求。

    展开查看版本要求

    集群版本

    kube-scheduler版本

    1.28及以上

    6.9.3及以上

    1.26

    6.8.7

    1.24

    6.4.7

    1.22

    6.4.5

  • 灵骏节点限制:如需在灵骏节点上使用云盘,需满足以下前提条件和配置要求。

    展开查看具体要求

    • CSI 组件版本:不低于 v1.34.3。

    • RAM角色授权:需为AliyunCCCSIPluginRole手动添加 eflo:DescribeNodeeflo:DescribeNodeType权限。

      操作入口,请参见RAM角色授权
    • StorageClass配置:需在 parameters 字段中声明特殊标签 diskTags: "createdByProduct:eflo"

      配置后,系统将自动创建带有 createdByProduct:eflo 标签的云盘和对应PV,该云盘可以且仅可以被调度到灵骏节点。

      apiVersion: storage.k8s.io/v1
      kind: StorageClass
      metadata:
        # 建议命名中体现灵骏专用,便于区分
        name: alicloud-disk-essd-pl0-lingjun
      parameters:
        type: cloud_essd
        performanceLevel: PL0
        # 关键配置:此标签用于指示CSI创建可供灵骏节点使用的云盘
        diskTags: "createdByProduct:eflo"
      provisioner: diskplugin.csi.alibabacloud.com
      reclaimPolicy: Delete
      allowVolumeExpansion: true

步骤一:选择StorageClass

为便于使用,ACK提供多种默认StorageClass。由于StorageClass创建后无法修改,若默认配置不满足需求,可通过手动创建StorageClass新建。

使用默认StorageClass

可从以下默认StorageClass中选择一个,在应用的storageClassName字段中引用其名称即可。

StorageClass名称

动态创建的云盘类型

alicloud-disk-topology-alltype(推荐)

默认先调度Pod再创建云盘,避免因可用区不匹配导致挂载失败(volumeBindingMode: WaitForFirstConsumer)。Pod调度到的节点可用区和实例规格,会结合云盘库存情况,按ESSD、SSD、高效云盘的顺序尝试创建。默认优先创建ESSD PL1,容量大小最低为20 GiB。

alicloud-disk-essd

ESSD云盘,默认为PL1性能级别,云盘容量大小最低为20 GiB。

重要

云盒内的ESSD云盘仅支持PL0级别,需手动创建StorageClass并指定performanceLevelPL0

alicloud-disk-ssd

SSD云盘,云盘容量大小最低为20 GiB。

alicloud-disk-efficiency

高效云盘,云盘容量大小最低为20 GiB。

可通过kubectl describe sc <storageclass-name>查看StorageClass详细配置。

手动创建StorageClass

kubectl

  1. 创建disk-sc.yaml

    示例以使用volumeBindingMode: WaitForFirstConsumer延迟绑定PVStorageClass为例。

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      # StorageClass名称
      name: alicloud-disk-wait-for-first-consumer
    # 驱动类型,使用阿里云云盘CSI插件时固定为此值。
    provisioner: diskplugin.csi.alibabacloud.com
    parameters:
      # 云盘类型,按优先级自适应选择
      type: cloud_auto,cloud_essd,cloud_ssd  
      # 文件系统类型
      fstype: ext4
      diskTags: "a:b,b:c"
      encrypted: "false"
      # ESSD云盘的性能级别
      performanceLevel: PL1 
      provisionedIops: "40000"
      burstingEnabled: "false"
    # 绑定模式,多可用区场景下建议使用WaitForFirstConsumer
    volumeBindingMode: WaitForFirstConsumer
    # 回收策略
    reclaimPolicy: Retain
    # 是否允许存储卷扩容
    allowVolumeExpansion: true
    # 拓扑限制:限制云盘只能在指定的可用区创建
    allowedTopologies:
    - matchLabelExpressions:
      - key: topology.diskplugin.csi.alibabacloud.com/zone
        values:
        # 替换为实际可用区
        - cn-hangzhou-i
        - cn-hangzhou-k

    主要参数说明如下:

    参数

    说明

    provisioner

    驱动类型,必填参数。使用阿里云云盘CSI插件时固定为diskplugin.csi.alibabacloud.com

    parameters

    type

    云盘类型,必填参数。可取值:

    支持任意组合,例如type: cloud_ssd,cloud_essd,cloud_auto。系统将按配置顺序依次尝试创建。最终创建的云盘类型受节点实例、所在可用区云盘支持情况等因素影响。

    resourceGroupId

    云盘所属资源组。默认为""

    regionId

    云盘所在地域,与集群地域相同。

    fstype

    云盘使用的文件系统。可取值:ext4(默认)、xfs

    mkfsOptions

    云盘格式化参数,如mkfsOptions: "-O project,quota"

    diskTags

    云盘标签。例如diskTags: "a:b,b:c",也可使用diskTags/a: b的格式指定。CSI组件需为v1.30.3及以上版本。

    encrypted

    云盘是否加密。默认为false,不加密。

    performanceLevel

    ESSD云盘性能级别,取值PL0PL1(默认)、PL2PL3

    通过云盒使用时需设置为PL0

    volumeExpandAutoSnapshot【废弃】

    CSI 1.31.4版本起已废弃。

    provisionedIops

    使用ESSD AutoPL云盘时,配置云盘的预配置性能(IOPS)

    burstingEnabled

    使用ESSD AutoPL云盘时,是否开启Burst(性能突发)。默认为false,不开启。

    multiAttach

    是否开启云盘多重挂载功能。默认为false,不开启。

    volumeBindingMode

    云盘的绑定模式。可取值:

    • Immediate(默认):先创建云盘再创建Pod。

    • WaitForFirstConsumer:延迟绑定,即先调度Pod,再根据Pod所在可用区创建云盘。

      多可用区场景下,建议使用WaitForFirstConsumer,以优化因云盘和ECS节点不在同一可用区导致的挂载失败。

      如需调度到虚拟节点,采用特定调度方式或添加了特定Annotation时,不支持使用WaitForFirstConsumer类型的StorageClass,请参见挂载云盘的Pod调度至虚拟节点时,PVC一直处于Pending状态怎么办?

    reclaimPolicy

    云盘回收策略。

    • Delete(默认):删除PVC时,PV和云盘会一起删除。

    • Retain:删除PVC时,PV和云盘数据不会被删除,需手动删除。

      对数据安全性要求高时,推荐使用Retain,以免误删数据。

    allowVolumeExpansion

    配置为true时,允许在线扩容云盘存储卷

    allowedTopologies

    限制云盘只能在特定的拓扑域中创建。

    • key:拓扑域标签。支持以下取值:

      • topology.diskplugin.csi.alibabacloud.com/zone:阿里云 CSI 插件提供的专用拓扑 key

      • alibabacloud.com/ecs-instance-id:使用弹性临时盘时,支持指定节点。

    • values:包含可用区或节点 ID 的列表。

  2. 创建StorageClass。

    kubectl create -f disk-sc.yaml
  3. 查看StorageClass。

    kubectl get sc

    输出中,StorageClass已创建,处于WaitForFirstConsumer绑定模式。

    NAME                                    PROVISIONER                       RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    alicloud-disk-wait-for-first-consumer   diskplugin.csi.alibabacloud.com   Retain          WaitForFirstConsumer   true                   10s

控制台

  1. ACK集群列表页面,单击目标集群名称,在集群详情页左侧导航栏,选择存储 > 存储类

  2. 单击创建,选择存储卷类型为云盘,完成参数配置,然后单击创建

    参数

    描述

    参数

    • 默认参数:type

      云盘类型,必填参数。可取值:

      支持任意组合,例如type: cloud_ssd,cloud_essd,cloud_auto。系统将按配置顺序依次尝试创建。最终创建的云盘类型受节点实例、所在可用区云盘支持情况等因素影响。

    • 展开查看可选参数

      • resourceGroupId云盘所属资源组。默认为""

      • regionId云盘所在地域,与集群地域相同。

      • fstype云盘使用的文件系统。可取值:ext4(默认)、xfs

      • mkfsOptions云盘格式化参数,如mkfsOptions: "-O project,quota"

      • diskTags云盘标签。例如diskTags: "a:b,b:c",也可使用diskTags/a: b的格式指定。CSI组件需为v1.30.3及以上版本。

      • encrypted云盘是否加密。默认为false,不加密。

      • performanceLevelESSD云盘性能级别,取值PL0PL1(默认)、PL2PL3

        通过云盒使用时需设置为PL0
      • provisionedIops使用ESSD AutoPL云盘时,配置云盘的预配置性能(IOPS)

      • burstingEnabled使用ESSD AutoPL云盘时,是否开启Burst(性能突发)。默认为false,不开启。

      • multiAttach是否开启云盘多重挂载功能。默认为false,不开启。

    回收策略

    云盘回收策略。

    • Delete(默认):删除PVC时,PV和云盘会一起删除。

    • Retain:删除PVC时,PV和云盘数据不会被删除,需手动删除。

      对数据安全性要求高时,推荐使用Retain,以免误删数据。

    绑定模式

    云盘的绑定模式。可取值:

    • Immediate(默认):先创建云盘再创建Pod。

    • WaitForFirstConsumer:延迟绑定,即先调度Pod,再根据Pod所在可用区创建云盘。

      多可用区场景下,建议使用WaitForFirstConsumer,以优化因云盘和ECS节点不在同一可用区导致的挂载失败。

      如需调度到虚拟节点,采用特定调度方式或添加了特定Annotation时,不支持使用WaitForFirstConsumer类型的StorageClass,请参见挂载云盘的Pod调度至虚拟节点时,PVC一直处于Pending状态怎么办?

    创建完成后,可在存储类页面查看新创建的StorageClass。

步骤二:创建应用并挂载云盘

StatefulSet为例介绍如何挂载云盘存储卷。

重要

云盘为非共享存储,未开启多重挂载时一次只能挂载一个Pod。在多副本 Deployment 中共享PVC会导致新Pod无法挂载仍被旧Pod占用的云盘而启动失败。推荐使用StatefulSet或单独为Pod挂载云盘。

如仍需在Deployment中使用云盘,建议使用云盘作为临时存储卷。如需启用多重挂载,请参见使用NVMe云盘多重挂载及Reservation

  1. 创建statefulset.yaml

    以下示例创建了包含2PodStatefulSet,使用 volumeClaimTemplates 来为每个 Pod 自动创建并绑定独立的持久化存储。
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      serviceName: "nginx"
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          # 建议配置以下securityContext以优化挂载性能
          securityContext:
            fsGroup: 1000
            fsGroupChangePolicy: "OnRootMismatch"
          containers:
          - name: nginx
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            ports:
            - containerPort: 80
            volumeMounts:
            # 将数据卷挂载到容器的/data目录
            # name需与volumeClaimTemplates中定义的metadata.name一致
            - name: pvc-disk
              mountPath: /data
      # 定义PVC模板
      volumeClaimTemplates:
      - metadata:
          name: pvc-disk
        spec:
          # 访问模式
          accessModes: [ "ReadWriteOnce" ]
          # 关联此前创建的StorageClass
          storageClassName: "alicloud-disk-wait-for-first-consumer"
          resources:
            requests:
              # 申请的存储容量,即云盘大小
              storage: 20Gi
    重要

    在 Pod 中配置 securityContext.fsgroup 会导致kubelet在挂载卷时递归修改文件权限(chmod/chown)。若文件数量庞大,将显著延长挂载时间。

    对于1.20及以上版本的集群,建议将fsGroupChangePolicy配置为OnRootMismatch,仅在首次挂载且卷根目录权限不匹配时才执行递归的权限变更,以优化挂载性能。若性能仍不满足要求或需更精细的权限控制,建议使用initContainer在主应用容器启动前自行执行权限调整命令。

  2. 创建StatefulSet。

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

    kubectl get pod -l app=nginx
  4. 查看挂载路径,确认已挂载云盘。

    本示例Pod名称为web-1,请按实际替换。
    kubectl exec web-1 -- df -h /data

    预期输出:

    Filesystem      Size  Used Avail Use% Mounted on
    /dev/vdb         20G   24K   20G   1% /data

步骤三:模拟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

应用于生产环境

  • 高可用性

    • 云盘选型

      需综合评估其性能计费以及节点的可用区和实例规格族,确保Pod能被调度至兼容的节点。

      选择云盘类型时,SSD云盘、高效云盘已逐步停止售卖。建议选用ESSD PL0云盘或ESSD Entry云盘替换高效云盘,选用ESSD AutoPL云盘替换SSD云盘。

    • 构建跨可用区容灾方案

      • 应用层容灾: 对于数据库等关键业务,在多个可用区部署应用实例,并通过应用自身的数据同步机制实现高可用。

      • 存储层容灾:选用支持多可用区容灾的云盘类型,将数据实时同步写入同一地域的不同可用区,实现跨可用区的故障恢复,请参见使用ESSD同城冗余云盘

  • 数据安全与备份

    • 防止意外删除数据:

      为防止数据丢失,建议将StorageClassreclaimPolicy设置为Retain,PVC删除后,后端的云盘不会被删除,便于数据恢复。

    • 常态化备份

      动态卷简化了资源供给,但不能替代数据备份。对于核心业务,使用备份中心进行数据的备份和恢复。

    • 启用静态加密:对于数据敏感型应用,在StorageClass中配置encrypted: "true"加密云盘

  • 性能与成本优化

    • 启用并行挂载

      默认情况下,单个节点的云盘操作是串行的。可使用云盘并行挂载,加速Pod启动。

    • 启用存储卷在线扩容

      StorageClass中设置allowVolumeExpansion: true,以便在未来存储需求增长时,在线扩容云盘存储卷

    • 配置存储监控与告警

      基于容器存储监控配置告警,及时发现存储卷异常或性能瓶颈。

计费说明

通过StorageClass动态创建的云盘采用按量付费,请参见块存储计费块存储价格

常见问题

挂载云盘的Pod调度至虚拟节点时,PVC一直处于Pending状态怎么办?

可能是使用了不支持虚拟节点调度场景的StorageClass。当通过特定标签(Label)或注解(Annotation)将Pod调度到虚拟节点时,不支持使用volumeBindingMode: WaitForFirstConsumer模式的StorageClass。

  • 原因:
    WaitForFirstConsumer模式依赖kube-schedulerPod选择一个物理节点,从而确定其可用区,然后再根据可用区创建云盘。但虚拟节点的部分调度机制不遵循此流程,导致CSI无法获取可用区信息,继而无法创建PV,PVC便处于Pending状态。

  • 如遇问题,请检查Pod或其命名空间中是否包含以下任意一种配置:

    • Label:

      • alibabacloud.com/eci: "true":调度至ECI Pod。

      • alibabacloud.com/acs: "true":调度至ACS Pod。

    • 指定节点:

      • 通过spec.nodeName直接指定一个节点(节点名称前缀为virtual-kubelet)。

    • Annotation:

      • k8s.aliyun.com/eci-vswitch:指定ECI Pod的交换机。

      • k8s.aliyun.com/eci-fail-strategy: "fail-fast":ECI Pod的故障处理策略为快速失败。

如何为单个Pod或单副本Deployment挂载云盘存储卷?

对于不需要多副本伸缩和稳定网络标识的简单应用,可手动创建PVC并将其挂载到PodDeployment,以实现持久化存储。

链路为:选择StorageClass -> 创建PVC -> 在应用中挂载PVC。

  1. 准备StorageClass

  2. 创建PVC,申请存储资源。

    kubectl

    1. 创建disk-pvc.yaml

      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: disk-pvc
      spec:
        # 访问模式
        accessModes:
        - ReadWriteOnce
        volumeMode: Filesystem
        resources:
          requests:
            # 申请的存储容量,即云盘大小
            storage: 20Gi
        # 关联此前创建的StorageClass
        storageClassName: alicloud-disk-topology-alltype 

      相关参数说明如下:

      参数

      说明

      accessModes

      存储卷的访问模式。可取值:ReadWriteOnceReadOnlyManyReadWriteMany。具体取决于StorageClass中的multiAttach配置以及PVC中的volumeMode配置。

      multiAttach表示是否开启云盘多重挂载。默认为false,不开启。
      • multiAttachfalsevolumeMode配置为任意值时,访问模式仅支持ReadWriteOnce

      • multiAttachtruevolumeModeFilesystem时,访问模式仅支持ReadWriteOnceReadOnlyMany

      • multiAttachtruevolumeModeBlock时,三种访问模式均支持。

      重要

      此场景下,访问模式通常为ReadWriteOnce (RWO) ,即同一时间只能被一个Pod挂载。因此Deployment副本数不能大于1。如尝试扩容,新Pod会因无法挂载已被占用的云盘而一直处于Pending状态。

      volumeMode

      存储卷的模式。可取值:

      • Filesystem(默认):存储卷会被格式化并挂载为目录。

      • Block:存储卷以未格式化的块设备形式直接提供给 Pod。

      storage

      申请的存储容量大小。不同云盘类型的容量范围不同。请确保storage取值符合其引用的 StorageClass 所对应的云盘类型的容量限制,以免云盘创建失败。

      storageClassName

      待绑定的StorageClass。

    2. 创建PVC。

      kubectl create -f disk-pvc.yaml
    3. 查看PVC。

      kubectl get pvc

      输出中,由于StorageClass使用WaitForFirstConsumer模式,此时PVC处于Pending状态,直到第一个使用它的 Pod 被成功调度。

      NAME       STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS                            VOLUMEATTRIBUTESCLASS   AGE
      disk-pvc   Pending                                      alicloud-disk-wait-for-first-consumer   <unset>                 14s

    控制台

    1. 在集群管理页左侧导航栏,选择存储 > 存储声明

    2. 存储声明页面,单击创建,选择存储声明类型云盘,按照页面提示完成参数的配置。

      参数

      描述

      分配模式

      选择使用存储类动态创建

      已有存储类

      默认创建或手动创建的StorageClass。

      总量

      申请的存储容量大小。不同云盘类型的容量范围不同。请确保storage取值符合其引用的 StorageClass 所对应的云盘类型的容量限制,以免云盘创建失败。

      访问模式

      仅支持ReadWriteOnce,表示卷只能被一个Pod以读写方式挂载。

      创建完成后,可在存储声明页面查看新创建的PVC。

  3. 在应用中挂载PVC。

    1. 创建disk-deployment.yaml

      展开查看示例YAML

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: single-pod-app
      spec:
        # 确保副本数为1
        replicas: 1
        selector:
          matchLabels:
            app: nginx-single
        template:
          metadata:
            labels:
              app: nginx-single
          spec:
            containers:
            - name: nginx
              image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
              ports:
              - containerPort: 80
              # 在容器内定义挂载点
              volumeMounts:
              - name: my-persistent-storage  # 必须与下面volumes中定义的name一致
                mountPath: /data  # 挂载到容器内的/data目录
            # 在Pod级别声明并引用PVC
            volumes:
            - name: my-persistent-storage # 供容器引用的卷
              persistentVolumeClaim:
                claimName: disk-pvc # 引用此前创建的PVC
    2. 部署Deployment。

      kubectl create -f disk-deployment.yaml
  4. 验证挂载结果。

    1. 确认Pod已经成功运行。

      kubectl get pods -l app=nginx-single
    2. 进入Pod内部,检查/data目录是否已成功挂载云盘。

      # 获取Pod名称
      POD_NAME=$(kubectl get pods -l app=nginx-single -o jsonpath='{.items[0].metadata.name}')
      
      # 执行df -h命令
      kubectl exec $POD_NAME -- df -h /data

      输出如下,表明20GiB的云盘已成功挂载。

      Filesystem      Size  Used Avail Use% Mounted on
      /dev/vdb         20G   24K   20G   1% /data

相关文档