← Terug naar tutorials

Docker Networking Deep Dive: Bridge, Host, Macvlan en Overlay Uitgelegd

docker networkingbridge networkhost networkmacvlanoverlay networkswarmkubernetesservice discoverynetwerkisolatiedevops

Docker Networking Deep Dive: Bridge, Host, Macvlan en Overlay Uitgelegd

Docker lijkt vaak “magisch” te netwerken: containers kunnen elkaar vinden, poorten worden “gepubliceerd”, en ineens is er een virtueel subnet dat je nooit zelf hebt aangemaakt. In deze tutorial duiken we diep in Docker networking met focus op de vier meest gebruikte drivers: bridge, host, macvlan en overlay. Je leert wat er onder de motorkap gebeurt, wanneer je welke driver kiest, en je krijgt echte commando’s om het zelf te testen en te troubleshooten.

Alle voorbeelden gaan uit van Linux (bijv. Ubuntu/Debian). Op macOS/Windows werkt Docker via een VM; sommige drivers/gedragingen (met name host en macvlan) zijn daar anders of beperkt.


Inhoud


1. Basisconcepten: namespaces, veth, bridges en iptables

Docker networking bouwt op Linux kernel primitives:

Je kunt dit letterlijk zien op de host:

ip addr
ip link
ip route
sudo iptables -t nat -L -n -v
sudo iptables -L -n -v

En per container:

docker run --rm -it alpine sh
# in container:
ip addr
ip route

Belangrijk: Docker kan verschillende “drivers” gebruiken om containerinterfaces te koppelen aan de host en/of aan andere hosts. Dat bepaalt hoe verkeer loopt, hoe IP’s worden toegekend, en welke isolatie je krijgt.


2. Bridge networking (default en user-defined)

2.1 Default bridge (docker0)

Als je Docker installeert, krijg je vrijwel altijd de default bridge: docker0. Containers die je start zonder --network komen hierop terecht (tenzij je daemon anders is geconfigureerd).

Check de default bridge:

ip addr show docker0
ip link show docker0
docker network ls
docker network inspect bridge

Je ziet meestal een subnet zoals 172.17.0.0/16. Wanneer je een container start:

docker run -d --name web1 nginx:alpine
docker inspect -f '{{.NetworkSettings.IPAddress}}' web1

Docker maakt een veth pair, hangt één kant in web1 als eth0, en de andere kant in de host namespace aan docker0. De bridge gedraagt zich als een switch: containers op dezelfde bridge kunnen elkaar op L2 bereiken.

Maar: de default bridge heeft beperkingen:

2.2 User-defined bridge: DNS, isolatie en controle

In de praktijk wil je meestal een user-defined bridge. Voordelen:

Maak een eigen bridge:

docker network create \
  --driver bridge \
  --subnet 172.30.0.0/16 \
  --gateway 172.30.0.1 \
  appnet

Start twee containers op dit netwerk:

docker run -d --name api --network appnet hashicorp/http-echo -text="hallo"
docker run --rm -it --network appnet alpine sh

In de Alpine container:

apk add --no-cache curl bind-tools
nslookup api
curl http://api:5678

Je ziet dat api via Docker DNS (embedded DNS server) resolvet naar het container-IP op appnet.

Isolatie voorbeeld: maak nog een netwerk en toon dat namen niet resolven over netwerken heen.

docker network create othernet
docker run -d --name db --network othernet postgres:16-alpine
docker run --rm -it --network appnet alpine sh
# in container:
nslookup db   # zal falen of geen resultaat geven

2.3 Port publishing en NAT: wat gebeurt er echt?

Als je een container draait op een bridge-netwerk, is hij standaard alleen bereikbaar vanaf:

Om verkeer van buiten naar binnen te krijgen, gebruik je port publishing:

docker run -d --name webpub -p 8080:80 nginx:alpine
curl -I http://127.0.0.1:8080

Wat gebeurt er onder water?

Bekijk de NAT rules:

sudo iptables -t nat -L -n -v | sed -n '1,200p'
sudo iptables -t nat -S | grep -E 'DOCKER|MASQUERADE|DNAT'

Je ziet regels die verwijzen naar chain DOCKER. Daarin staan mappings zoals “tcp dpt:8080 to:172.17.x.y:80”.

Belangrijk detail: -p 8080:80 bindt standaard op alle host-interfaces. Wil je alleen localhost:

docker run -d --name weblocal -p 127.0.0.1:8081:80 nginx:alpine

Controleer luisterende sockets:

ss -lntp | grep -E ':8080|:8081'

2.4 Troubleshooting bridge

Handige checks:

  1. Welke netwerken en IP’s?
docker network ls
docker network inspect appnet
docker inspect web1 | less
  1. Routing en ARP op host:
ip route
ip neigh show
bridge link
bridge fdb show | head
  1. Verkeer volgen met tcpdump (host):

Zoek eerst de veth-interface die bij een container hoort:

docker inspect -f '{{.State.Pid}}' web1
# stel PID=12345
sudo nsenter -t 12345 -n ip addr

Op host kun je ook ip link bekijken; veth-namen wisselen. Sniffen op de bridge is vaak makkelijker:

sudo tcpdump -ni docker0 port 80
  1. Connectivity testen:
docker exec -it web1 sh -c "apk add --no-cache curl >/dev/null 2>&1 || true; curl -I http://127.0.0.1"

3. Host networking: performance en valkuilen

Met --network host krijgt de container geen eigen netwerk namespace (of: hij deelt die van de host). Gevolgen:

Voorbeeld:

docker run --rm -d --name hostng --network host nginx:alpine

Test:

curl -I http://127.0.0.1:80
ss -lntp | grep ':80'

Je zult zien dat nginx nu op de hostpoort 80 luistert (dus als je al een webserver had draaien, faalt dit).

Wanneer gebruiken?

Valkuilen:


4. Macvlan: containers als “echte” hosts op je LAN

Macvlan laat Docker containers een eigen MAC-adres geven op een fysieke interface (de “parent”), waardoor containers direct op je LAN kunnen verschijnen met een IP uit het LAN-subnet. Ze gedragen zich alsof het aparte machines zijn.

Waarom is dit nuttig?

4.1 Macvlan modes en beperkingen

Macvlan kent meerdere modes; Docker gebruikt meestal bridge mode (niet te verwarren met Docker bridge driver). In macvlan bridge mode kunnen macvlan interfaces onderling communiceren via de parent, afhankelijk van switch/driver.

Belangrijke beperking: de host kan standaard niet met macvlan containers praten via dezelfde parent interface. Dit is een veelvoorkomende “waarom kan ik mijn container niet pingen vanaf de host?”-vraag. Oplossing volgt in 4.3.

Daarnaast:

4.2 Macvlan opzetten (met parent interface)

Stel:

Maak het macvlan netwerk:

docker network create -d macvlan \
  --subnet=192.168.10.0/24 \
  --gateway=192.168.10.1 \
  --ip-range=192.168.10.192/26 \
  -o parent=eth0 \
  lanmac

Start een container met vast IP:

docker run --rm -it --network lanmac --ip 192.168.10.210 alpine sh

In de container:

ip addr
ip route
apk add --no-cache curl

Vanaf een andere machine op het LAN:

ping 192.168.10.210

Je kunt ook een service draaien zonder port publishing:

docker run -d --name lanweb --network lanmac --ip 192.168.10.211 nginx:alpine
# vanaf een andere machine:
curl -I http://192.168.10.211

4.3 Host ↔ container communicatie oplossen

Standaard kan de host niet direct praten met macvlan containers. Een gangbare oplossing is een macvlan sub-interface op de host maken en die in hetzelfde subnet zetten (met een vrij IP). Bijvoorbeeld:

  1. Maak macvlan interface op host:
sudo ip link add macvlan0 link eth0 type macvlan mode bridge
sudo ip addr add 192.168.10.190/24 dev macvlan0
sudo ip link set macvlan0 up
  1. Voeg route toe (vaak al aanwezig door /24, maar expliciet kan helpen):
sudo ip route add 192.168.10.192/26 dev macvlan0
  1. Test vanaf host:
ping -c 2 192.168.10.211
curl -I http://192.168.10.211

Let op IP-conflicten: kies een host-IP (192.168.10.190) dat niet door DHCP wordt uitgedeeld en niet door Docker --ip-range wordt gebruikt.

Persistency: bovenstaande ip link add is niet persistent na reboot. Maak het persistent via je distro’s network config (bijv. systemd-networkd of NetworkManager), maar dat valt buiten de scope van deze Docker-only tutorial.


5. Overlay networking: multi-host met Swarm

Overlay netwerken zijn bedoeld voor container-to-container networking over meerdere Docker hosts. Docker gebruikt hiervoor o.a. VXLAN encapsulatie. In de praktijk gebruik je overlay meestal samen met Docker Swarm (ingebouwd in Docker Engine).

Belangrijke concepten:

5.1 Swarm init en overlay aanmaken

Op de eerste host (manager):

docker swarm init --advertise-addr <MANAGER_IP>

Bekijk join tokens:

docker swarm join-token worker
docker swarm join-token manager

Op een tweede host (worker), voer het join-commando uit dat je net kreeg.

Controleer status op manager:

docker node ls

Maak een overlay netwerk:

docker network create -d overlay --attachable appovl
docker network ls
docker network inspect appovl

--attachable betekent dat je naast services ook losse containers kunt attachen (handig voor debug).

5.2 Services, VIP vs DNSRR, routing mesh

Maak een service op overlay:

docker service create --name whoami --network appovl --replicas 3 traefik/whoami
docker service ls
docker service ps whoami

Test service discovery door een debug container te starten op hetzelfde overlay netwerk:

docker run --rm -it --network appovl alpine sh

In de debug container:

apk add --no-cache curl bind-tools
nslookup whoami
curl http://whoami

VIP (Virtual IP) load balancing: standaard krijgt een service een VIP en Docker load-balancet naar tasks. Je ziet één IP bij nslookup whoami.

Wil je DNS round-robin (DNSRR) in plaats van VIP:

docker service update --endpoint-mode dnsrr whoami

Dan zal DNS meerdere A-records geven (één per task IP), en je client doet de balancing.

Routing mesh en published ports

Swarm heeft een “routing mesh”: als je een service poort publiceert, kan je die poort op elke node benaderen, ongeacht waar de task draait.

Voorbeeld:

docker service create \
  --name web \
  --network appovl \
  --replicas 2 \
  --publish published=8080,target=80 \
  nginx:alpine

Test vanaf buiten (naar eender welke node IP):

curl -I http://<ANY_NODE_IP>:8080

Wil je host-mode publishing (alleen op nodes waar een task draait, geen routing mesh):

docker service update --publish-rm 8080 web
docker service update --publish-add published=8080,target=80,mode=host web

Controleer waar tasks draaien:

docker service ps web

5.3 Encryptie en poorten

Overlay gebruikt VXLAN (UDP 4789) en control plane verkeer. Zorg dat in je netwerk/firewall minimaal dit openstaat tussen nodes:

Versleutelde overlay (data plane encryptie):

docker network create -d overlay --opt encrypted --attachable secureovl

Dit voegt overhead toe, maar kan nodig zijn op onbetrouwbare netwerken.

5.4 Troubleshooting overlay

  1. Swarm status:
docker info | sed -n '1,120p'
docker node ls
docker network ls
  1. Service DNS en connectiviteit:
docker run --rm -it --network appovl alpine sh
# in container:
apk add --no-cache curl bind-tools
nslookup web
curl -I http://web
  1. Inspect tasks en endpoints:
docker service inspect web --pretty
docker service ps web
docker inspect $(docker ps -q --filter name=web.) | less
  1. Check poorten op nodes:
ss -lntup | grep -E '2377|7946|4789'
  1. VXLAN interface op host (kan per distro verschillen):
ip -d link show | grep -A2 -E 'vxlan|docker_gwbridge'
ip addr show docker_gwbridge

docker_gwbridge is een speciale bridge die Swarm vaak gebruikt als gateway tussen overlay en host/extern verkeer.


6. Keuzehulp: welke driver wanneer?

Bridge (user-defined)

Host

Macvlan

Overlay


7. Handige inspect- en debugcommando’s

Docker-level

Netwerken en details:

docker network ls
docker network inspect bridge
docker network inspect appnet

Container netwerkinfo:

docker inspect web1 --format '{{json .NetworkSettings.Networks}}' | jq
docker exec -it web1 ip addr
docker exec -it web1 ip route

Snel IP ophalen:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web1

Container aan extra netwerk hangen:

docker network connect appnet webpub
docker network disconnect bridge webpub

Linux-level

Interfaces, bridges:

ip link
ip addr
bridge link
bridge vlan show

Routes en NAT:

ip route
sudo iptables -t nat -L -n -v
sudo iptables -t nat -S | grep DOCKER

Traffic capture:

sudo tcpdump -ni docker0
sudo tcpdump -ni br-$(docker network inspect -f '{{.Id}}' appnet | cut -c1-12)

Namespace debugging met nsenter:

PID=$(docker inspect -f '{{.State.Pid}}' web1)
sudo nsenter -t "$PID" -n ip addr
sudo nsenter -t "$PID" -n ip route
sudo nsenter -t "$PID" -n ss -lntup

Afsluiting

Docker networking is geen black box: het is een combinatie van Linux namespaces, virtuele interfaces, bridges, en (meestal) iptables-regels. Door bewust te kiezen tussen bridge, host, macvlan en overlay kun je je netwerkontwerp afstemmen op isolatie, performance, bereikbaarheid en schaal over meerdere hosts.

Als je wilt, kan ik op basis van jouw situatie (single host vs multi-host, LAN-subnet, security-eisen, Compose/Swarm) een concreet netwerkplan uitschrijven met exacte commando’s en een testmatrix (ping/curl/DNS) om te verifiëren dat alles correct werkt.