Quelle est la différence entre «exposer» et «publier» dans Docker?

517

J'expérimente avec Dockerfiles, et je pense que je comprends la plupart de la logique. Cependant, je ne vois pas la différence entre "exposer" et "publier" un port dans ce contexte.

Tous les tutoriels que j'ai vus en premier incluent la EXPOSEcommande dans le Dockerfile:

...
EXPOSE 8080
...

Ils construisent ensuite une image à partir de ce Dockerfile:

$ docker build -t an_image - < Dockerfile

Et puis publiez le même port que ci-dessus lors de l'exécution de l'image:

$ docker run -d -p 8080 an_image

ou publier tous les ports en utilisant

$ docker run -d -P an_image

Quel est l'intérêt d'exposer un port dans le Dockerfile, s'il est quand même publié? Serait-il jamais nécessaire d'exposer un port en premier, et de ne pas le publier plus tard? En effet, je voudrais spécifier tous les ports que j'utiliserai dans le Dockerfile lors de la création de l'image, puis ne plus les déranger, en les exécutant simplement avec:

$ docker run -d an_image

Est-ce possible?

user1496984
la source

Réponses:

733

Fondamentalement, vous avez trois options:

  1. Ni préciser EXPOSEni-p
  2. Précisez seulement EXPOSE
  3. Précisez EXPOSEet-p

1) Si vous ne spécifiez ni EXPOSEni -p, le service dans le conteneur sera uniquement accessible de l' intérieur du conteneur lui-même.

2) Si vous êtes EXPOSEun port, le service dans le conteneur n'est pas accessible depuis l'extérieur Docker, mais depuis l'intérieur d'autres conteneurs Docker. C'est donc bon pour la communication entre conteneurs.

3) Si vous EXPOSEet -pun port, le service dans le conteneur est accessible de n'importe où, même en dehors de Docker.

La raison pour laquelle les deux sont séparés est à mon humble avis parce que:

  • le choix d'un port hôte dépend de l'hôte et n'appartient donc pas au Dockerfile (sinon cela dépendrait de l'hôte),
  • et souvent c'est suffisant si un service dans un conteneur est accessible à partir d'autres conteneurs.

La documentation indique explicitement:

L' EXPOSEinstruction expose les ports à utiliser dans les liens.

Il vous indique également comment lier des conteneurs , qui est essentiellement la communication inter-conteneurs dont j'ai parlé.

PS: Si vous le faites -p, mais pas EXPOSE, Docker fait implicitement EXPOSE. En effet, si un port est ouvert au public, il est également automatiquement ouvert à d'autres conteneurs Docker. Par conséquent -pcomprend EXPOSE. C'est pourquoi je ne l'ai pas répertorié ci-dessus comme quatrième cas.

Golo Roden
la source
57
Je pense que vous n'avez pas raison avec EXPOSE. À partir d'autres conteneurs, vous pouvez accéder à tous les ports de conteneurs sans les exposer. J'ai essayé ça. Le hic ici est que l'adresse IP du conteneur est imprévisible. Je crois que ce lien est utilisé pour spécifier le conteneur que vous souhaitez connecter (donc vous liez à un IP de conteneur spécifique), et non pour activer la connexion.
Jiri
7
« Si vous ne spécifiez aucun de ces » serait utile si vous avez précisé que , avec « ceux » vous voulez dire EXPOSEet -pet non pas les trois points de balle nombreux précédents. Ça m'a un peu troublé.
Pithikos
4
Pour être pleinement complet, cette réponse devrait également aborder un quatrième cas possible: vous ne spécifiez pas EXPOSE, mais vous ne spécifiez -p. Je crois comprendre que si vous utilisez -pet exécutez toujours des conteneurs individuels, il EXPOSEest bon d'omettre, mais cela devient utile / nécessaire lorsque vous utilisez -Pou --link. (Et puisque vous ne savez pas comment les autres utiliseront votre image, cela EXPOSEdevrait être spécifié dans toutes les images publiques.)
GrandOpener
6
Les documents n'indiquent plus "L'instruction EXPOSE expose les ports à utiliser dans les liens".
Lorin Hochstein
11
Votez car cela est substantiellement incorrect. Expose est essentiellement de la documentation, et ne pas l'utiliser ne restreint pas l'accès. Il s'agit d'une incompréhension dangereuse si quelqu'un s'y fie pour limiter l'accès.
mc0e
167

Réponse courte:

  • EXPOSEest un moyen de documenter
  • --publish(ou -p) est un moyen de mapper un port hôte sur un port conteneur en cours d'exécution

Notez ci-dessous que:

  • EXPOSEest lié à Dockerfiles( documenter )
  • --publishest lié à docker run ...( exécution / exécution )

Exposition et publication de ports

Dans la mise en réseau Docker, il existe deux mécanismes différents qui impliquent directement les ports réseau: l'exposition et la publication des ports. Cela s'applique au réseau de ponts par défaut et aux réseaux de ponts définis par l'utilisateur.

  • Vous exposez les ports à l'aide du EXPOSEmot - clé dans le Dockerfile ou de l' --exposeindicateur de docker run. L'exposition des ports est un moyen de documenter quels ports sont utilisés, mais ne mappe ni n'ouvre aucun port . L'exposition des ports est facultative.

  • Vous publiez des ports à l'aide de l' indicateur --publishou . Cela indique à Docker quels ports ouvrir sur l'interface réseau du conteneur. Lorsqu'un port est publié, il est mappé sur un port de niveau supérieur disponible (supérieur à ) sur la machine hôte, sauf si vous spécifiez le port à mapper sur la machine hôte lors de l'exécution. Vous ne pouvez pas spécifier le port à mapper sur la machine hôte lorsque vous créez l'image (dans le Dockerfile), car il y a--publish-alldocker run30000 aucun moyen de garantir que le port sera disponible sur la machine hôte sur laquelle vous exécutez l'image .

de: mise en réseau de conteneurs Docker

Mise à jour d'octobre 2019 : le texte ci-dessus n'est plus dans la documentation mais une version archivée est ici: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

Peut-être que la documentation actuelle est la suivante:

Ports publiés

Par défaut, lorsque vous créez un conteneur, il ne publie aucun de ses ports dans le monde extérieur. Pour mettre un port à la disposition des services en dehors de Docker ou des conteneurs Docker qui ne sont pas connectés au réseau du conteneur, utilisez l' indicateur --publishou -p. Cela crée une règle de pare-feu qui mappe un port de conteneur à un port sur l'hôte Docker.

et peut être trouvé ici: docs.docker.com/config/containers/container-networking/#published-ports

Aussi,

EXPOSER

... L' EXPOSEinstruction ne publie pas réellement le port . Il fonctionne comme un type de documentation entre la personne qui construit l'image et la personne qui exécute le conteneur, sur les ports qui doivent être publiés.

de: référence Dockerfile






Accès au service lorsque EXPOSE/ --publishne sont pas définis:

À la réponse de @Golo Roden, il est indiqué que:

"Si vous ne spécifiez aucun de ces éléments, le service dans le conteneur ne sera pas accessible de n'importe où, sauf de l'intérieur du conteneur lui-même."

C'était peut-être le cas au moment où la réponse a été écrite, mais maintenant il semble que même si vous n'utilisez pas EXPOSEou --publish, le hostet les autres containersdu même réseau pourront accéder à un service que vous pouvez démarrer à l'intérieur de ce conteneur.

Comment tester cela:

J'ai utilisé ce qui suit Dockerfile. Fondamentalement, je commence par ubuntu et installe un petit serveur Web:

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

Je buildl'image comme "testexpose" et runun nouveau conteneur avec:

docker run --rm -it testexpose bash

À l'intérieur du conteneur, je lance quelques exemples de mini-httpd:

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

Je peux ensuite utiliser à curlpartir de l'hôte ou d'autres conteneurs pour récupérer la page d'accueil de mini-httpd.

tgogos
la source
16
c'est maintenant la bonne réponse. la réponse acceptée est basée sur des versions antérieures, semble-t-il.
Luke W
quel port hôte avez-vous utilisé pour curl?
tempête cérébrale
J'ai utilisé l'adresse IP du conteneur (quelque chose comme 172.17.0.2) et tous les ports que je mentionne. Si vous utilisez Docker pour Mac / Windows, la mise en réseau est différente. Il n'y a pas de docker0pont.
tgogos
lors de la publication de tous les ports EXPOSEd avec l'indicateur "-P", comment savoir quel port est utilisé sur l'hôte ??
sixty4bit
1
@ sixty4bit jetez un oeil à cette question: Comment savoir quel port aléatoire Docker a choisi? .
tgogos
9

Voir la référence de la documentation officielle: https://docs.docker.com/engine/reference/builder/#expose

Vous EXPOSEpermet de définir des ports privés (conteneur) et publics (hôte) à exposer au moment de la création de l'image lorsque le conteneur s'exécute si vous exécutez le conteneur avec -P.

$ docker help run
...
  -P, --publish-all                    Publish all exposed ports to random ports
...

Le port public et le protocole sont facultatifs, si aucun port public n'est spécifié, un port aléatoire sera sélectionné sur l'hôte par docker pour exposer le port de conteneur spécifié sur Dockerfile.

Une bonne pratique est de ne pas spécifier de port public, car cela limite un seul conteneur par hôte (un deuxième conteneur jettera un port déjà utilisé).

Vous pouvez utiliser -pin docker runpour contrôler quel port public les ports de conteneurs exposés seront connectables.

Quoi qu'il en soit, si vous n'utilisez pas EXPOSE(avec -Psur docker run) ni -p, aucun port ne sera exposé.

Si vous utilisez toujours -pat docker runvous n'en avez pas besoin EXPOSEmais si vous utilisez EXPOSEvotre docker runcommande peut être plus simple, EXPOSEpeut être utile si vous ne vous souciez pas du port qui sera exposé sur l'hôte, ou si vous êtes sûr qu'un seul conteneur sera chargé.

tonne
la source
c'est correct. Lorsque vous avez EXPOSE portNumber dans Dockerfile, n'oubliez pas d'appeler docker run avec -P.
KunYu Tsai
6

Vous exposez les ports à l'aide du mot clé EXPOSE dans le Dockerfile ou de l'indicateur --expose à l'exécution de docker. L'exposition des ports est un moyen de documenter les ports utilisés, mais ne mappe ni n'ouvre aucun port. L'exposition des ports est facultative.

Source: github commit

mzalazar
la source
3

La plupart des gens utilisent Docker Composer avec des réseaux. La documentation indique:

La fonctionnalité réseau Docker prend en charge la création de réseaux sans avoir à exposer les ports du réseau, pour des informations détaillées, voir la présentation de cette fonctionnalité).

Ce qui signifie que si vous utilisez des réseaux pour la communication entre les conteneurs, vous n'avez pas à vous soucier de l'exposition des ports.

Herm
la source
-5

EXPOSE est utilisé pour mapper le port de conteneur de port local, c'est-à-dire: si vous spécifiez exposer dans un fichier docker comme

EXPOSE 8090

Que fera-t-il pour mapper le port local de l'hôte 8090 au port de conteneur 8090

Mansur Ali
la source