Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 02.06.2026 · 10 min Lesezeit

Docker-Netzwerke und Volumes richtig nutzen

Container finden sich nicht, Daten sind nach dem Neustart weg? Diese Anleitung zeigt user-defined Bridge-Netze mit DNS, Ports, Named Volumes und Bind-Mounts, Backup per tar und UID/GID-Fallen, getestet mit Docker 29.

Geprüft am 29.09.2026 · für docker-engine 29.1.3

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Netzwerk-Switch mit blauen und gelben Patchkabeln neben zwei gestapelten Speichergehäusen auf einem Holzregal

Container, die sich nicht finden, und Daten, die nach docker rm fehlen, haben meist dieselbe Ursache: falsch genutzte Docker-Netzwerke und Volumes. Alle Befehle gelten für Debian 12 oder Ubuntu 24.04 LTS und sind mit Docker Engine 29 getestet.

Voraussetzungen

  • Linux-Server mit Debian 12 oder Ubuntu 24.04 LTS und Docker Engine (siehe Docker installieren).
  • Ein Benutzer in der Gruppe docker oder Zugriff per sudo.
  • Docker Compose v2 (docker compose) für Schritt 9.
  • 1 CPU-Kern, 1 GB freier RAM, rund 1 GB Speicher für die Beispiel-Images (nginx, postgres, alpine, ubuntu), x86-64 oder ARM64.

Prüfen Sie vorab, ob Docker bereit ist:

docker version
docker info | grep -i 'Server Version'

Schritt 1: Default Bridge vs. user-defined Bridge verstehen

Jede frische Docker-Installation bringt drei Netzwerke mit:

docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
6f1a...        bridge    bridge    local
9c2b...        host      host      local
3d4e...        none      null      local

Im Default-Bridge-Netz bridge (docker0) erreichen sich Container nur per IP-Adresse, ohne Namensauflösung (außer über das veraltete --link).

Ein selbst angelegtes user-defined Bridge-Netz bietet zusätzlich:

  • DNS-Auflösung über Container-Namen und Aliase per eingebettetem DNS-Server (127.0.0.11), externe Namen über das Host-DNS.
  • Isolation: Nur Container im selben Netz erreichen sich.

Docker empfiehlt je Anwendung ein eigenes Netz.

Verifizieren: docker network ls zeigt die Netze bridge, host und none.

Schritt 2: Ein eigenes Netzwerk anlegen und inspizieren

Ohne weitere Angabe nutzt Docker den Treiber bridge mit DNS:

docker network create my-net

Subnetz und Gateway legen Sie selbst fest, etwa gegen Überschneidung mit dem Firmennetz:

docker network create -d bridge \
  --subnet=172.28.0.0/16 \
  --gateway=172.28.0.1 \
  br0

inspect zeigt Subnetz, Gateway und verbundene Container samt IPs:

docker network inspect my-net

Verwaltungsbefehle:

docker network ls                         # alle Netzwerke auflisten
docker network connect my-net mein-container      # laufenden Container ins Netz haengen
docker network disconnect my-net mein-container   # Container vom Netz trennen
docker network rm my-net                  # Netz loeschen (muss leer sein)
docker network prune                      # alle ungenutzten Netze entfernen

Verifizieren: docker network inspect my-net --format '{{.Driver}} {{range .IPAM.Config}}{{.Subnet}}{{end}}' gibt bridge und ein Subnetz aus, z. B. bridge 172.20.0.0/16.

Schritt 3: DNS-Auflösung über Container-Namen testen

Starten Sie Webserver und Datenbank im selben Netz. Ohne POSTGRES_PASSWORD beendet sich das PostgreSQL-Image sofort:

# Webserver: Port 8080 (Host) -> 80 (Container) nach aussen oeffnen
docker run -d --name web --network my-net -p 8080:80 nginx:latest

# Datenbank: KEIN -p, nur intern erreichbar
docker run -d --name db --network my-net -e POSTGRES_PASSWORD=bitte-aendern postgres:18

Namensauflösung per Wegwerf-Container im selben Netz prüfen:

docker run --rm --network my-net alpine ping -c2 db

Verifizieren: Der Ping liefert zwei Antworten von einer Adresse aus dem Subnetz von my-net, und docker ps zeigt web und db mit Status „Up“. Gegentest: Ohne --network my-net (Default-Bridge-Netz) scheitert derselbe Aufruf mit ping: bad address 'db'.

Schritt 4: Ports veröffentlichen vs. interne Kommunikation

  • -p / --publish macht einen Container-Port vom Host und potenziell aus dem Internet erreichbar: -p 8080:80 leitet Host-Port 8080 auf Container-Port 80.
  • Container im selben Netz brauchen untereinander kein -p. EXPOSE dokumentiert den Port nur.

Vorsicht: -p umgeht die UFW-Firewall

-p 8080:80 bindet standardmäßig an alle Interfaces (0.0.0.0). Docker schreibt eigene iptables-Regeln, die vor UFW greifen: Der Dienst bleibt erreichbar, obwohl UFW ihn scheinbar blockt. Für einen Reverse Proxy auf demselben Host binden Sie an Loopback:

# Container web aus Schritt 3 ersetzen, nur auf dem Host erreichbar:
docker rm -f web
docker run -d --name web --network my-net -p 127.0.0.1:8080:80 nginx:latest

Verifizieren: curl -I http://127.0.0.1:8080 auf dem Server liefert HTTP/1.1 200 OK, von einem anderen Rechner ist Port 8080 nicht erreichbar. docker port web zeigt 80/tcp -> 127.0.0.1:8080.

Die TLS-Freigabe nach außen zeigt die Anleitung nginx Reverse Proxy mit TLS.

Schritt 5: host- und none-Modus gezielt einsetzen

Zwei weitere Modi wählen Sie per --network:

ModusVerhaltenEinsatz
bridge (Default)eigenes virtuelles Netz, Port-Mapping per -pStandard für fast alles
hostteilt den Netzwerk-Stack des Hosts direkt; -p wird ignoriertnur wenn maximale Netzwerk-Performance nötig ist
nonegar kein Netzwerk, vollständige IsolationBatch-Jobs ohne Netzbedarf, Sicherheits-Sandbox
# host-Modus: nutzt den Host-Netzwerk-Stack direkt, -p wird ignoriert
# Achtung: nginx belegt dann Port 80 des Hosts
docker run -d --network host nginx:latest

# none-Modus: vollstaendige Netzwerk-Isolation
docker run -d --network none alpine sleep 1000

Der host-Modus birgt Port-Konflikte und Sicherheitsrisiken; nur wo nötig einsetzen.

Netz ohne Internetzugang (--internal)

Ein Netz ohne Default-Gateway und Internet, etwa für eine Datenbankschicht, erzeugt --internal:

docker network create --internal isoliert-net

Verifizieren: docker run --rm --network isoliert-net alpine wget -q -T3 -O- http://1.1.1.1 endet mit „Network unreachable“, docker run --rm --network none alpine ip addr zeigt nur das Loopback-Interface lo.

Schritt 6: Named Volumes vs. Bind-Mounts für persistente Daten

Änderungen im Container-Dateisystem gehen beim Löschen verloren. Für dauerhafte Daten gibt es zwei Wege:

AspektNamed VolumeBind-Mount
Verwaltungvollständig von Docker (unter /var/lib/docker/volumes/NAME/_data)konkreter Host-Pfad, von Ihnen verwaltet
Typischer EinsatzDatenbank-Daten, Anwendungs-StateConfig-Dateien, Quellcode in der Entwicklung
Vorbefüllungleeres Volume wird beim ersten Mount mit dem Image-Inhalt des Zielpfads gefülltüberdeckt vorhandene Container-Dateien (erscheint ggf. leer)

Docker empfiehlt die ausführlichere --mount-Syntax, -v funktioniert weiterhin:

docker volume create my-vol

# klassisch mit -v
docker run -d --name app -v my-vol:/data nginx:latest

# bevorzugt mit --mount (expliziter)
docker run -d --name app2 --mount type=volume,src=my-vol,dst=/data nginx:latest

Ein Bind-Mount bindet einen absoluten Host-Pfad ein, :ro bzw. readonly verhindert Schreibzugriffe:

# Bind-Mount, read-only, mit -v
docker run -d --name app3 -v /srv/appdata:/data:ro nginx:latest

# Bind-Mount mit --mount (Quelle MUSS existieren)
docker run -d --name app4 --mount type=bind,src=/srv/appdata,dst=/data nginx:latest

Unterschiede der Syntaxen:

  • Fehlende Quelle: -v legt das Host-Verzeichnis als root an, --mount type=bind bricht mit „bind source path does not exist“ ab.
  • SELinux-Labels (z = geteilt, Z = privat) gehen nur mit -v. Relevant auf RHEL/Fedora; Debian/Ubuntu nutzen AppArmor.

Verwaltung wie bei Netzwerken:

docker volume ls               # alle Volumes auflisten
docker volume inspect my-vol   # Mountpoint und Details anzeigen
docker volume rm my-vol        # einzelnes Volume loeschen
docker volume prune            # ungenutzte Volumes entfernen (Vorsicht!)

Anonyme Volumes erhalten einen Zufallsnamen; docker run --rm und docker rm -v löschen sie mit, docker rm allein nicht. Named Volumes bleiben.

Verifizieren: docker volume inspect my-vol zeigt den Mountpoint /var/lib/docker/volumes/my-vol/_data. Die Vorbefüllung prüfen Sie mit einem frischen Volume: docker run --rm -v test-vol:/usr/share/nginx/html nginx:latest ls /usr/share/nginx/html zeigt 50x.html und index.html aus dem Image.

Schritt 7: Ein Volume sichern und wiederherstellen (tar)

Ein kurzlebiger Hilfscontainer hängt das Named Volume ein und schreibt es per tar ins aktuelle Verzeichnis:

# Named Volume direkt nach my-vol.tar.gz sichern (gzip)
docker run --rm \
  -v my-vol:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/my-vol.tar.gz -C /data .

Die Methode der Docker-Doku übernimmt per --volumes-from die Volumes eines bestehenden Containers (hier dbstore, angelegt mit docker create -v /dbdata --name dbstore ubuntu /bin/bash):

# Sichern: Volumes von dbstore nach backup.tar im aktuellen Verzeichnis
docker run --rm --volumes-from dbstore \
  -v $(pwd):/backup \
  ubuntu tar cvf /backup/backup.tar /dbdata
# Wiederherstellen in einen Container dbstore2
docker run --rm --volumes-from dbstore2 \
  -v $(pwd):/backup \
  ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"

Datenbanken vorher stoppen oder per Dump (pg_dump, mysqldump) sichern, sonst droht eine inkonsistente Kopie.

Verifizieren: tar tzf my-vol.tar.gz listet die Dateien des Volumes. Nach dem Restore zeigt docker run --rm --volumes-from dbstore2 ubuntu ls -R /dbdata dieselben Dateien wie im Original.

Schritt 8: Die UID/GID-Falle vermeiden

Häufigste Stolperfalle bei Bind-Mounts sind Besitzrechte: Container laufen standardmäßig als root (UID 0), Dateien im Bind-Mount gehören auch auf dem Host root. Läuft die Anwendung als anderer Benutzer, folgt Permission denied.

Drei saubere Lösungen, kein dauerhaftes chmod 777:

# 1) Ownership eines Named Volumes einmalig auf UID:GID 1000 setzen
docker run --rm -v my-vol:/data alpine chown -R 1000:1000 /data
# 2) Container mit der UID/GID des Host-Users starten,
#    damit erzeugte Dateien dem Host-User gehoeren
docker run -u $(id -u):$(id -g) -v /srv/appdata:/data alpine touch /data/test.txt

Dritte Variante: Entrypoint-chown oder Init-Container setzt die Rechte beim Start, danach läuft die Anwendung ohne root.

Verifizieren: ls -ln /srv/appdata zeigt test.txt mit der UID/GID Ihres Benutzers (z. B. 1000 1000), eine ohne -u geschriebene Datei dagegen 0 0. docker run --rm -v my-vol:/data alpine stat -c '%u:%g' /data liefert nach Lösung 1 1000:1000.

Schritt 9: Netzwerke und Volumes in Docker Compose

Compose legt automatisch ein Netz PROJEKT_default an; Services erreichen sich über den Service-Namen. Ab PostgreSQL 18 gehört das Volume nach /var/lib/postgresql statt /var/lib/postgresql/data, sonst startet der Container nicht:

services:
  web:
    image: nginx:latest
    ports:
      - "127.0.0.1:8080:80"   # nur lokal erreichbar
    networks:
      - frontend
      - backend
    depends_on:
      - db

  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: bitte-aendern
    volumes:
      - db-data:/var/lib/postgresql   # Named Volume, ab PostgreSQL 18 dieser Pfad
    networks:
      - backend   # KEIN ports: -> db ist nur intern erreichbar

networks:
  frontend:
  backend:
    internal: true   # backend hat keinen Internetzugang

volumes:
  db-data:

Starten und prüfen:

docker compose up -d
docker compose ps
docker compose exec web getent hosts db   # DNS ueber den Service-Namen db

Das nginx-Image enthält kein ping, daher prüft getent hosts die Auflösung. external: true bindet vorhandene Netze oder Volumes ein.

Verifizieren: docker compose ps zeigt web und db mit „Up“, getent hosts db gibt eine IP und db aus, curl -I http://127.0.0.1:8080 liefert 200 OK, docker compose exec db pg_isready meldet „accepting connections“. Die Datenbank hat keinen Internetzugang, web dagegen schon, weil es zusätzlich im Netz frontend hängt. Mehr in der Anleitung zu Docker Compose und Stacks.

Troubleshooting

  • „ping: bad address 'db'“: Container im Default-Bridge-Netz. Eigenes Netz anlegen (Schritt 2 und 3).
  • Dienst trotz UFW-Block erreichbar: Port an 127.0.0.1 binden (Schritt 4).
  • „Permission denied“ beim Schreiben ins Volume: UID/GID passen nicht, Lösungen in Schritt 8.
  • --mount-Fehler „bind source path does not exist“: Host-Verzeichnis vorher anlegen oder -v nutzen, wenn es automatisch entstehen darf.
  • Zielordner im Bind-Mount leer: Der Bind-Mount verdeckt die Image-Dateien; zur Vorbefüllung ein Named Volume nutzen.
  • Daten nach Aufräumen weg: docker volume prune und docker system prune --volumes löschen ungenutzte Volumes samt Daten. Vorher docker volume ls prüfen.
  • host-Modus: Port-Konflikt: Der Container belegt Host-Ports direkt. Bridge-Netz mit Port-Mapping nutzen.
  • PostgreSQL-Container beendet sich sofort: POSTGRES_PASSWORD fehlt, oder bei Version 18 liegt das Volume unter /var/lib/postgresql/data („unused mount/volume“); richtig ist /var/lib/postgresql.

Häufige Fragen

Warum funktioniert ping über den Container-Namen nicht?

Default-Bridge-Netz ohne Namensauflösung; eigenes Netz wie in Schritt 2 und 3 anlegen.

Brauche ich -p, damit zwei Container miteinander reden?

Nein. -p dient nur dem Zugriff vom Host oder von außen (Schritt 4).

Named Volume oder Bind-Mount – was nehme ich?

Named Volume für Anwendungs- und Datenbankdaten, Bind-Mount für Konfiguration oder Quellcode (Tabelle in Schritt 6).

Wie sichere ich ein Volume regelmäßig?

Mit dem tar-Befehl aus Schritt 7 per Cron; Datenbanken vorher stoppen oder dumpen.

Überlebt ein Named Volume das Löschen des Containers?

Ja. Named Volumes entfernen nur docker volume rm oder docker volume prune; anonyme Volumes löschen docker run --rm und docker rm -v mit.

-v oder --mount?

Beide funktionieren, empfohlen ist --mount (Unterschiede in Schritt 6).

Fazit

Zwei Regeln tragen fast jedes Setup: ein user-defined Bridge-Netz je Anwendung und Named Volumes für Daten. Ports nur bei Bedarf veröffentlichen, interne Dienste an 127.0.0.1 binden, UID/GID beachten; Vorlage ist Schritt 9.

Weiterführende Anleitungen und Quellen

Quellen: Docker Docs – Bridge network driver, Docker Docs – Volumes, Docker Docs – Bind mounts und Docker Docs – Networking in Compose.