KVM Backup online

Script to backup KVM VMs to backup location online

In order to move or copy the VM to a different server, you need to extract the qcow2 file to a disk location:

#!/bin/bash

# ----------- Configuration -----------
VM_NAME="your_vm_name"
[[ $# -gt 0 ]] && VM_NAME="$1"

BACKUP_DIR="/backups/kvm/${VM_NAME}"
TIMESTAMP=$(date +%F_%H-%M-%S)
SNAPSHOT_PREFIX="backup_snapshot_${TIMESTAMP}"
VM_XML_FILE="${BACKUP_DIR}/${VM_NAME}_config_${TIMESTAMP}.xml"
declare -a CREATED_SNAPSHOTS
# ------------------------------------

set -euo pipefail

# Cleanup handler in case of error or interrupt
cleanup_on_exit() {
    echo "[!] Cleanup triggered due to error or interruption."
    for SNAP_INFO in "${CREATED_SNAPSHOTS[@]}"; do
        IFS='|' read -r DEVICE DISK <<< "$SNAP_INFO"
        SNAP_PATH="${DISK}.snap"
        if [[ -f "$SNAP_PATH" ]]; then
            echo "  ✘ Removing leftover snapshot: $SNAP_PATH"
            rm -f "$SNAP_PATH"
        fi
        # Try to pivot back if snapshot is still active
        echo "  ↻ Attempting to blockcommit $DEVICE..."
        virsh blockcommit "$VM_NAME" "$DEVICE" --active --pivot 2>/dev/null || true
    done
    echo "[!] Cleanup complete. Exiting."
}
trap cleanup_on_exit ERR INT

echo "[*] Starting backup of VM: $VM_NAME"
mkdir -p "$BACKUP_DIR"

# Step 0: Save VM XML
echo "[0] Saving VM configuration..."
virsh dumpxml "$VM_NAME" > "$VM_XML_FILE"
echo "    ✔ Saved to $VM_XML_FILE"

# Step 1: Get disks
mapfile -t DISK_ENTRIES < <(virsh domblklist "$VM_NAME" --details | awk '$2 == "disk" {print $3 "|" $4}')
if [[ ${#DISK_ENTRIES[@]} -eq 0 ]]; then
    echo "[!] No disks found for VM: $VM_NAME"
    exit 1
fi

# Step 2: Snapshot
echo "[1] Creating snapshots..."
for ENTRY in "${DISK_ENTRIES[@]}"; do
    IFS='|' read -r DEVICE DISK <<< "$ENTRY"
    SNAP_PATH="${DISK}.snap"

    if [[ -f "$SNAP_PATH" ]]; then
        echo "    ⚠ Snapshot file already exists: $SNAP_PATH (removing)"
        rm -f "$SNAP_PATH"
    fi

    virsh snapshot-create-as --domain "$VM_NAME" \\
      --name "$SNAPSHOT_PREFIX" \\
      --no-metadata \\
      --atomic \\
      --disk-only \\
      --diskspec "$DEVICE",snapshot=external,file="$SNAP_PATH"

    CREATED_SNAPSHOTS+=("${DEVICE}|${DISK}")
    echo "    ✔ Created snapshot for $DEVICE ($DISK → $SNAP_PATH)"
done

# Step 3: Compress with zstd
echo "[2] Backing up disks with zstd..."
for ENTRY in "${DISK_ENTRIES[@]}"; do
    IFS='|' read -r DEVICE DISK <<< "$ENTRY"
    DISK_BASENAME=$(basename "$DISK")
    BACKUP_FILE="${BACKUP_DIR}/${VM_NAME}_${DISK_BASENAME}_${TIMESTAMP}.qcow2.zst"
    echo "    → Compressing $DISK to $BACKUP_FILE"
    zstd -T0 -19 -o "$BACKUP_FILE" "$DISK"
done

# Step 4: Blockcommit snapshots
echo "[3] Merging snapshots..."
for ENTRY in "${DISK_ENTRIES[@]}"; do
    IFS='|' read -r DEVICE DISK <<< "$ENTRY"
    virsh blockcommit "$VM_NAME" "$DEVICE" --active --pivot
    echo "    ✔ Committed snapshot for $DEVICE"
done

# Step 5: Remove snapshot files
echo "[4] Cleaning up snapshot files..."
for ENTRY in "${DISK_ENTRIES[@]}"; do
    IFS='|' read -r DEVICE DISK <<< "$ENTRY"
    SNAP_PATH="${DISK}.snap"
    if [[ -f "$SNAP_PATH" ]]; then
        rm -f "$SNAP_PATH"
        echo "    ✘ Removed $SNAP_PATH"
    fi
done

# Reset trap
trap - ERR INT
echo "[✓] Backup completed successfully for VM: $VM_NAME"

zstd -d your_vm_disk.qcow2.zst -o your_vm_disk.qcow2

and import the vm definition with:

virsh define your_vm_config.xml


Βαθμολογήστε αυτή τη καταχώρηση:

0 (0 Ψήφοι)