This guide explores how Docker utilizes Linux namespaces to provide container isolation. We'll use various command-line tools to inspect and interact with these namespaces.
1. Starting a Test Container
First, let's start a simple Nginx container in detached mode.
sudodockerrun-d--namemynginxnginx# Using '--name mynginx' for easier reference latersudodockerps# Note the Container ID or name ('mynginx') from the output.
The question to consider: Can you curlinside this Nginx container from the host at this point without using docker exec or port publishing? (Typically, no, not directly to its container IP without knowing it or specific routing).
2. Inspecting Container Namespaces from the Host
2.1 Get the Container's Process ID (PID)
To inspect a container's namespaces from the host, we first need the PID of the main process running inside the container.
# Replace 'mynginx' with your container's name or ID if differentPID=$(sudodockerinspect--format'{{.State.Pid}}'mynginx)# Example with a specific ID:# PID=$(sudo docker inspect --format '{{.State.Pid}}' a8f058d6936c)echo"The PID of the container's main process on the host is: $PID"# You can see this process listed in the host's process listpsaux|grep"$PID"
2.2 List Namespaces for the Container's Process
The lsns command can list the namespaces associated with a given PID.
2.3 Find Processes Sharing a Namespace
You can also use pgrep to find all processes (PIDs) that share the same specific namespace as the container's main process. For example, to find all PIDs in the same PID namespace:
3. Entering a Container's Namespaces with nsenter
The nsenter command allows you to run commands within one or more of a process's namespaces. This is a powerful way to "enter" a container's environment from the host without using docker exec.
Enter all key namespaces of the container:
The following command attempts to enter the mount, UTS (hostname), IPC, network, and PID namespaces of the container.
Once inside the namespace (you'll see a new shell prompt):
You are now operating within the container's context. For an Ubuntu/Debian-based container like Nginx, you can try:
Comparison with docker exec:docker exec is the standard Docker way to run commands inside a running container. nsenter is a lower-level Linux tool that achieves a similar result by directly manipulating namespaces.
4. Manipulating Network Namespaces
Let's demonstrate how to create a virtual network interface and move one end into the container's network namespace.
Create a veth pair on the host:
A veth (virtual Ethernet) pair consists of two connected virtual interfaces.
Check the interfaces on the host:
Move one end of the veth pair into the container's network namespace:
The veth-guest interface will disappear from the host's interface list and now exist inside the container's network namespace. veth-host remains on the host.
Configure the interface inside the container's namespace using nsenter:
Enter the container's network namespace (and others for full context):
Now, from the new shell prompt (inside the namespace):
(Note: ifconfig is older; ip addr / ip link from iproute2 are preferred. Added iproute2 to the suggested install.)
Verify with docker exec:
You can also see the new interface using docker exec.
5. Advanced Exercise: Inter-Container Communication via Custom Network (Optional)
This section is for users comfortable with Linux networking. The goal is to enable communication between two containers using manually configured veth pairs and potentially a bridge.
Create a second container.
Create another veth pair, assign one end to the second container, and give it an IP address (e.g., 10.10.10.11/24) on the same conceptual subnet as the first container's veth-guest.
On the host, configure the host-side ends of the veth pairs (e.g., veth-host from the first pair, and the equivalent from the second). You might:
Bring up these host interfaces (e.g., sudo ip link set veth-host up).
Create a Linux bridge on the host (e.g., sudo ip link add name mybridge type bridge; sudo ip link set mybridge up).
Add the host-side veth interfaces to this bridge (e.g., sudo ip link set veth-host master mybridge).
Ensure IP forwarding is enabled on the host if traffic needs to be routed beyond the bridge:
Configure iptables or nftables if necessary, for example, to allow forwarding between the interfaces or to NAT traffic if containers need to reach outside. The original example snippet:
(Corrected "mifgt" to "might". Changed <br> to list items. Clarified iptables rule example.)
This exercise demonstrates the underlying networking primitives that Docker's own networking commands (docker network create, etc.) abstract away.
# This will show the different types of namespaces (mnt, uts, ipc, net, pid, user, cgroup)
sudo lsns | grep "$PID"
# This usually shows the processes running inside the container as seen from the host
sudo pgrep --ns "$PID"
# This will give you a shell prompt that is effectively "inside" the container's environment.
sudo nsenter --target "$PID" --mount --uts --ipc --net --pid
# (Inside nsenter shell)
apt-get update
apt-get install -y wget curl # Install tools if not present
# Try accessing the Nginx server from "within itself"
curl http://127.0.0.1
wget -O - http://127.0.0.1 # Another way
# Check hostname, processes, network interfaces as seen from within the container
hostname
ps aux
ip a # or ifconfig if 'ip a' not available and net-tools installed
# Exit the nsenter shell when done
exit
# Using docker exec for comparison (run from another host terminal):
sudo docker exec -it mynginx bash
# (Inside docker exec shell)
# apt-get update && apt-get install -y wget curl
# curl http://127.0.0.1
# exit
# Run these commands on the host
sudo ip link add veth-host type veth peer name veth-guest
sudo ip link show
# Run on the host
sudo ip link set veth-guest netns "$PID"
# (Inside nsenter shell)
# Install net-tools if 'ifconfig' or 'ip' command is not found (common in minimal images)
# apt-get update && apt-get install -y net-tools iproute2
# List interfaces (you should see veth-guest or a similar name, it might be renamed e.g. ethX)
ip link show # or ifconfig -a
# Assuming the interface moved is now named 'veth-guest' inside the container:
ip addr add 10.10.10.10/24 dev veth-guest
ip link set veth-guest up
# Verify
ip addr show dev veth-guest # or ifconfig veth-guest
exit # Exit nsenter shell
# Run on the host
sudo docker exec -it mynginx ip addr show
# You should see the 'veth-guest' interface (or its renamed equivalent) with IP 10.10.10.10
# sudo sysctl -w net.ipv4.ip_forward=1
# Example: Allow FORWARDing for traffic to/from the 10.10.10.0/24 subnet
# sudo iptables -A FORWARD -p tcp -i mybridge -o mybridge -s 10.10.10.0/24 -d 10.10.10.0/24 -j ACCEPT
# Or more broadly, if routing through other interfaces:
# sudo iptables -A FORWARD -p tcp -d 10.10.10.0/24 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT