1. Introduction

Linux enables us to run multiple processes simultaneously. However, sometimes we may want to isolate some processes from others. For instance, we could opt to run a web server in a separate environment from our desktop applications. Also, we may want to create a sandbox for experimenting with new software without affecting our system. One way to achieve this is by using namespaces.

In this tutorial, we’ll explore how to find the namespaces of a specific process in Linux. In addition, we’ll discuss how namespaces are used in Docker and containerization technology.

2. Namespaces

Namespaces are a feature of the Linux kernel that enables us to create isolated environments for running processes. Each namespace has its own resources, such as process IDs, network interfaces, mount points, user IDs, and hostnames. Processes in different namespaces can’t see or affect each other’s resources unless they share a common namespace.

Notably, each type of namespace isolates a different aspect of the system. Mainly, seven types of namespaces are used in Linux:

Further, namespaces have identifiers, i.e., inode numbers that uniquely identify each namespace on the system. Now, let’s discuss various tools and commands to determine the namespaces of a process in Linux.

3. Using the ps Command

The ps command is a common tool for displaying information about processes. One of the ps options is to show the namespace identifiers for each process.

3.1. Root Namespaces

To use this option, we specify which type of namespace we want to see:

$ ps -o pid,pidns,args
PID    PIDNS COMMAND
  1 4026531836 /sbin/init splash
  2 4026531836 [kthreadd]
  3 4026531836 [rcu_gp]
  4 4026531836 [rcu_par_gp]
  6 4026531836 [kworker/0:0H-kblockd]
  9 4026531836 [mm_percpu_wq]
 10 4026531836 [ksoftirqd/0]
 11 4026531836 [rcu_sched]

The -o option specifies the output format by choosing which columns to show for each process. The pidns value is one of the possible column names. It shows the PID namespace identifier for each process. Also, we can see that all current processes share the same PID namespace identifier (4026531836). Thus, this means that they belong to the same PID namespace.

Similarly, we can use the same option for other types of namespaces:

  • netns – network namespace
  • ipcns – IPC namespace
  • mntns – mount namespace
  • utsns – UTS namespace
  • userns – user namespace

However, these namespaces are usually the root or default namespaces on the system.

3.2. New Namespaces

In addition to them, we can create a new PID namespace by using the unshare command:

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

This command uses fork to create a new process and put it in a new PID namespace. Additionally, it mounts a new procfs under /proc for that namespace.

We can display the namespaces of a particular PID with the appropriate option:

# ps -o pid,pidns,netns,mntns,ipcns,utsns,userns,args -p 1
    PID      PIDNS      NETNS      MNTNS      IPCNS      UTSNS     USERNS COMMAND
      1 4026532718 4026531840 4026532699 4026531839 4026531838 4026531837 bash

Apparently, PID 1 belongs to six different namespaces:

  • PID
  • network
  • mount
  • IPC
  • UTS
  • user

We can also see their inode numbers and the command line arguments of the process.

Of course, if the PID doesn’t belong to any namespace, then the ps command won’t show any output in the respective columns:

# ps -o pid,pidns,netns,mntns,ipcns,utsns,userns,args -p 9999
  PID      PIDNS      NETNS      MNTNS      IPCNS      UTSNS     USERNS COMMAND

We can see that there’s no output, so process 9999 doesn’t belong to any namespace.

4. The /proc/<PID>/ns Directory

Generally, the /proc/<PID>/ns directory contains symbolic links to the namespace files for each type of namespace that the process belongs to.

For instance, let’s use ls to check the namespaces of the process with PID 5151:

$ ls -l /proc/5151/ns
total 0
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:48 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:55 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:55 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:55 net -> 'net:[4026531840]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:55 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 07:36 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 07:32 time -> 'time:[4026531834]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 07:36 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:55 user -> 'user:[4026531837]'
lrwxrwxrwx 1 abdulhameed abdulhameed 0 Jul 26 06:55 uts -> 'uts:[4026531838]'

From the output above, we can see that each symbolic link has the format <type> -> ‘<type>:[<inode>]’. Firstly, <type> is the type of namespace, such as cgroup, ipc, mnt, net, pid, or user. Then, the <inode> is the inode number that uniquely identifies each namespace on the system.

Additionally, we can use these inode numbers to enter the namespaces of the process using the nsenter command:

$ sudo nsenter --net=/proc/5151/ns/net

Basically, we run a shell in the network namespace of the process with PID 5151. In this shell, we can use network commands and tools to inspect and modify the network configuration and communication of that namespace.

5. ip-netns Command

The ip-netns command is part of the iproute2 package, which provides tools for network administration. Also, the ip-netns command can list, add, delete, and execute commands in network namespaces.

Firstly, we need to have a network namespace file in the /var/run/netns directory. This file can be created by using the ip-netns add command:

$ sudo ip netns add router

Thus, we create a network namespace file named router in the /var/run/netns directory.

Next, we can create a new named network namespace using the ip-netns attach command:

$ sudo ip netns attach router 350

If router is available in /var/run/netns, this command attaches the network namespace of process 350 to router as if it were created with ip-netns.

Of course, we can use ip-netns to find the namespace of a process:

$ sudo ip netns identify 5151

In this case, 5151 is the process ID to look up the namespaces of.

6. Using Python listns.v3.py

Alternatively, we can find the namespaces of a process with a Python script called listns.v3.py.

To use this script, we need to have Python installed on our system. Let’s verify using the python3 –version command:

$ python3 --version

If Python is installed, we’d see the version number. If not, the output shows an error message or a command to install Python using the system package manager.

After ensuring we have the interpreter available, we use wget to download the listns.v3.py from its GitHub repository:

$ wget https://raw.githubusercontent.com/Intika-Linux-Namespace/Namespace-Lister/master/listns.v3.py

Now, we can run the script with root access:

$ sudo python3 listns.v3.py
       PID  Namespace             Thread/Command
        38  mnt:[4026531862]      
       312  uts:[4026532232]      
       312  mnt:[4026532231]      
       583  uts:[4026532282]      
       583  mnt:[4026532278]      
       585  mnt:[4026532280]      
       590  uts:[4026532283]      
       590  mnt:[4026532279]      
       684  net:[4026532284]      
       684  mnt:[4026532339]      
       693  mnt:[4026532340]      
       698  mnt:[4026532397]      
       705  mnt:[4026532398]      
       745  mnt:[4026532399]      
       749  uts:[4026532341]      
       749  mnt:[4026532400]      
       812  mnt:[4026532404]      
       880  mnt:[4026532461]      
       902  mnt:[4026532395]     

Evidently, listns.v3.py lists all the namespaces on the system, along with their type and inode number.

Furthermore, we can pipe the output to grep to filter by a specific PID:

$ sudo python3 listns.v3.py | grep 11861
     11861  net:[4026532635]
     11861  pid:[4026532424]
     11861  pid:[4026532424]

Here, we see the namespaces associated with PID 11861.

7. Docker and Containerization

Docker is a popular and widely-used tool for creating and managing containers on Linux. In essence, containers provide isolated environments for running applications and services that don’t affect each other or the host system. Moreover, containers are based on namespaces and other features of the Linux kernel. Indeed, namespaces are of benefit to containers due to their similar characteristics:

  • isolation
  • portability
  • scalability

At the core of Docker’s functionality lies the concept of namespaces. By using these namespaces, Docker ensures that each container operates independently, safeguarding against interference with other processes on the host machine.

When exploring namespaces to find the isolation boundaries of a process in Linux, the principles and mechanisms that Docker employs in containerization become greatly relevant. Understanding Docker’s implementation shows us how namespaces enable secure and isolated environments for running applications. This makes it a powerful tool for developers and system administrators alike.

Docker uses namespaces to limit resource usage and system calls of containers. At the same time, it provides a high-level and low-level interface for creating and managing containers and interacting with namespaces.

An example use case for this is to run multiple web servers on the same host, each in its own container with a different network namespace. This way, each web server can listen on port 80 without conflicting with each other. Also, they can be accessed by different IP addresses or hostnames.

8. Conclusion

In this article, we’ve learned what namespaces are, and why they are important for process isolation. Also, we explored various methods to find the namespaces of a process in Linux. Finally, we briefly discussed how namespaces are used in Docker and containerization technology.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.