Emil blog

Pipelines como código en Go-cd

Se habla mucho de Job DSL en Jenkins pero no se habla tanto de Go-cd y menos todavía de DSL en Go-cd. En este post vamos a tratar el tema sin profundizar demasiado e intentaremos dar un punto de partida para aquel que no conozca demasiado esta práctica y quiera saber más de ella.
Pero primero, aunque algunos ya sabrán el significado, vamos a comentar rápidamente unos cuantos conceptos básicos en torno al concepto de Job DSL.

¿Qué es Job DSL?

DSL no es un concepto nuevo, se refiere a las palabras Domain Specific Language. Todos conocemos muchos DSL’s, uno de los más conocidos sería CSS, por ejemplo. (Un buen libro para profundizar en el tema de los DSL’s en general se puede encontrar aquí).

Por tanto, Job DSL se referirá a utilizar una particularización de algún lenguaje de programación de forma específica para un uso concreto; en este caso para definir jobs (de integración o despliegue continuo). Como ocurre en Jenkins, que se hace un uso particular de Groovy. Pero no hemos venido a hablar de Groovy y Jenkins, vamos a analizar primero el por qué se hace necesario utilizar DSL’s en despliegue continuo y qué opciones existen si queremos utilizar la alternativa de Go-cd en nuestro proyecto.

¿Por qué Job DSL?

Hace no mucho aparecieron unas herramientas sin las que hoy no podríamos vivir y que nos facilitaron mucho tanto la integración de código como su despliegue. Pero todas estas herramientas se volvían engorrosas de utilizar en el momento en el que nuestros entornos escalaban y nos encontrábamos con cientos o miles de jobs con sus correspondientes tareas, por ende mantener todo esto se volvía muy complicado. Aparecieron los templates, que ayudaron bastante a resolver este problema pero, de repente, algunos pensaron: “¿Por qué no automatizamos también la creación de estos jobs, además como código para poder versionarlos y mantenerlos de una forma cómoda?”.

Así pues: Job DSL en Go-cd

Existen muchos artículos donde se compara Go-cd con Jenkins (no vamos a tratar las opciones de pago como Atlassian Bamboo en este post). Pero es un debate muy extenso que se puede resumir en que, dependiendo de tus necesidades, uno encajará mejor que el otro. Actualmente Go-cd posee los plugins necesarios para realizar cualquier tarea que se nos pueda plantear a la hora de desplegar nuestro código, o al menos no vamos a tener mayores dificultades que con Jenkins. Por tanto, si decidimos utilizar Go-cd o hemos heredado un entorno que ya utiliza esta herramienta y se nos complica el hecho de sustituirlo por otro, ya sea por falta de tiempo o por otros motivos, todavía disponemos de unas cuantas opciones para gestionar nuestros pipelines como código.

En general lo que se pretende es generar la configuración en XML desde algo más sencillo. Un ejemplo muy visual para darnos cuenta de la ventaja de usar un DSL para definir configuraciones de nuestros jobs sería el de este enlace. Si entramos y ejecutamos este ejemplo veremos cómo de unas pocas líneas en Groovy se genera una configuración bastante extensa en XML.

El más popular: Gomatic

Gomatic utiliza Python 2.7 como DSL para escribir la configuración de Go-cd, que también es en XML, del mismo modo que ocurre en Jenkins. Una configuración simple tendría este aspecto:

from gomatic import *

go_server = GoServerConfigurator(HostRestClient("localhost:8153"))
pipeline = go_server \
    .ensure_pipeline_group("Group") \
    .ensure_replacement_of_pipeline("example-pipeline") \
    .set_git_url("http://foobargit.url")
stage = pipeline.ensure_stage(“test-stage")
job = stage.ensure_job("test-job")
job.add_task(ExecTask(['test-task']))

go_server.save_updated_config()

Pero además, Gomatic viene con un extra, que es la posibilidad de hacer ingeniería inversa a un pipeline existente y darte como resultado el DSL en Python, de modo que ejecutando esto:

#!/usr/bin/env python
from gomatic import *
go_server = GoServerConfigurator(HostRestClient("localhost:8153"))
pipeline = go_server\
    .ensure_pipeline_group("test-group")\
    .find_pipeline("example_pipeline")
print go_server.as_Python(pipeline)

Suponiendo que nuestro go-server se encuentre en localhost, obtendremos la configuración del pipeline llamado example-pipeline del grupo test-group, que quedará así:

#!/usr/bin/env python
from gomatic import *

go_server_configurator = GoServerConfigurator(HostRestClient("localhost:8153"))
pipeline = go_server_configurator\
    .ensure_pipeline_group("test-group")\
    .ensure_replacement_of_pipeline("example-pipeline")\
    .set_git_url("http://foobargit.url")
stage = pipeline.ensure_stage("example-stage")
job = stage.ensure_job("example-job")
job.add_task(ExecTask(['exaemple-task']))

go_server_configurator.save_updated_config(save_config_locally=True, dry_run=True)

Y este DSL generaría de nuevo la config XML que obtuvimos en un primer momento. Si nos fijamos en la última instrucción, una buena práctica sería ejecutar un dry run para comprobar que todo funciona como debe y que nada cambia con respecto al pipeline original.

Gomatic todavía se encuentra en un estado de implementación intermedio, funciona bien y es estable pero, por ejemplo, si definimos pipelines vacíos no nos va a avisar de esto, será go-server quien lo haga cuando intentemos aplicarlos (por eso es bueno ejecutar un dry run, como se ha mencionado).

Del mismo modo, Gomatic implementa todas las funcionalidades de la última versión (o la más reciente posible) de Go-cd, por tanto, si queremos usar funcionalidades modernas en versiones viejas de Go-cd, no nos avisará tampoco hasta que apliquemos. Será de nuevo go-server (del pasado) quien nos diga que intentamos usar una funcionalidad que para él no existe. Como hemos comentado, dry run será nuestro amigo.

Los “no tan DSL”: JSON configuration plugin y YAML config plugin

JSON configuration plugin y de un modo similar YAML config plugin son dos opciones válidas, puesto que utilizan DSL’s para generar la config en XML. Pero claro, tanto JSON como YAML son descriptivos y realmente no resultan tan potentes como utilizar Groovy en Jenkins o Python con Gomatic para Go-cd. Pero al final vamos a escribir una configuración bastante similar a la que escribiríamos directamente en XML y Go-cd nos facilita esto último, puesto que cuenta con un editor en la propia GUI. Pero bueno, al final escribir un YAML es mucho más sencillo que escribir un JSON o un XML.

Como estos dos hay muchos más, pero estos son los que constan en la página de plugins en la web de Go-cd. No se reconocen como “oficiales” pero podremos considerarlos “pseudo-oficiales”.

La forma engorrosa: la API

Go-cd dispone de una API a la que se puede atacar para crear o destruir recursos en Go-cd. En general no recomiendo utilizarla teniendo las herramientas anteriores. Por ejemplo, en el caso de Gomatic no se utiliza la API porque Gomatic implementa más funcionalidad que la propia API de Go-cd.

Además, en lo que se refiere al tema que estamos tratando en este artículo, Gomatic es más puro. Las otras dos opciones sí que se basan en la API de Go-cd, solo que nos facilitan algunas tareas típicas cuando se trata con una API. Por tanto, usando la API directamente no vamos a ganar nada con respecto a los plugins anteriores, y ni mucho menos vamos a acercarnos a la funcionalidad que nos da Gomatic. En cualquier caso, siempre podremos crear un recurso de Go-cd, por ejemplo, de la siguiente forma:

curl 'http://localhost:8153/go/api/admin/environments' \
  	-u 'username:password' \
  	-H 'Accept: application/vnd.go.cd.v1+json' \
  	-H 'Content-Type: application/json' \
  	-X POST -d '
{
         	"name" : "Development",
         	"pipelines" : [
                	{
                      	"name" : "BuildPipeline1"
                	},
                	{
                      	"name" : "DeployPipeline1"
                	}
         	]
}'

Esto crearía el entorno Development y asociaría a él los dos pipelines BuildPipeline1 y DeployPipeline1 que deberán existir previamente.

Conclusión

Es posible hacer Job DSL en Go-cd mediante Gomatic, del mismo modo que lo podemos hacer en Jenkins con su plugin de DSL. Utilizando DSL’s para definir pipelines podremos guardar toda nuestra configuración versionada, lo que nos facilitará desplegarla las veces que deseemos, escalarla, etc. Como cualquier código, será testable, revisable y susceptible de ser mejorado de forma continua. También podremos probarlo tantas veces como sea necesario antes de aplicarlo definitivamente.

De modo que, de nuevo, a la hora de seleccionar nuestra herramienta de integración y despliegue continuo no podremos decantarnos por uno u otro en base a si tenemos la posibilidad de utilizar DSL’s. Tendremos que valorar otros aspectos y procurar que se ajusten lo máximo posible a las necesidades concretas de nuestro proyecto. Esto, desde mi punto de vista, nos aleja de las “modas” que considero que debemos evitar. Aunque también hay que ser consciente de que no se pueden dominar todas las herramientas que aparecen: al final debemos procurar centrarnos en algunas, las que mejor se adapten a nosotros y a nuestros proyectos.

2 abril, 2017
Top