¿Cuál es la diferencia entre "exponer" y "publicar" en Docker?

517

Estoy experimentando con Dockerfiles, y creo que entiendo la mayor parte de la lógica. Sin embargo, no veo la diferencia entre "exponer" y "publicar" un puerto en este contexto.

Todos los tutoriales que he visto primero incluyen el EXPOSEcomando en el Dockerfile:

...
EXPOSE 8080
...

Luego construyen una imagen de este Dockerfile:

$ docker build -t an_image - < Dockerfile

Y luego publique el mismo puerto que el anterior cuando ejecute la imagen:

$ docker run -d -p 8080 an_image

o publicar todos los puertos usando

$ docker run -d -P an_image

¿Cuál es el punto de exponer un puerto en el Dockerfile, si se publicará de todos modos? ¿Alguna vez será necesario exponer un puerto primero y no publicarlo más tarde? Efectivamente, me gustaría especificar todos los puertos que usaré en el Dockerfile al crear la imagen, y luego no molestarme con ellos nuevamente, ejecutándolos simplemente con:

$ docker run -d an_image

es posible?

usuario1496984
fuente

Respuestas:

733

Básicamente, tienes tres opciones:

  1. Ni especifique EXPOSEni-p
  2. Solo especifique EXPOSE
  3. Especificar EXPOSEy-p

1) Si se especifica ni EXPOSEtampoco -p, el servicio en el contenedor sólo será accesible desde el interior del propio recipiente.

2) Si tiene EXPOSEun puerto, el servicio en el contenedor no es accesible desde fuera de Docker, sino desde el interior de otros contenedores de Docker. Entonces esto es bueno para la comunicación entre contenedores.

3) Si usted EXPOSEy -pun puerto, el servicio en el contenedor es accesible desde cualquier lugar, incluso fuera de Docker.

La razón por la cual ambos están separados es en mi humilde opinión porque:

  • elegir un puerto de host depende del host y, por lo tanto, no pertenece al Dockerfile (de lo contrario, dependería del host),
  • y a menudo es suficiente si un servicio en un contenedor es accesible desde otros contenedores.

La documentación declara explícitamente:

La EXPOSEinstrucción expone los puertos para su uso dentro de los enlaces.

También le indica cómo vincular contenedores , que básicamente es la comunicación entre contenedores de la que hablé.

PD: Si lo haces -p, pero no lo haces EXPOSE, Docker lo hace implícito EXPOSE. Esto se debe a que si un puerto está abierto al público, también se abre automáticamente a otros contenedores Docker. Por lo tanto -pincluye EXPOSE. Es por eso que no lo mencioné arriba como un cuarto caso.

Golo Roden
fuente
57
Creo que no estás en lo correcto con EXPOSE. Desde otros contenedores, puede acceder a todos los puertos de contenedor sin exponerlos. Lo intenté El problema aquí es que la dirección IP del contenedor es impredecible. Creo que ese enlace se usa para especificar qué contenedor desea conectar (por lo que debe vincular a una IP de contenedor específica), no para habilitar la conexión.
Jiri
77
"Si no se especifica ninguna de las personas", sería útil si aclarado que con "los que" se quiere decir EXPOSEy -pno los de los tres puntos de la bala precedentes de. Me confundí un poco allí.
Pithikos
44
Para estar completamente completo, esta respuesta también debe abordar un cuarto caso posible: no especificó EXPOSE, pero especificó -p. Tengo entendido que si siempre usa -py ejecuta contenedores individuales, EXPOSEestá bien omitirlos, pero se vuelve útil / necesario cuando se usa -Po --link. (Y como no sabe cómo otras personas usarán su imagen, EXPOSEdebe especificarse en cualquier imagen pública).
GrandOpener
66
Los documentos ya no indican "La instrucción EXPOSE expone los puertos para su uso dentro de los enlaces".
Lorin Hochstein
11
Voto negativo porque esto es sustancialmente incorrecto. Exponer es básicamente documentación, y no usarlo no restringe el acceso. Este es un malentendido peligroso si alguien confía en él para limitar el acceso.
mc0e
167

Respuesta corta:

  • EXPOSEes una forma de documentar
  • --publish(o -p) es una forma de asignar un puerto host a un puerto contenedor en ejecución

Observe a continuación que:

  • EXPOSEestá relacionado con Dockerfiles( documentación )
  • --publishestá relacionado con docker run ...( ejecución / tiempo de ejecución )

Puertos de exposición y publicación

En la red Docker, hay dos mecanismos diferentes que involucran directamente los puertos de red: exponer y publicar puertos. Esto se aplica a la red puente predeterminada y a las redes puente definidas por el usuario.

  • EXPOSEExpone los puertos utilizando la palabra clave en el Dockerfile o el --exposeindicador para ejecutar Docker . Exponer puertos es una forma de documentar qué puertos se usan, pero en realidad no asigna ni abre ningún puerto . La exposición de los puertos es opcional.

  • Publica puertos utilizando el --publisho--publish-all indicadordocker run . Esto le dice a Docker qué puertos abrir en la interfaz de red del contenedor. Cuando se publica un puerto, se asigna a un puerto de orden superior disponible (más alto que 30000) en la máquina host, a menos que especifique el puerto para asignar en la máquina host en tiempo de ejecución. No puede especificar el puerto para asignar en la máquina host cuando construye la imagen (en el Dockerfile), porque no hay forma de garantizar que el puerto estará disponible en la máquina host donde ejecuta la imagen .

de: redes de contenedores Docker

Actualización de octubre de 2019 : el texto anterior ya no está en los documentos, pero hay una versión archivada aquí: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

Quizás la documentación actual es la siguiente:

Puertos publicados

De manera predeterminada, cuando crea un contenedor, no publica ninguno de sus puertos en el mundo exterior. Para hacer que un puerto esté disponible para servicios fuera de Docker, o para contenedores Docker que no están conectados a la red del contenedor, use el indicador --publisho -p. Esto crea una regla de firewall que asigna un puerto de contenedor a un puerto en el host Docker.

y se puede encontrar aquí: docs.docker.com/config/containers/container-networking/#published-ports

También,

EXPONER

... La EXPOSEinstrucción en realidad no publica el puerto . Funciona como un tipo de documentación. entre la persona que construye la imagen y la persona que ejecuta el contenedor, sobre qué puertos están destinados a ser publicados.

de: referencia de Dockerfile






Acceso al servicio cuando EXPOSE/--publish no están definidos:

En la respuesta de @Golo Roden se afirma que ::

"Si no especifica ninguno de esos, el servicio en el contenedor no será accesible desde cualquier lugar, excepto desde el interior del contenedor".

Tal vez ese era el caso en el momento en que se estaba escribiendo la respuesta, pero ahora parece que incluso si no usa EXPOSEo --publish, el hosty otroscontainers red de la misma podrá acceder a un servicio que puede iniciar dentro de ese contenedor.

Cómo probar esto:

He usado lo siguiente Dockerfile. Básicamente, comienzo con ubuntu e instalo un pequeño servidor web:

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

I buildla imagen como "testexpose" y runun nuevo contenedor con:

docker run --rm -it testexpose bash

Dentro del contenedor, lanzo algunas instancias de mini-httpd:

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

Entonces puedo usar curldesde el host u otros contenedores para buscar la página de inicio de mini-httpd.

tgogos
fuente
16
Esta es ahora la respuesta correcta. La respuesta aceptada se basa en versiones anteriores, al parecer.
Luke W
¿Cuál es el puerto host que usaste para curl?
tormenta de cerebro
Usé la IP del contenedor (algo así como 172.17.0.2) y todos los puertos que estoy mencionando. Si está utilizando Docker para Mac / Windows, la red es diferente. No hay docker0puente
tgogos
al publicar todos los puertos EXPOSEd con el indicador "-P", ¿cómo puedo saber qué puerto se usa en el host?
sixty4bit
1
@ sixty4bit eche un vistazo a esta pregunta: ¿Cómo puedo saber qué puerto aleatorio ha elegido Docker? .
tgogos
9

Consulte la referencia de documentación oficial: https://docs.docker.com/engine/reference/builder/#expose

Le EXPOSEpermiten definir puertos privados (contenedor) y públicos (host) para exponer en el momento de creación de la imagen para cuando el contenedor se está ejecutando si ejecuta el contenedor con -P.

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

El puerto público y el protocolo son opcionales, si no se especifica un puerto público, Docker seleccionará un puerto aleatorio en el host para exponer el puerto contenedor especificado en Dockerfile.

Una buena práctica es no especificar el puerto público, ya que limita solo un contenedor por host (un segundo contenedor arrojará un puerto ya en uso).

Se puede utilizar -pen docker runcontrolar lo público portuario los puertos de contenedores expuestos serán conectable.

De todos modos, si no usa EXPOSE(con -PDocker Run) ni -p, no se expondrán puertos.

Si utiliza siempre -pen docker runque no es necesario EXPOSEpero si se utiliza EXPOSEel docker runcomando puede ser más simple, EXPOSEpuede ser útil si no le importa qué puerto se expone en el host, o si está seguro de un solo contenedor se cargará.

tonelada
fuente
esto es correcto. Cuando tenga EXPOSE portNumber en Dockerfile, recuerde invocar docker run con -P.
KunYu Tsai
6

Expone los puertos utilizando la palabra clave EXPOSE en el Dockerfile o el indicador --expose para ejecutar Docker. Exponer puertos es una forma de documentar qué puertos se utilizan, pero en realidad no asigna ni abre ningún puerto. La exposición de los puertos es opcional.

Fuente: github commit

mzalazar
fuente
3

La mayoría de las personas usan docker componer con redes. La documentación dice:

La función de red Docker admite la creación de redes sin la necesidad de exponer puertos dentro de la red; para obtener información detallada, consulte la descripción general de esta función).

Lo que significa que si usa redes para la comunicación entre contenedores, no necesita preocuparse por exponer los puertos.

herm
fuente
-5

EXPOSE se utiliza para asignar el puerto del contenedor del puerto local, es decir: si especifica exponer en el archivo acoplable como

EXPOSE 8090

Lo que hará será asignar el puerto localhost 8090 al puerto de contenedor 8090

Mansur Ali
fuente