GNU/Linux >> Tutoriales Linux >  >> Panels >> Docker

Cómo exponer o publicar el puerto Docker

En una configuración de varios contenedores, los servicios que se ejecutan en los contenedores se comunican entre sí a través de una red común. En la misma configuración, algunos contenedores también interactúan con el mundo exterior.

Esta comunicación interna y externa se maneja con puertos expuestos y publicados en Docker respectivamente.

En este tutorial, hablaré sobre el manejo de puertos en Docker. Continuaré con la diferencia entre exponer y publicar puertos, por qué se usan y cómo usarlos.

Exponer vs publicar un puerto en Docker

Hay dos formas de manejar los puertos en Docker:exponer los puertos y publicar los puertos.

Exponer un puerto simplemente significa informar a los demás en qué puerto escuchará la aplicación en contenedor o aceptará conexiones. Esto es para comunicarse con otros contenedores, no con el mundo exterior.

Publicar un puerto es más como mapear los puertos de un contenedor con los puertos del host. De esta manera, el contenedor puede comunicarse con sistemas externos, el mundo real, Internet.

Estos gráficos te ayudarán a entender.

Verá, ¿cómo se asigna el puerto 80 del contenedor SERVIDOR al puerto 80 del sistema host? De esta forma, el contenedor puede comunicarse con el mundo exterior utilizando la dirección IP pública del sistema host.

A los puertos expuestos, por otro lado, no se puede acceder directamente desde fuera del mundo del contenedor.

Para recordar:

  • Los puertos expuestos se utilizan para la comunicación interna del contenedor, dentro del mundo del contenedor.
  • Los puertos publicados se utilizan para comunicarse con sistemas fuera del mundo de los contenedores.
¿Cuál es la diferencia entre los puertos docker-compose frente a la exposición? ¿Cuál es la diferencia entre los puertos y las opciones de exposición en docker-compose.yml? Desbordamiento de pilaBibek Shrestha

Exponiendo puertos en Docker

En primer lugar, exponer un puerto no es estrictamente necesario. ¿Por qué? Porque la mayoría de las imágenes acoplables que usa en su configuración ya tienen un puerto predeterminado expuesto en su configuración.

Por ejemplo, una aplicación front-end en contenedor puede comunicarse con una base de datos MariaDB simplemente especificando la IP del contenedor y el puerto en el que MariaDB acepta conexiones (predeterminado 3306).

La exposición ayuda en una situación en la que no se utilizan los valores predeterminados, como en este caso si MariaDB no aceptara conexiones en el puerto 3306, se debe mencionar un puerto alternativo exponiéndolo.

Hay dos formas de exponer un puerto:

  1. Uso de EXPOSE Instrucción de Dockerfile.
  2. Usando --expose con docker CLI o expose clave en docker-compose.

Es hora de profundizar en ambos.

Método 1:exponer puertos a través de Dockerfile

Puede agregar una instrucción simple en su Dockerfile para que otros sepan en qué puerto aceptará conexiones su aplicación.

Sobre esta instrucción, lo que debe saber es lo siguiente:-

  • EXPOSE no agregue capas adicionales a la imagen acoplable resultante. Solo agrega metadatos.
  • EXPOSE es una forma de documentar su puerto de aplicación. El único efecto que tiene es en términos de legibilidad o comprensión de la aplicación.

Puede ver cómo funciona la exposición con una imagen de contenedor simple que he creado solo para este propósito. Esta imagen no hace nada .

Tira de la imagen.

docker pull debdutdeb/expose-demo:v1

Esta imagen expone un total de cuatro puertos, liste la imagen usando el siguiente comando.

docker image ls --filter=reference=debdutdeb/expose-demo:v1

Eche un vistazo al SIZE columna, dirá 0 bytes.

➟ docker image ls --filter=reference=debdutdeb/expose-demo:v1
REPOSITORY              TAG       IMAGE ID       CREATED   SIZE
debdutdeb/expose-demo   v1        ad3d8ffa9bfe   N/A       0B

La razón es simple, no hay capas en esta imagen, todas las instrucciones de exposición agregadas eran metadatos, no hay capas reales.

También puede obtener el número de capas disponibles usando el siguiente comando:-

docker image inspect -f '{{len .RootFS.Layers}}' debdutdeb/expose-demo:v1

Debería ver una salida como esta:-

➟ docker image inspect -f '{{len .RootFS.Layers}}' debdutdeb/expose-demo:v1 
0

Como dije anteriormente, los puertos expuestos se agregan como metadatos de imagen, para que sepamos qué puertos está usando la aplicación.

¿Cómo ves esa información sin mirar un Dockerfile? Necesitas inspeccionar la imagen. Para ser más específico, vea el comando a continuación, puede usar un comando similar en cualquier imagen para enumerar los puertos expuestos.

Estoy usando mi imagen de muestra para la demostración.

docker image inspect -f \
	'{{range $exposed, $_ := .Config.ExposedPorts}}{{printf "%s\n" $exposed}}{{end}}' \
    debdutdeb/expose-demo:v1

Salida de muestra:

➟ docker image inspect -f '{{range $exposed, $_ := .Config.ExposedPorts}}{{printf "%s\n" $exposed}}{{end}}' debdutdeb/expose-demo:v1 
443/tcp
80/tcp
8080/tcp
9090/tcp

También puede comparar esta imagen, que expone un par de puertos, con debdutdeb/noexpose-demo:v1 imagen, eso no está exponiendo ningún puerto. Ejecute el mismo conjunto de comandos en esa imagen y observe la diferencia.

Método 2:exponer puertos a través de CLI o docker-compose

A veces, los desarrolladores de aplicaciones evitan incluir un EXPOSE extra instrucción en su Dockerfile.

En tal caso, para asegurarse de que otros contenedores (a través de la API de la ventana acoplable) puedan detectar fácilmente el puerto en uso, puede exponer varios puertos después de la compilación, como parte del proceso de implementación.

Elija el método imperativo, es decir, la CLI, o el método declarativo, es decir, componer archivos.

Método CLI

En este método, al crear un contenedor, todo lo que tiene que hacer es usar --expose opción (tantas veces como sea necesario) con el número de puerto y, opcionalmente, el protocolo con un / . Aquí hay un ejemplo:-

docker container run \
	--expose 80 \
    --expose 90 \
    --expose 70/udp \
    -d --name port-expose busybox:latest sleep 1d

Estoy usando el busybox imagen que no expone ningún puerto por defecto.

Método de composición de archivos

Si está utilizando un archivo de redacción, puede agregar una matriz expose en la definición del servicio. Puede convertir la implementación anterior en un archivo compuesto así:-

version: "3.7"
services:
	PortExpose:
    	image: busybox
        command: sleep 1d
        container_name: port-expose
        expose:
        	- 80
            - 90
            - 70/udp

Una vez que tenga el contenedor en ejecución, al igual que antes, puede inspeccionarlo para saber qué puertos están expuestos. El comando se ve similar.

docker container inspect -f \
	'{{range $exposed, $_ := .NetworkSettings.Ports}}
    {{printf "%s\n" $exposed}}{{end}}' \
    port-expose

Salida de muestra:-

➟ docker container inspect -f '{{range $exposed, $_ := .NetworkSettings.Ports}}{{printf "%s\n" $exposed}}{{end}}' port-expose 
70/udp
80/tcp
90/tcp

Publicar un puerto en Docker

La publicación de puertos es sinónimo de reenvío de puertos, donde las solicitudes de una conexión entrante en un puerto público se reenvían al puerto del contenedor.

De manera similar, las respuestas enviadas desde el contenedor a través de su puerto se envían al cliente reenviando el tráfico al puerto especificado en el espacio del puerto del host.

Hay dos formas de publicar un puerto, una a través de la CLI y otra usando un archivo de composición. Ambos métodos también tienen una sintaxis larga y una sintaxis corta.

Método 1:publicar puertos mediante el comando Docker

Las dos sintaxis son las siguientes:

  1. -p [optional_host_ip]:[host_port]:[container_port]/[optional_protocol]
  2. --publish target=[container_port],published=[optional_host_ip]:[host_port],protocol=[optional_protocol]
Para la IP de host opcional, puede usar cualquier dirección IP asociada con cualquiera de las NIC. Si se omite la IP, Docker enlazará el puerto con todas las direcciones IP disponibles.

Vas a usar más el primero. El segundo es más legible. Veamos un ejemplo usando un contenedor nginx. Ejecute el siguiente comando:-

docker container run --rm --name nginx \
	--publish target=80,published=127.0.0.1:8081,protocol=tcp \
    -d nginx

Con este comando, simplemente estoy vinculando el puerto 80 del contenedor al puerto 8081 de mi host en localhost. Ahora, si se dirige a http://localhost:8081, verá nginx ejecutándose.

El comando anterior se puede convertir fácilmente a la forma más corta así

docker container run --rm --name nginx \
	-p 80:127.0.0.1:8081/tcp -d nginx

Aunque es más corto, es más difícil de leer.

También puedes usar -p o --publish varias veces para publicar varios puertos.

Método 2:publicar un puerto a través de un archivo de composición

Para publicar un puerto usando un archivo de redacción, necesitará una matriz llamada ports en la definición del servicio. Esta matriz puede ser una lista de cadenas que se parece a la sintaxis corta de la CLI, o puede usar una lista de objetos que es similar a la sintaxis larga.

Si tuviera que convertir la implementación anterior de nginx usando un archivo de redacción con una matriz de cadenas para la sección de puertos, se vería así:-

version: "3.7"
services:
	Nginx:
    	image: nginx
		container_name: nginx
        ports:
        	- 80:127.0.0.1:8081/tcp

Permítame mostrarle también cómo usar la sintaxis de matriz de objetos.

version: "3.7"
services:
	Nginx:
    	image: nginx
        container_name: nginx
        ports:
        	- target: 80
              published: 127.0.0.1:8081
              protocol: tcp

Para ver la lista de todos los puertos publicados, puede inspeccionar el contenedor así:

docker container inspect -f '{{range $container, $host := .NetworkSettings.Ports}}{{printf "%s -> %s\n" $container $host}}{{end}}' nginx

Si lo ejecuta, verá el siguiente resultado:-

➟ docker container inspect -f '{{range $container, $host := .NetworkSettings.Ports}}{{printf "%s -> %s\n" $container $host}}{{end}}' nginx 
80/tcp -> [{127.0.0.1 8081}]

Hay otra forma más fácil de listar los puertos publicados, usando el docker container port comando.

docker container port nginx

Salida de ejemplo:-

➟ docker container port nginx
80/tcp -> 127.0.0.1:8081

¿Cuándo exponer un puerto y cuándo publicarlo?

Esta es una pregunta justa. Se supone que exponer y publicar no son competidores. Cada uno tiene un propósito diferente. Si es el desarrollador de una imagen, expondrá los puertos para que el usuario pueda estar más seguro de dónde intentar una conexión. Por otro lado, si está utilizando una imagen y necesita ponerla a disposición del mundo exterior, publicará los puertos necesarios.

Espero que este artículo te haya sido útil. Si tiene alguna pregunta, hágamelo saber en los comentarios a continuación.


Docker
  1. Cómo instalar Jenkins con Docker

  2. Cómo usar Docker Compose

  3. Cómo conectar contenedores Docker

  4. Cómo ejecutar ssh en varios puertos

  5. Conceptos básicos de Docker:exposición de puertos, vinculación de puertos y enlace de Docker

Cómo instalar Docker CE en Linux Mint 20

Cómo usar Netcat para escanear puertos abiertos en Linux

Cómo exponer o publicar el puerto Docker

Cómo eliminar contenedores Docker

Cómo detener los contenedores de Docker

Cómo instalar Docker en Mac