HowItWorks:Docker: Difference between revisions

From Wikibase
Jump to navigation Jump to search
Line 9: Line 9:
Programmatically independent but sharing the host's kernel, a Docker container offers the full isolation provided by '''Virtual Machines (VM)''' at a fraction of the resource overhead.<ref>{{#cite:Q1408}}</ref>
Programmatically independent but sharing the host's kernel, a Docker container offers the full isolation provided by '''Virtual Machines (VM)''' at a fraction of the resource overhead.<ref>{{#cite:Q1408}}</ref>


=== A short history ===
== A short history ==


Docker was first pioneered by [[Person:Solomon Hykes|Solomon Hykes]], founder of dotCloud, as an internal project to solve virtualisation bottlenecks for his company's PaaS service.  
Docker was first pioneered by [[Person:Solomon Hykes|Solomon Hykes]], founder of dotCloud, as an internal project to solve virtualisation bottlenecks for his company's PaaS service.  

Revision as of 07:16, 1 September 2026

Languages: English · français · Esperanto

Explains how things actually work — part of our technology dissections collection.

Written in Go and built on top of Linux kernel,Docker packages an application — code, runtime, libraries, configuration — into a container: a loosely isolated environment that runs the same on any device: on a developer's laptop like on a data centre server[1] [1].

Container ?

A container is an isolated, self-sufficient process without external dependencies. It contains all the files it needs to run, making it extremely portable.[2]

Programmatically independent but sharing the host's kernel, a Docker container offers the full isolation provided by Virtual Machines (VM) at a fraction of the resource overhead.[2]

A short history

Docker was first pioneered by Solomon Hykes, founder of dotCloud, as an internal project to solve virtualisation bottlenecks for his company's PaaS service.

In March 2013, it was decided to open-source the project, so, as Hykes himself described, that "pioneers can start to use containers and collaborate in a monolithic open source codebase: Docker".[3]

The opensourced Docker became an instant hit. By October 2013, seven months after the project's first open-source pre-release, Docker was downloaded more than 140,000 times, and forked more than 800 times on Github.[4] It was so popular that dotCloud decided to rename itself Docker, Inc.[5]

Docker 1.0, the first production-ready release, shipped on June 9, 2014.[6]

In 2015, Docker's container format and runtime became the cornerstone of the newly written open standards for containers under the Open Container Initiative (OCI) led by the Linux Foundation.[7].

In 2016, the core container runtime of Docker was spun out into a standalone project called containerd and donated to the Cloud Native Computing Foundation (CNCF).[8][9]

In 2017, the Moby Project was launched to host all open-source collaboration around Docker.[3] It aims to provide "an open framework to assemble specialized container systems without reinventing the wheel".[10]

As of August 2026, the Moby project's Github repo has more than 2330 contributors, and 19.2k forks.[11]

Components and interactions

Docker uses a client-server architecture: the Docker client talks to the Docker daemon (dockerd), which does "the heavy lifting of building, running, and distributing" containers, over a REST API on a UNIX socket or network interface.[1] The daemon manages Docker objects — images, containers, networks, volumes, plugins — and can even communicate with other daemons (for Docker services).[1] Another client, besides the CLI, is Docker Compose, for multi-container applications.[1]

Modern Docker Engine is not one monolith but a stack of cooperating components:

The responsibilities are split roughly as follows:

  • dockerd — the API server and object manager. It receives every request, holds the state of images/containers/networks/volumes, and orchestrates the rest of the stack.[1]
  • containerd — "an industry-standard container runtime", a daemon that "manages the complete container lifecycle of its host system, from image transfer and storage to container execution and supervision to low-level storage to network attachments and beyond".[9] Since Docker Engine 29, the containerd image store is the default for fresh installs.[12]
  • runc — the OCI runtime that actually creates and runs container processes, applying namespaces, cgroups and filesystem isolation; it is the reference implementation of the OCI runtime specification.[7]
  • containerd-shim — the small per-container process that keeps the container's stdio open and lets the daemons restart without killing containers.
  • The Linux kernel — the isolation primitives themselves: namespaces (each container gets its own set), cgroups for resource limits, OverlayFS for layered filesystems, seccomp and capabilities for security.[1]
  • A registry — stores and distributes images; Docker Hub is the default, and docker pull/docker run fetch from it while docker push uploads to it.[1]
  • BuildKit — the builder backend that executes image builds; since its adoption it is "the default builder for Docker Desktop and Docker Engine users".[13]

Docker in action

Two flows cover most of what Docker does: building an image from a Dockerfile, and running a container from an image.

Image build

To build your own image you write a Dockerfile, "a text document that contains all the commands a user could call on the command line to assemble an image".[14] Each instruction — FROM, RUN, COPY, CMD, ENTRYPOINT, ... — becomes a layer of the image.[1] Because layers are immutable and cached, "when you change the Dockerfile and rebuild the image, only those layers which have changed are rebuilt" — the main reason images are so lightweight and builds so fast compared with other virtualization technologies.[1]

Underneath the classic docker build command sits BuildKit. Its core is a Low-Level Build (LLB) format: "a content-addressable dependency graph" that lets it detect and skip unused build stages, run independent stages in parallel, and transfer only the changed files of the build context.[13] A "frontend" — itself distributed as an image — turns the human-readable Dockerfile into LLB, so the Dockerfile language can evolve without rebuilding the engine.[13]

Container run

A container is "a runnable instance of an image", "defined by its image as well as any configuration options you provide to it when you create or start it".[1] When you run docker run -i -t ubuntu /bin/bash, the documented sequence is:[1]

  1. If the ubuntu image is not present locally, Docker pulls it from the configured registry.
  2. Docker creates a new container (as with docker container create).
  3. Docker allocates a read-write filesystem to the container as its final layer — the only layer a running container may write to.
  4. Docker creates a network interface connecting the container to the default network and assigns it an IP address.
  5. Docker starts the container and executes /bin/bash, attached to your terminal.
  6. When you type exit, the container stops but is not removed — you can start it again or delete it.

That last point is important: "when a container is removed, any changes to its state that aren't stored in persistent storage disappear."[1] Data that must survive goes into volumes or bind mounts; ephemeral state simply dies with the container.

Key design decisions

Containers share the host kernel

The founding decision: a container is not a mini-VM. Docker uses Linux namespaces to give each container an isolated view (processes, networking, filesystem, users, and more), and cgroups to limit CPU, memory and I/O.[1] Because every container on a host shares the same kernel, there is no guest OS to boot, so containers start in seconds and many more fit on a machine than VMs would.[2]

The trade-off is architectural: isolation is as good as the kernel's — and the admin's — configuration. Docker historically defaulted to cgroups v1; the ecosystem has since moved to cgroups v2, and as of Docker Engine 29 cgroup v1 is deprecated but supported until at least May 2029.[12] On macOS and Windows, Docker Desktop bundles the daemon, the client, Docker Compose, Kubernetes and more, so the same Linux-based engine is available everywhere.[1]

Images are immutable, layered and content-addressed

An image is a "read-only template", often "based on other images, with some additional customization" — e.g. the Ubuntu image plus the Apache web server plus your application.[1][15].

As most consumer images are a combination of base images with customisation, they can be considered as the sum of multiple layers. Docker identifies them by a hash of their content, and identical layers are shared between images via content-addressable storage, which means they are only downloaded and stored once, regardless of the number of consumer images.[15]

  • Union filesystems — at run time, layers are stacked into a single unified view; the container's root is set to that view with chroot. On top of the read-only image layers, a directory is created for the running container, so the container writes without ever touching the image. For additional robustness, Docker uses copy-on-write. [15]

This design ensures that images are always state-consistent and optimised for network distribution and storage.

The Dockerfile is a declarative build recipe

Rather than mutating a running machine (and hoping the result is reproducible), Docker builds images from a declarative Dockerfile — "all the commands a user could call on the command line to assemble an image".[14] A valid Dockerfile must start with FROM, which "initializes a new build stage and sets the base image".[14] The key instructions:

  • RUN — "execute any commands to create a new layer on top of the current image".[14]
  • COPY / ADD — copy files from the build context (or another stage) into the image.
  • CMD / ENTRYPOINT — define the command executed when a container starts; ENTRYPOINT configures the container to run "as an executable", CMD provides default arguments.[14]
  • Multiple FROM lines enable multi-stage builds — build in one stage, copy only the artifacts into a minimal final stage.[14]

Because each instruction is a layer, the instruction sequence is also the cache key: RUN layers are reused on rebuild unless invalidated — a changed COPY or ADD invalidates the cache — so instructions placed early in the file are the ones that get reused across builds.[14] BuildKit hardened this model by tracking "the checksums of build graphs" instead of heuristics, making the cache faster, more precise and portable — it can even be exported to a registry.[13]

A daemon-centric client-server design

Docker uses a single privileged daemon that owns all state, fronted by a deliberately thin CLI.[1] Every docker command is a REST call to the Engine API; the daemon performs it and reports back.[1] This concentrates complexity in one place, enforcing the object model and facilitating security auditing. It also makes the engine highly scriptable — CI systems, orchestrators and tools like Compose and Docker Desktop all call the daemon's API.[1]

A logical downside of this complexity concentration is a long-lived server process as a single point of failure. To mitigate the risk, the daemon behaves a bit like a manager: it does not handle low-level container lifecycle itself but instead delegates them to containerd. This way, in case of state corruption the daemon can restart without killing containers, a bit like how a manager can go for a short refresher while ground workers continue to function normally.

The Engine API is versioned and stable

As Docker's contract with the outside world, the Docker API must be stable and compatible across versions. To achieve this, Docker's Engine API is versioned. Clients and daemons negotiate a mutually compatible API version, so a newer CLI can drive an older daemon and vice versa.

However, this unfortunately does not mean that all versions of Docker are mutually compatible. Docker Engine 29's daemon now requires API version v1.44 or later, and its client dropped support for negotiating versions below v1.44, as the changes have become genuinely hard to bridge.[12]

In a nutshell, Docker's versioned API does not guarantee that old code would work forever, but it provides additional years of runway to migrate.[12]

Bundled software, standardized primitives

As can be seen in the components and interactions diagram, Docker has a layered architecture.

An important factor leading to Docker's lasting success is its interoperability. Docker's low-level layers are built as open standards and neutral primitives: The Open Container Initiative (OCI) specifications for runtime, image, and distribution; containerd for runtime daemon;runc for runtime execution; and BuildKit for builder backend. As such a Docker image can be built, distributed and run by any OCI-compliant toolchain with no additional arguments".[7]

Try it yourself

The commands below are drawn from Docker's official documentation, as read on 2026-08-31.

# 1. Confirm the welcome-to-docker image really exists on Docker Hub (live check, 2026-08-31)
curl -s "https://hub.docker.com/v2/repositories/docker/welcome-to-docker/" | grep -o '"pull_count":[0-9]*'

Output (verified live):

"pull_count":6104168
# 2. Start a web server container, publishing port 8080 on the host to port 80 in the container
docker run -d -p 8080:80 docker/welcome-to-docker

"The output from this command is the full container ID."[2] The container now serves a small website at http://localhost:8080.

# 3. List running containers
docker ps

Documented output (IDs and names vary):[2]

CONTAINER ID   IMAGE                      COMMAND                  CREATED          STATUS          PORTS                      NAMES
a1f7a4bb3a27   docker/welcome-to-docker   "/docker-entrypoint.…"   11 seconds ago   Up 11 seconds   0.0.0.0:8080->80/tcp       gracious_keldysh
# 4. Stop the container
docker stop a1f7a4bb3a27

"Only enough of the ID to make it unique" is needed — docker stop a1f would do.[2]

# 5. Run an interactive Ubuntu shell in a container
docker run -i -t ubuntu /bin/bash

If the image isn't local, Docker pulls it; then it creates the container, allocates its writable layer, attaches it to the default network, starts it and runs /bin/bash — type exit and the container stops but is not removed.[1]

6. Build your own image from a Dockerfile

# 6a. make a dedicated directory and move into it.
#     That directory will be the build context — files in it (and only in it)
#     can be referenced by COPY / ADD instructions.
mkdir myapp && cd myapp


# 6b. Create the Dockerfile and the script to be copied into the image.
cat > Dockerfile <<'EOF'
# syntax=docker/dockerfile:1
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl
COPY app.sh /app.sh
CMD ["/app.sh"]
EOF

cat > app.sh <<'EOF'
#!/bin/sh
echo "Hello from my Docker image!"
EOF
chmod +x app.sh

A Dockerfile is "a text file containing instructions for building source code", read top to bottom; the instruction syntax is defined by the Dockerfile reference.[16][14] Each instruction becomes a layer of the image.[1] The essential instructions:

  • FROM — "defines a base for your image"; a valid Dockerfile starts with it.[16][14]
  • RUN — "executes any commands in a new layer on top of the current image and commits the result" (here: install curl).[16]
  • COPY — copies files or directories from the build context into the image's filesystem.[16]
  • CMD — "defines the default program that is run once you start the container"; only the last CMD counts, and the JSON-array form used here runs /app.sh directly, without a shell.[16]

The Dockerfile must live in the root of the directory you pass to docker build. That directory then becomes the build context, or the set of files that your build can access.[17] By default the file is named Dockerfile, without a file extension, so that docker build needs no extra flags.

When there are alternative builds, a common convention is *.Dockerfile) pass * with -f / --file.[16]

To keep the build context lean, list what must not reach the builder — node_modules, build artifacts, secrets — in a .dockerignore file in the context root: the build client drops matching files before the context is sent.[17]

# 6c. Build the image 
docker build -t myapp:latest .

-t names and tags the image, the trailing dot selects the build context (the current directory).[16] Docker reads the instructions in order; each creates a layer, and unchanged layers are reused from the build cache on the next build.[14][1]

Output (step numbers, hashes and timings vary):

[+] Building 2.6s (7/7) FINISHED
 => [internal] load build definition from Dockerfile    0.0s
 => [internal] load .dockerignore                       0.0s
 => [internal] load build context                       0.0s
 => => transferring context: 2B                         0.0s
 => [1/4] FROM docker.io/library/ubuntu:24.04           1.8s
 => [2/4] RUN apt-get update && apt-get install -y curl  0.7s
 => [3/4] COPY app.sh /app.sh                           0.0s
 => [4/4] CMD ["/app.sh"]                               0.0s
 => exporting to image                                  0.0s
 => => naming to docker.io/library/myapp:latest         0.0s
# 6d. Run it: start a container from the image; --rm removes it on exit.
docker run --rm myapp:latest

Documented output:

Hello from my Docker image!
# 6e. Confirm the image is stored in the local image store.
docker image ls

Documented output (image ID, age and size vary):[16]

REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
myapp         latest    a1b2c3d4e5f6   2 minutes ago    120MB

References

  1. Docker, Inc. (n.d.). What is Docker? (Webpage). In Docker Docs (Website).
  2. Docker, Inc. (n.d.). What is a container? (Webpage). In Docker Docs (Website).
  3. Hykes, S. (2017). Introducing Moby Project (Webpage). In Docker Blog (Website).
  4. Seroter, R. (n.d.). Introducing Docker, Inc: dotCloud Goes All-In On Container Technology (Webpage). In InfoQ: Software Development News, Trends & Best Practices - InfoQ (Website).
  5. Q1419. (2013). As Open Source Docker Grows DotCloud Changes Name, Business Model - Linux.com (Webpage). In Linux.com - News For Open Source Professionals (Website).
  6. Docker, Inc. (2014). It’s Here: Docker 1.0 (Webpage). In Docker Blog (Website).
  7. Open Container Initiative. (n.d.). About the Open Container Initiative (Webpage). In opencontainers.org (Website).
  8. Hykes, S. (2016). containerd – a core container runtime project for the industry (Webpage). In Docker Blog (Website).
  9. The Linux Foundation. (n.d.). containerd.io (Website).
  10. Docker, Inc. (n.d.). Moby Project (Website).
  11. Moby Project. (n.d.). GitHub - moby/moby: The Moby Project - a collaborative project for the container ecosystem to assemble container-based systems (Webpage). In GitHub · Change is constant. GitHub keeps you ahead. (Website).
  12. Docker, Inc. (n.d.). Docker Engine version 29 release notes (Webpage). In Docker Docs (Website).
  13. Docker, Inc. (n.d.). BuildKit (Webpage). In Docker Docs (Website).
  14. Docker, Inc. (n.d.). Dockerfile reference (Webpage). In Docker Docs (Website).
  15. Docker, Inc. (n.d.). Understanding the image layers (Webpage). In Docker Docs (Website).
  16. Docker, Inc. (2026). Dockerfile overview (Webpage). In Docker Docs (Website).
  17. Docker, Inc. (2026). Build context (Webpage). In Docker Docs (Website).

Further reading