Netwerken in Docker Compose: services laten samenwerken in productie

Hoe configureer je Docker Compose networking correct voor productie? Custom networks, DNS resolution, isolatie en troubleshooting.

Jean-Pierre Broeders

Freelance DevOps Engineer

12 maart 20266 min. leestijd

Netwerken in Docker Compose: services laten samenwerken in productie

Twee containers die niet met elkaar kunnen praten. Het klinkt als een simpel probleem, maar het komt verrassend vaak voor. Meestal omdat het standaard network van Docker Compose net even anders werkt dan verwacht.

Het default network

Docker Compose maakt automatisch een bridge network aan voor elke stack. Alle services in dezelfde docker-compose.yml belanden op dat network en kunnen elkaar bereiken via hun service naam. Dus als er een api en een postgres service bestaan, dan werkt postgres://postgres:5432 vanuit de api-container gewoon. Geen IP-adressen nodig.

Dat klinkt mooi. En voor development is het prima. Maar in productie zitten er een paar addertjes onder het gras.

# Simpele setup - alles op één network
services:
  api:
    image: myapp/api:latest
    ports:
      - "8080:8080"
  
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
  
  redis:
    image: redis:7-alpine

Het probleem: alle services kunnen met alle andere services praten. De Redis cache kan de database bereiken. De database kan de API aanspreken. Er is geen enkele isolatie.

Custom networks voor isolatie

De oplossing is simpel maar wordt vaak overgeslagen: splits het verkeer op in logische networks.

services:
  nginx:
    image: nginx:alpine
    ports:
      - "443:443"
    networks:
      - frontend

  api:
    image: myapp/api:latest
    networks:
      - frontend
      - backend

  worker:
    image: myapp/worker:latest
    networks:
      - backend

  postgres:
    image: postgres:16
    networks:
      - backend

  redis:
    image: redis:7-alpine
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true

Wat gebeurt hier? Nginx zit alleen op het frontend network en kan dus niet rechtstreeks bij de database. De API zit op beide networks — die vormt de brug. En het backend network heeft internal: true, wat betekent dat containers op dat network geen uitgaand internetverkeer hebben. Postgres kan nergens naartoe bellen. Precies wat je wilt.

DNS resolution en aliassen

Een handige feature die weinig wordt gebruikt: network aliases. Hiermee kan een service meerdere namen hebben, afhankelijk van het network.

services:
  api:
    image: myapp/api:latest
    networks:
      frontend:
        aliases:
          - app-backend
      backend:
        aliases:
          - data-consumer

Vanuit nginx is de API bereikbaar als api én als app-backend. Vanuit postgres als api én als data-consumer. Klinkt als overkill, maar het wordt handig bij migraties. Een oude service verwacht hostname legacy-api? Voeg een alias toe en de oude configuratie blijft werken zonder aanpassingen.

Wanneer DNS resolution hapert

Docker's ingebouwde DNS werkt goed, maar er zijn valkuilen. De meest voorkomende: een container start sneller op dan de service waar hij van afhankelijk is.

services:
  api:
    image: myapp/api:latest
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - backend

  postgres:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - backend

depends_on met een health check condition voorkomt dat de API start voordat Postgres daadwerkelijk verbindingen accepteert. Zonder die condition wacht Docker alleen tot de container draait — niet tot de service klaar is. Groot verschil.

Een andere DNS-gerelateerde valkuil: caching. Docker cached DNS responses niet agressief, maar applicaties soms wel. Java-applicaties zijn hier berucht om. De JVM cached DNS lookups standaard voor altijd (of heel lang). Als een container opnieuw start en een ander IP krijgt, blijft de Java-app het oude adres gebruiken.

De fix zit in de JVM configuratie:

-Dsun.net.inetaddr.ttl=30
-Dsun.net.inetaddr.negative.ttl=10

Of in java.security:

networkaddress.cache.ttl=30
networkaddress.cache.negative.ttl=10

Communicatie tussen Compose stacks

Soms draaien services in aparte docker-compose.yml bestanden. Een monitoring stack apart van de applicatie stack, bijvoorbeeld. Die moeten wel met elkaar kunnen praten.

De aanpak: een extern network dat beide stacks delen.

# In de applicatie stack
networks:
  shared:
    name: monitoring-bridge
    external: true
  backend:
    driver: bridge
# In de monitoring stack
networks:
  shared:
    name: monitoring-bridge
    driver: bridge

De monitoring stack maakt het network aan. De applicatie stack gebruikt het via external: true. Services op het gedeelde network vinden elkaar via DNS, ongeacht in welke Compose file ze staan.

Let op: het network moet bestaan voordat de applicatie stack start. Anders faalt docker compose up met een foutmelding over een onbekend network. Start dus altijd de stack die het network aanmaakt als eerste.

Troubleshooting

Wanneer containers niet met elkaar praten, is systematisch checken de snelste weg naar een oplossing.

# Bekijk welke networks bestaan
docker network ls

# Inspecteer een specifiek network
docker network inspect backend

# Check vanuit een container of DNS werkt
docker exec -it api nslookup postgres

# Test connectiviteit
docker exec -it api nc -zv postgres 5432
SymptoomMogelijke oorzaakOplossing
Connection refusedService luistert op localhost i.p.v. 0.0.0.0Bind op 0.0.0.0 in de applicatie config
Name resolution failedContainers op verschillende networksZet ze op een gedeeld network
Intermitterende timeoutsDNS caching in de applicatieTTL verlagen of DNS cache uitzetten
Kan externe services niet bereikenNetwork staat op internal: trueGebruik een apart network voor uitgaand verkeer

Afsluitend

Networking in Docker Compose hoeft niet complex te zijn. Splits verkeer op met custom networks, gebruik internal: true waar het kan, en test connectiviteit voordat het in productie problemen oplevert. Het kost vijf minuten extra bij het opzetten, maar bespaart uren debugging op een vrijdagavond.

Wil je op de hoogte blijven?

Schrijf je in voor mijn nieuwsbrief of neem contact op voor freelance projecten.

Neem Contact Op