744 Stimmen

Was ist der Unterschied zwischen "expose" und "publish" in Docker?

Ich experimentiere mit Dockerfiles, und ich glaube, dass ich die meisten der Logik verstehe. Allerdings sehe ich den Unterschied zwischen "exposing" und "publishing" eines Ports in diesem Kontext nicht.

All die Tutorials, die ich gesehen habe, beinhalten zuerst den EXPOSE Befehl im Dockerfile:

...
EXPOSE 8080
...

Dann bauen sie ein Image aus diesem Dockerfile:

$ docker build -t an_image - < Dockerfile

Und dann publishen sie denselben Port wie oben beim Ausführen des Images:

$ docker run -d -p 8080 an_image

oder sie veröffentlichen alle Ports mit

$ docker run -d -P an_image

Was ist der Sinn darin, einen Port im Dockerfile freizugeben, wenn er sowieso veröffentlicht wird? Gäbe es jemals ein Bedürfnis, zuerst einen Port freizugeben und ihn später nicht zu veröffentlichen? Effektiv möchte ich alle Ports, die ich im Dockerfile beim Erstellen des Images verwenden werde, angeben und mich dann einfach damit befassen, sie erneut auszuführen:

$ docker run -d an_image

Ist das möglich?

944voto

Golo Roden Punkte 125652

Im Grunde hast du drei (vier) Optionen:

  1. Weder EXPOSE noch -p spezifizieren

  2. Nur EXPOSE spezifizieren

  3. EXPOSE und -p spezifizieren

  4. Nur -p spezifizieren, was implizit auch EXPOSE macht

  5. Wenn du weder EXPOSE noch -p spezifizierst, ist der Service im Container nur von innerhalb des Containers aus zugänglich.

  6. Wenn du einen Port mit EXPOSE zugänglich machst, ist der Service im Container nicht von außerhalb von Docker aus erreichbar, sondern nur von innerhalb anderer Docker-Container. Das ist also gut für die Kommunikation zwischen Containern.

  7. Wenn du einen Port mit EXPOSE und -p zugänglich machst, ist der Service im Container von überall aus erreichbar, sogar von außerhalb von Docker.

  8. Wenn du -p verwendest, aber nicht EXPOSE, führt Docker implizit ein EXPOSE durch. Das liegt daran, dass wenn ein Port für die Öffentlichkeit geöffnet ist, er automatisch auch für andere Docker-Container geöffnet ist. Daher beinhaltet -p auch EXPOSE. Das ist effektiv das Gleiche wie 3).

Meiner Meinung nach sind beide getrennt, weil:

  • die Auswahl eines Host-Ports vom Host abhängt und somit nicht in das Dockerfile gehört (ansonsten wäre es abhängig vom Host),
  • und oft reicht es aus, wenn ein Service in einem Container von anderen Containern aus erreichbar ist.

Die Dokumentation besagt ausdrücklich:

Die Anweisung EXPOSE öffnet Ports für die Verwendung innerhalb von Links.

Sie zeigt auch, wie man Container verlinkt (veraltetes Feature), was im Grunde die von mir angesprochene Inter-Container-Kommunikation ist.

375voto

tgogos Punkte 19599

Kurze Antwort:

  • EXPOSE ist eine Möglichkeit, zu dokumentieren
  • --publish (oder -p) ist eine Möglichkeit, einen Host-Port auf einen laufenden Container-Port zuzuweisen

Beachten Sie unten, dass:

  • EXPOSE im Zusammenhang mit Dockerfiles steht ( dokumentieren )
  • --publish steht im Zusammenhang mit docker run ... ( Ausführung / Laufzeit )

Ports freigeben und veröffentlichen

In der Docker-Netzwerkkonfiguration gibt es zwei verschiedene Mechanismen, die direkt Netzwerkports betreffen: Ports freigeben und veröffentlichen. Dies gilt für das Standard-Brücken-Netzwerk und benutzerdefinierte Brücken-Netzwerke.

  • Sie geben Ports mit dem Schlüsselwort EXPOSE in der Docker-Datei oder dem Flag --expose bei docker run frei. Das Freigeben von Ports ist eine Möglichkeit, zu dokumentieren, welche Ports verwendet werden, öffnet oder weist jedoch keine Ports tatsächlich zu. Das Freigeben von Ports ist optional.

  • Sie veröffentlichen Ports mit dem Flag --publish oder --publish-all bei docker run. Dies teilt Docker mit, welche Ports auf der Netzwerkschnittstelle des Containers geöffnet werden sollen. Wenn ein Port veröffentlicht wird, wird er auf einem verfügbaren Hochordnungsport (höher als 30000) auf dem Host-Rechner abgebildet, es sei denn, Sie geben den Port an, auf den er zur Laufzeit auf dem Host-Rechner abgebildet werden soll. Sie können den Port, auf den er zur Laufzeit auf dem Host-Rechner abgebildet werden soll, nicht angeben, wenn Sie das Image erstellen (in der Docker-Datei), da es keine Möglichkeit gibt, sicherzustellen, dass der Port auf dem Host-Rechner verfügbar ist, auf dem Sie das Image ausführen.

aus: Docker-Container-Netzwerk

Update Oktober 2019: Der obige Text ist nicht mehr in den Dokumenten enthalten, aber eine archivierte Version ist hier zu finden: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

Vermutlich ist die aktuelle Dokumentation die folgende:

Veröffentlichte Ports

Standardmäßig werden bei der Erstellung eines Containers keine Ports nach außen freigegeben. Um einen Port für Dienste außerhalb von Docker oder für Docker-Container verfügbar zu machen, die nicht mit dem Netzwerk des Containers verbunden sind, verwenden Sie das Flag --publish oder -p. Dies erstellt eine Firewall-Regel, die einen Containerport auf einem Port des Docker-Hosts abbildet.

und kann hier gefunden werden: docs.docker.com/config/containers/container-networking/#published-ports

Außerdem,

EXPOSE

...Die Anweisung EXPOSE veröffentlicht den Port nicht tatsächlich. Es fungiert als eine Art Dokumentation zwischen der Person, die das Image erstellt, und der Person, die den Container ausführt, über welche Ports veröffentlicht werden sollen.

aus: Dockerfile-Referenz


Dienstzugriff, wenn EXPOSE / --publish nicht definiert sind:

In der Antwort von @Golo Roden wird angegeben, dass:

"Wenn Sie keine davon spezifizieren, ist der Service im Container nur aus diesem selbst heraus erreichbar."

Vielleicht war das zum Zeitpunkt der Antwort der Fall, aber jetzt scheint es, dass auch wenn Sie EXPOSE oder --publish nicht verwenden, der Host und andere Container im selben Netzwerk auf einen Dienst zugreifen können, den Sie möglicherweise in diesem Container starten.

So testen Sie dies:

Ich habe das folgende Dockerfile verwendet. Grundsätzlich starte ich mit Ubuntu und installiere einen kleinen Webserver:

FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd

Ich baue das Image als "testexpose" und führe einen neuen Container mit dem folgenden Befehl aus:

docker run --rm -it testexpose bash

Im Container starte ich ein paar Instanzen von mini-httpd:

root@fb8f7dd1322d:/# mini_httpd -p 80
root@fb8f7dd1322d:/# mini_httpd -p 8080
root@fb8f7dd1322d:/# mini_httpd -p 8090

Ist dann in der Lage, mit curl vom Host oder anderen Containern abzurufen, um die Startseite von mini-httpd abzurufen.


Weiterführende Informationen

Sehr detaillierte Artikel zum Thema von Ivan Pepelnjak:

15voto

ton Punkte 3011

Siehe die offizielle Dokumentationsreferenz: https://docs.docker.com/engine/reference/builder/#expose

Das EXPOSE ermöglicht es Ihnen, private (Container-) und öffentliche (Host-) Ports zur Image-Build-Zeit zu definieren, wenn der Container ausgeführt wird wenn Sie den Container mit -P ausführen.

$ docker help run
...
  -P, --publish-all                    Veröffentlichen Sie alle freigegebenen Ports an zufälligen Ports
...

Der öffentliche Port und das Protokoll sind optional, wenn kein öffentlicher Port angegeben ist, wird von Docker ein zufälliger Port auf dem Host ausgewählt, um den angegebenen Container-Port im Dockerfile freizugeben.

Eine gute Praxis ist es, keinen öffentlichen Port zu spezifizieren, da dies nur einen Container pro Host (ein zweiter Container würde einen Port bereits in Verwendung melden) beschränkt.

Sie können -p in docker run verwenden, um zu steuern, mit welchem öffentlichen Port die freigegebenen Container-Ports verbindbar sein werden.

Wie auch immer, wenn Sie weder EXPOSE (mit -P bei docker run) noch -p verwenden, werden keine Ports freigegeben.

Wenn Sie immer -p bei docker run verwenden, benötigen Sie kein EXPOSE, aber wenn Sie EXPOSE verwenden, kann Ihr docker run Befehl einfacher sein, EXPOSE kann nützlich sein, wenn es Ihnen egal ist, welcher Port auf dem Host freigegeben wird, oder wenn Sie sicher sind, dass nur ein Container geladen wird.

12voto

mzalazar Punkte 5722

Sie können Ports mithilfe des EXPOSE-Schlüsselworts in der Dockerfile oder des --expose-Flags für docker run. Das Exponieren von Ports ist eine Möglichkeit zu dokumentieren, welche Ports verwendet werden, aber es werden keine Ports tatsächlich zugeordnet oder geöffnet. Das Exponieren von Ports ist optional.

Quelle: github commit

6voto

herm Punkte 15093

Die meisten Menschen verwenden Docker Compose mit Netzwerken. Die Dokumentation besagt:

Die Docker-Netzwerkfunktion unterstützt das Erstellen von Netzwerken, ohne Ports innerhalb des Netzwerks freizugeben. Weitere Informationen finden Sie im Überblick über dieses Feature).

Das bedeutet, dass Sie sich keine Sorgen machen müssen, Ports freizugeben, wenn Sie Netzwerke zur Kommunikation zwischen Containern verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X