Skip to content
Home
Linux Namespaces & Container Isolation Guide

Linux Namespaces & Container Isolation Guide

Linux Linux 8 min read 1500 words Beginner ExcellentWiki Editorial Team

How Linux Namespaces Enable Containers

Linux namespaces partition kernel resources such that one group of processes sees a set of resources while another group sees a different set. Each namespace type wraps a global system resource — process IDs, network interfaces, mount points, user IDs — providing processes within the namespace an isolated view. Containers combine multiple namespaces to create the illusion of a separate operating system instance sharing the same kernel. Unlike virtual machines, namespaces impose minimal overhead because they partition the kernel rather than emulating hardware. This architectural choice is why containers start in milliseconds rather than seconds and achieve near-native performance. Linux currently implements eight namespace types: PID, Network, Mount, User, Cgroup, IPC, UTS, and Time (added in Linux 5.6). Docker, Podman, and Kubernetes all rely on namespaces as the foundation of container isolation (Kerrisk, “The Linux Programming Interface,” No Starch Press, 2010; man namespaces, Linux Programmer’s Manual). The lsns command lists all currently active namespaces on the system with their types and associated processes.

PID Namespace: Process Isolation

PID namespaces isolate process ID number spaces. A process inside a new PID namespace sees itself as PID 1 and cannot see or signal processes outside the namespace. This prevents container escapes where a compromised process might manipulate host processes:

unshare --fork --pid --mount-proc /bin/bash
# Inside: echo $$ prints "1"
# Inside: ps aux shows only namespace processes

The --mount-proc flag is essential — without it, the new namespace would still see the host’s /proc filesystem, leaking process information. When PID 1 inside a namespace exits, the kernel sends SIGKILL to all remaining processes in that namespace, ensuring clean container shutdown. PID namespaces support nesting up to 32 levels deep. The host PID namespace can see all processes across all child namespaces, but each child only sees its own processes.

Network Namespace: Complete Network Stack Isolation

Network namespaces provide a completely independent network stack per namespace: interfaces, routing tables, firewall rules (iptables/nftables), socket binding space, and the /proc/net directory. Container runtimes create a network namespace per container and connect them through virtual Ethernet (veth) pairs:

ip netns add web
ip netns add db
ip link add veth-web type veth peer name veth-br
ip link set veth-web netns web
ip netns exec web ip addr add 10.0.1.2/24 dev veth-web
ip netns exec web ip link set veth-web up

Network namespaces allow containers to bind to the same port (e.g., 80) without conflict. Docker’s bridge network mode creates one namespace per container and bridges them. Host networking mode (--net=host) omits the network namespace for maximum performance. The CNI plugin architecture provides standardized network configuration in orchestrated environments like Kubernetes.

Mount Namespace: Filesystem Isolation

Mount namespaces isolate the set of filesystem mount points visible to a process. Each container mounts a different root filesystem through pivot_root or MS_MOVE:

unshare --mount /bin/bash
mount --bind /some/custom/dir /mnt  # Only visible within this namespace

Mount propagation controls whether mount events propagate between namespaces. Private propagation (the default) blocks propagation entirely. Shared propagation enables event propagation. These modes are managed through mount --make-shared, mount --make-private, etc.

User Namespace: Rootless Containers

User namespaces map UIDs and GIDs between the namespace and the host. UID 0 inside the namespace can be mapped to an unprivileged UID (e.g., 1000) outside:

unshare --user --map-root-user /bin/bash
# Inside: whoami reports "root"
# Outside: process runs as UID 1000

The mapping is specified via /proc/[pid]/uid_map and /proc/[pid]/gid_map. Without user namespace isolation, a container running as root would have root privileges on the host — a major security concern that rootless containers eliminate.

Cgroup, IPC, and UTS Namespaces

Cgroup namespaces virtualize the view of the cgroup filesystem, making the container’s view of resource limits consistent. IPC namespaces isolate System V IPC resources and POSIX message queues. UTS namespaces isolate the hostname and domain name — the hostname command inside a container returns the container’s hostname, not the host’s.

Combining Namespaces for Containers

The clone() system call creates all namespaces simultaneously. Container runtimes use flags like CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWUSER | CLONE_NEWCGROUP for fully isolated environments. nsenter allows joining existing namespaces for debugging.

Debugging Namespace Issues

Troubleshooting namespace problems requires specialized tools. nsenter joins existing namespaces for debugging: nsenter -t PID -n ip addr inspects the network namespace of a running process. lsns lists all active namespaces with their types, associated processes, and hierarchy. /proc/PID/ns/ contains symlinks to each namespace type, allowing comparison: ls -l /proc/1/ns/ shows host namespaces. The unshare command creates new namespaces from the command line for testing. Docker’s docker exec uses nsenter internally, and docker inspect --format '{{.State.Pid}}' reveals the PID needed for manual nsenter debugging. Common issues include: PID namespace leaks where zombie processes accumulate; network namespace misconfiguration causing connectivity loss; and mount namespace propagation problems where host mounts appear inside containers. The strace -f -e unshare,setns,clone command traces namespace-related system calls, helping diagnose container runtime bugs. Modern container runtimes like crun and youki provide their own debugging tools for namespace inspection.

Security Implications and Best Practices

Namespace-based isolation provides significant security benefits but is not equivalent to virtual machine isolation. The kernel’s attack surface remains exposed: syscalls are shared across namespaces, and bugs in network drivers, filesystem code, or the scheduler can escape namespace boundaries. The user_namespaces(7) man page details the security properties of user namespaces, including the principle of least authority. Best practices for secure container deployments include: always use user namespaces to map container root to an unprivileged host UID; combine namespaces with seccomp filters to restrict available syscalls; apply AppArmor or SELinux profiles for mandatory access control; and drop all capabilities except those explicitly needed. The pivot_root system call should be used instead of chroot for namespace root filesystem changes, as it properly isolates the mount namespace. Recent kernel hardening includes the no_new_privs flag that prevents privilege escalation within namespaces. Regular security audits should verify namespace configurations against the CIS Docker Benchmark or the NIST Application Container Security Guide.

Combining Namespaces with Cgroups

Namespaces provide isolation while cgroups enforce resource limits; together they form the foundation of Linux containerization. Each namespace type restricts a different global resource view: PID namespaces isolate process trees, network namespaces provide independent network stacks, and mount namespaces isolate filesystem mount points. Cgroups v2 control CPU, memory, I/O, and PID limits through the unified hierarchy at /sys/fs/cgroup/. When creating containers, first create cgroup directories under the appropriate controllers, then apply namespace isolation.

The systemd-nspawn tool combines namespace creation with cgroup management through systemd’s unified hierarchy. For manual container creation, unshare --mount --pid --net --fork target_binary runs a process in new namespaces while cgcreate and cgset configure limits. The pivot_root . put_old sequence changes the root filesystem within the mount namespace. After entering new namespaces, remount /proc to reflect the new PID namespace view. User namespace mapping with /proc/PID/uid_map and /proc/PID/gid_map converts between container and host UIDs. Docker and Podman automate these steps, but understanding the primitives is essential for debugging container escape vulnerabilities and optimizing container performance.

Network Namespace Configuration

Network namespaces provide independent network stacks, each with its own interfaces, routing tables, and firewall rules. Creating a network namespace with ip netns add blue creates /var/run/netns/blue and a loopback interface. Virtual Ethernet pairs (veth) connect namespaces: ip link add veth0 type veth peer name veth1 netns blue. Assigning IP addresses and bringing interfaces up: ip addr add 10.0.0.1/24 dev veth0; ip link set veth0 up inside the initial namespace and similar commands inside the target namespace.

Routing between multiple network namespaces requires an intermediate namespace or bridge. The ip link add br0 type bridge creates a Linux bridge, and attaching veth pairs enables namespace-to-namespace communication. Network address translation (NAT) via iptables or nftables allows namespace egress to external networks: iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE. The ip netns exec command runs arbitrary processes within a namespace: ip netns exec blue ping 8.8.8.8. For container workloads, the Container Network Interface (CNI) plugin architecture automates namespace networking, with plugins like bridge, macvlan, ipvlan, and calico providing different isolation and performance characteristics.

Frequently Asked Questions

How do Linux namespaces differ from virtual machines? Namespaces partition the kernel, providing lightweight isolation with near-zero overhead. VMs emulate hardware with a separate kernel, providing stronger isolation but higher overhead.

Can a process escape its namespace? Privileged namespace escape is prevented by kernel design, but the kernel surface area exposed to containers is large. Recent CVEs demonstrate the importance of defense-in-depth.

What is a rootless container? A rootless container runs without any privileged UID on the host, using user namespaces to map container root to an unprivileged host UID.

How many namespace types does Linux support? Linux supports 8 namespace types: PID, Network, Mount, User, Cgroup, IPC, UTS, and Time (added in Linux 5.6).

What is the difference between Docker and Podman namespaces? Podman uses the same kernel namespaces but defaults to rootless user namespace isolation. Docker traditionally requires root privileges.

Related: Linux Systemd Guide | Linux Systemd Advanced | Linux Storage Guide

Section: Linux 1500 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top