KubeVirt: Running VMs in Kubernetes
KubeVirt extends Kubernetes to manage virtual machines alongside containers. This article covers installation, configuration, and running VMs in our homelab.
What is KubeVirt?
KubeVirt is a Kubernetes operator that adds VM management capabilities:
- VMs as Kubernetes resources
- Manage VMs with
kubectl - Unified platform for containers and VMs
- Hardware virtualization support
Why KubeVirt?
Traditional Approach:
- Separate hypervisor (Proxmox, VMware)
- Different tools for containers and VMs
- Complex networking between platforms
KubeVirt Approach:
- Everything in Kubernetes
- Unified management (
kubectl) - Same networking and storage
- Containers and VMs together
Architecture
┌─────────────────────────────────────┐
│ Kubernetes API Server │
│ + KubeVirt CRDs │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ KubeVirt Operator │
│ - virt-api (API server) │
│ - virt-controller (VM lifecycle) │
│ - virt-handler (node agent) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ VM Pod (virt-launcher) │
│ └─ QEMU/KVM (actual VM) │
└─────────────────────────────────────┘
Installation
Prerequisites
Hardware Virtualization:
# Check CPU support
talosctl -e 192.168.1.100 --nodes 192.168.1.100 read /proc/cpuinfo | grep -E "vmx|svm"
# Should show: vmx (Intel) or svm (AMD)
BIOS Settings:
- Enable VT-x (Intel) or AMD-V
- Enable virtualization in BIOS
Install KubeVirt
# Set version
export KUBEVIRT_VERSION=v1.1.2
# Install operator
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml
# Wait for operator
kubectl wait --for=condition=ready pod -n kubevirt-system -l kubevirt.io=virt-operator --timeout=120s
# Install KubeVirt CR
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml
# Wait for installation
kubectl wait --for=condition=ready pod -n kubevirt-system -l kubevirt.io=virt-handler --timeout=300s
Verify Installation
# Check pods
kubectl get pods -n kubevirt-system
# Expected:
# NAME READY STATUS
# virt-api-xxxxx 1/1 Running
# virt-controller-xxxxx 1/1 Running
# virt-handler-xxxxx 1/1 Running
# virt-operator-xxxxx 1/1 Running
# Check CRDs
kubectl get crd | grep kubevirt
# virtualmachines.kubevirt.io
# virtualmachineinstances.kubevirt.io
# etc.
Creating Your First VM
Simple Ubuntu VM
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: ubuntu-vm
namespace: default
spec:
running: true
template:
metadata:
labels:
kubevirt.io/domain: ubuntu-vm
spec:
domain:
cpu:
cores: 2
memory:
guest: 4Gi
devices:
disks:
- name: rootdisk
disk:
bus: virtio
- name: cloudinitdisk
disk:
bus: virtio
interfaces:
- name: default
masquerade: {}
networks:
- name: default
pod: {}
volumes:
- name: rootdisk
persistentVolumeClaim:
claimName: ubuntu-vm-disk
- name: cloudinitdisk
cloudInitNoCloud:
userData: |
#cloud-config
password: ubuntu
chpasswd:
expire: false
ssh_authorized_keys:
- ssh-rsa AAAAB3...
Create PVC for VM Disk
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ubuntu-vm-disk
spec:
storageClassName: local-path
resources:
requests:
storage: 20Gi
Apply VM
kubectl apply -f vm-ubuntu.yaml
kubectl get vms
# NAME AGE STATUS READY
# ubuntu-vm 10s Running True
VM Management
Start/Stop VM
Via kubectl:
# Stop
kubectl patch vm ubuntu-vm --type merge -p '{"spec":{"running":false}}'
# Start
kubectl patch vm ubuntu-vm --type merge -p '{"spec":{"running":true}}'
Via virtctl:
# Install virtctl
export VIRTCTL_VERSION=v1.1.2
curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VIRTCTL_VERSION}/virtctl-${VIRTCTL_VERSION}-darwin-amd64
chmod +x virtctl
sudo mv virtctl /usr/local/bin/
# Start/Stop
virtctl start ubuntu-vm
virtctl stop ubuntu-vm
virtctl restart ubuntu-vm
Via Custom Console:
- Web UI with start/stop/restart buttons
- Real-time status updates
- No CLI needed
Console Access
VNC Console:
virtctl console ubuntu-vm
SSH (if configured):
# Get VM IP
kubectl get vmi ubuntu-vm -o jsonpath='{.status.interfaces[0].ipAddress}'
# SSH
ssh user@<vm-ip>
VM Status
# List VMs
kubectl get vms
# Detailed status
kubectl describe vm ubuntu-vm
# VM Instance (actual running VM)
kubectl get vmi ubuntu-vm
# Logs
kubectl logs -n kubevirt-system virt-handler-xxxxx
Networking
Pod Network (Default)
VMs get IP from pod network:
- Same network as containers
- Accessible via ClusterIP services
- NAT through pod network
networks:
- name: default
pod: {}
interfaces:
- name: default
masquerade: {}
Bridge Network (Advanced)
For direct network access:
- Requires CNI plugin (Multus)
- More complex setup
- Better for production
Storage
PVC for VM Disks
volumes:
- name: rootdisk
persistentVolumeClaim:
claimName: vm-disk
DataVolumes (CDI)
For importing ISOs/images:
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: ubuntu-iso
spec:
source:
http:
url: https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso
pvc:
storageClassName: local-path
resources:
requests:
storage: 10Gi
Example VMs
Ubuntu Server
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: ubuntu-server
spec:
running: true
template:
spec:
domain:
cpu:
cores: 4
memory:
guest: 8Gi
devices:
disks:
- name: root
disk: {}
interfaces:
- name: default
masquerade: {}
volumes:
- name: root
persistentVolumeClaim:
claimName: ubuntu-disk
Windows VM
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: windows-vm
spec:
running: false
template:
spec:
domain:
cpu:
cores: 4
memory:
guest: 8Gi
devices:
disks:
- name: windows-disk
disk:
bus: sata
- name: windows-iso
cdrom: {}
interfaces:
- name: default
masquerade: {}
volumes:
- name: windows-disk
persistentVolumeClaim:
claimName: windows-disk
- name: windows-iso
dataVolume:
name: windows-iso-dv
Performance
Hardware Virtualization
KubeVirt uses hardware virtualization (VT-x/AMD-V):
- Near-native performance
- Full CPU features
- GPU passthrough possible (advanced)
Resource Allocation
resources:
requests:
cpu: 2
memory: 4Gi
limits:
cpu: 4
memory: 8Gi
- Requests: Guaranteed resources
- Limits: Maximum resources
Troubleshooting
VM Won’t Start
Check VMI status:
kubectl get vmi ubuntu-vm
kubectl describe vmi ubuntu-vm
Check virt-handler logs:
kubectl logs -n kubevirt-system -l kubevirt.io=virt-handler
Verify hardware virtualization:
talosctl -e 192.168.1.100 --nodes 192.168.1.100 read /proc/cpuinfo | grep vmx
VM Stuck in Pending
Check PVC:
kubectl get pvc
kubectl describe pvc vm-disk
Check node resources:
kubectl describe node r430-k8s-master
Console Not Working
Install virtctl:
# Required for console access
virtctl console ubuntu-vm
Check VNC service:
kubectl get svc -n kubevirt-system
Best Practices
- Resource Limits - Set CPU/memory limits to prevent resource exhaustion
- Storage Planning - Allocate appropriate disk sizes
- Backup Strategy - Backup PVCs regularly
- Network Isolation - Use NetworkPolicies for security
- Monitoring - Monitor VM resource usage
- Naming Convention - Use descriptive names
Use Cases
Development Environments
- Isolated dev environments
- Easy to create/destroy
- Version controlled (YAML)
Legacy Applications
- Run apps that need full OS
- Windows applications
- Legacy software
Testing
- Test different OS versions
- Isolated test environments
- CI/CD integration
Comparison: Containers vs VMs
| Feature | Containers | VMs (KubeVirt) |
|---|---|---|
| Startup Time | Seconds | Minutes |
| Resource Usage | Low | Higher |
| Isolation | Process | Full OS |
| Use Case | Cloud-native apps | Legacy apps, full OS |
| Management | Same (kubectl) | Same (kubectl) |
Future Enhancements
- GPU passthrough
- Live migration (multi-node)
- Snapshot support
- Template management
- VM marketplace
Conclusion
KubeVirt brings VM management into Kubernetes:
- ✅ Unified platform
- ✅ Same tools (kubectl)
- ✅ Hardware virtualization
- ✅ Production-ready
Perfect for homelabs that need both containers and VMs.
Next: Troubleshooting Guide