27 – docker swarm

Te doy la bienvenida al episodio 27 de deployandome, el podcast de tecnología para sysadmins y devops. Soy Rodolfo Pilas y estoy grabando el 20 de marzo de 2018.

Si recuerdas el episodio anterior de deployándome habíamos estado conversando en forma general sobre los cluster de docker y habíamos visto que permiten solucionar problemas de escalabilidad. Vimos que son útiles cuando tus aplicaciones o servicios tienen requisitos de disponibilidad continua y en caso de problemas necesitas recuperarte automáticamente. También los clusters, permiten adaptar en forma elástica el consumo de recursos de computación asignando mas recursos o liberándolos.

En esta edición voy a concentrar las características del cluster nativo de Docker; vamos a estar viendo Docker Swarm: que podemos definir como la manera de tener varios Docker Engine corriendo como un enjambre.


Decir que Docker Swarm es nativo en Docker tiene una doble implicancia:

Por un lado significa que no se debe instalar nada más que docker (y me refiero al daemon Docker Engine y su cliente docker) para poder armar un cluster, es decir que Docker Swarm está integrado en Docker que ya tienes instalado.

Y, por el otro lado, significa que es muy fácil de implementar, pues el trabajo de instalarlo es exactamente el mismo que instalar Docker en varias máquinas. Lo que vamos a tener son Docker Engine que asumen distintos roles y esos roles son dos: manager y worker. Los worker solamente levantarán dockers con mi aplicación y los manager también lo harán, pero además se encargarán de los servicios del propio cluster.

Además de estas dos características, Docker Swarm tiene una serie de funciones automáticas, de las cuales te comento cinco de ellas:

Primero, la reconciliación de estado, es decir que si mi servicio se basa en tener levantados, por ejemplo, cinco réplicas de contenedores balanceados y por algún motivo alguna se cae, Docker Swarm se dará cuenta del problema y se encargará de recuperar el estado deseado de mi servicio sin que necesite tomar ninguna acción.

Pero la reconciliación del estado no se queda solo en el servicio o mi aplicación. Si por algún motivo el nodo con el rol de manager activo se cae otro nodo con el rol manager tomará su lugar y se volverá activo, si es que configuramos más de un manager dentro del cluster (algo recomendado en ambientes de producción)

Segundo el descubrimiento de los servicios. ¿qué quiere decir esto? supongamos que tengo un cluster formado por diez computadores (o máquinas virtuales) cada una de ellas corriendo Docker Swarm y cuando levanto mi servicio digo que debe tener cinco réplicas corriendo, cada una ira a levantarse en alguno de los nodos, sin un orden y será tarea del manager activo registrar en qué nodos se levantó cada réplica de mi servicio, para conducir las peticiones de los clientes hasta la aplicación. Obviamente podemos definir políticas de afinidad para que una aplicación vaya al nodo o grupo de nodos que deseo.

En tercer lugar Docker Swarm hará una magia interesante a nivel de red para que mi servicio que puede requerir multiples dockers pueda funcionar como siempre, es decir, como si estuviera en una sola máquina.

A ver si me explico:

Supongamos que levantamos WordPress: tendremos un docker para el servidor web, digamos nginx, otro para el PHP con php-fpm y otro para la base de datos MySQL, cada uno de estos docker tendrá con la directiva EXPOSE configurado el puerto que escucha su servicio y se vinculará con la directiva LINK desde el docker que consume los servicios. Hasta aquí algo que hacemos con cualquier WordPress que levantamos en docker.

Cuando lo llevamos a un cluster Docker Swarm esto se complica, pues podemos configurar que tendremos solo una réplica para el MySQL que se levanta en algun nodo, digamos el nodo 1; tres réplicas de PHP que se levantará en los nodos 2, 3 y 4 y dos réplicas del web de nginx que se levantaran en los nodos 3 y 5.

¿empezas a ver donde está la magia?

En este ejemplo Docker Swarm se encargará de presentar el puerto EXPOSE 3306 del docker MySQL que corre en el nodo 1 como localhost:3306 en los docker de PHP que están corriendo en los nodos 2, 3 y 4 y yo no tendré nada más que hacer lo que siempre he hecho, usar la directiva LINK.

Y si los docker cambian de nodo, por reconciliación o por el motivo que sea, Docker Swarm se encargará de gestionar el tráfico interno de red para que los docker se comuniquen como si estuvieran en la misma máquina.

¿te estarás preguntando si esto funciona con VOLUMES? Y no, Docker Swarm para un storage entre varios docker requiere un servicio de storage independiente al cluster. A mi modo de ver un manejo externo del storage compartido no es muy diferente a lo que requiere un servicio de cloud con múltiples instancias.

Pero sigamos con las funcionalidades de Docker Swarm:

Estamos en el cuarto punto, Docker Swarm se encargará balancear automáticamente las peticiones de los clientes hacia todas las instancias docker repartidas en el cluster que se encargan de nuestro servicio.

Y, por último como quinto punto, Docker Swarm se encargará de gestionar los procesos de actualización de nuestros aplicaciones, siempre manteniendo el servicio activo mientras va reemplazando uno a uno los contenedores con la nueva versión cuando se deba actualizar.

¿te gusta? pongámos a correr nuestro cluster Docker Swarm y luego me cuentas.


Para empezar necesitamos un conjunto de máquinas corriendo Docker Engine. La forma más fácil que conozco es con la utilidad docker-machine que también viene nativa con Docker.

Docker Machine es una herramienta que nos permite levantar y administrar máquinas virtuales con docker sobre hypervisores Oracle Virtualbox o Microsoft Hyper-V tanto en forma local como en nuestro propio datacenter y también en instancias en las nubes de Amazón, Digitalocean o Azure. Además docker-machine nos va ayudar administrar nuestro conjunto de máquinas ya sea para ingresar a alguna de ellas por ssh o para configurar el entorno de nuestro cliente docker local para utilizar el cluster swarm que levantemos.

Así que con docker-machine create vamos a ir levantando una a una las máquinas de soportarán nuestro cluster, las que necesitemos: yo con cinco máquinas me conformo para estas pruebas y con docker-machine ls podemos listar las máquinas que se han creado.

#!/bin/bash

docker-machine create --driver virtualbox manager1
docker-machine create --driver virtualbox manager2
docker-machine create --driver virtualbox worker1
docker-machine create --driver virtualbox worker2
docker-machine create --driver virtualbox worker3

echo
echo
sleep 5
docker-machine ls

A conjunto de máquinas necesitamos configurarlas en un cluster swarm. Para ello necesitamos ingresar a cada una de las máquinas con docker-machine ssh y ejecutar unos comandos de docker siguiendo estos cuatro pasos:

Primero: ingresar en el nodo manager y ejecutar docker swarm init para iniciar nuestro cluster y que nos va a devolver un comando docker swarm join con un token.

Segundo: ingresar en cada uno de los nodos que serán worker y pegar ese comando de docker swarm join con el token para unirlos al cluster.

Tercero: nuevamente en el nodo manager ejecutamos docker swarm join-token manager que nos devolverá otro comando docker swarm join pero ahora con el token para unir nodos managers.

Y cuarto: ingresar a los otros nodos manager y ejecutar docker swarm join pero con el token de manager.

Con esto tendremos nuestro cluster Docker Swarm con manager activo, managers no-activos y workers armado. ¿fácil, no? Para poder administrarlo con nuestro docker local corremos docker-machine env que nos devolverá el entorno que debemos configurar localmente y ahora sí podemos ejecutar comandos como docker node ls para consultar el estado de nuestro cluster.

Si has conseguido seguir mi explicación, te resultará muy simple.


¿cómo levantamos una aplicación en nuestro cluster?

Tiene algunas "pisadas", pero es casi lo mismo que levantar una aplicación docker común y corriente, es decir, podemos usar tanto el comando docker como docker-compose.

Debemos recordar que si vamos a basarnos en una imágen esa imagen debe estar accesible en un repositorio al que todos los nodos puedan llegar ya que será cada nodo el que descargue y levante la imagen. Suelo hacer docker push contra repositorios en Amazon Elastic Container Registry, pero perfectamente puedes usar docker hub o un Registry dentro de tu datacenter.

Ahora docker no va a levantar un contenedor, sino que lo que levantará es un servicio con el comando docker service create y como parámetro el número de réplicas que queremos que mantenga el cluster.

Y ya está! podemos ejecutar docker service ls reiteradas veces para ver como el cluster va levantando de a una las replicas del servicio que le he pedido hasta llegar al estado deseado.


En un ambiente de pruebas quedan muchas cosas divertidas por hacer:

  • apagar algunos nodos worker para ver como nuestro servicio se re-establece
  • apagar el manager activo, para ver como el otro manager toma su lugar
  • cambiar la cantidad de replicas deseadas de un servicio
  • actualizar la imagen de nuestra aplicación y correr docker service update para ver como Docker Swarm realiza el recambio de los docker por la última version.

y de seguro se te ocurrirán más cosas, pues te confieso que esto tiene tela para rato. Por ejemplo, puedes orquestar un servicio multi-container con docker-compose, pero si además usas archivos yaml de docker-compose version 3, puedes usar la funcionalidad de docker-compose ya nativa del comando docker con docker deploy.

Te invito a que busques alguna imagen docker con un servicio para probar o te crees una tuya propia, utilices docker-machine para levantar varias máquinas virtuales y armes tu cluster Docker Swarm.


Soy Rodolfo Pilas, en twitter me puedes seguir por @pilasguru y te dejo un saludo. Confío que este podcast te haya aportado para mejorar y, como siempre, espero tus inquietudes y sugerencias comentando en deployando.me

Hasta la próxima edición.