Skip to content

Instantly share code, notes, and snippets.

@caruccio
Last active April 17, 2024 20:13
Show Gist options
  • Save caruccio/be825aa39d53535217494369cc793dbd to your computer and use it in GitHub Desktop.
Save caruccio/be825aa39d53535217494369cc793dbd to your computer and use it in GitHub Desktop.
Migrate EBS Volume based PVs across AWS availability zones
#!/bin/bash
if [ $# -lt 6 ]; then
echo "Usage: $0 [source-namespace] [source-pvc-name] [target-namespace] [target-pvc-name] [target-aws-zone] [target-pv-name] [kind/workload=None]"
echo "Clone EBS, PV and PVC from source to target. Will stop kind/workload if defined."
exit
fi
set -eu
SOURCE_NAMESPACE=$1
SOURCE_PVCNAME=$2
TARGET_NAMESPACE=$3
TARGET_PVCNAME=$4
TARGET_ZONE=$5
TARGET_PVNAME=$6
if [ $# -gt 6 ]; then
DEPLOYMENTOBJ=$7
REPLICAS=$(kubectl -n $SOURCE_NAMESPACE get $DEPLOYMENTOBJ --template={{.spec.replicas}})
else
DEPLOYMENTOBJ=""
REPLICAS=0
fi
## Nao precisa mexer a partir daqui
SOURCE_PVNAME=$(kubectl -n $SOURCE_NAMESPACE get pvc $SOURCE_PVCNAME --template={{.spec.volumeName}})
SOURCE_VOLUMEID=$(kubectl -n $SOURCE_NAMESPACE get pv $SOURCE_PVNAME --template='{{or .spec.awsElasticBlockStore.volumeID ""}}{{or .spec.csi.volumeHandle ""}}' | awk -F/ '{print $NF}')
SOURCE_STORAGE=$(kubectl -n $SOURCE_NAMESPACE get pvc $SOURCE_PVCNAME --template={{.spec.resources.requests.storage}})
SOURCE_VOLUMEMODE=$(kubectl -n $SOURCE_NAMESPACE get pv $SOURCE_PVNAME --template={{.spec.volumeMode}})
if [ -z "$SOURCE_VOLUMEMODE" ]; then
SOURCE_VOLUMEMODE=Filesystem
fi
TARGET_STORAGE=$SOURCE_STORAGE
TARGET_VOLUMEMODE=$SOURCE_VOLUMEMODE
cat <<EOF
Summary:
${SOURCE_NAMESPACE@A}
${SOURCE_PVCNAME@A}
${SOURCE_PVNAME@A}
${SOURCE_VOLUMEID@A}
${SOURCE_STORAGE@A}
${SOURCE_VOLUMEMODE@A}
${TARGET_NAMESPACE@A}
${TARGET_PVCNAME@A}
${TARGET_PVNAME@A}
${TARGET_ZONE@A}
${TARGET_STORAGE@A}
${TARGET_VOLUMEMODE@A}
${DEPLOYMENTOBJ@A}
${REPLICAS@A}
EOF
read -p 'Press ENTER to continue'
echo
if [ -v DEPLOYMENTOBJ ] && [ $REPLICAS -gt 0 ]; then
echo "Scaling down $DEPLOYMENTOBJ: $REPLICAS -> 0"
kubectl -n $SOURCE_NAMESPACE scale --replicas=0 $DEPLOYMENTOBJ
while true; do
r="$(kubectl -n $SOURCE_NAMESPACE get $DEPLOYMENTOBJ --template={{.status.replicas}})"
[ "$r" == "0" ] && break || true
[ "$r" == "<no value>" ] && break || true
echo waiting pods to die...
sleep 1
done
while sleep 0.1; do
kubectl -n $SOURCE_NAMESPACE get pod --no-headers
read -p "Press ENTER to continue" -t 3 || { echo; continue; }
break
done
fi
DESCRIPTION="cloned from ns=${SOURCE_NAMESPACE}, pvc=${SOURCE_PVCNAME}, pv=$SOURCE_PVNAME, volumeId=$SOURCE_VOLUMEID"
echo "Waiting volume $SOURCE_VOLUMEID to become available..."
echo "Use \`aws ec2 detach-volume --volume-id $SOURCE_VOLUMEID\` to force detach"
aws ec2 wait volume-available --volume-id $SOURCE_VOLUMEID
echo "Creating snapshot from $SOURCE_VOLUMEID... "
SNAPSHOTID=$(aws ec2 create-snapshot --volume-id $SOURCE_VOLUMEID --description "$DESCRIPTION" --output text --query SnapshotId)
aws ec2 wait snapshot-completed --filter Name=snapshot-id,Values=$SNAPSHOTID
echo ${SNAPSHOTID@A}
echo "Creating volume from snapshot $SNAPSHOTID... "
TAGSPEC="ResourceType=volume,Tags=[{Key=Name,Value=$TARGET_NAMESPACE-$TARGET_PVNAME},{Key=kubernetes.io/created-for/pv/name,Value=$TARGET_PVNAME},{Key=kubernetes.io/created-for/pvc/name,Value=$TARGET_PVCNAME},{Key=kubernetes.io/created-for/pvc/namespace,Value=$TARGET_NAMESPACE}]"
TARGET_VOLUMEID=$(aws ec2 create-volume \
--availability-zone $TARGET_ZONE \
--snapshot-id $SNAPSHOTID \
--volume-type gp2 \
--output text \
--query VolumeId \
--tag-specifications "$TAGSPEC")
echo ${TARGET_VOLUMEID@A}
echo Creating new PV/PVC...
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: $TARGET_PVCNAME
namespace: $TARGET_NAMESPACE
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: ${TARGET_STORAGE}
volumeMode: ${TARGET_VOLUMEMODE}
volumeName: ${TARGET_PVNAME}
---
apiVersion: v1
kind: PersistentVolume
metadata:
labels:
failure-domain.beta.kubernetes.io/region: ${TARGET_ZONE:0:-1}
failure-domain.beta.kubernetes.io/zone: $TARGET_ZONE
name: ${TARGET_PVNAME}
spec:
accessModes:
- ReadWriteOnce
awsElasticBlockStore:
fsType: ext4
volumeID: aws://$TARGET_ZONE/$TARGET_VOLUMEID
capacity:
storage: ${TARGET_STORAGE}
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: $TARGET_PVCNAME
namespace: $TARGET_NAMESPACE
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
EOF
if [ -v DEPLOYMENTOBJ ]; then
echo "Now \`kubeclt edit $DEPLOYMENTOBJ\` to use new pvc/$TARGET_PVCNAME and then \`kubectl scale --replicas=1 $DEPLOYMENTOBJ\`"
fi
#if [ -v DEPLOYMENTOBJ ] && [ $REPLICAS -gt 0 ]; then
# echo "Scaling back $DEPLOYMENTOBJ: 0 -> $REPLICAS"
# kubectl -n $SOURCE_NAMESPACE scale --replicas=$REPLICAS $DEPLOYMENTOBJ
#fi
@caruccio
Copy link
Author

A good alternative is this tool: https://github.com/utkuozdemir/pv-migrate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment