Running CentOS in Kubernetes using KubeVirt

Ian Kiprotich
7 min readMay 15, 2023

If you’re seeking to harness the capabilities of virtual machines (VMs) within your Kubernetes environment, KubeVirt is a powerful tool you should be familiar with. By extending Kubernetes through CustomResourceDefinitions (CRDs), KubeVirt enables seamless VM management alongside your container workloads.

In this blog post, we’ll guide you step-by-step on how to run a CentOS VM in Kubernetes using the robust capabilities of KubeVirt. I had already talked about what is KubeVirt you can find the link-here.

Prerequisites

Before we get started, make sure you have the following:

  • A Kubernetes cluster running.
  • Kubectl installed
  • Krew installed

Installing Krew

You can easily install KubeVirt using Krew which helps you discover plugins, install and manage them on your machine. It is similar to tools like apt, dnf or brew.

Installing Krew

You can easily install Krew and start using Kubernetes plugins available to you via the Kubectl.

Bash or ZSH shells

  1. Make sure that git is installed.
  2. Run this command to download and install krew:
(
set -x; cd "$(mktemp -d)" &&
OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
KREW="krew-${OS}_${ARCH}" &&
curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
tar zxvf "${KREW}.tar.gz" &&
./"${KREW}" install krew
)

3. Add the $HOME/.krew/bin directory to your PATH environment variable. To do this, update your .bashrc or .zshrc file and append the following line:

export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"

4. Run kubectl krew to check the installation.

kubectl krew

Install KubeVirt

You can install KubeVirt using krew or using the custom resources

Installing using Krew

Now that Krew is installed let us enable the KubeVirt plugin using krew

kubectl krew install virt                  

Check the list of installed Krew plugins.

Using kubectl to deploy KubeVirt

export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases | grep tag_name | grep -v -- '-rc' | sort -r | head -1 | awk -F': ' '{print $2}' | sed 's/,//' | xargs)
echo $VERSION
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml

If the minikube cluster runs on a virtual machine consider enabling nested virtualization. Follow the instructions described here. If for any reason nested virtualization cannot be enabled do enable KubeVirt emulation as follows:

kubectl -n kubevirt patch kubevirt kubevirt --type=merge --patch '{"spec":{"configuration":{"developerConfiguration":{"useEmulation":true}}}}'

Again use kubectl to deploy the KubeVirt custom resource definitions:

kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml

Verify components

By default, KubeVirt will deploy 7 pods, 3 services, 1 daemonset, 3 deployment apps, 3 replica sets.

  • Check the deployment:
kubectl get kubevirt.kubevirt.io/kubevirt -n kubevirt -o=jsonpath="{.status.phase}"
  • Check the components:
kubectl get all -n kubevirt
  • When using the minikube KubeVirt addon check logs of the kubevirt-install-manager pod:
kubectl logs pod/kubevirt-install-manager -n kube-system

Virtctl

KubeVirt provides an additional binary called virtctl for quick access to the serial and graphical ports of a VM and also handle start/stop operations.

Install virtctl

virtctl can be retrieved from the release page of the KubeVirt github page.

VERSION=$(kubectl get kubevirt.kubevirt.io/kubevirt -n kubevirt -o=jsonpath="{.status.observedKubeVirtVersion}") ARCH=$(uname -s | tr A-Z a-z)-$(uname -m | sed 's/x86_64/amd64/') || windows-amd64.exe echo ${ARCH} curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-${ARCH} chmod +x virtctl sudo install virtctl /usr/local/bin

Install as Krew plugin

virtctl can be installed as a plugin via the krew plugin manager. Occurrences of virtctl <command>... can then be read as kubectl virt <command>....

  • Run the following to install:
kubectl krew install virt

Containerized Data Importer

The Containerized-Data-Importer (CDI) serves as an essential tool for managing persistent storage within a Kubernetes environment. Its fundamental objective is to establish a declarative method for constructing Virtual Machine Disks on Persistent Volume Claims (PVCs), specifically for Kubevirt virtual machines.

The unique aspect of CDI is its ability to work seamlessly with standard Kubernetes resources, while maintaining an agnostic stance towards the type of storage device used. While the primary use case for CDI lies in creating disk images for Kubevirt, its utility extends beyond this. CDI proves beneficial even outside the context of Kubevirt by providing an efficient mechanism to populate your Kubernetes Volumes with data.

Install the Containerized Data Importer

Next we determine the latest version of CDI and apply both the Operator and the CR that starts the deployment:

export VERSION=$(curl -Ls https://github.com/kubevirt/containerized-data-importer/releases/latest | grep -m 1 -o "v[0-9]\.[0-9]*\.[0-9]*")
echo $VERSION

Deploy the operator (and scale its replicas down to one due to the resource limitations of the environment):

kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-operator.yaml
kubectl -n cdi scale deployment/cdi-operator --replicas=1

Create CRD to trigger operator deployment of CDI:

kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-cr.yaml

Check status of CDI deployment. It may take some time before the cdi “PHASE” reads “Deployed”


kubectl get cdi -n cdi
kubectl -n cdi get pods

Review the “cdi” pods that were added.

Prepare your CentOs image

To begin, you will require a CentOS disk image, compatible with KubeVirt. Accepted formats include raw or qcow2. An optimal choice would be a CentOS cloud image, readily available for download from the official CentOS website.

Upload the CentOS Image

With the image ready, it’s time to upload it to a PersistentVolumeClaim (PVC) in your Kubernetes cluster. We’ll use the Containerized Data Importer (CDI) to accomplish this. Here’s an example YAML file that defines a DataVolume to import the CentOS image:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: fedora1
labels:
app: containerized-data-importer
annotations:
cdi.kubevirt.io/storage.import.endpoint: "https://download.fedoraproject.org/pub/fedora/linux/releases/30/Cloud/x86_64/images/Fedora-Cloud-Base-30-1.2.x86_64.raw.xz"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi

Apply the configuration using kubectl apply command

Create the VirtualMachine Instance

apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachine
metadata:
generation: 1
labels:
kubevirt.io/os: linux
name: fedora1
spec:
running: true
template:
metadata:
creationTimestamp: null
labels:
kubevirt.io/domain: fedora1
spec:
domain:
cpu:
cores: 1
devices:
disks:
- disk:
bus: virtio
name: disk0
- cdrom:
bus: sata
readonly: true
name: cloudinitdisk
resources:
requests:
memory: 128M
volumes:
- name: disk0
persistentVolumeClaim:
claimName: fedora1
- cloudInitNoCloud:
userData: |
#cloud-config
user: centos
password: onai
hostname: fedora1
ssh_pwauth: True
disable_root: false
name: cloudinitdisk

Save and apply this configuration using kubectl apply command.

This will create and start a Virtual Machine named fedora1. We can use the following command to check our Virtual Machine is running and to gather its IP address. You are looking for the IP address beside the

kubectl get pod -o wide

Please be patient while the Virtual Machine initiates and becomes ready for user access. Keep in mind that the duration required for the VM to start up is contingent upon the efficiency of your virtualization hardware and the performance speed of your underlying storage infrastructure. This means that more advanced virtualization technology and faster storage systems will result in quicker boot times.

Finally, we will connect to the fedora1 VM as a regular user would do, i.e. via ssh.

Get the IP adress and store it

IP=$(kubectl get vmi fedora1 -o jsonpath='{.status.interfaces[0].ipAddress}')

SSH into the vm using the command

ssh centos@${IP}

Use the default password of gocubsgo to log in.

Congratulations! You are now successfully logged into the virtual machine (VM) that is operating within a cluster powered by KubeVirt. This environment allows you to interact with the VM just as you would with any traditional machine. Feel free to explore, modify, and deploy your applications within this virtual environment to your heart’s content.

In conclusion,

leveraging tools like Containerized-Data-Importer (CDI) and KubeVirt can significantly streamline the management of persistent storage and virtual machines within a Kubernetes environment. These tools not only offer a declarative way to construct Virtual Machine Disks on Persistent Volume Claims (PVCs) but also facilitate the population of your Kubernetes Volumes with data.

Once your VM is up and running, you’ll have the freedom to interact with it as if it were a traditional machine. Deploy applications, make modifications, and truly explore the capabilities of your virtual environment.

By understanding and effectively using these tools, you can fully harness the power of Kubernetes, paving the way for efficient, scalable, and flexible application deployment. As always, keep exploring, keep learning, and keep pushing the boundaries of what you can achieve with these technologies.

Thank you for joining us on this journey through Kubernetes, KubeVirt, and Containerized-Data-Importer. We hope this has been a useful guide, and we look forward to sharing more insights with you in the future.

Reach out to me via LinkedIn Twitter and email @ onai.rotich@gmail.com

--

--