Skip to main content
Welcome to this article where we explore how Docker manages data storage within the filesystem. You will learn where Docker stores its data by default, and how it structures files related to containers, images, and layers. When Docker is installed, it creates a default folder structure at /var/lib/docker. For example, listing the contents of this directory might display the following:
In this structure, directories such as aufs, builder, containers, image, network, plugins, and swarm are clearly visible. Docker stores container-related files in the containers folder and image-related files in the image folder.
The storage driver plays a crucial role in managing image layers and associated files. You can check which storage driver is active by running docker info.
When you execute the docker info command, you will see several details including the Docker version (e.g., 17.09) and the storage driver. In this example, the storage driver is aufs, which is the default on Debian and Ubuntu systems. The root directory for the storage driver is /var/lib/docker/aufs. Listing the contents of the /var/lib/docker/aufs directory provides further insight:
  • The diff folder contains the actual content of each image layer. Every instruction in a Dockerfile (for instance, copying source code into the image) creates a new layer stored within this directory.
  • The layers folder holds metadata indicating how these image layers are stacked.
  • The mnt folder stores information about the associated mount points.
At this stage, if no images or containers have been created, these directories may appear empty:

Pulling the Hello-World Image

Next, pull the sample Docker image known as “hello-world” to see how Docker populates these directories:
After pulling the image, inspecting /var/lib/docker/aufs again shows the directories (while they might still appear empty at the top level, their subdirectories are now populated):
The output from pulling the hello-world image is similar to:
To inspect how the hello-world image is built, use the docker history command along with its image ID. First, list the available images:
Then, view the image history:
This output reveals that the hello-world image comprises two steps:
  1. A script is copied into the image.
  2. The copied script is then set as the container’s command.
Although you could theoretically run this script directly from the Docker host, this demonstration is purely for illustrating Docker’s file storage locations.

Building a Sample Python Flask Web Application

Next, let’s build a custom Docker image containing a simple Python Flask web application. In the sample application folder named simple-webapp-docker, you will find two files:
  • app.py – the source code of the application.
  • Dockerfile – the build instructions.

Step 1: Exploring the Application Files

Navigate to the application directory and list its contents:
View the contents of the Dockerfile:

How the Dockerfile Works

  1. Base Image: The application is built on top of Ubuntu 17.04.
  2. Package Installation: The package list is updated and Python along with pip is installed.
  3. Dependency Installation: The Flask package is installed via pip.
  4. Copying Source Code: The application source code (app.py) is copied into the /opt/ directory.
  5. Launching the Application: An entry point is established to run the Flask application.

Step 2: Building the Docker Image

Build the Docker image by running:
During the build process, layers are created and cached. For instance, because Ubuntu is not available locally, it is pulled automatically. The build output will indicate the progress of each step, similar to:
After the build completes, list the available images:
The unnamed image is the one you just built because no repository name or tag was specified. To make management easier, tag your image using the -t parameter.
To view detailed build history and layer information, run:
For example:
This history illustrates that the bulk of the image size arises from the Ubuntu base and the Python dependency installations.

Inspecting the AUFS Diff Directory

After building an image, Docker stores the actual content in the AUFS diff directory. To see the disk usage and structure under this directory, run:
You might recognize the folder that contains your application code by its smaller size. For instance, if you suspect a directory holds your application files, navigate into it and inspect its contents:

Demonstrating Layered Architecture with Multiple Dockerfiles

Docker’s layered architecture allows reuse of base layers (like operating system and dependencies) even if only the application code changes. Consider the following example with two Dockerfiles:

Dockerfile (Original Application)

Build this image with:

Dockerfile2 (Updated Application Version)

Build the updated image with:
Since the base operating system and dependencies remain unchanged, Docker reuses the cached layers for both builds. Only the layer that involves copying the updated application code (app2.py) is rebuilt. Note that when any step changes, Docker clears the cache for that step and all subsequent layers.

Creating an Updated Application

To demonstrate this:
  1. Copy the existing application file and Dockerfile:
  2. Edit app2.py (for example, change “Welcome” to “Welcome 2”) and update Dockerfile2 to reference app2.py:
  3. Build the new image with the updated Dockerfile:
List the images to confirm the updated tags:
Although both web application images report a size of 467MB, most layers (such as the Ubuntu base image and dependencies) are shared. The reported size includes duplicated layers; to view the unique disk usage, use the following command:
The docker system df command presents the actual disk consumption without counting shared layers multiple times. For an even more detailed view, include the verbose flag (-v) to examine each image’s layer breakdown.

Conclusion

In this article we explored:
  • The default file structure created by Docker in /var/lib/docker
  • How storage drivers like AUFS organize images into layers using directories such as diff, layers, and mnt
  • How to inspect Docker images using the docker history command
  • The efficiency of Docker’s layer caching during image rebuilds after minor application changes
  • Monitoring actual disk usage with the docker system df command
We hope this comprehensive guide deepens your understanding of Docker’s storage mechanisms and layer management. Happy containerizing!

Watch Video

Practice Lab