Every developer tutorial starts with “docker run” and moves on. But what actually happens when you run that command? Understanding the internals makes you a better developer and helps you debug container issues that would otherwise seem like black magic.
Containers Are Not Virtual Machines
This is the most common misconception. A VM runs a complete operating system with its own kernel. A container shares the host’s kernel and just isolates processes. That’s why containers start in seconds while VMs take minutes.
Think of it this way: VMs are like separate apartments in a building (each with their own plumbing and electricity). Containers are like rooms in the same apartment – they share infrastructure but have walls between them.
The Three Pillars of Containers
1. Linux Namespaces (Isolation)
Namespaces are what give each container its own “view” of the system. There are several types:
- PID namespace: Process inside container thinks it’s PID 1
- NET namespace: Container gets its own network stack
- MNT namespace: Container has its own filesystem mount points
- UTS namespace: Container can have its own hostname
- IPC namespace: Isolated inter-process communication
- USER namespace: Different user/group IDs inside vs outside
2. Control Groups (Resource Limits)
Cgroups limit how much of the host’s resources a container can use:
# Limit container to 512MB RAM and 50% of one CPU core
docker run -m 512m --cpus 0.5 nginx
Without cgroups, a runaway container could eat all your host’s memory and bring everything down. Cgroups prevent that.
3. Union Filesystems (Layered Images)
Docker images are built in layers. Each instruction in a Dockerfile creates a new layer. When you run a container, Docker adds a thin writable layer on top of the read-only image layers.
FROM python:3.12-slim # Layer 1: base image
COPY requirements.txt . # Layer 2: add requirements file
RUN pip install -r requirements.txt # Layer 3: install deps
COPY . . # Layer 4: add app code
CMD ["python", "app.py"] # Metadata, not a layer
This layering system is why pulling images is fast – if you already have some layers cached, Docker skips downloading them.
What “docker run” Actually Does
When you type docker run nginx, here’s the sequence:
- Docker daemon checks if the nginx image exists locally
- If not, pulls it from Docker Hub (layer by layer)
- Creates a new container (allocates a writable layer)
- Sets up namespaces for the container
- Configures the network (creates a virtual ethernet pair)
- Applies cgroup limits
- Runs the container’s entrypoint command
Why This Matters in Practice
Understanding these internals helps when things go wrong. Container running out of memory? That’s cgroups in action. Can’t reach another container? Probably a network namespace issue. Image taking forever to build? Optimize your layer caching.
The developers who really understand Docker aren’t just copying Dockerfiles from Stack Overflow – they’re thinking about layer efficiency, security implications of running as root, and resource allocation. That understanding starts with knowing what’s happening under the hood.
