Docker [02]: PID Namespaces

Docker [02]: PID Namespaces

So now we understand why it is important to make these lightweight isolated environments on Linux, we can ask how can we do that. If you remember from the previous post on docker, we mentioned some namespaces that will allow us to make these isolated environments. In this post, we will describe only one of them, which is the PID namespace.

PID Namespaces:

To understand what this is we need to go one step back and try to describe how Linux processes work. Simply a Linux operating system is made up of one process, namely “init”, so once the OS runs this process is the only process that gets executed. This process is responsible for creating all the other processes that are needed for the OS to be used by other applications. Think of it as a tree where the root is the init process and all other processes are children of that process. The child processes themselves and can have their own children.

# This shows the process tree on Ubuntu VM
pstree

Alt Text

What namespaces do exist on my machine?

# This command will show the namespaces that are applied to the current root process (init) and all its children 
# unless there is a child that has another set of namespaces applied to it then the parent namespaces will not apply then
lsns

Alt Text

As we can see, the pid namespace along with the other namespaces is applied to the root process and all its children. I'm using Ubuntu, so the root init process is called "system" and not "init" as it is in other Linux distributions.

What pid namespace is?

It is a numbering for the existing processes which gives a process a PID, a unique number to identify this process. Following what we mentioned before, as init is the root of all processes, it is given an ID of one.

pstree -p

Alt Text

Remember! Our goal is to make an isolated environment to run our applications. Should we leave the PIDs as global IDs where any running process knows that one of its parents is the init process? No, we need to isolate the pids so that each process thinks that it is the root of the process tree. This is what the PID namespace does. It gives each process a unique PID that is only known to the process itself and its children. So, if we have a process that has a PID of 1, it will think that it is the root of the process tree and it will not know that there is another process that has the same PID. This is how we isolate the processes from each other.

Once we have that, each process will not know about the other processes that are running on the machine or even know that there is a parent that controls them all. This is the first step to creating an isolated environment.

How to create a pid namespace?

# The unshare command forks a new process from the process that will run the below command
# This command will create a new pid namespace and run a command "bash" in it as the root of that new namespace
# So, the new bash process will think that it is the root of the process tree and not know 
# the process that created it or any other process
unshare --pid --fork --mount-proc /bin/bash

Alt Text

Now we are in the new process, what should happen if we run the pstree command again?

Alt Text

Yes, the root process that is running the bash process with pid=1 and another child that was created from the parent bash to run the pstree command.

How does it look from outside of the new namespace?

pstree -p

Alt Text

As I am connecting to the testing machine using SSH, you can see that any command that I run is created as a child of that bash process that is connecting me to the SSH daemon. Also, the process that we create with a new PID namespace is visible from the outside to the root and has a global PID, so it is still a part of the original tree.

References: