Understanding OverlayFS: The Union Filesystem Behind Every Docker Container
AI generated
$
/etc
Linux
Understanding OverlayFS
The union filesystem behind every Docker container

Anyone starting Docker containers every day uses OverlayFS without usually knowing it. Understanding how lowerdir, upperdir, and workdir interact, and when the expensive copy up mechanism kicks in, makes it possible to design image layers more deliberately and avoid performance problems with large files inside containers.

10 min read Linux OverlayFS Docker

1. Why every container sits on a union filesystem

A Docker image consists of several read only layers stacked on top of each other, and every running container additionally gets its own writable layer on top of that stack. For applications inside the container to see this as one perfectly ordinary, unified filesystem, a union filesystem transparently merges several directory trees into a single view.

OverlayFS has been part of the mainline Linux kernel since version 3.18 and has become the standard storage driver for Docker and containerd, since it is considerably simpler to implement than older approaches like AUFS and is maintained directly in the mainline kernel. Understanding how OverlayFS works internally also explains why containers start so quickly, and why certain workloads inside containers can be surprisingly slow.

2. The concept: lowerdir, upperdir, and workdir

OverlayFS combines at least two directories into a single view: lowerdir holds one or more read only layers, while upperdir is the single writable layer that every actual change gets written to. From the perspective of a process entering the combined mount point, only one merged file tree exists, in which files from upper layers shadow same named files from lower layers.

The third required directory, workdir, is purely internal scratch space the kernel uses for atomic operations such as renaming files and must never be written to manually or used for anything else. It has to live on the same filesystem as upperdir, because OverlayFS relies internally on rename system calls for certain operations that are only atomic within the same filesystem.


# Prepare the directory structure for a manual OverlayFS mount
mkdir -p /overlay/lower /overlay/upper /overlay/work /overlay/merged

# Mount OverlayFS with a single lower layer
mount -t overlay overlay \
  -o lowerdir=/overlay/lower,upperdir=/overlay/upper,workdir=/overlay/work \
  /overlay/merged

3. How Docker builds image layers on top of it

Every instruction in a Dockerfile that changes the filesystem state typically produces its own read only layer, stored as its own directory in the storage backend. When starting a container, Docker stacks every layer of an image as a lowerdir chain, with the order determined by creation time and dependency chain, and creates a fresh, empty layer as upperdir for the container itself.

The overlay2 storage driver has supported multiple lowerdir entries at once since kernel 4.0, which removed the earlier two layer limitation of the original OverlayFS design and explains why modern Docker installations handle images with many layers without noticeable performance loss.


# Inspect the layers of a running container at the host level
docker inspect --format '{{ .GraphDriver.Data.LowerDir }}' mycontainer
docker inspect --format '{{ .GraphDriver.Data.UpperDir }}' mycontainer

# Check the storage driver and backing filesystem of the Docker daemon
docker info --format '{{ .Driver }}'

4. Mounting and testing OverlayFS manually

For troubleshooting and understanding, a manual mount outside of Docker is worthwhile, since it makes it possible to trace, in isolation, which file from which layer is actually visible in the merged directory. Changes made inside the merged directory land exclusively in upperdir, while lowerdir stays completely untouched, even if a file appears to have been overwritten there.

When a file from a lower layer is deleted inside the merged directory, OverlayFS creates a so called whiteout file in upperdir, a special character device with major and minor numbers of 0, which tells the kernel to ignore the same named file from the lower layers when assembling the view, without the original file in the lower layer actually being deleted.


# Example: create a file only in the lower layer
echo "original" > /overlay/lower/config.txt

# Delete it in the merged directory and inspect the whiteout file
rm /overlay/merged/config.txt
ls -la /overlay/upper/config.txt
stat /overlay/upper/config.txt | grep 'character special'

5. The copy up mechanism and what it costs

As soon as a file that only exists in a lower layer needs to be modified inside the merged directory, the kernel first copies it fully into upperdir before the actual write operation executes. This process is called copy up and is barely noticeable for small configuration files, but becomes a real source of latency for large files such as database files or log archives in the double digit megabyte or gigabyte range, since even changing a single byte copies the entire file.

For workloads that frequently modify large files inside a container, for example a database running directly on the container filesystem instead of a mounted volume, this exact effect produces unexpected latency spikes on the first write after container startup. The standard recommendation is therefore to always keep mutable, write heavy data in bind mounts or named volumes outside the OverlayFS layer stack.

6. Multi layer lowerdir stacks in detail

With multiple lowerdir entries, they are specified separated by colons, and order matters: the first path listed has the highest priority and shadows same named files from every following path. Docker relies on this property to stack layers in the correct historical order, so a layer created later in the Dockerfile always takes precedence over an earlier one.

For deep layer stacks with many levels, as they appear in images built from dozens of Dockerfile instructions, the number of lookups needed to open a file grows linearly with the number of layers, since the kernel may in the worst case have to search every layer from top to bottom until the file is found. In practice this effect stays negligible for typical image sizes, but can become measurable with an extreme number of layers.


# Combine multiple lower layers, the first one has highest priority
mount -t overlay overlay \
  -o lowerdir=/overlay/layer3:/overlay/layer2:/overlay/layer1,\
upperdir=/overlay/upper,workdir=/overlay/work \
  /overlay/merged

7. Performance characteristics compared to the native filesystem

Read access to files already residing in upperdir, or read unchanged from the topmost matching lowerdir layer, is nearly as fast as direct access to the underlying native filesystem, since OverlayFS needs no extra copy operation for that case. The noticeable overhead comes almost exclusively from the copy up mechanism mentioned above, plus metadata operations that span many layers.

For database workloads with many small, randomly distributed writes, a bind mount or volume is generally the better choice over the OverlayFS layer stack, since neither copy up nor whiteout bookkeeping occurs there, and the I/O path is passed straight through to the host's native filesystem.

8. Best practices for running container hosts

On the host, a regular docker system prune or the equivalent for the relevant container runtime is worth running, since unused layers otherwise permanently occupy space in the storage backend, even once no container references them anymore. Production hosts also benefit from a dedicated filesystem for the Docker storage directory, so a filled up layer stack does not endanger the entire root filesystem and the system's operation along with it.

Images should be kept deliberately lean, for example through multi stage builds that leave build dependencies in a discarded intermediate layer and only carry the actually needed artifacts into the final layer stack. Fewer and smaller layers mean fewer lookups on file access and overall faster container startup, which becomes noticeable especially with frequent deployments.

9. Common pitfalls in production operation

The most frequent trap is storing mutable application data directly on the container filesystem instead of in a volume, which not only causes the copy up latency already mentioned, but also means all that data is lost irrecoverably once the container is removed, since upperdir gets deleted along with the container.

A second trap involves filesystem limits: since OverlayFS potentially creates a full copy of every changed file in upperdir, a container that modifies many large files can unexpectedly hit the host filesystem's inode or space limits, even when the Docker image itself looks comparatively small. Nesting OverlayFS on top of OverlayFS, for example in certain Docker in Docker scenarios, also causes compatibility issues depending on kernel version and should be avoided.

Directory Role Writable Special note
lowerdir One or more read only base layers No Multiple paths colon separated, order matters
upperdir Single writable layer Yes Holds whiteout files for deleted lower entries
workdir Internal kernel scratch space Internal only Must live on the same filesystem as upperdir
merged Combined, visible overall view Yes, via upperdir The only mount point applications ever see

Mironsoft

Server administration, Docker hosts, and performance tuning

Linux servers nobody on the team really understands anymore?

We handle setup, hardening, and performance tuning of Linux servers and Docker hosts for Magento deployments, documented and traceable instead of grown and unclear.

Server Audit

Review the existing server configuration for security gaps and performance bottlenecks.

Docker Host Setup

Set up and secure production-ready Docker environments for Magento cleanly.

Monitoring & Tuning

Measure resource usage and tune systemd, kernel, and services with purpose.

10. Summary

OverlayFS

Core concept

lowerdir, upperdir, and workdir combine into a single unified view

Docker connection

Every image layer is a lowerdir layer, the container layer is upperdir

Biggest cost source

Copy up copies the entire file on every first modification

Best practice

Keep mutable large data in volumes instead of the layer stack

11. FAQ: OverlayFS

1What is the difference between lowerdir and upperdir?
lowerdir holds one or more read only layers that are never modified, while upperdir is the single layer that all actual writes land in. OverlayFS combines both into one transparent, unified view.
2Why must workdir never be written to manually?
workdir serves the kernel as internal scratch space for atomic operations such as renames and is managed exclusively internally. Manual intervention can destroy the internal consistency of the overlay structure.
3What happens when a file from lowerdir is deleted in the merged directory?
OverlayFS creates a whiteout file in upperdir with major and minor numbers of 0, telling the kernel to ignore the same named file from lowerdir when assembling the view. The original file physically remains in lowerdir.
4What exactly is the copy up mechanism?
Copy up copies a file that only exists in a lower layer fully into upperdir as soon as it needs to be modified. For large files, even a single byte change can cause noticeable latency because the entire file has to be copied.
5How many lowerdir layers does OverlayFS support at once?
Since kernel 4.0, an arbitrary number of lowerdir entries can be combined at once, separated by colons. Before that, the number of layers was more restricted, which explains the earlier need to periodically squash layers into one.
6Why should databases not run directly on the container filesystem?
Databases generate many small, frequent writes, which incur extra latency through the copy up mechanism and whiteout bookkeeping of OverlayFS. A bind mount or named volume bypasses the layer stack entirely and delivers native filesystem performance.
7Can OverlayFS run on top of any arbitrary filesystem?
OverlayFS works on top of most common filesystems such as ext4 and XFS for lowerdir and upperdir, with somewhat limited support on some network or older specialty filesystems. It is important that upperdir and workdir always live on the same filesystem.
8How do I inspect which layers a running Docker container actually uses?
The docker inspect command with the GraphDriver.Data format field returns the concrete LowerDir and UpperDir paths on the host filesystem. That makes it possible to trace exactly which file comes from which layer.
9What happens to the data in upperdir when a container is removed?
upperdir gets deleted along with the container layer, unless the data was moved out into a volume or bind mount. Any change stored only on the container filesystem is lost irrecoverably.
10Is nesting OverlayFS on top of OverlayFS problematic?
Yes, nested OverlayFS mounts cause compatibility issues depending on kernel version, and in some cases lose copy up guarantees. In Docker in Docker scenarios, the vfs storage driver or external volumes should be used instead wherever possible.