Cómo funcionan las redes en Docker

Gisela Torres
Computación en la nube
January 12, 2021

Cómo funcionan las redes en Docker

Cuando decides aprender Docker uno de los temas que más suele costar es la parte de networking. Por eso hoy quiero contarte a modo de resumen cómo nos ayuda esta tecnología a cubrir esta parte.

Port mapping

Normalmente, cuando comienzas a jugar con Docker, lo primero que usas es lo que se conoce como port mapping. El objetivo de esta característica es poder acceder a la aplicación que está hospedada en un contenedor de Docker desde tu máquina local. Para ello, lo que hacemos es mapear un puerto de nuestra máquina con el puerto por el que está a la escucha en el contenedor. Esto se consigue de la siguiente manera:

El comando –publish (normalmente acortado a -p) es el que nos permite crear esa asociación entre mi puerto local (9090) y el puerto que nos interese del contenedor (80). En este caso, para acceder simplemente necesitaríamos utilizar un navegador web y acudir a la dirección http://localhost:9090

Por otro lado, si la imagen que estamos utilizando para crear nuestro contenedor ha hecho un buen uso de las instrucciones EXPOSE, podemos usar el comando de esta otra manera, para que Docker se encargue de elegir por nosotros puertos aleatorios en nuestra máquina que mapear con aquellos especificados en el Dockerfile:

Esto está bien cuando yo, Gisela, quiero hablar con uno de los contenedores que se está ejecutando en mi máquina a nivel de desarrollo pero ¿y si quiero que los contenedores hablen entre sí?

Docker y el networking

Si seguiste los artículos anteriores que escribí sobre Docker, ya sabes más que de sobra que las aplicaciones se ejecutan dentro de contenedores, de manera independiente unas de otras. Sin embargo, estas aplicaciones necesitan comunicarse entre ellas, en la mayoría de las ocasiones, como puede ser el front end con el back end, como bases de datos, APIs, etcétera. En este sentido, Docker tiene una forma súper sencilla de lidiar con las redes ¿Y si te dijera que has estado trabajando con redes en Docker desde el minuto uno sin tu saberlo? Pues así de fácil es.

A modo de culturilla, la parte de networking de Docker está basada en una arquitectura llamada Container Network Model (CNM). Esta está implementada en una librería llamada libnetwork, que forma parte de Docker Engine. Por otro lado, cada SO que soporta Docker Engine tiene un conjunto de drivers que permiten a libnetwork crear la configuración de la red que corresponda en cada sistema operativo por nosotros. De manera nativa, estos traen consigo cuatro tipos:

  • Bridge/NAT: Se utiliza cuando tienes un solo host de Docker y neesitas que tus contenedores hablen entre sí.
  • Overlay: está disponible cuando trabajamos en un formato clúster, es decir que tenemos más de un host de Docker trabajando como uno solo, por lo que necesito que los contenedores puedan hablar entre sí, independientemente de dónde les haya tocado ejecutarse dentro del clúster.
  • None: este driver es la forma de decir a Docker que para un contenedor/es en concreto no queremos que estén conectados a ninguna red. Lo que hace en este caso es no asignarle una tarjeta de red y listo
🙂
  • Macvlan: esta opción se utiliza en el caso de querer conectar los dos mundos: el dockerizado y el sin dockerizar. Se trataría de un entorno híbrido que hace que mis contenedores tengan asignadas una IP dentro de la red donde está mi host/s.

También existen plugins de terceros que extienden estas opciones, como por ejemplo Weave Net.

Por defecto, todas las instalaciones de Docker vienen con tres configuraciones creadas por defecto. Para comprobarlo puedes utilizar el siguiente comando:

Este te devolverá lo siguiente:

Veamos cada una de ellas con detalle.

Bridge

Este tipo es el más simple que ofrece Docker y es el que has estado usando todo este tiempo, sin tú saberlo. Se utiliza cuando sólo existe un host y solo es necesario comunicar los contenedores que viven en él entre ellos. En Linux se crean con el driver llamado bridge mientras que en Windows se utiliza el llamado nat, pero el funcionamiento es el mismo. Esta red es la utilizada por defecto, salvo que utilices el parámetro –network, que veremos después. Para comprobarlo, vamos a crear dos contenedores:

Si inspeccionamos la red bridge, veremos que existe un apartado llamado Containers donde aparecen los dos que tenemos ejecutándose:

docker network inspect bridge

Como ves, ahí están tus dos contendores, con las IPs 172.17.0.3 y 172.17.0.2, lo cual nos indica que están dentro del mismo rango y podrían comunicarse entre ellos. Pruebas a hacer un ping desde el container-1 al container-2:

y verás que el resultado es satisfactorio:

Sin embargo, cada vez que cree este contendor esta IP puede ser diferente, ya que de ninguna forma estas IPs se reservan a mis contenedores. Esto puede suponer un problema si varios contenedores se comunican entre sí, y quiero añadir esta información como parte de mi aplicación. Es por ello que lo que molaría es que pudieramos comunicarnos con los contenedores a través de su nombre, en lugar de la IP, y es otra de las características que Docker nos brinda. Sin embargo, en esta red bridge generada por defecto no es posible usar este mecanismo. De hecho, si lo intentas verás que los contenedores en esta red no se reconocen por su nombre:

Para ello debemos crearnos nuestras propias redes.

Crear tu propia red

Para crea una red dentro de Docker es súper sencillo, solamente debes utilizar el siguiente comando:

Una vez creada, si vuelves a listar las redes disponibles en tu host verás que tienes una nueva, llamada returngis-net que utiliza el driver bridge.

Para probar la comunicación a través del nombre vamos a crear dos contenedores dentro de la misma, utilizando el parámetro –network:

Si ahora intentamos hacer ping desde el contenedor b al contenedor a:

Veremos que en esta ocasión el resultado es positivo:

Esto es así porque en este escenario Docker utiliza un servidor DNS configurado por cada contenedor que les permite resolver el nombre del resto con los que comparta red.

Conectar un contenedor a dos redes

Una duda que puede surgirte a raíz de este ejemplo es ¿puede un contenedor conectarse a más de un red? Pues la respuesta es que sí

🙂

y también es muy fácil de hacerlo. Sin embargo, durante la creación solo es posible conectarse a una única red. Para conectarse a una segunda, tercera, etcétera necesitas hacerlo a posteriori utilizar el comando network connect:

Si has ido ejecutando todos los ejemplos, ahora el container-1, que originalmente solo estaba en la red por defecto, llamada bridge, ahora también pertenece a la red llamada returngis-net, por lo que podría comunicarse tanto con container-a como con container-b:

Host

Otra de las redes que aparece en el listado de tu máquina local era la llamada host. Lo que hace esta red es eliminar el aislamiento entre el host y los contenedores, por lo que un contenedor no recibe su propia IP, como vimos en los ejemplos anteriores, sino que utiliza la del host. Por lo tanto, si ejecutas un contenedor asociado a esta red escuchando por el puerto 80, la aplicación del contenedor estará disponible a través del puerto 80 de la IP del host. Este modo suele ser útil cuando necesitas mejorar el rendimiento de tu aplicación. Sólo funciona en Linux y no está soportado en Docker Desktop, debido a que estamos trabajando con una máquina virtual.

Para comprobar que funciona deberías de acceder a http://localhost:80.

None

En el caso de que no quisieramos que un contenedor tenga una red asignada, utilizaremos –network none como en el siguiente ejemplo:

Si ahora revisas las tarjetas de red que tiene asignado este contenedor comprobarás que solo aparece la interfaz loopback, que es para que el contenedor pueda hablar consigo mismo, pero nada más.

Overlay

Para el tipo overlay, necesitas trabajar en modo clúster. Si intentas crear una red de este tipo, sin estar en este modo, obtendrás el siguiente mensaje:

Sin embargo, la experiencia para ti sería la misma: la comunicación entre los diferentes contenedores podrá hacerse tanto a través de su IP como de su nombre, actuando como una única red, aunque haya diferentes máquinas ejecutando nuestros contenedores.

Macvlan

Como decía al inicio, existe un cuarto modo llamado macvlan que nos permite asignar IPs de una red a cada uno de los contenedores que viven en nuestro host. Sin embargo, para que este tipo de redes funcione necesitamos que la tarjeta de red del host esté en modo promiscuo, lo cual significa que necesita estar a la escucha de todos los paquetes que viajan por dicha red, simplemente para poder reconocer aquellos que potencialmente pueden ser para uno de sus contendores. Este modo muchas veces no está permitido en muchas organizaciones. La forma de configurar una red de este tipo sería así:

Con ello conseguiríamos que los contenedores que estén dentro de esta puedan ser alcanzados por otras aplicaciones que vivan fuera de Docker.

Gisela Torres

Gisela Torres trabaja en Microsoft como Cloud Solution Architect. Se trata de un puesto técnico cuya misión es apoyar y asesorar sobre soluciones y arquitecturas cloud utilizando Microsoft Azure como plataforma. Antes de eso trabajo como arquitecta de software y desarrolladora de aplicaciones en varias empresas. Durante esos años recibio varios premios por ejemplo Most Valuable Professional en Microsoft Azure. Le encanta programar y la tecnología en general.

Más artículos de Gisela en su blog - https://www.returngis.net/

Related Posts

Boletin informativo SpainClouds.com

Thank you! Your submission has been received!

Oops! Something went wrong while submitting the form