DEV Community

Cover image for Understanding Container Magic: The Overlay Filesystem Story
Ajinkya Singh
Ajinkya Singh

Posted on • Edited on

Understanding Container Magic: The Overlay Filesystem Story

๐Ÿš€ I'm Building My Own Container Runtime!

This is part of a complete series where I'm building Conti - a container runtime from scratch. Check it out on GitHub!

About This Series:

  • I'm sharing everything I learn while building my own container runtime
  • Most concepts come from videos, documentation, and LLM-assisted learning (for educational purposes)
  • Focus: Understanding through practice - raw Linux commands and practical implementation
  • Important: When building your own container, DON'T copy code from sources - it kills the fun! Write it yourself, break things, debug, and learn.

Why Build Your Own?

  • Deep understanding of how containers really work
  • Master low-level Linux concepts
  • Learn by doing, not just reading
  • It's incredibly fun when things finally click!

How modern containers achieve incredible efficiency and isolation


๐ŸŽฌ Act 1: The Party Problem

Imagine you're organizing a massive tech conference with three separate tracks happening simultaneously:

๐ŸŽจ The Design Track - UI/UX designers discussing Figma and Sketch

๐Ÿ’ป The DevOps Track - Engineers exploring Kubernetes and CI/CD

๐Ÿค– The AI Track - Researchers presenting machine learning models

Each track needs:

  • A presentation room (isolated space)
  • Audio/visual equipment (shared resources)
  • Custom materials (track-specific content)
  • Whiteboards for notes (temporary changes)

The Expensive Approach โŒ

You could buy three complete sets of everything:

  • 3 projectors @ $2,000 each = $6,000
  • 3 sound systems @ $1,500 each = $4,500
  • 3 furniture sets @ $3,000 each = $9,000

Total: $19,500 ๐Ÿ˜ฑ

The Smart Approach โœ…

What if you could:

  • Share the expensive equipment (projectors, furniture)
  • Give each track private notebooks for their own notes
  • Let them customize only what they need

Total: $6,500 + 3 notebooks

This is exactly what overlay filesystems do for containers!


๐Ÿ—๏ธ Act 2: Understanding the Architecture

The Three-Layer Cake ๐ŸŽ‚

Think of the overlay filesystem as a delicious three-layer cake:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     ๐Ÿฐ MERGED LAYER (What You See)   โ”‚ โ† The complete cake you eat
โ”‚     Combines everything below        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚     โœ๏ธ  UPPER LAYER (Your Changes)   โ”‚ โ† Your frosting and decorations
โ”‚     Read/Write - Personal Edits      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚     ๐Ÿ“ฆ LOWER LAYER (Base Recipe)     โ”‚ โ† The original cake (untouched)
โ”‚     Read-Only - Shared Foundation    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ The Lower Layer (The Foundation)

  • Read-only - Like a published cookbook
  • Contains your base operating system (Ubuntu, Alpine Linux)
  • Shared across ALL containers
  • Never gets modified

โœ๏ธ The Upper Layer (Your Workspace)

  • Read/write - Your personal notepad
  • Stores all YOUR changes
  • Unique to each container
  • Where creativity happens!

๐Ÿ‘€ The Merged Layer (The Magic View)

  • What users actually see and interact with
  • Automatically combines Lower + Upper
  • Feels like one complete filesystem

๐ŸŽช Act 3: The Copy-on-Write Magic Show

Let me show you the most clever trick in the container world: Copy-on-Write (COW)

Scenario: The Recipe Book ๐Ÿ“–

Imagine you have a master recipe book (lower layer) with 100 recipes.

Day 1: You read "Chocolate Cake" โ†’ No copying needed!

You're just reading from the shared book. Fast and efficient!

Day 2: You want to modify "Chocolate Cake" โ†’ NOW the magic happens!

STEP 1: System spots you editing
   โ†“
STEP 2: "Hold on! Let me copy this page to YOUR notebook!"
   โ†“
STEP 3: Copy "Chocolate Cake" to upper layer
   โ†“
STEP 4: You modify YOUR copy
   โ†“
STEP 5: Original recipe stays pristine โœจ
Enter fullscreen mode Exit fullscreen mode

The Result:

  • Master book: Still has original "Chocolate Cake" โœ…
  • Your notebook: Has your modified "Spicy Chocolate Cake" โœ…
  • Everyone else: Still sees the original recipe โœ…

Real Container Example

# Container starts with nginx.conf from base image
$ cat /etc/nginx/nginx.conf
โ†’ Reading from LOWER layer (shared base image)

# You edit the config file
$ echo "worker_processes 4;" >> /etc/nginx/nginx.conf
โ†’ System COPIES file to UPPER layer
โ†’ Your edit goes into YOUR copy
โ†’ Base image remains unchanged!

# Your change is private to YOUR container
โ†’ 1000 other nginx containers still see the original
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Act 4: The Real-World Impact

Before Overlay FS: The Dark Ages ๐Ÿ˜ฑ

Launching 100 web applications:

App 1:  Ubuntu (500MB) + Node.js (100MB) = 600MB
App 2:  Ubuntu (500MB) + Node.js (100MB) = 600MB
App 3:  Ubuntu (500MB) + Node.js (100MB) = 600MB
...
App 100: Ubuntu (500MB) + Node.js (100MB) = 600MB

TOTAL: 60,000 MB (60 GB!) ๐Ÿ’€
Enter fullscreen mode Exit fullscreen mode

After Overlay FS: The Renaissance โœจ

Shared Ubuntu:     500MB (one time!)
Shared Node.js:    100MB (one time!)
App 1 changes:     2MB
App 2 changes:     3MB
App 3 changes:     1MB
...
App 100 changes:   2MB

TOTAL: 600MB + 200MB changes = 800MB ๐ŸŽ‰

SAVED: 59.2 GB (98.7% reduction!)
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ Act 5: Hands-On Workshop

Let's build our own overlay filesystem step-by-step!

Workshop Setup: Three Coffee Shops โ˜•

You're running three coffee shops, each needs menus and custom recipes.

Step 1: Create the Directory Structure

# Our shared base (the franchise template)
mkdir -p coffee-franchise/{base,shop-downtown,shop-uptown,shop-campus}
mkdir -p coffee-franchise/work-{downtown,uptown,campus}
mkdir -p coffee-franchise/merged-{downtown,uptown,campus}

cd coffee-franchise

# Create shared base menu (lower layer)
echo "1. Espresso - $3" > base/menu.txt
echo "2. Latte - $4" >> base/menu.txt
echo "3. Cappuccino - $4.50" >> base/menu.txt
echo "Standard Coffee Brewing Guide" > base/brewing.txt
Enter fullscreen mode Exit fullscreen mode

Step 2: Mount Downtown Shop (First Container)

# Create the overlay filesystem
sudo mount -t overlay overlay \
  -o lowerdir=base,upperdir=shop-downtown,workdir=work-downtown \
  merged-downtown

# Check what's visible
ls merged-downtown/
# Output: menu.txt  brewing.txt (from base!)
Enter fullscreen mode Exit fullscreen mode

Step 3: Make Shop-Specific Changes

# Downtown caters to business people - add premium options
echo "4. Cold Brew - $5" >> merged-downtown/menu.txt
echo "Downtown Specialty: Extra Strong!" > merged-downtown/special.txt

# Check what happened:
ls base/
# Output: menu.txt  brewing.txt (unchanged!)

ls shop-downtown/
# Output: menu.txt  special.txt (YOUR changes only!)
Enter fullscreen mode Exit fullscreen mode

Step 4: Create Another Shop (Second Container)

# Mount campus shop
sudo mount -t overlay overlay \
  -o lowerdir=base,upperdir=shop-uptown,workdir=work-uptown \
  merged-uptown

# Campus caters to students - add budget options
echo "4. Small Coffee - $2" >> merged-uptown/menu.txt
echo "Campus Special: Student Discount 20%!" > merged-uptown/special.txt

# Each shop sees different menus!
cat merged-downtown/special.txt
# Output: Downtown Specialty: Extra Strong!

cat merged-uptown/special.txt
# Output: Campus Special: Student Discount 20%!
Enter fullscreen mode Exit fullscreen mode

๐ŸŽŠ What We Achieved:

โœ… One base menu shared across all shops

โœ… Custom modifications per shop

โœ… Complete isolation - changes don't affect others

โœ… Massive space savings - one copy of common files


๐ŸŽญ Act 6: The Delete Mystery

What happens when you delete a file from the lower layer?

# Try to delete the base menu from downtown
rm merged-downtown/menu.txt

# The file disappears from downtown view... but wait!
ls merged-downtown/
# Output: brewing.txt  special.txt (menu.txt is gone!)

# Check the other shop
ls merged-uptown/
# Output: menu.txt  brewing.txt  special.txt (still there!)

# The secret: a WHITEOUT file
ls -la shop-downtown/
# Output: c--------- 1 root root 0, 0 menu.txt (special marker!)
Enter fullscreen mode Exit fullscreen mode

The Magic:

Instead of deleting from base (impossible - it's read-only!), the system creates a special "whiteout" marker that hides the file only in your view.


๐Ÿš€ Act 7: Real Container Architecture

Here's how Docker/Kubernetes actually use this:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   YOUR RUNNING CONTAINER (Merged)       โ”‚
โ”‚   What you see when you 'docker exec'   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚   CONTAINER LAYER (Upper) โœ๏ธ            โ”‚
โ”‚   - Your app logs                        โ”‚
โ”‚   - Temp files                           โ”‚
โ”‚   - Runtime changes                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚   APP LAYER (Lower 3) ๐Ÿ“ฑ                โ”‚
โ”‚   - Your application code                โ”‚
โ”‚   - App dependencies                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚   RUNTIME LAYER (Lower 2) โš™๏ธ            โ”‚
โ”‚   - Python/Node.js/Java                  โ”‚
โ”‚   - Libraries                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚   BASE OS LAYER (Lower 1) ๐Ÿ—๏ธ            โ”‚
โ”‚   - Ubuntu/Alpine Linux                  โ”‚
โ”‚   - Core utilities                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
     โ†‘
     โ””โ”€ All "Lower" layers are SHARED!
Enter fullscreen mode Exit fullscreen mode

The Dockerfile Connection

FROM ubuntu:20.04           # โ† Lower Layer 1 (shared!)
RUN apt-get install python3  # โ† Lower Layer 2 (shared!)
COPY app.py /app/           # โ† Lower Layer 3 (shared!)
CMD ["python3", "app.py"]    # โ† Upper Layer (YOUR changes!)
Enter fullscreen mode Exit fullscreen mode

Each line creates a layer. When you run 1000 containers from this image:

  • Ubuntu layer: Stored ONCE
  • Python layer: Stored ONCE
  • App layer: Stored ONCE
  • Runtime changes: 1000 unique upper layers (small!)

Top comments (0)