Kurze Antwort: Das geht nicht. Docker hat keine unterstützte Möglichkeit, einem bereits laufenden Container einen veröffentlichten Port hinzuzufügen. Port-Zuordnungen werden bei der Container-Erstellung festgelegt, und weder docker run noch docker container update können sie nachträglich ändern. Das Flag --publish-add existiert nur für Swarm-Dienste, nicht für eigenständige Container.
Wenn Sie den Container nicht neu starten können, sind dies die Optionen, die tatsächlich funktionieren:
| Ansatz | Fügt eine echte Docker-Port-Zuordnung hinzu? | Funktioniert auf Docker Desktop (macOS/Windows)? | Überlebt Neustart? |
|---|---|---|---|
socat-Sidecar-Container |
Nein (TCP-Weiterleitung) | Ja | Ja, wenn der Sidecar neu startet |
| Reverse Proxy (Nginx/Traefik/HAProxy) | Nein (proxied) | Ja | Ja |
Host-iptables-DNAT |
Nein (Host-NAT-Regel) | Nein, nur natives Linux | Nein, außer dauerhaft gespeichert |
Container mit -p neu erstellen |
Ja | Ja | Ja |
Der einzige Ansatz, der eine echte, von Docker verwaltete veröffentlichte Port-Zuordnung erzeugt – die in docker ps und docker port angezeigt wird – ist die Neuerstellung des Containers. Alles andere leitet den Datenverkehr auf einer Ebene oberhalb oder unterhalb der Docker-Port-Buchhaltung weiter. Wählen Sie basierend darauf, ob Sie einen Neustart tolerieren können, und lesen Sie die untenstehenden Hinweise, bevor Sie etwas in der Produktion ausführen.
Dieser Artikel erklärt jede Methode, die genauen Befehle und wo jede versagt.
Hintergrund: Wie Docker-Port-Zuordnung funktioniert
Grundlegende Prinzipien der Container-Port-Zuordnung
In Docker wird die Verbindung zwischen einem internen Port eines Containers und dem Host-Port über Port-Zuordnung hergestellt. Normalerweise geben wir Port-Zuordnungen mit den Parametern -p oder --publish beim Starten eines Containers an, wie unten gezeigt:
docker run -d -p 8080:80 nginx
Der obige Befehl bildet Port 8080 auf dem Host auf Port 80 im Container ab. Dadurch können externe Benutzer den im Container laufenden Webdienst über Port 8080 auf dem Host erreichen.
Warum Docker dies nicht erlaubt
Sobald ein Container gestartet ist, unterstützt Docker im Allgemeinen nicht das dynamische Hinzufügen neuer Port-Zuordnungen. Mit anderen Worten, die anfänglichen Port-Zuordnungen bleiben während des gesamten Lebenszyklus des Containers fest. Wenn Sie weitere Port-Zuordnungen hinzufügen müssen, besteht der traditionelle Ansatz darin, den Container zu stoppen und neu zu starten, was Dienste unterbrechen kann und in Produktionsumgebungen inakzeptabel ist.
Die vier Workarounds
Um dynamisch Port-Zuordnungen zu einem laufenden Container hinzuzufügen, können mehrere Methoden eingesetzt werden:
2.1 Sidecar-Container, der den Port weiterleitet (empfohlen)
Ein separater Container veröffentlicht den neuen Host-Port und leitet den Datenverkehr über ein gemeinsames Docker-Netzwerk an den ursprünglichen Container weiter. Dies ist die sicherste Option, da der ursprüngliche Container nie berührt wird.
Eine wichtige Korrektur zuerst: Sie können --network container:<name> nicht mit -p kombinieren. Die Docker-Netzwerkdokumentation stellt klar, dass --publish, --publish-all und --expose nicht unterstützt werden für Container, die den Netzwerkmodus container: verwenden, da ein solcher Container keinen eigenen Netzwerk-Namespace hat, in den Ports abgebildet werden könnten. Jede Anleitung, die Ihnen sagt, docker run -p 8081:81 --net container:your-container ... auszuführen, ist falsch, und Docker wird dies ablehnen.
Das funktionierende Muster verwendet ein benutzerdefiniertes Netzwerk, damit der Sidecar das Ziel per Containername erreichen kann:
# 1. Ein Netzwerk erstellen und den laufenden Container daran anschließen (kein Neustart erforderlich)
docker network create app-net
docker network connect app-net your-container
# 2. Einen socat-Sidecar starten, der 8081 veröffentlicht und an Port 81 des Ziels weiterleitet
docker run -d --name port-sidecar \
--network app-net \
--restart unless-stopped \
-p 8081:81 \
alpine/socat \
TCP-LISTEN:81,fork,reuseaddr TCP:your-container:81
Beachten Sie, dass docker network connect auf einem laufenden Container funktioniert, daher verursacht Schritt 1 keine Ausfallzeit. Der Sidecar hört auf Port 81 in seinem eigenen Namespace, und -p 8081:81 veröffentlicht diesen auf dem Host.
Einschränkungen:
- Dies ist eine TCP-Weiterleitung, keine Docker-Port-Zuordnung. Sie wird nicht in
docker port your-containerangezeigt. alpine/socatleitet nur TCP weiter. Für UDP verwenden SieUDP-LISTEN/UDP, und für HTTP mit hostbasiertem Routing bevorzugen Sie Nginx, Traefik, Caddy oder HAProxy.- Fügen Sie
--restart unless-stoppedhinzu (wie oben), sonst verschwindet die Weiterleitung nach einem Neustart. - Der zusätzliche Hop verursacht eine geringe Latenz und fügt einen weiteren zu überwachenden Prozess hinzu.
2.2 Host-iptables-DNAT-Regel (nur natives Linux)
Auf einem nativen Linux-Host können Sie eine DNAT-Regel hinzufügen, die einen Host-Port an die interne IP des Containers weiterleitet:
# Container-IP ermitteln
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' your-container)
# Host-Port 8081 an Container-Port 81 weiterleiten
sudo iptables -t nat -A DOCKER -p tcp --dport 8081 \
-j DNAT --to-destination "${CONTAINER_IP}:81"
Dies gibt Ihnen eine feinkörnige Kontrolle, birgt jedoch das größte operationelle Risiko aller hier genannten Methoden:
- Docker Desktop auf macOS und Windows funktioniert so nicht. Container laufen in einer Linux-VM, daher berühren
iptables-Regeln auf Ihrer Maschine nicht den Netzwerkpfad von Docker. Diese Methode ist nur für natives Linux. - Regeln bleiben nicht dauerhaft. Sie gehen bei Neustart, Firewall-Neuladung oder einem Wechsel zwischen nftables/iptables verloren. Verwenden Sie den Persistenzmechanismus Ihrer Distribution, wenn sie überleben sollen.
- Docker besitzt die
DOCKER-Kette. Docker erstellt und verwaltet diese Regeln aus der Port-Konfiguration laufender Container, und seine Dokumentation besagt, dass Sie die von Docker erstellten Regeln nicht ändern sollten. Für benutzerdefinierte Filterung hat DockerDOCKER-USERals Platzhalter für benutzerdefinierte Regeln vorgesehen, da Regeln, die anFORWARDangehängt werden, nach Docks eigenen Regeln verarbeitet werden. - Container-IPs sind nicht stabil. Die Adresse ändert sich, wenn der Container neu erstellt wird, und hinterlässt eine veraltete Regel, die still ins Leere leitet.
- Umgeht die Docker-Buchhaltung. Der Port wird nicht in
docker psoderdocker portangezeigt.
2.3 Ausführen von socat direkt auf dem Host
Sie können socat auch als einfachen Host-Prozess statt in einem Container ausführen:
socat TCP-LISTEN:8081,fork,reuseaddr TCP:<container_ip>:81
Dies funktioniert auf nativem Linux, wo die Container-IP vom Host aus erreichbar ist. Auf Docker Desktop für macOS und Windows ist die Container-IP nicht von Ihrer Maschine aus erreichbar, verwenden Sie daher den Sidecar aus Abschnitt 2.1. In jedem Fall benötigen Sie einen Prozess-Supervisor (systemd oder --restart auf dem Sidecar), um Neustarts zu überleben, da ein bloßer socat-Prozess mit seiner Shell stirbt.
2.4 Neuerstellen des Dienstes mit Docker Compose
Dies ist die einzige Methode, die einen echten, von Docker verwalteten veröffentlichten Port liefert. Fügen Sie die Zuordnung in compose.yaml hinzu:
services:
app:
image: your-image:tag
ports:
- "8081:81"
Erstellen Sie dann nur diesen Dienst neu:
docker compose up -d app
Compose erstellt den Container neu, daher gibt es eine kurze Unterbrechung – dies ist keine Live-Änderung. Beachten Sie, dass modernes Docker docker compose (ein Unterbefehl) verwendet, nicht das ältere eigenständige docker-compose-Binary. Halten Sie den Zustand in benannten Volumes oder Bind Mounts, damit er die Neuerstellung überlebt.
2.5 Bearbeiten von Docker-internen Konfigurationsdateien (nicht empfohlen)
Sie werden Ratschläge finden, /var/lib/docker/containers/<id>/config.v2.json und hostconfig.json von Hand zu bearbeiten, um einen PortBindings-Eintrag hinzuzufügen, und dann den Daemon neu zu starten. Es funktioniert manchmal, aber behandeln Sie es als letzten Ausweg:
- Dies sind interne Implementierungsdateien ohne Stabilitätsgarantien, keine unterstützte API. Das Format kann sich zwischen Docker-Versionen ändern.
- Der Daemon hält den Container-Status im Speicher. Das Bearbeiten von Dateien unter einem laufenden Daemon birgt das Risiko, dass Ihre Änderungen überschrieben werden, und unvollständige Bearbeitungen können den Netzwerkstatus des Containers inkonsistent mit seinen Metadaten machen.
- Sie müssen den Daemon vor dem Bearbeiten stoppen, was alle Container auf dem Host betrifft.
- Wenn
live-restoreaktiviert ist, laufen Container über einen Daemon-Neustart hinweg weiter – aber das wendet keine bearbeitete Port-Zuordnung an. Live-Restore ändert nicht die Regel, dass ein neuer veröffentlichter Port eine Container-Neuerstellung erfordert.
Wenn Sie an dem Punkt sind, Daemon-Status von Hand zu bearbeiten, ist das Neuerstellen des Containers mit dem korrekten -p-Flag schneller und sicherer.
Fazit
Docker unterstützt nicht das Hinzufügen eines veröffentlichten Ports zu einem laufenden Container, und kein Workaround ändert das. Was die obigen Methoden Ihnen bieten, ist eine Möglichkeit, neuen Datenverkehr zu einem Container zu leiten, den Sie nicht neu starten können.
Wählen Sie in dieser Reihenfolge:
- Können Sie einen kurzen Neustart tolerieren? Erstellen Sie den Container mit dem richtigen
-p-Flag neu oder fügen Sieports:incompose.yamlein und führen Siedocker compose up -daus. Dies ist die einzige Methode, die eine echte Docker-Port-Zuordnung erzeugt. - Kein Neustart möglich? Verwenden Sie den
socat-Sidecar aus Abschnitt 2.1 oder einen Reverse-Proxy, wenn Sie HTTP-Routing, TLS oder Health Checks benötigen. - Natives Linux und brauchen eine schnelle temporäre Weiterleitung? Eine
iptables-DNAT-Regel funktioniert, aber persistieren Sie sie bewusst und erwarten Sie, dass Docker in seine eigenen Ketten eingreift. - Vermeiden Sie das Bearbeiten von Daemon-Konfigurationsdateien von Hand.
Wenn sich Port-Zuordnungen häufig ändern, ist das normalerweise ein Designsignal: Stellen Sie von Anfang an einen Reverse-Proxy vor den Dienst und lassen Sie ihn die hostseitigen Ports verwalten, sodass Container-Lebenszyklus und Routing unabhängig bleiben.
Quellen: Docker: Veröffentlichen von Ports, Docker: Container-Netzwerkmodi, Docker: Paketfilterung und Firewalls, Docker und iptables, docker container port.
Sie können Novita AI für GPU-Instanzen und Modell-APIs besuchen.
