Skip to content
Published on

Container Runtimes 2026 Deep Dive - containerd, runc, Podman, CRI-O, Kata, gVisor, Firecracker, Wasm

Authors

Intro — May 2026, Container Runtimes Have Entered the Multi-Layer Isolation Era

The era when Docker was synonymous with containers is over. As of May 2026, more than 95% of Kubernetes clusters run on containerd or CRI-O. On the developer desktop, Podman and Docker Desktop trade share. Serverless backends run on Firecracker. And Wasm runtimes are starting to eat parts of the container niche, with WasmEdge and wasmtime plugging into Kubernetes directly through a containerd-shim called runwasi.

This article is not a marketing matrix. It is an honest look at "what runtime fits where in 2026 production": OCI image spec, CRI, low-level runtimes, isolation strength, image builders, registries, signing, and vulnerability scanning, end to end.

Five Layers of the Container Stack — From OCI Image to Kernel

Big picture first. The 2026 container stack decomposes into five layers.

  1. OCI image format (image-spec): manifest + layered tarballs + config JSON
  2. Registry (distribution-spec): ECR, GAR, Harbor, Quay all share the same API
  3. High-level runtime (CRI/engine): containerd, CRI-O, Docker Engine, Podman
  4. Low-level runtime (OCI runtime): runc, crun, youki, kata-runtime, runsc(gVisor)
  5. Isolation mechanism: namespaces + cgroups, micro VMs, userspace kernels, Wasm sandboxes

These layers are connected by two standards: OCI image-spec and OCI runtime-spec. An image built by any builder should run on any runtime. As of 2026 this promise rarely breaks.

containerd — The Default CRI for Kubernetes

containerd started life inside Docker Engine, graduated from CNCF in 2017, and became the de facto CRI for Kubernetes. EKS, GKE, AKS, and OpenShift all default to containerd. Docker Desktop also uses containerd under the hood.

The architecture is simple.

  • containerd daemon: image pull, storage, networking, container lifecycle
  • CRI plugin: talks gRPC with kubelet
  • OCI runtime shim: per-container small shim that invokes runc
  • snapshotter: layer filesystem (overlayfs, native, btrfs, zfs, stargz)

containerd 2.0 (GA late 2025) makes NRI (Node Resource Interface), userspace NRI plugins, and Wasm shim (runwasi) integration first-class. nerdctl is the docker-compatible CLI for containerd and supports nearly identical commands.

# Drive containerd directly with nerdctl
sudo nerdctl pull alpine:3.20
sudo nerdctl run --rm -it alpine:3.20 sh
sudo nerdctl images
sudo nerdctl ps -a

# Inspect the CRI plugin
sudo crictl info | jq '.config.containerd'
sudo crictl ps

runc, crun, youki — Three OCI Low-Level Runtimes

The OCI runtime spec is an interface: "given a config.json and rootfs, start a container." Three runtimes implement it.

  • runc: the de facto reference, written in Go. Applies namespaces, cgroups, and seccomp.
  • crun: C implementation. Faster startup and lower memory than runc. Red Hat ships it by default in Podman and CRI-O.
  • youki: Rust reimplementation of runc. Frequently discussed at Container Plumbing Days and adopted by some sandbox projects.

Because all three implement the OCI spec, they are interchangeable in containerd runtimes config.

# /etc/containerd/config.toml (excerpt)
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun]
  runtime_type = "io.containerd.runc.v2"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun.options]
    BinaryName = "/usr/bin/crun"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.youki]
  runtime_type = "io.containerd.runc.v2"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.youki.options]
    BinaryName = "/usr/local/bin/youki"

CRI-O — A Lean Kubernetes-Only CRI

CRI-O is a Kubernetes-specific CRI led by Red Hat. It does not pretend to be docker-compatible. It only acts as a bridge between kubelet and an OCI runtime. It is the default CRI on OpenShift and has a smaller node footprint than containerd.

Choosing between containerd and CRI-O usually comes down to operator familiarity. EKS and GKE defaults give you containerd. OpenShift gives you CRI-O. In 2026 the practical isolation and feature gap is small.

Docker Engine — Surviving on Desktops and Legacy Servers

Docker Engine is still around in 2026, but its role has narrowed. It is the default on desktop (Docker Desktop) and some legacy servers. It has nearly disappeared from Kubernetes nodes. The engine itself is a thin wrapper that internally uses containerd.

Where Docker still wins is developer UX. docker compose for multi-container development is dominant, and Buildx + Docker Build Cloud accelerated builds. So "production on containerd, development on Docker Desktop" remains a common pairing.

Podman + Buildah + Skopeo — The Rootless, Daemonless Trio

Podman offers a docker-compatible CLI without a daemon. Each container is a user process; systemd manages its lifecycle. With no daemon, no root is required (rootless). It is the default on Fedora, RHEL, and CentOS Stream and ships as a standard package on Ubuntu LTS.

  • Podman: container execution and pod management (the same concept as a Kubernetes pod)
  • Buildah: Dockerfile builder. Builds OCI images without a daemon
  • Skopeo: image metadata inspection, copy, and signature verification

The trio is Red Hat driven but follows OCI standards strictly, so it mixes freely with other runtimes and registries.

# Rootless Podman
podman run --rm -it --userns=keep-id alpine:3.20 id

# Daemonless build with Buildah
buildah bud -t myapp:1.0 .
buildah push myapp:1.0 docker://registry.example.com/myapp:1.0

# Copy images across registries with Skopeo
skopeo copy --src-creds user:pass --dest-creds user:pass \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.example.com/library/nginx:1.27

Kata Containers 3.x — Strong Isolation via Lightweight VMs

Kata Containers runs a lightweight VM behind the container interface so the guest kernel is isolated from the host. A host-kernel CVE no longer trivially turns into a container escape. The 3.x line (2024-2026) lets you pick QEMU, Firecracker, or Cloud Hypervisor as the hypervisor and brings startup down to 1-2 seconds.

Kata registers in containerd as kata-qemu, kata-fc, or kata-clh. In Kubernetes you use RuntimeClass to apply different isolation tiers per workload.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata-clh
handler: kata-clh
---
apiVersion: v1
kind: Pod
metadata:
  name: untrusted-workload
spec:
  runtimeClassName: kata-clh
  containers:
    - name: app
      image: registry.example.com/untrusted-app:1.0

gVisor — Google's Userspace Kernel Sandbox

gVisor (runsc) is Google's userspace kernel. Instead of passing syscalls through to the host kernel, runsc implements them in user space. It is not a VM but still drastically shrinks host-kernel attack surface.

The downside is that some network and file I/O paths are slower for certain workloads. gVisor fits untrusted code execution (serverless functions, CI build runners, AI inference for user code) and is less suited to I/O-heavy workloads like databases. Google Cloud Run and GKE Sandbox use gVisor internally.

# Register runsc with Docker and run
sudo runsc install
sudo systemctl restart docker
docker run --rm --runtime=runsc alpine:3.20 uname -a
# The kernel version printed will reflect runsc's simulated kernel, not the host

Firecracker — AWS MicroVMs

Firecracker is the KVM-based micro VM monitor AWS built. Lambda, Fargate, and App Runner all isolate workloads in Firecracker microVMs. A VM boots in under 125ms with less than 5MB of memory overhead. It is written in Rust and trims the device model aggressively to minimize attack surface.

Firecracker takes a REST API to configure vCPU, memory, kernel image, rootfs, and network interfaces, then starts the instance.

{
  "boot-source": {
    "kernel_image_path": "/var/lib/firecracker/vmlinux",
    "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
  },
  "drives": [
    {
      "drive_id": "rootfs",
      "path_on_host": "/var/lib/firecracker/rootfs.ext4",
      "is_root_device": true,
      "is_read_only": false
    }
  ],
  "machine-config": {
    "vcpu_count": 2,
    "mem_size_mib": 512,
    "smt": false
  }
}

Cloud Hypervisor — A Joint Intel, AWS, Microsoft MicroVM

Cloud Hypervisor started at Intel and now has AWS, Microsoft, Tencent and others as core contributors. Like Firecracker it is a KVM-based VMM, but with a richer device model and both ARM and x86 support. It backs Kata Containers (kata-clh), Azure Confidential Containers, and parts of AWS container isolation. In 2026 the micro-VM space is essentially Firecracker vs. Cloud Hypervisor.

Wasm Runtimes — A New Isolation Unit Inside Kubernetes

WebAssembly is eating parts of the container space fast. WasmEdge, wasmtime, wasmer, and lunatic start in microseconds and have memory overhead an order of magnitude lower than containers. CNCF standardized Wasm-in-Kubernetes through the runwasi containerd-shim.

  • WasmEdge: CNCF Incubation. Strong K8s integration and AI inference (LLM, video)
  • wasmtime: Bytecode Alliance reference implementation, leads WASI
  • wasmer: multiple backends (LLVM, Cranelift, Singlepass)
  • lunatic: actor model inspired by Erlang/BEAM
  • Spin (Fermyon): Wasm microservices framework
  • wasmCloud: distributed Wasm actor system, CNCF Incubation

The common path to run Wasm workloads in Kubernetes is to register runwasi with containerd and route via RuntimeClass.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: wasmedge
handler: wasmedge
---
apiVersion: v1
kind: Pod
metadata:
  name: hello-wasm
spec:
  runtimeClassName: wasmedge
  containers:
    - name: hello
      image: registry.example.com/hello-wasm:1.0
      command: ['/hello.wasm']

WASI and the Wasm Component Model — Compatibility Standards

The key to Wasm replacing parts of containers is WASI (WebAssembly System Interface). WASI preview 1 shipped first, preview 2 stabilized in 2024, and the component model approached GA in late 2025. The component model unifies language-level ABIs so a Wasm component built in Rust runs unchanged inside Go, JavaScript, or Python hosts.

In 2026 the most active use of WASI and the component model is in edge computing (Cloudflare Workers, Fastly Compute), plugin systems (Envoy, Open Policy Agent, Istio), and AI inference (WasmEdge + ONNX, GGUF).

Isolation Strength Compared — Which to Use When

The two main axes when picking a runtime are isolation strength and startup time. As of May 2026 the typical combinations look like this.

  • runc/crun/youki: process isolation, 50-200ms startup. Trusted code. Default for most K8s workloads
  • gVisor (runsc): userspace kernel, 200-400ms startup. Untrusted user code, CI runners
  • Kata Containers: lightweight VM (QEMU/FC/CLH), 1-2s startup. Multi-tenant, compliance
  • Firecracker microVM: KVM, 100-200ms startup. Serverless, short-lived
  • Wasm (WasmEdge/wasmtime + runwasi): sandbox, 1-10ms startup. Edge, plugins, AI

Strictly speaking, micro VMs and Kata offer the strongest isolation. Wasm is weaker but has a different threat model — it does not protect against container-escape kernel CVEs the way a VM does. runc is the weakest but fastest and most compatible.

OCI Image Builders — BuildKit, kaniko, buildah, jib, ko, Buildpacks

In 2026 you still have many ways to build an image. Which you pick depends on environment (do you have a docker daemon, or are you building inside Kubernetes?) and language stack.

  • BuildKit: Docker's next-gen builder. Cache mounts, secret mounts, multi-platform are first-class. docker buildx is the user interface.
  • kaniko: Build Dockerfiles inside a Kubernetes pod with no docker daemon. Most common in GitLab CI and Argo Workflows.
  • buildah: Podman's sibling. Build OCI images without a daemon and script the build steps from shell.
  • img: Userspace builder that drives BuildKit without a daemon.
  • jib: Maven/Gradle plugin. Builds JVM apps into OCI images with no Dockerfile.
  • ko: For Go. ko build turns Go sources directly into OCI images and pushes to K8s.
  • Bazel container_image rules / rules_oci: deterministic image builds from a Bazel graph.
  • Cloud Native Buildpacks (Paketo): no Dockerfile; heuristics pick the base. The spiritual heir to Heroku and Pivotal buildpacks.

A typical BuildKit multi-stage Dockerfile with cache mounts looks like this.

# syntax=docker/dockerfile:1.7
FROM golang:1.23 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    go mod download
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build \
    --mount=type=cache,target=/go/pkg/mod \
    CGO_ENABLED=0 go build -o /out/app ./cmd/server

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]

OCI Image Format — Manifest v2 and the Image Index

The OCI image spec consists of three objects. A manifest referencing layers and config, a config JSON with entrypoint, env, and history, and layers as tar.gz or zstd archives. Multi-architecture images are grouped under an image index (manifest list).

In 2026 the standardization wins include OCI image-spec 1.1 zstd layers, OCI artifacts (push non-image payloads in the same format), and the referrer API from OCI 1.1 dist-spec. These let cosign signatures, SBOMs, and attestations live as sidecars next to the image in the same registry.

OCI Distribution and Registries — A Full-Stack View

Registries have also converged on the OCI distribution spec. Whatever cloud registry you use, the API is the same.

  • Docker Hub: public images center. Pull-rate limits push production pulls elsewhere
  • GitHub Container Registry (ghcr.io): integrated with GitHub Actions and friendly to OSS
  • GitLab Container Registry: bundled with self-hosted GitLab
  • AWS ECR / ECR Public: IAM integration, multi-region, pull-through cache
  • Google Artifact Registry (GAR): successor to GCR, multi-format
  • Azure Container Registry (ACR): geo-replication, OCI artifacts on Premium SKU
  • Harbor: CNCF Graduate. The self-hosted standard, with replication, scanning, and signing enforcement
  • Quay: Red Hat. Bundled with OpenShift
  • JFrog Artifactory: multi-package-manager universal registry
  • DigitalOcean Container Registry: cost-effective for small teams
  • NVIDIA NGC: AI and HPC container catalog

Image Signing — cosign and notation (Notary v2)

Image provenance standardization landed in 2024.

  • cosign: part of Sigstore. Keyless signing (OIDC + Fulcio + Rekor) removes key management overhead. SLSA provenance and SBOM attestations use the same tool.
  • notation (Notary v2): CNCF Sandbox. X.509 based signing, fits enterprise PKI. Driven by Microsoft and IBM.

In Kubernetes, admission controllers (Sigstore Policy Controller, Kyverno, OPA Gatekeeper) block unsigned images.

# Keyless cosign signing and verification
cosign sign --yes registry.example.com/myapp:1.0
cosign verify \
  --certificate-identity-regexp 'https://github.com/myorg/.*' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  registry.example.com/myapp:1.0

Vulnerability Scanning — Trivy, Grype, Snyk, Clair

Image scanning at build or push time is now standard too.

  • Trivy: Aqua Security, donated to CNCF. CVEs, secrets, IaC, and Kubernetes policies in a single binary
  • Grype: Anchore. SBOM-driven scanning, paired with Syft
  • Snyk Container: SaaS-first, strong developer UX
  • Clair: bundled with Quay, the self-hosted standard
  • Docker Scout: integrated with Docker Desktop, dependency graph and base-image suggestions

The most common combo in 2026 is GitHub Actions or GitLab CI failing builds via Trivy, Harbor or ECR scanning automatically on push, and K8s admission verifying both cosign signatures and Trivy reports.

Rootless, userns, cgroups v2 — Baselines in 2026

Linux-host isolation baselines have also stabilized.

  • rootless: daemon and runtime run as an unprivileged user. Podman is rootless by default; containerd does it via rootlesskit
  • user namespaces remapping: container root maps to an unprivileged user on the host. K8s 1.30+ user-namespace support is beta to GA
  • cgroups v2: unified memory, CPU, and I/O controllers. Default on every major 2026 distro
  • seccomp: syscall whitelist. K8s recommends a default profile
  • eBPF-based LSMs: Tetragon and Tracee provide runtime monitoring and enforcement

Kubernetes RuntimeClass and Multi-Runtime Nodes

RuntimeClass is the Kubernetes API for selecting which runtime among several registered ones runs a workload. A common picture is: runc for trusted workloads, gVisor for user code, Kata for multi-tenant, Wasm for edge functions — all in the same cluster.

Operationally the simplest is splitting node pools by runtime. But the pattern of registering multiple runtimes on the same node and routing via admission has grown. In managed K8s, GKE Sandbox (gVisor), AKS Confidential Containers (Kata + Cloud Hypervisor), and EKS on Fargate (Firecracker) each take their own route.

Build Cache and Reproducible Builds

In 2026 build cache is no longer optional. BuildKit and buildah support inline and registry-pushed cache manifests. Bazel rules_oci, ko, and jib guarantee deterministic builds (same input → same digest). Reproducible builds are the foundation of SLSA-grade provenance.

The biggest CI win is combining BuildKit cache mounts with external cache (--cache-to type=registry on Buildx).

Korea — Naver Container Engine and Coupang's Runtime Journey

Korea has matured by deeply consuming standards rather than building its own runtimes.

  • Naver Container Engine (NCE): managed K8s on Naver Cloud Platform. Built on containerd, bundles its own CNI, registry, and security tooling.
  • Coupang: during its peak traffic growth, it widely migrated from Docker Engine to containerd. Build pipelines mix BuildKit and kaniko, and internal registries split between Harbor and ECR per environment.
  • Kakao: internal PaaS standardizes on K8s + containerd, and is evaluating extra isolation like gVisor for select user-code paths.
  • Samsung SDS and LG CNS: many enterprise OpenShift (CRI-O) deployments, with managed K8s mixed across NCE, EKS, and GKE.

Japan — Mercari's containerd Migration and LY Verda Containers

Japan moved to OSS standards quickly too.

  • Mercari: between 2019 and 2021 it migrated nodes from Docker Engine to containerd, and unified its internal PaaS and build pipelines around BuildKit + GAR. The story has been shared at multiple conferences.
  • LY (LINE + Yahoo Japan) Verda: LY's private cloud. Kubernetes runs on containerd, evaluates Kata for select workloads, and operates a full Harbor fleet as the internal registry.
  • CyberAgent and DeNA: K8s + containerd is the standard, with public PoCs for gVisor and Firecracker for untrusted code execution.
  • NTT Communications: SmartCloud offers managed OpenShift (CRI-O).

Migration Patterns — From Docker Engine to containerd

The most common legacy migration is Docker Engine to containerd. After Kubernetes 1.24 removed dockershim, EKS, GKE, AKS, and OpenShift all switched automatically, but self-hosted clusters still have some migration ahead of them.

The core moves are (1) replacing the node container runtime, (2) updating monitoring and logging agents to the new socket path (/var/run/docker.sock → /run/containerd/containerd.sock), and (3) decoupling internal build pipelines from a docker daemon by switching to BuildKit, kaniko, or buildah.

Cost and Ops Perspective — Which Combo Should You Pick

As of May 2026 the recommended combinations by workload look like this.

  • Generic K8s workloads: containerd + runc, BuildKit for builds, one of ECR / GAR / Harbor for the registry, cosign for signing, Trivy for scanning
  • Untrusted user code: containerd + gVisor (runsc) or Kata. Route via RuntimeClass
  • Serverless functions: Firecracker-based (AWS Lambda, Fargate). Self-built means Firecracker + jailer
  • Edge and plugins: WasmEdge or wasmtime + runwasi. Faster startup and lighter memory than containers
  • Developer machines: Podman or Docker Desktop. macOS leans Docker Desktop or OrbStack, Linux leans Podman

Security Best Practices — A 2026 Checklist

These are checklist items at the full-stack level, not per runtime.

  • Image provenance: cosign keyless signing + Sigstore Rekor transparency log, SLSA Level 3 or higher build environment
  • Image content: Trivy or Grype scan on every push, slim bases like distroless, Chainguard, or Wolfi
  • Node isolation: rootless containers, user namespace remapping, seccomp default profile, AppArmor or SELinux
  • K8s admission: signature verification, vulnerability policy, network policy, Kyverno or OPA Gatekeeper
  • Runtime visibility: Falco, Tetragon, or Tracee for eBPF-based syscall and network anomaly detection
  • Signing and SBOM retention: push SBOM (SPDX, CycloneDX) attestations next to images and retain every trace

Wrapping Up — The Next Decade of Containers

Containers are not over. But the "Docker container" as a single model is over. As of May 2026, behind the container interface sit at least five isolation mechanisms: namespaces + cgroups, micro VMs, userspace kernels, Wasm sandboxes, and confidential VMs. OCI standards stitch the layers together.

Two shifts will define the next decade. First, Wasm will keep eating parts of the container space — starting at the edge, plugins, and AI inference, then expanding into general backends. Second, confidential computing (AMD SEV-SNP, Intel TDX, ARM CCA) will become the standard for multi-tenant and regulated workloads. Both ride on OCI and Kubernetes standards. Teams that deeply understand the standards will adapt the fastest.

References