All Products
Search
Document Center

Container Service for Kubernetes:Back up and restore applications using Terraform

Last Updated:Mar 26, 2026

Use the Terraform CLI to declaratively manage application backup and restoration across ACK clusters. This approach deploys custom resources (CRs) — BackupLocation, ApplicationBackup, BackupSchedule, ApplicationRestore, and DeleteRequest — without manual console or kubectl operations.

Prerequisites

Before you begin, ensure that you have:

Usage notes

  • Do not run kubectl delete to remove backup or restoration tasks. Related cloud resources may not be fully deleted. To delete resources correctly, see Step 5: Delete resources.

  • Keep migrate-controller updated to the latest version. See Manage components.

  • Do not remove any parameters from the sample code in the following steps. Missing parameters can prevent backups from being restored.

Step 1: Connect to a cluster

Use the Terraform Kubernetes provider to connect to your cluster via a KubeConfig file. For details about the provider, see Kubernetes Provider.

  1. Create a Terraform working directory.

  2. In the directory, create a configuration file named csdr.tf and add the following content:

    provider "kubernetes" {
      config_path = "~/.kube/config"
    }
  3. Initialize the Terraform runtime environment:

    terraform init

    Expand to view the output

    Initializing the backend...
    
    Initializing provider plugins...
    - Reusing previous version of hashicorp/alicloud from the dependency lock file
    - Reusing previous version of hashicorp/kubernetes from the dependency lock file
    - Using previously-installed hashicorp/alicloud v1.223.1
    - Using previously-installed hashicorp/kubernetes v2.30.0
    
    ╷
    │ Warning: Additional provider information from registry
    │
    │ The remote registry returned warnings for registry.terraform.io/hashicorp/alicloud:
    │ - For users on Terraform 0.13 or greater, this provider has moved to aliyun/alicloud. Please
    │ update your source in required_providers.
    ╵
    
    Terraform has been successfully initialized!

Step 2: Create a backup vault

A backup vault (BackupLocation CR) defines where backups are stored in OSS and how your cluster accesses the bucket.

  1. Add the following resource block to csdr.tf, replacing the placeholder values:

    Parameter Required Description
    name Yes Name of the backup vault. Must comply with Kubernetes naming conventions.
    network Yes Network mode for accessing the OSS bucket. internal: all clusters must be in the same region as the bucket. public: no region restrictions.
    region Yes Region where the OSS bucket resides.
    bucket Yes OSS bucket name. Must start with cnfs-oss-.
    prefix No Subdirectory in the OSS bucket. If specified, backups are stored in that subdirectory.
    provider Yes Cloud provider. Set to alibabacloud.
    resource "kubernetes_manifest" "backuplocation-demo" {
      manifest = {
        apiVersion = "csdr.alibabacloud.com/v1beta1"
        kind       = "BackupLocation"
        metadata = {
          name      = "<your-backup-vault-name>"   # Must comply with Kubernetes naming conventions
          namespace = "csdr"
        }
    
        spec = {
          backupSyncPeriod = "0s"
          config = {
            network = "internal"    # "internal": bucket and clusters must be in the same region
                                    # "public": no region restrictions
            region  = "cn-beijing"  # Region where the OSS bucket resides
          }
          objectStorage = {
            bucket = "<cnfs-oss-your-bucket-name>"  # Must start with cnfs-oss-
            prefix = "<sub-directory>"              # Optional: stores backups in this subdirectory
          }
          provider = "alibabacloud"
        }
      }
    
      # Wait until the backup vault is ready before proceeding
      wait {
        fields = {
          "status.phase" = "Available"
        }
      }
    
      timeouts {
        create = "10m"
      }
    }
  2. Preview the changes:

    terraform plan
  3. Apply the configuration to create the backup vault:

    terraform apply

    Expand to view the response

    kubernetes_manifest.backuplocation-demo: Creating...
    kubernetes_manifest.backuplocation-demo: Creation complete after 1s
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Step 3: Create a backup task

ACK supports two backup modes: instant backup (runs once on demand) and scheduled backup (runs on a cron schedule).

Create an instant backup task

  1. Add the following resource block to csdr.tf, replacing the placeholder values:

    If your ACK cluster uses Velero, join DingTalk group 35532895 for technical support.
    Parameter Required Description
    csdr.alibabacloud.com/backuplocations Yes The backup vault annotation. Must match the BackupLocation configuration exactly.
    name Yes Name of the instant backup task.
    includedNamespaces Yes Namespaces to back up.
    includedResources No Resource types to include. Specify only one of includedResources or excludedResources. If both are empty, all resource types are backed up.
    excludedResources No Resource types to exclude. See the note for includedResources.
    matchLabels No Labels of the resources to back up.
    includeClusterResources No Controls cluster-scoped resources. true: all cluster-scoped resources. false or unset: only those referenced by the specified namespaces. Default in the ACK console: false.
    defaultPvBackup No true: back up applications and volumes. false: back up applications only.
    storageLocation Yes Name of the backup vault (BackupLocation).
    ttl Yes Backup validity period. Format: 720h0m0s. Valid range: 24h0m0s to 1572864h0m0s. Expired backups cannot be restored.
    resource "kubernetes_manifest" "applicationbackup-demo" {
      manifest = {
        apiVersion = "csdr.alibabacloud.com/v1beta1"
        kind       = "ApplicationBackup"
        metadata = {
          name      = "<your-backup-task-name>"
          namespace = "csdr"
          annotations = {
            # Must match the backup vault configuration exactly
            "csdr.alibabacloud.com/backuplocations" = "{\"name\":\"<your-backup-vault-name>\",\"region\":\"cn-beijing\",\"bucket\":\"<cnfs-oss-your-bucket-name>\",\"prefix\":\"<sub-directory>\",\"provider\":\"alibabacloud\"}"
          }
        }
        spec = {
          includedNamespaces = ["default", "default1"]  # Namespaces to back up
    
          # Specify only one of includedResources or excludedResources.
          # If both are empty, all resource types are backed up.
          includedResources = ["statefulset"]
          excludedResources = ["excludedResources"]
    
          labelSelector = {
            matchLabels = {
              "app" = "mysql-sts"  # Optional: back up only resources with these labels
            }
          }
    
          pvBackup = {
            defaultPvBackup = "false"  # "true": back up apps and volumes; "false": apps only
          }
    
          storageLocation = "<your-backup-vault-name>"  # Must match the BackupLocation name
    
          ttl = "720h0m0s"  # Backup validity period. Format: 720h0m0s
                            # Valid range: 24h0m0s to 1572864h0m0s
                            # Expired backups cannot be restored
    
          # includeClusterResources controls whether cluster-scoped resources are included:
          # "true"  — include all cluster-scoped resources (StorageClasses, CRDs, webhooks, etc.)
          # "false" — include only cluster-scoped resources referenced by the specified namespaces
          #           (for example, if a pod uses a service account with a cluster role,
          #            that cluster role is automatically included)
          # Unset  — same behavior as "false" when namespace filtering is used
          includeClusterResources = "false"
        }
      }
    
      # Uncomment to wait for backup completion (recommended for scripted workflows).
      # Backup duration depends on the number of applications and volume data size.
      #wait {
      #  fields = {
      #    "status.phase" = "Completed"
      #  }
      #}
      #timeouts {
      #  create = "60m"
      #}
    }
  2. Preview the changes:

    terraform plan
  3. Create the instant backup task:

    terraform apply

    Expand to view the output

    kubernetes_manifest.applicationbackup-demo: Creating...
    kubernetes_manifest.applicationbackup-demo: Creation complete after 1s
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Create a scheduled backup task

  1. Add the following resource block to csdr.tf, replacing the placeholder values:

    Expand to view the configuration file

    resource "kubernetes_manifest" "backupschedule-demo" {
      manifest = {
        apiVersion = "csdr.alibabacloud.com/v1beta1"
        kind       = "BackupSchedule"
        metadata = {
          name      = "<your-schedule-name>"
          namespace = "csdr"
          annotations = {
            "csdr.alibabacloud.com/backuplocations" = "{\"name\":\"<your-backup-vault-name>\",\"region\":\"cn-beijing\",\"bucket\":\"<cnfs-oss-your-bucket-name>\",\"prefix\":\"<sub-directory>\",\"provider\":\"alibabacloud\"}"
          }
        }
        spec = {
          # Cron expression for the backup schedule (server time zone).
          # Format:  minute  hour  day-of-month  month  day-of-week
          # Example: "1 4 * * *" runs at 04:01 every day.
          schedule = "1 4 * * *"
    
          template = {
            includedNamespaces = ["default", "default1"]
            includedResources  = ["statefulset"]
            excludedResources  = ["excludedResources"]
            labelSelector = {
              matchLabels = {
                "app" = "mysql-sts"
              }
            }
            pvBackup = {
              defaultPvBackup = "false"  # Required for BackupSchedule
            }
            storageLocation         = "<your-backup-vault-name>"
            ttl                     = "720h0m0s"
            includeClusterResources = "false"
          }
        }
      }
    
      wait {
        fields = {
          "status.phase" = "Enabled"
        }
      }
    
      timeouts {
        create = "10m"
      }
    }
    Parameter Required Description
    csdr.alibabacloud.com/backuplocations Yes The backup vault annotation. Must match the BackupLocation configuration exactly.
    name Yes Name of the scheduled backup task.
    schedule Yes Backup frequency as a cron expression. Format: minute hour day-of-month month day-of-week. Example: "1 4 * * *" runs at 04:01 every day.
    includedNamespaces Yes Namespaces to back up.
    includedResources No Resource types to include. Specify only one of includedResources or excludedResources. If both are empty, all resource types are backed up.
    excludedResources No Resource types to exclude. See the note for includedResources.
    matchLabels No Labels of the resources to back up.
    includeClusterResources No Controls cluster-scoped resources. true: all cluster-scoped resources. false or unset: only those referenced by the specified namespaces.
    defaultPvBackup Yes true: back up applications and volumes. false: back up applications only.
    storageLocation Yes Name of the backup vault (BackupLocation).
    ttl Yes Backup validity period. Format: 720h0m0s. Valid range: 24h0m0s to 1572864h0m0s.
  2. Preview the changes:

    terraform plan
  3. Create the scheduled backup task:

    terraform apply

    Expand to view the output

    kubernetes_manifest.backupschedule-demo: Creating...
    kubernetes_manifest.backupschedule-demo: Creation complete after 1s
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Manage scheduled backup tasks

Find backups created by a schedule

Use a label selector to list all backups generated by a specific scheduled task:

data "kubernetes_resources" "list-applicationbackup" {
  api_version    = "csdr.alibabacloud.com/v1beta1"
  kind           = "ApplicationBackup"
  namespace      = "csdr"
  label_selector = "csdr/schedule-name=<your-schedule-name>"
}

output "applicationbackup-name" {
  value = data.kubernetes_resources.list-applicationbackup.objects
}

Modify a scheduled backup task

To change backup parameters such as the schedule frequency:

  1. Set spec.paused to "true" to pause the schedule, then update the desired parameters. Example — pause the schedule and change the backup frequency:

    Expand to view the configuration file

    resource "kubernetes_manifest" "backupschedule-demo" {
      manifest = {
        apiVersion = "csdr.alibabacloud.com/v1beta1"
        kind       = "BackupSchedule"
        metadata = {
          name      = "<your-schedule-name>"
          namespace = "csdr"
          annotations = {
            "csdr.alibabacloud.com/backuplocations" = "{\"name\":\"<your-backup-vault-name>\",\"region\":\"cn-beijing\",\"bucket\":\"<cnfs-oss-your-bucket-name>\",\"prefix\":\"<sub-directory>\",\"provider\":\"alibabacloud\"}"
          }
        }
        spec = {
          paused   = "true"        # Pause the schedule before modifying
          schedule = "0 5 * * *"   # Updated backup frequency
          template = {
            includedNamespaces      = ["default", "default1"]
            includedResources       = ["statefulset"]
            excludedResources       = ["excludedResources"]
            labelSelector = {
              matchLabels = {
                "app" = "mysql-sts"
              }
            }
            pvBackup = {
              defaultPvBackup = "false"
            }
            storageLocation         = "<your-backup-vault-name>"
            ttl                     = "720h0m0s"
            includeClusterResources = "false"
          }
        }
      }
      wait {
        fields = {
          "status.phase" = "Paused"  # Confirm the schedule is paused before applying further changes
        }
      }
      timeouts {
        create = "10m"
      }
    }
  2. Preview the changes:

    terraform plan
  3. Apply the updated configuration:

    terraform apply

    A successful update returns:

    kubernetes_manifest.backupschedule-demo: Modifying...
    kubernetes_manifest.backupschedule-demo: Modifications complete after 1s
    
    Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Step 4: Create a restoration task

A restoration task (ApplicationRestore CR) restores applications from a backup into the target cluster, optionally remapping namespaces and converting StorageClasses.

  1. Add the following resource block to csdr.tf, replacing the placeholder values:

    Parameter Required Description
    csdr.alibabacloud.com/backuplocations Yes The backup vault annotation. Must match the BackupLocation configuration.
    name Yes Name of the restoration task.
    appRestoreOnly No true: restore only applications (not persistent volume claims (PVCs), persistent volumes (PVs), or volume data); manually create PVCs and PVs before restoring. false: restore applications and volume data. Default: false.
    preserveNodePorts No true: retain the original NodePort values. false: reassign NodePorts to random ports. If the backup cluster and restore cluster use the same NodePort, set this parameter to false.
    includedNamespaces Yes Namespaces to restore. If empty, all backed-up namespaces are restored.
    includedResources No Resource types to include. Specify only one of includedResources or excludedResources.
    excludedResources No Resource types to exclude.
    backupName Yes Name of the backup to restore from. For scheduled backups, specify a point-in-time backup name, such as <your-schedule-name>-20221205225845.
    namespaceMapping No Maps <backup-namespace> to <target-namespace>. If the target namespace does not exist, it is created automatically.
    convertedarg No StorageClass conversion list for FileSystem-type volumes (OSS, NAS, CPFS, local). Each entry specifies convertToStorageClassType (target StorageClass; must be disk or NAS and must exist in the cluster), namespace, and persistentVolumeClaim. Run kubectl -ncsdr describe <backup-name> to identify eligible PVCs.
    Important

    ReadWriteMany volumes cannot be converted to disk. For ReadOnlyMany volumes, ensure replicas are not simultaneously mounted on multiple nodes.

    resource "kubernetes_manifest" "applicationrestore-demo" {
      manifest = {
        apiVersion = "csdr.alibabacloud.com/v1beta1"
        kind       = "ApplicationRestore"
        metadata = {
          name      = "<your-restoration-task-name>"
          namespace = "csdr"
          annotations = {
            "csdr.alibabacloud.com/backuplocations" = "{\"name\":\"<your-backup-vault-name>\",\"region\":\"cn-beijing\",\"bucket\":\"<cnfs-oss-your-bucket-name>\",\"prefix\":\"<sub-directory>\",\"provider\":\"alibabacloud\"}"
          }
        }
        spec = {
          # "false": restore applications and volume data (default)
          # "true":  restore applications only; manually create PVCs and PVs beforehand
          appRestoreOnly = "false"
    
          # "true":  retain the original NodePort values from the backup
          # "false": reassign NodePorts to random ports (use when backup and target clusters share the same NodePort)
          preserveNodePorts = "true"
    
          includedNamespaces = ["default", "default1"]
          includedResources  = ["statefulset"]
          excludedResources  = ["excludedResources"]
    
          # StorageClass conversion for FileSystem-type volumes (OSS, NAS, CPFS, local volumes).
          # Run `kubectl -ncsdr describe <backup-name>` and check
          # status.resourceList.dataResource.pvcBackupInfo to find PVCs eligible for conversion.
          # Important: ReadWriteMany volumes cannot be converted to disk.
          # For ReadOnlyMany volumes converted to disk, ensure replicas are not mounted on multiple nodes simultaneously.
          convertedarg = [
            {
              convertToStorageClassType = "alicloud-disk-topology-alltype"  # Target StorageClass (must exist in the cluster; disk or NAS only)
              namespace                 = "default"
              persistentVolumeClaim     = "pvc-nas"
            },
            {
              convertToStorageClassType = "alicloud-disk-topology-alltype"
              namespace                 = "default1"
              persistentVolumeClaim     = "pvc-oss"
            }
          ]
    
          # The backup to restore from.
          # For scheduled backups, specify a point-in-time backup name, for example:
          # "<your-schedule-name>-20221205225845"
          backupName = "<your-backup-task-name>"
    
          # Maps a namespace in the backup to a different namespace in the target cluster.
          # If the target namespace does not exist, it is created automatically.
          namespaceMapping = {
            "<backup-namespace>" = "<target-namespace>"
          }
        }
      }
    
      # Uncomment to wait for restoration completion (recommended for scripted workflows).
      # Restoration duration depends on the number of applications and volume data size.
      #wait {
      #  fields = {
      #    "status.phase" = "Completed"
      #  }
      #}
      #timeouts {
      #  create = "60m"
      #}
    }
  2. Preview the changes:

    terraform plan
  3. Create the restoration task:

    terraform apply

    Expand to view returned information

    kubernetes_manifest.applicationrestore-demo: Creating...
    kubernetes_manifest.applicationrestore-demo: Creation complete after 1s
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Step 5: Delete resources

Important

The backup vault (BackupLocation) cannot be deleted because other clusters may depend on it.

Delete a scheduled backup task

Run terraform destroy to remove the BackupSchedule resource and stop the schedule.

Delete a backup task or restoration task

Use a DeleteRequest CR to safely remove backup or restoration tasks and their associated cloud resources.

Deleting a backup task does not affect the backups already created. Deleting a restoration task does not affect the data already restored.
  1. Add the following resource block to csdr.tf:

    Parameter Required Description
    name Yes Name of the deletion request. Format: <ApplicationBackup-name>-dbr to delete a backup task, or <ApplicationRestore-name>-dbr to delete a restoration task.
    deleteObjectName Yes Name of the resource to delete.
    deleteObjectType Yes "Backup": deletes the ApplicationBackup CR and related resources. "Restore": deletes the ApplicationRestore CR and related resources.
    resource "kubernetes_manifest" "deleterequest-demo" {
      manifest = {
        apiVersion = "csdr.alibabacloud.com/v1beta1"
        kind       = "DeleteRequest"
        metadata = {
          name      = "<object-name>-dbr"  # Format: <ApplicationBackup-or-ApplicationRestore-name>-dbr
          namespace = "csdr"
        }
        spec = {
          deleteObjectName = "<object-name>"   # Name of the backup or restoration task to delete
          deleteObjectType = "Backup"          # "Backup": deletes ApplicationBackup and related resources
                                               # "Restore": deletes ApplicationRestore and related resources
        }
      }
    }
  2. Preview the changes:

    terraform plan
  3. Apply the deletion:

    terraform apply

    Expand to view the output

    kubernetes_manifest.deleterequest-demo: Creating...
    kubernetes_manifest.deleterequest-demo: Creation complete after 0s
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

    After the system deletes the target resource, it also deletes the DeleteRequest CR automatically.

What's next

References