Cuando recibes el encargo de montar un servidor de Jenkins desde cero, una de las cosas que hay que pensar mucho es cómo organizar los pipelines. ¿Usamos pipelines declarativos o en script? ¿Cómo organizamos la biblioteca groovy? ¿Utilizamos un pipeline único general para todo o ponemos un pipeline a cada job….? Y de ser así, ¿dónde guardamos ese pipeline, en el repo del proyecto o en la librería?

Al empezar este trabajo desde cero, un compañero añadió una pregunta más: “¿Y si organizamos el código y los pipelines utilizando el plugin Jenkins Templating Engine (JTE)?”. Nos miramos, nos enseñó una POC que montó en dos días y reflexionamos: “vaya, esto puede funcionar”.

Sí, pero ¿qué es JTE?

JTE es un desarrollo original de la empresa estadounidense Booz Allen Hamilton y licenciado bajo licencia Apache-2.0. Este plugin se centra en una premisa importante: diferentes equipos de desarrollo van a utilizar diferentes herramientas para la generación y despliegue de sus desarrollos, pero el pipeline de todos ellos va a ser, a grandes rasgos, el mismo. Para eso, lo que plantea JTE es crear un pipeline global y común a todos los proyectos y una plantilla por proyecto que proporciona los datos de entrada del pipeline y, lo más relevante, la lista de las tecnologías necesarias para la construcción y despliegue del artefacto.

Animación creada por los desarrolladores de JTE.
Animación creada por los desarrolladores de JTE.

Vamos a verlo funcionando

Lo primero que debemos hacer, una vez hemos instalado el plugin, es configurar los repositorios en los que guardamos el pipeline “global” junto a la configuración global y las librerías. Lo podemos tener en un mismo repositorio, como es nuestro caso, o en varios, uno para la configuración del pipeline y uno o más para las librerías.

Si vais a contar con un equipo de mantenimiento grande, y con gente de diversas áreas tocando las librerías, igual una buena política es separar el código en varios repos: uno, para la configuración general de los pipelines, y otro, por cada tecnología. Lo bueno, si empiezas cortando por lo sano y metiéndolo todo junto, es que podrás sacar código a nuevos repositorios muy fácilmente.

Además, puedes referenciar a los repositorios por una rama o un tag concreto. Como veis en las capturas de pantalla estamos usando la rama develop. ¡¡¡No hagáis esto en casa sin supervisión de una persona adulta!!!

La primera pieza de nuestro puzle es el pipeline global. En nuestro caso estamos usando uno lo más sencillo posible: realizamos un primer step de inicialización, donde tomamos todos los datos necesarios para ejecutar el pipeline correctamente, pasamos un análisis de código en Sonar, construimos lo que sea que el proyecto va a construir y lo desplegamos.

La segunda pieza es el fichero de configuración, llamado pipeline_config. Aquí tenemos mucho que contar: primero, indicamos las librerías que van a ser comunes para todos los pipelines. En nuestro caso, una librería de log para mostrar los logs en bonitos colores; una librería común, empleada para la lógica común a los proyectos; la librería de SonarQube; una para las funciones propias de git y otra con las funciones propias de psono.

Voy a abrir un pequeño paréntesis. Los desarrolladores de este plugin también han creado una serie de librerías públicas que puedes utilizar y que están en su GitHub.

Mediante la instrucción “merge” permitimos añadir en los pipelines librerías extra a estas. Más adelante lo veremos con un ejemplo. Mediante las instrucciones “override” permitimos que se defina, en cada job, unos valores diferentes a los valores por defecto.

Las secciones application_environments y keywords sirven para organizar los parámetros de entrada de las librerías. No vamos a entrar mucho en detalle porque la idea de este artículo no es ser una traducción de la documentación oficial.

Lo siguiente que hacemos es definir steps dentro de cada librería, que se llaman igual que el directorio que las contiene. La estructura de las librerías es la siguiente:

Terminado esto podemos volver a Jenkins y configurar nuestros jobs para utilizar estas librerías. Para eso vamos a ver un primer ejemplo: la configuración de un job que construye un artefacto Python y lo despliega en una Lambda de AWS:

En este caso concreto además queremos que la construcción del artefacto se realice en un worker diferente al que se usa para ejecutar todo el pipeline, por lo que en el job especificamos que no queremos usar el pipeline por defecto y usamos otro.

En la llamada a los steps de construcción y despliegue le pasamos una variable “build_env” y “deploy_env” con los parámetros necesarios para las librerías correspondientes. El siguiente paso es configurar esas librerías:

Como se puede ver, sobreescribimos los parámetros de entrada de la librería “commons” y especificamos que, además de las librerías por defecto que vimos más arriba, vamos a utilizar las de Python, lambda y nexus. En el caso de la librería Python no hace falta indicarle parámetros extra y por eso el map se lo pasamos vacío. La keyword del nombre del artefacto la empleamos en los steps de construcción y despliegue.

El resultado es un pipeline declarativo normal y corriente, con la excepción de que no tenemos, por norma general, un pipeline para cada job, sino que lo tenemos unificado y solo en aquellos casos excepcionales podemos usar un pipeline diferente.

A modo de resumen, ¿qué nos ha parecido?

Para ser sinceros, este plugin tiene dos pegas:

Por otro lado, tiene algunas ventajas, aunque la primera es compartida con los pipelines declarativos en general:

¿Tienes alguna duda? ¿Quieres hacernos una pregunta? ¡Deja un comentario!

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.