OCI (Open Container Initiative): defines standards for container images and runtimes
Image Spec: container image format (layers, manifest, config)
Runtime Spec: how to run a container (filesystem bundle + config.json)
Distribution Spec: registry API (push/pull images)
Runtime
Layer
Notes
containerd
High-level
industry standard; used by Kubernetes, Docker
CRI-O
High-level
Kubernetes-native OCI runtime
runc
Low-level
default; spawns containers via namespaces/cgroups
crun
Low-level
faster C replacement for runc
gVisor (runsc)
Sandboxed
intercepts syscalls in userspace (Google)
Kata Containers
VM-based
each container runs in a microVM
Tools
CLI with Runtimes
docker CLI
dockerd (moby)
nerdctl CLI
containerd (contaiNERD)
podman CLI
runc, crun, runv (or any other OCI compliant runtime)
daemonless and rootless by default
each container is a direct child process (no central daemon)
podman commands are drop-in replacements for docker
Management
Docker desktop
Rancher desktop
Podman desktop
Linting Dockerfile
Hadolint
Rootless Containers
run daemon/containers as non-root using user namespaces
container root maps to an unprivileged host user
smaller blast radius if a container is compromised
Linux Kernel Primitives
The three kernel features that make containers possible
Namespaces (isolation)
Namespace wraps a global kernel resource so each container sees its own isolated copy
runc calls clone() / unshare() syscalls to create new namespaces per container
without namespaces, ps inside a container would show all host processes
Linux has 8 namespace types:
# list all namespaces of a running container (get PID first)docker inspect --format '{{.State.Pid}}' <container>lsns -p <pid># see namespace files kernel exposes per processls -la /proc/<pid>/ns/# enter a container's network namespace from the hostnsenter -t <pid> -n ip addr# demo: hostname isolation via uts namespaceunshare --uts bashhostname isolated-test # only visible inside this shell
Namespace
Isolates
pid
process IDs — container PID 1 = host PID
net
network interfaces, routing tables, ports
mnt
filesystem mount points
uts
hostname and domain name
ipc
System V IPC, POSIX message queues
user
UID/GID mappings (enables rootless containers)
cgroup
cgroup root view
time
system clock offsets (Linux 5.6+)
cgroups (resource limits)
Control Groups
It is a kernel mechanism to limit, account for, and isolate resource usage of process groups
Two versions in use:
cgroups v1: per-resource hierarchy (separate trees for cpu, memory, etc.)
cgroups v2: unified hierarchy — one tree for all resources; preferred since Linux 4.5
resources controlled:
CPU shares / quota
memory limit + OOM kill threshold
block I/O weight
device access
Docker maps --memory, --cpus, --cpu-shares flags directly to cgroup entries under /sys/fs/cgroup/
# run a container with resource limitsdocker run --memory=256m --cpus=0.5 nginx# inspect the cgroup limit Docker wrote (cgroups v2)cat /sys/fs/cgroup/system.slice/docker-<full-id>.scope/memory.maxcat /sys/fs/cgroup/system.slice/docker-<full-id>.scope/cpu.max# live resource usagedocker stats <container># demo: spawn a process in a new cgroup manually (cgroups v2)mkdir /sys/fs/cgroup/demoecho 52428800 > /sys/fs/cgroup/demo/memory.max # 50 MBecho $$ > /sys/fs/cgroup/demo/cgroup.procs # add current shell
OverlayFS (layered images)
It is union filesystem that merges multiple directory trees into one view
Docker uses it as the default storage driver (overlay2)
Two layers per container:
lower dir: read-only image layers stacked on top of each other