Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Images, containers and registries: the anatomy

By updated

Improve this page

Logo Docker

The docker command you type does not launch any container itself. It plays the role of a client: it sends a request to a daemon, a program that runs in the background and waits for requests. The daemon passes the work to containerd, then to a runtime, the program that actually creates the process of the container.

This runtime follows the OCI standard. The OCI (Open Container Initiative) is the body that sets the format of images and the way a container is launched.

This lesson is for anyone starting with Docker. It follows that path from end to end, then shows you how to check which daemon answers your commands. Finally, it separates two words that are often confused: the image, which is a template, and the container, which is a launched copy of it.

What you will learn

  • Trace the path between a Docker command and an application process
  • Identify the context and the daemon the client really contacts
  • Name the role of the client, the API, dockerd, containerd and the OCI runtime
  • Tell an image from its instances, then read its layers and its configuration
  • Know where an image comes from and what a registry is

Prerequisites

Read Containers or virtual machines: which one to choose? first. It defines a container as a process isolated from the host.

This lesson comes before the one that installs Docker Engine, Install Docker Engine 29 and prove it works. You can therefore read the demonstrations and their outputs before installing Docker. Replay them afterwards, with the lab of this page, once the installation is done. The outputs were taken on Docker Engine 29.9.2.

As long as your account does not belong to the docker group, prefix the commands with sudo. This group allows you to talk to the daemon without sudo. With sudo, the client reads the configuration of root, as the section on the contacted daemon explains.

Who does what when you type a docker command?

A docker command goes through five stages before becoming a process, and each has its role. The diagram puts them in order. First follow the thick arrow, which is the path of the request. The dotted arrow then shows where the files of the container come from.

A chain from left to right: the docker client sends a request to the API of the daemon, which is carried by dockerd; dockerd delegates to containerd; containerd asks runc, the OCI runtime, to create the process of the container. A dotted arrow links the image, a read-only template, to containerd, which provides its files.HTTP requestdelegatesasks to createstartsprovides the filesdocker clientthe typed commandDaemon APIsocket or context addressdockerdthe daemoncontainerdimages and lifecycleOCI runtimeruncContainer processthe instanceImagethe read-only template
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

The client (docker) contains almost no logic. It turns your command into an HTTP request. This request arrives on the API of the daemon, an interface exposed by the dockerd program. By default, it goes through a local Unix socket, a special file through which two programs of the same machine exchange data.

The daemon dockerd receives the request. It exposes the API and manages the networks and the volumes. For the rest, it delegates to containerd. On a fresh installation of Docker 29, the daemon uses the image store of containerd, which therefore stores the images and manages the life cycle of the containers. containerd then asks an OCI runtime to create the process. The default runtime is runc. It applies the kernel isolation, launches the program, then exits.

This separation has two useful consequences. First, the client and the daemon are two programs. They can run on two different machines, which lets you drive a remote server from your workstation. Second, the lower stages are standard building blocks, which can be reused without Docker.

The page Runtime, engine, orchestrator (in French) compares these layers. Who launches a container measures the process tree, that is, who is the parent of whom, that these layers create on the machine. This lesson does not detail it.

Which daemon really answers my commands?

The client is not tied to any particular daemon. It contacts a single one at a time, designated by its context. A context is a named target that carries the address of a daemon, local or remote. If the context points to another server than the one you think, you delete containers in the wrong place. So learn to read this target right now.

Terminal window
docker context show
docker context inspect --format '{{.Endpoints.docker.Host}}'
default
unix:///var/run/docker.sock

The first command gives the name of the active context. The second gives the address it targets. Here, it is the local Unix socket /var/run/docker.sock.

An environment variable can, however, take precedence over the context. It is a setting that the programs launched from your shell read. If DOCKER_HOST is set in your shell, the client uses it instead of the context.

docker context show does not report this case. As soon as DOCKER_HOST is set, it answers default, even if you had activated another context. On Docker 29.9.2, an active context named mesure-ctx gave mesure-ctx, and the same command gave default once DOCKER_HOST was set.

With DOCKER_HOST=tcp://127.0.0.1:1, docker context show therefore answers default. Yet docker version tries to reach that address and fails with Cannot connect to the Docker daemon at tcp://127.0.0.1:1. Is the docker daemon running?.

So start by checking this variable. Then ask the daemon to introduce itself, since it is the daemon, not the client, that knows what it is. If you use sudo docker, the echo below proves nothing: sudo resets the environment, and the client then reads the configuration of root (its ~/.docker). The DOCKER_HOST variable of your shell is therefore not the one sudo docker uses.

Terminal window
echo "DOCKER_HOST=${DOCKER_HOST:-not set}"
docker version
docker info --format '{{.Name}} {{.ServerVersion}} {{.DefaultRuntime}}'
DOCKER_HOST=not set
Client: Docker Engine - Community
Version: 29.9.2
API version: 1.56
Go version: go1.26.10
Git commit: a82e528
Built: Tue Oct 20 18:45:13 2026
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 29.9.2
API version: 1.56 (minimum version 1.40)
Go version: go1.26.10
Git commit: 0367cbe
Built: Tue Oct 20 18:45:13 2026
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v2.4.2
GitCommit: b7a25261e029d68978bbf290df0a62fc819b3c51
runc:
Version: 1.5.2
GitCommit: v1.5.2-0-g29dd3dc2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
d29-debian.lab 29.9.2 runc

docker version displays two blocks, Client and Server, each with its own version. The Server block describes the daemon actually contacted. If it is present, the request succeeded. It also names the lower stages of the chain with their version: containerd v2.4.2 and runc 1.5.2, those of the diagram.

On the last line, the one from docker info, three fields follow one another: the host name of the machine that runs the daemon, its version, then the default OCI runtime. If the host name is not that of your machine, you are talking to a remote daemon. The installation lesson uses these same commands to describe an environment: version, runtime, host name.

What is an image, and what is a container?

An image is a read-only template. It contains files (a minimal system, libraries, the program) and a configuration that tells how to launch it. A container is an instance of this image, that is, a copy launched from it. It is the running process, placed on these files, with a thin writable layer of its own.

The image never changes when the container runs. You can launch as many instances as you want from the same template. The common analogy is that of a class and its objects, or a mold and the parts it produces.

To see it, list the images present, then launch two instances of the same image. In each docker run, -d detaches the container from the terminal, --name gives it a name, and sleep 300 is the program it runs: a wait of five minutes, which keeps it alive long enough to observe it.

Terminal window
docker image ls alpine
docker run -d --name instance-un alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a sleep 300
docker run -d --name instance-deux alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a sleep 300
docker ps
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
alpine@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a be2656061b53 13MB 3.94MB
37c9ed7a1a487dddcd864d888e62d94cce3ad89717ef8452464c4e9b682aca2f
064d0581fd741222123689eb4ed377b356ff48411ef6e3f8806099df0baf5f4e
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
064d0581fd74 alpine:3.24 "sleep 300" 1 second ago Up Less than a second instance-deux
37c9ed7a1a48 alpine:3.24 "sleep 300" 1 second ago Up Less than a second instance-un

The alpine filter of docker image ls limits the list to this image, because a machine that has already been used often carries others. The alpine image appears only once, whereas docker ps lists two containers. You therefore have one template and two instances.

The image is displayed under its digest (alpine@sha256:…), the fingerprint that identifies an exact content, because the launch command designated it by this digest. The two long strings displayed by docker run -d are the identifiers of the containers. They change at each launch. The first launch downloaded the image if it was missing. The second is immediate, because the image is already stored.

To confirm that the two containers come from the same template, ask each one for the identifier of its image.

Terminal window
docker container inspect --format '{{.Image}}' instance-un
docker container inspect --format '{{.Image}}' instance-deux
sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a
sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a

The two lines carry the same identifier. It is that of the image, not that of a container. Its first twelve characters (be2656061b53) are the ID displayed by docker image ls. The name or the identifier of a container designates an instance, which can disappear. The identifier of an image designates a precise content.

This difference is found again in the removal commands. docker rm removes an instance and leaves the image. docker rmi removes the template.

What does an image contain?

An image contains two things, which the inspection commands separate: its layers and its configuration. A layer is a set of files added or modified compared with the previous one. The layers stack up and form the file system the container will see. Two images that share a base also share these layers on disk.

The configuration describes the execution: environment variables, default command, user. It also contains labels, key-value pairs of metadata that the author of the image writes into it, such as its author or the version of the software. You can therefore read an image by its content or by its configuration. One does not replace the other.

Terminal window
docker image inspect --format '{{json .RootFS.Layers}}' alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a
docker image inspect --format '{{json .Config.Cmd}} {{json .Config.Env}}' alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a
docker history alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a
["sha256:75c137aedfb2760f88629236cb7b797630aed0c3d91d626d1d1bb694878fc2ba"]
["/bin/sh"] ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
IMAGE CREATED CREATED BY SIZE COMMENT
be2656061b53 11 days ago CMD ["/bin/sh"] 0B buildkit.dockerfile.v0
<missing> 11 days ago ADD alpine-minirootfs-3.24.3-x86_64.tar.gz /… 9.08MB buildkit.dockerfile.v0

The first command lists the fingerprints of the layers of the content. Alpine has only one. To know what two images share, run the same command on each and compare: a fingerprint present in both lists is a common layer.

The second command gives the default command (/bin/sh) and the environment (a PATH). The labels are read at the same place, in .Config.Labels.

The third command, docker history, lists the build steps of the image. Not all of them correspond to a layer of files: here, the CMD line weighs 0B. You therefore cannot guess the number of layers by reading the history. To know the layers, query the image with docker image inspect, not its recipe.

Where does an image come from?

An image arrives on your machine from a registry. It is a service that stores images and serves them under a name of the form repository:tag. A digest identifies the exact content.

When docker run does not find the image locally, the daemon downloads it with docker pull, from the registry indicated in its name. By default, it is Docker Hub. The daemon then saves the image in its local storage, where it stays until it is removed. The OCI standardizes the format of images and that of the registry. The page Understanding OCI: tag, digest, manifest, multi-arch and artifacts details tags, digests and manifests.

The client downloads nothing: the daemon does it, from the machine where it runs. With a remote context, the image therefore arrives on the server and not on your workstation.

How do you clean up what the lesson created?

The two test containers are still running, with a five-minute sleep. Remove them, then check that the list is empty. The image is left in place on purpose: it is used in the following lessons.

Terminal window
docker rm -f instance-un instance-deux
docker ps --all --filter name=instance
instance-un
instance-deux
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

docker rm -f repeats the two names. Then docker ps shows only its header: no container has a name that starts with instance any more.

Practice

In the lab, you examine two images already built on the machine. You count their layers, you spot those they have in common and you read what their configuration declares. You query Docker rather than rely on the recipe of the images. The validation recomputes your answers by querying Docker at grading time. Only the real state of the images counts, not the commands you typed.

Key points

  1. The docker client turns a command into a request on the API of a daemon. It creates no container itself.
  2. dockerd exposes the API and manages the networks and the volumes. containerd stores the images (with the default store of Docker 29) and manages the life cycle of the containers. An OCI runtime such as runc creates the process.
  3. The active context designates the daemon contacted, unless DOCKER_HOST is set: it then takes precedence, and docker context show still answers default. docker version and docker info prove which daemon answers.
  4. An image is a read-only template. A container is an instance of this image, and several instances share the same template.
  5. docker rm removes an instance, docker rmi removes an image.
  6. An image is read by its layers (.RootFS.Layers) and by its configuration (.Config: command, environment, labels). The number of steps in its history says nothing about the number of layers. Two images share the layers whose fingerprints are identical.
  7. The daemon downloads images from a registry. With a remote context, they arrive on the server.

Knowledge check

Check that the essentials of this guide stuck. The questions cover only what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn