Ga naar hoofdinhoud

Hoe geef je een Docker-poort vrij

Leer hoe je in Docker poorten effectief kunt vrijgeven en publiceren, zodat je containers met de buitenwereld kunnen communiceren. Deze gids behandelt alles van Dockerfile-configuratie en runtime-flags tot Docker Compose-orkestratie en troubleshootingtechnieken.
· 11 min lezen

Verken met AI

Als je met Docker-containers werkt, is een van de belangrijkste aspecten het mogelijk maken van netwerkcommunicatie tussen containers en de buitenwereld. Zonder de juiste poortconfiguratie blijven gecontaineriseerde applicaties geïsoleerd en onbereikbaar. In dit artikel neem ik je mee door het proces van het vrijgeven van Docker-poorten, een basisvaardigheid voor iedereen die met gecontaineriseerde applicaties werkt.

Deze gids is speciaal bedoeld voor softwareontwikkelaars, DevOps-engineers en IT-professionals die hun gecontaineriseerde applicaties toegankelijk moeten maken voor gebruikers, andere services of externe systemen. Of je nu een webserver, een API of een database in een container inzet, inzicht in poortvrijgave is essentieel om functionele Docker-gebaseerde systemen te bouwen.

Aan het einde van dit artikel begrijp je helder hoe Docker-netwerken werken, de verschillende manieren om poorten vrij te geven, en praktische technieken om deze concepten in je eigen projecten toe te passen.

Ben je nieuw met Docker? Overweeg dan een van onze cursussen, zoals Introduction to Docker, Containerization and Virtualization with Docker and Kubernetes, Intermediate Docker of Containerization and Virtualization Concepts.

Wat betekent een poort vrijgeven in Docker?

Voordat we de technische details induiken, is het belangrijk te begrijpen wat poortvrijgave betekent in het Docker-ecosysteem.

Principes van netwerkisolatie voor containers

Docker-containers zijn ontworpen met isolatie als kernprincipe. Deze isolatie wordt bereikt via Linux-kernelfeatures zoals namespaces en cgroups. Namespaces zorgen voor procesisolatie, zodat processen binnen een container geen processen in andere containers of op het hostsysteem kunnen zien of ermee kunnen communiceren. Cgroups regelen daarentegen de toewijzing van resources en beperken hoeveel CPU, geheugen en andere resources een container kan gebruiken.

Vanuit netwerkoogpunt krijgt elke container een eigen netwerknamespace, inclusief een virtuele Ethernet-interface (veth-paar). Deze interface is standaard verbonden met een Docker-bridge netwerk, waardoor containers onderling kunnen communiceren terwijl ze geïsoleerd blijven van het hostnetwerk. Zie het als een eigen privé-netwerkadres per container, onzichtbaar voor de buitenwereld.

In de standaardconfiguratie is een Docker-container volledig gesandboxed. Services die binnenin draaien, kunnen met elkaar communiceren, maar zijn onbereikbaar van buiten de container, zelfs vanaf de hostmachine. Hier wordt poortvrijgave noodzakelijk.

Expose vs publish: semantisch onderscheid

Bij het configureren van Docker-poorten kom je twee verwante maar verschillende concepten tegen: poorten vrijgeven (expose) en publiceren (publish).

Poorten vrijgeven is in de eerste plaats een documentatiefunctie. Als je een poort in Docker vrijgeeft, voeg je in feite metadata toe aan je containerimage die aangeeft dat de gecontaineriseerde applicatie op specifieke poorten luistert. 

Het vrijgeven van een poort maakt deze echter niet daadwerkelijk toegankelijk van buiten de container. Het dient als documentatie voor gebruikers van je image.

Poorten publiceren is wat je services in containers daadwerkelijk beschikbaar maakt voor de buitenwereld. Publiceren maakt een mapping tussen een poort op de hostmachine en een poort in de container. Wanneer je een poort publiceert, configureert Docker het netwerk van de host om verkeer van de opgegeven hostpoort door te sturen naar de bijbehorende containerpoort.

Wanneer gebruik je welke aanpak?

  • Gebruik expose als je images bouwt die door andere Docker-gebruikers worden gebruikt, om te documenteren welke poorten je applicatie gebruikt.
  • Gebruik publish wanneer externe systemen (inclusief de host) toegang moeten hebben tot services die in je container draaien.
  • Gebruik beide samen voor volledige documentatie en functionaliteit, vooral in productieomgevingen.

Hoe geef je Docker-poorten vrij

Nu we de concepten begrijpen, bekijken we de praktische aspecten van het vrijgeven van Docker-poorten in verschillende contexten.

Declaratiestrategieën in Dockerfile

De meest basale manier om een poort vrij te geven is met de instructie EXPOSE in je Dockerfile. Hiermee declareer je welke poorten de container hoort te gebruiken.

FROM my-image:latest
EXPOSE 80
EXPOSE 443

In dit voorbeeld heb ik aangegeven dat de container de poorten 80 en 443 gebruikt, die standaard zijn voor respectievelijk HTTP (Hypertext Transfer Protocol) en HTTPS (Hypertext Transfer Protocol Secure) verkeer. Je kunt deze ook combineren in één instructie:

EXPOSE 80 443

Bij het opgeven van poorten is het goed om ook het protocol te vermelden, TCP (Transmission Control Protocol) of UDP (User Datagram Protocol), als je applicatie een specifiek protocol gebruikt:

EXPOSE 53/udp
EXPOSE 80/tcp

Als je geen protocol opgeeft, wordt standaard TCP aangenomen. Dit is geschikt voor de meeste webapplicaties, maar services zoals DNS (Domain Name System) of gameservers hebben vaak UDP nodig.

Vanuit beveiligingsperspectief raad ik aan alleen de poorten vrij te geven die je applicatie daadwerkelijk nodig heeft. Elke vrijgegeven poort vormt een potentieel aanvalsvlak, dus het minimaliseren van het aantal vrijgegeven poorten volgt het principe van least privilege.

Poortbeheer tijdens runtime

Hoewel de instructie EXPOSE documenteert welke poorten een container gebruikt, moet je ze publiceren wanneer je de container start om ze vanaf de host of andere machines toegankelijk te maken.

Zo bind je expliciet een containerpoort aan een specifieke hostpoort:

docker run -p 8081:80 my-image

Met de vlag -p (of --publish) kun je één poort of een reeks poorten in de container aan de host binden.

Deze opdracht koppelt poort 80 in de container aan poort 8081 op de host. Na het uitvoeren van deze opdracht kun je de webserver openen door in je browser naar http://localhost:8081 te gaan.

Voor gemak tijdens development biedt Docker de vlag -P (hoofdletter P) of --publish-all, die automatisch alle vrijgegeven poorten publiceert naar willekeurige hoge poorten op de host:

docker run -P my-image

Om te zien welke hostpoorten zijn toegewezen, kan ik de opdracht docker ps gebruiken:

docker ps

Dit toont output zoals:

CONTAINER ID   IMAGE  COMMAND    CREATED  STATUS  PORTS                                  NAMES
a7c53d9413bf   image  "/docker-.…"  10 s ago   Up 9 s    0.0.0.0:49153->80/tcp, :::49153->80/tcp   wizardl

Hier is poort 80 in de container gemapt naar poort 49153 op de host.

Bij services die zowel TCP als UDP op dezelfde poort gebruiken (zoals DNS-servers), moet je het protocol specificeren bij het publiceren:

docker run -p 53:53/tcp -p 53:53/udp dns-server

Docker Compose-orkestratie

Voor applicaties met meerdere containers biedt Docker Compose een beter beheersbare manier om netwerk en poorten te configureren.

In een Docker Compose-YAML-bestand kun je poortmappings opgeven onder de sleutel ports voor elke service:

services:
  web:
    image: my-image
    ports:
      - "8081:80"
      - "443:443"
  api:
    build: ./api
    ports:
      - "3000:3000"

Docker Compose maakt een belangrijk onderscheid tussen ports en expose. De sectie ports creëert gepubliceerde poortmappings die van buitenaf toegankelijk zijn, terwijl expose poorten alleen beschikbaar maakt voor gekoppelde services binnen hetzelfde Compose-netwerk:

services:
  web:
    image: my-image
    ports:
      - "8081:80"
  database:
    image: postgres
    expose:
      - "5432"

In dit voorbeeld is de service web toegankelijk vanaf de host op poort 8081, maar de PostgreSQL-database is alleen toegankelijk voor andere services binnen het Compose-bestand, niet rechtstreeks vanaf de host.

Voor flexibele configuraties, vooral over verschillende omgevingen heen, kan ik omgevingsvariabelen gebruiken in poortmappings:

services:
  web:
    image: my-image
    ports:
      - "${WEB_PORT:-8081}:80"

Met deze syntax kan ik de hostpoort opgeven via een omgevingsvariabele (WEB_PORT), met 8081 als standaard als deze niet is ingesteld.

Docker-poorten vrijgeven - Voorbeeld

Laten we een compleet voorbeeld doorlopen van het vrijgeven van Docker-poorten voor een webapplicatie met een database-backend.

Stel dat we een eenvoudige webapplicatie bouwen die bestaat uit een Python Flask API-service en een PostgreSQL-database. De API-service luistert op poort 5000, en PostgreSQL gebruikt de standaardpoort 5432.

Zo kan onze eenvoudige Flask-applicatie (app.py) eruitzien. Deze applicatie maakt een database myapp aan en haalt data op uit de tabel items, zodra deze tabel in de database is aangemaakt.

from flask import Flask, jsonify
import os
import psycopg2

app = Flask(__name__)

# Database connection parameters from environment variables
DB_HOST = os.environ.get('DB_HOST', 'db')
DB_NAME = os.environ.get('DB_NAME', 'myapp')
DB_USER = os.environ.get('DB_USER', 'postgres')
DB_PASS = os.environ.get('DB_PASSWORD', 'postgres')

@app.route('/')
def index():
    return jsonify({'message': 'API is running'})

@app.route('/items')
def get_items():
    # Connect to the PostgreSQL database
    conn = psycopg2.connect(
        host=DB_HOST,
        database=DB_NAME,
        user=DB_USER,
        password=DB_PASS
    )
    
    # Create a cursor and execute a query
    cur = conn.cursor()
    cur.execute('SELECT id, name FROM items')
    
    # Fetch results and format as list of dictionaries
    items = [{'id': row[0], 'name': row[1]} for row in cur.fetchall()]
    
    # Close connections
    cur.close()
    conn.close()
    
    return jsonify(items)

if __name__ == '__main__':
    # Run the Flask app, binding to all interfaces (important for Docker)
    app.run(host='0.0.0.0', port=5000)

Vervolgens maak ik ons bestand requirements.txt aan:

flask
psycopg2-binary

Nu maak ik een Dockerfile voor onze Python API-service:

FROM python:3.9-slim
WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose the port Flask runs on
EXPOSE 5000

# Command to run the application
CMD ["python", "app.py"]

Tot slot maak ik een Docker Compose-bestand om beide services te orkestreren:

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      tags:
        - "my-custom-image:latest"
    container_name: my-custom-api
    ports:
      - "5000:5000"
    environment:
      - DB_HOST=db
      - DB_NAME=myapp
      - DB_USER=postgres
      - DB_PASSWORD=postgres
    depends_on:
      - db
  
  db:
    container_name: my-custom-db
    image: postgres:13
    expose:
      - "5432"
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

In deze configuratie:

  1. De API-service wordt gebouwd vanuit onze Dockerfile en publiceert poort 5000, waardoor deze toegankelijk is vanaf de hostmachine.
  2. De PostgreSQL-service geeft poort 5432 vrij maar publiceert deze niet; daardoor is hij alleen toegankelijk voor andere services binnen het Compose-netwerk.
  3. De API-service kan de database benaderen via de hostnaam db (de servicenaam) en poort 5432.

Om deze applicatie te starten, gebruik je:

docker-compose up

Nu kan ik de API openen op http://localhost:5000, maar de PostgreSQL-instantie is niet direct toegankelijk van buiten het Docker-netwerk, wat een goede beveiligingspraktijk is voor databaseservices. Je kunt echter wel toegang krijgen tot PostgreSQL vanuit de draaiende container:

docker compose exec db psql -U postgres -d myapp

Deze opdracht opent de PostgreSQL-CLI, waar ik de database kan bekijken en een tabel items kan aanmaken. Zodra die is aangemaakt, kan ik de data bekijken op http://localhost:5000/items

Meerdere Docker-poorten vrijgeven

Als mijn Python-applicatie meerdere poorten moet vrijgeven, kan ik ze allemaal in de Dockerfile opgeven:

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000 8081 9090
CMD ["python", "app.py"]

Deze Dockerfile geeft vrij:

  • Poort 5000 voor de hoofdapplicatie in Flask (nu actief)
  • Poort 8081 voor een mogelijke monitoringdashboard 
  • Poort 9090 voor een toekomstige debuginterface

Belangrijk om te weten: hoewel ik poorten 8081 en 9090 als documentatie in de Dockerfile heb vrijgegeven, is mijn huidige Flask-applicatie alleen geconfigureerd om te luisteren op poort 5000. De extra vrijgegeven poorten geven aan waar toekomstige functionaliteit kan worden geïmplementeerd.

Hoe publiceer je vrijgegeven poorten

Om poorten te publiceren die in een Dockerfile zijn vrijgegeven, gebruik ik de vlag -p of -P bij het starten van de container:

docker run -p 8081:5000  my-custom-image

Dit mappt poort 5000 in de container (die in de Dockerfile is vrijgegeven en waar Flask luistert) naar poort 8081 op de host. Na het uitvoeren van deze opdracht kan ik mijn Flask-applicatie openen door in mijn browser naar http://localhost:8081 te gaan.

Ik kan ook de vlag -P gebruiken om alle vrijgegeven poorten automatisch te publiceren naar willekeurige poorten op de host:

docker run -P my-custom-image

Om te controleren welke poorten zijn gepubliceerd, kan ik gebruiken:

docker ps

Voor meer details kan ik gebruiken:

docker port [container_id]
5000/tcp -> 0.0.0.0:32768
8081/tcp -> 0.0.0.0:32769
9090/tcp -> 0.0.0.0:32770

Deze opdracht toont alle poortmappings voor een specifieke container. Als mijn Flask-applicatie bijvoorbeeld alleen luistert op poort 5000 maar ik meerdere poorten in de Dockerfile heb vrijgegeven, laat docker port me precies zien welke hostpoorten naar welke containerpoorten zijn gemapt. Dus als poort 5000 is gemapt naar 32768, kan ik mijn Flask-applicatie openen via http://localhost:32768

Diagnose- en troubleshootingtechnieken

Zelfs met zorgvuldige configuratie kunnen er problemen ontstaan met Docker-poortmappings. Dit zijn enkele technieken die ik gebruik om veelvoorkomende issues te diagnosticeren en op te lossen.

Inspectie van poortmappings

De eerste stap bij het diagnosticeren van poortgerelateerde problemen is verifiëren dat de mappings correct zijn ingesteld. Hiervoor gebruik ik deze opdrachten:

Lijst alle draaiende containers met poortmappings:

docker ps

Gedetailleerde info over een specifieke container:

docker inspect [container_id]

Controleer poortmappings voor een specifieke container:

docker port [container_id]

De opdracht docker inspect geeft gedetailleerde informatie, waaronder netwerkinstellingen. Om te focussen op netwerkdetails, gebruik je:

docker inspect --format='{{json .NetworkSettings.Ports}}' [container_id] | jq

Als je diepgaandere verkeersanalyse moet uitvoeren, zijn tools zoals tcpdump en netstat erg handig. Zorg eerst dat ze in de container zijn geïnstalleerd. Als de container deze tools nog niet bevat, kun je ze installeren met de volgende opdracht:

docker exec -u root -it f5c6cac71492 bash -c "apt-get update && apt-get install -y net-tools tcpdump"

Om te zien op welke poorten de applicatie binnen de container luistert:

docker exec -it [container_id] netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.11:42265        0.0.0.0:*               LISTEN
udp        0      0 127.0.0.11:34267        0.0.0.0:*

Dit laat bijvoorbeeld zien dat de Flask-app luistert op alle interfaces op poort 5000.

Om inkomend en uitgaand verkeer op de hoofdnetwerkinterface van de container (meestal eth0) te monitoren:

docker exec -it [container_id] tcpdump -i eth0
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

Met deze opdracht kun je verkeer traceren en vaststellen of verzoeken de container bereiken of dat pakketten worden gedropt of verkeerd gerouteerd.

Analyse van iptables-regels

Docker gebruikt iptables om Network Address Translation (NAT) te beheren en de verkeersstroom tussen host en containers te regelen. Het voegt automatisch regels toe om hostpoorten door te sturen naar de juiste container-IP’s en -poorten, zodat je naadloos toegang hebt tot gecontaineriseerde services.

Op native Linux-hosts kun je deze regels inspecteren met opdrachten zoals:

sudo iptables -t nat -L DOCKER -n -v

Dit laat zien hoe Docker inkomend verkeer op specifieke hostpoorten naar containerendpoints mappt. Op basis van het eerdere Docker Compose-bestand zie je de doorgestuurde poorten:

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
   50  3000 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
  100  6000 RETURN     all  --  br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0
  500 30000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:5000 to:172.18.0.2:5000
  400 24000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.18.0.2:5000
  300 18000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:9090 to:172.18.0.2:5000

Hierbij:

  • DNAT-regels leiden verkeer van de host om naar de container.
  • RETURN-regels zorgen voor correcte routering van intern Docker-netwerkverkeer.

Afhankelijk van je omgeving (bijvoorbeeld Docker Desktop op Windows of WSL2) kan Docker poortforwarding anders afhandelen, en zijn iptables-regels mogelijk niet zichtbaar of aanpasbaar binnen het systeem. In dat geval kun je portforwarding controleren met de volgende opdracht:

sudo ss -tulnp
Netid    State       Recv-Q      Send-Q            Local Address:Port         Peer Address:Port 
tcp        LISTEN     0                 4096                                          *:5000           	        *:*           
tcp        LISTEN     0                 4096                          		   *:8081                               *:*    
tcp        LISTEN     0                 4096                          		   *:9090                              *:*    

Tips voor troubleshooting:

  • Bevestig poortmappings met docker ps en docker port [container].
  • Controleer of de firewall of beveiligingssoftware op de host poorten blokkeert.
  • Gebruik containerlogs en netwerktools zoals netstat en tcpdump om het netwerkgedrag van je applicatie te verifiëren.

Conclusie

Poorten vrijgeven in Docker is een basisvaardigheid die de kloof overbrugt tussen containerisolatie en praktische bruikbaarheid. In dit artikel heb ik uitgelegd hoe het netwerkmodel van Docker werkt, het verschil tussen poorten vrijgeven en publiceren, en praktische voorbeelden gegeven voor verschillende scenario’s.

Onthoud de volgende kernpunten:

  • Gebruik EXPOSE in Dockerfiles om te documenteren welke poorten je applicatie gebruikt
  • Gebruik -p of -P bij het draaien van containers om die poorten van buitenaf toegankelijk te maken
  • Zet Docker Compose in voor het beheren van complexe applicaties met meerdere containers
  • Gebruik diagnostische tools om problemen op te sporen wanneer ze zich voordoen

Als je deze concepten en technieken beheerst, kun je robuustere gecontaineriseerde applicaties ontwerpen die zowel intern als met de buitenwereld effectief communiceren. Of je nu een eenvoudige webapplicatie of een complexe microservicesarchitectuur ontwikkelt, goed poortbeheer is cruciaal voor succes.

Nu containers een dominante rol blijven spelen in moderne deploymentstrategieën, blijft het vaardig beheren van Docker-netwerken en poorten een essentiële skill in de toolkit van elke developer.

Wil je blijven leren? Bekijk dan zeker de volgende resources:

Exposing a Docker Port FAQs

Wat betekent het om een poort in Docker vrij te geven?

Het vrijgeven van een poort in Docker is een manier om te documenteren op welke poorten je gecontaineriseerde applicatie luistert, maar het maakt de poort niet toegankelijk buiten de container.

Hoe maak ik de poort van een Docker-container toegankelijk vanaf mijn hostmachine?

Je publiceert een poort met de vlag -p bij docker run of via de sectie ports in Docker Compose, waarmee je een hostpoort aan de containerpoort koppelt.

Wat is het verschil tussen `EXPOSE` en `-p` in Docker?

EXPOSE wordt in de Dockerfile gebruikt om poorten te declareren voor documentatie, terwijl -p die poorten publiceert en mappt voor externe toegang.

Kan ik meerdere poorten vrijgeven voor één Docker-container?

Ja, je kunt meerdere poorten vrijgeven met meerdere EXPOSE-instructies in de Dockerfile of door meerdere poorten op te geven in de sectie ports van Docker Compose.

Hoe los ik problemen met Docker-poortmapping op?

Gebruik opdrachten zoals docker ps, docker port, docker inspect en netwerktools in de container (bijv. netstat, tcpdump) om poortmappings en verkeersstroom te verifiëren.

Benito Martin

Auteur

Benito Martin

Als oprichter van Martin Data Solutions en freelance data scientist, ML- en AI-engineer heb ik een divers portfolio in regressie, classificatie, NLP, LLM, RAG, neurale netwerken, ensemblemethoden en computer vision.

  • Met succes meerdere end-to-end ML-projecten ontwikkeld, inclusief datacleaning, analytics, modellering en deployment op AWS en GCP, met impactvolle en schaalbare oplossingen als resultaat.
  • Interactieve en schaalbare webapplicaties gebouwd met Streamlit en Gradio voor uiteenlopende usecases in de industrie.
  • Studenten lesgegeven en gecoacht in data science en analytics, en hun professionele groei gestimuleerd met gepersonaliseerde leertrajecten.
  • Cursusinhoud ontworpen voor retrieval-augmented generation (RAG)-toepassingen, afgestemd op enterprise-vereisten.
  • Technische blogs met hoge impact geschreven over AI & ML, met onderwerpen als MLOps, vectordatabases en LLM’s, die veel betrokkenheid opleverden.

In elk project dat ik aanpak, pas ik actuele praktijken uit software-engineering en DevOps toe, zoals CI/CD, codelinting, formattering, modelmonitoring, experimenttracking en robuuste foutafhandeling. Ik zet me in om complete oplossingen te leveren en data-inzichten te vertalen naar praktische strategieën die bedrijven helpen groeien en het maximale halen uit data science, machine learning en AI.

Onderwerpen

Gerelateerd