it-swarm.com.de

Freigeben eines Ports in einem aktiven Docker-Container

Ich versuche, einen Docker-Container zu erstellen, der wie eine virtuelle Maschine wirkt. Ich weiß, dass ich die EXPOSE-Anweisung in einem Dockerfile verwenden kann, um einen Port freizugeben, und ich kann das -p-Flag mit docker run zum Zuweisen von Ports verwenden. Ist jedoch ein Container tatsächlich aktiv, gibt es einen Befehl zum Öffnen/Zuordnen zusätzlicher Ports live?

Angenommen, ich habe einen Docker-Container, auf dem sshd ausgeführt wird. Jemand, der den Container ssh verwendet, installiert und installiert httpd. Gibt es eine Möglichkeit, Port 80 des Containers verfügbar zu machen und Port 8080 auf dem Host zuzuordnen, sodass Benutzer den im Container ausgeführten Webserver besuchen können, ohne ihn neu zu starten?

349
reberhardt

Sie können dies nicht über Docker tun, aber Sie können über den Host-Computer auf den nicht freigelegten Port des Containers zugreifen.

wenn Sie einen Container haben, auf dessen Port 8000 etwas ausgeführt wird, können Sie ausführen 

wget http://container_ip:8000

Führen Sie die 2 Befehle aus, um die IP-Adresse des Containers abzurufen:

docker ps

docker inspect container_name | grep IPAddress

Wenn Sie ein Bild ausführen, ruft Docker intern die Möglichkeit auf, iptables anzurufen. Möglicherweise funktionieren einige Abweichungen davon.

um den Port 8000 des Containers auf Ihrem localhosts-Port 8001 verfügbar zu machen:

 iptables -t nat -A  DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000

Eine Möglichkeit, dies herauszufinden, besteht darin, einen anderen Container mit der gewünschten Portzuordnung einzurichten und die Ausgabe des Befehls iptables-save zu vergleichen (obwohl ich einige der anderen Optionen entfernen musste, die erzwingen Datenverkehr über den Docker-Proxy).

HINWEIS: Dies ist ein Unterlauf des Dockers, daher sollte mit der Gewissheit vorgegangen werden, dass möglicherweise blauer Rauch erzeugt wird.

ODER 

Eine andere Alternative ist, die (neue? Post 0.6.6?) -P-Option zu suchen, die zufällige Host-Ports verwendet und diese dann verdrahtet.

OR

mit 0.6.5 können Sie die LINKs-Funktion verwenden, um einen neuen Container aufzurufen, der mit dem vorhandenen kommuniziert, und zusätzlich zu den -p-Flags dieses Containers weitergeleitet. (Ich habe noch keine LINKs verwendet)

OR

mit Docker 0,11? Sie können docker run --net Host .. verwenden, um Ihren Container direkt an die Netzwerkschnittstellen des Hosts anzuhängen (dh das Netzwerk hat keinen Namen). Daher sind alle-Ports, die Sie im Container öffnen, verfügbar.

296
SvenDowideit

Folgendes würde ich tun:

  • Bestätigen Sie den Live-Container.
  • Führen Sie den Container erneut mit dem neuen Image mit offenen Ports aus.
Sudo docker ps 
Sudo docker commit <containerid> <foo/live>
Sudo docker run -i -p 22 -p 8000:80 -m /data:/data -t <foo/live> /bin/bash
129
bosky101

Sie können zwar keinen neuen Port eines vorhandenen Containers freigeben, aber Sie können einen neuen Container im selben Docker-Netzwerk starten und ihn dazu bringen, den Datenverkehr an den ursprünglichen Container weiterzuleiten.

# docker run \
  --rm \
  -p $PORT:1234 \
  verb/socat \
    TCP-LISTEN:1234,fork \
    TCP-CONNECT:$TARGET_CONTAINER_IP:$TARGET_CONTAINER_PORT

Gearbeitetes Beispiel

Starten Sie einen Webdienst, der Port 80 abhört, aber machen Sie nicht ​​seinen internen Port 80 verfügbar (oops!):

# docker run -ti mkodockx/docker-Pastebin   # Forgot to expose PORT 80!

Finden Sie die Docker-Netzwerk-IP:

# docker inspect 63256f72142a | grep IPAddress
                    "IPAddress": "172.17.0.2",

Starten verb/socat mit offengelegtem Port 8080 und Weiterleitung des TCP Datenverkehrs an den Port 80 dieser IP:

# docker run --rm -p 8080:1234 verb/socat TCP-LISTEN:1234,fork TCP-CONNECT:172.17.0.2:80

Sie können nun über http: // localhost: 8080 / auf Pastebin zugreifen, und Ihre Anforderungen gehen an socat:1234 der es weiterleitet an Pastebin:80, und die Antwort bewegt sich in umgekehrter Richtung.

34
RobM

Hier ist eine andere Idee. Verwenden Sie SSH, um die Portweiterleitung durchzuführen. Dies hat den Vorteil, dass Sie auch unter OS X (und wahrscheinlich auch unter Windows) arbeiten, wenn Ihr Docker Host eine VM ist.

docker exec -it <containterid> ssh -R5432:localhost:5432 <user>@<hostip>
32
Scott Carlson

IPtables-Hacks funktionieren nicht, zumindest auf Docker 1.4.1.

Der beste Weg wäre, einen anderen Container mit dem freigelegten Port und das Relay mit socat zu betreiben. Dies ist, was ich mit SQLPlus gemacht habe, um (vorübergehend) eine Verbindung zur Datenbank herzustellen:

docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus

Dockerfile:

FROM debian:7

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody

CMD socat -dddd TCP-LISTEN:1521,reuseaddr,fork TCP:db:1521
29
Ricardo Branco

Ich musste mich mit diesem Problem befassen und konnte es lösen, ohne meine laufenden Container zu stoppen. Dies ist eine Lösung, die seit Februar 2016 mit Docker 1.9.1 auf dem neuesten Stand ist. Diese Antwort ist eine detaillierte Version der Antwort von @ ricardo-branco, jedoch für neue Benutzer ausführlicher.

In meinem Szenario wollte ich vorübergehend eine Verbindung zu MySQL herstellen, das in einem Container ausgeführt wird. Da andere Anwendungscontainer mit diesem Container verbunden sind, war das Stoppen, Umkonfigurieren und erneutes Ausführen des Datenbankcontainers kein Starter.

Da ich gerne extern auf die MySQL-Datenbank zugreifen möchte (von Sequel Pro über SSH-Tunneln), verwende ich port 33306 auf dem Host-Computer. (Nicht 3306, nur für den Fall, dass eine äußere MySQL-Instanz ausgeführt wird.)

Etwa eine Stunde des Tweaking iptables erwies sich als fruchtlos, obwohl:

Schritt für Schritt, was ich getan habe:

mkdir db-expose-33306
cd db-expose-33306
vim Dockerfile

Bearbeiten Sie dockerfile und platzieren Sie dies in:

# Exposes port 3306 on linked "db" container, to be accessible at Host:33306
FROM ubuntu:latest # (Recommended to use the same base as the DB container)

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody
EXPOSE 33306

CMD socat -dddd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306

Dann baue das Bild:

docker build -t your-namespace/db-expose-33306 .

Dann führen Sie es aus und verknüpfen Sie mit Ihrem laufenden Container. (Verwenden Sie -d anstelle von -rm, um ihn im Hintergrund zu halten, bis er explizit gestoppt und entfernt wird. Ich möchte, dass er in diesem Fall nur vorübergehend ausgeführt wird.)

docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306  your-namespace/db-expose-33306
8
Excalibur

Um die Lösung " akzeptierte Antwortiptables" hinzuzufügen, musste ich zwei weitere Befehle auf dem Host ausführen, um sie nach außen zu öffnen.

Host> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
Host> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
Host> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https

Hinweis: Ich habe Port https (443) geöffnet, meine interne IP-Adresse des Dockers war 172.17.0.2.

Hinweis 2: Diese Regeln und das temporäre Verhalten gelten nur bis zum Neustart des Containers.

4
dstj

Sie können ein Overlay-Netzwerk wie Weave Net verwenden, das jedem Container eine eindeutige IP-Adresse zuweist und alle Ports implizit jedem Containerteil des Netzwerks zur Verfügung stellt.

Weave bietet auch Host-Netzwerkintegration . Sie ist standardmäßig deaktiviert. Wenn Sie jedoch auch vom Host aus auf die Container-IP-Adressen (und alle zugehörigen Ports) zugreifen möchten, führen Sie einfach weave expose aus.

Vollständige Offenlegung: Ich arbeite bei Weaveworks.

2
fons

Sie können SSH verwenden, um einen Tunnel zu erstellen und Ihren Container in Ihrem Host verfügbar zu machen.

Sie können dies auf zwei Arten tun, vom Container zum Host und vom Host zum Container. Sie benötigen jedoch ein SSH-Tool wie OpenSSH (Client in einem und Server in einem anderen).

In dem Container können Sie beispielsweise tun

$ yum install -y openssh openssh-server.x86_64
service sshd restart
Stopping sshd:                                             [FAILED]
Generating SSH2 RSA Host key:                              [  OK  ]
Generating SSH1 RSA Host key:                              [  OK  ]
Generating SSH2 DSA Host key:                              [  OK  ]
Starting sshd:                                             [  OK  ]
$ passwd # You need to set a root password..

Die Container-IP-Adresse finden Sie in dieser Zeile (im Container):

$ ifconfig eth0 | grep "inet addr" | sed 's/^[^:]*:\([^ ]*\).*/\1/g'
172.17.0.2

Dann können Sie im Host einfach Folgendes tun:

Sudo ssh -NfL 80:0.0.0.0:80 [email protected]
2
ton

Es gibt einen praktischen HAProxy-Wrapper.

docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_Host=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy

Dadurch wird ein HAProxy für den Zielcontainer erstellt. kinderleicht.

1
kwerle

Falls für jemanden keine Antwort funktioniert - prüfen Sie, ob Ihr Zielcontainer bereits im Docker-Netzwerk ausgeführt wird

docker inspect my-target-container | grep NetworkMode
        "NetworkMode": "my-network-name",

Wenn ja, sollten Sie den Proxy-Container in demselben Netzwerk ausführen.

docker inspect my-target-container | grep -A2 Aliases
                "Aliases": [
                    "my-alias",
                    "23ea4ea42e34a"

Endbefehl:

docker run --net my-network-name --name my-new-proxy \
-d -p 8080:1234 Alpine/socat TCP-LISTEN:1234,fork TCP-CONNECT:my-alias:80
1
ktalik

Lesen Sie zuerst die Antwort von Ricardo . Das hat bei mir funktioniert.

Es gibt jedoch ein Szenario, in dem dies nicht funktioniert, wenn der laufende Container mit Docker-Compose gestartet wurde. Dies liegt daran, dass Docker-Compose (ich arbeite Docker 1.17) ein neues Netzwerk erstellt. Die Lösung für dieses Szenario wäre

docker network ls

Hängen Sie dann folgendes an docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name

1
ice.nicer

Es ist nicht möglich, ein Live-Port-Mapping durchzuführen, es gibt jedoch mehrere Möglichkeiten, einem Docker-Container die Beträge zu geben, die einer realen Schnittstelle wie bei einer virtuellen Maschine entsprechen. 

Macvlan-Schnittstellen

Docker enthält jetzt einen Macvlan-Netzwerktreiber . Dadurch wird ein Docker-Netzwerk mit einer "realen Welt" -Schnittstelle verbunden, und Sie können diese Netzwerkadressen direkt dem Container zuweisen (z. B. überbrückte virtuelle Maschinen).

docker network create \
    -d macvlan \
    --subnet=172.16.86.0/24 \
    --gateway=172.16.86.1  \
    -o parent=eth0 pub_net

pipework kann auch eine reale Schnittstelle zuordnen in einen Container oder eine Unteroberfläche einrichten in älteren Versionen von Docker.

IP-Routing

Wenn Sie die Kontrolle über das Netzwerk haben, können Sie zusätzliche Netzwerke an Ihren Docker Host zur Verwendung in den Containern weiterleiten. 

Dann weisen Sie dieses Netzwerk den Containern zu und richten Ihren Docker-Host so ein, dass die Pakete über das Docker-Netzwerk weitergeleitet werden. 

Shared Host-Schnittstelle

Mit der Option --net Host kann die Hostschnittstelle in einem Container freigegeben werden. Dies ist jedoch aufgrund der gemeinsamen Natur wahrscheinlich keine gute Einrichtung für die Ausführung mehrerer Container auf einem Host. 

0
Matt

Hier sind einige Lösungen:

https://forums.docker.com/t/how-to-expose-port-on-running-container/3252/12

Die Lösung zum Zuordnen des Ports während der Container ausgeführt wird.

docker run -d --net = host myvnc

dadurch wird der Port automatisch dem Host angezeigt und zugeordnet

0
Ijaz Ahmad Khan