Understanding Docker Images and Containers: A Visual Guide to the Union Filesystem

Image Definition

An image is a collection of read-only layers stacked vertically, offering users a unified view of the filesystem. The following diagram illustrates this concept.

From the left side, you can observe multiple read-only layers stacked on top of each other. Each layer (except the bottom one) contains a pointer to the layer beneath it. These layers are internal Docker implementation details, but they are accessible on the host filesystem. The union filesystem combines these layers into a single coherent filesystem, hiding the multi-layer architecture from the user's perspective. The right side of the diagram shows how this unified view appears to end users.

You can locate these layer files on your host system. However, these layers remain invisible from within a running container. On a typical Linux system running Docker, these layers reside under /var/lib/docker/aufs.

sudo tree -L 1 /var/lib/docker/

Output:

/var/lib/docker/
├── aufs
├── containers
├── graph
├── init
├── linkgraph.db
├── repositories-aufs
├── tmp
├── trust
└── volumes
7 directories, 2 files

Container Definition

A container shares the exact same structure as an image, with one critical difference: the topmost layer of a container is read-write capable.

An important observation: the container definition says nothing about whether the container is actually running. This distinction proves crucial for understanding container behavior.

Core principle: Container = Image + Read-Write Layer. The definition does not require a container to be in a runing state.

Running Container Definition

A running container consists of a read-write filesystem combined with isolated process space containing one or more processes. The following diagram depicts an active container.

Filesystem isolation is what makes Docker such a powerful technology. Processes within a container can modify, delete, or create files, and all these changes occur in the read-write layer. The diagram below demonstrates this behavior.

Consider this verification:

docker run ubuntu touch progress.log

Even after the Ubuntu container stops running, you can locate the new file on the host filesystem:

find / -name progress.log

Result:

/var/lib/docker/aufs/diff/860a7b...889/progress.log

Image Layer Definition

Image layers consolidate scattered data into manageable units. Each layer encompasses more than just filesystem changes—it includes additional metadata as well.

Metadata provides supplementary information about each layer, enabling Docker to retrieve build-time and runtime information, along with parent layer hierarchy details. Both read-only and read-write layers contain metadata.

Furthermore, every layer includes a pointer to its parent layer. If a layer lacks this pointer, it sits at the base of the stack.

Metadata Location:

On most systems, image layer metadata lives in JSON files:

/var/lib/docker/graph/e809f156dc985.../json

Here, e809f156dc985... represents the layer's unique identifier.

Container metadata gets distributed across multiple files within /var/lib/docker/containers/<id>, where <id> corresponds to a read-write layer's identifier. These files typically contain runtime data such as network configuration and logs.

Command Reference

docker create

The docker create command adds a read-write layer on top of the specified image, forming a new container. Critically, this container does not start automatically.

docker start

The docker start command establishes an isolated process space for the container's filesystem. Each container maintains exactly one process isolation space.

docker run

Users often wonder about the distinction between docker start and docker run.

The docker run command performs two operations sequential: it creates a container from the image, then starts that container. This convenience hides implementation details, which can create confusion about what actually occurs.

Similar to how git pull combines git fetch and git merge, docker run combines docker create and docker start.

docker ps

The docker ps command displays only running containers, obscuring stopped containers from view.

docker ps -a

Adding the -a flag includes both running and stopped containers in the output.

docker images

The docker images command lists all top-level images. The distinction between images and read-only layers requires explanation—only images used to create containers or pulled directly qualify as top-level. Each top-level image conceals multiple underlying layers.

docker images -a

The -a flag reveals all images, effectively listing all read-only layers. To examine every layer belonging to a specific image-id, use docker history.

docker stop

The docker stop command sends a SIGTERM signal to running processes within the container, then terminates those processes gracefully.

docker kill

The docker kill command sends a SIGKILL signal to all processes in the container, terminating them immediately without cleanup.

docker pause

Unlike docker stop and docker kill which send UNIX signals directly to processes, docker pause leverages cgroups to suspend all processes in the container's namespace. This approach uses cgroups-based freezing rather than traditional signal handling.

docker rm

The docker rm command removes the read-write layer constituting the container. This operation works only on stopped containers.

docker rmi

The docker rmi command removes a read-only layer from an image. Only top-level layers can be removed directly. The -f flag forces removal of intermediate read-only layers.

docker commit

The docker commit command converts the container's read-write layer in to a read-only layer, effectively transforming a running container into an immutable image.

docker build

The docker build command executes a sequence of operations repeatedly.

It retrieves the base image from the Dockerfile's FROM instruction, then iteratively performs three steps: run (encompassing create and start), modify, and commit. Each iteration generates a new layer, resulting in numerous layers for complex builds.

docker exec

The docker exec command spawns a new process inside a running container, enabling interactive operations within the container.

docker inspect or

The docker inspect command extracts metadata from the topmost layer of a container or image, providing detailed configuration information.

docker save

The docker save command creates a compressed archive of an image for transfer to another Docker host. Unlike export, this preserves metadata and layer information for each layer. This command operates exclusively on images.

docker export

The docker export command generates a tar archive, stripping metadata and unnecessary layers by consolidating multiple layers into a single layer representing only the current unified view. After importing an exported container into Docker, docker images reveals only a single image layer, unlike saved images which preserve the complete layer history.

docker history

The docker history command recursively displays the complete history of layers for a given image, showing the lineage from base layer to top-level image.

Tags: docker containers images union-filesystem layered-architecture

Posted on Thu, 07 May 2026 02:50:21 +0000 by ArmanIc