Lerne, wie du Ports in Docker effektiv freigeben und veröffentlichen kannst, um die Kommunikation zwischen deinen Containern und der Außenwelt zu ermöglichen. Dieser Leitfaden deckt alles ab, von der Konfiguration von Dockerdateien und Laufzeitflags bis hin zur Orchestrierung von Docker Compose und Techniken zur Fehlerbehebung.
Bei der Arbeit mit Docker-Containern ist einer der wichtigsten Aspekte, auf den ich gestoßen bin, die Netzwerkkommunikation zwischen Containern und der Außenwelt. Ohne die richtige Portkonfiguration bleiben containerisierte Anwendungen isoliert und unzugänglich. In diesem Artikel zeige ich dir, wie du Docker-Ports freischaltest - eine grundlegende Fähigkeit für alle, die mit containerisierten Anwendungen arbeiten.
Dieser Leitfaden richtet sich an Softwareentwickler, DevOps-Ingenieure und IT-Experten, die ihre containerisierten Anwendungen für Nutzer, andere Dienste oder externe Systeme zugänglich machen müssen. Egal, ob du einen Webserver, eine API oder eine Datenbank in einem Container bereitstellst, das Verständnis der Portfreigabe ist für den Aufbau funktionaler Docker-basierter Systeme unerlässlich.
Am Ende dieses Artikels wirst du ein klares Verständnis davon haben, wie das Docker-Netzwerk funktioniert, die verschiedenen Methoden zur Freigabe von Ports und praktische Techniken, um diese Konzepte in deinen eigenen Projekten umzusetzen.
Bevor du in die technischen Details eintauchst, ist es wichtig zu verstehen, was Port Exposure im Docker-Ökosystem bedeutet.
Grundsätze der Isolierung von Containernetzwerken
Bei der Entwicklung von Docker-Containern ist die Isolation ein zentrales Prinzip. Diese Isolierung wird durch Linux-Kernel-Funktionen wie Namespaces und cgroups erreicht. Namensräume sorgen für eine Prozessisolierung und stellen sicher, dass Prozesse innerhalb eines Containers keine Prozesse in anderen Containern oder im Hostsystem sehen oder mit ihnen interagieren können. Cgroups hingegen kontrollieren die Ressourcenzuweisung und begrenzen, wie viel CPU, Speicher und andere Ressourcen ein Container verbrauchen kann.
Aus der Netzwerkperspektive erhält jeder Container seinen eigenen Netzwerk-Namensraum, komplett mit einer virtuellen Ethernet-Schnittstelle (Veth-Paar). Diese Schnittstelle verbindet sich standardmäßig mit einem Docker-Bridge-Netzwerk, das die Kommunikation zwischen den Containern ermöglicht und gleichzeitig vom Host-Netzwerk isoliert ist. Stell dir das so vor, dass jeder Container seine eigene private Netzwerkadresse hat, die für die Außenwelt unsichtbar ist.
In der Standardkonfiguration ist ein Docker-Container vollständig in einer Sandbox untergebracht. Dienste, die innerhalb des Containers laufen, können miteinander kommunizieren, sind aber von außerhalb des Containers nicht erreichbar, auch nicht vom Host-Rechner aus. Das ist der Punkt, an dem die Hafenexposition notwendig wird.
Expose vs. Publish: semantische Unterscheidung
Bei der Arbeit mit der Docker-Port-Konfiguration wirst du auf zwei verwandte, aber unterschiedliche Konzepte stoßen: das Freigeben und Veröffentlichen von Ports.
Die Offenlegung der Ports ist in erster Linie eine Dokumentationsfunktion. Wenn du einen Port in Docker freigibst, fügst du deinem Container-Image im Wesentlichen Metadaten hinzu, die angeben, dass die containerisierte Anwendung auf bestimmten Ports lauscht.
Die Freigabe eines Ports bedeutet jedoch nicht, dass er von außerhalb des Containers zugänglich ist. Sie dient als Dokumentation für die Nutzer deines Bildes.
Die Veröffentlichung von Ports macht deine containerisierten Dienste für die Außenwelt verfügbar. Die Veröffentlichung erstellt eine Zuordnung zwischen einem Port auf dem Host-Rechner und einem Port im Container. Wenn du einen Port veröffentlichst, konfiguriert Docker das Netzwerk des Hosts so, dass der Datenverkehr vom angegebenen Host-Port an den entsprechenden Container-Port weitergeleitet wird.
Hier erfährst du, wann du welche Methode anwenden solltest:
verwenden. expose wenn du Images erstellst, die von anderen Docker-Nutzern verwendet werden sollen, um zu dokumentieren, welche Ports deine Anwendung verwendet.
Verwende veröffentlichen wenn du möchtest, dass externe Systeme (einschließlich des Hosts) auf Dienste zugreifen können, die in deinem Container laufen.
Verwende beide zusammen für eine vollständige Dokumentation und Funktionalität, besonders in Produktionsumgebungen.
Wie man Docker Ports freilegt
Nachdem wir nun die Konzepte verstanden haben, wollen wir uns die praktischen Aspekte der Freigabe von Docker-Ports in verschiedenen Kontexten ansehen.
Strategien für Dockerfile-Deklarationen
Die einfachste Art, einen Port freizugeben, ist die Anweisung EXPOSE in deinem Dockerfile. Hier werden die Ports angegeben, die der Container verwenden soll.
In diesem Beispiel habe ich angegeben, dass der Container die Ports 80 und 443 verwenden soll, die standardmäßig für HTTP- (Hypertext Transfer Protocol) und HTTPS- (Hypertext Transfer Protocol Secure) Datenverkehr verwendet werden. Du kannst sie auch zu einer einzigen Anweisung kombinieren:
Wenn du Ports angibst, solltest du auch das Protokoll angeben: TCP (Transmission Control Protocol) oder UDP (User Datagram Protocol), wenn deine Anwendung ein bestimmtes Protokoll verwendet:
Wenn kein Protokoll angegeben wird, wird standardmäßig TCP angenommen. Dies ist für die meisten Webanwendungen geeignet, aber Dienste wie DNS (Domain Name System) oder Spieleserver benötigen oft UDP.
Aus der Sicherheitsperspektive empfehle ich, nur die Ports freizugeben, die deine Anwendung tatsächlich benötigt. Jeder freiliegende Port stellt einen potenziellen Angriffsvektor dar, daher folgt die Minimierung der Anzahl der freiliegenden Ports dem Prinzip der geringsten Privilegien.
Verwaltung der Runtime Ports
Während die Anweisung EXPOSE dokumentiert, welche Ports ein Container verwendet, musst du diese Ports beim Ausführen des Containers veröffentlichen, um sie für den Host oder andere Maschinen zugänglich zu machen.
Hier erfährst du, wie du einen Container-Port explizit an einen bestimmten Host-Port binden kannst:
Mit dem -p (oder --publish) Flag kannst du einen einzelnen Port oder einen Bereich von Ports im Container an den Host binden.
Dieser Befehl ordnet Port 80 innerhalb des Containers dem Port 8081 auf dem Host zu. Nachdem du diesen Befehl ausgeführt hast, kannst du auf den Webserver zugreifen, indem du in deinem Browser zu http://localhost:8081 navigierst.
Um die Entwicklung zu vereinfachen, bietet Docker das -P, capital P oder --publish-all Flag, das automatisch alle exponierten Ports auf zufälligen, hoch nummerierten Ports des Hosts veröffentlicht:
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 wizardlBereitgestellt von
Hier wird Port 80 innerhalb des Containers auf Port 49153 auf dem Host abgebildet.
Wenn du mit Diensten arbeitest, die sowohl TCP als auch UDP auf demselben Port verwenden (wie DNS-Server), musst du bei der Veröffentlichung das Protokoll angeben:
Für Anwendungen mit mehreren Containern bietet Docker Compose eine einfachere Möglichkeit, Netzwerke und Ports zu konfigurieren.
In einer Docker Compose YAML-Datei kannst du für jeden Dienst Port-Zuordnungen unter dem Schlüssel ports angeben:
services:web:image: my-image
ports:-"8081:80"-"443:443"api:build: ./api
ports:-"3000:3000"Bereitgestellt von
Docker Compose macht einen wichtigen Unterschied zwischen ports und expose. Der Abschnitt ports erstellt veröffentlichte Port-Zuordnungen, die von außen zugänglich sind, während expose die Ports nur für verknüpfte Dienste innerhalb desselben Compose-Netzwerks verfügbar macht:
services:web:image: my-image
ports:-"8081:80"database:image: postgres
expose:-"5432"Bereitgestellt von
In diesem Beispiel ist der Dienst web vom Host über Port 8081 erreichbar, aber die PostgreSQL-Datenbank ist nur für andere Dienste innerhalb der Compose-Datei zugänglich, nicht direkt vom Host.
Für flexible Konfigurationen, insbesondere in verschiedenen Umgebungen, kann ich Umgebungsvariablen in den Port-Zuordnungen verwenden:
services:web:image: my-image
ports:-"${WEB_PORT:-8081}:80"Bereitgestellt von
Mit dieser Syntax kann ich den Host-Port über eine Umgebungsvariable (WEB_PORT) angeben, die standardmäßig auf 8081 gesetzt wird, wenn sie nicht gesetzt ist.
Docker Ports freigeben - Praktisches Beispiel
Lass uns ein komplettes Beispiel für die Freigabe von Docker-Ports für eine Webanwendung mit einem Datenbank-Backend durchgehen.
Stell dir vor, wir bauen eine einfache Webanwendung, die aus einem Python Flask API Service und einer PostgreSQL Datenbank besteht. Der API-Dienst lauscht auf Port 5000, und PostgreSQL verwendet seinen Standardport 5432.
So könnte unsere einfache Flask-Anwendung (app.py) aussehen. Diese Anwendung erstellt eine Datenbank myapp und holt die Daten aus der Tabelle items, sobald diese Tabelle in der Datenbank erstellt ist.
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)Bereitgestellt von
Als Nächstes werde ich unsere requirements.txt Datei erstellen:
Jetzt muss ich eine Dockerdatei für unseren Python-API-Dienst erstellen:
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"]Bereitgestellt von
Zum Schluss werde ich eine Docker Compose-Datei erstellen, um beide Dienste zu orchestrieren:
Der API-Dienst wird aus unserem Dockerfile erstellt und über den Port 5000 veröffentlicht, sodass er vom Host-Rechner aus zugänglich ist.
Der PostgreSQL-Dienst stellt den Port 5432 zur Verfügung, veröffentlicht ihn aber nicht, so dass er nur für andere Dienste innerhalb des Compose-Netzwerks zugänglich ist.
Der API-Dienst kann auf die Datenbank mit dem Hostnamen db (das ist der Name des Dienstes) und dem Port 5432 zugreifen.
Jetzt kann ich auf die API unter http://localhost:5000 zugreifen, aber die PostgreSQL-Instanz ist nicht direkt von außerhalb des Docker-Netzwerks zugänglich, was eine gute Sicherheitspraxis für Datenbankdienste ist. Du kannst aber aus dem laufenden Container auf PostgreSQL zugreifen:
Mit diesem Befehl rufe ich das PostgreSQL CLI auf, wo ich die Datenbank einsehen und eine Tabelle items erstellen kann. Einmal erstellt, kann ich die Daten in http://localhost:5000/items
Wie man mehrere Docker Ports freigibt
Wenn meine Python-Anwendung mehrere Ports zur Verfügung stellen muss, kann ich sie alle in der Dockerdatei angeben:
FROM python:3.9-slimWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .EXPOSE 5000 8081 9090CMD ["python", "app.py"]Bereitgestellt von
Dieses Dockerfile zeigt an:
Port 5000 für die Hauptanwendung von Flask (derzeit aktiv)
Port 8081 für ein mögliches Monitoring-Dashboard
Port 9090 für eine zukünftige Debugging-Schnittstelle
Es ist wichtig zu beachten, dass ich zwar die Ports 8081 und 9090 in der Dockerdatei als Dokumentation freigegeben habe, meine aktuelle Flask-Anwendung aber nur so konfiguriert ist, dass sie auf Port 5000 lauscht. Die zusätzlichen offenen Ports zeigen, wo zukünftige Funktionen implementiert werden könnten.
Wie man offene Ports veröffentlicht
Um Ports, die in einem Dockerfile offengelegt sind, zu veröffentlichen, verwende ich das -p oder -P Flag, wenn ich den Container starte:
Dadurch wird der Port 5000 im Container (der im Dockerfile angegeben ist und auf dem Flask lauscht) dem Port 8081 auf dem Host zugeordnet. Nachdem ich diesen Befehl ausgeführt habe, kann ich auf meine Flask-Anwendung zugreifen, indem ich in meinem Browser zu http://localhost:8081 navigiere.
Ich kann auch das -P Flag verwenden, um automatisch alle exponierten Ports auf zufälligen Ports auf dem Host zu veröffentlichen:
5000/tcp ->0.0.0.0:32768
8081/tcp ->0.0.0.0:32769
9090/tcp ->0.0.0.0:32770Bereitgestellt von
Dieser Befehl zeigt alle Port-Zuordnungen für einen bestimmten Container an. Wenn meine Flask-Anwendung zum Beispiel nur auf Port 5000 lauscht, ich aber mehrere Ports in der Dockerdatei freigegeben habe, zeigt mir Docker port genau, welche Host-Ports welchen Container-Ports zugeordnet sind. Wenn also Port 5000 auf 32768 gemappt wurde, kann ich auf meine Flask-Anwendung unter http://localhost:32768
Diagnose- und Fehlersuchtechniken
Auch bei sorgfältiger Konfiguration können Probleme mit der Docker-Port-Zuordnung auftreten. Hier sind einige Techniken, die ich verwende, um häufige Probleme zu diagnostizieren und zu lösen.
Überprüfung der Hafenkartierung
Der erste Schritt bei der Diagnose von Port-Problemen besteht darin, zu überprüfen, ob die Zuordnungen richtig eingerichtet sind. Ich benutze diese Befehle:
Listet alle laufenden Container mit Port-Zuordnungen auf:
Der Befehl docker inspect liefert detaillierte Informationen, einschließlich der Netzwerkeinstellungen. Um dich auf netzwerkbezogene Details zu konzentrieren, verwende:
docker inspect --format='{{json .NetworkSettings.Ports}}'[container_id]| jqBereitgestellt von
Wenn du den Datenverkehr genauer analysieren willst, können Tools wie tcpdump und netstat sehr nützlich sein. Vergewissere dich zunächst, dass sie im Inneren des Containers installiert sind. Wenn der Container diese Tools noch nicht enthält, kannst du sie mit dem folgenden Befehl installieren:
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:*Bereitgestellt von
Dies zeigt zum Beispiel, dass die Flask-App auf allen Schnittstellen auf Port 5000 lauscht.
Zur Überwachung des ein- und ausgehenden Datenverkehrs auf der Hauptnetzwerkschnittstelle des Containers (normalerweise eth0):
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytesBereitgestellt von
Mit diesem Befehl kannst du den Datenverkehr verfolgen und feststellen, ob die Anfragen den Container erreichen oder ob Pakete verworfen oder fehlgeleitet werden.
Iptables Regelanalyse
Docker nutzt iptables, um Network Address Translation (NAT) zu verwalten und den Datenverkehr zwischen dem Host und den Containern zu kontrollieren. Es fügt automatisch Regeln ein, um Host-Ports an die entsprechenden Container-IPs und -Ports weiterzuleiten und ermöglicht so einen nahtlosen Zugang zu containerisierten Diensten.
Auf nativen Linux-Hosts kannst du diese Regeln mit Befehlen wie dem folgenden überprüfen:
Dies zeigt, wie Docker eingehenden Datenverkehr auf bestimmten Host-Ports den Container-Endpunkten zuordnet. Basierend auf der Docker Compose-Datei von vorhin, siehst du die weitergeleiteten Ports:
DNAT Regeln leiten den Verkehr vom Host zum Container um.
RETURN Regeln sorgen für die korrekte Weiterleitung des internen Docker-Netzwerkverkehrs.
Je nach Umgebung (z. B. Docker Desktop unter Windows oder WSL2) kann Docker die Portweiterleitung jedoch anders handhaben, und die Regeln von iptables sind möglicherweise nicht sichtbar oder können vom System aus geändert werden. In diesem Fall kannst du die Portweiterleitung mit dem folgenden Befehl überprüfen:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 04096 *:5000 *:*
tcp LISTEN 04096 *:8081 *:*
tcp LISTEN 04096 *:9090 *:* Bereitgestellt von
Tipps zur Fehlersuche:
Bestätige die Port-Zuordnungen mit docker ps und docker port [container].
Überprüfe, ob die Firewall oder Sicherheitssoftware des Hostsystems Ports blockiert.
Nutze Container-Logs und Netzwerk-Tools wie netstat und tcpdump, um das Netzwerkverhalten deiner Anwendung zu überprüfen.
Fazit
Die Offenlegung von Docker-Ports ist eine grundlegende Fähigkeit, die die Lücke zwischen der Isolierung von Containern und der praktischen Nutzbarkeit schließt. In diesem Artikel habe ich erklärt, wie das Netzwerkmodell von Docker funktioniert, den Unterschied zwischen dem Freigeben und Veröffentlichen von Ports erläutert und praktische Beispiele für verschiedene Szenarien gegeben.
Behalte diese wichtigen Punkte im Hinterkopf:
Verwende EXPOSE in Dockerfiles, um zu dokumentieren, welche Ports deine Anwendung verwendet
Verwenden Sie -p oder -P, wenn Sie Container betreiben, um diese Ports von außen zugänglich zu machen.
Nutzen Sie Docker Compose für die Verwaltung komplexer Multi-Container-Anwendungen
Benutze Diagnosetools, um Probleme zu beheben, wenn sie auftreten
Wenn du diese Konzepte und Techniken beherrschst, kannst du robustere containerisierte Anwendungen entwickeln, die sowohl intern als auch mit der Außenwelt effektiv kommunizieren. Ganz gleich, ob du eine einfache Webanwendung oder eine komplexe Microservices-Architektur entwickelst, die richtige Portverwaltung ist entscheidend für den Erfolg.
Da Container weiterhin die modernen Strategien zur Anwendungsbereitstellung dominieren, wird die Fähigkeit, Docker-Netzwerke und Ports sicher zu verwalten, eine wesentliche Fähigkeit im Werkzeugkasten jedes Entwicklers bleiben.
Um weiter zu lernen, solltest du dir die folgenden Ressourcen ansehen:
Was bedeutet es, einen Port in Docker freizugeben?⌄
Durch die Freigabe eines Ports in Docker kannst du dokumentieren, auf welchen Ports deine containerisierte Anwendung lauscht, aber es macht den Port nicht außerhalb des Containers zugänglich.
Wie kann ich den Port eines Docker-Containers von meinem Host-Rechner aus zugänglich machen?⌄
Du veröffentlichst einen Port mit dem -p Flag mit docker run oder dem ports Abschnitt in Docker Compose, der einen Host-Port dem Container-Port zuordnet.
Was ist der Unterschied zwischen "EXPOSE" und "p" in Docker?⌄
EXPOSE wird im Dockerfile verwendet, um Ports für die Dokumentation zu deklarieren, während -p diese Ports für den externen Zugriff veröffentlicht und zuordnet.
Kann ich mehrere Ports für einen einzigen Docker-Container freigeben?⌄
Ja, du kannst mehrere Ports freigeben, indem du mehrere EXPOSE Anweisungen im Dockerfile verwendest oder indem du mehrere Ports im ports Abschnitt von Docker Compose angibst.
Wie behebe ich Probleme mit der Docker-Port-Zuordnung?⌄
Verwende Befehle wie docker ps, docker port, docker inspect und Netzwerk-Tools innerhalb des Containers (z.B. netstat, tcpdump), um die Port-Zuordnungen und den Verkehrsfluss zu überprüfen.
Als Gründer von Martin Data Solutions und freiberuflicher Datenwissenschaftler, ML- und KI-Ingenieur bringe ich ein vielfältiges Portfolio in den Bereichen Regression, Klassifizierung, NLP, LLM, RAG, Neuronale Netze, Ensemble-Methoden und Computer Vision mit.
Er hat erfolgreich mehrere End-to-End-ML-Projekte entwickelt, einschließlich Datenbereinigung, Analyse, Modellierung und Bereitstellung auf AWS und GCP, und dabei wirkungsvolle und skalierbare Lösungen geliefert.
Du hast mit Streamlit und Gradio interaktive und skalierbare Webanwendungen für verschiedene Branchen entwickelt.
Er unterrichtete und betreute Studierende in den Bereichen Datenwissenschaft und Analytik und förderte ihre berufliche Entwicklung durch personalisierte Lernansätze.
Entwickelte Kursinhalte für Retrieval-Augmented-Generating (RAG)-Anwendungen, die auf die Anforderungen von Unternehmen zugeschnitten sind.
Er hat hochwirksame technische Blogs zu Themen wie MLOps, Vektordatenbanken und LLMs verfasst und damit ein hohes Maß an Engagement erzielt.
Bei jedem Projekt, das ich übernehme, achte ich darauf, dass ich die neuesten Praktiken des Software-Engineerings und der DevOps anwende, wie CI/CD, Code Linting, Formatierung, Modellüberwachung, Experiment-Tracking und robuste Fehlerbehandlung. Ich biete Komplettlösungen an und verwandle Datenerkenntnisse in praktische Strategien, die Unternehmen dabei helfen, zu wachsen und das Beste aus Data Science, maschinellem Lernen und KI herauszuholen.
Entdecke die Möglichkeiten von Docker und Kubernetes: Mit diesem interaktiven Lernpfad kannst du Anwendungen in modernen Umgebungen entwickeln und bereitstellen.
Tauche mit unserem Lernpfad zum Professional Data Engineer tief in fortgeschrittene Kompetenzen und modernste Tools ein, die das Data Engineering heute revolutionieren.
Bei der Arbeit mit Docker-Containern ist einer der wichtigsten Aspekte, auf den ich gestoßen bin, die Netzwerkkommunikation zwischen Containern und der Außenwelt. Ohne die richtige Portkonfiguration bleiben containerisierte Anwendungen isoliert und unzugänglich. In diesem Artikel zeige ich dir, wie du Docker-Ports freischaltest - eine grundlegende Fähigkeit für alle, die mit containerisierten Anwendungen arbeiten.
Dieser Leitfaden richtet sich an Softwareentwickler, DevOps-Ingenieure und IT-Experten, die ihre containerisierten Anwendungen für Nutzer, andere Dienste oder externe Systeme zugänglich machen müssen. Egal, ob du einen Webserver, eine API oder eine Datenbank in einem Container bereitstellst, das Verständnis der Portfreigabe ist für den Aufbau funktionaler Docker-basierter Systeme unerlässlich.
Am Ende dieses Artikels wirst du ein klares Verständnis davon haben, wie das Docker-Netzwerk funktioniert, die verschiedenen Methoden zur Freigabe von Ports und praktische Techniken, um diese Konzepte in deinen eigenen Projekten umzusetzen.
Wenn du Docker noch nicht kennst, solltest du einen unserer Kurse besuchen, z.B. Einführung in Docker, Containerisierung und Virtualisierung mit Docker und Kubernetes, Docker für Fortgeschrittene oder Containerisierungs- und Virtualisierungskonzepte.
Was ist die Freigabe eines Ports in Docker?
Bevor du in die technischen Details eintauchst, ist es wichtig zu verstehen, was Port Exposure im Docker-Ökosystem bedeutet.
Grundsätze der Isolierung von Containernetzwerken
Bei der Entwicklung von Docker-Containern ist die Isolation ein zentrales Prinzip. Diese Isolierung wird durch Linux-Kernel-Funktionen wie Namespaces und cgroups erreicht. Namensräume sorgen für eine Prozessisolierung und stellen sicher, dass Prozesse innerhalb eines Containers keine Prozesse in anderen Containern oder im Hostsystem sehen oder mit ihnen interagieren können. Cgroups hingegen kontrollieren die Ressourcenzuweisung und begrenzen, wie viel CPU, Speicher und andere Ressourcen ein Container verbrauchen kann.
Aus der Netzwerkperspektive erhält jeder Container seinen eigenen Netzwerk-Namensraum, komplett mit einer virtuellen Ethernet-Schnittstelle (Veth-Paar). Diese Schnittstelle verbindet sich standardmäßig mit einem Docker-Bridge-Netzwerk, das die Kommunikation zwischen den Containern ermöglicht und gleichzeitig vom Host-Netzwerk isoliert ist. Stell dir das so vor, dass jeder Container seine eigene private Netzwerkadresse hat, die für die Außenwelt unsichtbar ist.
In der Standardkonfiguration ist ein Docker-Container vollständig in einer Sandbox untergebracht. Dienste, die innerhalb des Containers laufen, können miteinander kommunizieren, sind aber von außerhalb des Containers nicht erreichbar, auch nicht vom Host-Rechner aus. Das ist der Punkt, an dem die Hafenexposition notwendig wird.
Expose vs. Publish: semantische Unterscheidung
Bei der Arbeit mit der Docker-Port-Konfiguration wirst du auf zwei verwandte, aber unterschiedliche Konzepte stoßen: das Freigeben und Veröffentlichen von Ports.
Die Offenlegung der Ports ist in erster Linie eine Dokumentationsfunktion. Wenn du einen Port in Docker freigibst, fügst du deinem Container-Image im Wesentlichen Metadaten hinzu, die angeben, dass die containerisierte Anwendung auf bestimmten Ports lauscht.
Die Freigabe eines Ports bedeutet jedoch nicht, dass er von außerhalb des Containers zugänglich ist. Sie dient als Dokumentation für die Nutzer deines Bildes.
Die Veröffentlichung von Ports macht deine containerisierten Dienste für die Außenwelt verfügbar. Die Veröffentlichung erstellt eine Zuordnung zwischen einem Port auf dem Host-Rechner und einem Port im Container. Wenn du einen Port veröffentlichst, konfiguriert Docker das Netzwerk des Hosts so, dass der Datenverkehr vom angegebenen Host-Port an den entsprechenden Container-Port weitergeleitet wird.
Hier erfährst du, wann du welche Methode anwenden solltest:
Wie man Docker Ports freilegt
Nachdem wir nun die Konzepte verstanden haben, wollen wir uns die praktischen Aspekte der Freigabe von Docker-Ports in verschiedenen Kontexten ansehen.
Strategien für Dockerfile-Deklarationen
Die einfachste Art, einen Port freizugeben, ist die Anweisung
EXPOSEin deinem Dockerfile. Hier werden die Ports angegeben, die der Container verwenden soll.In diesem Beispiel habe ich angegeben, dass der Container die Ports
80und443verwenden soll, die standardmäßig für HTTP- (Hypertext Transfer Protocol) und HTTPS- (Hypertext Transfer Protocol Secure) Datenverkehr verwendet werden. Du kannst sie auch zu einer einzigen Anweisung kombinieren:Wenn du Ports angibst, solltest du auch das Protokoll angeben: TCP (Transmission Control Protocol) oder UDP (User Datagram Protocol), wenn deine Anwendung ein bestimmtes Protokoll verwendet:
Wenn kein Protokoll angegeben wird, wird standardmäßig TCP angenommen. Dies ist für die meisten Webanwendungen geeignet, aber Dienste wie DNS (Domain Name System) oder Spieleserver benötigen oft UDP.
Aus der Sicherheitsperspektive empfehle ich, nur die Ports freizugeben, die deine Anwendung tatsächlich benötigt. Jeder freiliegende Port stellt einen potenziellen Angriffsvektor dar, daher folgt die Minimierung der Anzahl der freiliegenden Ports dem Prinzip der geringsten Privilegien.
Verwaltung der Runtime Ports
Während die Anweisung
EXPOSEdokumentiert, welche Ports ein Container verwendet, musst du diese Ports beim Ausführen des Containers veröffentlichen, um sie für den Host oder andere Maschinen zugänglich zu machen.Hier erfährst du, wie du einen Container-Port explizit an einen bestimmten Host-Port binden kannst:
Mit dem
-p(oder--publish) Flag kannst du einen einzelnen Port oder einen Bereich von Ports im Container an den Host binden.Dieser Befehl ordnet Port 80 innerhalb des Containers dem Port 8081 auf dem Host zu. Nachdem du diesen Befehl ausgeführt hast, kannst du auf den Webserver zugreifen, indem du in deinem Browser zu
http://localhost:8081navigierst.Um die Entwicklung zu vereinfachen, bietet Docker das
-P, capital P oder--publish-allFlag, das automatisch alle exponierten Ports auf zufälligen, hoch nummerierten Ports des Hosts veröffentlicht:Um herauszufinden, welche Host-Ports zugewiesen wurden, kann ich den Befehl
docker psverwenden:Dies führt zu einer Ausgabe wie:
Hier wird Port 80 innerhalb des Containers auf Port 49153 auf dem Host abgebildet.
Wenn du mit Diensten arbeitest, die sowohl TCP als auch UDP auf demselben Port verwenden (wie DNS-Server), musst du bei der Veröffentlichung das Protokoll angeben:
Docker Compose Orchestrierung
Für Anwendungen mit mehreren Containern bietet Docker Compose eine einfachere Möglichkeit, Netzwerke und Ports zu konfigurieren.
In einer Docker Compose YAML-Datei kannst du für jeden Dienst Port-Zuordnungen unter dem Schlüssel
portsangeben:Docker Compose macht einen wichtigen Unterschied zwischen
portsundexpose. Der Abschnittportserstellt veröffentlichte Port-Zuordnungen, die von außen zugänglich sind, währendexposedie Ports nur für verknüpfte Dienste innerhalb desselben Compose-Netzwerks verfügbar macht:In diesem Beispiel ist der Dienst
webvom Host über Port 8081 erreichbar, aber die PostgreSQL-Datenbank ist nur für andere Dienste innerhalb der Compose-Datei zugänglich, nicht direkt vom Host.Für flexible Konfigurationen, insbesondere in verschiedenen Umgebungen, kann ich Umgebungsvariablen in den Port-Zuordnungen verwenden:
Mit dieser Syntax kann ich den Host-Port über eine Umgebungsvariable (
WEB_PORT) angeben, die standardmäßig auf 8081 gesetzt wird, wenn sie nicht gesetzt ist.Docker Ports freigeben - Praktisches Beispiel
Lass uns ein komplettes Beispiel für die Freigabe von Docker-Ports für eine Webanwendung mit einem Datenbank-Backend durchgehen.
Stell dir vor, wir bauen eine einfache Webanwendung, die aus einem Python Flask API Service und einer PostgreSQL Datenbank besteht. Der API-Dienst lauscht auf Port
5000, und PostgreSQL verwendet seinen Standardport5432.So könnte unsere einfache Flask-Anwendung (
app.py) aussehen. Diese Anwendung erstellt eine Datenbankmyappund holt die Daten aus der Tabelleitems, sobald diese Tabelle in der Datenbank erstellt ist.Als Nächstes werde ich unsere
requirements.txtDatei erstellen:Jetzt muss ich eine Dockerdatei für unseren Python-API-Dienst erstellen:
Zum Schluss werde ich eine Docker Compose-Datei erstellen, um beide Dienste zu orchestrieren:
In dieser Konfiguration:
5000veröffentlicht, sodass er vom Host-Rechner aus zugänglich ist.5432zur Verfügung, veröffentlicht ihn aber nicht, so dass er nur für andere Dienste innerhalb des Compose-Netzwerks zugänglich ist.5432zugreifen.Um diese Anwendung auszuführen, verwende:
Jetzt kann ich auf die API unter
http://localhost:5000zugreifen, aber die PostgreSQL-Instanz ist nicht direkt von außerhalb des Docker-Netzwerks zugänglich, was eine gute Sicherheitspraxis für Datenbankdienste ist. Du kannst aber aus dem laufenden Container auf PostgreSQL zugreifen:Mit diesem Befehl rufe ich das PostgreSQL CLI auf, wo ich die Datenbank einsehen und eine Tabelle
itemserstellen kann. Einmal erstellt, kann ich die Daten inhttp://localhost:5000/itemsWie man mehrere Docker Ports freigibt
Wenn meine Python-Anwendung mehrere Ports zur Verfügung stellen muss, kann ich sie alle in der Dockerdatei angeben:
Dieses Dockerfile zeigt an:
5000für die Hauptanwendung von Flask (derzeit aktiv)8081für ein mögliches Monitoring-Dashboard9090für eine zukünftige Debugging-SchnittstelleEs ist wichtig zu beachten, dass ich zwar die Ports
8081und9090in der Dockerdatei als Dokumentation freigegeben habe, meine aktuelle Flask-Anwendung aber nur so konfiguriert ist, dass sie auf Port5000lauscht. Die zusätzlichen offenen Ports zeigen, wo zukünftige Funktionen implementiert werden könnten.Wie man offene Ports veröffentlicht
Um Ports, die in einem Dockerfile offengelegt sind, zu veröffentlichen, verwende ich das
-poder-PFlag, wenn ich den Container starte:Dadurch wird der Port
5000im Container (der im Dockerfile angegeben ist und auf dem Flask lauscht) dem Port8081auf dem Host zugeordnet. Nachdem ich diesen Befehl ausgeführt habe, kann ich auf meine Flask-Anwendung zugreifen, indem ich in meinem Browser zuhttp://localhost:8081navigiere.Ich kann auch das -P Flag verwenden, um automatisch alle exponierten Ports auf zufälligen Ports auf dem Host zu veröffentlichen:
Um zu prüfen, welche Ports veröffentlicht sind, kann ich verwenden:
Für genauere Informationen kann ich verwenden:
Dieser Befehl zeigt alle Port-Zuordnungen für einen bestimmten Container an. Wenn meine Flask-Anwendung zum Beispiel nur auf Port
5000lauscht, ich aber mehrere Ports in der Dockerdatei freigegeben habe, zeigt mir Docker port genau, welche Host-Ports welchen Container-Ports zugeordnet sind. Wenn also Port5000auf 32768 gemappt wurde, kann ich auf meine Flask-Anwendung unterhttp://localhost:32768Diagnose- und Fehlersuchtechniken
Auch bei sorgfältiger Konfiguration können Probleme mit der Docker-Port-Zuordnung auftreten. Hier sind einige Techniken, die ich verwende, um häufige Probleme zu diagnostizieren und zu lösen.
Überprüfung der Hafenkartierung
Der erste Schritt bei der Diagnose von Port-Problemen besteht darin, zu überprüfen, ob die Zuordnungen richtig eingerichtet sind. Ich benutze diese Befehle:
Listet alle laufenden Container mit Port-Zuordnungen auf:
Erhalte detaillierte Informationen über einen bestimmten Container:
Überprüfe die Port-Zuordnungen für einen bestimmten Container:
Der Befehl docker inspect liefert detaillierte Informationen, einschließlich der Netzwerkeinstellungen. Um dich auf netzwerkbezogene Details zu konzentrieren, verwende:
Wenn du den Datenverkehr genauer analysieren willst, können Tools wie
tcpdumpundnetstatsehr nützlich sein. Vergewissere dich zunächst, dass sie im Inneren des Containers installiert sind. Wenn der Container diese Tools noch nicht enthält, kannst du sie mit dem folgenden Befehl installieren:Um zu sehen, auf welchen Ports die Anwendung innerhalb des Containers lauscht:
Dies zeigt zum Beispiel, dass die Flask-App auf allen Schnittstellen auf Port
5000lauscht.Zur Überwachung des ein- und ausgehenden Datenverkehrs auf der Hauptnetzwerkschnittstelle des Containers (normalerweise eth0):
Mit diesem Befehl kannst du den Datenverkehr verfolgen und feststellen, ob die Anfragen den Container erreichen oder ob Pakete verworfen oder fehlgeleitet werden.
Iptables Regelanalyse
Docker nutzt
iptables, um Network Address Translation (NAT) zu verwalten und den Datenverkehr zwischen dem Host und den Containern zu kontrollieren. Es fügt automatisch Regeln ein, um Host-Ports an die entsprechenden Container-IPs und -Ports weiterzuleiten und ermöglicht so einen nahtlosen Zugang zu containerisierten Diensten.Auf nativen Linux-Hosts kannst du diese Regeln mit Befehlen wie dem folgenden überprüfen:
Dies zeigt, wie Docker eingehenden Datenverkehr auf bestimmten Host-Ports den Container-Endpunkten zuordnet. Basierend auf der Docker Compose-Datei von vorhin, siehst du die weitergeleiteten Ports:
Hier:
DNATRegeln leiten den Verkehr vom Host zum Container um.RETURNRegeln sorgen für die korrekte Weiterleitung des internen Docker-Netzwerkverkehrs.Je nach Umgebung (z. B. Docker Desktop unter Windows oder WSL2) kann Docker die Portweiterleitung jedoch anders handhaben, und die Regeln von
iptablessind möglicherweise nicht sichtbar oder können vom System aus geändert werden. In diesem Fall kannst du die Portweiterleitung mit dem folgenden Befehl überprüfen:Tipps zur Fehlersuche:
docker psunddocker port [container].netstatundtcpdump, um das Netzwerkverhalten deiner Anwendung zu überprüfen.Fazit
Die Offenlegung von Docker-Ports ist eine grundlegende Fähigkeit, die die Lücke zwischen der Isolierung von Containern und der praktischen Nutzbarkeit schließt. In diesem Artikel habe ich erklärt, wie das Netzwerkmodell von Docker funktioniert, den Unterschied zwischen dem Freigeben und Veröffentlichen von Ports erläutert und praktische Beispiele für verschiedene Szenarien gegeben.
Behalte diese wichtigen Punkte im Hinterkopf:
EXPOSEin Dockerfiles, um zu dokumentieren, welche Ports deine Anwendung verwendet-poder-P, wenn Sie Container betreiben, um diese Ports von außen zugänglich zu machen.Wenn du diese Konzepte und Techniken beherrschst, kannst du robustere containerisierte Anwendungen entwickeln, die sowohl intern als auch mit der Außenwelt effektiv kommunizieren. Ganz gleich, ob du eine einfache Webanwendung oder eine komplexe Microservices-Architektur entwickelst, die richtige Portverwaltung ist entscheidend für den Erfolg.
Da Container weiterhin die modernen Strategien zur Anwendungsbereitstellung dominieren, wird die Fähigkeit, Docker-Netzwerke und Ports sicher zu verwalten, eine wesentliche Fähigkeit im Werkzeugkasten jedes Entwicklers bleiben.
Um weiter zu lernen, solltest du dir die folgenden Ressourcen ansehen: