Automatización de construcción, pruebas y despliegues.

El flujo de CI-CD propuesto consta de 5 pasos y las tareas a ejecutar en cada uno de ellos son las siguientes.

jenkins pipeline

  1. Paso Initialize. Se obtiene la última versión de la definición del pipeline ubicada en el repositorio de código fuente en un fichero Jenkinsfile y se descarga de la rama Master el código fuente de la aplicación a construir.
  2. Paso Build. Se verifica que todas las herramientas a utilizar en la construcción del entregable se encuentran bien y se hace la construcción de la aplicación con Maven con perfil de producción.
  3. Paso Test. Se ejecutan las pruebas declaradas en la aplicación, en este caso jUnit para pruebas funcionales y Jacoco para pruebas de cobertura de código, también se ejecutan pruebas de performance adicionales con Gattling y se generan reportes de resultados de todas las pruebas para ser visualizados por el equipo al terminar la entrega.
  4. Paso Sonar. Se ejecutan pruebas de calidad de código con SonarQube para java y se genera un reporte de igual manera que en el paso anterior.
  5. Paso Docker. Solo llegamos a este paso si los anteriores pasaron exitosamente, lo que quiere decir, que se construyó satisfactoriamente la aplicación y que las pruebas pasaron sin problemas. Una vez tengamos garantías que todo está bien se procede a actualizar las imágenes de Docker donde está corriendo la aplicación con la última versión descargada y se hacen push al registry de Docker donde se van a almacenar.

En este caso, como la máquina virtual donde se encuentra desplegado el Jenkins es la misma que tenemos para “producción” no necesitamos hacer ninguna conexión externa por ssh a otro ambiente para ejecutar las tareas allá. Aunque al hacer push a todas las imágenes al final del pipeline hacia un registry de Docker se puede fácilmente hacer un pull de las mismas y un recreate de los contenedores en otro ambiente si fuera necesario.

Vamos a proceder a instalar las herramientas restantes para preparar nuestro pipeline de integración y entrega continua.

Para ambientes Windows es recomendable instalar Jenkins en el host pues al no tener puertos de sockets disponibles la comunicación con el agente de Docker es muy inestable.

Al instalar Jenkins vamos a asegurarnos de que se instalen todos los plugins recomendados por defecto.

jenkins install1

Adicionalmente necesitamos los siguientes plugins:

  • Blue Ocean (Automáticamente instala todas las dependencias, unas 30 aproximadamente).
  • SonarQube Scanner.
  • Test Results Analyzer.

jenkins plugins

Ahora tenemos que configurar el Jenkins con nuestras credenciales y enlaces a las herramientas y agentes externos a utilizar.

En el menú credenciales, sistema y credenciales globales, introducimos el usuario y contraseña del registry de Docker a donde vamos a hacer push a las imágenes nuevas, en este caso DockerHub.

jenkins docker credentials

En el menú gestionar Jenkins, configurar sistema, debemos adicionar un servidor de SonarQube.

jenkins sonar config

El token se obtiene en el servidor sonar.

sonar token

Con el Jenkins configurado podemos proceder con la creación del pipeline. Desde la vista Blue Ocean se pueden crear los pipelines haciendo uso del lenguaje declarativo de forma muy fácil, incluso se encarga de gestionar el Jenkinsfile con el SCM seleccionado.

blueocean pipeline

Luego de seleccionar la organización y el proyecto del SVC, en este caso GitHub accedemos a la vista de creación de pipelines donde podemos agregar los escenarios y pasos necesarios de forma visual muy amigable.

Se agregan los 4 stage restantes pues el inicial lo construye Blue Ocean automáticamente.

pipeline build1
pipeline test1
pipeline sonar
pipeline docker1

El resultado final es el siguiente fichero Jenkinsfile:

pipeline {
    agent any
    stages {
      stage('Initialize') {
        steps {
          echo 'Initializing pipeline'
        }
      }
      stage('Build') {
        agent any
        steps {
          echo 'Testing ENV'
          sh '''java -version
  mvn --version
  docker --version'''
          echo 'Maven build'
          sh '''cd microservice
  mvn -Pprod clean package'''
        }
      }
      stage('Test') {
        steps {
          echo 'Running test'
          sh '''cd microservice
  mvn test
  mvn gatling:execute
  pwd
  mv target/gatling/results/*/productgatlingtest*/* target/gatling/results
  ls target/gatling/results'''
          junit 'microservice/target/surefire-reports/*.xml'
          script {
            publishHTML(target: [
              allowMissing: false,
              alwaysLinkToLastBuild: false,
              keepAll: true,
              reportDir: 'microservice/target/test-results/coverage/jacoco',
              reportFiles: 'index.html',
              reportTitles: "Coverage Report",
              reportName: "Coverage Report"
            ])
          }
  

          script {
            publishHTML(target: [
              allowMissing: false,
              alwaysLinkToLastBuild: false,
              keepAll: true,
              reportDir: 'microservice/target/gatling/results',
              reportFiles: 'index.html',
              reportTitles: "Performance Report",
              reportName: "Performance Report"
            ])
          }
  

        }
      }
      stage('Sonar') {
        steps {
          echo 'Sonar Test'
          sh '''cd microservice
  mvn sonar:sonar \\
    -Dsonar.host.url=http://demo.setit.cl:9002 \\
    -Dsonar.login=bf4e8cd87ffb7ee90e781cf5071c88c80cd927ca'''
        }
      }
      stage('Docker') {
        steps {
          sh '''export DOCKER_HOST="tcp://127.0.0.1:2375"
  /usr/local/bin/docker-compose --version
  cd microservice
  /usr/local/bin/docker-compose -f src/main/docker/app.yml up -d
  docker commit docker_microservice-app_1 rbravet/microservice
  '''
          script {
            docker.withRegistry('https://index.docker.io/v1/', 'docker_rbravet') {
              /* def customImage = docker.build("rbravet/microservice")
              Push the container to the custom Registry
              customImage.push()*/
              sh 'docker tag rbravet/microservice rbravet/microservice'
              sh 'docker push rbravet/microservice'
            }
          }
  

        }
      }
    }
    tools {
      maven 'Maven 3.5'
      jdk 'JDK 8'
    }
  }

Mientras el pipeline se ejecutando se puede acceder a la vista de la ejecución y mirar que va ocurriendo en cada paso. Al final de la misma se pueden ver los logs de cada uno de ellos mediante los componentes expand en la parte inferior o un export full de los logs en el menú Artifacts.

jenkins pipeline run

También podemos analizar los resultados de los test con los reportes de jUnit, Jacoco, Gatling y Sonar. En cómodos formatos HTML con opciones de navegación, filtrado y drill down.

unit test report

Reporte de ejecución de pruebas de jUnit.

code coverage report

Reporte de cobertura de código de Jacoco.

performance report

Reporte de pruebas de performance de Gatling.

sonar reportPNG

Reporte de análisis de calidad de código de Sonar.

El pipeline de la construcción de la aplicación gateway es exactamente idéntico al de microservicios pero, logicamente, utilizando el código fuente de la aplicación como tal.

De esta forma damos por terminado el tutorial. Espero que les sea de utilidad. Cualquier duda o sugerencia no dude en comentar.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

%d