Skip to content
Linux Namespaces

Linux Namespaces

August 16, 2026·anupam
anupam

Linux Namespace goes very technical, but I am presenting this in plain way — everyone should understand “tech” but it can be in “less-tech” way too. Did you know Docker and containers may not have existed if Linux namespaces hadn’t existed?


What are Linux Namespaces?

To put it simple, linux namespaces make some of the global system resources (network interfaces, hostname, mounts, etc.) isolated beween independent processes. This means any two independent processes on the host can have different view of these global system resources just because they are in different namespaces.

Resources exist in the host but kernel makes them visible or invisible depending on which namespace the process is on. When a process enters a namespace, the namespace makes sure that what view of system components the process should have.

    flowchart LR
  Processes -- Enter --> Namespaces -- decide-process'-view-of --> Resources["System Components"]
  

One thing not to get confused regarding namespaces is that they doesn’t restrict access to physical resources like: CPU, RAM or Disk. That’s actually metered and restricted by Cgroups.

Type of Namespaces

The level of isolation depends on the namespaces a process is associated with. The table below lists the types of namespaces available at the time of writing. Some examples show how containers takes advantage of different namespaces.

Namespace TypeIsolatesShort example
CgroupCgroup root directoryLimit CPU/memory for a container
IPCSystem V IPC, POSIX message queuesIsolate shared memory between containers
NetworkNetwork devices, stacks, ports, etc.Give a container its own IP and network stack
MountMount pointsGive a container its own filesystem view
PIDProcess IDsMake a container’s process appear as PID 1
TimeBoot and monotonic clocksGive processes a different view of system time
UserUser and group IDsMap container root to an unprivileged host user
UTSHostname and NIS domain nameGive a container its own hostname

Listing Namespaces

Important

Before starting, I want to make sure that most of the commands you use requires root access. Keep that on mind.

The lsns (the full form is list namespaces) utility allows us to list the namespaces available on a system or the namespaces associated with a particular process.

Per User View of Namespaces

By default lsns shows the list of namespaces current user can see. This means two user can have different namespace view.

# Who is this?
$ whoami
alice

# Namespaces visible to alice
$ lsns
NS           TYPE   NPROCS   PID   USER      COMMAND
4026531833   net        21   571   alice    -bash
4026531834   time       21   571   alice    -bash
4026531835   cgroup     21   571   alice    -bash
4026531837   user       21   571   alice    -bash
4026532208   ipc        21   571   alice    -bash
4026532219   mnt         1   642   alice    -bash
4026532220   uts        21   571   alice    -bash
4026532221   pid        21   571   alice    -bash
4026532240   mnt        20   571   alice    -bash

# Switch to root
$ sudo su

$ whoami
root

# Namespaces visible to root
$ lsns
NS            TYPE    NPROCS     PID   USER              COMMAND
4026531833    net        56       1    root               /sbin/init
4026531834    time       56       1    root               /sbin/init
4026531835    cgroup     56       1    root               /sbin/init
4026531837    user       56       1    root               /sbin/init
4026532208    ipc        56       1    root               /sbin/init
4026532219    mnt        22       1    root               /sbin/init
4026532220    uts        51       1    root               /sbin/init
4026532221    pid        56       1    root               /sbin/init
4026532231    mnt         1      90    root               ├─/usr/lib/systemd/systemd-udevd
4026532232    uts         1      90    root               ├─/usr/lib/systemd/systemd-udevd
4026532233    mnt         1     166    systemd-resolve    ├─/usr/lib/systemd/systemd-resolved
4026532234    mnt         1     167    systemd-timesync   ├─/usr/lib/systemd/systemd-timesyncd
4026532235    uts         1     167    systemd-timesync   ├─/usr/lib/systemd/systemd-timesyncd
4026532256    uts         1     189    root               ├─/usr/libexec/wsl-pro-service -vv
4026532294    uts         1     186    root               ├─/usr/lib/systemd/systemd-logind
4026532295    uts         1     191    syslog             ├─/usr/sbin/rsyslogd -n -iNONE
4026532296    mnt         1     189    root               ├─/usr/libexec/wsl-pro-service -vv
4026532297    mnt         1     186    root               └─/usr/lib/systemd/systemd-logind
4026532240    mnt        29     570    root               /init
  • NS is the ID of namespace
  • TYPE is the type of namespace
  • NPROS is the number of processes in the namespace
  • PID is the lowest processID in the namespace
  • UESR is the username of the PID
  • COMMAND is the command of the PID

Per Process View of Namespaces

init is the first process after linux system boots which gets the PID 1. So the view of namespaces as per PID 1 will be:

lsns -p 1

Note

As PID 1 user is root, you need to be root in order to view the namespaces of PID 1.

The -p <PID> option lets you view the namespaces per process.

First you need to find pid of service you want to view namespace of. For example, if dockerd is running:

pid=$(pidof dockerd)

gives the pid of dockerd. In my case, I get the pid of dockerd in $pid variable. Now list namespaces for that $pid:

lsns -p $pid
NS            TYPE   NPROCS PID USER COMMAND
4026531833    net        54   1 root /sbin/init
4026531834    time       54   1 root /sbin/init
4026531835    cgroup     54   1 root /sbin/init
4026531837    user       54   1 root /sbin/init
4026532208    ipc        54   1 root /sbin/init
4026532219    mnt        20   1 root /sbin/init
4026532220    uts        49   1 root /sbin/init
4026532221    pid        54   1 root /sbin/init

My Process Namespace

List all the namespaces related to my current process:

ls -l /proc/$$/ns

All Process Inside A Namespace

Use lsns <NAMESPACE_ID> to view all the processes inside a particular namespace (I use the uts namespace ID from above):

lsns 4026532220
PID     PPID      USER        COMMAND
571      570      alice      -bash
714      571      alice      └─myserver --serve-without-reload
642      572      alice      -bash
37152    37151    alice      -bash
40149    37152    alice      └─lsns 4026532220

Create Linux Namespace And Run Programs Inside New Namespaces

unshare (un share parent namespace) utility provides the way to create new linux namespace and run programs/commands insde it.

As an example:

unshare --uts yourprogram

The command creates brand new UTS Namespace and execute yourprogram program. If yourprogram is not daemon or doesn’t create any other child process than the namespace is destroyed as soon as yourprogram finishes it’s task.

This is important to know:

New Namespace persist only as long as it has child or member process running. It gets destroyed automatically as soon as last member process finishes it’s job.

If you want to run more commands inside new namespace, you can open interactive shell like sh or bash:

unshare --pid /bin/bash

You decide the type of namespace you want by --<TYPE>, I choose --pid namespace.

Entering Inside Existing Namespace

While you can create new namespace using unshare and run commands inside them, nsenter (namespace enter) provides you a way to enter inside the existing namespace of a particular process and execute particular command. The general syntax is:

nsenter -t <PID> --<NAMESPACE_TYPE> [CMD]

You specify the type of namespace you want to enter of particular pid with the command you want to execute. As CMD is optional, if you don’t provide, the default is $SHELL which is /bin/bash in my case. Also you can provide --all if you want to enter inside all namespaces of given PID.

Let’s say I wanted to enter inside --time namespace of the same dockerd pid -t 284 with default $SHELL:

nsenter -t 284 --time

You are now time namespace of PID 284 and have interactive shell to interact with it.

Example1: Docker Network Isolation

All the concepts and commands you learnt so far can be understood properly by simulating similar to docker behaviour of how Docker isolates network from containers to containers or containers to host.

Create a new network namespace (--net) with unshare and specify $SHELL to go inside it

unshare --net $SHELL

You are now inside newly created network namespace. From the namespace types table we know that net namespace is responsible for providing netwrok level isolation. This means:

This newly created network namespace has been networkly isolated i.e. it has different view of network compared to it’s parent.

This can be proved. List the interfaces from inside the namespace:

ip link

You see only the loopback lo interface:

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

Now exit the namespace. It’s easy — use the exit command.

Now list the interfaces again after exiting:

ip link

You have completely different view of network interfaces:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000

You can think the first view is the view of Docker containers and the second one is your actual host. I know it’s oversimplified but yes Docker does it all the time — more programatically and more effictively tho.

Example2: Hostname Isolation

If you remember the table, it’s uts namespace that provides the Hostname Isolation. You guessed it right — yes we are entering uts namespace now. But before that, let’s take a note of our current uts namespace id.

readlink /proc/$$/ns/uts

This shows current process uts namespace id is:

uts:[4026532220]

Now let’s enter new uts namespace. The command we all know:

unshare --uts

You will get your default $SHELL now, but inside newly created uts namespace. Verify with the same command:

readlink /proc/$$/ns/uts

You will get different uts namespase id this time:

uts:[4026532237]

Note your hostname too before changing:

hostname

For me, it’s:

Ansible-Controller

Now let’s change the hostname to linuxbox:

hostname linuxbox

Verify with hostname command, you will get:

linuxbox

Also note the current process id:

echo $$

For me, it was:

56146

Great! Keep this terminal as it is and open new terminal. I get my initial bash as such:

root@Ansible-Controller:~#

This is not unexpected because it’s not the namespace we poke with the hostname. It was the uts namespace of pid 56146 we noted above. Now that, we know the PID, we can enter the uts namespace with nsenter we see a little while ago:

nsenter -t 56146 --uts

Now, I am greeted with this bash:

root@linuxbox:~#

Yep! linuxbox was the same hostname we changed in uts namespace (uts:[4026532237]) belonging to pid 56146.


What else should I say? Good bye!

Last updated on