Container Networking Deep Dive Part 2: Two Namespaces on the Same Host
2024-04-14
Introduction
What Are We Building? 🧱
In this second part of the series, we connect two network namespaces (netns1, netns2) to the same virtual bridge on a single VM. This mirrors how Kubernetes pods share a flat L2 network on a single node.
Why This Matters
This setup is the basis of many container networks. It replicates the behavior of a Linux bridge or a virtual switch (like what Docker and most CNIs do).
Scenario Overview
- Two namespaces:
netns1
,netns2
- Each has a veth interface (
veth11
,veth21
) - The host side of the veth pairs (
veth10
,veth20
) is connected to a Linux bridgebr0
- The bridge has IP
172.16.0.1
netns1
gets172.16.0.2
,netns2
gets172.16.0.3
- All interfaces are on the same /24 subnet
Architecture
Setup
We'll use the same setup script as in the previous part.
NAME=scenario2
IMAGE=22.04
up:
@if multipass info $(NAME) >/dev/null 2>&1; then \
echo "$(NAME) already exists. Skipping launch."; \
else \
echo "Launching $(NAME)..."; \
multipass launch --name $(NAME) --memory 1G --disk 5G; \
fi
@chmod +x env.sh setup.sh test.sh
@echo "Transferring files..."
@for f in env.sh setup.sh test.sh; do \
multipass transfer $$f $(NAME):/home/ubuntu/; \
done
Now run the VM setup.
make up
env.sh contains the variables for the scenario.
CON1="netns1" CON2="netns2" NODE_IP="10.0.0.10" BRIDGE_IP="172.16.0.1" IP1="172.16.0.2" IP2="172.16.0.3"
Creating the Namespaces & Interfaces
setup.sh creates the namespaces and interfaces.
#!/bin/bash -e . /home/ubuntu/env.sh sudo ip netns add $CON1 sudo ip netns add $CON2 sudo ip link add veth10 type veth peer name veth11 sudo ip link add veth20 type veth peer name veth21 sudo ip link set veth11 netns $CON1 sudo ip link set veth21 netns $CON2 sudo ip netns exec $CON1 ip addr add $IP1/24 dev veth11 sudo ip netns exec $CON2 ip addr add $IP2/24 dev veth21 sudo ip netns exec $CON1 ip link set veth11 up sudo ip netns exec $CON2 ip link set veth21 up
Connecting via Bridge
sudo ip link add name br0 type bridge sudo ip link set veth10 master br0 sudo ip link set veth20 master br0 sudo ip addr add $BRIDGE_IP/24 dev br0
Bridging everything together
sudo ip link set br0 up sudo ip link set veth10 up sudo ip link set veth20 up sudo ip netns exec $CON1 ip link set lo up sudo ip netns exec $CON2 ip link set lo up
Routing configuration
sudo ip netns exec $CON1 ip route add default via $BRIDGE_IP dev veth11 sudo ip netns exec $CON2 ip route add default via $BRIDGE_IP dev veth21
Manual testing
Conditions to test:
- Ping from
netns1
tonetns2
- Ping from
netns2
tonetns1
- Ping from host to
netns1
& host tonetns2
- Ping from
netns1
to host &netns2
to host.
AutomatedTesting
test.sh contains the tests for the scenario.
#!/bin/bash
. /home/ubuntu/env.sh
check() {
echo "[TEST] $1"
eval "$2"
echo ""
}
fail_if_empty() {
if [ -z "$($1)" ]; then
echo "[FAIL] $2"
exit 1
else
echo "[PASS] $2"
fi
}
fail_if_empty "sudo ip netns list | grep $CON1" "Namespace $CON1 exists"
fail_if_empty "sudo ip netns list | grep $CON2" "Namespace $CON2 exists"
check "IP in $CON1" "sudo ip netns exec $CON1 ip a show dev veth11"
check "IP in $CON2" "sudo ip netns exec $CON2 ip a show dev veth21"
check "Ping $IP2 from $CON1" "sudo ip netns exec $CON1 ping -c 3 $IP2"
check "Ping $IP1 from $CON2" "sudo ip netns exec $CON2 ping -c 3 $IP1"
check "Ping bridge from $CON1" "sudo ip netns exec $CON1 ping -c 3 $BRIDGE_IP"
check "Ping bridge from $CON2" "sudo ip netns exec $CON2 ping -c 3 $BRIDGE_IP"
check "Bridge info" "ip a show br0"
Run with make test
.
Makefile workflow
run: multipass exec $(NAME) -- bash /home/ubuntu/setup.sh test: multipass exec $(NAME) -- bash /home/ubuntu/test.sh shell: multipass shell $(NAME) destroy: multipass delete $(NAME) --purge || echo "Nothing to destroy."
make run # Run the setup script make test # Run the test script make shell # Drop into the VM make destroy # Clean up
Key Takeaways
- A Linux bridge behaves like a virtual switch
- All devices on the same bridge can talk L2 directly
- Namespaces need explicit routing (default route via bridge IP)
- Debugging tools like
ip a
,ip r
,ip link
help massively when it comes to networking & troubleshooting.
Conclusion
You now have a working L2 network across multiple isolated namespaces. This is the basis for pod networking on a single node.
Next up in Part 3: we’ll span this setup across two VMs, and show how to keep everything on the same subnet using a shared L2 segment or VXLAN overlay.