En esta guía voy a explicar cómo usar el DC/OS Commons, es un SDK desarrollado por Mesosphere (D2IQ) para integrar frameworks y servicios en la plataforma DC/OS basada en Apache Mesos, muy popular en proyectos Big Data. El SDK consiste en un conjunto de librerías, herramientas y documentación disponible en el siguiente repositorio de Github:
https://github.com/mesosphere/dcos-commons
La documentación es bastante escasa y en mi opinión complicada de entender para desarrolladores que empiezan de cero a implementar sus servicios para DC/OS. Esta documentación se puede encontrar en el siguiente enlace:
https://mesosphere.github.io/dcos-commons/developer-guide
Este SDK facilita la tarea de implementar frameworks para DC/OS. Como expliqué en la guía cómo crear un framework para Apache Mesos, se deben tener en cuenta muchas consideraciones entorno a la gestión del estado y de la tolerancia a fallos. En el caso de usar el DC/OS Commons, abstraemos toda esta complejidad asociada a la capa de gestión de los recursos y la delegamos al framework, de forma que nos permite centrarnos en implementar el plan y los componentes de nuestro servicio.
El SDK se encuentra en fase alfa, esto significa que la API cambia frecuentemente, recuerda actualizar tu repositorio con los últimos cambios a medida que se publiquen.
Los beneficios de usar el SDK de DC/OS commons son los siguientes:
- Es simple y flexible: el SDK provee una API declarativa, en formato YAML. También es posible extender esta funcionalidad mediante el uso del lenguaje Java.
- Automatización del mantenimiento: Es posible definir rutinas de mantenimiento, de backup y de restauración, de forma que los servicios con estado más complejos pueden automatizarlos.
- Disponibilidad y durabilidad: Al definir estrategias de restauración para las ocasiones en las que los servidores fallan o se deben replanificar tareas, se evita pérdida de datos y de servicio e impacto en su rendimiento.
Contenidos
Cómo configurar el entorno de desarrollo para implementar un nuevo servicio con DC/OS Commons (SDK)
Como prerequisito para desarrollar usando el SDK debemos disponer de una instalación de DC/OS accesible. Para ello, podemos virtualizar un pequeño clúster o bien realizar una instalación en hardware adicional.
- En primer lugar, debemos clonarnos en nuestro equipo de desarrollo el repositorio de Github con el código del SDK.
- Creamos un nuevo repositorio en Github para nuestro servicio.
- Clonamos el repositorio que acabamos de crear en el directorio dcos-commons/frameworks del SDK. Podemos partir del esqueleto de un servicio simple que he creado en Github, listo para desplegar.
- Para compilar el proyecto, debemos añadir las siguientes líneas en el fichero dcos-commons/settings.gradle:
include 'frameworks/dcos-skeleton-service'
project(":frameworks/dcos-skeleton-service").name = "skeleton"
5. En el caso de que queramos evitar warnings y errores relacionados con el estilo del código mientras estamos implementando el servicio, recomiendo añadir la siguiente línea en el fichero dcos-commons/gradle/checkstyle/suppressions.xml:
<suppress files="[\\/]dcos-skeleton-service[\\/]" checks="[a-zA-Z0-9]*"/>
Cómo desplegar el servicio en DC/OS
Para desplegar el servicio en DC/OS podemos hacer uso de la herramienta por línea de comandos DCOS CLI. Esta herramienta nos permite gestionar clusters de DC/OS desde nuestra terminal, instalar y gestionar paquetes, inspeccionar su estado y gestionar servicios y tareas.
Una vez que se encuentra instalada en nuestro sistema, debemos añadir a la configuración el clúster de DC/OS sobre el que queremos probar nuestro servicio.
dcos cluster setup
Tras configurar el cluster, debemos establecer las variables de entorno necesarias para que nuestro script configure el servidor HTTP local en el que se van a publicar los ficheros y la configuración de nuestro servicio:
export HTTP_HOST=(Tu ip local)
export HTTP_PORT=8080
Podemos compilar nuestro servicio con el script build.sh que encontramos en el esqueleto:
> cd /dcos-commons/frameworks/dcos-skeleton-service/
> ./build.sh local
> dcos package repo add --index=0 skeleton-local http://(tu ip local)/stub-universe-skeleton.json
Nota: Deberás deshabilitar el servicio firewalld en sistemas linux para servir el repositorio a un clúster DC/OS externo.
Tras añadir nuestro repositorio en la instalación de DC/OS nos aparecerá en la lista:
También nos aparecerá un nuevo servicio en el catálogo de servicios de DC/OS llamado skeleton:
Para desplegar este servicio y empezar a ejecutarlo debemos seleccionarlo y configurarlo. En nuestro caso, como este es un servicio de prueba, no vamos a modificar la configuración por defecto:
Tras pulsar en «Review & Run» nos aparecerán los parámetros de configuración que hemos definido en el código. Hay una pestaña para el scheduler (skeleton) y, a continuación, otra para el executor (pod).
Componentes del servicio
Tras confirmar y desplegar el servicio nos aparecerá en la lista de trabajos activos:
El funcionamiento de nuestro servicio básico consiste en ejecutar una instancia con el JDK que imprime la versión de Java que ejecuta. Como podemos observar en la lista de trabajos, aparece un trabajo llamado «skeleton» que corresponde al scheduler. También aparece periódicamente otro pod:
Esta otra instancia es el ejecutor, el contenedor encargado de realizar las acciones que hemos implementado (en este caso imprimir la versión de Java).
Podemos observar los ficheros que existen en sandbox de cada instancia y los logs que están generando en tiempo real desde la interfaz de DC/OS:
Cómo implementar un nuevo servicio con DC/OS commons (SDK)
En esta sección de la guía vamos a partir del código que he mencionado anteriormente como «skeleton». Este código es una versión mínima funcional que se puede usar como esqueleto para el desarrollo de frameworks y servicios más complejos. Sirve como un punto de partida funcional sobre el que iterar e ir añadiendo funcionalidad adicional.
simple.yml
Este fichero yml contiene la definición del servicio (ServiceSpec). Especifica qué tareas ejecutar y la manera de hacerlo mediante un plan. Existen dos formas de definir un servicio válido: Mediante un fichero YAML o con código Java. Esta definición de servicio permite desplegar una o más instancias del mismo servicio en un clúster DC/OS.
name: {{FRAMEWORK_NAME}}
scheduler:
principal: {{FRAMEWORK_PRINCIPAL}}
user: {{FRAMEWORK_USER}}
pods:
skeletonpod:
count: {{SKELETON_COUNT}}
tasks:
server:
goal: RUNNING
cmd: |
set -e
export JAVA_HOME=$(ls -d $MESOS_SANDBOX/jdk*/)
./jdk-11.0.3+7-jre/bin/java -version
cpus: {{SKELETON_CPUS}}
memory: {{SKELETON_MEM}}
env:
SLEEP_DURATION: {{SLEEP_DURATION}}
uris:
- {{JAVA_URI}}
- name: Especifica el nombre de la instancia del servicio que va a desplegar DC/OS. No es posible desplegar dos instancias con el mismo nombre simultáneamente.
- scheduler: Este componente es el encargado de gestionar la ejecución del servicio y lo mantiene ejecutando cuando sea necesario.
- user: Especifica el usuario del sistema que se va a usar para ejecutar los procesos relativos a este componente.
- pods: Se denominan pods a grupos de tareas.
- skeletonpod: Nombre del pod, en nuestro ejemplo solo existe uno.
- count: Número de instancias de este pod.
- tasks: Lista de tareas para ejecutar en este executor (pod).
- server: Nombre de la tarea.
- goal: especifica el estado que debe tener la tarea. Existen 3 estados posibles: RUNNING, FINISH y ONCE. La etiqueta RUNNING indica que esta tarea debe estar siempre en ejecución.
- cmd: El comando a ejecutar.
- cpus: Cantidad de CPUs que debe tener el contenedor.
- memory: Cantidad de memoria que debe tener el contenedor.
- env: Variables de entorno disponibles en la tarea
- server: Nombre de la tarea.
- uris: Recursos adicionales que deben estar presentes en el sandbox del contenedor.
- skeletonpod: Nombre del pod, en nuestro ejemplo solo existe uno.
Main
Este código Java es el punto de entrada para el Scheduler en DC/OS commons. En el ejemplo está obteniendo la definición del servicio de la plantilla YAML que hemos descrito en la sección anterior del primer argumento.
La llamada a este código que va a realizar el contenedor del Scheduler se especifica en la sección «cmd» del fichero marathon.json.moustache.
Tras leer la configuración del servicio de la definición del servicio, inicializamos la clase SchedulerRunner y la ejecutamos con su método run.
config.json
Este fichero contiene la configuración del servicio. Especifica las opciones que se mostrarán en la interfaz web de DC/OS al desplegar una instancia. Es posible establecer valores por defecto.
Todas los valores establecidos en este fichero son accesibles desde la plantilla marathon.json.moustache con la notación de doble llave.
marathon.json.moustache
En DC/OS la ejecución de frameworks se gestiona con el planificador Marathon. Este fichero contiene la configuración que usará Marathon para el servicio. Entre la configuración más importante se encuentran las variables de entorno env y el comando que va a ejecutar el contenedor del scheduler para invocar a su Main.
package.json
Contiene la información relativa a la distribución y empaquetado del servicio. Permite definir tags, descripción, mantenedor, versión, etc.
resource.json
Este fichero contiene la lista de recursos que contiene el servicio, así como dependencias y uris externas que son necesarias, como imágenes, código o binarios.
build.sh
Este script realiza la compilación, empaquetado y publicación del servicio en la máquina en la que se ejecute. En nuestro ejemplo usaremos la opción local, con la que levanta un servidor HTTP que sirve de repositorio para el clúster de DC/OS