Part 1: Architecture Under the Hood
When engineers first hear about OpenShift Virtualization (formerly CNV / Container-Native Virtualization), their immediate reaction is often skepticism:
"Wait... are you putting an entire virtual machine inside a container? Isn't that anti-pattern virtualization-ception?"
The short answer: No.
OpenShift Virtualization does not run a hypervisor inside a container. Instead, it leverages the open-source KubeVirt technology to treat Virtual Machines as native Kubernetes workloads—giving VMs the same declarative deployment, GitOps pipelines, software-defined networking, and storage capabilities as regular containers.
In this first part of our series, we're popping the hood to see how KubeVirt actually coordinates compute, memory, and kernel primitives across an OpenShift cluster.
🏗️ The Big Picture Architecture
At its core, a virtual machine on Linux is simply a QEMU process running in user space, accelerated by the KVM kernel module.
KubeVirt encapsulates that QEMU process inside standard Linux namespaces (cgroups, network, PID) through a specialized pod called virt-launcher.
Here is how the control plane and worker nodes interact:
http://googleusercontent.com/image_generation_content/8_25
Let's break down each component shown above.
🧠 The Control Plane Components
The control plane orchestrates the lifecycle of virtual machines using standard Kubernetes controller patterns:
1. virt-operator
The operator responsible for deploying, upgrading, and managing the lifecycle of all KubeVirt custom resource definitions (CRDs) and services across the cluster. It ensures your virtualization stack stays healthy and up-to-date.
2. virt-api
Acts as the entry door for virtualization requests. It provides:
- Admission Webhooks: Validates and mutates VM specifications before they hit
etcd. - Subresource Endpoints: Powers interactive features like VNC graphical consoles, serial consoles, and power actions (start, stop, pause, restart) via
virtctl.
3. virt-controller
The brain behind state reconciliation. When you request a virtual machine:
- It reads your
VirtualMachinemanifest. - It coordinates with the Kubernetes scheduler by generating a matching Pod specification.
- It tracks VM lifecycle transitions (e.g., Scheduling ➔ Starting ➔ Running ➔ Stopping).
⚙️ The Node-Level Components
Down on the worker nodes where compute happens, two key components make virtualization possible:
1. virt-handler (DaemonSet)
Runs as a privileged pod on every worker node eligible to run virtual machines. Its responsibilities include:
- Communicating with the local node's
libvirtdaemon. - Interfacing with host hardware devices (like
/dev/kvm). - Executing node-specific operations triggered by the
virt-controller.
2. virt-launcher Pod
This is the pod scheduled by Kubernetes to host your virtual machine.
- It creates the cgroup and namespace boundaries.
- It executes
libvirtand boots theqemu-kvmprocess. - If your VM crashes or shuts down, the
virt-launcherpod terminates cleanly.
📄 The Two Essential CRDs: VM vs. VMI
One of the most common early confusions in KubeVirt is the difference between:
| Custom Resource | Equivalent in K8s | Purpose |
|---|---|---|
VirtualMachine (VM) | Deployment / StatefulSet | Declarative definition of the VM (CPU, memory, disks). Maintains desired running state even across reboots. |
VirtualMachineInstance (VMI) | Pod | The active, ephemeral running instance of a VM. Created dynamically when a VM is started (running: true). |
yaml` apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: name: fedora-workload spec: running: true # <--- Setting this creates the active VMI template: spec: domain: devices: disks: - name: containerdisk disk: bus: virtio resources: requests: memory: 2Gi cpu: 2 volumes: - name: containerdisk containerDisk: image: quay.io/containerdisks/fedora:latest 🛠️ Step-by-Step: Enabling OpenShift Virtualization To get started on your OpenShift cluster via CLI: 1. Subscribe to the Operator Bash cat <<EOF | oc apply -f - apiVersion: [operators.coreos.com/v1alpha1](https://operators.coreos.com/v1alpha1) kind: Subscription metadata: name: hco-operatorhub namespace: openshift-cnv spec: channel: stable name: kubevirt-hyperconverged source: redhat-operators sourceNamespace: openshift-marketplace EOF 2. Deploy the HyperConverged Cluster (HCO) CR Once the operator CSV reports Succeeded, initialize the control plane: Bash cat <<EOF | oc apply -f - apiVersion: hco.kubevirt.io/v1beta1 kind: HyperConverged metadata: name: kubevirt-hyperconverged namespace: openshift-cnv spec: {} EOF 3. Verify Health Verify that all control plane and node daemon pods are running: Bash oc get pods -n openshift-cnv 💡 Battle-Tested Gotchas & Pro-Tips ⚠️ Gotcha: Is Hardware Virtualization Enabled? If your worker nodes run inside a public cloud or nested lab environment, KVM hardware acceleration (/dev/kvm) might not be exposed by default. Verify your node labels: Bash oc get nodes -l kubevirt.io/schedulable=true If you see no nodes matching this label, check if nested virtualization is enabled on the hypervisor host: Bash # On your node terminal: ls -l /dev/kvm egrep -c '(vmx|svm)' /proc/cpuinfo For dev/lab testing only: You can enable software emulation inside the HyperConverged CR under spec.configuration.developerConfiguration.useEmulation: true, though it is strictly not supported for production. ⏭️ What's Next? Now that the control plane is live and you understand the anatomy of a virt-launcher pod, the next critical hurdle is Storage. In Part 2, we will dissect: Block vs. Filesystem volume modes. TopoLVM / LVM Storage vs. ODF. Avoiding the dangerous extent size calculation bug when creating CSI snapshots. 💬 Question for you: Are you currently planning a migration from legacy hypervisors to OpenShift Virtualization, or experimenting in labs? Drop your thoughts in the comments! 原文:https://www.a8q9.cn/en/article/part-1-architecture-under-the-hood-e6d02b.html