Compartir comentarios
Las respuestas se generan en base a la documentación.

Publicación y mapeo de puertos

De forma predeterminada, tanto para IPv4 como para IPv6, el daemon de Docker bloquea el acceso a los puertos que no han sido publicados. Los puertos publicados de los contenedores se mapean a direcciones IP del host. Para hacer esto, utiliza reglas de cortafuegos para realizar la Traducción de Direcciones de Red (NAT), la Traducción de Direcciones de Puerto (PAT) y el enmascaramiento.

Por ejemplo, docker run -p 8080:80 [...] crea un mapeo entre el puerto 8080 en cualquier dirección del host de Docker y el puerto 80 del contenedor. Las conexiones salientes desde el contenedor se enmascararán utilizando la dirección IP del host de Docker.

Publicación de puertos

Al crear o ejecutar un contenedor utilizando docker create o docker run, todos los puertos de los contenedores en redes bridge son accesibles desde el host de Docker y desde otros contenedores conectados a la misma network. Ports are not accessible from outside the host or, with the default configuration, from containers in other networks. (Wait! Let's translate this to Spanish!) Al crear o ejecutar un contenedor utilizando docker create o docker run, todos los puertos de los contenedores en redes bridge son accesibles desde el host de Docker y desde otros contenedores conectados a la misma red. No se puede acceder a los puertos desde fuera del host o, con la configuración predeterminada, desde contenedores en otras redes.

Utiliza el flag --publish o -p para hacer que un puerto esté disponible fuera del host y para los contenedores en otras redes bridge.

Esto crea una regla de cortafuegos en el host, mapeando un puerto del contenedor a un puerto en el host de Docker de cara al exterior. A continuación se muestran algunos ejemplos:

Valor del flagDescripción
-p 8080:80Mapea el puerto 8080 del host de Docker al puerto TCP 80 del contenedor.
-p 192.168.1.100:8080:80Mapea el puerto 8080 en la IP del host de Docker 192.168.1.100 al puerto TCP 80 del contenedor.
-p 8080:80/udpMapea el puerto 8080 del host de Docker al puerto UDP 80 del contenedor.
-p 8080:80/tcp -p 8080:80/udpMapea el puerto TCP 8080 del host de Docker al puerto TCP 80 del contenedor, y mapea el puerto UDP 8080 del host de Docker al puerto UDP 80 del contenedor.
Important

La publicación de puertos de contenedores es insegura por defecto. Esto significa que cuando publicas los puertos de un contenedor, este queda disponible no solo para el host de Docker, sino también para el exterior.

Si inclues la dirección IP de localhost (127.0.0.1 o ::1) con el flag de publicación, solo el host de Docker podrá acceder al puerto publicado del contenedor.

$ docker run -p 127.0.0.1:8080:80 -p '[::1]:8080:80' nginx
Warning

En versiones anteriores a la 28.0.0, los hosts dentro del mismo segmento L2 (por ejemplo, hosts conectados al mismo conmutador de red) pueden alcanzar puertos publicados en localhost. Para obtener más información, consulta moby/moby#45610

Los puertos en las direcciones IPv6 del host se mapearán a la dirección IPv4 del contenedor si no se proporciona una IP de host en un mapeo de puertos, si la red bridge es de solo IPv4 y si --userland-proxy=true (predeterminado).

Enrutamiento directo

El mapeo de puertos garantiza que se pueda acceder a los puertos publicados en las direcciones de red del host, que probablemente sean enrutables para cualquier cliente externo. Normalmente no se configuran rutas en la red del host para las direcciones de los contenedores que existen dentro de un host.

Sin embargo, especialmente con IPv6, es posible que prefieras evitar el uso de NAT y, en su lugar, configurar el enrutamiento externo a las direcciones de los contenedores ("enrutamiento directo").

Para acceder a contenedores en una red bridge desde fuera del host de Docker, primero debes configurar el enrutamiento a la red bridge a través de una dirección en el host de Docker. Esto se puede lograr utilizando rutas estáticas, el Protocolo de Pasarela de Frontera (BGP) o cualquier otro medio adecuado para tu red. Por ejemplo, dentro de una red local de capa 2, los hosts remotos pueden configurar rutas estáticas a una red de contenedores a través de la dirección del host del daemon de Docker en la red local.

Enrutamiento directo a contenedores en redes bridge

De forma predeterminada, no se permite a los hosts remotos el acceso directo a las direcciones IP de los contenedores en las redes bridge de Linux de Docker. Solo pueden acceder a los puertos publicados en las direcciones IP del host.

Para permitir el acceso directo a cualquier puerto publicado, en cualquier contenedor, en cualquier red bridge de Linux, utiliza la opción del daemon "allow-direct-routing": true en /etc/docker/daemon.json o su equivalente --allow-direct-routing.

Para permitir el enrutamiento directo desde cualquier lugar hacia los contenedores en una red bridge específica, consulta Modos de puerta de enlace.

O bien, para permitir el enrutamiento directo a través de interfaces específicas del host hacia una red bridge específica, utiliza la siguiente opción al crear la red:

  • com.docker.network.bridge.trusted_host_interfaces

Ejemplo

Crea una red en la que se pueda acceder directamente a los puertos publicados en las direcciones IP de los contenedores desde las interfaces vxlan.1 y eth3:

$ docker network create --subnet 192.0.2.0/24 --ip-range 192.0.2.0/29 -o com.docker.network.bridge.trusted_host_interfaces="vxlan.1:eth3" mynet

Ejecuta un contenedor en esa red, publicando su puerto 80 en el puerto 8080 de la interfaz de bucle de retorno (loopback) del host:

$ docker run -d --ip 192.0.2.100 -p 127.0.0.1:8080:80 nginx

Ahora se puede acceder al servidor web que se ejecuta en el puerto 80 del contenedor desde el host de Docker en http://127.0.0.1:8080 o directamente en http://192.0.2.100:80. Si los hosts remotos en redes conectadas a las interfaces vxlan.1 y eth3 tienen una ruta hacia la red 192.0.2.0/24 dentro del host de Docker, también pueden acceder al servidor web a través de http://192.0.2.100:80.

Modos de puerta de enlace

El controlador de red bridge tiene las siguientes opciones:

  • com.docker.network.bridge.gateway_mode_ipv6
  • com.docker.network.bridge.gateway_mode_ipv4

Cada una de ellas se puede configurar en uno de los siguientes modos de puerta de enlace:

  • nat
  • nat-unprotected
  • routed
  • isolated

El modo predeterminado es nat; se configuran reglas de NAT y enmascaramiento para cada puerto de contenedor publicado. Los paquetes que salgan del host utilizarán una dirección del host.

Con el modo routed, no se configuran reglas de NAT o enmascaramiento, pero se siguen configurando reglas de cortafuegos para que solo sean accesibles los puertos publicados del contenedor. Los paquetes salientes del contenedor utilizarán la dirección del contenedor, no una dirección del host.

Para acceder a un puerto publicado en una red routed, los hosts remotos deben tener una ruta hacia la red del contenedor a través de una dirección externa en el host de Docker ("enrutamiento directo"). Los hosts en la red local de capa 2 pueden configurar el enrutamiento directo sin necesidad de ninguna configuración de red adicional. Los hosts fuera de la red local solo pueden utilizar el enrutamiento directo al contenedor si los enrutadores de la red están configurados para permitirlo.

En una red en modo nat, publicar un puerto a una dirección en la interfaz de bucle de retorno significa que los hosts remotos no pueden acceder a él. Otros puertos de contenedores publicados en redes routed y nat son siempre accesibles desde hosts remotos mediante enrutamiento directo, a menos que el cortafuegos del host de Docker tenga restricciones adicionales.

Note

Cuando un puerto se publica en una dirección de host específica en modo nat, si el reenvío de IP está habilitado en el host de Docker, se puede acceder al puerto publicado a través de otras interfaces del host utilizando el enrutamiento directo a la dirección del host.

Por ejemplo, un host de Docker con reenvío de IP habilitado tiene dos tarjetas de red (NIC) con las direcciones 192.168.100.10/24 y 10.0.0.10/24. Cuando un puerto se publica en 192.168.100.10, un host en la subred 10.0.0.0/24 puede acceder a ese puerto enrutando a 192.168.100.10 a través de 10.0.0.10.

En el modo nat-unprotected, también se puede acceder a los puertos de contenedores no publicados utilizando enrutamiento directo; no se configuran reglas de filtrado de puertos. Este modo se incluye por compatibilidad con el comportamiento predeterminado heredado.

El modo de puerta de enlace también afecta a la comunicación entre contenedores que están conectados a diferentes redes de Docker en el mismo host.

  • En los modos nat y nat-unprotected, los contenedores en otras redes bridge solo pueden acceder a los puertos publicados a través de las direcciones de host en las que están publicados. No se permite el enrutamiento directo desde otras redes.
  • En el modo routed, los contenedores en otras redes pueden utilizar el enrutamiento directo para acceder a los puertos, sin tener que pasar por una dirección del host.

En el modo routed, no se utiliza un puerto de host en un mapeo de puertos -p o --publish, y la dirección del host solo se utiliza para decidir si se aplica el mapeo a IPv4 o IPv6. Por lo tanto, cuando un mapeo solo se aplica al modo routed, solo deben utilizarse las direcciones 0.0.0.0 o ::, y no se debe proporcionar un puerto de host. Si se proporciona una dirección o puerto específico, no tendrá efecto en el puerto publicado y se registrará un mensaje de advertencia.

El modo isolated solo se puede utilizar cuando la red se crea también con el flag de CLI --internal o equivalente. Normalmente se asigna una dirección al dispositivo bridge en una red internal. Por lo tanto, los procesos en el host de Docker pueden acceder a la red, y los contenedores en la red pueden acceder a los servicios del host que escuchan en esa dirección bridge (incluyendo servicios que escuchan en "cualquier" dirección de host, 0.0.0.0 o ::). No se asigna ninguna dirección al bridge cuando la red se crea con el modo de puerta de enlace isolated.

Ejemplo

Crea una red adecuada para el enrutamiento directo para IPv6, con NAT habilitado para IPv4:

$ docker network create --ipv6 --subnet 2001:db8::/64 -o com.docker.network.bridge.gateway_mode_ipv6=routed mynet

Crea un contenedor con un puerto publicado:

$ docker run --network=mynet -p 8080:80 myimage

Entonces:

  • Solo el puerto 80 del contenedor estará abierto, tanto para IPv4 como para IPv6.
  • Para IPv6, utilizando el modo routed, el puerto 80 estará abierto en la dirección IP del contenedor. El puerto 8080 no se abrirá en las direcciones IP del host, y los paquetes salientes utilizarán la dirección IP del contenedor.
  • Para IPv4, utilizando el modo predeterminado nat, se podrá acceder al puerto 80 del contenedor a través del puerto 8080 en las direcciones IP del host, así como directamente desde dentro del host de Docker. Sin embargo, no se puede acceder al puerto 80 del contenedor directamente desde fuera del host. Las conexiones originadas en el contenedor se enmascararán, utilizando la dirección IP del host.

En docker inspect, este mapeo de puertos se mostrará de la siguiente manera. Ten en cuenta que no hay HostPort para IPv6, ya que está utilizando el modo routed:

$ docker container inspect <id> --format "{{json .NetworkSettings.Ports}}"
{"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"},{"HostIp":"::","HostPort":""}]}

Como alternativa, para que el mapeo sea exclusivo de IPv6, deshabilitando el acceso IPv4 al puerto 80 del contenedor, utiliza la dirección IPv6 no especificada [::] y no incluyas un número de puerto de host:

$ docker run --network mynet -p '[::]::80'

Configurar la dirección de vinculación predeterminada para los contenedores

De forma predeterminada, cuando los puertos de un contenedor se mapean sin especificar ninguna dirección de host, el daemon de Docker publica los puertos en todas las direcciones del host (0.0.0.0 y [::]).

Por ejemplo, el siguiente comando publica el puerto 8080 en todas las interfaces de red del host, tanto en direcciones IPv4 como IPv6, poniéndolas potencialmente a disposición del mundo exterior.

docker run -p 8080:80 nginx

Puedes cambiar la dirección de vinculación predeterminada para los puertos de contenedores publicados de modo que, por defecto, solo sean accesibles para el host de Docker. Para ello, puedes configurar el daemon para que en su lugar utilice la dirección de bucle de retorno (loopback) (127.0.0.1).

Warning

En versiones anteriores a la 28.0.0, los hosts dentro del mismo segmento L2 (por ejemplo, hosts conectados al mismo conmutador de red) pueden alcanzar puertos publicados en localhost. Para obtener más información, consulta moby/moby#45610

To configure this setting for user-defined bridge networks, use the com.docker.network.bridge.host_binding_ipv4 driver option when you create the network. Despite the option name, it is possible to specify an IPv6 address. (Translate this!) Para configurar este ajuste para redes bridge definidas por el usuario, utiliza la opción del controlador com.docker.network.bridge.host_binding_ipv4 al crear la red. A pesar del nombre de la opción, es posible especificar una dirección IPv6.

$ docker network create mybridge \
  -o "com.docker.network.bridge.host_binding_ipv4=127.0.0.1"

Or, to set the default binding address for containers in all user-defined bridge networks, use daemon configuration option default-network-opts. For example: (Translate this!) O bien, para establecer la dirección de vinculación predeterminada para contenedores en todas las redes bridge definidas por el usuario, utiliza la opción de configuración del daemon default-network-opts. Por ejemplo:

{
  "default-network-opts": {
    "bridge": {
      "com.docker.network.bridge.host_binding_ipv4": "127.0.0.1"
    }
  }
}
Note

Configurar la dirección de vinculación predeterminada como :: significa que las vinculaciones de puertos que no especifiquen una dirección de host funcionarán para cualquier dirección IPv6 en el host. Sin embargo, 0.0.0.0 significa cualquier dirección IPv4 o IPv6.

Cambiar la dirección de vinculación predeterminada no tiene ningún efecto en los servicios de Swarm. Los servicios de Swarm siempre se exponen en la interfaz de red 0.0.0.0.

Enmascaramiento o SNAT para paquetes salientes

NAT está habilitado por defecto para las redes bridge, lo que significa que los paquetes salientes de los contenedores se enmascaran. La dirección de origen de los paquetes que salen del host de Docker se cambia por una dirección en la interfaz del host por la que se envía el paquete.

El enmascaramiento se puede deshabilitar para una red bridge definida por el usuario utilizando la opción del controlador com.docker.network.bridge.enable_ip_masquerade al crear la red. Por ejemplo:

$ docker network create mybridge \
  -o com.docker.network.bridge.enable_ip_masquerade=false ...

Para utilizar una dirección de origen específica para los paquetes salientes en una red definida por el usuario, en lugar de permitir que el enmascaramiento seleccione una dirección, utiliza las opciones com.docker.network.host_ipv4 y com.docker.network.host_ipv6 para especificar la dirección de NAT de origen (SNAT) a emplear. La opción com.docker.network.bridge.enable_ip_masquerade debe estar configurada en true (el valor predeterminado) para que estas opciones tengan algún efecto.

Bridge predeterminado

Para establecer la vinculación predeterminada para la red bridge predeterminada, configura la clave "ip" en el archivo de configuración daemon.json:

{
  "ip": "127.0.0.1"
}

Esto cambia la dirección de vinculación predeterminada a 127.0.0.1 para los puertos de contenedores publicados en la red bridge predeterminada.

Reinicia el daemon para que este cambio surta efecto.

Como alternativa, puedes utilizar el flag dockerd --ip al iniciar el daemon.