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.
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.
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.
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:
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:
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:
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:
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 wizardlMogelijk gemaakt door
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:
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"Mogelijk gemaakt door
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"Mogelijk gemaakt door
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:
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('/')defindex():return jsonify({'message':'API is running'})@app.route('/items')defget_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)Mogelijk gemaakt door
Vervolgens maak ik ons bestand requirements.txt aan:
Nu maak ik een Dockerfile voor onze Python API-service:
FROM python:3.9-slimWORKDIR /app# Install dependenciesCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt# Copy application codeCOPY . .# Expose the port Flask runs onEXPOSE 5000# Command to run the applicationCMD ["python", "app.py"]Mogelijk gemaakt door
Tot slot maak ik een Docker Compose-bestand om beide services te orkestreren:
De API-service wordt gebouwd vanuit onze Dockerfile en publiceert poort 5000, waardoor deze toegankelijk is vanaf de hostmachine.
De PostgreSQL-service geeft poort 5432 vrij maar publiceert deze niet; daardoor is hij alleen toegankelijk voor andere services binnen het Compose-netwerk.
De API-service kan de database benaderen via de hostnaam db (de servicenaam) en poort 5432.
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:
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-slimWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .EXPOSE 5000 8081 9090CMD ["python", "app.py"]Mogelijk gemaakt door
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:
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:
5000/tcp ->0.0.0.0:32768
8081/tcp ->0.0.0.0:32769
9090/tcp ->0.0.0.0:32770Mogelijk gemaakt door
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:
De opdracht docker inspect geeft gedetailleerde informatie, waaronder netwerkinstellingen. Om te focussen op netwerkdetails, gebruik je:
docker inspect --format='{{json .NetworkSettings.Ports}}'[container_id]| jqMogelijk gemaakt door
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:
dockerexec-u root -it f5c6cac71492 bash-c"apt-get update && apt-get install -y net-tools tcpdump"Mogelijk gemaakt door
Om te zien op welke poorten de applicatie binnen de container luistert:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 000.0.0.0:5000 0.0.0.0:* LISTEN
tcp 00127.0.0.11:42265 0.0.0.0:* LISTEN
udp 00127.0.0.11:34267 0.0.0.0:*Mogelijk gemaakt door
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:
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytesMogelijk gemaakt door
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:
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:
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:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 04096 *:5000 *:*
tcp LISTEN 04096 *:8081 *:*
tcp LISTEN 04096 *:9090 *:* Mogelijk gemaakt door
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:
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.
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.
Duik diep in geavanceerde vaardigheden en de nieuwste tools die de wereld van data-engineering nu op z'n kop zetten met ons Professional Data Engineer-traject.
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?
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
EXPOSEin je Dockerfile. Hiermee declareer je welke poorten de container hoort te gebruiken.In dit voorbeeld heb ik aangegeven dat de container de poorten
80en443gebruikt, die standaard zijn voor respectievelijk HTTP (Hypertext Transfer Protocol) en HTTPS (Hypertext Transfer Protocol Secure) verkeer. Je kunt deze ook combineren in één instructie: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:
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
EXPOSEdocumenteert 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:
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:8081te 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:Om te zien welke hostpoorten zijn toegewezen, kan ik de opdracht
docker psgebruiken:Dit toont output zoals:
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 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
portsvoor elke service:Docker Compose maakt een belangrijk onderscheid tussen
portsenexpose. De sectieportscreëert gepubliceerde poortmappings die van buitenaf toegankelijk zijn, terwijlexposepoorten alleen beschikbaar maakt voor gekoppelde services binnen hetzelfde Compose-netwerk:In dit voorbeeld is de service
webtoegankelijk 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:
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 standaardpoort5432.Zo kan onze eenvoudige Flask-applicatie (
app.py) eruitzien. Deze applicatie maakt een databasemyappaan en haalt data op uit de tabelitems, zodra deze tabel in de database is aangemaakt.Vervolgens maak ik ons bestand
requirements.txtaan:Nu maak ik een Dockerfile voor onze Python API-service:
Tot slot maak ik een Docker Compose-bestand om beide services te orkestreren:
In deze configuratie:
5000, waardoor deze toegankelijk is vanaf de hostmachine.5432vrij maar publiceert deze niet; daardoor is hij alleen toegankelijk voor andere services binnen het Compose-netwerk.5432.Om deze applicatie te starten, gebruik je:
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:Deze opdracht opent de PostgreSQL-CLI, waar ik de database kan bekijken en een tabel
itemskan aanmaken. Zodra die is aangemaakt, kan ik de data bekijken ophttp://localhost:5000/itemsMeerdere Docker-poorten vrijgeven
Als mijn Python-applicatie meerdere poorten moet vrijgeven, kan ik ze allemaal in de Dockerfile opgeven:
Deze Dockerfile geeft vrij:
5000voor de hoofdapplicatie in Flask (nu actief)8081voor een mogelijke monitoringdashboard9090voor een toekomstige debuginterfaceBelangrijk om te weten: hoewel ik poorten
8081en9090als documentatie in de Dockerfile heb vrijgegeven, is mijn huidige Flask-applicatie alleen geconfigureerd om te luisteren op poort5000. 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
-pof-Pbij het starten van de container:Dit mappt poort
5000in de container (die in de Dockerfile is vrijgegeven en waar Flask luistert) naar poort8081op de host. Na het uitvoeren van deze opdracht kan ik mijn Flask-applicatie openen door in mijn browser naarhttp://localhost:8081te gaan.Ik kan ook de vlag -P gebruiken om alle vrijgegeven poorten automatisch te publiceren naar willekeurige poorten op de host:
Om te controleren welke poorten zijn gepubliceerd, kan ik gebruiken:
Voor meer details kan ik gebruiken:
Deze opdracht toont alle poortmappings voor een specifieke container. Als mijn Flask-applicatie bijvoorbeeld alleen luistert op poort
5000maar ik meerdere poorten in de Dockerfile heb vrijgegeven, laat docker port me precies zien welke hostpoorten naar welke containerpoorten zijn gemapt. Dus als poort5000is gemapt naar 32768, kan ik mijn Flask-applicatie openen viahttp://localhost:32768Diagnose- 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:
Gedetailleerde info over een specifieke container:
Controleer poortmappings voor een specifieke container:
De opdracht docker inspect geeft gedetailleerde informatie, waaronder netwerkinstellingen. Om te focussen op netwerkdetails, gebruik je:
Als je diepgaandere verkeersanalyse moet uitvoeren, zijn tools zoals
tcpdumpennetstaterg 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:Om te zien op welke poorten de applicatie binnen de container luistert:
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:
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
iptablesom 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:
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:
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:Tips voor troubleshooting:
docker psendocker port [container].netstatentcpdumpom 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:
EXPOSEin Dockerfiles om te documenteren welke poorten je applicatie gebruikt-pof-Pbij het draaien van containers om die poorten van buitenaf toegankelijk te makenAls 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: