Skip to main content
Software Engineering
•8 min read

Kiri – A Deep Architectural Dive into the Modern Container Runtime

Kiri re‑imagines the container runtime stack with a Rust‑first, zero‑copy design that slashes start‑up latency and improves isolation. This editorial unpacks its internals, critiques common engineering pitfalls, and sketches a roadmap for the next wave of cloud‑native execution.

Kiri – A Deep Architectural Dive into the Modern Container Runtime

Introduction

The container ecosystem has coalesced around a handful of battle‑tested runtimes—

runc
,
crun
, and
containerd
. Each iteration has chased performance, security, and developer ergonomics, but they all inherit a legacy C‑centric ABI and a heavyweight OCI shim layer. Kiri (https://runkiri.com/) arrives as a modern container runtime written entirely in Rust, promising sub‑millisecond start‑up, deterministic memory management, and a pluggable scheduling model that can be embedded directly into a service mesh or edge node.

In this deep‑dive we will:

  1. Dissect Kiri’s architecture—its protocol stack, memory model, and latency‑critical paths.
  2. Offer a first‑person FutureStack commentary from Mubashir Arham on why teams repeatedly trip over the same design traps.
  3. Provide a runnable Rust snippet that demonstrates how to launch a sandboxed process via Kiri’s native API.
  4. Compare Kiri against the incumbent runtimes across latency, cost, scalability, and complexity.
  5. Project how container runtimes will evolve over the next 18‑36 months.

Deep Architectural Breakdown

1. Execution Model – From OCI to Kiri’s Native Spec

Kiri implements a superset of the OCI Runtime Specification but does not rely on the OCI shim for process management. Instead, it defines a Kiri Execution Graph (KEG) that models a container as a directed acyclic graph of tasks (processes, side‑cars, init containers). Each node in the graph is a Kiri Task Descriptor (KTD) containing:

  • uid/gid
    mapping
  • cgroup
    profile identifier
  • namespace
    bindings (net, pid, ipc, uts)
  • resource‑limits
    (CPU, memory, IO)
  • entrypoint
    binary and arguments

When a

kiri run
request arrives, the runtime parses the KEG, allocates a Task Arena (a memory‑mapped region shared between the parent and child via
memfd_create
), and spawns the first task using
clone3(2)
with a minimal set of flags (
CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWNET|CLONE_NEWUTS
). The key departure from
runc
is that Kiri does not fork a shim process; the parent process directly monitors the child via
pidfd_open(2)
and
epoll
. This eliminates a full process context switch and reduces start‑up latency by ~40 % in micro‑benchmarks.

2. Scheduler & Isolation – The Rust‑Owned Scheduler

Kiri ships its own cooperative scheduler built on top of

tokio
(or
async-std
for no‑std environments). The scheduler is responsible for:

  • Cgroup v2 management – Kiri interacts with the unified hierarchy via the
    cgroupfs
    API, applying
    io.max
    ,
    cpu.max
    , and
    memory.high
    atomically using
    cgroup2.clone_children
    .
  • Namespace lifecycle – Namespace creation is lazily performed; a shared network namespace can be reused across multiple tasks, reducing
    netns
    churn.
  • Resource reclamation – When a task exits, the scheduler asynchronously tears down the cgroup, unmounts overlayfs layers, and releases the
    memfd
    arena.

Because the scheduler lives in the same address space as the runtime, Kiri can batch syscalls (e.g.,

mount
multiple layers in a single
mount_setattr
call) and avoid the “fork‑exec‑wait” penalty that plagues older runtimes.

3. Memory & Filesystem Layer – Zero‑Copy OverlayFS

Kiri’s Zero‑Copy Overlay (ZCO) leverages

overlayfs
with the
index=on
and
metacopy=on
options. The runtime pre‑populates a read‑only base layer (often an OCI image unpacked into
/var/lib/kiri/base/<digest>
) and then creates a per‑task writable layer using
tmpfs
backed by a
memfd
. The writable layer is memory‑mapped directly into the task’s address space via
mmap(MAP_SHARED|MAP_ANONYMOUS)
, eliminating the need for copy‑on‑write page faults for most writes.

The memory model follows Rust’s ownership rules: the Task Arena owns a

Arc<Mutex<...>>
that guards mutable state, while the child process receives a read‑only file descriptor for the base layer. This design guarantees that a buggy container cannot corrupt the base image, a common source of security incidents in C‑based runtimes.

4. Networking Stack – Integrated CNI Lite

Kiri embeds a lightweight CNI implementation called KiriCNI. Instead of invoking an external plugin binary, KiriCNI loads a JSON net‑config and creates a veth pair using

netlink
directly from the runtime. The host side of the veth is attached to a bridge namespace that can be shared across many containers, while the container side is placed in the task’s network namespace.

Key performance knobs:

  • TC‑based shaping is applied via
    tc qdisc
    at bridge creation time, enabling deterministic bandwidth limits without per‑container iptables rules.
  • IPAM is performed using an in‑process allocator that reserves IP blocks from a CIDR pool, avoiding the latency of external etcd calls.

5. Security & Credential Management – Capability‑Centric Design

Kiri’s security model is capability‑first. The runtime parses a Capability Policy (YAML) that maps high‑level intents (

network-access
,
host‑pid
) to Linux capabilities (
CAP_NET_RAW
,
CAP_SYS_PTRACE
). The policy is enforced at task creation via
prctl(PR_SET_SECUREBITS, ...)
and
capset(2)
. Additionally, Kiri integrates with KMS‑backed secrets:

  • Secrets are fetched from Vault/Google KMS using a zero‑trust token.
  • The secret is written to a memfd that is passed as an FD to the container, never touching the host filesystem.

6. Latency & Compute Dynamics – Numbers from the Reference Benchmarks

PhaseSystem Call(s)Avg Latency (µs)Comments
Namespace creation
clone3
,
unshare
45One‑shot creation; no intermediate shim.
Cgroup attach
cgroup2.attach
,
io.max
write
12Batched via
writev
.
Overlay mount
mount_setattr
(multiple layers)
28Zero‑copy, no page‑fault churn.
Network setup
netlink
veth + bridge
33In‑process CNI avoids external exec.
Total start‑up (empty container)–~115 µsRoughly 5× faster than
runc
on identical hardware.

The compute dynamics are dominated by the CPU cache locality of the scheduler. Because the scheduler runs in the same process as the runtime, task state lives in the same L3 cache line, reducing cache misses during cgroup updates. This is a subtle but measurable advantage when scaling to thousands of short‑lived containers (e.g., serverless functions).


The FutureStack Perspective (Mubashir Arham)

When I first evaluated Kiri for our edge‑compute platform at FutureStack, the first thing that struck me was the absence of a shim. Most teams cling to the shim because it feels “safer” – a separate process to monitor the child. In practice that shim becomes a latency black‑hole and a maintenance liability. Kiri’s decision to own the monitoring loop with

pidfd
and
epoll
is a bold, but technically sound, move that aligns with the Rust guarantee of memory safety.

*A recurring mistake I see in many engineering groups is the over‑reliance on OCI’s “spec‑first” mindset. The spec is a great lingua‑franca, but it was written for C‑centric runtimes. By treating the spec as a hard boundary, teams inherit unnecessary indirections (fork‑exec, JSON‑heavy config). Kiri demonstrates that you can extend the spec with a native graph model without breaking compatibility – the

kiri convert
command can ingest a standard
config.json
and emit a KEG.

*Another pitfall is resource‑fragmentation. When you spin up 10 000 containers on a node, each shim consumes a few megabytes of RSS and a file descriptor. Multiply that by 10 000 and you’re fighting OOM before you hit CPU limits. Kiri’s single‑process model reduces per‑container overhead to ~200 KB (Task Arena + memfd), which is a game‑changer for serverless workloads.

*Finally, the security model. Many runtimes rely on AppArmor or SELinux profiles that are static and hard to audit. Kiri’s capability‑policy is declarative, version‑controlled, and enforced at the syscall boundary. This makes automated compliance scans far more tractable.

In short, Kiri forces us to rethink three entrenched assumptions: (1) you need a shim, (2) the OCI spec must be the execution contract, and (3) security is an after‑thought. Teams that continue to cling to those assumptions will find themselves out‑paced by the next generation of edge‑first runtimes.


Code / Implementation Blueprint (Rust)

Below is a minimal, self‑contained example that launches an Alpine container using Kiri’s public crate

kiri-runtime
. The snippet showcases:

  • Building a
    TaskDescriptor
  • Attaching a cgroup v2 slice
  • Mounting a read‑only base layer
  • Passing a secret via
    memfd
use kiri_runtime::{
    runtime::{Runtime, RuntimeBuilder},
    task::{TaskDescriptor, Namespace, Capability},
    cgroup::CgroupSpec,
    secret::SecretMemfd,
};
use std::path::PathBuf;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 1️⃣ Initialise the runtime (uses the default Tokio scheduler)
    let runtime = RuntimeBuilder::default().build()?;

    // 2️⃣ Define a simple capability policy – only NET_RAW is needed for curl
    let caps = vec![Capability::NetRaw];

    // 3️⃣ Prepare a secret (e.g., API token) without touching the host FS
    let secret = SecretMemfd::from_bytes(b"my‑super‑secret-token")?;

    // 4️⃣ Build the task descriptor – note the overlay base image path
    let task = TaskDescriptor::builder()
        .uid(1000)
        .gid(1000)
        .namespace(Namespace::new()
            .new_pid()
            .new_net()
            .new_mount())
        .cgroup(CgroupSpec::builder()
            .cpu_max("50000 100000") // 50% of a single CPU
            .memory_max(256 * 1024 * 1024) // 256 MiB
            .build())
        .capabilities(caps)
        .rootfs(PathBuf::from("/var/lib/kiri/base/alpine_latest"))
        .entrypoint(vec!["/bin/sh", "-c", "echo $TOKEN && sleep 5"]) // prints secret then sleeps
        .env(vec![("TOKEN", "fd://".to_string())]) // token will be injected via FD
        .secret_fd(secret.as_raw_fd())
        .build();

    // 5️⃣ Run the container – `run` returns a handle we can await on
    let handle = runtime.run(task).await?;
    println!("Container started with PID {}", handle.pid());

    // Wait for the container to exit and collect the exit code
    let exit = handle.wait().await?;
    println!("Container exited with status {}", exit);
    Ok(())
}

Explanation of the critical parts:

  • RuntimeBuilder::default()
    constructs the cooperative scheduler and pre‑loads the KiriCNI bridge.
  • SecretMemfd
    creates a memfd that is only readable by the child after
    execve
    (the parent drops the FD).
  • env
    entry
    TOKEN="fd://"
    is a convention in Kiri: the runtime substitutes the placeholder with the actual FD number at launch time.
  • No external
    docker
    or
    ctr
    binary is required; the whole lifecycle lives inside the Rust process.

Empirical Trade‑Off Table

FeatureKiricontainerd (with runc)crunrunc (stand‑alone)
Start‑up latency (empty container)≈115 µs (single‑process)520 µs (shim + fork)380 µs (shim‑less but C)450 µs
Per‑container memory overhead~200 KB (Task Arena)2–4 MB (shim + libcontainer)1.5 MB2 MB
Cgroup versionUnified v2 (native)v2 via libcontainerv2 nativev1/v2 via libcontainer
Security surfaceCapability‑policy + memfd secrets (Rust safety)AppArmor/SELinux profiles (external)Capability + seccomp (C)Same as containerd
Language ecosystemRust (zero‑cost abstractions)Go (garbage‑collected)C (fast but unsafe)C
Scalability (containers/host)~30 k short‑lived functions (CPU‑bound)~10 k (shim limit)~12 k~8 k
Complexity for operatorsModerate – single binary, config via YAMLHigh – separate daemon, socket, pluginsLow – similar to runc but C‑centricLow
Observability hooksBuilt‑in Prometheus metrics, async eventsgRPC + plugin hooksLimitedLimited

Numbers are taken from Kiri’s benchmark suite (v0.3.1) on a 32‑core AMD EPYC 7542, compared against official

containerd
1.7.0 benchmarks on the same hardware.


Future Industry Trajectory (18‑36 months)

  1. Unified Runtime APIs – We will see a convergence on graph‑based execution descriptors (similar to KEG) that allow orchestrators to express complex topologies (side‑cars, init‑containers, fan‑out tasks) without spawning multiple runtimes. Projects like Krun and Kiri are early adopters.
  2. Rust‑first Cloud‑Native Stack – The safety guarantees of Rust are becoming a decisive factor for security‑critical workloads (e.g., fintech, edge AI). Expect major CNCF projects (CNI, CRI) to expose Rust bindings, and for runtimes to be offered as WebAssembly System Interface (WASI) modules that can be swapped at runtime.
  3. Zero‑Copy Secrets & Config – Memfd‑based secret injection will become the default, reducing the attack surface of host‑mounted volumes. Integration with secret‑management platforms via gRPC‑streamed memfd will be standardized.
  4. Serverless‑Native Scheduling – The distinction between “container” and “function” will blur. Runtimes that can batch schedule thousands of micro‑containers with sub‑millisecond latency (Kiri’s sweet spot) will be the backbone of next‑gen FaaS platforms.
  5. Observability‑First Design – Future runtimes will ship structured event streams (OpenTelemetry) from the scheduler itself, enabling real‑time autoscaling decisions without extra side‑car instrumentation.
  6. Hardware‑Accelerated Isolation – With the rise of confidential compute (AMD SEV‑SNP, Intel TDX), runtimes will need to expose hardware‑rooted memory encryption hooks. Kiri’s memory‑model, built on
    memfd
    and
    mmap
    , is already compatible with these upcoming APIs.

In summary, the next three years will be defined by runtime minimalism, type‑safe languages, and tight coupling between scheduling and security. Kiri is a strong indicator of that direction, and teams that adopt its principles early will gain a decisive edge in cost, performance, and compliance.


Conclusion

Kiri challenges the status quo by discarding the shim, embracing Rust’s safety, and exposing a graph‑centric execution model that dramatically lowers latency and per‑container overhead. For engineering teams, the lesson is clear: question legacy process boundaries, lean on language guarantees, and design security as a first‑class resource.

FutureStack will continue to evaluate Kiri for our edge‑node fleet, and we anticipate that the ideas pioneered here will cascade into the broader CNCF landscape. The container runtime is no longer a static plumbing layer—it is an active participant in the performance, security, and economics of cloud‑native workloads.


Author: Mubashir Arham, Founder & Chief Architect, BS Artificial Intelligence, FutureStack

Advertisement•Sponsored
Google AdSense Ready

Responsive Ad Placement (728×90 / Dynamic). Live ads will serve once your publisher ID is linked.

Mubashir Arham
Written by

Mubashir Arham

CEO & Founder of futurestack.online | Full Stack Developer | BS Artificial Intelligence

CEO, Developer of futurestack.online, Digital Entrepreneur, Full Stack Developer, Author, Digital Mentor, Owner, and Bachelor of Artificial Intelligence (BS AI). Architecting the frontier of autonomous AI software systems, scalable cloud stacks, and digital knowledge products.

Read all publications by Mubashir Arham

Deliberations (0)

Moderated • Anti-Spam & Link Safety Active

Contribute your perspective

Loading discussion thread...