Abstract geometric containers with neon lighting representing Docker isolation
Back to Blog
Development
2026-01-15
11 min read

Docker Container Isolation: Namespaces and Cgroups Explained

A

Abhay Vachhani

Developer

Key Takeaways

  • Containers are isolated processes, not lightweight VMs.
  • Namespaces provide the "view" isolation (PID, Network, Mount).
  • Cgroups enforce resource limits (CPU, RAM, I/O).
  • Process isolation happens entirely within the Linux kernel.

There's a common misconception that containers are "lightweight virtual machines." This isn't quite right. The reality is simpler and more elegant: a container is just a process on your host machine, wrapped in a few clever Linux kernel features. Understanding how Docker container isolation works is the key to mastering DevOps and system architecture.

The Truth About Docker Process Isolation

When you run docker run nginx, Docker doesn't spin up a mini operating system. It starts a process—just like any other process on your machine. You can verify this yourself by checking the host's process tree.

Feature Linux Namespaces Control Groups (Cgroups)
Primary Purpose Resource Isolation (Visibility) Resource Limiting (Allocation)
Answers the Question "What can I see?" "How much can I use?"
Examples PID, Network, Mount CPU, Memory, Disk I/O

Linux Namespaces Explored

Namespaces are the magic that makes containers feel isolated. They create separate views of system resources, so a process thinks it's alone in the world. Modern Linux provides several types of namespaces that Docker orchestrates to ensure process isolation.

1. PID Namespace

Process ID isolation. Inside a container, the main process sees itself as PID 1, even though the host sees it as a different PID. This creates the illusion of a separate process tree.

# Inside container

$ ps aux
PID USER COMMAND
1 root nginx

# On host - get the actual PID

CID=$(docker run -d nginx)
PID=$(docker inspect -f '{{.State.Pid}}' "$CID")

# Proof: inspect namespace links

ls -l /proc/$PID/ns/pid
lrwxrwxrwx 1 root root 0 pid:[4026532198]

The PID 1 gotcha: PID 1 has special responsibilities in Linux. it must reap zombie processes and handle signals differently. If your container hangs on shutdown, it's often because your app doesn't handle SIGTERM properly. Use docker run --init or tini to get a proper init process.

2. Network Namespace

Each container gets its own network stack: network interfaces, IP addresses, routing tables, and port bindings. This is why multiple containers can each bind to port 80 inside their own namespace without conflicts. However, only one container can publish to the host's port 80 at a time (e.g., -p 80:80).

# Create a network namespace manually

$ sudo ip netns add demo
$ sudo ip netns exec demo ip addr

# Shows only loopback, isolated from host

3. Mount Namespace

Filesystem isolation. Containers have their own root filesystem and mount points. When you see /app inside a container, it's completely separate from the host's /app.

4. UTS Namespace

Hostname and domain name isolation. Each container can have its own hostname without affecting the host or other containers.

5. IPC Namespace

Inter-Process Communication isolation. Shared memory segments, semaphores, and message queues are isolated between containers.

6. User Namespace

UID/GID mapping. This allows a process to be root inside the container (UID 0) while being an unprivileged user on the host. This is critical for security but often not enabled by default. available via rootless Docker or userns-remap configuration.

7. Cgroup Namespace

Isolates the view of cgroups, making the container's cgroup appear as the root. This is a newer addition to Linux namespaces.

8. Time Namespace

Time namespaces virtualize CLOCK_MONOTONIC and CLOCK_BOOTTIME by applying per-namespace offsets. This is useful for testing time-dependent logic (timeouts, retries, "uptime", boot-time assumptions) without changing the host clock. Note: it doesn't generally "warp" wall-clock time (CLOCK_REALTIME).

Cgroups: Resource Limits

While namespaces provide isolation, cgroups (control groups) enforce resource limits. Without cgroups, a container could consume all available CPU or memory, starving other processes. Cgroups prevent this.

Resource Controllers

  • CPU: Limit CPU usage with --cpus or --cpu-shares. On cgroup v2, relative CPU sharing is expressed via weight (cpu.weight), while hard caps use cpu.max.
  • Memory: Set hard limits with --memory
  • Block I/O: Control disk read/write with --blkio-weight
  • Network: Managed via traffic control (tc) outside Docker
# Limit container to 512MB RAM and 0.5 CPU cores

CID=$(docker run -d --memory=512m --cpus=0.5 nginx)
PID=$(docker inspect -f '{{.State.Pid}}' "$CID")

# Inspect cgroup settings (works on both v1 and v2)

cat /proc/$PID/cgroup

# Follow the path under /sys/fs/cgroup/...

# On cgroup v2: cat /sys/fs/cgroup/.../memory.max

# On cgroup v1: cat /sys/fs/cgroup/memory/.../memory.limit_in_bytes

Putting It Together: How Docker Uses These

When you run docker run, here's what happens under the hood:

  • Docker creates a new set of namespaces (PID, network, mount, etc.)
  • Docker configures cgroups to enforce resource limits
  • The container runtime (runc) starts your process inside these namespaces
  • Your process runs, completely unaware it's "containerized"

Practical Demonstrations

Creating a "Container" Manually

You can create container-like isolation without Docker using the unshare command:

# Create a new PID and mount namespace

$ sudo unshare --pid --fork --mount-proc /bin/bash

# You're now in an isolated environment

$ ps aux

# Shows only processes in this namespace

Inspecting Container Namespaces

# List all namespaces

$ sudo lsns

# Enter a container's namespace

$ docker inspect [container] | grep Pid
$ sudo nsenter -t [pid] -n ip addr

# Now you're inside the container's network namespace

Viewing Cgroup Configuration

# Get PID, then locate cgroup path (v1 or v2)

CID=$(docker run -d --memory=512m --cpus=0.5 nginx)
PID=$(docker inspect -f '{{.State.Pid}}' "$CID")

# Shows the cgroup membership paths (works everywhere)

cat /proc/$PID/cgroup

# On cgroup v2 you'll typically read:

# /sys/fs/cgroup//memory.max

# On cgroup v1 you'll read controller-specific files like:

# /sys/fs/cgroup/memory//memory.limit_in_bytes

# Monitor resource usage in real-time

$ systemd-cgtop

Security Implications

Understanding namespaces and cgroups is crucial for container security:

  • Namespaces provide isolation, not security boundaries. A kernel vulnerability can allow escape.
  • Privileged containers bypass many protections. Avoid --privileged unless absolutely necessary.
  • User namespaces improve security by mapping container root to an unprivileged host user.
  • Cgroups prevent resource exhaustion attacks but don't prevent privilege escalation.

Actionable mitigations: Drop unnecessary capabilities (--cap-drop=ALL --cap-add=NET_BIND_SERVICE), prevent privilege escalation (--security-opt no-new-privileges), use seccomp profiles to restrict syscalls, enable AppArmor or SELinux, and mount filesystems read-only where possible (--read-only). Defense in depth is key.

Common FAQs

Conclusion

Containers aren't magic. they're processes with clever isolation. By understanding namespaces and cgroups, you gain insight into how Docker really works, which helps with debugging, security, and performance optimization. The next time you run docker run, remember: you're just starting a process with some kernel features enabled. That's the beauty of containers.

FAQs

How does Docker container isolation work?

Docker uses Linux namespaces to provide an isolated view of the system (PID, Network, Mount, etc.) and cgroups to enforce resource limits (CPU, Memory), ensuring processes stay separated.

Are containers really just processes?

Yes. They're processes with Linux kernel features (namespaces + cgroups) applied. There's no magic virtualization layer.

What's the difference between namespaces and cgroups?

Namespaces handle isolation (what the process can see), while cgroups handle resource allocation (what the process can use).

What is Docker process isolation?

It refers to the technique of using kernel features to isolate a process from the rest of the system, making it think it has its own private environment.

Can I use namespaces without Docker?

Absolutely. Tools like unshare, nsenter, and ip netns let you work with namespaces directly.