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:
| Constraint | Detail |
|---|---|
| Region | The registered cluster, ACK cluster, and OSS bucket must all be in the same region. Cross-region migration is not supported. |
| Kubernetes version | External cluster must be version 1.16 or later. ACK restore cluster must be version 1.18 or later. |
| Storage plug-in | The restore cluster must use the Container Storage Interface (CSI) plug-in. FlexVolume and mixed csi-compatible-controller + FlexVolume configurations are not supported. |
| Persistent volumes | Before backing up, PVs and PVCs must be created using Alibaba Cloud's CSI plug-in. |
Prerequisites
Before you begin, make sure you have:
Clusters:
A registered cluster with an external Kubernetes cluster (version 1.16 or later) registered to ACK. See Create a registered cluster.
An ACK cluster (version 1.18 or later) in the same region as the registered cluster. See Create an ACK managed cluster or Create an ACK dedicated cluster.
The cluster backup feature enabled for both clusters. See Install migrate-controller and grant permissions.
Cloud Backup activated.
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:
Registered cluster: Create a Resource Access Management (RAM) user with OSS and Cloud Backup permissions. Create a Secret named
alibaba-addon-secretin thecsdrnamespace to store the RAM user's AccessKey ID and AccessKey secret.ACK managed cluster: Cloud Backup is activated and an OSS bucket named
cnfs-oss-****is created.ACK dedicated cluster: The worker node RAM role has OSS and Cloud Backup permissions. See Grant OSS permissions to an ACK dedicated cluster and Grant Cloud Backup permissions to an ACK dedicated cluster or registered cluster.
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 csdrExpected output:
alibaba-addon-secret Opaque 2 5d22hIf the Secret is missing, complete the permissions setup described in the Prerequisites section before continuing.
Create a namespace named
test1:kubectl create namespace test1Create a file named
app-mysql.yamlwith the following content. Replace<your-hostname>with the name of the node to back up. Setusernameandpasswordto 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.Apply the manifest to create the MySQL StatefulSet, persistent volume, PVC, and Secret:
kubectl create -f app-mysql.yamlExpected output:
statefulset.apps/mysql-sts created persistentvolume/example-pv created persistentvolumeclaim/example-pvc created secret/mysql-pass createdVerify that the MySQL Pod is running:
kubectl get pod -n test1 | grep mysql-stsExpected 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.
In the ACK console, navigate to the registered cluster and create a backup vault. See Create a backup vault.
Create a real-time backup task named
MySQL. See Create a backup plan or back up instantly. Configure the following settings:Parameter Value Name MySQLBackup Vaults Select the backup vault created in the previous step Backup Namespaces test1On the Application Backup page, click the Backup Records tab and wait for the
MySQLbackup 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.
In the ACK console, navigate to the ACK cluster and create a restore task. See Restore applications and volumes. Configure the following settings:
Parameter Value Name mysql-restoreBackup Vaults Select the backup vault created in Step 2. Click Initialize Backup Vault to associate the ACK cluster with the vault. Select Backup MySQLReset Namespace Change test1totest2StorageClass Conversion For the example-pvcPVC, select thealibabacloud-cnfs-nasStorageClassClick View Restoration Records next to Restore and wait for the
mysql-restoretask status to change from InProgress to Completed.Verify that the MySQL Pod is running in the ACK cluster:
kubectl get pod -n test2 | grep mysql-stsExpected output:
mysql-sts-0 1/1 Running 0 4sVerify that the StorageClass was converted to
alibabacloud-cnfs-nas:kubectl get pvc -n test2 | grep example-pvcExpected output:
example-pvc Bound nas-acde4acd-59b6-4332-90af-b74ef6****** 25Gi RWO alibabacloud-cnfs-nas 31mVerify 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.