为多个云盘存储卷创建组快照

云盘存储快照可以帮助您实现应用数据的备份和恢复。在多云盘场景下,通过VolumeSnapshot资源为云盘分别单独创建快照,难以保证快照时刻一致。通过组快照,您可以统一管理和备份多个云盘,减少因异步快照导致的数据不一致风险。

前提条件

  • 已创建ACK托管集群,且集群为1.28及以上版本。

  • 集群默认已安装CSI组件,确保CSI组件为1.31.4及以上版本。如需升级请参见升级csi-plugincsi-provisioner

    说明

    如果您集群中使用Flexvolume组件,由于Flexvolume已废弃,请在迁移FlexvolumeCSI完成后再使用组快照。您可以在运维管理 > 组件管理,在存储页签下确认存储组件类型。

  • 已开通快照,开通快照不收费,创建快照后才开始收费。

计费说明

组快照功能基于ECS快照一致性组实现,使用ECS快照一致性组本身不收费,但会收取组内各个快照的容量费用。更多信息,请参见快照计费

使用限制

组快照的使用限制与ECS快照一致性组一致,请参见创建快照一致性组

使用说明

您可以通过定义以下自定义资源(CRD),声明五种与组快照相关的Kubernetes资源类型。

CRD

描述

VolumeGroupSnapshotClass

定义VolumeGroupSnapshot使用的删除策略等参数。

VolumeGroupSnapshot

声明一个存储卷组快照实例,指定需要备份的云盘目标。

VolumeGroupSnapshotContent

记录实际创建的ECS快照一致性组实例信息。

VolumeSnapshot

声明单个存储卷快照实例。VolumeGroupSnapshot创建后,将自动为需要备份的云盘生产时刻一致的一组VolumeSnapshot。

VolumeSnapshotContent

记录实际创建的单个ECS快照实例信息。

VolumeGroupSnapshotClass、VolumeGroupSnapshotVolumeGroupSnapshotContent之间的关系类似于StorageClass、PersistentVolumeClaimPersistentVolume。当VolumeGroupSnapshot资源创建成功后,CSI组件将会创建出对应的ECS快照一致性组,自动在集群中生成一组VolumeSnapshot及对应的VolumeSnapshotContent。若某个云盘出现异常,可通过其对应的VolumeSnapshot完成恢复。

使用示例

1、开启组快照相关的特性门控

创建组快照前,您需要先开启EnableVolumeGroupSnapshots特性门控。

  1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,单击组件管理

  3. 组件管理页面,找到csi-provisioner组件,单击对应的配置

  4. csi-provisioner 参数配置页面,设置FeatureGate参数为EnableVolumeGroupSnapshots=true,然后单击确认

    若之前已经开启过其他特性门控,则参数填写格式为xxxxxx=true,yyyyyy=false,EnableVolumeGroupSnapshots=true

2、创建MySQL示例应用

  1. 使用以下YAML示例,创建多副本的有状态应用mysql.yaml文件。

    展开查看有状态应用mysql.yaml文件

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mysql
    spec:
      selector:
        matchLabels:
          app: mysql
      serviceName: "mysql"
      replicas: 2
      template:
        metadata:
          labels:
            app: mysql
        spec:
          containers:
          - name: mysql
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/mysql:8.0.30-8.6
            env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - name: data
              # MySQL存放数据的位置
              mountPath: /var/lib/mysql
              subPath: mysql
      volumeClaimTemplates:
      - metadata:
          name: data
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "alicloud-disk-essd"
          resources:
            requests:
              storage: 20Gi
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: mysql-pass
    type: Opaque
    data:   # 以下为登录MySQL示例数据库的用户名和密码(BASE64编码形式),也可自定义。
      password: MTIzNDU2   
      username: cm9vdA==  
    
  2. 部署有状态应用MySQL。

    kubectl apply -f mysql.yaml
  3. 为两个不同副本分别写入数据。

    1. 登录mysql-0副本,并连接数据库。

      kubectl exec -it mysql-0 -- bash  # 登录Pod。
      mysql -uroot -p123456  # 连接数据库。
    2. 在数据库中执行以下命令,写入数据。

      create database test;
      use test;
      create table scores( name VARCHAR(50) NOT NULL, score INT AUTO_INCREMENT PRIMARY KEY );
      insert into scores(name,score) values("Amy",95);
      select * from scores;

      最后一步预期输出:

      +------+-------+
      | name | score |
      +------+-------+
      | Amy  |    95 |
      +------+-------+
    3. 使用以上方法,为mysql-1副本写入数据。

3、为MySQL应用创建组快照

  1. 创建组快照类VolumeGroupSnapshotClass。

    此时集群中应已默认存在组快照类alibabacloud-disk-group-snapshot,您也可以使用以下group-snapshot-class-demo.yaml示例,创建自定义组快照类。

    apiVersion: groupsnapshot.storage.k8s.io/v1alpha1
    kind: VolumeGroupSnapshotClass
    metadata:
      name: group-snapshot-class-demo
    deletionPolicy: Delete
    driver: diskplugin.csi.alibabacloud.com

    deletionPolicy参数取值说明如下:

    • Delete:删除VolumeGroupSnapshot时,VolumeGroupSnapshotContent以及关联的组快照也会一起被删除。

    • Retain:删除VolumeGroupSnapshot时,VolumeGroupSnapshotContent以及关联的组快照不会被删除。

    说明

    当前ECS快照一致性组暂不支持设置过期时间,创建的组快照实例需要手动删除。

  2. 部署创建组快照类VolumeGroupSnapshotClass。

    kubectl apply -f group-snapshot-class-demo.yaml
  3. 使用以下group-snapshot-demo.yaml示例,为上述MySQL应用创建出的两个云盘存储卷创建组快照。

    apiVersion: groupsnapshot.storage.k8s.io/v1alpha1
    kind: VolumeGroupSnapshot
    metadata:
      name: group-snapshot-demo
      namespace: default
    spec:
      source:
        selector:
          matchLabels:
            app: mysql
      volumeGroupSnapshotClassName:
        group-snapshot-class-demo

    source.selector:labelSelector用于选择需要备份的PVC的标签。

    volumeClaimTemplates创建的PVC会自带与应用一致的标签。若您通过其他方式创建PVC,可手动打上统一的标签。

  4. 部署组快照。

    kubectl apply -f group-snapshot-demo.yaml

4、验证组快照是否创建成功

  1. 查询已创建的VolumeGroupSnapshot资源,并等待其创建成功。

    kubectl get vgs group-snapshot-demo -w

    预期READYTOUSEfalse变为true

  2. 查询实际备份的PVC列表,以及为每个PVC自动创建的VolumeSnapshot列表。

    kubectl describe vgs group-snapshot-demo

    预期输出包含类似以下内容:

    Status:
      Bound Volume Group Snapshot Content Name: groupsnapcontent-adcef6ef-811a-4e9d-ba51-3927caxxxxxx
      Creation Time: 2024-11-27T06:02:56Z
      Pvc Volume Snapshot Ref List:
        Persistent Volume Claim Ref:
          Name: disk-mysql-0
        Volume Snapshot Ref:
          Name: snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7xxxxxx-2024-11-27-6.4.7
        Persistent Volume Claim Ref:
          Name: disk-mysql-1
        Volume Snapshot Ref:
          Name: snapshot-37a2fbf634d68cd2103f261313c2ed781fbd2bd52b5a0d0e0c0ef7c339xxxxxx-2024-11-27-6.4.9

    参数

    说明

    Bound Volume Group Snapshot Content Name

    与该VolumeGroupSnapshot绑定的VolumeGroupSnapshotContent资源。

    Pvc Volume Snapshot Ref List

    PVC关联的VolumeSnapshot,包含以下参数:

    • Persistent Volume Claim Ref:备份的云盘存储卷的PVC名称。

    • Volume Snapshot Ref:自动创建的与PVC对应VolumeSnapshot资源。

  3. 查询Volumesnapshot资源。

    kubectl get volumesnapshot \ 

    预期输出:

    snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7xxxxxx-2024-11-27-6.4.7 \
    snapshot-37a2fbf634d68cd2103f261313c2ed781fbd2bd52b5a0d0e0c0ef7c339xxxxxx-2024-11-27-6.4.9

    预期ReadyToUse均为true

  4. 查询实际创建的ECS快照一致性组实例信息。

    kubectl describe vgsc groupsnapcontent-adcef6ef-811a-4e9d-ba51-3927caxxxxxx

    预期输出包含类似以下内容:

      Volume Group Snapshot Handle:  ssg-2zeg72d1qym6vnxxxxxx

    前往ECS管理控制台,在左侧导航栏选择存储与快照 > 快照,在快照一致性组页签下,通过以上输出的快照一致性组ID搜索ssg-2zeg72d1qym6vnxxxxxx,预期看到对应的组快照实例信息。

5、使用快照恢复MySQL中的云盘存储卷

您可以手动恢复单个指定的云盘存储卷,也可以通过脚本批量恢复组快照中所有的云盘存储卷

手动恢复单个指定的云盘存储卷

下文示例以恢复上述MySQL应用中的disk-mysql-0对应的云盘存储卷为例,介绍如何恢复指定的云盘存储卷。

  1. 使用以下disk-mysql-0-copy.yaml示例,创建恢复的云盘存储卷。CSI将为其创建新的云盘,且云盘内数据与disk-mysql-0一致。

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: disk-mysql-0-copy
    spec:
      volumeMode: Filesystem
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi 
      storageClassName: "alicloud-disk-essd"
      dataSource:
        # disk-mysql-0 PVC对应的VolumeSnapshot资源。
        name: snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7xxxxxx-2024-11-27-6.4.7
        kind: VolumeSnapshot
        apiGroup: snapshot.storage.k8s.io
  2. 创建恢复的云盘存储卷。

    kubectl apply -f disk-mysql-0-copy.yaml
  3. 查询已创建的PVC。

    kubectl get pvc disk-mysql-0-copy

    预期输出:

    disk-mysql-0-copy   Bound    d-2ze0iwwqg0s6b0xxxxxx             20Gi       RWO            alicloud-disk-essd               <unset>                 69s

    前往ECS管理控制台,在左侧导航栏选择存储与快照 > 块存储,在云盘页签下,通过以上输出的云盘ID搜索d-2ze0iwwqg0s6b0xxxxxx,并单击该ID查询其详情,可见其由快照创建。

通过脚本批量恢复组快照中所有的云盘存储卷

下文示例使用组快照批量重建云盘PVC,由上述MySQL应用挂载。

  1. MySQL应用副本数缩至0。

    kubectl scale sts mysql --replicas=0
  2. 删除已有的两个云盘存储卷。

    kubectl delete pvc data-mysql-0 data-mysql-1
  3. 使用以下generate_pvc.sh脚本,生成部署系列数据源为快照的PVC YAML文件。

    1. 使用以下generate_pvc.sh脚本,需提前安装jq命令行工具。

      展开查看如何安装jq

      • CentOS

        yum install jq 
      • Ubuntu

        apt-get install jq

      展开查看generate_pvc.sh脚本

      #!/bin/bash
      
      # 输入参数。
      NAMESPACE=$1
      VGS_NAME=$2
      STORAGE_CLASS_NAME=$3
      CAPACITY=$4
      KUBECONFIG_PATH=$5
      OUTPUT_FILE=$6
      
      # 获取 VolumeGroupSnapshot 的详细信息。
      VGS_INFO=$(kubectl --kubeconfig=${KUBECONFIG_PATH} -n ${NAMESPACE} get vgs ${VGS_NAME} -o json)
      
      # 检查 .status.pvcVolumeSnapshotRefList 是否存在。
      if ! echo ${VGS_INFO} | jq -e '.status.pvcVolumeSnapshotRefList' &>/dev/null; then
        echo "Error: .status.pvcVolumeSnapshotRefList not found in VolumeGroupSnapshot."
        exit 1
      fi
      
      # 解析 .status.pvcVolumeSnapshotRefList。
      PVCS=($(echo ${VGS_INFO} | jq -r '.status.pvcVolumeSnapshotRefList[].persistentVolumeClaimRef.name'))
      SNAPSHOTS=($(echo ${VGS_INFO} | jq -r '.status.pvcVolumeSnapshotRefList[].volumeSnapshotRef.name'))
      
      # 清空输出文件。
      > ${OUTPUT_FILE}
      
      # 生成 N 个 PVC 的 YAML 文件。
      for i in "${!PVCS[@]}"; do
        PVC_NAME=${PVCS[$i]}
        SNAPSHOT_NAME=${SNAPSHOTS[$i]}
      
        cat <<EOF >> ${OUTPUT_FILE}
      ---
      kind: PersistentVolumeClaim
      apiVersion: v1
      metadata:
        name: ${PVC_NAME}
      spec:
        volumeMode: Filesystem
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: ${CAPACITY}
        storageClassName: "${STORAGE_CLASS_NAME}"
        dataSource:
          name: ${SNAPSHOT_NAME}
          kind: VolumeSnapshot
          apiGroup: snapshot.storage.k8s.io
      EOF
      done
      
      echo "PVC YAML files have been written to ${OUTPUT_FILE}"

      generate_pvc.sh脚本中输入参数的变量说明如下:

      入参

      说明

      示例值

      1

      VolumeGroupSnapshot资源所在命名空间。

      default

      2

      VolumeGroupSnapshot资源名称。

      group-snapshot-demo

      3

      存储类名称。

      alicloud-disk-essd

      4

      云盘的容量。

      20Gi

      5

      KubeConfig文件位置。

      .kube/config (默认位置)

      6

      生成的PVC YAML文件存放的位置。

      ./output.yaml

    2. 生成数据源为快照的PVC YAML文件。

      bash generate_pvc.sh default group-snapshot-demo alicloud-disk-essd 20Gi .kube/config ./output.yaml

      生成的output.yaml示例如下,可根据实际情况调整,然后在集群中部署。

      ---
      kind: PersistentVolumeClaim
      apiVersion: v1
      metadata:
        name: disk-mysql-0
      spec:
        volumeMode: Filesystem
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 20Gi
        storageClassName: "alicloud-disk-essd"
        dataSource:
          name: snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7adb850-2024-11-27-6.4.7
          kind: VolumeSnapshot
          apiGroup: snapshot.storage.k8s.io
      ---
      kind: PersistentVolumeClaim
      apiVersion: v1
      metadata:
        name: disk-mysql-1
      spec:
        volumeMode: Filesystem
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 20Gi
        storageClassName: "alicloud-disk-essd"
        dataSource:
          name: snapshot-37a2fbf634d68cd2103f261313c2ed781fbd2bd52b5a0d0e0c0ef7c3396fea1c-2024-11-27-6.4.9
          kind: VolumeSnapshot
          apiGroup: snapshot.storage.k8s.io
    3. 在集群中部署生成的output.yaml文件,批量重建云盘PVC。

      kubectl apply -f output.yaml
  4. 恢复MySQL应用的副本数。

    kubectl scale sts mysql --replicas=2
  5. 应用重新启动后,确认数据已经恢复。

    kubectl exec -it mysql-0 -- bash   # 登录Pod。
    mysql -uroot -p123456              # 在Pod中继续执行。
    use test;                          # 在数据库中执行。
    select * from scores;

    最后一步预期输出:

    +------+-------+
    | name | score |
    +------+-------+
    | Amy  |    95 |
    +------+-------+

相关文档

如需为单个云盘创建快照,请参见为单个云盘存储卷创建快照