linux namespaces explained with examples

Linux Namespaces Explained with Practical Examples

You run a Docker container and it has its own hostname, process list, network stack, filesystem view, and sometimes even its own idea of who “root” is.

But it is still using the same Linux kernel as the host.

That feels strange until you understand Linux namespaces.

If you are looking for linux namespaces explained with examples, the simplest way to think about namespaces is this:

A namespace gives a process a private view of a global Linux resource.

The resource is still managed by the same kernel, but processes inside different namespaces see different versions of it.

That idea is the foundation of containers, Kubernetes Pods, rootless containers, network isolation, process isolation, and many Linux sandboxing tools.

In this guide, we will go beyond definitions. You will inspect namespaces on a real system, create a few with unshare, enter existing ones with nsenter, and understand how they work together to make containers possible.


What Are Linux Namespaces?

Linux namespaces explained with examples showing isolated views of global kernel resources

Linux normally has many global resources:

  • One process ID space
  • One hostname
  • One network stack
  • One mount tree
  • One set of IPC objects
  • One view of user and group IDs
  • One cgroup path view
  • One boot-time and monotonic-clock view

Namespaces split those global resources into isolated views.

For example, two processes can run on the same host but see different hostnames:

Process A → hostname = host-server
Process B → hostname = container-1

Both processes are using the same kernel. They are simply in different UTS namespaces.

That is the key difference between containers and virtual machines.

A virtual machine runs a separate guest kernel. A container uses the host kernel but isolates processes using namespaces, cgroups, capabilities, seccomp, filesystem layers, and other Linux features.

Namespaces provide isolation of “what the process can see.” Cgroups control “how much resource the process can use.”

Both are important, but they solve different problems.

Types of Linux Namespaces

Linux supports several namespace types.

NamespaceIsolatesPractical example
Mount mntMount points and filesystem viewA container has its own root filesystem
PID pidProcess IDsA process appears as PID 1 inside a container
Network netInterfaces, routes, ports, firewall rulesA container gets its own IP and network stack
UTS utsHostname and NIS domain nameA container has a different hostname
IPC ipcSystem V IPC and POSIX message queuesShared memory isolation between workloads
User userUser IDs, group IDs, capabilitiesRoot inside a namespace maps to non-root outside
Cgroup cgroupView of cgroup pathsA container sees / as its cgroup root
Time timeBoot and monotonic clock offsetsTesting time-sensitive workloads

Not every container uses every namespace in the same way.

For example, Kubernetes Pods commonly share a network namespace between containers in the same Pod. That is why containers inside one Pod can reach each other through localhost.

How to See Namespaces for a Process

Every Linux process exposes namespace handles under:

/proc/<PID>/ns/

Check your current shell:

ls -l /proc/$$/ns

Example output:

cgroup -> cgroup:[4026531835]
ipc    -> ipc:[4026531839]
mnt    -> mnt:[4026531840]
net    -> net:[4026531969]
pid    -> pid:[4026531836]
user   -> user:[4026531837]
uts    -> uts:[4026531838]

The number inside brackets is a namespace inode.

If two processes show the same namespace inode for net, they are in the same network namespace. If the numbers differ, they are in different network namespaces.

Compare your shell with PID 1:

readlink /proc/$$/ns/pid
readlink /proc/1/ns/pid

On the host, these may match.

Inside a container, your shell may see a different PID namespace from the host’s PID 1.

You can also use:

lsns

This lists namespaces known to the system and the processes using them.

Example 1: UTS Namespace — Give a Shell Its Own Hostname

The UTS namespace isolates the hostname.

Open a shell in a new UTS namespace:

sudo unshare --uts bash

Inside that shell, change the hostname:

hostname ns-demo
hostname

Output:

ns-demo

Now open another terminal on the host and run:

hostname

The host hostname is unchanged.

Exit the namespace shell:

exit

This is a small example, but it explains why a container can show a different hostname without changing the host.

A container runtime simply creates a new UTS namespace, sets the hostname inside it, and starts the container process there.

Example 2: PID Namespace — Make a Process See Itself as PID 1

The PID namespace isolates process IDs.

Create a new PID namespace:

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

Now run:

echo $$
ps -ef

You should see that your shell is PID 1 inside this namespace.

That does not mean it is PID 1 on the host. It means the process has one PID inside the namespace and another PID outside.

This is why a container process can appear as PID 1 inside the container but as a normal process on the host.

A simplified view looks like this:

Host PID namespace:
  PID 43210 → container shell

Container PID namespace:
  PID 1 → same shell

This also explains why PID 1 behavior matters in containers.

Inside a PID namespace, the first process acts like init for that namespace. If it exits, the namespace’s process tree is terminated. That is one reason container entrypoints should handle signals and child processes correctly.

For production containers, this is why tools like tini, dumb-init, or well-designed application entrypoints matter.

Example 3: Mount Namespace — Create a Private Mount View

The mount namespace isolates the list of mount points.

Create a new mount namespace:

sudo unshare --mount --fork bash

Inside it, make mount propagation private to avoid surprises:

mount --make-rprivate /

Now create a temporary mount:

mkdir -p /tmp/ns-mount-demo
mount -t tmpfs tmpfs /tmp/ns-mount-demo
df -h /tmp/ns-mount-demo

You will see a tmpfs mounted inside this namespace.

Open another terminal on the host and run:

mount | grep ns-mount-demo

You should not see the mount there.

Exit the namespace shell:

exit

The mount disappears when the namespace is destroyed.

This is the basic idea behind container filesystem isolation. A container can have a different root filesystem, different mounted volumes, and different /proc view without changing the host mount tree.

One important detail: mount propagation can make mount events visible across namespaces in some cases. That is why many container runtimes carefully configure mount propagation as private, slave, or shared depending on the use case.

Example 4: Network Namespace — Create a Private Network Stack

The network namespace isolates network devices, IP addresses, routing tables, firewall rules, sockets, and ports.

Create a namespace:

sudo ip netns add blue

Run a command inside it:

sudo ip netns exec blue ip addr

You will usually see only the loopback interface:

1: lo: <LOOPBACK> mtu 65536

Bring loopback up:

sudo ip netns exec blue ip link set lo up

Now check routes:

sudo ip netns exec blue ip route

There are no normal host routes unless you add them.

This explains why a container can have its own IP address, routing table, and port space.

For example, two containers can both listen on port 8080 because they are in different network namespaces:

Container A netns → 0.0.0.0:8080
Container B netns → 0.0.0.0:8080

On the host, those ports are not automatically the same port. Port publishing is an extra step handled by the container runtime using networking rules, proxies, or NAT.

Clean up:

sudo ip netns delete blue

Example 5: User Namespace — Root Inside, Non-Root Outside

The user namespace is one of the most powerful and misunderstood namespaces.

It isolates user IDs, group IDs, and capabilities.

Try:

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

Inside the shell:

id

You may see:

uid=0(root) gid=0(root)

But this does not mean you became real root on the host.

You are root inside the user namespace. Outside the namespace, that root user maps back to your normal user ID.

This is the foundation of rootless containers.

The benefit is huge: a process can have “root-like” privileges inside its own namespace without having full root privileges on the host.

However, user namespaces are also security-sensitive. Some distributions restrict unprivileged user namespace creation or control it through settings such as:

cat /proc/sys/user/max_user_namespaces

or distribution-specific sysctls.

If unshare --user --map-root-user fails, your system may have disabled or limited unprivileged user namespaces.

Example 6: Enter an Existing Namespace with nsenter

unshare creates new namespaces.

nsenter enters namespaces that already exist.

Find a process:

ps -ef | grep nginx

Suppose the PID is 12345.

Enter its network namespace:

sudo nsenter --target 12345 --net bash

Now run:

ip addr
ip route
ss -lntp

You are seeing networking from that process’s namespace.

This is extremely useful when debugging containers.

For example, if a container has network connectivity issues, you can enter its network namespace from the host and test routes, DNS, ports, and firewall rules from the same network view as the container.

To enter multiple namespaces:

sudo nsenter \
  --target 12345 \
  --mount \
  --uts \
  --ipc \
  --net \
  --pid \
  bash

Be careful. Once you enter a process’s namespaces, commands may affect that isolated environment.

Namespaces vs Cgroups

Namespaces and cgroups are often mentioned together, but they are not the same.

FeatureNamespacesCgroups
Main purposeIsolationResource control
Controls what?What a process can seeHow much it can use
ExamplesPID list, hostname, network stackCPU, memory, I/O, process count
Container roleCreates isolated viewsEnforces limits and accounting

A PID namespace can make a process see only a few processes.

A cgroup can limit that process to 512 MB of memory.

You usually need both for containers.

Without namespaces, the process sees too much of the host. Without cgroups, the process may consume too many host resources.

How Containers Use Namespaces Together

A container is not one namespace. It is a process placed into several namespaces at once.

A simplified container startup flow looks like this:

Container runtime
   ↓
Create namespaces
   ↓
Set hostname
   ↓
Prepare mount tree
   ↓
Configure network namespace
   ↓
Map users if rootless
   ↓
Apply cgroups and security policies
   ↓
Start container process

Docker documentation describes a container as a process isolated with its own filesystem, networking, and process tree. Under the hood, namespaces provide much of that isolation.

A typical container may use:

  • PID namespace for process isolation
  • Mount namespace for filesystem view
  • Network namespace for interfaces and routes
  • UTS namespace for hostname
  • IPC namespace for IPC isolation
  • User namespace for rootless or remapped users
  • Cgroup namespace to hide host cgroup paths

Kubernetes adds another layer.

A Kubernetes Pod usually shares one network namespace across its containers. That is why sidecars and application containers inside the same Pod can communicate over localhost.

So when you debug Kubernetes networking, you are often debugging the Pod’s network namespace, not an individual container’s private network stack.

Practical Debugging Commands

Show namespaces for the current shell

ls -l /proc/$$/ns

Compare two processes

readlink /proc/<PID1>/ns/net
readlink /proc/<PID2>/ns/net

If the output matches, both processes share the same network namespace.

List namespaces

lsns

Show processes in a namespace

lsns -t net

Enter a container-like process namespace

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

Create a temporary namespace for testing

sudo unshare --uts --mount --fork bash

Check namespace limits

ls /proc/sys/user/
cat /proc/sys/user/max_user_namespaces

These commands are useful when Docker, Podman, Kubernetes, or systemd-nspawn behavior feels confusing.

Common Misunderstandings About Linux Namespaces

“A namespace is a security boundary by itself”

Not completely.

Namespaces are an isolation primitive, but secure containers also depend on cgroups, capabilities, seccomp, AppArmor or SELinux, read-only filesystems, user namespaces, and correct runtime configuration.

A privileged container can break many assumptions.

“Root inside a container is always root on the host”

Not necessarily.

With user namespaces, root inside a container can map to an unprivileged user outside. Without user namespace remapping, root inside the container often has more dangerous access if other protections are weakened.

“A mount namespace gives a container its own disk”

No.

It gives the process a different mount view. The underlying storage may still be directories, overlay filesystems, volumes, bind mounts, or network storage from the host.

“Network namespace means internet access automatically works”

No.

A fresh network namespace may only have loopback. You need interfaces, IP addresses, routes, DNS, NAT, or bridges to make it useful.

“PID namespace hides a process from the host”

It hides host processes from the namespace, but the host can still see processes inside child PID namespaces.

That is why you can run ps on the host and see container processes.

Conclusion

Linux namespaces are the reason containers can feel like lightweight virtual machines while still using the host kernel.

They do not create a new operating system. They create isolated views of specific kernel-managed resources.

A PID namespace gives a process its own process tree. A network namespace gives it its own interfaces, routes, and ports. A mount namespace gives it a private filesystem view. A UTS namespace gives it a separate hostname. A user namespace can make root inside the namespace map to a normal user outside.

Once you understand that, Docker and Kubernetes become much easier to reason about.

The best way to learn is hands-on:

ls -l /proc/$$/ns
sudo unshare --uts bash
sudo unshare --pid --fork --mount-proc bash
sudo ip netns add demo
sudo nsenter --target <PID> --net bash

Start with one namespace at a time. Watch what changes. Then combine them mentally into the container model.

That is when Linux namespaces stop feeling like hidden container magic and start looking like practical, inspectable Linux building blocks.

Have you used unshare, nsenter, or /proc/<PID>/ns to debug a container or Kubernetes issue? Share the command that helped you understand the problem in the comments.

For more practical Linux, Docker, Kubernetes, and DevOps troubleshooting guides, subscribe to Codefy and explore the related tutorials.