Docker-Netzwerke verbinden die einzelnen Bausteine deiner selbst gehosteten Anwendungen. Ein Reverse Proxy muss den Webdienst erreichen, eine Anwendung ihre Datenbank finden und dein Browser die richtige Adresse verwenden. Dabei kommt es darauf an, von wo eine Verbindung aufgebaut wird: aus einem Container, vom Docker-Host oder von einem anderen Gerät.
Diese Anleitung erklärt Bridge-Netzwerke, Compose-Dienstnamen und den Unterschied zwischen internen Container-Ports und veröffentlichten Host-Ports. Anschließend verbindest du zwei getrennte Compose-Projekte über ein gemeinsames Netzwerk. Für Verbindungsprobleme bekommst du einen festen Ablauf, mit dem du DNS-Fehler, falsche Ports und nicht erreichbare Dienste eingrenzen kannst.
Voraussetzungen für die Beispiele
Du benötigst eine laufende Docker Engine und Docker Compose. Die Beispiele verwenden Linux-Container: entweder direkt auf einem Linux-Host oder über Docker Desktop. Eine grundlegende Einrichtung beschreibt der Artikel Installation und Konfiguration von Docker.
- Alle Container des Beispiels laufen auf derselben Docker Engine.
- Dein Benutzer darf Docker-Befehle ausführen.
- Host-Port
8080ist für das Beispiel verfügbar. - Du kannst die benötigten Images herunterladen.
Prüfe zunächst, ob Engine und Compose erreichbar sind:
docker version
docker compose version
docker context show
docker version sollte Angaben zu Client und Server liefern. Der letzte Befehl zeigt den aktiven Docker-Kontext. Das ist besonders wichtig, wenn du zwischen einem lokalen Docker Desktop und einem entfernten Server wechselst.
Die Docker-Befehle unten verwenden keine mehrzeiligen Shell-Konstruktionen und lassen sich in einer Linux-Shell sowie in PowerShell ausführen. Betriebsspezifische HTTP-Tests sind gesondert angegeben.
Wie Bridge-Netzwerke in Docker funktionieren
Ein Bridge-Netzwerk ist ein virtuelles Netzwerk innerhalb eines Docker-Hosts. Angeschlossene Container erhalten eigene Netzwerkschnittstellen und IP-Adressen. Container im selben Bridge-Netzwerk können sich untereinander erreichen, sofern die jeweilige Anwendung Verbindungen auf dem angesprochenen Port annimmt.
Für typische Self-Hosting-Projekte reicht dieser Netzwerktyp aus. Ein gemeinsames Bridge-Netzwerk verbindet allerdings keine Container auf unterschiedlichen Docker-Hosts. Zwei Netzwerke mit demselben Namen auf zwei Servern bleiben zwei getrennte Netzwerke.
Das Netzwerk „bridge“ und eigene Bridge-Netzwerke unterscheiden
Docker legt bei der Installation ein Netzwerk mit dem Namen bridge an. Ein mit docker run gestarteter Container landet normalerweise dort, wenn du kein anderes Netzwerk angibst.
Benutzerdefinierte Bridge-Netzwerke bieten zusätzlich eine automatische Namensauflösung zwischen angeschlossenen Containern. Dadurch kannst du Dienste über Namen ansprechen und musst keine wechselnden Container-IP-Adressen eintragen. Das eingebaute Netzwerk bridge bietet diese automatische Namensauflösung zwischen Containern nicht in derselben Weise.
Die Unterschiede erläutert die Docker-Dokumentation zum Bridge-Treiber.
Docker Compose erstellt normalerweise ein eigenes Netzwerk
Wenn du in einer Compose-Datei keine Netzwerke festlegst, erstellt Compose ein gemeinsames Standardnetzwerk für das Projekt. Es heißt üblicherweise PROJEKTNAME_default.
Die Dienste dieses Projekts können sich darin über ihre Compose-Dienstnamen erreichen. Zwei getrennte Compose-Projekte erhalten dagegen normalerweise unterschiedliche Standardnetzwerke. Dass beide auf demselben Server laufen, reicht deshalb für eine direkte Verbindung über Dienstnamen noch nicht aus.
Worauf verweist localhost innerhalb eines Containers?
In einem gewöhnlichen Bridge-Container verweist localhost auf den Container selbst. Dasselbe gilt für die IPv4-Loopback-Adresse 127.0.0.1 und die IPv6-Loopback-Adresse ::1.
Ein Reverse Proxy in einem Container erreicht mit http://localhost:3000 somit einen Dienst im eigenen Netzwerk-Namensraum. Er erreicht damit weder automatisch den Docker-Host noch eine Anwendung in einem anderen Container.
| Wo wird die Verbindung aufgebaut? | Worauf verweist localhost? |
|---|---|
| Im Browser auf deinem PC | Auf deinen PC |
| In einer Shell auf dem Docker-Server | Auf den Docker-Server |
| Im Webcontainer | Auf den Netzwerk-Namensraum des Webcontainers |
| Im Proxycontainer | Auf den Netzwerk-Namensraum des Proxycontainers |
Für die Verbindung zwischen zwei Containern verwendest du deshalb üblicherweise den Dienstnamen oder einen Netzwerkalias des Zielcontainers.
Abweichungen gibt es bei ausdrücklich gemeinsam genutzten Netzwerk-Namensräumen, etwa mit network_mode: host oder network_mode: service:.... Diese Anleitung verwendet normale Bridge-Netzwerke mit getrennten Netzwerk-Namensräumen.
Container-Port und Host-Port richtig unterscheiden
Ein Container-Port ist der Port, auf dem die Anwendung innerhalb des Containers lauscht. Ein Host-Port ist ein Port auf dem Docker-Host, den Docker an einen Container-Port weiterleitet.
Ein Beispiel für die Portfreigabe eines Compose-Dienstes lautet:
ports:
- "127.0.0.1:8080:80"
Dieser Ausschnitt gehört unter den betreffenden Dienst. Die Bestandteile bedeuten:
127.0.0.1: Die Freigabe wird an die lokale IPv4-Loopback-Adresse des Docker-Hosts gebunden.8080: Auf diesem Host-Port nimmt Docker Verbindungen entgegen.80: An diesen Port im Container werden die Verbindungen weitergeleitet.
Die Anwendung im Container muss tatsächlich auf Port 80 lauschen. Die Portfreigabe ändert ihre interne Konfiguration nicht.
| Zugriffsweg | Verwendete Adresse |
|---|---|
| Vom Docker-Host über die obige Freigabe | http://127.0.0.1:8080 |
| Aus einem anderen Container im selben Netzwerk | Zum Beispiel http://web:80 |
| Aus dem Zielcontainer selbst | http://127.0.0.1:80, sofern der Dienst dort lauscht |
Zwischen Containern im gemeinsamen Netzwerk verwendest du den internen Port des Zieldienstes. Der veröffentlichte Host-Port gehört zum Zugriffsweg über den Docker-Host.
Was ändert sich ohne 127.0.0.1?
Eine Angabe wie "8080:80" veröffentlicht den Port standardmäßig auf allen Host-Schnittstellen. Dadurch kann der Dienst abhängig von Routing und Firewall auch aus dem lokalen Netzwerk oder dem Internet erreichbar werden.
Für den lokalen Versuch verwenden wir deshalb "127.0.0.1:8080:80". Die Docker-Dokumentation zu Portfreigaben beschreibt außerdem eine Einschränkung älterer Engine-Versionen: Vor Docker Engine 28.0.0 konnten solche Loopback-Freigaben unter bestimmten Bedingungen aus demselben Layer-2-Netz erreichbar sein.
Ist expose für die Verbindung zwischen Containern erforderlich?
Im üblichen benutzerdefinierten Bridge-Netzwerk ist kein expose:-Eintrag erforderlich, damit ein anderer angeschlossener Container einen lauschenden Dienst erreichen kann.
expose: in Compose und EXPOSE im Dockerfile beschreiben vorgesehene Container-Ports. Sie veröffentlichen allein keinen Host-Port und starten keinen Listener. Sie bilden auch keine Zugriffsliste, die alle anderen Ports innerhalb des gemeinsamen Netzwerks sperrt.
Compose-Dienstnamen als interne Adressen verwenden
Der Schlüssel direkt unter services: ist der Compose-Dienstname. Heißt ein Dienst dort web, können andere Container im gemeinsamen Compose-Netzwerk ihn normalerweise über web ansprechen.
Für eine Datenbank mit dem Dienstnamen db würde eine Anwendung beispielsweise den Hostnamen db und den internen Datenbankport verwenden. Der Name des Compose-Projektordners und ein veröffentlichter Datenbankport ersetzen diesen internen Zielnamen nicht.
Verwende möglichst Namen statt fester Container-IP-Adressen. Beim Neuerstellen eines Containers kann sich seine IP ändern. Der Dienstname bleibt der vorgesehene Verbindungspunkt. Bereits bestehende Verbindungen können dabei abbrechen; die Anwendung muss anschließend erneut auflösen und verbinden können.
Ein festes container_name: ist für diese Kommunikation nicht nötig. Die Grundlagen beschreibt Networking in Compose.
Der Browser verwendet nicht automatisch Docker-DNS
Ein häufiger Stolperstein bei Webanwendungen: JavaScript, das im Browser ausgeführt wird, baut seine Verbindungen vom Rechner des Besuchers auf. Eine Adresse wie http://api:3000 funktioniert dort nicht allein deshalb, weil ein Compose-Dienst api heißt.
Für Browseranfragen benötigst du eine vom Browser erreichbare Adresse, beispielsweise eine öffentliche HTTPS-Adresse oder einen Pfad wie /api, den dein Reverse Proxy weiterleitet. Serveranfragen aus einem Container können dagegen den internen Docker-Dienstnamen verwenden.
Zwei Compose-Projekte über ein gemeinsames Docker-Netzwerk verbinden
Das folgende Beispiel besteht aus zwei unabhängig verwalteten Projekten:
- Website: Ein Nginx-Webserver liefert eine kleine Testseite aus.
- Proxy: Ein zweiter Nginx nimmt Browseranfragen entgegen und leitet sie an die Website weiter.
Beide verwenden das gemeinsame Bridge-Netzwerk fundus_proxy_net. Nur der Proxy veröffentlicht einen Host-Port. Die Website benötigt für die Verbindung zum Proxy keine eigene Portfreigabe.
Schritt 1: Verzeichnisse und Dateien vorbereiten
Lege einen neuen Ordner mit dieser Struktur an:
docker-netzwerk-demo/
├── website/
│ ├── compose.yaml
│ └── index.html
└── proxy/
├── compose.yaml
└── default.conf
Alle folgenden Befehle werden im übergeordneten Ordner docker-netzwerk-demo ausgeführt. Durch -f wählen sie jeweils die passende Compose-Datei aus.
Erstelle auch die beiden eingebundenen Dateien index.html und default.conf, bevor du die Container startest. Bei einem entfernten Docker-Host müssen die Bind-Mount-Quelldateien auf diesem Host am passenden Pfad vorhanden sein.
Schritt 2: Gemeinsames Netzwerk erstellen
Erstelle das Netzwerk einmalig auf der Docker Engine, auf der beide Projekte laufen:
docker network create --driver bridge fundus_proxy_net
Falls dieser Name bereits existiert, prüfe das vorhandene Netzwerk:
docker network inspect fundus_proxy_net
Für dieses Beispiel muss es ein geeignetes Bridge-Netzwerk auf derselben Engine sein. Ein Netzwerk auf einem anderen Docker-Kontext steht hier nicht automatisch zur Verfügung.
Schritt 3: Compose-Projekt für die Website anlegen
Speichere unter website/compose.yaml:
name: fundus-website
services:
web:
image: nginx:stable-alpine
restart: unless-stopped
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
networks:
shared:
aliases:
- fundus-web
networks:
shared:
external: true
name: fundus_proxy_net
Speichere anschließend diesen Inhalt unter website/index.html:
<p>Der Webdienst ist über das gemeinsame Docker-Netzwerk erreichbar.</p>
Der Dienst heißt web. Zusätzlich bekommt er im gemeinsamen Netzwerk den Alias fundus-web. Diesen eindeutigen Namen verwendet später der Proxy.
Ein eigener Alias ist besonders hilfreich, wenn mehrere Projekte Dienste mit allgemeinen Namen wie web, app oder db in dasselbe Netzwerk aufnehmen. Mehrfach vergebene Namen können dort zu einer mehrdeutigen Auflösung führen. Der Alias ergänzt den Dienstnamen; er entfernt dessen Registrierung nicht.
Schritt 4: Compose-Projekt für den Proxy anlegen
Speichere unter proxy/compose.yaml:
name: fundus-proxy
services:
proxy:
image: nginx:stable-alpine
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- shared
networks:
shared:
external: true
name: fundus_proxy_net
Speichere unter proxy/default.conf:
server {
listen 80;
server_name _;
location / {
proxy_pass http://fundus-web:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Der Proxy leitet Anfragen an fundus-web auf dessen internem Port 80 weiter. localhost wäre hier das falsche Ziel: Damit würde der Proxy wieder seinen eigenen Container ansprechen.
Der Image-Tag stable-alpine ist veränderlich. Für einen dauerhaft betriebenen Dienst solltest du eine bewusst gewählte Version oder einen Digest festlegen und Updates einplanen. Dazu passt die Anleitung Docker Compose aktualisieren: Images, Volumes und Rollback sicher handhaben.
Schritt 5: Konfiguration prüfen und Website starten
Prüfe zunächst beide Compose-Dateien:
docker compose -f website/compose.yaml config --quiet
docker compose -f proxy/compose.yaml config --quiet
Eine erfolgreiche Prüfung bleibt mit --quiet ohne Ausgabe. Sie bestätigt, dass Compose die Konfiguration verarbeiten kann. Ob der Webdienst erreichbar ist und die Nginx-Konfiguration funktioniert, prüfen die nächsten Schritte.
Starte zuerst die Website:
docker compose -f website/compose.yaml up -d
docker compose -f website/compose.yaml ps
Teste sie aus einem kurzlebigen Container im gemeinsamen Netzwerk:
docker run --rm --network fundus_proxy_net busybox:1.37 wget -q -O - http://fundus-web:80/
Bei erfolgreicher Verbindung erscheint der Inhalt der Testseite. Das BusyBox-Image wird bei Bedarf heruntergeladen; der Testcontainer wird nach dem Befehl entfernt. Falls der Webserver unmittelbar nach dem Start noch nicht bereit ist, prüfe die Logs und wiederhole den Test.
Schritt 6: Proxy starten und Browserzugriff prüfen
Starte den Proxy, sobald die Website erreichbar ist:
docker compose -f proxy/compose.yaml up -d
docker compose -f proxy/compose.yaml ps
docker compose -f proxy/compose.yaml logs --tail=30 proxy
Öffne auf dem Docker-Host beziehungsweise dem Rechner mit Docker Desktop die Adresse http://127.0.0.1:8080. Der Browser sollte den Text der Website anzeigen.
Die Verbindung nimmt diesen Weg:
Browser auf dem Docker-Host
→ 127.0.0.1:8080
→ Proxycontainer, Port 80
→ fundus_proxy_net
→ fundus-web:80
→ Websitecontainer
Wenn Docker auf einem entfernten Server läuft, verweist 127.0.0.1 im Browser deines PCs weiterhin auf deinen PC. Für die lokale Freigabe des entfernten Servers brauchst du beispielsweise einen SSH-Tunnel oder einen Browser direkt auf diesem Server.
Das Beispiel verwendet HTTP für einen lokalen Funktionstest. Für einen Zugriff über das Internet benötigst du zusätzlich eine passende Veröffentlichung, HTTPS und den Zugriffsschutz deiner Anwendung.
Was bedeutet external: true?
external: true bedeutet, dass Compose das Netzwerk als bereits vorhandene Ressource verwendet. Compose erstellt es nicht und meldet einen Fehler, wenn es fehlt. Der Eintrag name: fundus_proxy_net legt den tatsächlichen Docker-Netzwerknamen fest.
„External“ bezeichnet hier die Verwaltung außerhalb des jeweiligen Compose-Projekts. Es bedeutet keine automatische Freigabe ins Internet. Die Einzelheiten stehen in der Compose-Referenz für Netzwerke.
Wenn du die Projekte später über Dockhand verwaltest, muss das gemeinsame Netzwerk ebenfalls auf dem ausgewählten Zielhost existieren. Den Umgang mit vorhandenen Projekten beschreibt Docker-Stacks in Dockhand importieren und remote verwalten.
Docker-Netzwerke systematisch prüfen
Ändere bei einem Verbindungsfehler zunächst keine beliebigen Ports oder DNS-Einstellungen. Prüfe die Verbindung in dieser Reihenfolge:
- Laufen die beteiligten Container?
- Sind sie am erwarteten Netzwerk angeschlossen?
- Kann der anfragende Container den Zielnamen auflösen?
- Stimmen Zielport und Protokoll?
- Lauscht die Zielanwendung auf einer erreichbaren Schnittstelle?
- Funktioniert der Zugriff über Proxy und Host-Port?
1. Containerstatus und Protokolle prüfen
docker compose -f website/compose.yaml ps --all
docker compose -f proxy/compose.yaml ps --all
docker compose -f website/compose.yaml logs --tail=100 web
docker compose -f proxy/compose.yaml logs --tail=100 proxy
Mit --all werden auch gestoppte Container angezeigt. Achte auf Zustände wie Exited oder Restarting. Ein Container, der wegen einer fehlerhaften Konfiguration ständig beendet wird, lässt sich durch eine zusätzliche Portfreigabe nicht reparieren.
Beim Proxy kann die Meldung host not found in upstream darauf hinweisen, dass der Zielname beim Einlesen der Nginx-Konfiguration nicht auflösbar war. Prüfe dann zuerst Websitecontainer, Netzwerk und Alias.
Wenn eine Compose-Datei geändert wurde, übernimm die Änderung mit dem jeweiligen docker compose ... up -d-Aufruf. Ein bloßes restart übernimmt geänderte Netzwerkzuordnungen oder Portfreigaben aus der Datei nicht.
2. Gemeinsames Netzwerk kontrollieren
docker network ls
docker network inspect fundus_proxy_net
Im Abschnitt Containers der Netzwerkausgabe sollten Website und Proxy auftauchen. Fehlt einer der Container, prüfe dessen networks:-Zuordnung in der Compose-Datei.
Eine Definition unter dem obersten networks:-Abschnitt allein verbindet noch keinen ausdrücklich anders konfigurierten Dienst damit. Der Dienst muss das Netzwerk auch verwenden.
Kontrolliere bei unerwarteten Ergebnissen außerdem den Docker-Kontext. Ein mit derselben Compose-Datei auf einer anderen Engine gestarteter Container gehört nicht zu diesem Netzwerk.
3. DNS-Auflösung aus dem anfragenden Container testen
Teste den Zielnamen im Proxycontainer:
docker compose -f proxy/compose.yaml exec proxy nslookup fundus-web
Bei erfolgreicher Auflösung sollte eine Container-IP für fundus-web erscheinen. Scheitert die Auflösung, prüfe:
- Ist der Name richtig geschrieben?
- Läuft der Zielcontainer?
- Teilen sich beide Container das vorgesehene Netzwerk?
- Ist der Alias am richtigen Netzwerk eingetragen?
- Wurde derselbe Alias versehentlich mehrfach vergeben?
Die Resolver-Konfiguration des Proxycontainers kannst du so ansehen:
docker compose -f proxy/compose.yaml exec proxy cat /etc/resolv.conf
In benutzerdefinierten Docker-Netzwerken erscheint üblicherweise 127.0.0.11 als DNS-Server. Das ist der von Docker im Container bereitgestellte DNS-Endpunkt. Er kennt die Namen im angeschlossenen Docker-Netzwerk und leitet externe DNS-Anfragen weiter.
Eine Namensauflösung auf deinem PC prüft einen anderen Weg. Dass dein PC fundus-web nicht kennt, sagt daher nichts über Docker-DNS im Proxycontainer aus.
Bei anderen Images können nslookup oder eine Shell fehlen. Die Meldung command not found ist dann zunächst ein fehlendes Diagnosewerkzeug. Für einen zusätzlichen Netzwerktest kannst du einen Hilfscontainer verwenden:
docker run --rm --network fundus_proxy_net busybox:1.37 nslookup fundus-web
Dieser Test prüft den Zugang eines weiteren Containers zum Netzwerk. Individuelle DNS- oder Anwendungseinstellungen des ursprünglichen Containers werden damit nicht vollständig nachgebildet.
4. Internen Zielport und HTTP-Verbindung testen
Wenn der Name aufgelöst wird, teste aus dem Proxy die eigentliche HTTP-Verbindung:
docker compose -f proxy/compose.yaml exec proxy wget -S -O - -T 5 http://fundus-web:80/
-S zeigt die Antwortheader, -O - schreibt den Inhalt ins Terminal und -T 5 begrenzt die Wartezeit.
Das Ziel ist fundus-web:80. Der Host-Port 8080 gehört zum Proxyzugriff vom Host und ist kein Zielport der Website.
| Ergebnis | Was du daraus ableiten kannst |
|---|---|
| Name wird nicht aufgelöst | Zuerst Namen, Alias und Netzwerkzugehörigkeit prüfen. |
Connection refused |
Am angesprochenen Zielport lauscht häufig kein Dienst, oder die Verbindung wird aktiv abgewiesen. |
| Zeitüberschreitung | Unter anderem Routing, Filterregeln und den Zustand des Zieldienstes prüfen. |
HTTP 200 mit Testseite |
Die getestete HTTP-Verbindung zum Webdienst funktioniert. |
HTTP 401, 403 oder 404 |
Ein HTTP-Dienst antwortet. Anmeldung, Berechtigung, Hostname oder Pfad prüfen. |
HTTP 502 beim Browserzugriff über den Proxy |
Der Proxy antwortet, hat aber ein Problem mit der Kommunikation zum vorgeschalteten Ziel. Seine Logs grenzen die Ursache ein. |
Prüfe außerdem das Protokoll. Ein HTTP-Port wird durch die Portweiterleitung nicht zu einem HTTPS-Port. Für Datenbankverbindungen brauchst du einen passenden Datenbankclient; ein HTTP-Test ersetzt keinen PostgreSQL-, MySQL- oder SQL-Server-Verbindungstest.
5. Prüfen, auf welcher Schnittstelle die Anwendung lauscht
Ein Dienst kann im eigenen Container funktionieren und trotzdem für andere Container unerreichbar sein. Eine typische Ursache ist die Bindung an 127.0.0.1.
Teste zunächst im Websitecontainer selbst:
docker compose -f website/compose.yaml exec web wget -S -O - -T 5 http://127.0.0.1:80/
docker compose -f website/compose.yaml exec web netstat -lnt
Die Ausgabe von netstat zeigt die lauschenden TCP-Ports. Bei anderen Images kann dafür ss -lnt verfügbar sein.
127.0.0.1:80bedeutet: Der Dienst lauscht nur auf der Loopback-Schnittstelle dieses Containers.0.0.0.0:80bedeutet: Der Dienst lauscht auf allen IPv4-Schnittstellen dieses Containers.- Bei einer IPv6-Bindung an
::hängt die zusätzliche IPv4-Erreichbarkeit von Anwendung und Systemeinstellung ab.
Für eine über IPv4 aus anderen Containern erreichbare Anwendung ist häufig eine Bindung an 0.0.0.0 erforderlich. Welche Einstellung dafür zuständig ist, hängt von der Anwendung ab.
Die Bind-Adresse innerhalb des Containers und die Bind-Adresse einer Host-Portfreigabe sind zwei getrennte Einstellungen. Eine Anwendung kann im Container auf 0.0.0.0:80 lauschen, während Docker ihren veröffentlichten Host-Port auf 127.0.0.1:8080 begrenzt.
6. Host-Port und Zugriff von außen prüfen
Wenn der interne Websitezugriff funktioniert, kontrolliere die Veröffentlichung des Proxys:
docker compose -f proxy/compose.yaml port proxy 80
Für das Beispiel sollte die Zuordnung zu 127.0.0.1:8080 erscheinen. Die Zahl 80 im Befehl bezeichnet den Container-Port, dessen Host-Zuordnung du abfragst.
Teste unter Linux auf dem Docker-Host:
curl -v --connect-timeout 3 --max-time 10 http://127.0.0.1:8080/
Unter Windows kannst du auf dem Rechner mit Docker Desktop PowerShell verwenden:
Invoke-WebRequest -Uri 'http://127.0.0.1:8080/' -TimeoutSec 10
Ein Zugriff von einem anderen Gerät über die LAN-IP ist bei der gewählten Loopback-Bindung nicht vorgesehen. Soll der Dienst über das Netzwerk erreichbar sein, musst du die Host-Bindung bewusst anpassen und die dazugehörigen Firewall- und Zugriffsregeln prüfen.
Auf Linux erstellt Docker eigene Regeln für Portweiterleitung und Netzwerkisolation. Insbesondere bei UFW solltest du nicht annehmen, dass jede veröffentlichte Docker-Portfreigabe wie ein gewöhnlicher Hostdienst gefiltert wird. Die Zusammenhänge beschreibt Docker zu Paketfiltern und Firewalls.
7. Läuft der Container nur, oder ist die Anwendung bereit?
Der Zustand running bestätigt, dass der Container läuft. Eine Datenbank kann währenddessen noch initialisieren, und eine Anwendung kann noch Konfigurationen laden.
Innerhalb eines Compose-Projekts kann ein geeigneter healthcheck zusammen mit depends_on und condition: service_healthy den Start abhängiger Dienste steuern. Die einfache Form von depends_on wartet dagegen nicht auf die fachliche Betriebsbereitschaft.
Zwischen den beiden getrennten Projekten dieses Beispiels gibt es keine solche Compose-Abhängigkeit. Deshalb wird zuerst die Website gestartet und geprüft. Dauerhaft betriebene Anwendungen sollten außerdem Verbindungsabbrüche erkennen und Verbindungen erneut aufbauen können.
Weitere Einzelheiten erklärt die Docker-Dokumentation zur Startreihenfolge.
8. Nach einem Containerwechsel die Namensauflösung der Anwendung beachten
Die einfache Nginx-Konfiguration im Beispiel löst den fest eingetragenen Zielnamen beim Laden der Konfiguration auf. Wenn der Websitecontainer später neu erstellt wird und eine andere IP erhält, kann der laufende Proxy noch die vorherige Adresse verwenden.
Prüfe in diesem Fall zuerst, ob fundus-web aus dem Proxy korrekt aufgelöst wird und der direkte HTTP-Test funktioniert. Prüfe anschließend die Nginx-Konfiguration und lade sie nach erfolgreicher Prüfung neu:
docker compose -f proxy/compose.yaml exec proxy nginx -t
docker compose -f proxy/compose.yaml exec proxy nginx -s reload
Führe den zweiten Befehl nur aus, wenn der erste erfolgreich war. Bei einem nicht laufenden Proxy musst du zunächst dessen Startfehler beheben.
Für einen dauerhaften Betrieb mit häufig wechselnden Containern ist eine Proxykonfiguration mit dynamischer DNS-Auflösung sinnvoll. Nginx unterstützt dafür entsprechende Resolver- und Upstream-Konfigurationen. Ein interner Dienstname bleibt zwar gleich, doch die anfragende Anwendung muss Änderungen seiner IP auch berücksichtigen.
Aus einem Container auf einen Dienst des Docker-Hosts zugreifen
Manche Anwendungen müssen einen Dienst erreichen, der direkt auf dem Host läuft. Dafür verwendest du im Bridge-Container nicht dessen eigenes localhost.
Docker Desktop stellt den Namen host.docker.internal bereit. Läuft auf dem Host beispielsweise ein erreichbarer HTTP-Dienst auf Port 8000, lautet das Ziel aus dem Container http://host.docker.internal:8000.
Bei einer nativen Docker Engine unter Linux kannst du den Namen beim betreffenden Compose-Dienst auf das Host-Gateway abbilden. Dieser Ausschnitt gehört unter dessen Dienstdefinition:
extra_hosts:
- "host.docker.internal:host-gateway"
Der Hostdienst muss auf einer aus dem Container erreichbaren Host-Adresse lauschen. Unter einer nativen Linux-Engine reicht eine ausschließliche Bindung des Hostdienstes an 127.0.0.1 dafür normalerweise nicht. Prüfe außerdem die Host-Firewall.
Wenn das Ziel ebenfalls ein Container auf derselben Engine ist, bleibt ein gemeinsames Docker-Netzwerk mit Dienstnamen meist der direktere Verbindungsweg.
Gemeinsame Netzwerke gezielt begrenzen
Ein gemeinsames Netzwerk erleichtert die Verbindung zwischen Projekten. Es schafft gleichzeitig zusätzliche Erreichbarkeit: Angeschlossene Container können grundsätzlich die lauschenden Ports der anderen Teilnehmer ansprechen. Ein Netzwerkalias begrenzt diesen Zugriff nicht.
Bei einer Anwendung mit Datenbank ist deshalb häufig diese Aufteilung sinnvoll:
| Dienst | Gemeinsames Proxy-Netzwerk | Separates Backend-Netzwerk |
|---|---|---|
| Reverse Proxy | Ja | Nein |
| Webanwendung | Ja | Ja |
| Datenbank | Nein | Ja |
Die Webanwendung erreicht damit ihre Datenbank über das Backend-Netzwerk. Der Proxy braucht nur eine Verbindung zur Webanwendung. Eine zusätzliche Veröffentlichung des Datenbankports ist für diesen Aufbau nicht erforderlich.
Optional kann ein Backend-Netzwerk mit internal: true extern isoliert werden. Ein Container, der zusätzlich ein anderes Netzwerk mit externer Anbindung verwendet, kann darüber weiterhin externe Verbindungen besitzen. Prüfe deshalb vor allem, welche Dienste auf ausgehende Verbindungen angewiesen sind.
Das Beispiel wieder entfernen
Beende und entferne beide Beispielprojekte aus dem Ordner docker-netzwerk-demo:
docker compose -f proxy/compose.yaml down
docker compose -f website/compose.yaml down
Das als extern deklarierte Netzwerk bleibt erhalten. Wenn es anschließend kein anderes Projekt mehr benötigt, kannst du es gesondert entfernen:
docker network rm fundus_proxy_net
Die selbst angelegten Compose-, HTML- und Konfigurationsdateien bleiben dabei bestehen. Für dieses Beispiel ist kein down -v erforderlich.
Docker-Netzwerke im eigenen Setup anwenden
Lege für jede Verbindung zuerst fest, wer die Anfrage stellt und welcher Dienst das Ziel ist. Zwischen Containern im gemeinsamen Netzwerk verwendest du Dienstnamen oder eindeutige Aliase und den internen Zielport. Vom Browser oder einem anderen Rechner aus brauchst du eine dort erreichbare Adresse und den vorgesehenen veröffentlichten Zugang.
Wenn eine Verbindung scheitert, prüfst du anschließend Status, Netzwerkzugehörigkeit, DNS, Zielport und Listener. So lässt sich erkennen, ob das Problem tatsächlich im Docker-Netzwerk liegt oder bereits in der Anwendung, ihrer Konfiguration oder dem verwendeten Zugriffsweg.
Werbung / Affiliate-Links: Die mit einem Sternchen (*) gekennzeichneten Links sind Amazon-Partnerlinks. Wenn du darüber etwas kaufst, erhalte ich möglicherweise eine Provision. Für dich entstehen dadurch keine zusätzlichen Kosten. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen.
-
Kompakter Docker-Host: Mini-PC *
Für einen separaten, dauerhaft laufenden Docker-Host. Prüfe Betriebssystem, Ethernet-Anschluss, Stromverbrauch und Ausstattung.
→ Mini-PCs für einen kompakten Docker-Host bei Amazon ansehen*
-
Kurze Stromausfälle überbrücken: USV *
Kann Host, Router und Modem zeitweise weiter versorgen. Achte auf Gesamtleistung und gewünschte Überbrückungszeit.
-
Zusätzlicher Speicher: externe SSD *
Ein mögliches Medium für zusätzliche Sicherungen. Plane getrennte Kopien und teste die Wiederherstellung.
→ Externe SSDs für zusätzliche Sicherungen bei Amazon ansehen*
Weiterführende Informationen
- Docker: Bridge-Netzwerke und automatische Namensauflösung
- Docker: Netzwerke in Compose und Verbindungen zwischen Projekten
- Docker: Compose-Netzwerkreferenz mit external, name und internal
- Docker: Container-Ports veröffentlichen
- Docker Desktop: Hostdienste erreichen und Netzwerkprobleme eingrenzen
- Docker: Startreihenfolge und Betriebsbereitschaft von Diensten
- Nginx: proxy_pass und Namensauflösung
- Nginx: Konfiguration neu laden