1.2. Start and stop a VM

Start and stop your virtual machines

In the previous section, we wrote a VirtualMachine specification and applied the manifest to the Kubernetes cluster.

Lifecycle

When the underlying technology libvirt refers to a VM it often also uses the concept of so-called guest domains.

According to libvirt.org , a guest domain can be in several states:

  1. Undefined: This is a baseline state. Libvirt does not know anything about domains in this state because the domain hasn’t been defined or created yet.
  2. Defined or Stopped: The domain has been defined but it’s not running. This state is also called stopped. Only persistent domains can be in this state. When a transient domain is stopped or shut down, it ceases to exist.
  3. Running: The domain has been created and started either as transient or persistent domain. Either domain in this state is being actively executed on the node’s hypervisor.
  4. Paused: The domain execution on the hypervisor has been suspended. Its state has been temporarily stored until it is resumed. The domain does not have any knowledge whether it was paused or not.
  5. Saved: Similar to the paused state, but the domain state is stored to persistent storage. Again, the domain in this state can be restored and it does not notice that any time has passed.

VM Lifecycle

Task 1.2.1: List your virtual machines

Since you created a VirtualMachine in the previous section, you may verify its creation with:

kubectl get virtualmachine --namespace lab-<username>

You should see your virtual machines listed as follows:

NAME            AGE   STATUS    READY
lab01-firstvm   10m   Stopped   False

This indicates that the VM has been created but is still in a stopped state.

Working with your VMs

There are different ways of starting and stopping your virtual machines. You can patch your VirtualMachine resource with kubectl or use virtctl to start the VM. Try starting and stopping your VM with different methods.

Task 1.2.4: Start with kubectl

Your VirtualMachine resource contains a field spec.runStrategy which indicates the desired state of the VM. You can check the resource with:

kubectl describe vm lab01-firstvm --namespace lab-<username>

Alternatively you can directly select the relevant field using a jsonpath:

kubectl get vm lab01-firstvm -o jsonpath='{.spec.runStrategy}' --namespace lab-<username>

Use the following command to start your VM:

kubectl patch vm lab01-firstvm --type merge -p '{"spec":{"runStrategy":"Always"}}' --namespace lab-<username>

The output should be:

virtualmachine.kubevirt.io/lab01-firstvm patched

Now check the state of your VM again:

kubectl get vm --namespace lab-<username>

You should see that the VM is now in Running state:

NAME            AGE   STATUS    READY
lab01-firstvm   11m   Running   True

Task 1.2.7: Stop with kubectl

Stopping the VM is similar to starting. Just set spec.runStrategy back to Halted:

kubectl patch vm lab01-firstvm --type merge -p '{"spec":{"runStrategy":"Halted"}}' --namespace lab-<username>

The output should again be:

virtualmachine.kubevirt.io/lab01-firstvm patched

Task 1.2.8: Start with virtctl

The binary virtctl provides an easier way of interacting with KubeVirt VMs. And adds additional features like:

  • Serial and graphical console access
  • Starting and stopping VirtualMachineInstances
  • Live migrating VirtualMachineInstances
  • Uploading virtual machine disk images
  • Adding, removing volumes
  • Exposing services
  • Debugging features: creating memory dumps

We will use some of those functionalities during the lab.

virtctl uses the default kubeconfig to interact with the Kubernetes Cluster.

Explore the capabilities of virtctl by executing the following commands:

virtctl --help

and

virtctl <command> --help

or the following to display all options

virtctl options

Let’s now start the VM by using virtctl by executing the following command:

virtctl start lab01-firstvm --namespace lab-<username>

The output should be:

VM lab01-firstvm was scheduled to start

If you check the state of your VM you’ll see that it had the same effect as using the kubectl command:

kubectl get vm --namespace lab-<username>

Your VM is in Running state:

NAME            AGE   STATUS    READY
lab01-firstvm   11m   Running   True

Question to explore virtctl: What’s the exact command to restart a VM (vm-to-restart) using the kubeconfig from (~/.kube/prod-cluster the config does not exist in the webshell, it’s just an example)

Solution
virtctl --kubeconfig ~/.kube/prod-cluster restart vm-to-restart --namespace lab-<username>

Task 1.2.9: Stop with virtctl

When using the --dry-run option we can see what would happen without really executing the actual command. This can be a helpful option when interacting with production workload.

Let’s dry-run the stop command:

virtctl stop lab01-firstvm --dry-run --namespace lab-<username>

This will return the following:

Dry Run execution
VM lab01-firstvm was scheduled to stop

To stop your VM for real, remove the --dry-run option:

virtctl stop lab01-firstvm --namespace lab-<username>

The output should be:

VM lab01-firstvm was scheduled to stop

Task 1.2.10: Pause a VirtualMachine with virtctl

Pausing a VM is as simple as:

virtctl pause vm lab01-firstvm --namespace lab-<username>

However, if you try to execute above command, it will result in an error:

Error pausing VirtualMachineInstance lab01-firstvm. VirtualMachine lab01-firstvm is not set to run

Obviously we can not pause a stopped VM, so start the VM first and then try the pause command again:

virtctl start lab01-firstvm --namespace lab-<username>

Make sure the VM shows it has started before you pause it:

kubectl get vm --namespace lab-<username>

Now pause it:

virtctl pause vm lab01-firstvm --namespace lab-<username>

The output should be:

VMI lab01-firstvm was scheduled to pause

Again, verify the state of the VM:

kubectl get vm --namespace lab-<username>

Resuming a VM can be done with:

virtctl unpause vm lab01-firstvm --namespace lab-<username>

The output should be:

VMI lab01-firstvm was scheduled to unpause

Involved components

When your VM is in a running state, you may have noticed that there is an additional pod running. Make sure your VM is running and issue the following command:

kubectl get pods --namespace lab-<username>

The output will be similar to:

NAME                                READY   STATUS    RESTARTS   AGE

<username>-webshell-885dbc579-lwhtd      2/2     Running   0          1d

virt-launcher-lab01-firstvm-mfxrs   3/3     Running   0          90s

For each running VM there is a virt-launcher pod which is responsible to start the effective VM process in the container and observes the VM state.

Beside the existence of the virt-launcher pod, a new custom resource VirtualMachineInstance is present. This resource is created under the hood by the virt-controller and will only be available as long as the VM is running. It represents a single running virtual machine instance.

You may see your VirtualMachineInstance with the following command:

kubectl get vmi --namespace lab-<username>

The output will be similar to:

NAME            AGE     PHASE     IP             NODENAME               READY
lab01-firstvm   3m59s   Running   10.244.3.144   training-worker-0   True

Above output also indicates that our lab01-firstvm is running on Kubernetes node training-worker-0.

Task 1.2.11: (Optional) Under the hood: Explore the virt-launcher pod

In this optional lab we are going to explore the virt-launcher pod, which we discovered in the previous task.

For every VirtualMachineInstance or VMI (running VM), one virt-launcher pod is created. The virt-launcher pod provides boundaries (cgoups, namespaces), the interface to the Kubernetes ecosystem and manages and monitors the lifecycle of the VMI.

In its core, the virt-launcher pod runs a libvirtd instance, which manages the lifecycle of the VMI process.

With the following command, we can have a look at the pod’s manifest (replace the pod name with the actual pod’s name from kubectl get pods --namespace lab-<username>):

kubectl get pod virt-launcher-lab01-firstvm-<pod> -o yaml --namespace lab-<username>

Or simply use the describe command:

kubectl describe pod virt-launcher-lab01-firstvm-<pod> --namespace lab-<username>

Explore the pod definition or use the describe command:

  • labels
  • ownerReference
  • initContainers and containers
    • container-disk-binary
    • volumecontainerdisk-init
    • compute
    • volumecontainerdisk
    • guest-console-log
  • limits and requests
  • volumes and volumeMounts
  • status

You can even exec into the pod and list the running processes, where you can find the running libvirt and qemu-kvm processes:

kubectl exec --stdin --tty --namespace lab-<username> virt-launcher-lab01-firstvm-<pod> -- /bin/bash
ps -ef

Press CTRL + d or type exit to exit the shell of the pod again.