Home/Learn/Docker/Docker Internals — Namespaces, cgroups & OverlayFS

Docker Internals — Namespaces, cgroups & OverlayFS

Advanced
Internals

Docker containers are not magic — they are Linux processes with namespace isolation, cgroup resource limits, and an OverlayFS layered filesystem. Understanding internals helps you debug, optimise, and reason about security.

Overview

Docker does not create a new OS or a new kernel. It creates an ordinary Linux process and applies three kernel features to isolate it: (1) Namespaces: separate the process's view of the system (PID namespace: container thinks it is PID 1; net namespace: own network stack; mnt namespace: own filesystem; uts: own hostname; user: own UID mapping; ipc: own IPC). (2) cgroups (control groups): limit CPU, memory, I/O, and network bandwidth for the process group. (3) OverlayFS: a Union File System that stacks image layers as the container's root filesystem with a writable layer on top.

Namespaces — Process View Isolation

Each namespace type gives a container its own isolated view of a system resource. The container process thinks it is alone on the machine.

bash — inspecting namespaces
# See a container's namespaces from the host

docker run -d --name demo nginx:alpine

PID=$(docker inspect -f '{{.State.Pid}}' demo)



# List namespaces of the container's root process

ls -la /proc/$PID/ns/

# lrwxrwxrwx ... cgroup -> cgroup:[4026531835]

# lrwxrwxrwx ... ipc    -> ipc:[4026532350]   ← isolated IPC

# lrwxrwxrwx ... mnt    -> mnt:[4026532348]   ← isolated filesystem

# lrwxrwxrwx ... net    -> net:[4026532352]   ← isolated network stack

# lrwxrwxrwx ... pid    -> pid:[4026532349]   ← isolated PIDs (PID 1 inside)

# lrwxrwxrwx ... uts    -> uts:[4026532347]   ← isolated hostname

# lrwxrwxrwx ... user   -> user:[4026531837]  ← UID/GID mapping



# Inside container, nginx is PID 1:

docker exec demo ps aux

# PID   USER     COMMAND

#   1   root     nginx: master process

#  31   nginx    nginx: worker process



# On host, it is just another PID (e.g., 18423):

ps aux | grep nginx

cgroups — Resource Limits

cgroups (control groups) limit and account for resource usage. Docker maps --memory, --cpus, and other flags to cgroup configurations.

bash — cgroup resource limits
# Run container with resource limits

docker run -d \

  --memory=512m \           # max 512 MB RAM

  --memory-swap=512m \      # = memory: no swap allowed

  --cpus=1.5 \              # max 1.5 CPU cores

  --cpu-shares=512 \        # relative weight (default 1024) when CPU is contested

  --pids-limit=100 \        # max 100 processes (prevents fork bombs)

  --name limited-app \

  my-app:latest



# View cgroup limits on host (cgroups v2)

cat /sys/fs/cgroup/system.slice/docker-$(docker inspect -f '{{.Id}}' limited-app).scope/memory.max

# 536870912   ← 512 MB in bytes



# Check actual usage

docker stats limited-app

# CONTAINER   CPU%   MEM USAGE / LIMIT   MEM%

# limited-app 0.1%   45MiB / 512MiB      8.8%



# OOM (Out of Memory) Kill — what happens when limit exceeded:

# Docker kills the container (exit code 137)

# docker events | grep oom   ← see OOM kill events

OverlayFS — How Image Layers Work at the Kernel Level

OverlayFS is a Union File System that merges directories (layers) into a single coherent view. Docker uses it to stack image layers as "lowerdir" and add a writable "upperdir" per container.

bash — OverlayFS internals
# OverlayFS structure on the host

ls /var/lib/docker/overlay2/

# Each directory is a layer (identified by chain ID)

# <layer-id>/

#   diff/   ← the actual filesystem files for this layer

#   link    ← short name for the layer

#   lower   ← pointer to parent layer

#   merged/ ← the unified view (container's root filesystem)

#   work/   ← OverlayFS working directory



# OverlayFS mount (conceptual):

# mount -t overlay overlay \

#   -o lowerdir=layer3:layer2:layer1,   ← image layers (read-only)

#      upperdir=container-writable,     ← writable layer (this container only)

#      workdir=overlay-work \

#   /var/lib/docker/overlay2/.../merged  ← container's root /



# Copy-on-Write:

# 1. Container reads /etc/nginx/nginx.conf → found in lowerdir layer2 → returns it

# 2. Container writes to /etc/nginx/nginx.conf

#    → file is COPIED to upperdir first

#    → write goes to the copy in upperdir

#    → lower layer unchanged (other containers unaffected)



# Inspect overlay mounts:

docker inspect demo | grep -A 20 '"GraphDriver"'

Key Points to Remember

  • 1Docker containers are Linux processes with namespace isolation — not VMs.
  • 2PID namespace: container thinks its process is PID 1 (not the host's PID).
  • 3cgroups enforce hard limits on CPU, memory, and processes — exceeding memory limit triggers OOM kill.
  • 4OverlayFS stacks read-only image layers + writable container layer using Copy-on-Write.
  • 5Writing a file in a container copies it from the lower layer to the writable upper layer (doesn't modify the image).
  • 6A "fat" image with many files is slow to start because more data must be read across layers.

Interview Questions

Sign in to ask Aria
1

How does Docker achieve container isolation without a full OS?

2

What is Copy-on-Write in the context of OverlayFS?

Ask Aria about Docker Internals — Namespaces, cgroups & OverlayFS

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…