Linux containerd as an Alternative to Docker
This article explains how the Linux operating system utilizes
containerd as an independent, lightweight container runtime
in place of the monolithic Docker daemon. It explores the architectural
differences between the two systems, the direct integration of
containerd with Linux kernel primitives via standard
interfaces, and how environments like Kubernetes use this configuration
to reduce overhead and improve container lifecycle management.
Architectural Shift: From Docker Daemon to containerd
Historically, the Docker daemon (dockerd) served as a
high-level platform handling a broad spectrum of responsibilities,
including image building, volume management, network configuration, API
routing, and container execution. Under the hood, Docker delegated core
runtime operations to containerd, which it originally
created and later donated to the Cloud Native Computing Foundation
(CNCF).
When Linux uses containerd directly, it bypasses
dockerd entirely. Rather than running a heavyweight daemon
with developer-centric tooling, the operating system manages a
streamlined system daemon that focuses strictly on the container
execution lifecycle: image transfer, storage management, container
execution, and supervision.
Integration with Linux System Services and Kernel Primitives
The Linux OS interacts with containerd primarily as a
native systemd service. The daemon runs in the background
and exposes a gRPC API through a local Unix domain socket (typically
located at /run/containerd/containerd.sock).
When a client or orchestrator requests a container action,
containerd translates these commands and communicates with
an Open Container Initiative (OCI) compliant runtime, typically
runc. The execution pipeline relies directly on fundamental
Linux kernel features:
- Namespaces: Isolate system resources such as
process trees (
pid), network interfaces (net), mount points (mnt), and user IDs (user). - Control Groups (cgroups): Allocate and throttle hardware resources, including CPU, memory, and disk I/O, using Linux cgroups v1 or v2.
- Security Modules: Enforce process restrictions using Linux security mechanisms such as AppArmor profiles, SELinux policies, and Seccomp system call filters.
Because containerd sits closer to these kernel
interfaces than the full Docker engine, it avoids intermediate
translation layers, resulting in lower CPU usage and a smaller memory
footprint.
Orchestration and Kubernetes via CRI
In orchestration platforms like Kubernetes, replacing the Docker
daemon with containerd standardizes operations through the
Container Runtime Interface (CRI). Previously, the Kubernetes
kubelet required a translation component known as
dockershim to communicate with the Docker daemon, which
then routed requests to containerd.
By configuring the kubelet to point directly to
containerd's CRI plugin (built into the runtime), the
operating system eliminates the Docker abstraction layer. The
communication path flows directly from kubelet over the
Unix domain socket into containerd, which invokes
runc to execute the container processes directly on the
Linux kernel.
Management Tools and CLI Alternatives
Because containerd does not include the user-facing
Docker CLI, interaction on a Linux host occurs through specialized
tools:
- ctr: A low-level command-line client shipped
directly with
containerd. It is designed for debugging and developer inspection rather than production orchestration. - nerdctl: A Docker-compatible CLI for
containerdthat provides a similar user experience to thedockercommand, supporting features like rootless execution, image encryption, and Compose configurations. - crictl: A CLI designed for CRI-compatible container runtimes, commonly used to inspect and troubleshoot pods and containers on Kubernetes nodes.
By utilizing containerd as a standalone runtime, Linux
hosts achieve improved stability, faster container start times, and
reduced attack surfaces while maintaining full compliance with modern
container standards.