Lab 16: Linux Namespaces

Time: 40 minutes | Level: Advanced | Docker: docker run -it --rm --privileged ubuntu:22.04 bash

Linux namespaces are the kernel technology that makes containers possible. Each namespace wraps a global system resource so that processes inside the namespace see an isolated view. In this lab you'll inspect, create, and enter all 7 namespace types from scratch — the same way Docker and Kubernetes do it under the hood.


Step 1: Meet the 7 Namespace Types

Linux 5.6+ supports exactly 7 namespace types. Let's see them all live:

apt-get update -qq && apt-get install -y -qq iproute2 procps util-linux
lsns

📸 Verified Output:

        NS TYPE   NPROCS PID USER COMMAND
4026531834 time        3   1 root bash
4026531837 user        3   1 root bash
4026532768 mnt         3   1 root bash
4026532769 uts         3   1 root bash
4026532770 ipc         3   1 root bash
4026532771 pid         3   1 root bash
4026532772 cgroup      3   1 root bash
4026532773 net         3   1 root bash
Namespace
Flag
Isolates

PID

CLONE_NEWPID

Process IDs — container PID 1 maps to host PID N

NET

CLONE_NEWNET

Network interfaces, routes, iptables

MNT

CLONE_NEWNS

Mount points and filesystem tree

UTS

CLONE_NEWUTS

Hostname and NIS domain name

IPC

CLONE_NEWIPC

SysV IPC, POSIX message queues

USER

CLONE_NEWUSER

UIDs/GIDs — unprivileged containers

CGROUP

CLONE_NEWCGROUP

cgroup root — process sees own hierarchy

💡 TIME namespace (Linux 5.6+) isolates clock offsets. Useful for checkpoint/restore. Listed as "time" in lsns output.


Step 2: Inspect Namespace File Descriptors in /proc

Every process has namespace file descriptors in /proc/PID/ns/:

📸 Verified Output:

The inode numbers (e.g. 4026532769) are namespace IDs. Two processes sharing the same inode are in the same namespace. This is how nsenter targets a namespace.

💡 Keep a namespace alive even after all processes exit by bind-mounting it: mount --bind /proc/1/ns/net /run/netns/saved


Step 3: UTS Namespace — Hostname Isolation

The UTS namespace is the simplest to demonstrate. It lets each container have its own hostname:

📸 Verified Output:

💡 Docker sets the container hostname via --hostname flag which internally creates a UTS namespace and writes the hostname into it.


Step 4: PID Namespace — Process ID Isolation

In a PID namespace, the first process gets PID 1. This is how containers get their own process tree:

📸 Verified Output:

Key flags used:

  • --pid — create new PID namespace

  • --fork — fork before exec (required so child becomes PID 1, not exec'd process)

  • --mount-proc — remount /proc to reflect the new PID namespace

💡 --mount-proc is shorthand for unshare --mount + mount -t proc proc /proc. Docker does the same when setting up a container's /proc.


Step 5: Network Namespace — Full Network Stack Isolation

Network namespaces give each container its own interfaces, routes, and iptables rules:

📸 Verified Output:

📸 Verified Output:

💡 Named network namespaces are stored as bind mounts in /run/netns/. Anonymous namespaces (used by Docker) exist only in /proc/PID/ns/net.


Step 6: MNT Namespace — Filesystem Isolation

Mount namespaces isolate the filesystem tree. This is what allows containers to have their own rootfs:

📸 Verified Output:

💡 Mount propagation modes: shared (default), private, slave, unbindable. Docker uses rprivate for container rootfs mounts to prevent leakage.


Step 7: USER Namespace — Privilege Isolation (Rootless Containers)

User namespaces map UIDs inside the namespace to different UIDs outside. This enables rootless containers:

📸 Verified Output:

The uid_map format: [ns_uid] [host_uid] [count]

  • Inside the namespace, UID 0 maps to host UID 1000 (your real user)

💡 Rootless Docker uses USER namespaces extensively. podman and docker rootless run entirely as unprivileged users by leveraging UID mapping.


Step 8: Capstone — Build a Minimal Container with unshare

Scenario: You're a platform engineer who needs to create an isolated execution environment manually — without Docker — to understand what's happening under the hood. Build a "container" using only unshare, mount, and a chroot.

📸 Verified Output:

You've just built a container from scratch using only Linux kernel primitives!


Summary

Concept
Command
What It Does

List namespaces

lsns

Show all namespaces on the system

Inspect process ns

ls -la /proc/PID/ns/

See namespace FDs for a process

UTS isolation

unshare --uts bash

Isolate hostname

PID isolation

unshare --pid --fork --mount-proc bash

New PID tree, PID 1

Network isolation

ip netns add NAME

Create named network namespace

Mount isolation

unshare --mount bash

Isolate filesystem mounts

User isolation

unshare --user --map-root-user bash

Map UIDs (rootless)

Enter namespace

nsenter -t PID --net bash

Join existing process's namespace

Namespace ID

/proc/PID/ns/TYPE symlink inode

Compare namespace membership

Key insight: Docker, Podman, and Kubernetes all reduce to these same clone(2) and unshare(2) syscalls. Namespaces provide isolation; cgroups provide resource limits — together they define a container.

Last updated