This repo contains sample kubevirt resources for deployment in Kubernetes or OpenShift clusters.
Use ACM console to deploy the VM, enable DR or delete the VM.
-
Create new application using:
- repo: this repo URL
- branch: main
- path: one of the
vm-*-odr-*directories
-
To enable DR assign DR Policy
Use ACM console to perform failover or relocate actions.
Use ACM console to delete the application.
In Kubernetes you need to deploy the VM and DR resources using the command line tools or API. In this example we use the ramen testing environment.
Ramen test environment creates 3 minikube clusters (hub, dr1, dr2) on your laptop, including OCM, Rook, Kubevirt, CDI, and many other components required by Ramen.
See the User quick start guide for complete instructions.
Important
When starting the environment, use the regional-dr-kubvirt.yaml
configuration.
If you want to inject your SSH key into the VM, you need to replace the included SSH public key with your own public key.
- Fork this repo in github
- Replace the contents of the
vm-standalone-pvc-k8s/test_rsa.pubwith your public key (e.g.~/.ssh/id_rsa.pub) - Update
channel/channel.yamlto point to your repository (e.g. https://github.com/my-github-user/ocm-kubevirt-samples.git) - If you are not using the
mainbranch updatesubscription/subscription.yamlto point to the right branch.
To start the VM deploy the subscription:
kubectl apply -k subscription --context hubThe subscription starts the VM vm-standalone-pvc-k8s on one of the
clusters in the default clusterset.
The subscription is optimized for Ramen minikube based test environment. To use in another setup you may need to modify the resources.
To find where the VM was placed look at the PlacementDecisions status:
kubectl get placementdecisions -n kubevirt-sample --context hub \
-o jsonpath='{.items[0].status.decisions[0].clusterName}{"\n"}'To inspect the VM and DR resources use:
watch -n 5 kubectl get vm,vmi,pod,pvc,vrg,vr -n kubevirt-sample --context dr1Example output:
Every 5.0s: kubectl get vm,vmi,pod,pvc,vrg,vr -n kubevirt-sample --context dr1
NAME AGE STATUS READY
virtualmachine.kubevirt.io/sample-vm 5m51s Running True
NAME AGE PHASE IP NODENAME READY
virtualmachineinstance.kubevirt.io/sample-vm 5m51s Running 10.244.0.61 dr1 True
NAME READY STATUS RESTARTS AGE
pod/virt-launcher-sample-vm-chsrh 1/1 Running 0 5m51s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/sample-vm-pvc Bound pvc-149bd414-c1b8-443c-90f7-7e30fc519eb4 128Mi RWX rook-ceph-block 5m51sAt this point there there are no vrg and vr resources, since we did
not enable DR for the VM yet.
We can inspect the underlying RBD image backing the VM PVC using the
rook-ceph kubectl krew plugin:
kubectl rook-ceph --context dr1 rbd du -p replicapool
Example output:
NAME PROVISIONED USED
csi-vol-a3fdb384-2e31-49f1-bd48-a97b2d79f981 128 MiB 80 MiBTo allow Ramen to protect the VM, you need to disable OCM scheduling by adding an annotation to the VM placement:
kubectl annotate placement kubevirt-placement \
cluster.open-cluster-management.io/experimental-scheduling-disable=true \
--namespace kubevirt-sample \
--context hubDeploy the DR resources to enable DR:
kubectl apply -k dr --context hubAt this point Ramen controls the VM placement and protects the VM data by replicating it to the secondary cluster ("dr2").
To wait until the VM data is replicating to the secondary cluster, wait
for the PeerReady condition:
kubectl wait drpc kubevirt-drpc \
--for condition=PeerReady \
--namespace kubevirt-sample \
--timeout 5m \
--context hubWe can inspect the VM DR status using the DRPlacementControl resource
on the hub cluster:
watch -n 5 kubectl get drpc -n kubevirt-sample --context hub -o wideExample output:
Every 5.0s: kubectl get drpc -n kubevirt-sample --context hub -o wide
NAME AGE PREFERREDCLUSTER FAILOVERCLUSTER DESIREDSTATE CURRENTSTATE PROGRESSION START TIME DURATION PEER READY
kubevirt-drpc 51s dr1 Deployed Completed 2023-11-19T20:26:53Z 5.035609263s TrueTo get more details we can watch the VM and DR reosurces on the managed cluster:
watch -n 5 kubectl get vm,vmi,pod,pvc,vrg,vr -n kubevirt-sample --context dr1Example output:
Every 5.0s: kubectl get vm,vmi,pod,pvc,vrg,vr -n kubevirt-sample --context dr1
NAME AGE STATUS READY
virtualmachine.kubevirt.io/sample-vm 16m Running True
NAME AGE PHASE IP NODENAME READY
virtualmachineinstance.kubevirt.io/sample-vm 16m Running 10.244.0.61 dr1 True
NAME READY STATUS RESTARTS AGE
pod/virt-launcher-sample-vm-chsrh 1/1 Running 0 16m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/sample-vm-pvc Bound pvc-149bd414-c1b8-443c-90f7-7e30fc519eb4 128Mi RWX rook-ceph-block 16m
NAME DESIREDSTATE CURRENTSTATE
volumereplicationgroup.ramendr.openshift.io/kubevirt-drpc primary Primary
NAME AGE VOLUMEREPLICATIONCLASS PVCNAME DESIREDSTATE CURRENTSTATE
volumereplication.replication.storage.openshift.io/sample-vm-pvc 2m46s vrc-sample sample-vm-pvc primary PrimaryThe cirros VM used by this example includes a logger service logging a message every 10 seconds:
virtctl ssh cirros@sample-vm -n kubevirt-sample --known-hosts= --context dr1 -c 'head /var/log/ramen.log'Example output:
Sun Nov 19 20:13:20 UTC 2023 START uptime=3.33
Sun Nov 19 20:13:30 UTC 2023 UPDATE
Sun Nov 19 20:13:40 UTC 2023 UPDATE
Sun Nov 19 20:13:50 UTC 2023 UPDATE
Sun Nov 19 20:14:00 UTC 2023 UPDATE
Sun Nov 19 20:14:10 UTC 2023 UPDATE
Sun Nov 19 20:14:20 UTC 2023 UPDATE
Sun Nov 19 20:14:30 UTC 2023 UPDATE
Sun Nov 19 20:14:40 UTC 2023 UPDATE
Sun Nov 19 20:14:50 UTC 2023 UPDATERamen set up RBD mirroring for the underlying RBD image. The same image is created on the secondary cluster ("dr2"):
kubectl rook-ceph --context dr2 rbd du -p replicapool
Example output:
NAME PROVISIONED USED
csi-vol-a3fdb384-2e31-49f1-bd48-a97b2d79f981 128 MiB 80 MiBIn case of a disaster in the primary cluster, we can start the VM using the replica on the secondary cluster.
In case of disaster you can force the VM to run on the other cluster. The VM will start on the other cluster using the data from the last replication. Data since the last replication is lost.
To simulate a disaster we can pause the minkube VM running cluster
dr1:
virsh -c qemu:///system suspend dr1To start Failover action, patch the VM DRPlacementControl resource
to set action and failoverCluster:
kubectl patch drpc kubevirt-drpc \
--patch '{"spec": {"action": "Failover", "failoverCluster": "dr2"}}' \
--type merge \
--namespace kubevirt-sample \
--context hubThe VM will start on the failover cluster ("dr2"). Nothing will change on the primary cluster ("dr1") since it is still paused.
Inspecting the /var/log/ramen.log via SSH show how much data was lost
during the failover:
virtctl ssh cirros@sample-vm -n kubevirt-sample --known-hosts= --context dr2 -c 'tail -f /var/log/ramen.log'Example output:
Sun Nov 19 20:33:42 UTC 2023 UPDATE
Sun Nov 19 20:33:53 UTC 2023 UPDATE
Sun Nov 19 20:34:03 UTC 2023 UPDATE
Sun Nov 19 20:34:13 UTC 2023 UPDATE
Sun Nov 19 20:34:23 UTC 2023 UPDATE
Sun Nov 19 20:34:33 UTC 2023 UPDATE
Sun Nov 19 20:34:43 UTC 2023 UPDATE
Sun Nov 19 20:34:53 UTC 2023 UPDATE
Sun Nov 19 20:37:43 UTC 2023 START uptime=3.18
Sun Nov 19 20:37:53 UTC 2023 UPDATE
Sun Nov 19 20:38:03 UTC 2023 UPDATETo enable replication from the secondary cluster to the primary cluster, we need to recover the primary cluster. In this example we can resume the minikube VM:
virsh -c qemu:///system resume dr1Ramen will clean up the VM resources from the primary cluster and enable RBD mirroring from the secondary cluster ("dr2") to the primary cluster ("dr1").
To wait until the VM data is replicated again to the other cluster:
kubectl wait drpc kubevirt-drpc \
--for condition=PeerReady \
--namespace kubevirt-sample \
--timeout 5m \
--context hubSince the primary cluster is recovered, we can move the VM back to the primary cluster.
To move the VM back to the original cluster after a disaster
you can use the Relocate action. The VM will be terminated on
the current cluster, and started on the other cluster. No data is lost
during this operation.
Patch the VM DRPlacementControl resource to set action and
if needed, preferredCluster.
kubectl patch drpc kubevirt-drpc \
--patch '{"spec": {"action": "Relocate", "preferredCluster": "dr1"}}' \
--type merge \
--namespace kubevirt-sample \
--context hubThe VM will terminate on the current cluster and will start on the preferred cluster.
To wait until the VM is relocated to the primary cluster, wait until the
drpc phase is Relocated:
kubectl wait drpc kubevirt-drpc \
--for jsonpath='{.status.phase}=Relocated' \
--namespace kubevirt-sample \
--timeout 5m \
--context hubInspecting /var/log/ramen.log shows that the VM was terminated cleanly
on the secondary cluster ("dr2") and started on the primary cluster
("dr1"). No data was lost!
virtctl ssh cirros@sample-vm -n kubevirt-sample --known-hosts= --context dr1 -c 'tail -f /var/log/ramen.log'Example output:
Sun Nov 19 20:41:53 UTC 2023 UPDATE
Sun Nov 19 20:42:03 UTC 2023 UPDATE
Sun Nov 19 20:42:13 UTC 2023 UPDATE
Sun Nov 19 20:42:23 UTC 2023 UPDATE
Sun Nov 19 20:42:33 UTC 2023 UPDATE
Sun Nov 19 20:42:43 UTC 2023 UPDATE
Sun Nov 19 20:42:53 UTC 2023 UPDATE
Sun Nov 19 20:42:58 UTC 2023 STOP
Sun Nov 19 20:41:17 UTC 2023 START uptime=3.45
Sun Nov 19 20:41:27 UTC 2023 UPDATE
Sun Nov 19 20:41:37 UTC 2023 UPDATETo wait until the VM is replicating data again to the secondary cluster,
wait for the PeerReady condition:
kubectl wait drpc kubevirt-drpc \
--for condition=PeerReady \
--namespace kubevirt-sample \
--timeout 5m \
--context hubDelete the dr resources to disable DR:
kubectl delete -k dr --context hubEnable OCM scheduling again by deleting the placement annotation we added before:
kubectl annotate placement kubevirt-placement \
cluster.open-cluster-management.io/experimental-scheduling-disable- \
--namespace kubevirt-sample \
--context hubAt this point OCM controls the VM and the storage used for replicating the VM data on the DR clusters will be reclaimed.
Delete the subscription to stop and delete the VM:
kubectl delete -k subscription --context hub