Linux Namespaces — The Isolation Illusion
LEVEL 0
The Problem
We just learned that containers are processes. Regular processes running on the host kernel.
But here’s the puzzle: If they’re just regular processes, why can’t they see each other?
When you’re inside a container and you run ps, you only see the container’s processes. You don’t see the hundreds of other processes running on the host.
When you run ls /, you see the container’s filesystem. Not the host’s filesystem.
When you run ifconfig or ip addr, you see the container’s network interface. Not the host’s network interfaces.
How does a process, running on the host kernel, have a completely different view of the system than other processes?
This is what Linux namespaces provide.
LEVEL 1
The Concept — The Selective Reality Helmet
The Concept
Imagine you’re wearing a VR headset.
You’re standing in your living room. But when you look around, you don’t see your couch, your TV, your windows. You see a completely different environment—maybe you’re on a spaceship, or underwater, or in a medieval castle.
You’re still physically in your living room. You’re still breathing the same air. If someone touches your shoulder, you’ll feel it. But your visual reality has been replaced.
Now imagine that instead of just your vision, the headset also controlled your other senses. You hear spaceship sounds instead of your living room. You feel the texture of medieval stone instead of your carpet. Every sense reports a different reality.
This is what Linux namespaces do.
A process is still running on the host kernel. It’s still using the same hardware, the same CPU, the same RAM. But when it asks the kernel “what processes exist?”, the kernel lies. It shows the process a filtered list—only the processes in the same namespace.
When it asks “what network interfaces exist?”, the kernel shows it a different set of interfaces.
The process isn’t in a different place. It just has a different view of reality.
LEVEL 2
The Mechanics — Types of Namespaces
The Mechanics
Linux provides several types of namespaces. Each namespace type isolates a different aspect of the system.
PID Namespace (Process ID)
The PID namespace gives a process its own isolated view of process IDs.
- From inside a PID namespace, the process sees itself as PID 1 (the init process).
- It can only see processes in its own namespace (its children).
- It has no idea that thousands of other processes exist outside its namespace.
Network Namespace
The network namespace gives a process its own isolated network stack.
- Its own network interfaces (like
eth0,lo) - Its own IP addresses
- Its own routing tables
- Its own firewall rules
Two processes in different network namespaces can both have a process listening on port 80, and they won’t conflict.
Mount Namespace
The mount namespace gives a process its own view of the filesystem.
- What appears at
/(root directory) - What filesystems are mounted where
- Changes to mounts in one namespace don’t affect others
This is how containers have their own root filesystem.
UTS Namespace (Unix Timesharing System)
The UTS namespace isolates hostname and domain name.
- Each namespace can have its own hostname
- Changing hostname in one namespace doesn’t affect others
This is why each container can have a unique hostname.
IPC Namespace (Inter-Process Communication)
The IPC namespace isolates inter-process communication resources like:
- Message queues
- Shared memory segments
- Semaphores
Processes in different IPC namespaces can’t communicate via these mechanisms.
User Namespace
The user namespace provides user and group ID isolation.
- A process can be root inside its namespace but unprivileged outside
- Provides security by limiting what “root in container” can actually do
Cgroup Namespace
The cgroup namespace virtualizes the view of /proc/self/cgroup, making cgroup limits less visible from inside.
LEVEL 3
How Docker Uses Namespaces
When you run a container, Docker asks the Linux kernel to create a new set of namespaces.
Step 1: Create new namespaces
Docker uses the clone() or unshare() system call to create new namespaces:
clone(child_func, stack, CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS | CLONE_NEWUTS, args);
This creates a new process with new PID, network, mount, and UTS namespaces.
Step 2: Set up the isolated environment
For each namespace type, Docker configures the isolated environment:
- PID namespace: The container process becomes PID 1 in its namespace
- Network namespace: Docker creates a virtual ethernet pair, puts one end in the container’s network namespace
- Mount namespace: Docker mounts the container’s root filesystem
- UTS namespace: Docker sets the container’s hostname
Step 3: Execute the container command
Finally, Docker executes the container’s main command inside these namespaces. The process runs, but everything it sees is filtered through its namespaces.
LEVEL 4
Exploring Namespaces on a Running Container
Let’s see namespaces in action.
Start a container:
docker run -d --name demo nginx
Get the container’s main process PID:
PID=$(docker inspect demo --format '{{.State.Pid}}')
echo $PID
View the process’s namespaces:
Every process on Linux has a directory at /proc/{PID}/ns/ that shows which namespaces it belongs to:
ls -la /proc/$PID/ns/
You’ll see something like:
lrwxrwxrwx 1 root root 0 Jan 31 10:00 ipc -> 'ipc:[4026532198]'
lrwxrwxrwx 1 root root 0 Jan 31 10:00 mnt -> 'mnt:[4026532196]'
lrwxrwxrwx 1 root root 0 Jan 31 10:00 net -> 'net:[4026532201]'
lrwxrwxrwx 1 root root 0 Jan 31 10:00 pid -> 'pid:[4026532199]'
lrwxrwxrwx 1 root root 0 Jan 31 10:00 uts -> 'uts:[4026532197]'
Each namespace has a unique identifier. Processes in the same namespace share the same identifier.
Compare with a host process:
ls -la /proc/1/ns/
Process 1 (init/systemd) has different namespace identifiers. It’s in different namespaces than your container.
Enter a container’s namespace:
You can use nsenter to run a command in another process’s namespaces:
nsenter --target $PID --pid --mount --net /bin/bash
This starts a bash shell that shares the container’s PID, mount, and network namespaces. You’re now seeing the world as the container sees it.
Try:
ps aux # You'll only see container processes
hostname # You'll see the container's hostname
ip addr # You'll see the container's network interfaces
This is exactly what docker exec does—it uses nsenter under the hood.
LEVEL 5
The Philosophical Implication
Namespaces are a brilliant trick.
They don’t move the process to a different place. They don’t create a separate kernel or operating system. They just change what the process can see when it asks questions.
The process thinks it’s alone. It thinks it’s PID 1. It thinks it has a whole network stack to itself.
But from the kernel’s perspective, it’s just another process with some metadata tags that say “when this process asks for a process list, filter it.”
This is why containers are so lightweight compared to VMs. There’s no emulation. No separate kernel. Just clever filtering of information at the kernel level.