Skip to content

Docker Engine

  • Docker Engine is the underlying runtime that handles container creation, networking, storage, and lifecycle management.
  • Splits into two parts: the daemon (dockerd) which does all the work, and the CLI client which sends instructions to the daemon over a REST API.
  • Docker Daemon (dockerd): Runs on the host. Manages container objects (images, containers, networks, volumes). Listens for API requests from the CLI or any REST client. Can communicate with remote daemons in a Swarm cluster.

  • Docker Client (docker CLI): The command-line tool users interact with. Translates user commands into Docker API calls. Does not need to be on the same host as the daemon.

    Terminal window
    # Run a container on a remote Docker daemon
    docker -H 10.123.2.1:2375 run nginx
    # Check daemon status
    systemctl status docker
  • Docker Registry: The image distribution layer. Public (Docker Hub) or private (ACR, ECR, GCR, Harbor). Images are identified as registry-url/image-name:tag.

![Docker Engine components](/images/virtualization/Untitled 32 2.png)

dockerd doesn’t create containers directly — it delegates down a chain:

Docker CLI → dockerd → containerd → containerd-shim → runc → container process
  • containerd — a graduated CNCF project and the actual container runtime. Manages image pulls, container lifecycle, snapshots, and networking. Kubernetes uses containerd directly (without dockerd).
  • runc — the low-level OCI runtime that calls Linux kernel APIs (namespaces, cgroups) to create and start the container process. Swappable — you can use crun, gVisor (runsc), or kata-containers instead.
  • containerd-shim — a small process that stays alive between runc exiting and the container process finishing. Allows dockerd to restart without killing running containers.

This is why docker rm -f $(docker ps -q) stops containers but containerd and its shims are still running — and why tools like ctr and nerdctl can manage containers independently of the Docker CLI.

Docker uses Linux namespaces to isolate each container’s view of the system, and cgroups to limit its resource consumption. No hypervisor is involved.

NamespaceIsolates
pidProcess tree - container processes can’t see host or other container processes
netNetwork stack - each container gets its own IP, routing table, and firewall rules
mntFilesystem - each container sees its own filesystem, not the host’s
ipcInter-process communication - shared memory, semaphores, message queues
utsHostname and domain name
userUser and group IDs (optional, not always enabled)
  • When the daemon creates a container, it creates a new set of namespaces and launches the container process inside them.
  • Result: A process that thinks it owns the entire system, but is actually isolated behind namespace boundaries.

![Namespace isolation diagram](/images/virtualization/Untitled 33 2.png)

  • While namespaces control what the process can see, cgroups control what resources it can use.

  • Docker uses cgroups to set limits on CPU shares, memory, disk I/O, and network bandwidth per container.

    Terminal window
    # Limit a container to 512MB RAM and half a CPU core
    docker run --memory=512m --cpus=0.5 nginx
  • Without cgroup limits, a runaway container can starve all other processes on the host - including the Docker daemon itself.