Como ya os he comentado en los anteriores capítulos, un stack es un conjunto de servicios interrelacionados que comparten dependencias y que pueden ser dirigidos (orchestrated) y escalados juntos.

La verdad es que ya lo hemos estado realizando hasta ahora (recordar los comandos docker stack). Lo que ahora nos hace falta es interrelacionar diferentes servicios y con ellos acceder a recursos permanentes.

Así, modificamos nuestro archivo «docker-compose.yml» para añadir dos servicios más. En total tendremos los siguientes servicios:

  • web — > Servicio web estática que nos muestra el nodo (hostname) que lo ejecuta y el numero de visitas a la web que lo obtiene de REDIS.
  • visualizer — > Servicio de visualización que usará la información que Docker almacena en el nodo «manager», y lo mapea a un almacenamiento con el mismo nombre. Este servicio se le forzará para que solo se ejecute en el nodo «manager» que es el que dispone de dicha información.
  • redis — > Este servicio es un almacén de estructura de datos (requiere que le establezcamos un sitio donde guardar esos datos dentro del contenedor a través de una relación del archivo host o nodo al contenedor) para ellos se mapea el directorio, sino hiciésemos esto, cada vez que se reinicie el nodo la información no sería permanente. Este servicio también se ejecuta solo en el nodo “manager”.

En las explicaciones anteriores han salido dos conceptos nuevos:

  •  Ejecución de servicios (o contenedores) en un nodo restringido. Esto lo conseguimos con el comando constraints: [node.role == manager].
  • Mapeo de almacenamiento (volumen). Esta es una característica que puede ser implementada de diferentes forma y de la que trataremos mas adelante en otras entradas, pero con saber que puedo «mapear» un espacio de almacenamiento local (host anfitrión) con uno interno del contenedor con el comando volumes: – «/home/user/data:/data« sobra. Obviamente tenemos que crear el archivo «./data» en el nodo manager antes de ejecutar “docker-compose.yml”.

El archivo nuevo de “docker-compose.yml” seria el siguiente:

version: «3»
services:
web:
# usamos una imagen desde un repositorio (como en este caso) o de la que ya dispongamos en el host local
image: maxtor71/test:part2
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: «0.1»
memory: 50M
ports:
– «4000:80»
networks:
– webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
– «8080:8080»
volumes:
– «/var/run/docker.sock:/var/run/docker.sock»
deploy:
placement:
constraints: [node.role == manager]
networks:
– webnet
redis:
image: redis
ports:
– «6379:6379»
volumes:
– «/home/user1/testdocker/data:/data»
deploy:
placement:
constraints: [node.role == manager]
command: redis-server –appendonly yes
networks:
– webnet
networks:
webnet:

Con el código anterior lanzamos 5 replicas de la web, 1 de redis y 1 de visualizer. En este caso hemos apagado un nodo y solo trabajamos con un nodo «manager» y otro «worker». Finalmente lanzamos nuestro stack como siempre docker stack deploy -c docker-compose.yml testmultiservices como podemos ver en la siguiente imagen.

Con docker service ls obtenemos la información de los servicios ejecutándose y los mapeo de puertos.

Comprobamos nuestros servicios con el servicio que nos proporciona visualizer en el puerto 8080.

Como vemos en visualizer tenemos dos nodos activos y otro apagado (en color rojo) y Swarm ha distribuido los contenedores entre los dos nodos restantes (manager y worker) pero manteniendo la restricción de que redis y visualizer deben de estar ejecutándose en el nodo «manager».

Para ver que nuestro servicio redis funciona vamos a comprobar si con varias visitas va aumentando el número de ellas que nos presenta en la web como se ve en la siguiente imagen.

Paramos todo (esto solo hace falta hacerlo en el nodo “manager”) y eliminamos la colmena en cada uno de los nodos. Esto se hace con:

  • docker stack rm testmultiservices
  • docker swarm leave –force

En el proximo capitulo hablaremos del gestor de volumenes y redes en dockers.