🚀 I'm Building My Own Container Runtime!
This is part of a complete series where I'm building Conti - a container runtime from scratch. Check it out on GitHub!
About This Series:
- I'm sharing everything I learn while building my own container runtime
- Most concepts come from videos, documentation, and LLM-assisted learning (for educational purposes)
- Focus: Understanding through practice - raw Linux commands and practical implementation
- Important: When building your own container, DON'T copy code from sources - it kills the fun! Write it yourself, break things, debug, and learn.
Why Build Your Own?
- Deep understanding of how containers really work
- Master low-level Linux concepts
- Learn by doing, not just reading
- It's incredibly fun when things finally click!
The Secret Ingredient in Modern Cloud Computing
Have you ever wondered how Docker runs thousands of applications on a single server without them interfering with each other? The answer lies in a powerful Linux kernel feature called namespaces. Let's dive into this fascinating technology that powers the modern cloud infrastructure.
📚 Previous Post Recap
In my previous article, we explored the fundamentals of Linux kernel namespaces - what they are, why they matter, and how they form the foundation of containerization. We covered the seven types of namespaces and their role in isolating different system resources.
Now, we're taking it a step further with hands-on examples and practical demonstrations. If you haven't read the previous post, I recommend checking it out for a solid foundation!
What Are Namespaces?
Linux namespaces are a kernel feature that creates isolated environments for processes. They partition system resources so that different groups of processes operate independently, each believing they have exclusive access to their own instance of global resources.
Core principle: When you think namespaces, think isolation.
Why Process Isolation Matters
In Linux systems, process isolation prevents unwanted interactions between different applications or users. The fundamental rule is simple: visibility equals communication. If one process cannot see another, they cannot interfere with each other.
Imagine running multiple applications on a server—a web service, a database, and a background job processor. Without isolation, these processes could potentially conflict, consume each other's resources, or create security vulnerabilities.
Types of Namespaces
Linux provides seven types of namespaces, each isolating different system resources:
- PID Namespace - Isolates process IDs
- Mount Namespace - Isolates filesystem mount points
- Network Namespace - Isolates network interfaces and routing tables
- UTS Namespace - Isolates hostname and domain name
- IPC Namespace - Isolates inter-process communication resources
- User Namespace - Isolates user and group IDs
- Cgroup Namespace - Isolates cgroup hierarchies
How PID Namespaces Work
The PID (Process ID) namespace is one of the most fundamental isolation mechanisms. It creates separate process ID spaces where processes in different namespaces can have the same PID without conflict.
The Parent-Child Hierarchy
Namespaces follow a hierarchical structure:
- Parent namespace can see all processes in child namespaces
- Child namespaces cannot see processes in the parent or sibling namespaces
- Each child namespace maintains its own isolated view of the system
This asymmetric visibility is crucial for system administration—the root namespace can monitor all processes while keeping workloads isolated from each other.
Creating a New PID Namespace
To create a new PID namespace, use the unshare
command:
sudo unshare -p -f --mount-proc /bin/bash
Breaking down the flags:
-
-p
creates a new PID namespace -
-f
forks a new process to become PID 1 in the new namespace -
--mount-proc
mounts a new /proc filesystem -
/bin/bash
launches a bash shell in the isolated environment
The Importance of --mount-proc
The --mount-proc
flag is critical. Without it, the new namespace would inherit the parent's /proc
filesystem, defeating the purpose of isolation. The /proc
filesystem exposes kernel information about running processes, so mounting a fresh instance ensures processes only see others in their namespace.
Practical Example: Isolating Applications
Let's create some simple scripts to demonstrate namespace isolation in action.
Test Scripts
First, create a simple web server simulator:
#!/bin/bash
# webserver.sh
echo "🌐 Web Server Starting..."
echo "Process: webserver | PID: $$"
while true; do
echo "[$(date +%T)] Serving requests..."
# Check if database is visible
if pgrep -f "database.sh" > /dev/null; then
echo " ✓ Database connection available"
else
echo " ✗ Database not found (isolated!)"
fi
sleep 3
done
Create a database simulator:
#!/bin/bash
# database.sh
echo "💾 Database Starting..."
echo "Process: database | PID: $$"
while true; do
echo "[$(date +%T)] Processing queries..."
# Check if webserver is visible
if pgrep -f "webserver.sh" > /dev/null; then
echo " ✓ Webserver connection detected"
else
echo " ✗ Webserver not found (isolated!)"
fi
sleep 3
done
Create a cache service:
#!/bin/bash
# cache.sh
echo "⚡ Cache Service Starting..."
echo "Process: cache | PID: $$"
while true; do
echo "[$(date +%T)] Caching data..."
# Count visible services
count=$(pgrep -f ".sh$" | wc -l)
echo " Visible processes: $count"
sleep 3
done
Make them executable:
chmod +x webserver.sh database.sh cache.sh
Scenario 1: No Isolation (Default)
Run all services in the same namespace:
# Terminal 1
./webserver.sh &
# Terminal 2
./database.sh &
# Terminal 3
./cache.sh &
# Check what each can see
ps aux | grep ".sh$"
Result: All services can see each other - no isolation!
Scenario 2: Partial Isolation
# Terminal 1 (Parent namespace)
./database.sh &
./cache.sh &
# Terminal 2 (Child namespace)
sudo unshare -p -f --mount-proc /bin/bash
./webserver.sh
Result:
- Webserver cannot see database or cache
- Database and cache can still see the webserver (parent sees all)
Scenario 3: Complete Isolation
# Terminal 1 (Namespace A)
sudo unshare -p -f --mount-proc /bin/bash
./webserver.sh
# Terminal 2 (Namespace B)
sudo unshare -p -f --mount-proc /bin/bash
./database.sh
# Terminal 3 (Namespace C)
sudo unshare -p -f --mount-proc /bin/bash
./cache.sh
Result: All three services run in complete isolation—none can see or interact with the others!
Understanding Process ID Mapping
An interesting aspect of namespaces is how process IDs differ between parent and child views:
Process | PID in Child Namespace | PID in Parent Namespace |
---|---|---|
webserver | 1 | 52341 |
worker | 15 | 52358 |
cache | 23 | 52367 |
The parent namespace assigns unique PIDs to distinguish between processes across multiple child namespaces that might use the same local PIDs.
Verifying Namespace Isolation
Check Current Namespace
# View your current PID namespace
lsns -t pid
# Check a specific process's namespace
readlink /proc/[PID]/ns/pid
Test Process Visibility
# In parent namespace
ps aux | grep webserver
# Shows: webserver with PID 42156
# In child namespace
ps aux | grep webserver
# Shows: webserver with PID 1 (or not at all if in different namespace)
Verify Communication Blocking
# Attempt to find processes from another namespace
pgrep database
# Returns nothing if isolated properly
Essential Commands Reference
# List all PID namespaces
lsns -t pid
# List all namespace types
lsns -t all
# Check process namespace
readlink /proc/[PID]/ns/pid
# Create new PID namespace
sudo unshare -p -f --mount-proc /bin/bash
# List processes in current namespace
ps aux
# Find process by name
pgrep [process_name]
Key Takeaways
- Namespaces enable isolation - They're the core technology behind containerization
- Parent-child hierarchy - Parents can monitor children, but children remain isolated from each other
- Multiple namespace types - Different resources require different namespace types
- The /proc filesystem matters - Always remount it for true PID isolation
- Building block for containers - Understanding namespaces illuminates how Docker and Kubernetes work under the hood
Stay tuned, and happy coding! 🚀
Found this helpful? Follow my journey building Conti on GitHub and share your own experiments with namespaces in the comments below!
Top comments (0)