All Products
Search
Document Center

Container Service for Kubernetes:Migrate applications from external Kubernetes clusters to ACK clusters

Last Updated:Mar 26, 2026

When you need to move stateful applications from a self-managed Kubernetes cluster to ACK, manually recreating workloads and migrating persistent volume data is error-prone and time-consuming. The ACK backup center automates this process: it backs up your application — including persistent volumes — from the external cluster, then restores it into ACK, with optional StorageClass conversion. This topic walks through migrating a MySQL StatefulSet with a local persistent volume as a working example.

How it works

Migration uses a shared backup vault. Both the external (source) cluster and the ACK (target) cluster point to the same Object Storage Service (OSS) bucket. You back up the application through the registered cluster, and ACK reads from the same vault to restore it. Because both clusters share a single backup location, no direct network path is required between them — only access to the OSS bucket.

Limitations

Review these constraints before starting the migration:

ConstraintDetail
RegionThe registered cluster, ACK cluster, and OSS bucket must all be in the same region. Cross-region migration is not supported.
Kubernetes versionExternal cluster must be version 1.16 or later. ACK restore cluster must be version 1.18 or later.
Storage plug-inThe restore cluster must use the Container Storage Interface (CSI) plug-in. FlexVolume and mixed csi-compatible-controller + FlexVolume configurations are not supported.
Persistent volumesBefore backing up, PVs and PVCs must be created using Alibaba Cloud's CSI plug-in.

Prerequisites

Before you begin, make sure you have:

Clusters:

Storage:

  • PVs and PVCs in the external cluster that mount local volumes using Alibaba Cloud's CSI plug-in. See Local volumes.

Network:

  • If the registered cluster connects to a virtual private cloud (VPC) via Cloud Enterprise Network (CEN), Express Connect, or VPN, configure a route pointing to the internal network of the region where the OSS bucket resides. See Internal OSS endpoints and VIP ranges.

Components (required before restore):

Install and configure these system components in the ACK cluster before running a restore task:

  • aliyun-acr-credential-helper: Grant permissions to the restore cluster and configure acr-configuration.

  • alb-ingress-controller: Configure an ALBConfig.

Permissions:

Step 1: Deploy an application in the external cluster

This step sets up a MySQL StatefulSet with a local persistent volume in the external cluster. Skip this step if you already have an application to migrate.

Before proceeding, verify that the alibaba-addon-secret Secret exists in the csdr namespace of the registered cluster:

kubectl get secret alibaba-addon-secret -n csdr

Expected output:

alibaba-addon-secret   Opaque   2      5d22h

If the Secret is missing, complete the permissions setup described in the Prerequisites section before continuing.

  1. Create a namespace named test1:

    kubectl create namespace test1
  2. Create a file named app-mysql.yaml with the following content. Replace <your-hostname> with the name of the node to back up. Set username and password to base64-encoded credentials for the MySQL application.

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mysql-sts
      namespace: test1
    spec:
      selector:
        matchLabels:
          app: mysql-sts
      serviceName: mysql-sts
      template:
        metadata:
          labels:
            app: mysql-sts
        spec:
          containers:
          - name: mysql-sts
            image: mysql:5.7
            env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password
            ports:
            - containerPort: 80
              name: mysql-sts
            volumeMounts:
            - name: mysql
              mountPath: /var/lib/mysql
          volumes:
            - name: mysql
              persistentVolumeClaim:
                claimName: example-pvc
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: example-pv
    spec:
      capacity:
        storage: 100Gi
      volumeMode: Filesystem
      accessModes:
      - ReadWriteOnce
      persistentVolumeReclaimPolicy: Delete
      storageClassName: local-storage
      local:
        path: /mnt/disk
      nodeAffinity:
        required:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - <your-hostname>  # Replace with the name of the node to back up.
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: example-pvc
      namespace: test1
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 25Gi
      storageClassName: local-storage
      volumeName: example-pv
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: mysql-pass
      namespace: test1
    type: Opaque
    data:
      username: dGVz****          # Replace with the base64-encoded MySQL username.
      password: dGVzdDEt****      # Replace with the base64-encoded MySQL password.
  3. Apply the manifest to create the MySQL StatefulSet, persistent volume, PVC, and Secret:

    kubectl create -f app-mysql.yaml

    Expected output:

    statefulset.apps/mysql-sts created
    persistentvolume/example-pv created
    persistentvolumeclaim/example-pvc created
    secret/mysql-pass created
  4. Verify that the MySQL Pod is running:

    kubectl get pod -n test1 | grep mysql-sts

    Expected output:

    mysql-sts-0   1/1     Running   1 (4m51s ago)   4m58s

Step 2: Back up the MySQL application in the registered cluster

Back up the application through the registered cluster. The ACK cluster reads from the same backup vault in Step 3.

  1. In the ACK console, navigate to the registered cluster and create a backup vault. See Create a backup vault.

  2. Create a real-time backup task named MySQL. See Create a backup plan or back up instantly. Configure the following settings:

    ParameterValue
    NameMySQL
    Backup VaultsSelect the backup vault created in the previous step
    Backup Namespacestest1
  3. On the Application Backup page, click the Backup Records tab and wait for the MySQL backup task status to change from InProgress to Completed.

Step 3: Restore the backup in the ACK cluster

This step restores the MySQL application from the backup vault into the test2 namespace of the ACK cluster, converting the StorageClass from local-storage to alibabacloud-cnfs-nas.

  1. In the ACK console, navigate to the ACK cluster and create a restore task. See Restore applications and volumes. Configure the following settings:

    ParameterValue
    Namemysql-restore
    Backup VaultsSelect the backup vault created in Step 2. Click Initialize Backup Vault to associate the ACK cluster with the vault.
    Select BackupMySQL
    Reset NamespaceChange test1 to test2
    StorageClass ConversionFor the example-pvc PVC, select the alibabacloud-cnfs-nas StorageClass
  2. Click View Restoration Records next to Restore and wait for the mysql-restore task status to change from InProgress to Completed.

  3. Verify that the MySQL Pod is running in the ACK cluster:

    kubectl get pod -n test2 | grep mysql-sts

    Expected output:

    mysql-sts-0   1/1     Running   0          4s
  4. Verify that the StorageClass was converted to alibabacloud-cnfs-nas:

    kubectl get pvc -n test2 | grep example-pvc

    Expected output:

    example-pvc   Bound    nas-acde4acd-59b6-4332-90af-b74ef6******   25Gi       RWO            alibabacloud-cnfs-nas   31m
  5. Verify that the PVC is mounted to the MySQL Pod:

    kubectl describe pvc example-pvc -n test2 | grep "Used By"

    Expected output:

    Used By:       mysql-sts-0

The MySQL application and its data are now running in the ACK cluster with storage backed by Cloud Native File System (CNFS) NAS.

What's next