Hola Fronters!!! Espero que la hayan pasado genial. En el artículo anterior hicimos una introducción a docker network, aprendimos a administrar redes en Docker: crearlas, eliminarlas, inspeccionarlas, conectarnos a una red definida por el usuario, tanto desde un contenedor pre existente como creando el contenedor desde cero, etc), y creamos redes con el driver bridge y así establecer niveles de aislamiento desde contenedores. Aprendimos bastante y no vamos a parar precisamente ahora. Si no has leído el artículo anterior, te dejo el enlace aquí y así te pones al día.

Docker, tal y como vimos en el artículo anterior, cuenta con varios modos de conexión. En resumen: dependiendo de la necesidad y el alcance del proyecto, el despliegue será diferente y, por ende, el enfoque y visión cambiará. No es lo mismo mostrar nuestro desarrollo a un compañero, al líder de proyecto o al CEO, ni desplegarlo en producción; sin embargo lo que sí podemos lograr con Docker es poder hacer que ese despliegue funcione con los mismos avances y mejoras que fuimos incorporando paso a paso, desde su fase inicial hasta la última etapa del proyecto, que es el pase a producción. En resumen: hacemos que funcione «tal cual como en nuestra máquina»… Aquí es donde Docker brilla.

Por qué repito algo que se supone que vimos en el primer post? Por nada, sólo quería decirlo y recordarte que aquí puedes leer toda esta serie de artículos desde el principio… Y se me acabó el café, ya vuelvo…

( … Cinco minutos más tarde… )

Ahora que estamos «recargados», veamos ahora más sobre las redes en Docker… Allá vamos!

Host networks

Las Host networks, son redes de un solo contenedor. Son especiales para los desarrolladores que llevan muchos proyectos y pueden necesitar activar y desactivar cada uno a la vez para retomar sus respectivas fases de desarrollo. No se requiere hacer mapeo de puertos, pues automáticamente todos los puertos del contenedor quedarán mapeados en el Docker Host. En pocas palabras: si levantamos un contenedor con NGINX, todos los puertos relacionados con el NGINX quedarán automáticamente reflejados en el Docker Host. Otro aspecto importante es que al utilizar este tipo de red, se perderá la capa de aislamiento, por lo tanto dependerá de una capa externa de seguridad para proteger al Docker Host y otorgar los accesos debidos a los puertos autorizados.

Docker ya viene con una red de tipo Host creada y no nos permitirá crear otra, pues no tiene sentido crear dos redes exactamente con las mismas limitaciones, si la que viene por defecto funciona perfectamente para lo que se necesita.

Para ponerla en funcionamiento, lo que haremos es, en principio, bajar todos los contenedores. La razón es sólo para evitar conflictos con el funcionamiento de puertos y de que puedan existir solapamientos en cuanto a los otros contenedores.

Ahora lo que haremos es crear el contenedor, al cual llamaremos intranethost y estará basado en una imagen de NGINX:

docker create --name intranethost --network host nginx:latest

Lo iniciamos:

docker start intranethost

Al entrar en el navegador e ir a la dirección IP del Docker Host veríamos a nuestro contenedor intranethost en acción :

Fases de creación de contenedor con red de tipo Host
Imagen 1: Fases de creación de contenedor con red de tipo Host

No hay portmapping en lo absoluto. Este tipo de redes toman la red que tenga el Docker Host y sólo eso. Perderemos el aislamiento, pero podremos pasar de un proyecto a otro con la misma velocidad que ejecutemos un docker start nombrecontenedor. Es todo.

Fue demasiado fácil, no puede ser!… Siguiente red… Café y galletitas…

Al contrario de las redes tipo Host que vimos anteriormente, con el tipo de redes a continuación: la ipvlan, cambia todo, tanto en funcionamiento como en complejidad. Trataremos de dar una explicación lo más sencilla y amigable posible… Así que, tomamos aire y allá vamos!!!

Esta vez necesitaremos un Bed Rull… No voy a decir tu nombre… PA-TRO-CI-NA-MEEEE xD

Redes IPvlan

Las redes IPvlan, o redes que hacen uso del controlador o driver IPvlan, son muy flexibles. Estas nos permiten crear un comportamiento similar al de las máquinas virtuales (VM), en cuanto a su forma de conectividad, sin embargo tiene ciertas ventajas que veremos posteriormente.

IPvlan nos da flexibilidad y autonomía sobre la configuración de las redes, tanto en IPv4 como en IPv6, y la gestión de los procesos de capa dos, concernientes al etiquetado de las redes virtuales (VLAN Tagging), como los de enrutamiento, concernientes a la capa tres. Estos procesos son llevados a cabo de una forma rápida y dinámica y se basan en la interface física de red (NIC), generando sub interfaces que permiten la separación lógica y el aislamiento entre redes a conveniencia de las necesidades y requerimientos del despliegue.

Lo anteriormente mencionado nos proporciona beneficios directos, tales como el evitar la utilización de los puentes (bridges) y que podamos trabajar directamente con la interface de red del Docker Host, mejorando el performance de la red de nuestros containers. Otro de los grandes beneficios es que no es necesario que utilicemos mapeo de puertos, permitiéndonos la implementación servicios que requieran la exposición de más de dos o más puertos en un mismo nodo / dirección IP. Eso es genial!!!

Un ejemplo de IPvlan L2

Partiendo del punto de que nuestra interface de red se llama eth0 y que nuestra subred en formato CIDR es la 192.168.16.0/24:

Verificación de la red en el Docker Host
Imagen 2: Verificación de la red en el Docker Host

Implementaremos este ecosistema simple:

  • Un (1) enrutador de red físico, el cual fungirá como puerta de enlace.
  • Un (1) Docker Host
  • Una (1) red de nombre ipvl2net, que utiliza el controlador tipo IPvlan, y que utiliza la interface eth0 del Docker Host y la misma subred física.
  • Tres (3) contenedores, todos conectados a la red ipvl2net:
    • Contenedor_A: cuya dirección IP es la 192.168.16.70.
    • Contenedor_B: cuya dirección IP es la 192.168.16.71.
    • Contenedor_C: cuya dirección IP es la 192.168.16.72.
Diagrama básico de red con driver IPvlan de capa 2 y asignación de IP estática
Imagen 3: Diagrama básico de red con driver IPvlan de capa 2 y asignación de IP estática

Para comenzar, lo primero que haremos es crear una red con controlador ipvlan, que llamaremos ipvl2net y cuya subred es la misma de la red física, por lo tanto también utilizará la misma puerta de enlace (la 192.168.16.1), para ello especificaremos que la interface padre de salida sea la eth0 y de este modo, tendrá exposición al a red física. Si no especificamos esto, entonces la red estará aislada.

docker network create -d ipvlan --subnet=192.168.16.0/24 --gateway=192.168.16.1 -o parent=eth0 \ ipvl2net
Creando la red ipvl2net con el controlador ipvlan
Imagen 4: Creando la red ipvl2net con el controlador ipvlan

Ahora crearemos los contenedores. El primero será contenedor_A, con las siguientes características:

docker run --name contenedor_A --net=ipvl2net --ip=192.168.16.70 -dit --rm ubuntu

Si disectamos el comando veremos que:

  • Utilizará la red que creamos anteriormente: ipvl2net (Con el parámetro –net=ipvl2net)
  • Le asignaremos la dirección IP fija 192.168.16.70 (Con el parámetro –ip=192.168.16.70)
  • Correrá en modo desatendido e interactivo (con los atributos -dit)
  • Al terminar su tiempo de vida se eliminará automáticamente ( Con los atributos –rm)
  • Utilizará la imagen de Ubuntu

Y veremos de este modo como

Creando contenedor_A y conectándolo a la red ipvl2net
Imagen 5: Creando contenedor_A y conectándolo a la red ipvl2net

Ahora crearemos los dos contenedores faltantes y verificaremos, tal y como lo hicimos con el contenedor_A, que estos últimos estén corriendo:

Creación de los contenedores B y C y verificación de estado de funcionamiento
Imagen 6: Creación de los contenedores B y C y verificación de estado de funcionamiento

Inspeccionamos sus parámetros de red y verificamos que todo está correcto:

docker inspect contenedor_A contenedor_B contenedor_C | grep '"IPAddress":'

Y veremos las direcciones IP de cada uno de los contenedores consultados, de forma consecutiva. Todo está aparentemente bien.

Revisión de las direcciones IP de los contenedores A, B y C con docker inspect
Imagen 7: Revisión de las direcciones IP de los contenedores A, B y C con docker inspect

Hora del café les digo… Oye, está muy bueno!!!! =P

Solucionando el (posible) problema de redireccionamiento interno en Docker

Tenemos que editar el archivo o fichero /etc/sysctl.conf y editar la siguiente línea como root o super usuario:

sudo nano /etc/sysctl.conf

Y descomentaremos las líneas que dice net.ipv4.ip_forward y net.ipv6.conf.all.forwarding, estableciendo su valor a 1, sólo en caso de que no lo esté:

net.ipv4.ip_forward=1

net.ipv6.conf.all.forwarding=1

Guardar y salir del editor y luego ejecutar ( como root ):

sysctl -p

Y ahora hacemos ping desde otro nodo hacia nuestros contenedores:

Haciendo ping desde un nodo físico de la red hacia los contenedores ld1, ld2 y ld3
Imagen 8: Haciendo ping desde un nodo físico de la red hacia los contenedores ld1, ld2 y ld3

Super genial!!!! Creo que fue bastante claro. No obstante te recomiendo consultar la documentación oficial de Docker para mayor información. Te dejo el enlace en las referencias.

Cappuchino… Si señorrr!!!

Ahora combinamos TODO lo aprendido

Ahora, ¿Qué tal si combinamos todo lo aprendido hasta este momento? Nos volvimos locos?!?! Si, que más da!!! Vamos, no le temas al éxito, pues el camino al éxito está lleno de innumerables altibajos, errores y caídas… Así que vamos, que si nos equivocamos, lo hacemos todos y entre todos hallaremos la solución, pues así es el mundo de IT y no dejes que nadie te diga lo contrario!!!

Para hacer un repaso de todo, crearemos un ecosistema con todos los puntos que vienen a continuación:

  • Crearemos una red que se llame ecosist-ipvlan con el driver ipvlan y trabajaremos con IPvlan de capa dos (L2)
  • Vamos a crear tres contenedores con NGINX, y en cada uno colocaremos una landing page en cada uno, pero en cada uno de ellos mapearemos el puerto 80 y a su vez volúmenes distintos.
  • Cada contenedor se llamará ld (de landing page) y su respectivo número ordinal (1, 2 y 3): ld1, ld2 y ld3.
  • Por otra parte crearemos en /home/$USER/clients del Docker Host directorios en los que colocaremos los contenidos de cada landing page y los convertiremos en volúmenes para cada contenedor respectivamente.
  • Cada contenedor tendrá una dirección IP estática: ld1 tendrá la 192.168.16.80, ld2 tendrá la 192.168.16.81 y ld3 tendrá la 192.168.16.82.
Diagrama de red con contenedores NGINX mostrando landing pages diferentes, mapeando puerto 80 y volúmenes
Imagen 9: Diagrama de red con contenedores NGINX mostrando landing pages diferentes, mapeando puerto 80 y volúmenes

Detendremos y eliminaremos los contenedores creados previamente. Luego, eliminaremos la red ipvl2net, en caso de que la tengamos activa y funcionando.

docker stop $(docker ps -aq)

docker rm $(docker ps -aq)

docker network rm ipvl2net

Ahora crearemos la nueva red ecosist-ipvlan en el Docker Host:

docker network create -d ipvlan --subnet=192.168.16.0/24 --gateway=192.168.16.1 -o parent=eth0 \ ecosist-ipvlan
Creación de la red ecosist-ipvlan con driver ipvlan
Imagen 10: Creación de la red ecosist-ipvlan con driver ipvlan

Revisamos las redes y veremos algo similar a esto:

Revisando las redes creadas
Imagen 11: Revisando las redes creadas

Ahora creamos los contenedores con la imagen de NGINX. Atentos a esto: Sólo los creamos, no los arrancamos (esa es la diferencia entre los comandos docker run y docker create 😉

Adicionalmente, montaremos los volúmenes respectivos de cada uno en el directorio /usr/share/nginx/html, del servicio NGINX, con acceso de sólo lectura.


# Creamos el contenedor ld1
docker create --name ld1 --net=ecosist-ipvlan --ip=192.168.16.80 -v /home/$USER/clients/ld1:/usr/share/nginx/html:ro --publish 0.0.0.0:80:80 nginx:latest

# Creamos el contenedor ld2
docker create --name ld2 --net=ecosist-ipvlan --ip=192.168.16.81 -v /home/$USER/clients/ld2:/usr/share/nginx/html:ro --publish 0.0.0.0:80:80 nginx:latest

# Creamos el contenedor ld3
docker create --name ld3 --net=ecosist-ipvlan --ip=192.168.16.82 -v /home/$USER/clients/ld3:/usr/share/nginx/html:ro --publish 0.0.0.0:80:80 nginx:latest
Creando los contenedores ld1, ld2 y ld3
Imagen12: Creando los contenedores ld1, ld2 y ld3

Ahora en el Docker Host crearemos la estructura de directorios necesaria para que nuestros volúmenes funcionen adecuadamente:

mkdir -p /home/$USER/clients/{ld1,ld2,ld3}

Verificamos que los directorios se hayan creado correctamente:

Verificación de la estructura de directorios creada.
Imagen12: Verificación de la estructura de directorios creada.

Bien, hecho esto buscaremos unas landing pages bien interesantes para hacer nuestro ejemplo. En este caso he encontrado estas tres en este sitio, pero la verdad puedes colocar una página estática cualquiera, como la del ejemplo que pusimos en el artículo anterior enel que hablamos sobre Mapeo de Puertos y Volúmenes. Si no lo has leído, te dejo el enlace aquí. Lo importante de todo esto es que podamos seguir con el laboratorio. En mi caso particular, he tenido que descargar los archivos zip, uno a uno, y luego enviarlos al Docker Host vía SCP, para luego descomprimirlos y ubicar los ficheros contenidos en cada uno de los volúmenes creados. Vaya tarea!!!

Estructura de ficheros y directorios de cada volumen por contenedor
Imagen 13: Estructura de ficheros y directorios de cada volumen por contenedor

Y por último, pero no menos importante!!! Iniciamos los contenedores:

docker start ld1 ld2 ld3
Iniciando nuestros contenedores
Imagen 14: Iniciando nuestros contenedores

Revisamos si nuestros contenedores están arriba y corriendo:

Chequeando el status de los contenedores
Imagen 15: Chequeando el estado de los contenedores

Ahora si vamos al navegador web y entramos a las direcciones IP de cada uno de los contenedores veremos nuestras landing pages funcionando.

En el contenedor ld1:

Contenedor ld1 corriendo con la primera landing page
Imagen 16: Contenedor ld1 corriendo con la primera landing page

En el contenedor ld2:

Contenedor ld2 corriendo con la segunda landing page
Imagen 17: Contenedor ld2 corriendo con la segunda landing page

Y en el contenedor ld3:

Contenedor ld3 corriendo con la tercera landing page
Imagen 18: Contenedor ld3 corriendo con la tercera landing page

Cierre y Despedida

¿Qué tal les pareció? Super bien salió todo!!!, Hoy hemos aprendido a desplegar contenedores con ipvlan y además reforzamos aprendizaje previo muy importante sobre volúmenes y puertos. De verdad espero que haya sido de su agrado y que hayamos podido entender e incorporar más conocimiento, pues de esto se trata: de aprender.

Recuerda que si tienes dudas o preguntas puedes colocarlas en los comentarios y así aprendemos todos un poco más y hacemos crecer a esta bonita comunidad.

Hasta luego Fronters!!!

Referencias

Docker: Documentación Oficial

Themewagon.com: Templates Landing Pages fabulosos