Recently I have been testing different storage backends (like Rancher Longhorn, Rook, NFS, etc.) for Kubernetes. Since I'm switching pretty frequently, I needed a simple way to migrate or copy data from one pvc to another.

  1. Make sure both PVCs are created and have PVs associated to them
  2. Make sure backups are working and current in case the wrong PVC is deleted
  3. Stop any pods currently using either PVC
  4. Save the script below as migrate-pvc.sh and make it executable
  5. Run the script like ./migrate-pvc.sh old_pvc_id new_pvc_id (double check what the script does and make sure you put things in the right order, or you'll end up deleting your old/existing pvc)
  6. Watch the logs for the pod created by the new job
  7. Once the pod completes, check the log for errors/etc
  8. Delete the old pvc, update deployment specs to point to the new pvc
#!/bin/bash
# See https://justyn.io/til/migrate-kubernetes-pvc-to-another-pvc/ for details

set -exu

src=$1
dst=$2

echo "Creating job yaml"
cat > migrate-job.yaml << EOF
apiVersion: batch/v1
kind: Job
metadata:
  name: migrate-pv-$src
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: debian
        command: [ "/bin/bash", "-c" ]
        args:
          -
            apt-get update && apt-get install -y rsync &&
            ls -lah /src_vol /dst_vol &&
            df -h &&
            rsync -avPS --delete /src_vol/ /dst_vol/ &&
            ls -lah /dst_vol/ &&
            du -shxc /src_vol/ /dst_vol/
        volumeMounts:
        - mountPath: /src_vol
          name: src
          readOnly: true
        - mountPath: /dst_vol
          name: dst
      restartPolicy: Never
      volumes:
      - name: src
        persistentVolumeClaim:
          claimName: $src
      - name: dst
        persistentVolumeClaim:
          claimName: $dst
  backoffLimit: 1
EOF

kubectl create -f migrate-job.yaml
kubectl get jobs -o wide
kubectl get pods | grep migrate