El artículo se ha escrito utilizando docker 1.12 y 4 máquinas ubuntu 16.04.1 LTS virtualizadas con VirtualBox, de las cuales solo 1 de ellas tenia instalado docker-machine.
Este artículo es una guia rápida de creación de un cluster de nodos de docker, gestionados de forma nativa por docker swarm.
Algunos de los conceptos manejados por docker swarm son:
- nodos. Diferentes equipos ejecutando docker
- manager. Uno de los nodos del cluster actúan de manager y es el responsable de gestionar los nodos del cluster.
- worker. El resto de nodos son los workers. Estos con los responsables de ejecutar las tareas que el manager le indica, creando y ejecutando los contenedores. El manager también puede actuar como worker.
Cuando desplegamos una aplicación en un cluster de docker swarm, creamos una definición de un servicio. Esta definición del servicio la enviamos al manager. El manager divide el servicio en tareas o tasks y las envia a los workers, que son los que finalmente ejecutan las tareas. Estas tareas o tasks se traducen en la creación de los contenedores que son los que finalmente ejecutan nuestra aplicación.
Creación del cluster swarm y del manager
Nos conectamos a uno de los nodos para seleccionarle como el manager.
$ eval $(docker-machine env node-2) $ docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS node-1 - generic Running tcp://192.168.56.104:2376 v1.12.1 node-2 * generic Running tcp://192.168.56.102:2376 v1.12.0 node-3 - generic Running tcp://192.168.56.103:2376 v1.12.0 $ docker swarm init --advertise-addr $(docker-machine ip node-2) Swarm initialized: current node (4hrikn3j4fls4xrdz8dzc2g9r) is now a manager. To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-31svc7oooa11nisnue3p2lysil3tczafncdkjk6voyht3zoh2a-36ng05zu8nw82d1npvxflbzpc \ 192.168.56.102:2377 To add a manager to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-31svc7oooa11nisnue3p2lysil3tczafncdkjk6voyht3zoh2a-7diqubxwe8ghhtqe2g3rgqhz1 \ 192.168.56.102:2377
Creacion de los workers
Nos conectamos al resto de nodos para que se unan al swarm o cluster recién creado y les decimos que actúen como workers.
$ eval $(docker-machine env node-3) $ docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS node-2 - generic Running tcp://192.168.56.102:2376 v1.12.0 node-3 * generic Running tcp://192.168.56.103:2376 v1.12.0 $ docker swarm join \ --token SWMTKN-1-31svc7oooa11nisnue3p2lysil3tczafncdkjk6voyht3zoh2a-36ng05zu8nw82d1npvxflbzpc \ 192.168.56.102:2377 This node joined a swarm as a worker.
Repetimos el mismo paso para el node-1.
Comprobar el estado del cluster
Nos conectamos al manager para comprobar el estado del cluster.
$ eval $(docker-machine env node-2) $ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 4hrikn3j4fls4xrdz8dzc2g9r * node-2 Ready Active Leader 6p5kd0u96vcs5m70kmc3c78s2 node-3 Ready Active 8aircf03acpeu1ym8oq9bb7j2 node-1 Ready Active
Volver a ver los tokens para gestionar los manager y los workers
Desde el nodo manager ejecutamos los comandos siguientes.
$ docker swarm join-token manager To add a manager to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-31svc7oooa11nisnue3p2lysil3tczafncdkjk6voyht3zoh2a-7diqubxwe8ghhtqe2g3rgqhz1 \ 192.168.56.102:2377 $ docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-31svc7oooa11nisnue3p2lysil3tczafncdkjk6voyht3zoh2a-36ng05zu8nw82d1npvxflbzpc \ 192.168.56.102:2377
Crear una red de tipo overlay
Para la comunicación entre contenedores desplegados en diferentes nodos debemos crear una red de tipo overlay.
$ docker network create --driver overlay mydemo-network 0wmy8heuieggqzsi8y5fg1vz2
Creación del primer servicio y comprobación del servicio
La imagen francois/apache-hostname está basada en un servidor apache que devuelve el id del contendor donde se ejecuta.
El servicio crea 3 contenedores en el cluster, cada uno de ellos desplegado en el puerto 80, pero accesible desde fuera en el puerto 8080.
Esto significa que cualquier petición que realicemos a cualquiera de los nodos del cluster al puerto 8080, docker swarm se va a encargar de enviar la petición balanceando la carga a 1 de los nodos del cluster al puerto 80, y será el contenedor ejecutandose en ese nodo el que responda a la petición.
Docker swarm realiza el balanceo a nivel interno creando una IP virtual por cada servicio. El balanceo se produce utilizando IPVS, el cual se encuentra implementado en el Kernel de linux, con lo que conseguimos un balanceo de carga con un rendimiento mayor del que conseguiríamos utilizando Nginx, HAProxy o similares.
IPVS (IP Virtual Server)
Creación del servicio
La definición del servicio se la mandamos al manager. Entre los parámetros posibles se encuentra el número de replicas del servicio, lo que se traduce en tareas que son enviadas a los workers, y que se convierten en la creación de 1 contenedor por replica.
Si una de las replicas (contenedor) cae, el servicio sigue siendo atendido por el resto de replicas (contenedores) mientras docker swarm levanta una nueva replica para mantener el estado inicial de la definición del servicio.
$ docker service create --name echo-container-id --replicas 3 --network mydemo-network -p 8080:80 francois/apache-hostname 8ccdsdi7av1hcpggb5y2xluwr $ docker service ls ID NAME REPLICAS IMAGE COMMAND 8ccdsdi7av1h echo-container-id 0/3 francois/apache-hostname
Recién creado el servicio no existe ninguna replica ejecutando el servicio. Por eso vemos 0/3 en el número de replicas. Si esperamos unos segundos y volvemos a ejecutar el mismo comando, veremos como el número de replicas disponibles se convierte en 3.
$ docker service ls ID NAME REPLICAS IMAGE COMMAND 8ccdsdi7av1h echo-container-id 3/3 francois/apache-hostname
Comprobación del servicio
Vemos como cada petición es resulta por diferentes contenedores, que se encuentran ejecutándose en nodos diferentes del cluster.
$ curl http://node-1:8080 <html><body>This page is displayed on the container: <b>21e83efd0c75</b></body></html> $ curl http://node-1:8080 <html><body>This page is displayed on the container: <b>317d9e7a04bc</b></body></html> $ curl http://node-1:8080 <html><body>This page is displayed on the container: <b>e75e3d5ddc73</b></body></html> $ curl http://node-2:8080 <html><body>This page is displayed on the container: <b>21e83efd0c75</b></body></html> $ curl http://node-3:8080 <html><body>This page is displayed on the container: <b>317d9e7a04bc</b></body></html>
Conclusión
Como vemos la creación de un cluster con docker swarm 1.12 es realmente sencilla. Cualquier aplicación que necesitemos crear la traduciremos en una definición del servicio, que como hemos visto se la enviaremos al manager, y el se encargará del resto por nosotros.