Cloud Native 30 min read

Understanding Container Networking: Namespaces, Veth Pairs, Bridges, Routing and NAT

This article explains how to virtualize and isolate Linux network resources for containers using network namespaces, virtual Ethernet devices, bridges, routing, and NAT, providing step‑by‑step commands to connect containers, expose ports, and enable external internet access without relying on Docker.

Top Architect
Top Architect
Top Architect
Understanding Container Networking: Namespaces, Veth Pairs, Bridges, Routing and NAT

Network configuration is often the most confusing part of containerization. This article shows how to solve single‑host container networking by virtualizing network resources so each container appears to have its own dedicated network stack.

Prerequisites : any recent Linux distribution (the examples use a fresh CentOS 8 VM via Vagrant).

1. Isolate containers with network namespaces :

$ vagrant init centos/8
$ vagrant up
$ vagrant ssh
$ sudo ip netns add netns0
$ ip netns
netns0

Enter the namespace with nsenter and observe an empty network stack.

2. Connect namespaces using a veth pair :

# create veth pair
$ sudo ip link add veth0 type veth peer name ceth0
# move one end into the namespace
$ sudo ip link set ceth0 netns netns0
# bring interfaces up and assign IPs
$ sudo ip link set veth0 up
$ sudo ip addr add 172.18.0.11/16 dev veth0
$ sudo nsenter --net=/var/run/netns/netns0
# inside netns0
$ ip link set lo up
$ ip link set ceth0 up
$ ip addr add 172.18.0.10/16 dev ceth0

Ping between the two ends to verify connectivity.

3. Add a second container and discover routing conflicts :

# create second namespace and veth pair
$ sudo ip netns add netns1
$ sudo ip link add veth1 type veth peer name ceth1
$ sudo ip link set ceth1 netns netns1
$ sudo ip link set veth1 up
$ sudo ip addr add 172.18.0.21/16 dev veth1
# inside netns1
$ ip link set lo up
$ ip link set ceth1 up
$ ip addr add 172.18.0.20/16 dev ceth1

Both containers share the 172.18.0.0/16 network, causing the host to have two identical routes and leading to unreachable traffic.

4. Resolve conflicts with a Linux bridge :

# clean up old namespaces
$ sudo ip netns delete netns0
$ sudo ip netns delete netns1
# create a bridge
$ sudo ip link add br0 type bridge
$ sudo ip link set br0 up
# attach veth ends to the bridge
$ sudo ip link set veth0 master br0
$ sudo ip link set veth1 master br0
# assign IP to the bridge (gateway)
$ sudo ip addr add 172.18.0.1/16 dev br0

Now containers can reach each other and the host via the bridge.

5. Enable external connectivity :

# enable IP forwarding
$ sudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
# add default route inside each namespace
$ sudo nsenter --net=/var/run/netns/netns0
$ ip route add default via 172.18.0.1
$ sudo nsenter --net=/var/run/netns/netns1
$ ip route add default via 172.18.0.1

Containers can now ping the internet.

6. Perform NAT for outbound traffic :

$ sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/16 ! -o br0 -j MASQUERADE

This masquerades container traffic so replies return correctly.

7. Publish container ports to the host (e.g., expose a web server on port 5000):

# DNAT for external traffic
$ sudo iptables -t nat -A PREROUTING -d 10.0.2.15 -p tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000
# DNAT for local host traffic
$ sudo iptables -t nat -A OUTPUT -d 10.0.2.15 -p tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000

Now curl 10.0.2.15:5000 reaches the container service.

8. Docker network drivers overview :

--network host : container shares the host network namespace.

--network none : container gets only a loopback interface.

--network bridge (default): similar to the manual bridge setup described above.

9. Unprivileged containers (e.g., Podman with slirp4netns ) provide network access without root, but lack true IP addresses and raw socket capabilities.

Conclusion : The article demonstrates a simple, reproducible method for container networking using native Linux tools—network namespaces, veth pairs, bridges, routing, and iptables—illustrating the fundamentals behind Docker’s default bridge driver and offering a foundation for more advanced networking solutions.

NATBridgeiptablesContainer NetworkingLinux namespacesVeth
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.