Everybody likes working with Containers. You can nearly perform whatever you want with them. However, the need for Virtual Machines has not diminished yet completely. As of this day, there are still many tasks that need Virtual Machines. KubeVirt comes into play right here. With the help of KubeVirt, you can run Virtual Machines inside of any Kubernetes Cluster.
In this article, I will be demonstrating how to create and run a Windows VM inside a KinD Cluster that is running on an Ubuntu machine.
Prerequisites
You need to have an Ubuntu Machine that should have Docker, Kubectl, and Kind installed as well as Nested Virtualization enabled. If you have one already, you can skip over the “Before Starting” part.
Before Starting
In this article, I will be using Google Cloud Console to host the Ubuntu Machine. You can follow along if you do not have one already, but make sure Nested Virtualization is enabled. You can check it via the command below. It should return something other than 0
grep -cw vmx /proc/cpuinfo
Go to GCP console, activate cloud shell and run the command below to create a disk
gcloud compute disks create kubevirt-disk --zone=us-west4-b --image-project=ubuntu-os-cloud --image-family=ubuntu-2004-lts --size=200GB
Then create an image out of that disk
gcloud compute images create kubevirt-image --source-disk kubevirt-disk --source-disk-zone us-west4-b --licenses « https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx »
Then the virtual machine
gcloud compute instances create kubevirt-vm --custom-cpu=8 --custom-memory=16GB --zone=us-west4-b --image kubevirt-image
Then create a firewall rule that will allow your local machine to access port 31002 of the Ubuntu machine
gcloud compute firewall-rules create allow-nodeport-31002 \— action=ALLOW \— direction=INGRESS \— network=default \— priority=10 \— rules=tcp:31002 \— source-ranges=/32
Be aware that the public IP of this VM is an Ephemeral one and will change if you stop and start the VM again.
Now ssh into the VM and install Docker
sudo su----------------------------------------------------------------apt update && apt upgrade -y && apt install -y ca-certificates curl gnupg lsb-release----------------------------------------------------------------curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg----------------------------------------------------------------echo « deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable » | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null----------------------------------------------------------------apt update && apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Then install kind and kubectl
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.12.0/kind-linux-amd64----------------------------------------------------------------chmod +x ./kind && mv kind /usr/local/bin----------------------------------------------------------------curl -LO « https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl »----------------------------------------------------------------sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl----------------------------------------------------------------echo « alias k=kubectl » >> ~/.bashrc && bash --login
Create a KinD Cluster
Here we will be creating a KinD cluster and exposing 31001 and 31002 ports for further use. If you have an existing KinD cluster and want to work on it, go to section 1.b
OPTIONAL: You can install “Nginx Ingress Controller” if you want, but we will not be needing it in our case.
b) Configure an existing KinD Cluster
If you want to create the Windows VM on an existing KinD cluster, you just need to run the two commands below in order to expose the NodePorts. Get the container name of your KinD cluster via docker ps command. It will be something like {your-cluster-name}-control-plane
docker run -d -p 31001:1234 --net kind alpine/socat \tcp-listen:1234,fork,reuseaddr tcp-connect:{your-cluster-name}-control-plane:31001---------------------------------------------------------------- docker run -d -p 31002:1234 --net kind alpine/socat \tcp-listen:1234,fork,reuseaddr tcp-connect:{your-cluster-name}-control-plane:31002
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)----------------------------------------------------------------k create -f https://github.com/kubevirt/kubevirt/releases/download/{VERSION}/kubevirt-operator.yaml----------------------------------------------------------------k create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml----------------------------------------------------------------k get pods -n kubevirt # wait until you see all 7 pods----------------------------------------------------------------root@virt-vm:/home/manas_petschenek# k pods -n kubevirtNAME READY STATUS RESTARTS AGEvirt-api-77df5c4f87-26mgm 1/1 Running 0 103svirt-api-77df5c4f87-jqpmh 1/1 Running 0 103svirt-controller-749d8d99d4-nxvw2 1/1 Running 0 78svirt-controller-749d8d99d4-rmg9j 1/1 Running 0 78svirt-handler-52km7 1/1 Running 0 78svirt-operator-564f568975-5cccj 1/1 Running 0 2m2svirt-operator-564f568975-k9c54 1/1 Running 0 2m2s
(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_ROOT:-HOME/.krew}/bin:PATH »’ >> ~/.bashrc && bash --login----------------------------------------------------------------k krew install virt
k apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/v1.48.1/cdi-operator.yaml----------------------------------------------------------------k apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/v1.48.1/cdi-cr.yaml----------------------------------------------------------------k get cdi cdi -n cdiroot@kubevirt-vm:/home/manas_petschenek# k get cdi cdi -n cdi
NAME AGE PHASE
cdi 118m Deployed----------------------------------------------------------------k get pods -n cdiroot@kubevirt-vm:/home/manas_petschenek# k get pods -n cdi
NAME READY STATUS RESTARTS AGE
cdi-apiserver-66998fc655-v5lb2 1/1 Running 0 118m
cdi-deployment-7b4986d49d-7n82s 1/1 Running 0 119m
cdi-operator-8496bfc49c-m4zl7 1/1 Running 0 119m
cdi-uploadproxy-5984d69cc7-tcq6j 1/1 Running 0 118m
Download Windows ISO
Visit https://www.microsoft.com/en-us/evalcenter/download-windows-server-2012-r2. Copy the dowload link adress and download the iso via wget command
wget -O win.iso 'link-you-just-copied’It will look like this:wget -O win.iso ‹ https://go.microsoft.com/fwlink/p/?LinkID=2195443&clcid=0x409&culture=en-us&country=US ›
Expose the “cdi-uploadproxy” Service
To upload data to the cluster, the cdi-uploadproxy service must be accessible from outside the cluster. Since the data is too much for ingress to handle, we are going to be using a NodePort service for this purpose. In a production environment consider using a LoadBalancer service instead
Upload the ISO file into a PVC
Run the following command where you downloaded the Windows ISO
k virt image-upload --image-path=win.iso --pvc-name=iso-win10 --access-mode=ReadWriteOnce --pvc-size=7G --uploadproxy-url=https://localhost:31001 --insecure --wait-secs=60
You should see something like
root@kubevirt-vm:/home/manas_petschenek# k virt image-upload \
–image-path=win.iso
–pvc-name=iso-win10
–access-mode=ReadWriteOnce
–pvc-size=7G
–uploadproxy-url=https://localhost:31001
–insecure
–wait-secs=60
PVC default/iso-win10 not found
PersistentVolumeClaim default/iso-win10 created
Waiting for PVC iso-win10 upload pod to be ready…
Pod now ready
Uploading data to https://localhost:310014.23 GiB / 4.23 GiB [====================================================================================================================================================================================] 100.00% 1m18sUploading data completed successfully, waiting for processing to complete, you can hit ctrl-c without interrupting the progress
Processing completed successfully
Uploading win.iso completed successfully
Create the Windows VM
First, pull the Docker image
docker pull quay.io/kubevirt/virtio-container-disk
Then create the VirtualMachine and PersistentVolumeClaim
Then start the VirtualMachine to create a VirtualMachineInstance
k virt start iso-win10
Check if they are running
root@kubevirt-vm:/home/manas_petschenek# k get vm,vmi
NAME AGE STATUS READY
virtualmachine.kubevirt.io/iso-win10 23s Running TrueNAME AGE PHASE IP NODENAME READY
virtualmachineinstance.kubevirt.io/iso-win10 11s Running 10.244.0.26 kubevirt-control-plane True
Connect to Windows VM
There are two different methods
If you have a graphical interface, run:
k virt vnc iso-win10
If you do not, then follow the steps below:
wget -O virtvnc.yaml https://github.com/wavezhang/virtVNC/raw/master/k8s/virtvnc.yaml----------------------------------------------------------------sed -i ‹ s/targetPort: 8001/targetPort: 8001\n nodePort: 31002/ › virtvnc.yaml----------------------------------------------------------------k apply -f virtvnc.yaml
Then access the console via http://{public-ip-of-ubuntu-vm}:31002
Click on the VNC button
10) Install Drivers
Follow the screenshots below
Select the language
Select the second option
Accept the license terms
Select the Custom installation path
Click on “Load driver”
Click on “Browse”
Expand the “virtio drive”
Go to the bottom and expand “viostor” and then “2k12R2”. Select “amd64” and click Ok
Click on Next
Click on Next
Wait until it finishes
If you see this page, Do not press any button just wait
Set admin password
Click on the “Send CtrlAltDel” button
Login with the admin password
Close this page
Windows is ready
RESOURCES:
KubeVirt quickstart with kind | KubeVirt.io
Kind quickly sets up a local Kubernetes cluster on macOS, Linux, and Windows allowing software developers to quickly…
kubevirt.io
KubeVirt: installing Microsoft Windows from an ISO | KubeVirt.io
Hello! nowadays each operating system vendor has its cloud image available to download ready to import and deploy a new…
kubevirt.io
Windows virtio drivers - KubeVirt User-Guide
Purpose of this document is to explain how to install virtio drivers for Microsoft Windows running in a fully…
kubevirt.io
Access Virtual Machines’ graphic console using noVNC | KubeVirt.io
NoVNC is a JavaScript VNC client using WebSockets and HTML5 Canvas. We provide websocket api for VNC access under…
kubevirt.io
Virtual hardware - KubeVirt User-Guide
Fine-tuning different aspects of the hardware which are not device related (BIOS, mainboard, etc.) is sometimes…
kubevirt.io
About nested virtualization | Compute Engine Documentation | Google Cloud
This document describes Compute Engine support for nested virtualization. Nested virtualization lets you run virtual…
cloud.google.com
Enabling nested virtualization | Compute Engine Documentation | Google Cloud
This document describes how to enable nested virtualization on a virtual machine (VM) instance and how to confirm that…
cloud.google.com
Windows Server 2012 R2 | Microsoft Evaluation Center
Windows Server 2012 R2 provides a wide range of new and enhanced features and capabilities spanning server…