Skip to main content

Migrate Kubernetes volume data between clusters

You can migrate volume data (PersistentVolumeClaim, PVC) from one Kubernetes cluster to another using the K8up operator.

K8up is a backup operator for Kubernetes. It backs up PVC data using restic, uploads it to S3-compatible storage, and restores it to any cluster where K8up is installed. This method is suitable when you need to migrate data from individual volumes rather than an entire cluster.

In the examples, a copy of the volume from the my-app namespace of the source cluster is saved to Selectel Object Storage and restored to a new PVC in the my-app-new namespace of the target cluster.

  1. Install K8up.

  2. Create secrets for K8up.

  3. Create a volume backup.

  4. Restore data to another cluster.

1. Install K8up

K8up must be installed in both the source and target clusters: first the CRD, then the K8up operator via Helm. The CRD version must match the K8up operator version — see the Releases page in the K8up GitHub repository for details.

  1. Open the CLI.

  2. Install the K8up CRD:

    kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.8.6/k8up-crd.yaml
  3. Install the K8up operator:

    helm repo add k8up-io https://k8up-io.github.io/k8up
    helm install k8up k8up-io/k8up --version 4.8.6 --namespace k8up --create-namespace
  4. Repeat steps 1-3 for the target cluster.

2. Create secrets for K8up

Secrets are created in the namespace containing the volumes being migrated. Two secrets are required: one with the S3 key for storage access and one with the restic repository password. All backups are encrypted with the repository password; without it, data cannot be restored.

  1. Open the CLI.

  2. Create a secrets.yaml file with secrets:

    apiVersion: v1
    kind: Secret
    metadata:
    name: s3-secrets-k8up
    namespace: my-app
    stringData:
    username: <s3_access_key>
    password: <s3_secret_key>
    ---
    apiVersion: v1
    kind: Secret
    metadata:
    name: restic-repository-password
    namespace: my-app
    stringData:
    password: <repo_password>

    Specify:

    • <s3_access_key> — the value of the Access key field from the S3 key;
    • <s3_secret_key> — the value of the Secret key field from the S3 key;
    • <repo_password> — the restic repository password; create and save it. All backups are encrypted with the repository password; without it, data cannot be restored.
  3. Apply the secrets:

    kubectl apply -f secrets.yaml

3. Create a volume backup

warning

To ensure data consistency, stop writing to the volume during the backup process.

  1. Open the CLI.

  2. Add a PVC label that K8up will use to find the volume:

    kubectl -n my-app label pvc <pvc_name> app.kubernetes.io/name=<pvc_name>

    Specify <pvc_name> — the name of the PVC being migrated.

  3. Create a backup.yaml file with the Backup resource:

    apiVersion: k8up.io/v1
    kind: Backup
    metadata:
    name: <pvc_name>
    namespace: my-app
    spec:
    podSecurityContext:
    runAsUser: 0
    runAsGroup: 1000
    labelSelectors:
    - matchExpressions:
    - key: app.kubernetes.io/name
    operator: In
    values:
    - "<pvc_name>"
    failedJobsHistoryLimit: 2
    successfulJobsHistoryLimit: 2
    backend:
    repoPasswordSecretRef:
    name: restic-repository-password
    key: password
    s3:
    endpoint: https://s3.<pool>.storage.selcloud.ru
    bucket: <bucket_name>
    accessKeyIDSecretRef:
    name: s3-secrets-k8up
    key: username
    secretAccessKeySecretRef:
    name: s3-secrets-k8up
    key: password

    Specify:

    • <pvc_name> — the name of the PVC being migrated;
    • <pool> — the pool where the bucket is located, for example ru-1;
    • <bucket_name> — the name of the bucket in Selectel S3.

    Here, podSecurityContext sets the user (UID) and group (GID) under which the backup pod reads the volume files. The value 0 (root) allows reading all files. If file read errors (permission denied) appear in the pod log, specify the UID and GID of the user running the application that uses this volume.

  4. Apply the Backup resource:

    kubectl apply -f backup.yaml

    K8up will create a pod named backup-<pvc_name>, which will copy the volume data to the storage.

  5. Check the status of the backup and the backup pod:

    kubectl -n my-app get backup
    kubectl -n my-app get pods
  6. Make sure that the data was copied completely by checking the backup pod logs:

    kubectl -n my-app logs <pod_name>

    Specify <pod_name> — the name of the backup pod.

  7. Record the snapshot ID — you will need it for restoration:

    kubectl -n my-app get snapshots

    A list of snapshots will appear in the output.

4. Restore data to another cluster

  1. In the target namespace, create a PVC to which the data will be restored. The PVC size must not be smaller than the size of the source volume. For a Managed Kubernetes cluster, follow the Create PersistentVolumeClaim instructions.

  2. In the target namespace, create the secrets that you created in step 2, with the same values as in the source cluster.

  3. Open the CLI.

  4. Create a restore.yaml file with the Restore resource:

    apiVersion: k8up.io/v1
    kind: Restore
    metadata:
    name: <pvc_name>
    namespace: my-app-new
    spec:
    podSecurityContext:
    runAsUser: 0
    runAsGroup: 0
    snapshot: <snapshot_id>
    restoreMethod:
    folder:
    claimName: <pvc_name>
    backend:
    repoPasswordSecretRef:
    name: restic-repository-password
    key: password
    s3:
    endpoint: https://s3.<pool>.storage.selcloud.ru
    bucket: <bucket_name>
    accessKeyIDSecretRef:
    name: s3-secrets-k8up
    key: username
    secretAccessKeySecretRef:
    name: s3-secrets-k8up
    key: password

    Specify:

    • <snapshot_id> — the snapshot ID you recorded in step 7 when creating a backup in step 3;
    • <pvc_name> — the name of the PVC you created in step 1;
    • <pool> — the pool where the bucket is located;
    • <bucket_name> — the name of the bucket in Selectel S3.

    Here, podSecurityContext sets the user (UID) and group (GID) under which files are restored — the restored data will be assigned this owner. Specify the UID and GID of the user running the application in the target cluster, otherwise the application might not be able to access the restored data.

  5. Apply the Restore resource:

    kubectl apply -f restore.yaml

    K8up will create a pod named restore-<pvc_name>, which will mount the PVC and restore data into it.

  6. Wait for the operation to complete and check the pod logs:

    kubectl -n my-app-new get pods
    kubectl -n my-app-new logs <pod_name>

    Specify <pod_name> — the name of the restore pod.

  7. Mount the restored PVC to the application in the target cluster.