kubevirt-community-stack

Kubevirt Community Stack

Create Kubevirt VMs via Helm
for use with ArgoCD, Argo Workflows, KEDA, ClusterAPI, Tekton etc...


Who is this for:

The Kubevirt-Community-Stack may be of interest if you:

Component charts

Kubervirt
Kubevirt is a Kubernetes Virtualization API and runtime which controls QEMU/KVM virtual machine instances and provides the CRDs that define them. It's distrubuted as a Kubernetes Operator which is install via the kubevirt chart.

Kubevirt CDI
The Containerized Data Importer can pull virtual machine images, ISO files, and other types of bootable media from sources like S3, HTTP, or OCI images. This data is then written to PVCs which are mounted as disks. For examples of various ways to use the CDI, see the notes in Argocd-Apps

Cloud-Init
The Cloud-init helm chart allows the user to define the specification of a linux-based vm's operating system as code. In addition to basec cloud-init functions, his chart provides some extra functionality via an initjob that makes cloud-init more GitOps friendly.

Additional Features: - Regex values using existing secrets or environmental variables via envsubst - Create random user passwords or use an existing secret - Download files from a URL - Base64 encode + gzip your `write_files` content - Populate Wireguard configuration values from an existsing secret - Track the total size of user-data and check file for valid syntax

Kubevirt VM
The Kubevirt-VM Chart allows a user to easily template a Kubevirt VirtualMachine or VirtualMachinePool and its associated resources sudch as Disks, DataVolumes, Horizontal Pod Autoscaler, Network Policies, Service, Ingres, Probes, and Cloud-init data (via bundled cloud-init subchart).

Kubevirt Manager
This is a community-developed web-ui which allows users to create, manage, and interact with virtual machines running in Kubevirt. See their official docs at kubevirt-manager.io

Screenshot showing the default page of Kubevirt-manager. The screen is devided into 2 sections. On the left, there is a vertical navigation tab with a grey background. The options in this bar are Dashboard, Virtual Machines, VM Pools, Auto Scaling, Nodes, Data Volumes, Instance Types, and Load Balancers.  On the right, there is a grid of blue rectangular icons each representing one of the option in the navigation tab, but with an icon and text representing metrics about that option.



Cluster API Operator & Addons
Cluster API provides a standardised kubernetes-native interface for creating k8s clusters using a wide variety of providers. The combined chart can install the Cluster API Operator as well as bootstrap the Cluster API Kubevirt Provider which allows creating k8s clusters from the CLI or as YAML using Kubevirt VMs. Cluster-api-provider-kubevirt also includes cloud-provider-kubevirt which enables the exposeure of LoadBalancer type services within tenant clusters to the host cluster. This negates the need for a dedicated loadbalancer such as MetalLB inside the tenant cluster.

See CAPI.md for a basic walkthrough of creating a CAPI-based tenant cluster.

CAPI Cluster
The CAPI Cluster helm chart provides a way to create workload clusters using the Kubevirt infrastructure, Kubeadm Bootstrap + ControlPlane, and Helm providers.

Dependencies

libvirt-clients
This utility will audit a host machine and report what virtualisation capabilities are available - Installation ```bash sudo apt-get install -y libvirt-clients ``` - Usage ```console $ virt-host-validate qemu QEMU: Checking for hardware virtualization : PASS QEMU: Checking if device /dev/kvm exists : PASS QEMU: Checking if device /dev/kvm is accessible : PASS QEMU: Checking if device /dev/vhost-net exists : PASS QEMU: Checking if device /dev/net/tun exists : PASS ```
virtctl
virtctl is the command-line utility for managing Kubevirt resources. It can be installed as a standalone CLI or as a Kubectl plugin via krew. - Standalone ```bash export VERSION=v0.41.0 wget https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-linux-amd64 ``` - Plugin ```bash kubectl krew install virt ```
clusterctl
The clusterctl CLI tool handles the lifecycle of a Cluster API management cluster. ```bash curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.7.2/clusterctl-linux-amd64 -o clusterctl sudo install -o root -g root -m 0755 clusterctl /usr/local/bin/clusterctl ```

Install The Kubevirt-Community-Stack

Expand to see individual chart installation
- kubevirt: Installs the Kubevirt Operator. ```bash helm repo add kubevirt https://cloudymax.github.io/kubevirt-community-stack helm install kubevirt kubevirt/kubevirt \ --namespace kubevirt \ --create-namespace ``` - Cluster API Operator: Installs the Cluster API Operator. ```bash Work in progress. ``` - kubevirt-cdi: Install the Containerized Data Importer. ```bash helm repo add kubevirt https://cloudymax.github.io/kubevirt-community-stack helm install kubevirt-cdi kubevirt/kubevirt-cdi \ --namespace cdi \ --create-namespace ``` - kubevirt-manager: Deploy the Kubevirt-Manager UI ```bash # Customize your own values.yaml before deploying helm repo add kubevirt https://cloudymax.github.io/kubevirt-charts helm install kubevirt-manager kubevirt/kubevirt-manager \ --fnamespace kubevirt-manager \ --create-namespace ```

Creating a VM

This is a qucik walkthrough of how I create VMs using kubevirt-community-stack. All the configuration for the VM happens in the values.yaml file of the Kubevirt-VM Chart chart.

From this file we can configure the VM, Disks, Cloudinit config, services, probes and more.

With the command or file below we will:

  1. Create a new VM named example with with 2 cores and 2Gi of RAM.
  2. Create a 16Gi PVC named harddrive which holds a debian12 cloud-image.
  3. Define a user named example and assign the user some groups and a random password which will be stored in a secret.
  4. Save our user-data as a secret named example-user-data
  5. Update apt-packes and install docker.
  6. Run the nginx docker container with port 8080 exposed from the container to the VM
  7. Define a service over which to expose port 8080 from the VM to the host.
Requirements
- you are running on bare-metal, not inside a VM - you set `cpuManagerPolicy: static` in your kubelet config - you have `yq` and either `virtctl` or `krew virt` installed - your host system passes all `virt-host-validate qemu` checks for KVM ```console QEMU: Checking for hardware virtualization : PASS QEMU: Checking if device /dev/kvm exists : PASS QEMU: Checking if device /dev/kvm is accessible : PASS ```
Command Line method: ```bash helm repo add kubevirt https://cloudymax.github.io/kubevirt-community-stack helm install example kubevirt/kubevirt-vm \ --namespace kubevirt \ --set virtualMachine.name="example" \ --set virtualMachine.namespace="kubevirt" \ --set virtualMachine.machine.vCores=2 \ --set virtualMachine.machine.memory.base="2Gi" \ --set disks[0].name="harddrive" \ --set disks[0].type="disk" \ --set disks[0].bus="virtio" \ --set disks[0].bootorder=2 \ --set disks[0].readonly="false" \ --set disks[0].pvsize="16Gi" \ --set disks[0].pvstorageClassName="fast-raid" \ --set disks[0].pvaccessMode="ReadWriteOnce" \ --set disks[0].source="url" \ --set disks[0].url="https://buildstars.online/debian-12-generic-amd64-daily.qcow2" \ --set cloudinit.hostname="example" \ --set cloudinit.namespace="kubevirt" \ --set cloudinit.users[0].name="example" \ --set cloudinit.users[0].groups="users\, admin\, docker\, sudo\, kvm" \ --set cloudinit.users[0].sudo="ALL=(ALL) NOPASSWD:ALL" \ --set cloudinit.users[0].shell="/bin/bash" \ --set cloudinit.users[0].lock_passwd="false" \ --set cloudinit.users[0].password.random="true" \ --set cloudinit.secret_name="example-user-data" \ --set cloudinit.package_update="true" \ --set cloudinit.packages[0]="docker.io" \ --set cloudinit.runcmd[0]="docker run -d -p 8080:80 nginx" \ --set service[0].name="example" \ --set service[0].type="NodePort" \ --set service[0].externalTrafficPolicy="Cluster" \ --set service[0].ports[0].name="nginx" \ --set service[0].ports[0].port="8080" \ --set service[0].ports[0].targePort="8080" \ --set service[0].ports[0].protocol="TCP" \ --create-namespace ```
Values File method: ```bash helm repo add kubevirt https://cloudymax.github.io/kubevirt-community-stack cat < example.yaml --- virtualMachine: name: example namespace: kubevirt machine: vCores: "2" memory: base: "2Gi" disks: - name: harddrive type:disk bus: virtio bootorder: 2 readonly: false pvsize: 16Gi pvstorageClassName: fast-raid pvaccessMode: ReadWriteOnce source: url url: "https://buildstars.online/debian-12-generic-amd64-daily.qcow2" cloudinit: hostname: example namespace: kubevirt users: - name: example groups: "users, admin, docker, sudo, kvm" sudo: "ALL=(ALL) NOPASSWD:ALL" shell:"/bin/bash" lock_passwd:"false" password: random: "true" secret_name: "example-user-data" package_update: "true" packages: - docker.io runcmd: - "docker run -d -p 8080:80 nginx" service: name: example type: ClusterIP externalTrafficPolicy: Cluster ports: - name: "nginx" port: "8080" targePort: "8080" protocol: "TCP" EOF ``` - Install VM as a helm-chart (or template it out as manifests): ```bash helm install example kubevirt/kubevirt-vm \ --namespace kubevirt \ --create-namespace \ -f example.yaml ``` </details> 1. Find the secret create to hold our user's password: ```bash kubectl get secret example-password -n kubevirt -o yaml \ |yq '.data.password' |base64 -d ``` 2. Connect to the vm over console & login as user "example": ```console kubectl virt console example -n kubevirt Successfully connected to example console. The escape sequence is ^] example login: example Password: ``` 3. Port-forward the nginx service and vistit in your browser: ```bash kubectl port-forward service/example -n kubevirt 8080:8080 --address 0.0.0.0 ``` 4. Uninstall/Delete the VM ```bash helm uninstall example ``` ## Uninstall In the event that Kubevirt does not uninstall gracefully, you may need to perform the following steps: ```bash export RELEASE=v0.17.0 # --wait=true should anyway be default kubectl delete -n kubevirt kubevirt kubevirt --wait=true # this needs to be deleted to avoid stuck terminating namespaces kubectl delete apiservices v1.subresources.kubevirt.io # not blocking but would be left over kubectl delete mutatingwebhookconfigurations virt-api-mutator # not blocking but would be left over kubectl delete validatingwebhookconfigurations virt-operator-validator # not blocking but would be left over kubectl delete validatingwebhookconfigurations virt-api-validator kubectl delete -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-operator.yaml --wait=false # Find hanging resources kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n kubevirt # If namespace is stuck kubectl get namespace "kubevirt" -o json | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/" | kubectl replace --raw /api/v1/namespaces/kubevirt/finalize -f - ```