How to transfer data between Kubernetes Persistent Volumes (quick and dirty hack)
I've recently been using fluxv2's helm controller to deploy applications into multiple clusters. Β In one instance I was replacing a manually-created 2Gb PVC for a postgres database with a new one created with a statefulset deployed by helm. The original PVC had been created outside of the helm chart values.yaml
using existingClaim
, and so didn't have the correct name, and wasn't "adopted" by the helm release when I upgraded it (see timestamps below)
I didn't want to have to wipe the database and start from scratch though, since that would represent hours of rework, so I came up with this quick-and-dirty hack:
First, I deleted all the daemonsets and statefulsets in the namespace, leaving the PVCs remaining (but not being accessed):
root@cowboy:~# kubectl delete deployments.apps -n harbor --all
deployment.apps "harbor-chartmuseum" deleted
deployment.apps "harbor-core" deleted
deployment.apps "harbor-jobservice" deleted
deployment.apps "harbor-nginx" deleted
deployment.apps "harbor-notary-server" deleted
deployment.apps "harbor-notary-signer" deleted
deployment.apps "harbor-portal" deleted
deployment.apps "harbor-registry" deleted
root@cowboy:~# kubectl delete statefulsets.apps -n harbor --all
statefulset.apps "harbor-postgresql" deleted
statefulset.apps "harbor-redis-master" deleted
statefulset.apps "harbor-trivy" deleted
root@cowboy:~# kubectl get pvc -n harbor
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-harbor-postgresql Bound pvc-48ffeb85-4dba-4c3c-bc46-545dc49c87dd 2Gi RWO rook-ceph-block 75d
data-harbor-trivy-0 Bound pvc-7e17a7ec-c9fb-4095-9144-cc1e3ca5ceb2 5Gi RWO rook-ceph-block 75d
harbor-chartmuseum Bound pvc-9405407e-9783-4494-984f-66f1ca7cd593 5Gi RWO rook-ceph-block 75d
harbor-jobservice Bound pvc-ae39ff46-c2d2-45b8-89d0-07d9061e86ff 1Gi RWO rook-ceph-block 75d
harbor-registry Bound pvc-d6c5694c-9723-43f6-b0f7-522bde19823c 100Gi RWO rook-ceph-block 75d
root@cowboy:~# kubectl get pods -n harbor
No resources found in harbor namespace.
root@cowboy:~#
Then I created a template pod YAML using kubectl run -n harbor datamigrator --image=alpine Β -o yaml --dry-run=client > /tmp/datamigrator.yaml
. Here's what it looked like initially:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: datamigrator
name: datamigrator
spec:
containers:
- image: alpine
name: datamigrator
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
Then I edited my new /tmp/datamigrator.yaml
to include two PVCs, and updated the command/argument to sleep for an hour. Now it looks like this:
root@cowboy:~# cat /tmp/datamigrator.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: datamigrator
name: datamigrator
spec:
volumes:
- name: old
persistentVolumeClaim:
claimName: data-harbor-postgresql
- name: new
persistentVolumeClaim:
claimName: data-harbor-postgresql-0
containers:
- image: alpine
name: datamigrator
resources: {}
command: [ "/bin/sleep" ]
args: [ "1h" ]
volumeMounts:
- name: old
mountPath: /old
- name: new
mountPath: /new
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
I deployed the pod by running kubectl apply -f /tmp/datamigrator.yaml Β -n harbor
, and then exec'd into the freshly-created pod by running kubectl exec -n harbor datamigrator -it /bin/ash
.
Finally, I wiped out the contents of /new
, and moved (in hindsight, it would have been better to copy, to be safe) all the data from /old
to /new
:
root@cowboy:~# kubectl exec -n harbor datamigrator -it /bin/ash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/ # df
Filesystem 1K-blocks Used Available Use% Mounted on
overlay 51474912 38422156 10414932 79% /
tmpfs 65536 0 65536 0% /dev
tmpfs 131935904 0 131935904 0% /sys/fs/cgroup
/dev/rbd2 1998672 337928 1644360 17% /old
/dev/rbd1 8191416 104400 8070632 1% /new
/dev/mapper/cow0-var 933300992 5867160 927433832 1% /etc/hosts
/dev/mapper/cow0-var 933300992 5867160 927433832 1% /dev/termination-log
/dev/mapper/VG--nvme-containerd
51474912 38422156 10414932 79% /etc/hostname
/dev/mapper/VG--nvme-containerd
51474912 38422156 10414932 79% /etc/resolv.conf
shm 65536 0 65536 0% /dev/shm
tmpfs 131935904 12 131935892 0% /run/secrets/kubernetes.io/serviceaccount
tmpfs 131935904 0 131935904 0% /proc/acpi
tmpfs 65536 0 65536 0% /proc/kcore
tmpfs 65536 0 65536 0% /proc/keys
tmpfs 65536 0 65536 0% /proc/timer_list
tmpfs 65536 0 65536 0% /proc/sched_debug
tmpfs 131935904 0 131935904 0% /proc/scsi
tmpfs 131935904 0 131935904 0% /sys/firmware
/ # ls /old
conf data lost+found
/ # ls /new
conf data lost+found
/ # mv /^C
/ # ls /new
conf data lost+found
/ # mv /old/* /new/
mv: can't remove '/new/conf': Is a directory
mv: can't remove '/new/data': Is a directory
mv: can't remove '/new/lost+found': Is a directory
/ # rm -rf /new/*
/ # mv /old/* /new/
/ # exit
root@cowboy:~#
Having finished with the datamigrator pod, I deleted it, and re-deployed my helm chart. The postgres data is found in the new PVC, and I deleted the old (and now empty) PVC.