Kahibaro
Discord Login Register

7.5.4 Namespaces

Overview: What Namespaces Solve

Namespaces isolate global kernel resources so that different sets of processes see different “worlds”:

They are the core building block of containers, but they are much more general: any process can enter its own set of namespaces and live in a “virtualized” view of the machine.

From here on, assume you already understand basic process lifecycle and cgroups at a high level; this chapter focuses on namespaces specifically.

Types of Linux Namespaces

Each namespace type virtualizes a particular kernel resource. A process can be in exactly one namespace of each type at any time, but in multiple different types simultaneously (e.g., one PID namespace, one mount namespace, one network namespace, etc.).

The main types (as of modern kernels) are:

Each is identified in the kernel by an internal ID and exposed to user space via /proc.

How Namespaces Are Represented

Every process has namespace membership tracked by the kernel. User space visibility is primarily through:

Example:

$ ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 user user 0 ... cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 user user 0 ... ipc    -> 'ipc:[4026531839]'
lrwxrwxrwx 1 user user 0 ... mnt    -> 'mnt:[4026531840]'
lrwxrwxrwx 1 user user 0 ... net    -> 'net:[4026531992]'
lrwxrwxrwx 1 user user 0 ... pid    -> 'pid:[4026531836]'
lrwxrwxrwx 1 user user 0 ... pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 user user 0 ... time   -> 'time:[4026531834]'
lrwxrwxrwx 1 user user 0 ... user   -> 'user:[4026531837]'
lrwxrwxrwx 1 user user 0 ... uts    -> 'uts:[4026531838]'

The bracketed number is a kernel-internal namespace ID.

Two PIDs share a namespace if their corresponding /proc/<pid>/ns/<type> links point to the same underlying object (same ID).

Mount (mnt) Namespace

Mount namespaces provide each process group with its own view of the filesystem tree:

Key behaviors:

Practical implications:

Example (using unshare from util-linux):

# Create a new mount namespace and run a shell
sudo unshare --mount --fork /bin/bash
# Inside, mount a tmpfs that only this shell can see
mount -t tmpfs tmpfs /mnt
# From another shell (host namespace), /mnt is unaffected

Mount propagation flags (e.g., MS_SHARED, MS_PRIVATE) control how mounts propagate between namespaces; these are advanced but crucial for real container implementations.

UTS Namespace (Hostname / Domainname)

UTS (UNIX Timesharing System) namespaces isolate:

This is what allows each container to have its own “host” name without changing the real host.

Example:

# New UTS namespace; change hostname only there
sudo unshare --uts --fork /bin/bash
hostname container1
hostname

Outside that namespace, hostname remains the host’s original name.

IPC Namespace

IPC namespaces isolate:

Without IPC namespaces, SysV resources are global per-kernel and visible to any process that knows their keys.

With IPC namespaces:

You can examine IPC objects with tools like ipcs and observe differences across namespaces.

PID Namespace

PID namespaces provide processes with their own PID numbering:

Key properties:

PID 1 semantics in a PID namespace:

Example:

# New PID namespace, mount namespace, and a shell
sudo unshare --pid --mount-proc --fork /bin/bash
# Inside
echo "PID in this namespace: $$"
ps -o pid,ppid,cmd
# Host's perspective:
ps -o pid,ppid,cmd | grep bash

--mount-proc remounts /proc inside the new namespace so /proc shows the namespaced PIDs, not the host’s global ones.

Nested view:

This is crucial for containers: processes think they are PID 1 in a “full” system.

Network Namespace

Network namespaces create isolated network stacks:

The initial network namespace contains the host’s real interfaces (e.g., eth0, wlan0).

A new network namespace starts with:

To connect network namespaces, you typically use:

Example:

# Create a new net namespace and run a shell
sudo unshare --net --uts --fork /bin/bash
# Inside the net namespace:
ip link            # Only 'lo'
ip addr add 10.0.0.2/24 dev lo
ip link set lo up

Typical container networking:

  1. Host creates a veth pair: veth-host and veth-guest.
  2. veth-guest is moved into the container’s net namespace.
  3. veth-host is attached to a Linux bridge (e.g., docker0).
  4. Routes and NAT rules are set on the host to give containers external access.

Tools:

User Namespace

User namespaces map user and group IDs inside the namespace to different IDs outside:

Key concepts:

  inside_id   outside_id   length

Meaning: for a range of length IDs starting at inside_id, map them to starting at outside_id in the parent user namespace.

Example (simplified):

Mapping:

0 100000 65536

So inside-UID 0 is host-UID 100000, inside-UID 1 is host-UID 100001, etc.

Security implications:

Unprivileged user namespaces:

Combined with other namespaces:

Cgroup Namespace

Cgroup namespaces virtualize the view of control groups:

Key effects:

Note: cgroup v1 and v2 behave differently in detail, but the namespace idea is the same: localized view of cgroup paths.

Time Namespace (Newer)

Time namespaces allow processes to have:

Motivations:

Key aspects:

Example usage is more specialized and often integrated with tools like CRIU (Checkpoint/Restore In Userspace).

Creating and Joining Namespaces Programmatically

At the system call level, namespaces are manipulated by:

Typical patterns:

  1. Use clone to start a process directly in a new namespace:
   pid_t child = clone(child_func, child_stack,
                       CLONE_NEWUTS | CLONE_NEWPID | SIGCHLD, arg);
  1. Use unshare and then execve:
   unshare(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID);
   execve("/bin/bash", ...);
  1. Use setns to enter a namespace that another process is already in:
   int fd = open("/proc/1234/ns/net", O_RDONLY);
   setns(fd, 0);  // enter PID 1234's net namespace
   close(fd);

Constraints:

Inspecting and Comparing Namespaces

Besides /proc/<pid>/ns, there are several ways to inspect and analyze namespaces:

  sudo lsns
  sudo lsns -t net

For debugging container internals:

  sudo nsenter --target <pid> --mount --uts --pid --net --ipc /bin/bash

Here, nsenter is essentially a convenient wrapper around setns.

Namespace Relationships and Nesting

A process has:

Key structural properties:

Lifecycle:

Interaction across namespaces:

Namespaces and Containers: Conceptual Mapping

While containers are not a kernel primitive, they are mostly composed of:

Higher-level tools (Docker, Podman, Kubernetes runtimes, LXC/LXD, systemd-nspawn) are essentially elaborate frontends that:

  1. Set up mount trees, networking, id mappings, and cgroups.
  2. Create and join namespaces appropriately.
  3. Manage lifecycle, images, and configuration.

As you study containers more deeply, understanding each namespace’s semantics and interactions is essential for debugging, security analysis, and performance tuning.

Practical Experiments to Understand Namespaces

To make the concepts concrete, useful hands-on exercises include:

These experiments help connect the abstract idea of “isolated kernel resources” with observable differences in process behavior and system layout.

Views: 144

Comments

Please login to add a comment.

Don't have an account? Register now!