Fehlerbehebung bei Docker-Netzwerken: Konnektivitätsprobleme effektiv lösen
Beheben Sie Docker-Netzwerkprobleme mit Container-DNS, benutzerdefinierten Netzwerken, Portveröffentlichung, Host-Zugriff, DNS und Firewalls.
Fehlerbehebung bei Docker-Netzwerken: Konnektivitätsprobleme effektiv lösen
Docker-Netzwerkprobleme sind viel einfacher zu lösen, wenn Sie die Richtung der fehlgeschlagenen Verbindung benennen. „Der Container kann keine Verbindung herstellen“ ist zu vage. Versucht der Host, einen Container zu erreichen? Versucht ein Container, einen anderen zu erreichen? Versucht ein Container, das Internet zu erreichen? Kommt der Datenverkehr von einem anderen Rechner? Jeder Pfad verwendet ein anderes Docker-Verhalten.
Beginnen Sie damit, den Pfad in einfacher Sprache zu notieren:
Browser auf Host -> localhost:8080 -> Container-Port 80
api-Container -> db-Container -> Port 5432
worker-Container -> öffentliches Internet -> api.example.com:443
entferntes Laptop -> öffentliche IP des Servers -> veröffentlichter Container-Port
Sobald Sie den Pfad kennen, können Sie jeden Hop testen, anstatt wahllos Netzwerke zu ändern.
Grundlegende Docker-Netzwerkmodi kennen
Die meisten Einzelhost-Docker-Setups verwenden Bridge-Netzwerke. Docker erstellt ein virtuelles Netzwerk auf dem Host, weist Containern private IP-Adressen zu und kann ausgewählte Container-Ports auf dem Host veröffentlichen.
Das Standard-bridge-Netzwerk funktioniert, aber benutzerdefinierte Bridge-Netzwerke sind für Anwendungen besser, da sie integrierte DNS-Auflösung nach Containernamen bieten. Das bedeutet, dass ein api-Container einen db-Container unter db:5432 erreichen kann, wenn beide an dasselbe benutzerdefinierte Netzwerk angeschlossen sind.
Erstellen Sie eines wie folgt:
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name api --network appnet my-api
Es gibt andere Modi. Das host-Netzwerk teilt den Netzwerk-Namespace des Hosts und hebt das normale Port-Publishing-Verhalten auf; es ist in einigen Linux-Fällen nützlich, reduziert aber die Isolation. none gibt einem Container kein Netzwerk. overlay ist für Multi-Host-Docker-Swarm-Netzwerke. Compose erstellt automatisch benutzerdefinierte Netzwerke für Projekte, sofern Sie nichts anderes konfigurieren.
„Netzwerk nicht gefunden“
Dieser Fehler bedeutet normalerweise, dass der Netzwerkname falsch ist oder das Netzwerk in einem anderen Kontext existiert, als der Befehl erwartet.
Verfügbare Netzwerke prüfen:
docker network ls
Das gewünschte Netzwerk inspizieren:
docker network inspect appnet
Wenn es nicht existiert, erstellen Sie es:
docker network create appnet
Bei Compose kann der tatsächliche Netzwerkname durch den Projektnamen ergänzt werden. Ein Netzwerk namens backend in compose.yml kann als myproject_backend erscheinen. Verwenden Sie:
docker compose ps
docker network ls
Wenn Sie ein externes Compose-Netzwerk deklariert haben, wird Compose es nicht für Sie erstellen:
networks:
appnet:
external: true
In diesem Fall erstellen Sie es manuell oder entfernen Sie external: true, wenn Compose es verwalten soll.
Container-zu-Container-Kommunikation schlägt fehl
Damit zwei Container per Name kommunizieren können, müssen sie sich normalerweise im selben benutzerdefinierten Netzwerk befinden. Überprüfen Sie das zuerst:
docker network inspect appnet
Suchen Sie beide Container im Abschnitt Containers.
Testen Sie dann von einem Container, der grundlegende Tools enthält. Ihr Anwendungsimage enthält möglicherweise kein curl, dig oder ping, und das ist in Ordnung. Verwenden Sie einen temporären Debug-Container im selben Netzwerk:
docker run --rm -it --network appnet nicolaka/netshoot
Von innen:
dig db
curl -v http://api:8080/health
nc -vz db 5432
Wenn DNS fehlschlägt, sind die Container wahrscheinlich nicht im selben benutzerdefinierten Netzwerk, oder Sie verwenden das Standard-Bridge-Netzwerk und erwarten eine Namensauflösung, die es nicht in gleicher Weise bietet. Wenn DNS funktioniert, die Verbindung aber fehlschlägt, prüfen Sie, ob der Zieldienst auf dem erwarteten Port lauscht.
Im Zielcontainer:
docker exec -it api sh
ss -ltnp || netstat -ltnp
Ein häufiger Fehler ist das Binden der App an 127.0.0.1 innerhalb des Containers. Das lauscht nur auf dem Loopback innerhalb dieses Containers. Andere Container können es nicht erreichen. Konfigurieren Sie die App so, dass sie auf 0.0.0.0 lauscht.
Stellen Sie außerdem sicher, dass Sie für den Container-zu-Container-Verkehr den Container-Port und nicht den Host-veröffentlichten Port verwenden. Wenn die Datenbank im Container auf 5432 lauscht, sollten andere Container db:5432 verwenden, nicht localhost:15432 oder den veröffentlichten Host-Port.
Host kann Container nicht erreichen
Damit der Host einen Dienst in einem Bridge-vernetzten Container erreichen kann, benötigen Sie normalerweise einen veröffentlichten Port:
docker run -d --name web -p 8080:80 nginx
Dies bildet Host-Port 8080 auf Container-Port 80 ab. Testen Sie vom Host aus:
curl -v http://localhost:8080
Prüfen Sie, was Docker veröffentlicht hat:
docker port web
docker ps --format 'table {{.Names}} {{.Ports}}'
Wenn es keine Port-Zuordnung gibt, veröffentlicht EXPOSE im Dockerfile den Port nicht. EXPOSE ist Dokumentation und Metadaten. Sie benötigen weiterhin -p oder Compose ports:.
Wenn der Port veröffentlicht ist, die Verbindung aber fehlschlägt, überprüfen Sie vier Dinge:
- Die Anwendung lauscht im Container auf dem Container-Port.
- Die Anwendung lauscht auf
0.0.0.0, nicht nur auf127.0.0.1. - Keine Host-Firewall blockiert den Host-Port.
- Kein anderer Prozess belegt bereits den Host-Port.
Host-Port-Konflikte finden:
sudo lsof -i :8080
# oder
sudo ss -ltnp 'sport = :8080'
Für Compose beachten Sie die Syntax:
ports:
- "8080:80"
Die linke Seite ist der Host-Port. Die rechte Seite ist der Container-Port.
Container kann das Internet nicht erreichen
Testen Sie IP-Konnektivität und DNS getrennt:
docker exec -it app sh
ping -c 2 1.1.1.1
ping -c 2 example.com
Einige Images enthalten kein ping. Verwenden Sie curl, falls verfügbar:
curl -I https://example.com
Wenn IP funktioniert, Namen aber fehlschlagen, liegt ein DNS-Problem vor. Prüfen Sie:
cat /etc/resolv.conf
Docker injiziert normalerweise Resolver-Einstellungen. Unternehmens-VPNs, benutzerdefiniertes DNS und Docker Desktop-Netzwerke können dies erschweren. Sie können Daemon-Level-DNS in den Docker-Daemon-Einstellungen konfigurieren oder DNS für einen bestimmten Container übergeben:
docker run --dns 1.1.1.1 ...
Verwenden Sie öffentliches DNS nicht blind in Unternehmensumgebungen, in denen interne Namen aufgelöst werden müssen. Verwenden Sie die für das Netzwerk geeigneten DNS-Server.
Wenn weder IP noch DNS funktionieren, prüfen Sie, ob der Container mit --network none läuft, ob Host-Firewall/NAT-Regeln defekt sind, ob der Docker-Daemon benutzerdefinierte Netzwerkeinstellungen hat und ob der Host selbst Internetzugang hat.
Ein Container muss einen Dienst auf dem Host erreichen
Von einem Container aus bedeutet localhost den Container selbst, nicht den Host. Dies ist eine der häufigsten Überraschungen bei Docker-Netzwerken.
Auf Docker Desktop löst host.docker.internal normalerweise den Host auf. Auf moderner Docker Engine für Linux können Sie einen Host-Gateway-Eintrag hinzufügen:
docker run --add-host=host.docker.internal:host-gateway ...
Dann kann der Container aufrufen:
curl http://host.docker.internal:3000
Stellen Sie sicher, dass der Host-Dienst auf einer Adresse lauscht, die von Docker erreichbar ist, nicht nur auf einer Loopback-Bindung, auf die Docker in Ihrer Umgebung nicht zugreifen kann. Wenn ein lokaler Entwicklungsserver nur an 127.0.0.1 bindet, müssen Sie ihn je nach Betriebssystem und Sicherheitsanforderungen möglicherweise an 0.0.0.0 oder das Host-Interface binden.
Entfernte Rechner können den Container nicht erreichen
Wenn der Host localhost:8080 erreichen kann, ein anderer Rechner aber nicht server-ip:8080 erreichen kann, ist Docker möglicherweise in Ordnung. Überprüfen Sie die Host-Firewall, die Cloud-Sicherheitsgruppe, den Router/NAT und ob Docker nur auf Loopback veröffentlicht hat.
Dies veröffentlicht auf allen Host-Interfaces:
docker run -p 8080:80 nginx
Dies veröffentlicht nur auf localhost:
docker run -p 127.0.0.1:8080:80 nginx
Loopback-only-Veröffentlichung ist oft wünschenswert für lokale Entwicklung oder Reverse-Proxy-Setups, blockiert aber von Natur aus den Fernzugriff.
Auf Cloud-Servern überprüfen Sie auch die Firewalls des Anbieters. Das Öffnen von ufw auf der VM hilft nicht, wenn die Cloud-Sicherheitsgruppe den Port immer noch blockiert.
Compose-Netzwerkfehler
Compose gibt jedem Dienst einen DNS-Namen basierend auf dem Dienstnamen. Wenn Ihr Dienst db heißt, sollten andere Dienste normalerweise eine Verbindung zu db herstellen, nicht zu localhost.
Beispiel:
services:
api:
build: .
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/app
depends_on:
- db
db:
image: postgres:16
depends_on steuert die Startreihenfolge, nicht die Bereitschaft. Der Datenbank-Container kann starten, bevor Postgres bereit ist, Verbindungen anzunehmen. Ihre Anwendung sollte Verbindungen wiederholen oder ein Healthcheck-bewusstes Startmuster verwenden.
Unterscheiden Sie auch ports von expose. ports veröffentlicht auf dem Host. expose dokumentiert oder legt Ports für verknüpfte Dienste offen, macht sie aber nicht in gleicher Weise vom Host aus erreichbar.
Paket-Level-Debugging
Wenn normale Überprüfungen das Problem nicht erklären, verwenden Sie ein Netzwerk-Debug-Image:
docker run --rm -it --network container:<target-container> nicolaka/netshoot
Dies tritt dem Netzwerk-Namespace des Zielcontainers bei, sodass Sie das Netzwerk aus derselben Perspektive inspizieren können, ohne Tools im App-Image zu installieren.
Nützliche Befehle sind:
ip addr
ip route
cat /etc/resolv.conf
dig service-name
curl -v http://service-name:port
tcpdump -nn -i any port 8080
Verwenden Sie tcpdump, wenn Sie wissen müssen, ob Pakete überhaupt ankommen. Wenn keine Pakete ankommen, suchen Sie vor dem Container: Veröffentlichung, Firewall, Routing, Load Balancer. Wenn Pakete ankommen und keine Antwort verlässt, suchen Sie im Container oder der Anwendung.
Ein kurzer Fehlerbehebungsablauf
Verwenden Sie diese Reihenfolge für die meisten Docker-Netzwerkprobleme:
- Definieren Sie den genauen Pfad: Host zu Container, Container zu Container, Container zu Internet oder Remote zu Host zu Container.
- Überprüfen Sie die Netzwerkverbindung mit
docker network inspect. - Überprüfen Sie die Namensauflösung von der Quellseite.
- Überprüfen Sie, ob der Zielprozess auf dem richtigen Interface und Port lauscht.
- Überprüfen Sie die Portveröffentlichung nur für Datenverkehr, der vom Host zum Container gelangt.
- Überprüfen Sie Firewall, VPN, Proxy, DNS und Cloud-Sicherheitsregeln außerhalb von Docker.
Die meisten Docker-Netzwerkprobleme sind keine tiefgreifenden Docker-Fehler. Es sind normalerweise falsche Namen, falsche Ports, Loopback-Bindung, fehlende veröffentlichte Ports, DNS-Annahmen oder Datenverkehr, der von der falschen Seite der Grenze getestet wird.