2 Commits
v0.2 ... v0.3

Author SHA1 Message Date
Bastian
0cee976786 Add lookup, in case pve poolname doesn't match Ceph poolname 2022-10-21 19:38:07 +02:00
Bastian
aadf7e656c Add stuff to readme 2022-10-21 18:18:24 +02:00
2 changed files with 67 additions and 17 deletions

View File

@@ -43,22 +43,32 @@ Report bugs to the Github repo at https://github.com/lephisto/crossover/
## Introduction ## Introduction
When working with hyperconverges Proxmox HA Clusters you sometimes need to get VMs migrated When working with hyperconverged Proxmox HA Clusters you sometimes need to get VMs migrated to another cluster, or have a cold-standby copy of a VM ready to start there in case your main Datacenter goes boom. Crossover implements functionality that enables you to do the following:
to another cluster, or have a cold-standby copy of a VM ready to start there. Crossover implements
functions that enable you to do the following:
- Transfer a non-running VM to another Cluster - Transfer a non-running VM to another Cluster
- Transfer a running VM to another Cluster - Transfer a running VM to another Cluster
- Continuously update a previously tranferred VM in another Cluster with incemental snapshots - Continuously update a previously tranferred VM in another Cluster with incemental snapshots
Backup And Restore Ceph for Proxmox VE with retention. This solution implements
a snapshotbackup for Ceph cluster exporting to specific directory. The mechanism using
Ceph snapshot, export and export differential. In backup export image and config
file VM/CT.
Currently this only works with Ceph based storage backends, since the incremental logic heavily Currently this only works with Ceph based storage backends, since the incremental logic heavily
relies on Rados block device features. relies on Rados block device features.
It'll work according this scheme:
```
.:::::::::. .:::::::::.
|Cluster-A| |Cluster-B|
| | | |
| _______ | rbd export-diff [..] | ssh pve04 | rbd import-diff [..] | _______ |
| pve01 -|-----------------------------------------------------------|->pve04 |
| _______ | | _______ |
| pve02 | | pve05 |
| _______ | | _______ |
| pve03 | | pve06 |
| _______ | | _______ |
| | | |
|:::::::::| |:::::::::|
```
## Main features ## Main features
* Currently only for KVM. I might add LXC support when I need to. * Currently only for KVM. I might add LXC support when I need to.
@@ -89,6 +99,32 @@ Mirror VM to another Cluster:
``` ```
root@pve01:~/crossover# ./crossover mirror --vmid=100:10100 --destination=pve04 --pool=data2 --keeplocal=4 --keepremote=8 --overwrite --keep-dlock --online root@pve01:~/crossover# ./crossover mirror --vmid=100:10100 --destination=pve04 --pool=data2 --keeplocal=4 --keepremote=8 --overwrite --keep-dlock --online
Start mirror 2022-10-21 18:09:36
Transmitting Config for VM 100 to desination 10100
update VM 100: -lock backup
update VM 10100: -lock backup
VM 100 - Issuing fsfreeze-freeze to 100 on pve01
2
VM 100 - Creating snapshot data/vm-100-disk-0@mirror-20221021180936
Creating snap: 100% complete...done.
VM 100 - Creating snapshot data/vm-100-disk-1@mirror-20221021180936
Creating snap: 100% complete...done.
VM 100 - Issuing fsfreeze-thaw to 100 on pve01
2
Exporting image: 100% complete...done.
Importing image diff: 100% complete...done.
Houskeeping localhost data vm-100-disk-0, keeping previous 4 Snapshots
Removing snap: 100% complete...done.
Houskeeping pve04 data2 vm-10100-disk-0, keeping previous 8 Snapshots
Exporting image: 100% complete...done.
Importing image diff: 100% complete...done.
Houskeeping localhost data vm-100-disk-1, keeping previous 4 Snapshots
Removing snap: 100% complete...done.
Houskeeping pve04 data2 vm-10100-disk-1, keeping previous 8 Snapshots
Unlocking source VM 100
root@pve01:~/crossover#
``` ```
This example creates a mirror of VM 100 (in the source cluster) as VM 10100 (in the destination cluster) using the ceph pool "data2" for storing all attached disks. It will keep 4 Ceph snapshots prior the latest (in total 5) and 8 snapshots on the remote cluster. It will keep the VM on the target Cluster locked to avoid an accidental start (thus causing split brain issues), and will do it even if the source VM is running. This example creates a mirror of VM 100 (in the source cluster) as VM 10100 (in the destination cluster) using the ceph pool "data2" for storing all attached disks. It will keep 4 Ceph snapshots prior the latest (in total 5) and 8 snapshots on the remote cluster. It will keep the VM on the target Cluster locked to avoid an accidental start (thus causing split brain issues), and will do it even if the source VM is running.

View File

@@ -5,7 +5,7 @@
# Cross Pool Migration and incremental replication Tool for Proxmox VMs using Ceph. # Cross Pool Migration and incremental replication Tool for Proxmox VMs using Ceph.
# Author: Bastian Mäuser <bma@netz.org> # Author: Bastian Mäuser <bma@netz.org>
declare -r VERSION=0.2 declare -r VERSION=0.3
declare -r NAME=$(basename "$0") declare -r NAME=$(basename "$0")
declare -r PROGNAME=${NAME%.*} declare -r PROGNAME=${NAME%.*}
@@ -163,6 +163,13 @@ function exist_file(){
done done
} }
function lookupcephpool() {
pvehost=$1
pvepoolname=$2
res=$(ssh $pvehost cat /etc/pve/storage.cfg | sed -n "/rbd: $pvepoolname/,/^$/p" | grep pool | cut -d " " -f 2)
echo $res
}
function get_vm_ids(){ function get_vm_ids(){
local data='' local data=''
local conf='' local conf=''
@@ -325,11 +332,15 @@ function mirror() {
fi fi
log info "Transmitting Config for VM $vm_id to desination $dvmid" log info "Transmitting Config for VM $vm_id to desination $dvmid"
rewriteconfig $PVE_NODES/"${pvnode[$vm_id]}"/$QEMU/"$vm_id".conf $opt_destination "$opt_pool" $PVE_NODES/"$opt_destination"/$QEMU/"$dvmid".conf "$dvmid" rewriteconfig $PVE_NODES/"${pvnode[$vm_id]}"/$QEMU/"$vm_id".conf $opt_destination "$opt_pool" $PVE_NODES/"$opt_destination"/$QEMU/"$dvmid".conf "$dvmid"
map_vmids_to_dsthost "$opt_destination"
fi fi
#Lock on source + destination #Lock on source + destination
if [ $opt_lock -eq 1 ]; then if [ $opt_lock -eq 1 ]; then
ssh root@"${pvnode[$vm_id]}" qm set "$vm_id" --lock backup ssh root@"${pvnode[$vm_id]}" qm set "$vm_id" --lock backup
fi
if [ $opt_lock -eq 1 ]; then
ssh root@"${dstpvnode[$dvmid]}" qm set "$dvmid" --lock backup ssh root@"${dstpvnode[$dvmid]}" qm set "$dvmid" --lock backup
fi fi
@@ -348,10 +359,13 @@ function mirror() {
dst_image_spec=$(echo $src_image_spec | sed -r -e "s/([a-zA-Z0-9]+\/[a-zA-Z0-9]+\-)([0-9]+)(\-[a-zA-Z0-9]+\-[0-9]+)/\1$dvmid\3/") dst_image_spec=$(echo $src_image_spec | sed -r -e "s/([a-zA-Z0-9]+\/[a-zA-Z0-9]+\-)([0-9]+)(\-[a-zA-Z0-9]+\-[0-9]+)/\1$dvmid\3/")
[ -z "$dst_image_spec" ] && continue [ -z "$dst_image_spec" ] && continue
[[ $disk =~ $recephimg ]] [[ $disk =~ $recephimg ]]
src_image_pool=${BASH_REMATCH[1]} #src_image_pool=${BASH_REMATCH[1]}
src_image_pool=$(lookupcephpool "localhost" ${BASH_REMATCH[1]})
src_image_name=${BASH_REMATCH[2]} src_image_name=${BASH_REMATCH[2]}
[[ $dst_image_spec =~ ^[a-zA-Z0-9]+\/(.*)$ ]] [[ $dst_image_spec =~ ^[a-zA-Z0-9]+\/(.*)$ ]]
dst_image_name=${BASH_REMATCH[1]} dst_image_name=${BASH_REMATCH[1]}
dst_image_pool=$(lookupcephpool $opt_destination $opt_pool)
echo "dst_image_pool: $dst_image_pool"
snapshot_name="@$opt_snapshot_prefix$timestamp" snapshot_name="@$opt_snapshot_prefix$timestamp"
localsnapcount=$(rbd ls -l $src_image_pool | grep $src_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1|wc -l) localsnapcount=$(rbd ls -l $src_image_pool | grep $src_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1|wc -l)
if [ $localsnapcount -ge 2 ]; then if [ $localsnapcount -ge 2 ]; then
@@ -359,7 +373,7 @@ function mirror() {
currentlocal=$(rbd ls -l $src_image_pool | grep $src_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1|tail -n 1) currentlocal=$(rbd ls -l $src_image_pool | grep $src_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1|tail -n 1)
localts=$(rbd ls -l $src_image_pool | grep $src_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1 | sed -r -e 's/.*@mirror-(.*)/\1/') localts=$(rbd ls -l $src_image_pool | grep $src_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1 | sed -r -e 's/.*@mirror-(.*)/\1/')
fi fi
latestremote=$(ssh $opt_destination rbd ls -l $opt_pool | grep $dst_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1|tail -n 1) latestremote=$(ssh $opt_destination rbd ls -l $dst_image_pool | grep $dst_image_name@$opt_snapshot_prefix | cut -d ' ' -f 1|tail -n 1)
if [ $latestremote ]; then if [ $latestremote ]; then
[[ $latestremote =~ ^.*@$opt_snapshot_prefix([0-9]+)$ ]] [[ $latestremote =~ ^.*@$opt_snapshot_prefix([0-9]+)$ ]]
latestremotets=${BASH_REMATCH[1]} latestremotets=${BASH_REMATCH[1]}
@@ -370,24 +384,24 @@ function mirror() {
done done
fi fi
if [ -z $basets ]; then if [ -z $basets ]; then
log debug "No matching Snapshot found on destination - Full Copy $src_image_pool/$src_image_name$snapshot_name to $opt_pool/$dst_image_name" log debug "No matching Snapshot found on destination - Full Copy $src_image_pool/$src_image_name$snapshot_name to $dst_image_pool/$dst_image_name"
xmitjob="rbd export --rbd-concurrent-management-ops 8 $src_image_pool/$src_image_name$snapshot_name --no-progress -|pv -r|ssh $opt_destination rbd import --image-format 2 - $opt_pool/$dst_image_name" xmitjob="rbd export --rbd-concurrent-management-ops 8 $src_image_pool/$src_image_name$snapshot_name --no-progress -|pv -r|ssh $opt_destination rbd import --image-format 2 - $dst_image_pool/$dst_image_name"
# create initial snapshot on destination # create initial snapshot on destination
if ! do_run $xmitjob; then if ! do_run $xmitjob; then
log error "Transmitting Image failed" log error "Transmitting Image failed"
return 1 return 1
fi fi
cmd="ssh $opt_destination rbd snap create $opt_pool/$dst_image_name$snapshot_name" cmd="ssh $opt_destination rbd snap create $dst_image_pool/$dst_image_name$snapshot_name"
do_run $cmd do_run $cmd
else else
log debug "Basecopy + snapshot on destination - let's just transfer the diff" log debug "Basecopy + snapshot on destination - let's just transfer the diff"
xmitjob="rbd export-diff --from-snap $opt_snapshot_prefix$basets $src_image_pool/$currentlocal - | ssh $opt_destination rbd import-diff - $opt_pool/$dst_image_name" xmitjob="rbd export-diff --from-snap $opt_snapshot_prefix$basets $src_image_pool/$currentlocal - | ssh $opt_destination rbd import-diff - $dst_image_pool/$dst_image_name"
if ! do_run $xmitjob; then if ! do_run $xmitjob; then
log error "Transmitting Image failed" log error "Transmitting Image failed"
return 1 return 1
fi fi
do_housekeeping "localhost" "$src_image_pool" "$src_image_name" $opt_keep_local do_housekeeping "localhost" "$src_image_pool" "$src_image_name" $opt_keep_local
do_housekeeping "$opt_destination" "$opt_pool" "$dst_image_name" $opt_keep_remote do_housekeeping "$opt_destination" "$dst_image_pool" "$dst_image_name" $opt_keep_remote
fi fi
done done
if [ ! $opt_keepslock -eq 1 ]; then if [ ! $opt_keepslock -eq 1 ]; then