Introducción y ejemplo de cluster de contenedores con Docker Swarm

Publicado por pico.dev el .
blog-stack gnu-linux planeta-codigo planeta-linux
Comentarios

Las funcionalidades de Docker Swarm están incorporadas en Docker para gestionar clusters de nodos con contenedores de los servicios que deseemos. En artículo comentaré algunas de las propiedades de networkning distribuido incorporado en Docker, como crear un cluster de nodos Docker usando VirtualBox con máquinas virtuales para simular múltiples máquinas junto con como lanzar un servicio en el cluster que en este caso consistirá en un servidor web nginx.

Docker

En artículos anteriores de la serie sobre Docker comentaba varias de las herramientas de Docker como Docker Compose, Dockerfile o Docker Machine con ejemplos de como usarlo en local. Una de las herramientas que me quedaba por investigar era Docker Swarm para crear clusters de nodos para contenedores Docker en un entorno de producción. A partir de la versión 1.12 de Docker se han incorporado varias características a Docker para usaar contenedores de forma distribuida y que a pesar de la complejidad subjacente que debe haber es realmente simple usarlo.

Una de las características es el networking que hace trasnparente la comunicación en red distribuida que se hace entre los nodos y los contenedores de esos nodos. Además permite crear redes por software para que los contenedores conectados a esas redes se comuniquen de forma privada. Otra característica interesante de Docker Swarm es que se encarga de monitorizar el estado de los servicios recreando contendores si alguno deja de funcionar. También a través del denominado routing mesh da igual al nodo del cluster por el que se acceda y da igual en que nodo esté el contenedor que Docker Swarm con esta propiedad se encargará de hacer llegar la petición al contenedor. Además, a lo que en Docker Swarm se denomina servicio se realiza balanceo de carga entre la instancias del mismo que haya en el cluster y al servicio se le asigna un DNS y dirección IP por el que puede ser accedido por otros servicios.

En el siguiente ejemplo para crear el cluster de nodos Docker usaré Docker Machine para crear las máquinas de los nodos en máquinas virtuales de VirtualBox aunque su funcionamiento es similar si usásemos la nube de Amazon EC2, Digital Ocean u otros.

El siguiente script crea primeramente varios nodos cada uno en una máquina virtual, luego establece el nodo 01 como manager y los nodos 02 y 03 como workers usando un token para unirlos al cluster según su rol. Los nodos manager se encargan de mantener el estado del cluster y los que a través de ellos los comandos de los servicios deben ser lanzados, en un entorno de producción posiblemente tendríamos 3 nodos manager para soportar tolerancia a fallos. Finalmente, se obtiene lista los nodos del cluster. El comando docker-machine env node-01 permite establecer el entorno contra el que el comando docker lanzará las operaciones como si de la máquina local se tratase.

Una vez creado los nodos es cuando podemos empezar a crear servicios en el cluster. Los servicios son una definición de los contenedores de Docker que queremos que el cluster ejecute. En el ejemplo definiré el servicio de un servidor web nginx, primeramente crearé una red por software en el cluster a la que los servicios pueden conectarse que en el ejemplo (aunque para este no es necesario) utilizaré para hacer una consulta DNS con la herramienta drill para ver el nombre de dominio y dirección IP que asigna Docker Swarm al servicio del servidor web. Con docker service create se crean los servicios, algunos de los parámetros del comando son el nombre del servicio que queremos asignarle, los puertos que expone en este caso el 80 y 443 en el host para que sea accesible desde fuera del cluster, la redes a las que está conectado y finalmente la imagen del contenedor del servicio que en este caso será la versión de nginx con Alpine para Docker. Se pueden listar los servicios que contiene el cluster con docker service ls y los procesos de cada nodo donde podemos ver en que nodos se está ejecutando los contenedores con docker ps.

Una de las propiedades interesantes del networking de Docker Swarm es que ofrece incorporado balanceo de carga, esto es, si el servicio de nginx del ejemplo estuviese formado por dos instancias las peticiones se distribuirían entre las instancias usando el método round-robin. Otra característica interesante si se observa el ejemplo con detalle es que da igual el nodo al que hagamos la petición que la respuesta se obtendrá igualmente, esto es, aunque la petición se haga al nodo 01 y realmente el contenedor del servidor nginx se esté ejecutando en el nodo 02 la petición se realizará correctamente gracias al routing mesh del neworking de Docker Swarm, esto es gracias a que cada servicio tiene asignada una dirección IP, como se ha visto anteriormente en la salida del comando drill.

En este vídeo de asciinema se ve en funcionamiento todos los anteriores comandos. Y en la aplicación de VirtualBox estarán las máquinas virtuales de cada uno de los nodos que crea el ejemplo. En el vídeo se aprecia que el servicio de nginx se está ejecutando en el nodo 02 cuando se listan los procesos de Docker de cada nodo con docker ps, nótese sin embargo que al hacer un petición HTTP a cualquiera de los nodos se devuelve la página de inicio de nginx ya que gracias al routing mesh de Docker Swarm la petición se redirige de forma transparente para el cliente y el servicio al nodo donde realmente se está ejecutando el contenedor de nginx.

Introducción y ejemplo de cluster de contenedores con Docker Swarm
Máquinas virtuales de los nodos del cluster de Docker Swarm

Los comandos para eliminar un servicio del cluster y eliminar completamente el cluster son los siguientes.

Un libro que me ha gustado mucho y que recomiendo leer sobre Docker Swarm es The Devops 2.1 Toolkit que lo explica detalladamente y todo el libro está orientado a como usarlo en un entorno de producción. Un libro más introductorio que también he leído y que está bastante bien es Docker in Action.

Finalmente, quizás si estás usando GNU/Linux y VirtualBox como yo al crear los nodos con el comando docker-machine te produzca el siguiente error (quizá se corrija en futuras versiones de Docker o VirtualBox).

La solución que he encontrado para que funcione es asignar una dirección IP al adaptador puente solo-anfitrión y levantar la interfaz que usa Docker para comunicarse con las máquinas virtuales previamente a crear el nodo. En Arch Linux con los siguientes comandos.

Se puede definir un conjunto de servicios como una unidad en un archivo en stacks de forma similar a como es posible hacer con Docker Compose cosa que mostraré en otro artículo.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub.

Yo apoyo al software libre