Chapter 03Lesson 01~105 minutes

Docker Engine Components: dockerd, containerd, runc, BuildKit, APIs, and Container Lifecycle: Concepts, Architecture, and Mental Model

Trace Docker requests through the client, Engine API, dockerd, managed containerd, shims, runc, the Linux kernel, and BuildKit so object state is never confused with runtime process or build-worker state.

Engine architecturedockerdcontainerdruncBuildKit

Learning objectives

  • Trace a container request from CLI/SDK through the Engine API, dockerd, containerd, shim/runc, and the kernel process.
  • Distinguish Docker object state, runtime task/process state, content/image state, and BuildKit builder state.
  • Explain the separate BuildKit build path and why builder/exporter evidence matters.
  • Capture read-only component/version/API evidence before changing anything.
  • Use current Engine 29 behavior without turning release numbers into permanent assumptions.
Chapter 03 platform baseline — verified 2026-09-20. Docker Engine 29.8.1 is current. The 29.8 API matrix lists API 1.55 maximum / 1.40 minimum. Engine 29.8 packages BuildKit 0.33.0 and runc 1.5.1; the 29.8.1 static-binary packaging update carries containerd 2.3.5. Treat these as dated reference points only: capture docker version, docker info, docker buildx version, and platform-specific runtime evidence on the machine that actually runs the lab.

1. The problem: one command crosses several ownership boundaries

Chapter 01 established that a container is an isolated process environment rather than a miniature virtual machine, and Chapter 02 separated the Docker client, selected context, daemon endpoint, installation source, and host prerequisites. The next failure mode is subtler: after the client reaches a healthy daemon, engineers often treat every internal failure as “Docker failed.” That phrase is too coarse to troubleshoot.

A request such as docker run begins at the CLI or SDK, crosses the Engine API, is interpreted by dockerd, uses Docker-managed containerd services for content and task lifecycle, invokes a containerd shim and an OCI runtime such as runc, and finally asks the kernel to create the workload process with its namespaces, cgroups, mounts, and security settings. A build request shares the client/API/control-plane entrance but branches into BuildKit, whose workers, cache, frontends, and exporters are a different execution path.

Do not troubleshoot from component names alone. A message that mentions a runtime, image, snapshotter, API, or builder is evidence, not a license to mutate that component directly. Preserve the request identity, object IDs, versions, timestamps, logs, and events first.

2. The Engine request path

The useful mental model is a control path plus a runtime path. The CLI is a client. dockerd is the Docker Engine control plane. containerd is a managed runtime/content service. A shim maintains the task boundary independently of the short-lived runc invocation. The Linux kernel actually schedules and isolates the resulting process.

Container request ownership
flowchart TD
  A[Docker CLI or SDK] --> B[Engine API]
  B --> C[dockerd control plane]
  C --> D[Docker-managed containerd]
  D --> E[containerd shim]
  E --> F[runc OCI runtime]
  F --> G[Kernel process + namespaces + cgroups]
  C --> H[Docker object metadata]
  D --> I[content / snapshots / task state]
  G --> J[logs + exit + resource evidence]
            

The arrows are ownership transitions, not a promise that every Docker package exposes each component as a separately managed host service. Engine 29.7 introduced an experimental embedded-containerd mode; the default remains Docker-managed containerd behavior, and shims still remain separate task processes. Course labs therefore inspect the installed environment instead of assuming process topology.

3. Object state, task state, and process state are different

Layer Useful identity What success proves What it does not prove
Client / context CLI version, context, endpoint The client selected an endpoint and could attempt an API request. That the daemon accepted it.
Engine API / dockerd Server version, API version, daemon PID/log timestamp The Docker control plane parsed and handled an API operation. That a workload process is healthy.
containerd / shim / runc runtime versions, task PID, shim/process evidence The runtime path created or managed a task. That the application is reachable or correct.
BuildKit builder, driver, worker, frontend, build record The selected builder solved the graph and completed its exporter. That the result was loaded into the Engine image store or pushed.
Container object container ID, inspect state, image ID Docker has an object with recorded configuration/state. That it is running now.

4. The build path branches through BuildKit

BuildKit is the modern Docker build backend. The default Buildx builder uses the docker driver and the BuildKit library bundled with the Engine; custom builders can run BuildKit in a dedicated container, Kubernetes, or a remote daemon. This means “Docker build succeeded” is incomplete unless you know which builder solved the graph and which exporter handled the result.

Build request branch
flowchart TD
  A[Docker CLI / buildx] --> B[Selected builder]
  B --> C{Driver}
  C -->|docker| D[BuildKit bundled with Engine]
  C -->|docker-container| E[Dedicated BuildKit container]
  C -->|remote / kubernetes| F[External BuildKit worker]
  D --> G[cache + result exporter]
  E --> G
  F --> G
  G --> H[local load / registry push / OCI output / cache-only]
            

5. Read-only baseline: identify the components you actually have

docker version
docker context show
docker context inspect "$(docker context show)"
docker info

docker buildx version
docker buildx ls
docker buildx inspect --bootstrap

# Native Linux Engine only; these may not be host-visible on Docker Desktop.
command -v containerd && containerd --version || true
command -v runc && runc --version || true
ps -eo pid,ppid,comm,args | grep -E '[d]ockerd|[c]ontainerd|[c]ontainerd-shim' || true

Do not treat a missing containerd or runc binary in the outer user shell as proof that Docker does not use those components. Docker Desktop places the Linux Engine inside a managed VM, and package layouts differ. The supported Docker-facing evidence is still docker version, docker info, and builder inspection.

6. Current Engine 29 baseline and why it is only a baseline

As of 2026-09-20, Docker Engine 29.8.1 is current. The Engine 29.8 API matrix lists API 1.55 maximum and 1.40 minimum. Engine 29.8 packaging includes BuildKit 0.33.0 and runc 1.5.1; 29.8.1 updates the static-binary containerd package to 2.3.5. Those numbers are useful compatibility anchors, but your package source or Docker Desktop can expose a different packaging surface. Diagnostics must start from installed evidence.

Engine 29 storage nuance. Fresh Engine 29 installations use the containerd image store by default, while upgraded older daemons can retain classic storage-driver state. This changes image/content inspection assumptions but does not turn containerd into a user-managed replacement for Docker Engine.

7. Why this model matters in DevOps

CI systems, release pipelines, incident responders, and platform teams need to distinguish source/build identity from Engine objects and runtime processes. A reliable incident note can say: “CLI 29.8.1 using context X negotiated API 1.55 with daemon Y; build builder Z produced image ID A; container B was created and task PID C started; the first failure occurred after start in application health.” That statement is actionable because every claim has an owner and observable evidence.

Next lesson

Next: Docker Engine Components: dockerd, containerd, runc, BuildKit, APIs, and Container Lifecycle: Guided Hands-On Workflow and Core Operations

Continue through the same Engine evidence chain while adding the next layer of operational reasoning.

Knowledge check

A Docker CLI command returns an API negotiation error before any container ID exists. Which layer should you investigate first?

Why is a Docker container not the same thing as the host process that executes its workload?

What does runc normally do in the Docker stack?

A BuildKit build succeeds with a custom docker-container builder, but docker image inspect cannot find the tag. Is the build necessarily broken?

Official references and version notes

Current baseline, not a frozen requirement

Verified 2026-09-20: Docker Engine 29.8.1 is current; the Engine 29.8 API matrix lists maximum API 1.55 and minimum API 1.40. Engine 29.8 packaging includes BuildKit 0.33.0 and runc 1.5.1; 29.8.1 updates the static-binary containerd package to 2.3.5. Package-managed distributions and Docker Desktop can bundle or expose components differently. Record the actual client/server/API/component/builder versions on the learner's environment before diagnosing compatibility.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.