跨可用区迁移使用云盘存储卷的有状态应用

storage-operator组件提供了云盘类型有状态应用(StatefulSet)跨可用区迁移和多地域打散的功能,实现了跨可用区迁移的自动化。迁移过程出现异常时,storage-operator组件可以通过预检查和回滚机制在原可用区恢复应用,保证业务的可用性。本文介绍如何实现云盘类型的有状态应用跨可用区迁移。

适用场景

  • 当遇到规划变更、应用规模扩大从而需要在多可用区部署,或当前可用区资源不足时,您都需要将已部署的有状态应用迁移至其他的可用区。

  • NAS、OSS存储底层支持跨可用区、多挂载使用。但云盘本身无多可用区漂移的能力,无法复用存储声明和存储卷,此时,需要将使用云盘存储卷的有状态应用迁移至新的可用区。

  • 能接受业务中断的应用。对于多副本的有状态应用,为保证数据的一致性,在迁移前会缩容至0副本,云盘迁移完成后再一次性恢复至原副本数,而非滚动迁移。

    重要

    有状态应用的跨可用区迁移过程中会产生业务的中断,中断时长与副本数量、容器启动速度、所使用云盘容量等因素相关。

实现原理及迁移流程

云盘实现应用的跨可用区迁移,依赖云盘快照功能,并且支持设定新建的快照保留时间。关于云盘快照的更多信息,请参见快照介绍。关于快照计费请参见快照计费

storage-operator组件提供的云盘类型有状态应用迁移流程如下。

  1. 相关预检查,例如,待迁移应用运行是否正常、是否有需要迁移的云盘等。若检查失败,则不会进行迁移。

  2. 将云盘类型有状态应用缩容至0副本,此时应用处于暂停状态。

  3. 为待迁移的有状态应用挂载的云盘制作快照,快照支持跨可用区。

  4. 确认快照可用后,使用快照在目标可用区制作新云盘,新云盘与原云盘的数据一致。

  5. 重建同名的存储声明及其对应的新存储卷,绑定新云盘。

  6. 云盘类型有状态应用副本恢复至原副本数量,并自动关联重建的存储声明,实际挂载新云盘。

    重要

    预检查完成并开始迁移后,每个步骤均对应了不同的失败回滚策略。为确保回滚后的应用能挂载原云盘,避免数据丢失,请确认迁移后的有状态应用运行正常后,再删除云盘。

  7. (可选)确认有状态应用运行正常后,删除原存储卷和相应的云盘。关于云盘计费,请参见块存储计费

注意事项

  • 待迁移的有状态应用使用的所有存储均为ESSD云盘。

    为了提升快照制作时间,本功能在迁移时选用极速快照,具体操作请参见快照极速可用能力。目前极速快照仅支持ESSD云盘,若您的应用使用非ESSD类型云盘,可通过以下方式处理。

  • 目标可用区支持ESSD云盘,且集群中已有在目标可用区支持ESSD云盘的节点可供调度。

前提条件

  • 集群的版本为1.20及以上,并且使用CSI存储插件。

    如需升级集群,请参见手动升级集群

  • 集群中已安装storage-operator组件,且版本不低于v1.26.2-1de13b6-aliyun。更多信息,请参见管理storage-operator组件

  • 集群中已安装csi-plugincsi-provisioner组件,且安装的csi-provisioner为非托管版。

    说明

    如果当前安装的是csi-provisioner托管版组件,卸载托管版后可以重新安装非托管版。切换CSI组件后,请执行kubectl delete pod -n kube-system <storage-controller-pod-name>重启storage controller。

  • 如果您的集群是ACK专有集群,需确保集群的WorkerRoleMasterRole具备ModifyDiskSpec权限。具体操作,请参见创建自定义权限策略

    ACK托管集群无需进行此授权。

    展开查看权限策略

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ecs:CreateSnapshot",
                    "ecs:DescribeSnapshot",
                    "ecs:DeleteSnapshot",
                    "ecs:ModifyDiskSpec",
                    "ecs:DescribeTaskAttribute"
                ],
                "Resource": "*"
            }
        ]
    }

使用方式

  1. 修改集群中ConfigMap的配置。

    kubectl patch configmap/storage-operator \
      -n kube-system \
      --type merge \
      -p '{"data":{"storage-controller":"{\"imageRep\":\"acs/storage-controller\",\"imageTag\":\"\",\"install\":\"true\",\"template\":\"/acs/templates/storage-controller/install.yaml\",\"type\":\"deployment\"}"}}'
  2. 在集群中创建有状态应用迁移任务。

    cat <<EOF | kubectl apply -f -
    apiVersion: storage.alibabacloud.com/v1beta1
    kind: ContainerStorageOperator
    metadata:
      name: default
    spec:
      operationType: APPMIGRATE
      operationParams:
        stsName: web
        stsNamespace: default
        stsType: kube
        targetZone: cn-beijing-h,cn-beijing-j
        checkWaitingMinutes: "1"
        healthDurationMinutes: "1"
        snapshotRetentionDays: "2"
        retainSourcePV: "true"
    EOF

    参数

    是否必选

    说明

    operationType

    必选

    取值为APPMIGRATE,表明当前的操作是有状态应用迁移。

    stsName

    必选

    有状态应用名称,当前仅支持填写单个有状态应用。

    说明

    部署多个有状态应用的迁移任务时,组件将以部署时间顺序依次迁移。

    stsNamespace

    必选

    有状态应用所在命名空间。

    targetZone

    必选

    迁移的目标可用区列表。当存在多个目标可用区时,可用区之间用英文半角逗号(,)隔开。例如cn-beijing-h,cn-beijing-j

    • 当应用挂载的某个云盘已在列表中时,应用将不进行迁移。

    • 当目标可用区大于1时,剩余云盘将按列表中可用区的排列顺序依次迁移至各个目标可用区。

    stsType

    可选

    指定的有状态应用的类型,默认为kube。取值:

    • kube:原生StatefulSet。

    • kruise:OpenKruise组件提供的Advanced StatefulSet。

    checkWaitingMinutes

    可选

    有状态应用在迁移后的可用区启动时,其状态检查的轮询间隔时间,单位为分钟。

    默认为"1",即每分钟检查一次,直至可用副本数与预期一致,或多次检查失败重试后回滚,回迁至原可用区。

    重要

    对于副本数较多、镜像拉取时间长、业务本身启动耗时较长的应用,需要适当增加轮询间隔时间,避免重试次数过多后应用回滚。

    healthDurationMinutes

    可选

    二次检查的间隔时间,单位为分钟。二次检查即当有状态应用迁移完成,可用副本数与预期一致后,等待指定时间进行二次检查,以增强数据敏感业务的迁移可靠性。

    默认为"0",即不进行二次检查。

    snapshotRetentionDays

    可选

    迁移过程中,新建极速快照的保留时间,单位为天。取值:

    • "1":默认值,保留一天。

    • "-1":将永久保留极速快照。

    retainSourcePV

    可选

    是否保留原云盘及其在集群中对应的存储卷资源。取值:

    • "false":默认值,不保留。

    • "true":保留,您可以登录ECS管理控制台找到原云盘实例,且集群内对应的存储卷资源也不会被删除,存储卷处于Released状态。

使用示例

测试集群为ACK托管集群Pro,包含不同可用区的多个节点,示例如下:

  • 可用区B:cn-shanghai.192.168.5.245

  • 可用区G:cn-shanghai.192.168.2.214

  • 可用区M:cn-shanghai.192.168.3.236、cn-shanghai.192.168.3.237

节点可用区

步骤一:创建使用ESSD云盘的有状态应用

在集群中创建一个使用ESSD云盘的StatefulSet用于后续测试。如果已有相关测试资源,可跳过该步骤。

  1. 创建StatefulSet并挂载ESSD云盘。

    展开查看部署有状态应用Nginx的文件

    cat << EOF | kubectl apply -f -
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx
      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: www
                  mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
        - metadata:
            name: www
            labels:
              app: nginx
          spec:
            accessModes: [ "ReadWriteOnce" ]
            storageClassName: "alicloud-disk-essd"
            resources:
              requests:
                storage: 20Gi
    EOF
    
  2. 确认StatefulSetPod的部署情况。

    kubectl get pod -o wide -l app=nginx

    返回示例如下,根据Node字段确认2Pod均被调度到了可用区M。

    说明

    实际可用区部署情况由调度器决定。

    NAME       READY   STATUS    RESTARTS   AGE   IP              NODE                        NOMINATED NODE   READINESS GATES
    web-0      1/1     Running   0          2m    192.168.3.243   cn-shanghai.192.168.3.237   <none>           <none>
    web-1      1/1     Running   0          2m    192.168.3.246   cn-shanghai.192.168.3.236   <none>           <none>

步骤二:创建有状态应用迁移任务

示例1:跨可用区迁移

  1. 创建有状态应用迁移任务。

    以下迁移任务示例中,将StatefulSet2Pod全部迁移至cn-shanghai-b可用区。

    重要

    迁移前,请确认该节点有足够的资源,且可用区和节点规格均支持ESSD云盘。

    cat <<EOF | kubectl apply -f -
    apiVersion: storage.alibabacloud.com/v1beta1
    kind: ContainerStorageOperator
    metadata:
      name: migrate-to-b
    spec:
      operationType: APPMIGRATE
      operationParams:
        stsName: web
        stsNamespace: default
        stsType: kube
        targetZone: cn-shanghai-b     # 迁移到的目标可用区。
        healthDurationMinutes: "1"    # 迁移完成后隔1分钟确认应用运行正常。
        snapshotRetentionDays: "-1"   # 新建的快照长期保留,直至在控制台删除。
        retainSourcePV: "true"        # 保留原可用区的云盘和对应PV。
    EOF
  2. 查询迁移任务的状态。

    kubectl describe cso migrate-to-b | grep Status

    预期返回如下,如果返回SUCCESS表明迁移任务状态正常。

      Status:
        Status:   SUCCESS
    说明

    如果返回FAILED,则表明迁移任务失败,请参考常见问题处理。

  3. 查询迁移后StatefulSet2Pod的部署情况。

    kubectl get pod -o wide -l app=nginx

    返回示例如下,可以看到2Pod均已迁移到cn-shanghai.192.168.5.245节点,对应可用区B。

    NAME    READY   STATUS    RESTARTS   AGE     IP              NODE                        NOMINATED NODE   READINESS GATES
    web-0   1/1     Running   0          2m36s   192.168.5.250   cn-shanghai.192.168.5.245   <none>           <none>
    web-1   1/1     Running   0          2m14s   192.168.5.2     cn-shanghai.192.168.5.245   <none>           <none>
  4. ECS管理控制台确认迁移任务符合预期。

    • 快照页面,确认已新建2个快照,且快照永久保留。

    • 块存储页面,确认在迁移后的可用区B已新建2个云盘,迁移前的可用区M2个云盘未被删除(因为迁移任务中retainSourcePV的配置为true)。

示例2:多可用区打散

为提高应用的可用性,需要将Pod及云盘打散部署到不同的可用区中。

  1. 创建有状态应用迁移任务。

    以下迁移任务示例中,将StatefulSet2Pod打散部署到可用区B和可用区G。

    cat <<EOF | kubectl apply -f -
    apiVersion: storage.alibabacloud.com/v1beta1
    kind: ContainerStorageOperator
    metadata:
      name: migrate
    spec:
      operationType: APPMIGRATE
      operationParams:
        stsName: web
        stsNamespace: default
        stsType: kube
        targetZone: cn-shanghai-b,cn-shanghai-g   # 迁移到的目标可用区。配置多个时,会自动打散。
        healthDurationMinutes: "1"                # 迁移完成后隔1分钟确认应用运行正常。
        snapshotRetentionDays: "-1"               # 新建的快照长期保留,直至在控制台删除。
        retainSourcePV: "true"                    # 保留原可用区的云盘和对应PV。
    EOF
  2. 查询迁移任务的状态。

    kubectl describe cso migrate | grep Status

    预期返回如下,如果返回SUCCESS表明迁移任务状态正常。

      Status:
        Status:   SUCCESS
    说明

    如果返回FAILED,则表明迁移任务失败,请参考常见问题处理。

  3. 查询迁移后StatefulSet2Pod的部署情况。

    kubectl get pod -o wide -l app=nginx

    返回示例如下,可以看到2Pod已打散部署到cn-shanghai.192.168.5.245节点(可用区B)和cn-shanghai.192.168.2.214节点(可用区G)。

    NAME    READY   STATUS    RESTARTS   AGE     IP              NODE                        NOMINATED NODE   READINESS GATES
    web-0   1/1     Running   0          4m59s   192.168.2.215   cn-shanghai.192.168.2.214   <none>           <none>
    web-1   1/1     Running   0          4m38s   192.168.5.250   cn-shanghai.192.168.5.245   <none>           <none>
  4. ECS管理控制台确认迁移任务符合预期。

    • 快照页面,确认已新建2个快照,且快照永久保留。

    • 块存储页面,确认在迁移后的可用区B和可用区G已新建2个云盘,迁移前的可用区M2个云盘未被删除(因为迁移任务中retainSourcePV的配置为true)。

常见问题

若查询到的迁移任务状态为FAILED,可通过以下命令查询失败原因,根据原因调整后再重试。

kubectl describe cso <ContainerStorageOperator-name> | grep Message -A 1

返回示例如下,表示失败是由于找不到待迁移的存储声明,可能原因为应用并未挂载存储、应用已挂载在目标可用区,无法获取存储声明信息等,请根据实际情况修改后重试。

  Message:
    Consume: failed to get target pvc, err: no pvc mounted in statefulset or no pvc need to migrated web