Tutorial Jenkins 2 – Configuración pipeline

Introducción

Después del tutorial de instalación de Jenkins 2 en Ubuntu, continuamos con la configuración de Jenkins 2 con un sencillo pipeline de integración continua.

En este tutorial aprenderemos los fundamentos de los pipelines de Jenkins y configuraremos uno sencillo en el que integraremos una aplicación java con Spring Boot + Maven + GitHub. El pipeline lo mantendremos en el propio repositorio de GitHub y conectaremos GitHub con Jenkins de forma que cada vez que se realice un commit en el repositorio se ejecute de forma automática el pipeline de Jenkins.

 

Índice

 

¿Qué son los pipelines de Jenkins?

Definen  el ciclo de vida de la aplicación de nuestro flujo de integración/entrega continua utilizando un lenguaje basado en Groovy. Debido a su gran flexibilidad y compatibilidad con numerosos plugins, permiten crear flujos complejos completos capaces de implementar sistemas de entrega continua (Continuos Delivery – CD). Además los pipelines pueden sobrevivir a reinicios del servidor y pueden ser pausados a la espera de que una persona realice una acción antes de que continúe la ejecución del flujo.

 

¿Qué elementos componen un pipeline?

Un pipeline se compone de distintas etapas (stages) secuenciales que ejecutan tareas (steps) que son lanzadas en nodos de trabajo (nodes).

Step

Son las tareas ó comandos que ejecutados de forma secuencial implementan la lógica de nuestro flujo de trabajo. Por ejemplo, un comando puede ser la escritura de un mensaje en la consola echo 'Mensaje de prueba' ó por ejemplo la descarga de un repositorio checkout scm.

Node

Los nodos son agrupaciones de tareas o steps que comparten un workspace. Los conjuntos de steps son añadidos a la cola de Jenkins para ser ejecutados cuando haya algún espacio libre entre los agentes de ejecución. Los agentes de ejecución pueden ser la misma máquina del servidor maestro de Jenkins o un Jenkins en otra máquina en modo esclavo dedicado a este propósito.

Es importante reseñar que el directorio de trabajo (workspace) es compartido por los steps del nodo, de forma que steps de un nodo pueden acceder a ficheros/directorios generados por steps de ese mismo nodo. Por el contrario un step de un nodo no puede acceder al workspace de otro nodo.

Stage

Son las etapas lógicas en las que se dividen los flujos de trabajo de Jenkins. Cada stage puede estar compuesto por un conjunto de steps, y cada node puede contener un conjunto de stages.

Es una práctica recomendada dividir nuestro flujo de trabajo en etapas ya que nos ayudará a organizar nuestros pipelines en fases. Además Jenkins nos muestra los resultados de la ejecución del pipeline divido en etapas, mostrando el resultado de la ejecución de cada una de ellas con un código de colores.

jenkins-stages

 

Creación del pipeline

Como paso previo debemos tener instalado un servidor Jenkins 2 con los plugins necesarios para la construcción del pipeline. Si aún no tienes un servidor Jenkins puedes seguir el Tutorial Jenkins 2 – Instalación para instalarlo de forma sencilla.

Vamos a crear un sencillo pipeline para controlar el ciclo de vida una aplicación Java desarrollada con Spring Boot y Maven. Utilizaremos el plugin de Jenkins Multibranch Pipeline que nos permite definir el pipeline en el propio Git del proyecto, de forma que podemos mantener en el proprio SCM el historial de cambios del pipeline. Además vamos a configurar un hook en Github para que cada vez que se realice un commit en el repositorio se lance una nueva ejecución del pipeline.

A continuación detallamos los pasos para la creación del pipeline:

1.- Creación del repositorio en Github

En nuestro caso hemos creado el repositorio https://github.com/dmunozfer/dmunozfer.es-tutorial-jenkins-2 en el que hemos subido el código de una aplicación de ejemplo que muestra un mensaje de bienvenida al usuario.

2.- Definición del pipeline

La definición del pipeline la vamos a realizar en un fichero Jenkinsfile que subiremos en el directorio principal de nuestro repositorio.

El fichero Jenkinsfile es un script basado en Groovy que permite definir un pipeline de Jenkins.

Se recomienda que la primera línea del script sea #!groovy para que los editores puedan interpretar que es un script de Groovy y lo muestren correctamente.

En nuestro caso hemos definido un pipeline compuesto de cuatro etapas:

  • Compilar: Descarga los fuentes del proyecto desde Github checkout scm y los compila con el comando mvn clean compile.
  • Test: Ejecuta los test de la aplicación utilizando el plugin surefire de maven mvn verify.
  • Instalar: Genera los binarios de la aplicación, en nuestro caso un jar, utilizando el comando mvn install -Dmaven.test.skip=true.
  • Archivar: Archiva los paquetes generados para poder ser visualizados desde Jenkins.

 

Contenido del fichero Jenkinsfile:

#!groovy

node {
   // ------------------------------------
   // -- ETAPA: Compilar
   // ------------------------------------
   stage 'Compilar'
   
   // -- Configura variables
   echo 'Configurando variables'
   def mvnHome = tool 'M3'
   env.PATH = "${mvnHome}/bin:${env.PATH}"
   echo "var mvnHome='${mvnHome}'"
   echo "var env.PATH='${env.PATH}'"
   
   // -- Descarga código desde SCM
   echo 'Descargando código de SCM'
   sh 'rm -rf *'
   checkout scm
   
   // -- Compilando
   echo 'Compilando aplicación'
   sh 'mvn clean compile'
   
   // ------------------------------------
   // -- ETAPA: Test
   // ------------------------------------
   stage 'Test'
   echo 'Ejecutando tests'
   try{
      sh 'mvn verify'
      step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
   }catch(err) {
      step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
      if (currentBuild.result == 'UNSTABLE')
         currentBuild.result = 'FAILURE'
      throw err
   }
   
   // ------------------------------------
   // -- ETAPA: Instalar
   // ------------------------------------
   stage 'Instalar'
   echo 'Instala el paquete generado en el repositorio maven'
   sh 'mvn install -Dmaven.test.skip=true'
   
   // ------------------------------------
   // -- ETAPA: Archivar
   // ------------------------------------
   stage 'Archivar'
   echo 'Archiva el paquete el paquete generado en Jenkins'
   step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar, **/target/*.war', fingerprint: true])
}

 

El script es bastante sencillo de comprender pero se pueden destacar las siguientes líneas:

step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])

Archiva los resultados de las pruebas realizadas con el plugin surefire de Maven para poder ser visualizados desde la interfaz web de Jenkins. Además este comando está envuelto en una estructura try/catch para que en el caso de que falle algún test los resultados también sean archivados.

step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar', fingerprint: true])

Archiva los ficheros jar generados por Maven para que estén disponibles desde la interfaz web de Jenkins.

3.- Dando de alta el pipeline en Jenkins

El primer paso será el acceso a la interfaz web de administración de nuestro servidor Jenkins, para ello navegamos a la URL de nuestro servidor http://IP_JENKINS:8080/ y tras identificarnos se nos mostrará la pantalla de bienvenida.

tutorial-jenkins-configuracion-01

Cómo vamos a utilizar Maven para la construcción de nuestra aplicación tenemos que configurar la herramienta Maven en nuestro Jenkins. Para ello pulsamos sobre Adminsitrar Jenkins -> Global Tool Configuration. Nos desplazamos hasta la parte inferior en la sección Maven y pulsamos en el botón Añadir Maven. Introducimos como nombre M3 (el mismo que configuramos en el Jenkinsfile) y marcamos la opción Instalar automáticamente. A continuación pulsamos sobre el botón Apply.

tutorial-jenkins-configuracion-02

El siguiente paso será añadir una nueva tarea para la definición del pipeline, para ello pulsamos sobre el enlace Back to Dashboard y a continuación pulsamos sobre el enlace Nueva Tarea.

tutorial-jenkins-configuracion-03

Nos aparecerá una pantalla en la que debemos introducir el nombre y tipo de la tarea, en nuestro caso introduciremos tutorial-jenkins-2 y seleccionaremos la opción Multibranch Pipeline. A continuación pulsamos el botón OK.

tutorial-jenkins-configuracion-04

Se nos mostrará la pantalla de configuración de la tarea. La configuración por defecto será suficiente, lo único que debemos configurar son los datos de el repositorio de GitHub. Para ello pulsamos sobre el desplegable Add source debajo de la sección Branch Sources y seleccionamos la opción GitHub.

tutorial-jenkins-configuracion-05

En el campo owner introducimos nuestro nombre de usuario de GitHub dmunozfer y en repository seleccionamos el repositorio donde tenemos el código fuente de la aplicación junto con el fichero Jenkinsfile dmunozfer.es-tutorial-jenkins-2. Pulsamos Save para guardar la configuración.

tutorial-jenkins-configuracion-06

Ya tenemos configurado la tarea de Jenkins con el pipeline que leerá desde el repositorio de GitHub.

4.- Configurando hook en GitHub

El siguiente paso será configurar un hook en el repositorio de GitHub para que cada vez que se realice un commit en el repositorio se inicie la tarea de Jenkins creada anteriormente. Para ello desde nuestro repositorio de GitHub pulsamos sobre el enlace Settings -> Webhooks & Services. Se mostrará la pantalla de configuración de los hooks, pulsamos sobre Add service y escribimos jenkins, seleccionamos el servicio Jenkins (GitHub plugin).

tutorial-jenkins-configuracion-07

Se nos mostrará la pantalla de configuración del servicio Jenkins de GitHub, en esta pantalla únicamente tenemos que introducir la URL al hook de nuestro Jenkins que será de la forma http://IP_JENKINS:8080/github-webhook/ y pulsamos el botón Add Service.

tutorial-jenkins-configuracion-08

¡Enhorabuena! En este momento ya tenemos configurado nuestro sistema de integración continua con Jenkins + Maven + GitHub.

 

Comprobando funcionamiento

Para comprobar que todo funciona correctamente únicamente tenemos que realizar un commit en nuestro repositorio. Una vez realizado, accedemos a la interfaz de Jenkins para ver el resultado de la ejecución de la tarea del pipeline tutorial-jenkins-2.

Accedemos a la pantalla principal de Jenkins y se nos mostrará la tarea multibranch definida anteriormente con un sol espléndido para indicarnos que no tiene errores. Pulsamos sobre tutorial-jenkins-2 para ver el detalle de la tarea.

tutorial-jenkins-configuracion-09

 

A continuación se mostrarán todas las ramas que contenga nuestro repositorio (en nuestro caso solo master) con la información de la última ejecución del pipeline para cada una de las ramas. Pulsamos en el enlace master para ver en detalle la información de la rama.

tutorial-jenkins-configuracion-11

En el detalle de la rama master podemos ver en la parte central las etapas de nuestro pipeline y el resultado de las últimas ejecuciones, en nuestro caso todas las etapas acabaron correctamente. En la parte superior podemos acceder al último .jar creado correctamente y en la parte inferior a los informes de test generados.

Para finalizar vamos a realizar un cambio en los test del programa para forzar un error. Una vez realizado el cambio realizamos un commit y un push a GitHub. De forma automática GitHub creará una nueva ejecución de nuestro pipeline. Si esperamos unos segundos veremos que se empieza a ejecutar una nueva instancia del pipeline y se nos muestran los resultados.

tutorial-jenkins-configuracion-13

Como forzamos un fallo en los test vemos que la ejecución del pipeline se detuvo en la fase de Test. Además podemos ver ha aparecido un gráfico de evolución de test fallidos en la parte superior derecha. En la parte inferior de la pantalla seguimos viendo el informe de los test, si accedemos en el enlace podremos ver en detalle los casos de prueba ejecutados y el resultado de cada uno de ellos.

 

Conclusión

Crear un pipeline sencillo en Jenkins no es complejo y nos será de gran ayuda a la hora de mantener y monitorizar el flujo de vida de nuestra aplicación desde el desarrollo hasta la puesta en producción. Para hacer flujos más complejos podéis consultar la documentación oficial, además dejo unos enlaces con documentación y ejemplos sobre los pipelines de Jenkins en el apartado recursos.

Espero que este tutorial os sirva como puerta de entrada en el mundo de los pipeline de Jenkins. A mí me ha resultado muy interesante hacerlo para fijar los conceptos y como base para el pipeline que estoy preparando para uno de mis próximos proyectos.

¡Nos vemos en la siguiente entrada!

Recursos:

 

Código fuente – Repositorio GitHub

Sobre el autor

Apasionado de las tecnologías, entusiasta del desarrollo de software. Especializado en Java EE. Cofundador de www.logrosxbox.com.