Container Runtimes

Containers package an application with everything it needs to run — code, dependencies, and configuration — into a single portable unit. They start in seconds, consume minimal overhead, and behave identically across environments. This consistency is why containers have become the standard unit of deployment.

How Containers Work

Containers aren't virtual machines. They share the host operating system's kernel and use two Linux primitives to create isolation:

Namespaces give each container its own view of the system — its own process tree, network interfaces, and filesystem mounts. A process inside a container can't see processes in another container or on the host.

Cgroups (control groups) limit and account for resource usage. They enforce boundaries on CPU, memory, and I/O so that one container can't monopolize the host.

The combination is lightweight isolation: near-native performance with strong boundaries between workloads.

The OCI Standard

The Open Container Initiative (OCI) defines the open standards for container formats and runtimes. This means container images built with one tool can run on any OCI-compliant runtime. The ecosystem includes:

  • runc — the reference low-level runtime that actually creates and runs containers
  • containerd — a higher-level runtime that manages the full container lifecycle (image pulls, storage, execution via runc)
  • Docker — the developer-facing tool that popularized containers, built on top of containerd
  • CRI-O — a lightweight runtime built specifically for Kubernetes

In practice, the choice of runtime matters less than it used to. The OCI standard ensures interoperability.

Images

A container image is a layered filesystem snapshot. Each layer represents a change — installing a package, copying application code, setting an environment variable. Layers are shared between images, which makes storage and transfer efficient.

Images are built from a Dockerfile (or equivalent) and stored in a registry — Docker Hub, GitHub Container Registry, or a private registry you operate. Multi-architecture builds allow the same image tag to serve different platforms (x86, ARM) transparently.

Orchestration

Running a single container is straightforward. Running hundreds across multiple hosts — with load balancing, health checks, scaling, and zero-downtime deployments — requires orchestration.

Orchestrators handle service discovery (how containers find each other), scheduling (which host runs which container), health monitoring (restarting failed containers), and rolling updates (deploying new versions without downtime).

Kubernetes is the dominant orchestration platform, but the underlying concepts — desired state, reconciliation loops, declarative configuration — apply broadly.

Security

Containers share a kernel, which means a kernel vulnerability can affect all containers on a host. The shared kernel is the fundamental difference from virtual machines — VMs isolate at the hardware level, containers isolate at the process level. This makes security hygiene essential.

Run as non-root. Every container should specify a non-root user. A process running as root inside a container has root on the host if it escapes the namespace boundary. The USER directive in a Containerfile or the securityContext in Kubernetes enforce this.

Drop capabilities. Linux capabilities grant fine-grained privileges. Containers start with a default set that's broader than most applications need. Drop everything unnecessary — most services need no capabilities at all.

Use read-only filesystems. If the application doesn't need to write to its own filesystem, mount it read-only. This prevents an attacker from modifying binaries or writing persistence mechanisms. Writable paths (/tmp, application data directories) can be mounted as specific volumes.

Scan images before deployment. Image scanning catches known CVEs in OS packages and application dependencies. Integrate it into CI so vulnerable images are flagged before they reach production. See supply-chain for scanning and signing practices.

Rootless containers run the entire container runtime without root privileges, which eliminates the most dangerous class of container escape. See containerd for rootless configuration with nerdctl.