Difference between revisions of "Pvc migration testing"

From UVOO Tech Wiki
Jump to navigation Jump to search
(Created page with "# Migrate many PVCs from one storage class to another in same namespace Use these scripts for migration and testing ## create-test-pvc.sh ``` #!/bin/bash set -eu NS=${1:-d...")
 
 
Line 61: Line 61:
 
SRC_SC="${2:?Source storage class required}"
 
SRC_SC="${2:?Source storage class required}"
 
DEST_SC="${3:?Destination storage class required}"
 
DEST_SC="${3:?Destination storage class required}"
 +
SINGLE_PVC="${4:-}" # optional fourth arg
  
pvcs=$(kubectl get pvc -n "$NS" -o jsonpath='{range .items[*]}{.metadata.name}{"|"}{.spec.storageClassName}{"|"}{.spec.resources.requests.storage}{"\n"}{end}' | awk -F'|' -v sc="$SRC_SC" '$2==sc{print $1 "|" $3}')
+
get_matching_pvcs() {
 +
  if [[ -n "$SINGLE_PVC" ]]; then
 +
    size=$(kubectl get pvc "$SINGLE_PVC" -n "$NS" -o jsonpath='{.spec.resources.requests.storage}')
 +
    sc=$(kubectl get pvc "$SINGLE_PVC" -n "$NS" -o jsonpath='{.spec.storageClassName}')
 +
    if [[ "$sc" == "$SRC_SC" ]]; then
 +
      echo "$SINGLE_PVC|$size"
 +
    else
 +
      echo "❌ PVC '$SINGLE_PVC' does not use storageClass '$SRC_SC'" >&2
 +
      exit 1
 +
    fi
 +
  else
 +
    kubectl get pvc -n "$NS" -o jsonpath='{range .items[*]}{.metadata.name}{"|"}{.spec.storageClassName}{"|"}{.spec.resources.requests.storage}{"\n"}{end}' |
 +
      awk -F'|' -v sc="$SRC_SC" '$2==sc{print $1 "|" $3}'
 +
  fi
 +
}
 +
 
 +
pvcs=$(get_matching_pvcs)
  
 
if [[ -z "$pvcs" ]]; then
 
if [[ -z "$pvcs" ]]; then
   echo "No PVCs found in namespace $NS with storage class $SRC_SC"
+
   echo "No matching PVCs found"
 
   exit 0
 
   exit 0
 
fi
 
fi
Line 74: Line 91:
 
   tmp_pvc="${pvc}-tmp"
 
   tmp_pvc="${pvc}-tmp"
  
   echo "🔷 Scaling down deployments/statefulsets using PVC $pvc..."
+
   echo "🔷 Scaling down workloads using PVC $pvc..."
   # scale down deployments
+
   scaled_objects=()
   for deploy in $(kubectl get deploy -n "$NS" -o name | xargs -n1); do
+
   for obj in $(kubectl get deploy,sts -n "$NS" -o name); do
     if kubectl get "$deploy" -n "$NS" -o json | grep -q "$pvc"; then
+
     if kubectl get "$obj" -n "$NS" -o json | grep -q "$pvc"; then
       echo "Scaling $deploy to 0"
+
       echo "Scaling $obj to 0"
       kubectl scale "$deploy" -n "$NS" --replicas=0
+
       kubectl scale "$obj" -n "$NS" --replicas=0
    fi
+
      scaled_objects+=("$obj")
  done
 
  # scale down statefulsets
 
  for sts in $(kubectl get sts -n "$NS" -o name | xargs -n1); do
 
    if kubectl get "$sts" -n "$NS" -o json | grep -q "$pvc"; then
 
      echo "Scaling $sts to 0"
 
      kubectl scale "$sts" -n "$NS" --replicas=0
 
 
     fi
 
     fi
 
   done
 
   done
Line 110: Line 121:
 
     --dest "$tmp_pvc" \
 
     --dest "$tmp_pvc" \
 
     -N "$NS" \
 
     -N "$NS" \
 +
    --strategies mnt2,svc \
 
     --compress \
 
     --compress \
 
     --ignore-mounted
 
     --ignore-mounted
Line 142: Line 154:
 
   kubectl delete pvc "$tmp_pvc" -n "$NS"
 
   kubectl delete pvc "$tmp_pvc" -n "$NS"
  
   echo "🔷 Scaling up deployments/statefulsets using PVC $pvc..."
+
   echo "🔷 Scaling workloads back up..."
   for deploy in $(kubectl get deploy -n "$NS" -o name | xargs -n1); do
+
   for obj in "${scaled_objects[@]}"; do
    if kubectl get "$deploy" -n "$NS" -o json | grep -q "$pvc"; then
+
     echo "Scaling $obj to 1"
      replicas=$(kubectl get "$deploy" -n "$NS" -o jsonpath='{.spec.replicas}')
+
    kubectl scale "$obj" -n "$NS" --replicas=1
      echo "Scaling $deploy to $replicas"
 
      kubectl scale "$deploy" -n "$NS" --replicas="$replicas"
 
    fi
 
  done
 
  for sts in $(kubectl get sts -n "$NS" -o name | xargs -n1); do
 
     if kubectl get "$sts" -n "$NS" -o json | grep -q "$pvc"; then
 
      replicas=$(kubectl get "$sts" -n "$NS" -o jsonpath='{.spec.replicas}')
 
      echo "Scaling $sts to $replicas"
 
      kubectl scale "$sts" -n "$NS" --replicas="$replicas"
 
    fi
 
 
   done
 
   done
  
 
   echo "✅ Migration of PVC $pvc complete."
 
   echo "✅ Migration of PVC $pvc complete."
 
done
 
done
 +
```
 +
 +
### example
 +
```
 +
./swap-storage-class.sh prometheus managed-csi-hdd standardssd-zrs prometheus-server
 
```
 
```
  

Latest revision as of 23:23, 23 July 2025

Migrate many PVCs from one storage class to another in same namespace

Use these scripts for migration and testing

create-test-pvc.sh

#!/bin/bash
set -eu

NS=${1:-default}
SC=${2:-managed-csi-hdd}
PVC_NAME=test-pvc
POD_NAME=test-pod

cat <<EOF | kubectl apply -n $NS -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: $PVC_NAME
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 1Gi
EOF

cat <<EOF | kubectl apply -n $NS -f -
apiVersion: v1
kind: Pod
metadata:
  name: $POD_NAME
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["sleep", "3600"]
    volumeMounts:
    - name: vol
      mountPath: /data
  volumes:
  - name: vol
    persistentVolumeClaim:
      claimName: $PVC_NAME
EOF

kubectl wait --for=condition=Ready pod/$POD_NAME -n $NS --timeout=60s
kubectl exec -n $NS $POD_NAME -- sh -c 'echo "This is a test." > /data/test.txt'

# kubectl delete pod/$POD_NAME pvc/$PVC_NAME -n $NS
kubectl delete pod/$POD_NAME -n $NS

swap-storage-class.sh

#!/bin/bash
set -euo pipefail

NS="${1:?Namespace required}"
SRC_SC="${2:?Source storage class required}"
DEST_SC="${3:?Destination storage class required}"
SINGLE_PVC="${4:-}" # optional fourth arg

get_matching_pvcs() {
  if [[ -n "$SINGLE_PVC" ]]; then
    size=$(kubectl get pvc "$SINGLE_PVC" -n "$NS" -o jsonpath='{.spec.resources.requests.storage}')
    sc=$(kubectl get pvc "$SINGLE_PVC" -n "$NS" -o jsonpath='{.spec.storageClassName}')
    if [[ "$sc" == "$SRC_SC" ]]; then
      echo "$SINGLE_PVC|$size"
    else
      echo "❌ PVC '$SINGLE_PVC' does not use storageClass '$SRC_SC'" >&2
      exit 1
    fi
  else
    kubectl get pvc -n "$NS" -o jsonpath='{range .items[*]}{.metadata.name}{"|"}{.spec.storageClassName}{"|"}{.spec.resources.requests.storage}{"\n"}{end}' |
      awk -F'|' -v sc="$SRC_SC" '$2==sc{print $1 "|" $3}'
  fi
}

pvcs=$(get_matching_pvcs)

if [[ -z "$pvcs" ]]; then
  echo "No matching PVCs found"
  exit 0
fi

for line in $pvcs; do
  pvc=$(cut -d'|' -f1 <<<"$line")
  size=$(cut -d'|' -f2 <<<"$line")
  tmp_pvc="${pvc}-tmp"

  echo "🔷 Scaling down workloads using PVC $pvc..."
  scaled_objects=()
  for obj in $(kubectl get deploy,sts -n "$NS" -o name); do
    if kubectl get "$obj" -n "$NS" -o json | grep -q "$pvc"; then
      echo "Scaling $obj to 0"
      kubectl scale "$obj" -n "$NS" --replicas=0
      scaled_objects+=("$obj")
    fi
  done

  echo "🔷 Creating temporary PVC $tmp_pvc with $DEST_SC..."
  cat <<EOF | kubectl apply -n "$NS" -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: $tmp_pvc
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: $size
  storageClassName: $DEST_SC
EOF

  echo "🔷 Migrating data from $pvc -> $tmp_pvc..."
  pv-migrate \
    --source "$pvc" \
    -n "$NS" \
    --dest "$tmp_pvc" \
    -N "$NS" \
    --strategies mnt2,svc \
    --compress \
    --ignore-mounted

  echo "🔷 Deleting original PVC $pvc..."
  kubectl delete pvc "$pvc" -n "$NS"

  echo "🔷 Re-creating original PVC $pvc with $DEST_SC..."
  cat <<EOF | kubectl apply -n "$NS" -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: $pvc
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: $size
  storageClassName: $DEST_SC
EOF

  echo "🔷 Migrating data back from $tmp_pvc -> $pvc..."
  pv-migrate \
    --source "$tmp_pvc" \
    -n "$NS" \
    --dest "$pvc" \
    -N "$NS" \
    --compress \
    --ignore-mounted

  echo "🔷 Deleting temporary PVC $tmp_pvc..."
  kubectl delete pvc "$tmp_pvc" -n "$NS"

  echo "🔷 Scaling workloads back up..."
  for obj in "${scaled_objects[@]}"; do
    echo "Scaling $obj to 1"
    kubectl scale "$obj" -n "$NS" --replicas=1
  done

  echo "✅ Migration of PVC $pvc complete."
done

example

./swap-storage-class.sh prometheus managed-csi-hdd standardssd-zrs prometheus-server

create-test-pod-and-mount.yaml

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-pvc-pod
spec:
  volumes:
    - name: my-pvc-storage
      persistentVolumeClaim:
        claimName: test-pvc # Replace with the name of your existing PVC
  containers:
    - name: ubuntu-container
      image: ubuntu:latest
      command: ["sleep", "infinity"]
      volumeMounts:
        - name: my-pvc-storage
          mountPath: /data # Replace with the desired mount path inside the container (e.g., /mnt/data)