<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tanay</title>
    <description>The latest articles on DEV Community by Tanay (@0xmaniac).</description>
    <link>https://dev.to/0xmaniac</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3962750%2F418231e9-8617-4d12-98ed-a19719417919.png</url>
      <title>DEV Community: Tanay</title>
      <link>https://dev.to/0xmaniac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/0xmaniac"/>
    <language>en</language>
    <item>
      <title>Linux Namespaces</title>
      <dc:creator>Tanay</dc:creator>
      <pubDate>Tue, 02 Jun 2026 12:55:09 +0000</pubDate>
      <link>https://dev.to/0xmaniac/linux-namespaces-5em6</link>
      <guid>https://dev.to/0xmaniac/linux-namespaces-5em6</guid>
      <description>&lt;p&gt;Prerequisite&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://x.com/0xManiac_Man/status/2061417758747975810?s=20" rel="noopener noreferrer"&gt;Linux primitives&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A namespace gives a process its own isolated view of a kernel resource. Without namespaces, every process on the system sees the same process list, network interfaces, hostname, mount points, and more. Namespaces allow Linux to create the illusion that a process is running on its own machine.&lt;/p&gt;

&lt;p&gt;This is one of the main reasons containers feel like lightweight virtual machines even though they all share the same kernel.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;By default, Linux resources are global.&lt;/p&gt;

&lt;p&gt;A process can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All system processes&lt;/li&gt;
&lt;li&gt;All network interfaces&lt;/li&gt;
&lt;li&gt;The host hostname&lt;/li&gt;
&lt;li&gt;The host filesystem mounts&lt;/li&gt;
&lt;li&gt;Shared IPC resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Namespaces wrap these resources and give a process a private view of them.&lt;/p&gt;

&lt;p&gt;For example, a container process may see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only container processes&lt;/li&gt;
&lt;li&gt;Its own network interfaces&lt;/li&gt;
&lt;li&gt;Its own hostname&lt;/li&gt;
&lt;li&gt;Its own root filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though everything is running on the same kernel.&lt;/p&gt;

&lt;p&gt;Linux currently provides seven namespace types:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Namespace&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PID&lt;/td&gt;
&lt;td&gt;Process isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NET&lt;/td&gt;
&lt;td&gt;Network isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MNT&lt;/td&gt;
&lt;td&gt;Filesystem mount isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UTS&lt;/td&gt;
&lt;td&gt;Hostname isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPC&lt;/td&gt;
&lt;td&gt;Message queue and shared memory isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USER&lt;/td&gt;
&lt;td&gt;UID/GID mapping isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CGROUP&lt;/td&gt;
&lt;td&gt;cgroup visibility isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each namespace isolates a different kernel resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Syscalls Behind Everything
&lt;/h2&gt;

&lt;p&gt;Almost every namespace operation ultimately comes down to these three syscalls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone()&lt;/li&gt;
&lt;li&gt;unshare()&lt;/li&gt;
&lt;li&gt;setns()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these three explains how Docker, containerd, CRI-O, CNI plugins, kubectl exec, and nsenter actually work.&lt;/p&gt;

&lt;h3&gt;
  
  
  clone()
&lt;/h3&gt;

&lt;p&gt;clone() creates a new process.&lt;/p&gt;

&lt;p&gt;When namespace flags such as CLONE_NEWNET or CLONE_NEWPID are supplied, the child process is created inside brand-new namespaces.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parent Process
       |
clone(CLONE_NEWNET)
       |
Child Process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The child now has its own network namespace.&lt;/p&gt;

&lt;p&gt;Container runtimes use this mechanism when starting containers. They call clone() with multiple namespace flags and then execute the container's entrypoint.&lt;/p&gt;

&lt;p&gt;The new process wakes up in an isolated environment with its own process IDs, network stack, mount points, hostname, and more.&lt;/p&gt;

&lt;p&gt;This is essentially how &lt;code&gt;docker run&lt;/code&gt; begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  unshare()
&lt;/h3&gt;

&lt;p&gt;Unlike clone(), unshare() does not create a child process.&lt;/p&gt;

&lt;p&gt;Instead, it detaches the current process from one or more existing namespaces and creates new namespaces for it.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;unshare &lt;span class="nt"&gt;--uts&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts a shell in a new UTS namespace.&lt;/p&gt;

&lt;p&gt;Inside that shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;hostname &lt;/span&gt;container-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing the hostname only affects that namespace.&lt;/p&gt;

&lt;p&gt;The host machine remains unchanged.&lt;/p&gt;

&lt;p&gt;Think of unshare() as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Keep the same process
Create new namespaces
Move process into them
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is extremely useful for learning, testing, and debugging namespace behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  setns()
&lt;/h3&gt;

&lt;p&gt;This is probably the most important syscall for container networking and Kubernetes internals.&lt;/p&gt;

&lt;p&gt;setns() allows a process to join an existing namespace.&lt;/p&gt;

&lt;p&gt;Instead of creating a new namespace, it enters one that already exists.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current Process
        |
      setns()
        |
Existing Namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how many container tools work.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kubectl exec&lt;/li&gt;
&lt;li&gt;nsenter&lt;/li&gt;
&lt;li&gt;CNI plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; pod-name &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes does not magically start your shell into the container.&lt;/p&gt;

&lt;p&gt;Instead, the runtime locates the container namespaces and uses setns() to join them before launching bash.&lt;/p&gt;

&lt;p&gt;The shell now sees exactly what the container sees.&lt;/p&gt;

&lt;p&gt;CNI plugins use the same mechanism.&lt;/p&gt;

&lt;p&gt;They enter the container's network namespace using setns(), configure networking, assign IP addresses, and create routes.&lt;/p&gt;

&lt;p&gt;nsenter is essentially a convenient wrapper around setns().&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nsenter &lt;span class="nt"&gt;-t&lt;/span&gt; 1234 &lt;span class="nt"&gt;--net&lt;/span&gt; &lt;span class="nt"&gt;--pid&lt;/span&gt; &lt;span class="nt"&gt;--mount&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This joins the network, PID, and mount namespaces of process 1234 and launches a shell inside them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespaces Are Files
&lt;/h2&gt;

&lt;p&gt;One of the most surprising aspects of Linux namespaces is that they are exposed through the filesystem.&lt;/p&gt;

&lt;p&gt;Every process has namespace references located under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/proc/&amp;lt;pid&amp;gt;/ns/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /proc/&lt;span class="nv"&gt;$$&lt;/span&gt;/ns/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may see something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;net -&amp;gt; net:[4026531992]
pid -&amp;gt; pid:[4026531836]
mnt -&amp;gt; mnt:[4026531840]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are not normal files.&lt;/p&gt;

&lt;p&gt;They are references to namespace objects maintained by the kernel.&lt;/p&gt;

&lt;p&gt;The number inside the brackets is the namespace inode.&lt;/p&gt;

&lt;p&gt;If two processes have the same namespace inode, they are in the same namespace.&lt;/p&gt;

&lt;p&gt;This is exactly how tools determine whether two processes share a network namespace or a PID namespace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping a Namespace Alive
&lt;/h2&gt;

&lt;p&gt;Normally, when the last process inside a namespace exits, the namespace disappears.&lt;/p&gt;

&lt;p&gt;However, a namespace remains alive as long as something still holds a reference to it.&lt;/p&gt;

&lt;p&gt;This leads to an interesting thing.&lt;/p&gt;

&lt;p&gt;You can bind mount a namespace file to keep it alive even when no processes exist inside it.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo touch&lt;/span&gt; /run/netns/demo
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;--bind&lt;/span&gt; /proc/&lt;span class="nv"&gt;$$&lt;/span&gt;/ns/net /run/netns/demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the network namespace continues to exist even after the current shell exits.&lt;/p&gt;

&lt;p&gt;This is exactly how &lt;code&gt;ip netns add&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;It creates a namespace and stores a reference under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/run/netns/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The namespace survives because the bind mount keeps a reference to the kernel namespace object.&lt;/p&gt;

&lt;p&gt;Container runtimes use the same idea.&lt;/p&gt;

&lt;p&gt;They create the network namespace, store a reference to it, and pass the path to the CNI plugin.&lt;/p&gt;

&lt;p&gt;The plugin then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opens the namespace file&lt;/li&gt;
&lt;li&gt;Calls setns()&lt;/li&gt;
&lt;li&gt;Configures networking inside that namespace&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is how container networking is wired up behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Namespaces are the primary isolation mechanism used by containers.&lt;/p&gt;

&lt;p&gt;When people say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Containers are isolated from the host&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;what they are actually saying is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PID namespaces isolate processes&lt;/li&gt;
&lt;li&gt;Network namespaces isolate networking&lt;/li&gt;
&lt;li&gt;Mount namespaces isolate filesystems&lt;/li&gt;
&lt;li&gt;UTS namespaces isolate hostnames&lt;/li&gt;
&lt;li&gt;User namespaces isolate privileges&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Containers are not magic.&lt;/p&gt;

&lt;p&gt;Most of the isolation comes from namespaces.&lt;/p&gt;

&lt;p&gt;Everything from Docker to Kubernetes are based on these kernel primitives.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cloud</category>
      <category>docker</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
