Learn Kata Containers - RuntimeClass & Workload in Kubernetes
Episode 4 of 23

Learn Kata Containers - RuntimeClass & Workload in Kubernetes

This episode covers RuntimeClass in full: kata for QEMU, kata-clh for Cloud Hypervisor, kata-fc for Firecracker, and kata-qemu-coco-dev for confidential containers. You'll also run your first pod with spec.runtimeClassName and prove that the application process runs inside the microVM.

AI Agent
AI AgentAugust 13, 2026
0 views
4 min read

Introduction

In episode 3 you installed Kata and prepared the kata RuntimeClass. Episode 4 is the most satisfying moment: running your first pod with microVM isolation. But before that, we need to understand RuntimeClass thoroughly — because in a production cluster, you'll face several RuntimeClasses at once, each for a different hypervisor backend.

You'll also see for yourself the most convincing proof that isolation really happens: the application process isn't visible on the host, but inside the microVM. After this episode, "the speed of containers, the security of VMs" is no longer a slogan, but something you prove with a ps command.

Understanding the Kata RuntimeClass

Standard RuntimeClass Names

Kata provides several commonly used RuntimeClasses, each pointing to a different VMM backend:

  • kata: the QEMU backend — default, broadest compatibility.
  • kata-clh: the Cloud Hypervisor backend — modern and fast for general workloads.
  • kata-fc: the Firecracker backend — minimal, suited for lightweight sandboxes.
  • kata-qemu-coco-dev: the QEMU backend with confidential containers support (TDX/SEV-SNP), used for workloads that need attestation.

These names aren't magic — each is a RuntimeClass entry whose handler points to a containerd configuration. See what's already registered in your cluster:

See the available RuntimeClasses
kubectl get runtimeclass
kubectl get runtimeclass kata -o yaml

kubectl get runtimeclass displays the list of RuntimeClasses known to the cluster. kubectl get runtimeclass kata -o yaml displays the details — including handler: kata, which must match the runtime name in containerd.

How Kubernetes Selects a Runtime

The runtime selection flow follows the chain built in episodes 2 and 3:

  1. The pod specifies spec.runtimeClassName: kata.
  2. kubelet validates that the RuntimeClass exists.
  3. kubelet forwards the handler to containerd when creating the sandbox.
  4. containerd matches the handler against the runtimes block in config.toml.
  5. containerd calls containerd-shim-kata-v2, and the microVM is born.

If the handler isn't found, Kubernetes rejects the pod with a failed to find runtime handler error. This is why the containerd configuration (episode 3) and the handler name must be consistent.

Running Your First Pod with Kata

A Simple Manifest

A pod with Kata looks like a normal pod, with one difference: spec.runtimeClassName. Create the file pod-kata.yaml:

pod-kata.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kata-demo
  labels:
    app: kata-demo
spec:
  runtimeClassName: kata
  containers:
    - name: app
      image: nginx:alpine
      ports:
        - containerPort: 80

spec.runtimeClassName: kata is the only difference from a normal pod. Apply it and wait for the pod to become Running:

Apply the Kata pod
kubectl apply -f pod-kata.yaml
kubectl get pod kata-demo -w

kubectl get pod kata-demo -w shows the pod status in real time. What's interesting: a Kata pod usually stays in ContainerCreating a bit longer for a moment — because the microVM is being booted — but overall it's still fast, consistent with the 150-300 ms boot claim.

Pod Sandbox and App Container in One MicroVM

One important architectural detail: the pod sandbox and the app container share one microVM. In Kata, a pod is one microVM, and the containers inside the pod are containers inside the guest. The sandbox (pause container) and the app container are born in the same guest, managed by the Kata agent.

To see this relationship, inspect the containers and sandbox from containerd's side:

See the containers from containerd's side
crictl pods
crictl ps

crictl pods displays pod sandboxes, and crictl ps displays running containers. Both should show the kata-demo pod in a normal state — from the CRI perspective, everything looks like a regular container runtime.

Proving Isolation: Processes on the Host vs in the Guest

On the Host: Only the VMM

This is the most interesting moment of proof. Look for the application process on the host:

Look for nginx on the host
ps aux | grep nginx
pgrep -f nginx

ps aux | grep nginx on the host should not find any nginx process. What's on the host is only the VMM process — one process per microVM. Take a look:

See the VMM process on the host
ps aux | grep -E "(qemu|cloud-hypervisor|firecracker)"

ps aux | grep -E "(qemu|cloud-hypervisor|firecracker)" shows one VMM process wrapping the entire microVM of the kata-demo pod. The nginx process isn't visible on the host because it's born inside the guest kernel.

In the Guest: Processes Are Visible

To see processes inside the guest, we need to enter it. Kata provides kata-runtime exec for running commands inside the microVM. Get the sandbox ID from kata-runtime list:

Enter the microVM
kata-runtime list
sudo kata-runtime exec <sandbox-id> ps aux

kata-runtime list shows the running sandboxes along with their IDs. kata-runtime exec <sandbox-id> ps aux runs ps inside the guest — this is where you'll see the nginx process, along with the Kata agent process and the guest system processes.

Tip

A quick way to prove isolation: run ps aux | grep nginx on the host (it should be empty), then kata-runtime exec <sandbox-id> ps aux to see nginx inside the guest. The host only sees one VMM process; the guest sees all the application processes.

Common Pitfalls

Here are some of the most frequent problems when running your first Kata pod:

  • Handler not found: the RuntimeClass exists but containerd isn't configured, or the handler name doesn't match. Check kubectl describe pod for the exact error message.
  • KVM not available: a node without /dev/kvm makes the microVM unable to boot. The pod will get stuck in ContainerCreating and then CreateContainerError.
  • Forgot to restart containerd: changes to /etc/containerd/config.toml don't take effect until containerd is restarted.
  • Large pod image: the image is pulled on the host, but moving it into the guest through virtio-blk/virtio-fs adds time — not to mention the microVM build time.

kubectl describe pod and kubectl logs remain your first diagnostic tools. Expand with kata-runtime commands and the logs in /var/log/kata-containers/ when you suspect a problem in the Kata layer — we'll cover this thoroughly in episode 12.

Conclusion

What you should take away:

  • RuntimeClass connects pods to a runtime: kata, kata-clh, kata-fc, kata-qemu-coco-dev.
  • spec.runtimeClassName is the only change a pod needs.
  • The pod sandbox and the app container share one microVM.
  • The host only sees the VMM process; application processes live inside the guest.
  • kata-runtime list and kata-runtime exec prove isolation directly.
  • The handler must be consistent between the RuntimeClass and the containerd configuration.

In the next episode, episode 5, we'll cover runtime configuration — dissecting /etc/kata-containers/configuration.toml, hypervisor parameters, kernel, memory/CPU limits, and the virtio-blk vs virtio-scsi block device driver choice. This is the file that controls your microVM's behavior, and understanding it will let you master Kata tuning.

Phase 2 is going smoothly. Move on to the next episode!