Inside the Docker Engine: containerd, runc, and Shims Explained

The Docker Engine is a modular system built from small, specialized components rather than one giant program. This article breaks down how containerd, runc, and shims work together to create and run containers, and how the Open Container Initiative shaped this architecture.

Docker Enginecontainerdrunc

~4 min read · Updated Sep 5, 2026

Introduction

The Docker Engine refers to the server-side components of Docker responsible for building, sharing, and running containers. Rather than being a single monolithic program, it is a modular system composed of many small, specialized tools contributed by projects such as the OCI, the CNCF, and the Moby Project.

From Monolith to Modular Design

When Docker was first released, the Engine consisted of two major parts: the Docker daemon, a monolithic binary handling the API, image building, and container execution, and LXC, which interfaced directly with the Linux kernel.

Relying on LXC created problems, since it was Linux-specific and evolved independently of Docker's needs. Docker eventually replaced it with its own platform-agnostic tool called libcontainer.

Over time, the monolithic daemon itself became a bottleneck for innovation, so Docker gradually broke it apart into smaller, reusable tools. The most notable results of this effort were containerd and runc, which are now used far beyond Docker itself, including in Kubernetes, Firecracker, and Fargate.

The Influence of the OCI

Around the same time, the Open Container Initiative (OCI) was defining two key standards: the image-spec and the runtime-spec, both released as version 1.0 in 2017. A third standard, the distribution-spec, governs how images move through registries.

Docker, Inc. was a founding member of the OCI and remains actively involved. Every modern version of Docker implements these specifications through tools like runc, BuildKit, and Docker Hub.

runc: The Low-Level Runtime

runc is the reference implementation of the OCI runtime-spec. It is a lightweight CLI wrapper around libcontainer, responsible for interfacing with the kernel to actually build and start a container's namespaces and cgroups. Once a container starts, the runc process that created it exits.

containerd: The High-Level Runtime

containerd manages the lifecycle of containers — starting, stopping, and deleting them — while delegating the low-level kernel work to runc. Originally intended as a small, focused tool, it has since grown to also manage images, networks, and volumes, which projects like Kubernetes can selectively use.

containerd was created by Docker, Inc. and later donated to the CNCF, where it is now a graduated, production-ready project.

How a Container Gets Started

When a command such as the following is run:

docker run -d --name ctr1 nginx

the CLI converts it into an API request sent to the daemon. The daemon passes the request to containerd over gRPC, which converts the image into an OCI bundle and instructs runc to create the container. runc interfaces with the kernel to build the required namespaces and cgroups, then exits once the container process is running.

This separation means the daemon can be stopped, restarted, or updated without affecting already-running containers — a concept known as daemonless containers.

What Is a Shim?

Between containerd and the OCI layer sits a shim process. For every new container, containerd forks a shim and a runc process; once runc exits, the shim becomes the container's parent process. Shims provide three key benefits: enabling daemonless containers, improving efficiency by keeping processes lightweight, and allowing runc to be swapped for other low-level runtimes.

Linux Implementation

On a Linux host, these components exist as separate binaries:

  • /usr/bin/dockerd
  • /usr/bin/containerd
  • /usr/bin/containerd-shim-runc-v2
  • /usr/bin/runc

Conclusion

The Docker Engine's modular design — built around the OCI specifications, containerd's lifecycle management, and runc's low-level execution — has made it more flexible, portable, and reusable across the wider container ecosystem. Understanding these layers is key to truly mastering how Docker works under the hood.

Written & researched by Dr. Shahin Siami

Related Articles

How Docker Uses Linux Security Technologies: Namespaces, Cgroups, and More

Docker's security model is built on layered defense, combining well-established Linux kernel technologies with sensible defaults out of the box. This article explains how namespaces, control groups, capabilities, mandatory access control, and seccomp work together to isolate and secure containers.

Continue

Managing Persistent Data in Docker with Volumes

Containers get a temporary writable layer by default, which disappears the moment a container is deleted — fine for scratch data, but risky for anything worth keeping. This article explains how Docker volumes decouple persistent data from container lifecycles, and walks through creating, using, and sharing them safely.

Continue

How Docker Overlay Networks Work: VXLAN Under the Hood

Overlay networks let containers on different hosts communicate as if they shared a single flat network, forming the backbone of most cloud-native microservices apps. This article covers how to build, encrypt, and test a Docker overlay network across a Swarm cluster, and explains the VXLAN tunneling technology powering it behind the scenes.

Continue

Connecting Docker Containers to VLANs and Load Balancing with Swarm

Beyond basic bridge networks, Docker can connect containers directly to existing physical VLANs, resolve service names automatically, and distribute traffic across a Swarm cluster. This article covers the macvlan driver, Docker's built-in service discovery, and Swarm's ingress load balancing mesh.

Continue

Understanding Docker Networking: CNM, Libnetwork, and Bridge Networks

Docker networking is built on an open design called the Container Network Model, implemented through libnetwork and extended by pluggable drivers. This article covers the theory behind Docker networking and walks through creating and testing single-host bridge networks, including name resolution and port mapping.

Continue

Deploying and Managing Multi-Node Clusters with Docker Swarm

Docker Swarm turns a group of Docker nodes into a secure, highly available cluster with built-in application orchestration. This article covers building a multi-node swarm, deploying a microservices app declaratively, and performing rolling updates without losing desired-state consistency.

Continue