在恢复应用时修改备份的集群资源

备份中心在备份集群资源时,默认将备份时刻的运行配置信息全量备份。但在恢复应用的过程中,运维人员往往需要手动修改某些字段或配置。例如,在混合云场景下,不同集群可能需要从不同的镜像仓库中拉取镜像,此时,您就需要在恢复应用时调整image字段的镜像地址。本文以备份并恢复一个有状态应用为例,介绍如何在恢复应用时修改对应的集群资源。

恢复应用时相关资源如何修改?

默认修改

无需任何配置,由组件在恢复时默认自动执行修改。常见修改的资源类型如下:

  • 删除资源UID等临时信息的通用修改。

  • 恢复存储卷时Flexvolume到CSI的变更。

  • API Version的自动升级。

  • 跨云场景的一些已知兼容修改。

常用修改

通过手动配置恢复任务中的相关字段,实现一些简单的修改。常见修改的资源类型如下:

  • 命名空间。

  • 存储类和镜像仓库地址的映射。

  • 兼容网络插件配置的Service和Ingress的注解(Annotations)复写等。

通用修改

通过Velero的Resource Modifier功能实现更多灵活的修改需求。通过编写配置项(ConfigMap)变更指定字段,该变更支持adddeletereplace等JSON Patch操作。

重要
  • 存储卷中的数据在备份恢复时默认使用动态存储卷,即由CSI根据使用的存储类来新建存储卷。因此,Resource Modifier功能在该场景下不支持修改存储卷。若您有修改存储卷配置的需求,可以考虑修改转换目标存储类。

  • Resource Modifier功能仅支持拥有集群RBAC管理员权限的用户使用,且不支持修改涉及安全敏感的资源组与字段。关于集群RBAC管理员授权,请参见为RAM用户或RAM角色授予RBAC权限

前提条件

  • 备份集群和恢复集群均已安装备份中心migrate-controller组件,且组件版本为1.8.1及以上。具体操作,请参见安装migrate-controller备份服务组件并配置权限

  • 已在备份集群中创建备份仓库。具体操作,请参见创建备份仓库。本文示例中的备份仓库基本信息如下:

    名称

    OSS Bucket名称

    OSS Bucket子目录

    OSS Bucket区

    可见范围

    vault

    cnfs-oss-test

    subpath

    cn-beijing

    <不影响查询>

  • 通过Resource Modifier功能修改资源,需确保恢复集群版本为1.20及以上,且使用CSI存储插件。

应用示例

本文以备份并恢复一个Nginx应用为例,介绍如何在恢复时通过手动配置来修改应用恢复的命名空间和镜像仓库的地址。同时,通过Resource Modifier功能修改存储卷的挂载路径并删除nodeAffinity。

应用示例介绍:备份集群中的有状态应用部署在default命名空间,镜像仓库由龙蜥社区提供,地址为anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis,需要公网拉取。应用通过volumeClaimTemplates字段为其自动创建云盘存储卷,使用的存储类为alicloud-disk-topology-alltype。

该应用的YAML示例如下:

展开查看应用的YAML示例

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  serviceName: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: node-role.kubernetes.io/control-plane
                operator: Exists
            weight: 1
      containers:
      - image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          name: web
          protocol: TCP
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: www
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      labels:
        app: nginx
      name: www
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi
      storageClassName: alicloud-disk-topology-alltype
      volumeMode: Filesystem

您可以通过以下命令,验证相关应用和存储卷状态正常。

kubectl get pod && kubectl get pvc

预期输出:

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          39s
web-1   1/1     Running   0          30s
NAME        STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS                     VOLUMEATTRIBUTESCLASS   AGE
www-web-0   Bound    d-2zefofsg0uzoiaxxxxxx   20Gi       RWO            alicloud-disk-topology-alltype   <unset>                 3m18s
www-web-1   Bound    d-2zedgdlghw2oudxxxxxx   20Gi       RWO            alicloud-disk-topology-alltype   <unset>                 30s

步骤一:在备份集群中备份应用

您可以通过kubectl命令行和控制台两种方式创建立即备份任务。

kubectl

  1. 使用以下内容,在备份集群中创建applicationbackup.yaml文件。

    apiVersion: csdr.alibabacloud.com/v1beta1
    kind: ApplicationBackup
    metadata:
      # 若集群中已经使用过该备份仓库,csdr.alibabacloud.com/backuplocations注释可以省去。
      annotations:
        csdr.alibabacloud.com/backuplocations: '{"name":"<backuplocationName>","region":"<bucketRegion>","bucket":"<bucketName>","prefix":"<path>","provider":"alibabacloud"}'
      name: <backupName>
      namespace: csdr
    spec:
      backupType: AppAndPvBackup
      includedNamespaces:
      - default
      pvBackup:
        defaultPvBackup: true
      storageLocation: <backuplocationName>
      ttl: 720h0m0s
  2. 在备份集群中执行以下命令,部署applicationbackup备份任务。

    kubectl apply -f applicationbackup.yaml
  3. 执行以下命令,查看并确认备份任务状态为Completed。

    kubectl -ncsdr get applicationbackup <立即备份任务名称> --watch

    预期输出:

    NAME                                  PHASE       AGE
    <backupName>                          Completed   18s

控制台

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

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理 > 应用备份

    系统会自动检测是否安装备份服务组件,如未安装,请根据界面提示,依次完成备份服务组件的安装。若您的集群为注册集群或专有版集群,还需要完成权限配置。具体操作,请参见安装migrate-controller备份服务组件并配置权限

  3. 应用备份页面,单击立即备份,在弹出的立即备份面板中,设置备份应用的相关参数,然后单击确定。更多高级配置参数信息,请参见创建备份计划或立即备份

    配置项

    说明

    示例

    名称

    立即备份的名称,必填项。

    backup

    备份仓库

    需要关联的备份仓库,必填项。

    cnfs-oss-test

    备份命名空间

    支持选中一个或者多个备份命名空间。表示备份选中的一个或多个命名空间中的应用,必填项。

    说明

    kube-system、kube-publish、kube-node-lease、csdr命名空间与集群强依赖,不建议直接进行备份恢复。因此,不支持备份这四个命名空间。

    default

    备份存储卷数据

    是否备份应用使用的存储卷中的数据。

    当选中备份存储卷时,当前的数据将备份在ECS快照或云备份中。

    • 云盘类型存储卷:默认通过ECS快照进行备份;

    • 其他类型的存储卷,通过云备份服务进行备份。

    恢复时,将从ECS快照或云备份服务中获取备份的数据,恢复至新的云盘等底层存储中。

    重要

    若不勾选备份存储卷,且未通过排除资源排除存储声明、存储卷时,备份记录仅包含对应的YAML,而不包含存储的数据。YAML中记录了云盘ID、NAS Server等存储底层信息。恢复时,将通过静态方式按照YAML恢复存储声明、存储卷。

    选中

  4. 应用备份备份记录页签,已创建的backup备份任务的状态列显示Completed,表示该任务备份成功。

(可选)步骤二:通过OSS控制台查看已完成备份的资源的JSON文件

备份资源的JSON文件包含所有备份的资源信息,包含资源的名称、类型、大小、创建日期等,您可以查看此文件来检查备份任务中是否包含您需要恢复的资源。下文以关联前提条件中已创建的备份仓库为例,介绍如何查看其中备份资源的JSON文件。

  1. 登录OSS管理控制台

  2. 在左侧导航栏,单击Bucket 列表,然后单击目标Bucket cnfs-oss-test。

  3. 在左侧导航栏,选择文件管理>文件列表

    /subpath/backups/<立即备份任务名称>/路径下,找到名为<立即备份任务名称>.tar.gz的压缩包,下载解压即可查看备份的所有资源的JSON文件。

步骤三:制定自定义资源调整策略

自定义资源调整策略主要包括conditionspatches两部分,conditions用于指定需要修改的资源,patches用于指定具体字段和修改方式。您可以参考以下示例编写配置项(ConfigMap)变更指定的字段。本示例同时对StatefulSet和Pod两种资源进行了修改,删除了节点亲和性配置,修改存储卷在容器中的挂载路径为/data

展开查看自定义资源调整策略的YAML文件

apiVersion: v1
data:
  modifier: |
    version: v1
    resourceModifierRules:
    - conditions:
        groupResource: statefulsets.apps
        namespaces:
        - default
        labelSelector:
          matchLabels:
            app: nginx
      patches:
      - operation: remove
        path: "/spec/template/spec/affinity/nodeAffinity"
      - operation: replace
        path: "/spec/template/spec/containers/0/volumeMounts/0/mountPath"
        value: "/data"
    - conditions:
        groupResource: pods
        resourceNameRegex: "^web.*$"
        namespaces:
        - default
        labelSelector:
          matchLabels:
            app: nginx
      patches:
      - operation: remove
        path: "/spec/affinity"
      - operation: replace
        path: "/spec/containers/0/volumeMounts/0/mountPath"
        value: "/data"
kind: ConfigMap
metadata:
  name: <backupName>-resource-modifier
  namespace: csdr

conditions字段说明如下:

字段

说明

是否必选

示例

groupResources

所属Kubernetes资源组,支持自定义资源类型。格式为<resourceName>.<groupName>,core组中的资源可省略组。

您可以通过kubectl api-resources命令查询。

statefulsets.apps

pods

namespaces

修改资源所在的命名空间。

为空时,修改对所有命名空间内的资源生效。

若使用命名空间映射功能,以原命名空间为准。

default

labelSelector

指定要修改的Kubernetes对象,支持matchLabelsmatchExpressions,符合标准的selector格式,与Deployment等应用的填写方式一致。

填写后,修改仅对选中的资源生效。

matchLabels:
  app: nginx 

resourceNameRegex

资源名称需满足的正则表达式。

填写后,修改仅对名称满足条件的资源生效。

"^web.*$"

patches字段说明如下:

字段

说明

是否必选

示例

operation

具体的修改操作,例如addremovereplace

replace

path

修改字段的路径。

"/spec/template/spec/containers/0/volumeMounts/0/mountPath"

value

追加或修改后的新值,仅支持在addreplace操作中使用。

"/data"

步骤四:在恢复集群中恢复调整后的应用

您需要在恢复集群中创建恢复任务来恢复调整后的应用,该任务中包含上一步制定的自定义资源调整策略,并通过namespaceMappingimageRegistryMapping字段配置了命名空间和镜像仓库地址的映射,格式均为Map。

  1. 参考以下示例创建恢复任务applicationrestore.yaml文件。

    该示例在恢复时将备份在default命名空间下的资源(含存储卷数据)恢复到default1命名空间,将龙蜥社区的镜像仓库地址修改为ACR镜像地址(仓库地址修改前已完成镜像同步)。

    apiVersion: csdr.alibabacloud.com/v1beta1
    kind: ApplicationRestore
    metadata:
      name: <restoreName>
      namespace: csdr
    spec:
      backupName: <backupName>
      namespaceMapping:
        default: default1   # 恢复至default1命名空间下。
      imageRegistryMapping:
        anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis: registry.cn-beijing.aliyuncs.com/<acrRegistry>  # 修改前,两个镜像仓库已完成镜像同步。
      resourceModifier:
        kind: ConfigMap
        name: <backupName>-resource-modifier
  2. 在恢复集群中执行以下命令,部署applicationrestore恢复任务。

    kubectl apply -f applicationrestore.yaml
  3. 执行以下命令,查看恢复任务状态。

    说明

    您也可以通过控制台查看恢复任务的状态。具体操作,请参见步骤三:恢复应用和数据卷

    kubectl -n csdr get applicationrestore <restoreName> --watch

    预期输出:

    NAME                                    PHASE       AGE
    <restoreName>                           Completed   18h

步骤五:验证应用已按照要求恢复完成

执行以下命令,获取恢复的有状态应用的配置信息。

kubectl -n default get sts web -oyaml

预期输出:

展开查看预期输出

apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"StatefulSet","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"web","namespace":"default"},"spec":{"replicas":2,"selector":{"matchLabels":{"app":"nginx"}},"serviceName":"nginx","template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"affinity":{"nodeAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"preference":{"matchExpressions":[{"key":"node-role.kubernetes.io/master","operator":"Exists"}]},"weight":1}]}},"containers":[{"image":"anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.2","imagePullPolicy":"IfNotPresent","name":"nginx","ports":[{"containerPort":80,"name":"web","protocol":"TCP"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","volumeMounts":[{"mountPath":"/usr/share/nginx/html/","name":"www"}]}]}},"volumeClaimTemplates":[{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"labels":{"app":"nginx"},"name":"www"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"20Gi"}},"storageClassName":"alicloud-disk-topology-alltype","volumeMode":"Filesystem"}}]}}
  creationTimestamp: "2024-10-09T08:32:50Z"
  generation: 1
  labels:
    app: nginx
    velero.io/backup-name: <立即备份任务名称>
    velero.io/restore-name: <恢复任务名称>
  name: web
  namespace: default1
  resourceVersion: "119622"
  uid: d23878ea-0b9f-40ba-b61b-1ff6bb77eb43
spec:
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain
    whenScaled: Retain
  podManagementPolicy: OrderedReady
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: nginx
  serviceName: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      affinity: {}
      containers:
      - image: registry.cn-beijing.aliyuncs.com/<acrRegistry>/nginx:1.14.1-8.6
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          name: web
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /data
          name: www
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
  updateStrategy:
    rollingUpdate:
      partition: 0
    type: RollingUpdate
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
      name: www
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi
      storageClassName: alicloud-disk-topology-alltype
      volumeMode: Filesystem
    status:
      phase: Pending
status:
  availableReplicas: 0
  collisionCount: 0
  currentRevision: web-7b454646b4
  observedGeneration: 1
  replicas: 2
  updateRevision: web-7b454646b4

在预期输出的配置中,容器镜像的镜像仓库地址、容器中的挂载路径、所在命名空间均已调整,节点亲和性配置也已删除。

说明

YAML中部分新增字段为Kubernetes自动填充。