I'm un poco principiante a Docker. No pude encontrar ninguna descripción clara de lo que hace esta opción en el comando de ejecución Docker en profundidad y poco confundido al respecto.
¿Podemos usarlo para acceder a las aplicaciones que se ejecutan en contenedores docker sin especificar un puerto? Por ejemplo, si ejecuto una webapp desplegada a través de una imagen docker en el puerto 8080 utilizando la opción -p 8080:8080
en el comando docker run, sé que tendré que acceder a ella en el puerto 8080 en los contenedores Docker ip /theWebAppName. Pero no se me ocurre como funciona la opción --net=host
.
Después de la instalación de Docker tienes 3 redes por defecto:
docker network ls
NETWORK ID NAME DRIVER SCOPE
f3be8b1ef7ce bridge bridge local
fbff927877c1 host host local
023bb5940080 none null local
Estoy tratando de mantener esto simple. Así que si inicias un contenedor por defecto se creará dentro de la red puente (docker0).
$ docker run -d jenkins
1498e581cdba jenkins "/bin/tini -- /usr..." 3 minutes ago Up 3 minutes 8080/tcp, 50000/tcp friendly_bell
En el dockerfile de jenkins los puertos 8080
y 50000
están expuestos. Esos puertos están abiertos para el contenedor en su red puente. Así que todo dentro de esa red puente puede acceder al contenedor en el puerto 8080
y 50000
. Todo en la red puente está en el rango privado de "Subnet": "172.17.0.0/16",
Si quieres acceder a ellos desde el exterior tienes que mapear los puertos con -p 8080:8080
. Esto mapeará el puerto de tu contenedor al puerto de tu servidor real (la red anfitriona). Así que acceder a su servidor en 8080
se dirigirá a su bridgenetwork en el puerto 8080
.
Ahora también tienes tu red host. Que no contiene la red de contenedores. Así que si inicias un contenedor en la red host se verá así (es el primero):
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1efd834949b2 jenkins "/bin/tini -- /usr..." 6 minutes ago Up 6 minutes eloquent_panini
1498e581cdba jenkins "/bin/tini -- /usr..." 10 minutes ago Up 10 minutes 8080/tcp, 50000/tcp friendly_bell
La diferencia es con los puertos. Tu contenedor está ahora dentro de la red anfitriona. Así que si abres el puerto 8080
en tu host accederás al contenedor inmediatamente.
$ sudo iptables -I INPUT 5 -p tcp -m tcp --dport 8080 -j ACCEPT
He abierto el puerto 8080
en mi firewall y cuando accedo a mi servidor en el puerto 8080
estoy accediendo a mi jenkins. Creo que este blog también es útil para entenderlo mejor.
La opción --net=host
se utiliza para hacer que los programas dentro del contenedor Docker parezcan estar ejecutándose en el propio host, desde la perspectiva de la red. Permite al contenedor un mayor acceso a la red del que puede obtener normalmente.
Normalmente tienes que redirigir puertos desde la máquina anfitriona a un contenedor, pero cuando los contenedores comparten la red del anfitrión, cualquier actividad de red ocurre directamente en la máquina anfitriona - tal y como ocurriría si el programa se estuviera ejecutando localmente en lugar de dentro de un contenedor.
Aunque esto significa que ya no tienes que exponer puertos y mapearlos a puertos de contenedor, significa que tienes que editar tus Dockerfiles para ajustar los puertos en los que escucha cada contenedor, para evitar conflictos ya que no puedes tener dos contenedores operando en el mismo puerto del host. Sin embargo, la verdadera razón de esta opción es para ejecutar aplicaciones que necesitan acceso a la red que es difícil de reenviar a través de un contenedor a nivel de puerto.
Por ejemplo, si quieres ejecutar un servidor DHCP, necesitas poder escuchar el tráfico de difusión en la red y extraer la dirección MAC del paquete. Esta información se pierde durante el proceso de reenvío de puertos, por lo que la única manera de ejecutar un servidor DHCP dentro de Docker es ejecutar el contenedor como --net=host
.
En general, --net=host
sólo es necesario cuando se ejecutan programas con necesidades de red muy específicas e inusuales.
Por último, desde una perspectiva de seguridad, los contenedores Docker pueden escuchar en muchos puertos, a pesar de que sólo anuncian (exponen) un único puerto. Normalmente esto está bien, ya que sólo se reenvía el único puerto esperado, sin embargo, si se utiliza --host=net
entonces obtendrá todos los puertos del contenedor escuchando en el host, incluso aquellos que no están listados en el Dockerfile. Esto significa que tendrá que comprobar el contenedor de cerca (especialmente si no es el suyo, por ejemplo, uno oficial proporcionado por un proyecto de software) para asegurarse de que no expone inadvertidamente servicios adicionales en la máquina.