Nomad – Despliegue y supervisión sencilla de aplicaciones

0
6414

En este tutorial vamos a conocer Nomad y ver cómo puede facilitarnos los despliegues y el escalado de aplicaciones.

Índice de contenidos


1. Introducción

Cuando comienzas a desarrollar aplicaciones complejas orientadas a servicios, o incluso con microservicios, el número de artefactos a desplegar se vuelve inmanejable.
Si además quieres tener un entorno de alta disponibilidad con varios nodos balanceados ejecutando tu aplicación esto es aún más tedioso.
Tanto si quieres desplegar contenedores de Docker, como aplicaciones Java directamente, o apps de otro tipo como Apache Spark; Nomad es lo que necesitas.

Nomad es una pequeña pieza de software que se instala en los servidores que formarán parte de tu clúster. Se compone de dos partes: una servidor (gestiona los despliegues) y otra cliente (aloja los depliegues).
Se recomienda tener 3 servidores y tantos clientes como se necesiten por cada zona.

Se declaran los trabajos, se planifican y muestran por pantalla los cambios que se aplicarán y se ejecuta el despliegue distribuido. Puedes ver el progreso en todo momento. Además te supervisarán los nodos y desplegará nuevas instancias en caso de caídas.
Permite el uso combinado de una nube pública (tipo AWS o Azure) y una entorno privado, distribuyendo las aplicaciones como si de uno solo se tratara.


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2.2 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS X El Capitan 10.11.6
  • Entorno de desarrollo: Atom
  • Sistema operativa de las VM: CentOS/7
  • Nomad 0.5.0
  • Consul 0.7.0
  • Vagrant
  • Ansible
  • VirtualBox
  • Nginx


3. Qué hace y qué no hace

Nomad es una utilidad de «HashiCorp» que se instala en servidores y puede tener dos roles. Actuar como servidor para gestionar y supervisar los despliegues; o actuar como cliente para alojar estos despliegues.

Nomad no pretende ser una solución completa para orquestar una red de contenedores de Docker. Al menos no por sí solo.

Nomad no es un servidor de descubrimiento para resolver las ubicaciones de las aplicaciones desplegadas, pero para ello se integra muy bien con «Consul», que es una herramienta también de «HashiCorp».

Nomad no es un balanceador de carga ni un proxy para redirigir las peticiones a los diferentes nodos que tienen una aplicación. Aunque para ello se puede utilizar Nginx, Fabio, Traefik, HAProxy, etc. y automatizar su configuración desde los datos de consul utilizando consul-template.

Nomad no dispone de una gestión de secretos pero para ello se integra muy bien con «Vault», que es una herramienta también de «HashiCorp».


4. Instalación y arquitectura

Vamos a automatizar la instalación de nomad utilizando Vagrant (creación de máquinas virtuales) y Ansible (instalación y configuración de aplicaciones).
Si no conocéis estas herramientas podéis ver un tutorial aquí.

Podéis clonaros el siguiente repositorio para seguir el tutorial:
https://github.com/miyoda/nomad-consul-nginx

Como podréis ver en el fichero «inventory» vamos a crear 6 máquinas de las cuales 3 serán servidores y 3 clientes de nomad. Con ips desde 192.168.10.11 hasta 16.

[server]
cluster1 ansible_host=192.168.10.11 ansible_ssh_host=192.168.10.11 consul_bootstrap=true
cluster2 ansible_host=192.168.10.12 ansible_ssh_host=192.168.10.12
cluster3 ansible_host=192.168.10.13 ansible_ssh_host=192.168.10.13

[client]
cluster4 ansible_host=192.168.10.14 ansible_ssh_host=192.168.10.14
cluster5 ansible_host=192.168.10.15 ansible_ssh_host=192.168.10.15
cluster6 ansible_host=192.168.10.16 ansible_ssh_host=192.168.10.16

Si ejecutamos desde línea de comando «vagrant up» se crearán automáticamente las máquinas tal cual se define en el fichero «Vagrantfile».

	$ vagrant up
	Bringing machine 'cluster1' up with 'virtualbox' provider...
	Bringing machine 'cluster2' up with 'virtualbox' provider...
	Bringing machine 'cluster3' up with 'virtualbox' provider...
	Bringing machine 'cluster4' up with 'virtualbox' provider...
	Bringing machine 'cluster5' up with 'virtualbox' provider...
	Bringing machine 'cluster6' up with 'virtualbox' provider...
	......

Ya tendremos las máquinas creadas en nuestro VirtualBox


Además se ejecutarán los siguientes roles de ansible (en función de la maquina) como se define en el fichero «nomad.yml»:

	- hosts: client
	  become: yes
	  roles:
	    - ansible-role-docker
	    - ansible-role-java

	- hosts: all
	  become: yes
	  roles:
	    - ansible-role-consul
	    - ansible-role-nomad

	- hosts: server
	  become: yes
	  roles:
	    - ansible-role-proxy

Los roles «ansible-role-docker» y «ansible-role-java» son para que los servidores que sean clientes nomad que ejecutarán las aplicaciones dispongan de un entorno de ejecución Docker y Java respectivamente.
Si, por ejemplo, un nodo no tiene Java instalado y das la orden de ejecutar un Job de Java, el nodo en cuestión no será seleccionado por Nomad para desplegar la aplicación por falta de drivers.

El role «ansible-role-consul» se encarga de la instalación de Consul en todos los nodos. Consul es un servicio de autodescubrimiento que nos será útil para que Nomad pueda descubrir al resto de nodos y para poder gestionar/almacenar dónde está desplegado cada aplicación/artefacto.

El role «ansible-role-nomad» se encarga de la instalación de Nomad en todos los nodos. Tres de ellos lo usaran como servidor y otros tres como cliente.

El role «ansible-role-proxy» se encarga de la instalación de nginx en los nodos servidores. Este role podría ser instalado en otro servidor independiente. La función de nginx aquí es servir de balanceador para las aplicaciones utilizando Consul para saber a que servidor redirigir cada petición en función de donde la haya desplegado Nomad. Configura también un tarea de consul-template para que la configuración de nginx cambie automáticamente si se despliega en nuevos nodos o desaparece alguno.


El flujo de comunicaciones y despliegue del sistema es, como se ve en la imagen, el siguiente:

  • 1. Nomad despliega una aplicación en uno o varios de sus nodos.
  • 2. Nomad registra en Consul los nodos que tienen aplicación desplegada.
  • 3. Nginx se autoconfigura con los datos de Consul mediante el proceso de consul-template.
  • 4. Las peticiones entrarán a «nginx» (cualquiera de los 3 nodos servidores que lo tienen desplegado).
  • 5. Nginx redirige la petición a uno de los nodos de Nomad que tienen la aplicación solicitada en función de la u
    Url de entrada.


5. Uso

Una vez finalice la creación de los servidores, lo cual puede llevar unos minutos, ya podemos conectarnos a ellos. Para conectarnos a una de las máquinas ejecutar «vagrant ssh cluster1» o «vagrant ssh cluster2», etc.

Consul

Podemos ejecutar comandos para ver el estado del servicio de Consul y sus nodos. Esto se puede ejecutar en cualquier nodo puesto que todos tienen Consul instalado.

	$ consul members
	Node      Address             Status  Type    Build  Protocol  DC
	cluster1  192.168.10.11:8301  alive   server  0.7.0  2         europe
	cluster2  192.168.10.12:8301  alive   server  0.7.0  2         europe
	cluster3  192.168.10.13:8301  alive   server  0.7.0  2         europe
	cluster4  192.168.10.14:8301  alive   server  0.7.0  2         europe
	cluster5  192.168.10.15:8301  alive   server  0.7.0  2         europe
	cluster6  192.168.10.16:8301  alive   server  0.7.0  2         europe

	$ consul monitor
	...

	$ consul info
	...

Si todo ha ido bien se habrá desplegado Consul en todos los nodos, se habrá seleccionado un líder, y debería estar accesible su UI desde la url siguiente (de cualquiera de los servidores):
http://192.168.10.11:8500/ui/

Nomad

Podemos ejecutar comandos para ver el estado del servicio de Nomad y sus nodos. Esto se puede ejecutar en cualquier nodo puesto que todos tienen nomad instalado; y si no es de tipo servidor se conectará a uno para obtener la información necesaria.

	$ nomad status
	No running jobs

	$ nomad server-members
	Name             Address        Port  Status  Leader  Protocol  Build  Datacenter  Region
	cluster1.global  192.168.10.11  4648  alive   false   2         0.5.0  dc1         global
	cluster2.global  192.168.10.12  4648  alive   true    2         0.5.0  dc1         global
	cluster3.global  192.168.10.13  4648  alive   false   2         0.5.0  dc1         global

	$ nomad node-status
	ID        DC   Name      Class   Drain  Status
	cf4a08d8  dc1  cluster6    false  ready
	9f1d65ca  dc1  cluster5    false  ready
	11e9ba9d  dc1  cluster4    false  ready

Como vemos ahora mismo no tenemos ningún job lanzado, y en clúster tiene listos tres nodos servidores con uno de ellos asignado como líder, y otros tres nodos clientes.

Job de ejemplo

Una vez desplegado y verificada la configuración de Consul y Nomad es el momento de comenzar a lanzar ‘Jobs’!
Los jobs son las configuraciones que se le pasan a Nomad para que despliegue. Están formados por ‘Tasks’ que representan las aplicaciones/artefactos a desplegar.

Vamos a comenzar creando y ejecutando nuestro primer job de ejemplo con los siguientes comandos:

	$ nomad init
	Example job file written to example.nomad

	$ nomad run example.nomad
	==> Monitoring evaluation "26cfc69e"
	    Evaluation triggered by job "example"
	    Allocation "8ba85cef" created: node "171a583b", group "cache"
	    Evaluation status changed: "pending" -> "complete"
	==> Evaluation "26cfc69e" finished with status "complete"

Ahora podremos ver más información sobre el estado de este despliegue utilizando los siguientes comandos:

	$ nomad status
	ID       Type     Priority  Status
	example  service  50        running

	$ nomad status example
	ID            = example
	Name          = example
	Submit Date   = 09/27/17 16:14:43 UTC
	Type          = service
	Priority      = 50
	Datacenters   = dc1
	Status        = running
	Periodic      = false
	Parameterized = false

	Summary
	Task Group  Queued  Starting  Running  Failed  Complete  Lost
	cache       0       0         1        0       0         0

	Latest Deployment
	ID          = 11c5cdc8
	Status      = successful
	Description = Deployment completed successfully

	Deployed
	Task Group  Desired  Placed  Healthy  Unhealthy
	cache       1        1       1        0

	Allocations
	ID        Node ID   Task Group  Version  Desired  Status   Created At
	8ba85cef  171a583b  cache       0        run      running  07/25/17 23:14:43 UTC

En la parte final del estado de una ‘task’ se puede ver sus ‘allocations’ que son las instancias de ejecución en un nodo concreto. en este caso en el nodo ‘171a583b’ el cual se puede identificar en el listado obtenido del comando ‘nomad node-status’. Puedes obtener más información sobre los logs de una ‘allocation’ concreta usando el comando:

	$ nomad alloc-status 8ba85cef
	ID                  = 8ba85cef
	Eval ID             = 61b0b423
	Name                = example.cache[0]
	Node ID             = 171a583b
	Job ID              = example
	Job Version         = 0
	Client Status       = running
	Client Description  = 
	Desired Status      = run
	Desired Description = 
	Created At          = 09/27/17 16:14:43 UTC
	Deployment ID       = fa882a5b
	Deployment Health   = healthy

	Task "redis" is "running"
	Task Resources
	CPU    Memory           Disk     IOPS  Addresses
	2/500  6.3 MiB/256 MiB  300 MiB  0     db: 127.0.0.1:30329

	Recent Events:
	Time                   Type      Description
	07/25/17 23:14:53 UTC  Started     Task started by client
	07/25/17 23:14:43 UTC  Driver      Downloading image redis:3.2
	07/25/17 23:14:43 UTC  Task Setup  Building Task Directory
	07/25/17 23:14:43 UTC  Received    Task received by client
Job tipo Docker

En el directorio ‘jobs’ del repositorio tenemos entre otros un ejemplo de job de una app web sobre un docker llamado ‘hello-docker.nomad’.
Tenemos el directorio ‘/vagrant/jobs’ en todas las máquinas virtuales con el contenido del directorio ‘jobs’ del proyecto.
Vamos a ejecutar este job:

	$ nomad run /vagrant/jobs/hello-docker.nomad
	==> Monitoring evaluation "38debb73"
	    Evaluation triggered by job "hello-docker"
	    Allocation "42c9d7c6" created: node "11e9ba9d", group "hello-docker"
	    Allocation "87e451bc" created: node "9f1d65ca", group "hello-docker"
	    Allocation "d284bf40" created: node "cf4a08d8", group "hello-docker"
	    Evaluation status changed: "pending" -> "complete"
	==> Evaluation "38debb73" finished with status "complete"

Esta aplicación está configurada en ese fichero para tener dos instancias. Por tanto debería estar desplegada en dos de los tres nodos clientes y accesible por tanto en dos de las siguientes urls:

http://192.168.10.14/
http://192.168.10.15/
http://192.168.10.16/

	$ nomad status hello-docker
	ID          = hello-docker
	Name        = hello-docker
	Type        = service
	Priority    = 50
	Datacenters = dc1
	Status      = running
	Periodic    = false

	Summary
	Task Group  Queued  Starting  Running  Failed  Complete  Lost
	web         0       0         2        0       0         0

	Allocations
	ID        Eval ID   Node ID   Task Group  Desired  Status   Created At
	42c9d7c6  38debb73  11e9ba9d  web         run      running  09/26/17 13:21:45 UTC
	87e451bc  38debb73  9f1d65ca  web         run      running  09/26/17 13:21:45 UTC

Nginx como proxy balanceador nos redirigirá automáticamente a los dos nodos que la tengan desplegada accediendo a la siguiente url. La web nos dirá qué nodo es el que ha respondido y podéis observar que cada vez será uno de los dos donde está desplegado:

http://192.168.10.11/hello-docker

Nginx se ha configurado automáticamente con una tarea cron que ejecuta el proceso «consul-template». Éste, basándose en la configuración de Consul y las plantillas del directorio ‘/usr/bin/consul-template’, configura los ficheros de ‘/etc/nginx’ y reinicia el servicio de nginx.

Job tipo Java

Ahora vamos a ejecutar un job que desplegará una aplicación Java directamente en los nodos clientes (sin Docker). Para ello usamos el ejemplo ‘hello-java.nomad’.

	$ nomad run /vagrant/jobs/hello-java.nomad
	==> Monitoring evaluation "749505c3"
	    Evaluation triggered by job "java"
	    Allocation "d648fc4b" created: node "9f1d65ca", group "java"
	    Evaluation status changed: "pending" -> "complete"
	==> Evaluation "749505c3" finished with status "complete"

Esta aplicación debería estar desplegada en dos de los tres nodos clientes y accesible por tanto en dos de las siguientes urls:

http://192.168.10.14:8080/
http://192.168.10.15:8080/
http://192.168.10.16:8080/

	$ nomad status hello-java
	ID          = hello-java
	Name        = hello-java
	Type        = service
	Priority    = 50
	Datacenters = dc1
	Status      = running
	Periodic    = false

	Summary
	Task Group  Queued  Starting  Running  Failed  Complete  Lost
	java        0       0         1        0       0         0

	Allocations
	ID        Eval ID   Node ID   Task Group  Desired  Status   Created At
	d648fc4b  749505c3  9f1d65ca  hello-java  run      running  09/26/17 13:38:05 UTC
	78119df7  14af1ff8  11e9ba9d  hello-java  run      running  09/26/17 13:42:50 UTC
Modificando un Job

Vamos a planificar el despliegue de una nueva versión de la aplicación Java. Para ello tenemos preparado otro fichero de job llamado ‘hello-java-v2.nomad’. Con el siguiente comando vemos que acciones se ejecutarían para realizar el despliegue de este nuevo fichero de configuración:

	$ nomad plan hello-java-v2.nomad
	+/- Job: "hello-java"
	    Datacenters {
	  Datacenters: "dc1"
	}
	+/- Task Group: "hello-java" (2 create/destroy update)
	  +/- Task: "java" (forces create/destroy update)
	    + Artifact {
	      + GetterSource: "https://.../hello2.jar"
	      + RelativeDest: "local/"
	    }
	    - Artifact {
	      - GetterSource: "https://.../hello.jar"
	      - RelativeDest: "local/"
	    }

	Scheduler dry-run:
	- All tasks successfully allocated.

	Job Modify Index: 90
	To submit the job with version verification run:

	nomad run -check-index 90 hello-java-v2.nomad

	When running the job with the check-index flag, the job will only be run if the
	server side version matches the job modify index returned. If the index has
	changed, another user has modified the job and the plan's results are
	potentially invalid.

Ahora podemos confirmar la ejecución de estos cambios que conllevan cambiar el .jar que se ejecutará y Nomad se encargará de parar las versiones antiguas y desplegar las nuevas.

	$ nomad run -check-index 90 hello-java-v2.nomad
	==> Monitoring evaluation "d77bfe4e"
	    Evaluation triggered by job "java"
	    Allocation "1914aac7" created: node "9f1d65ca", group "java"
	    Allocation "d5b08cff" created: node "11e9ba9d", group "java"
	    Evaluation status changed: "pending" -> "complete"
	==> Evaluation "d77bfe4e" finished with status "complete"

Veamos cómo va el despliegue… ¡todo correcto!

	$ nomad status hello-java
	ID          = java
	Name        = java
	Type        = service
	Priority    = 50
	Datacenters = dc1
	Status      = running
	Periodic    = false

	Summary
	Task Group  Queued  Starting  Running  Failed  Complete  Lost
	java        0       2         0        0       2         0

	Allocations
	ID        Eval ID   Node ID   Task Group  Desired  Status    Created At
	1914aac7  d77bfe4e  9f1d65ca  java        run      running   09/26/17 13:48:58 UTC
	d5b08cff  d77bfe4e  11e9ba9d  java        run      running   09/26/17 13:48:58 UTC
	78119df7  14af1ff8  11e9ba9d  java        stop     complete  09/26/17 13:42:50 UTC
	d648fc4b  14af1ff8  9f1d65ca  java        stop     complete  09/26/17 13:38:05 UTC
Pruebas de estabilidad del clúster

¡Ahora es el momento de probar lo estable que es el sistema!
Puedes probar a tirar la máquina virtual que actualmente es el líder de Consul y verás con el comando ‘consul monitor’ desde cualquiera de la otras máquinas que otro nodo adquiere la responsabilidad de líder.

Puedes probar a tirar al servidor Nomad que sea líder y verás con el comando ‘nomad server-members’ desde cualquier de las otras máquinas que otro nodo tipo server adquiere la responsabilidad de líder.

Puedes probar a tirar alguno de los nodos nomad cliente y observar que las task que tengan una allocation en este nodo crearán una nueva allocation en otro de los nodos clientes. Puedes verlo con el comando ‘nomad status hello-docker’ por ejemplo.


6. Nomad vs Otro software

No es fácil comparar Nomad con un software como Kubernetes. Kubernetes es una solución centrada más en los contendeores de Docker y que ofrece un sistema completo de orquestación con autodescubrimiento, balanceo de carga, gestión de volúmenes, networking, gestión de secretos, configuración, etc.
En cambio Nomad es de propósito más general soportando aplicaciones virtualizadas, standalone y con contenedores de Docker. Nomad tiene una arquitectura mucho mas simple con un simple binario y requiere de otras piezas externas para añadir funcionalidades de coordinación o almacenamiento.
Parecida es la comparación con otros sistemas como Docker Swarm.

Si lo comparamos con AWS ECS la principal diferencia es que ECS es para desplegar en los servidores de Amazon, mientras que Nomad es totalmente open source y permite el despliegue en cualquier nube privada o pública. Además ECS está centrado en contenedores de Docker mientras que Nomad tiene un propósito más general aunque soporta Docker también.


7. Conclusiones

Si necesitas una pieza de software que se encargue simplemente de gestionar y supervisar los despliegues distribuidos de tus aplicaciones o contenedores Docker; Nomad es una buena opción!
Además, combinado con otras herramientas de ‘HashiCorp DevOps Infrastructure’ como Consul, Terraform y Vault puedes tener una solución bastante completa de infraestructura.


8. Referencias

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad