Tutorial paso a paso: Desarrollando y desplegando una aplicación Java Spring Boot con Azure DevOps I

Tutorial paso a paso: Desarrollando y desplegando una aplicación Java Spring Boot con Azure DevOps I

En este primer laboratorio, estableceremos las bases para los próximos laboratorios que desarrollaremos en el futuro. Nos enfocaremos principalmente en el trabajo con el repositorio de plantillas. Como siempre, definiremos los objetivos de esta primera parte, los cuales incluyen:

  • Crear una base inicial de plantillas para el CI.
  • Configurar la integración de Azure DevOps.
  • Integrar SonarCloud para análisis estático del código.
  • Incorporar Debricked para análisis de seguridad del software.
  • Utilizar SpectralOps para la integración de vulnerabilidades.
  • Construir una imagen y publicarla en Docker Hub.
  • Desarrollar una aplicación Spring Boot.
  • Realizar pruebas unitarias exhaustivas.

Durante este laboratorio, trabajaremos con dos repositorios de código: uno para nuestra aplicación Java y otro para las plantillas del flujo de CI.

labs-danieljsaldana / TemplatesDaniel J. Saldaña · Azure Devops

Comenzaremos hablando del repositorio de la aplicación Java, el cual está basado en Spring Boot. Para simular un caso de uso más realista, hemos creado dos pruebas simples con el objetivo de emular pruebas unitarias.

En esta sección, nos centraremos únicamente en la parte del pipeline de Java, ya que el propósito de este artículo es desarrollar un modelo de integración continua (CI).

azure-pipelines.yml
trigger:
- main
- develop
- release*
parameters:
- name: snapshot
displayName: Create snapshot
type: boolean
default: false
- name: jdkversionoption
displayName: jdkVersionOption
type: string
default: '17'
values:
- '17'
variables:
- group: java
resources:
repositories:
- repository: remoteRepo
type: git
name: labs-danieljsaldana/Templates
ref: main
extends:
template: pipe/backend/library.yml@remoteRepo
parameters:
snapshot: ${{ parameters.snapshot }}

En este pipeline, podemos observar los desencadenadores (triggers) que activarán su ejecución. En futuros trabajos, nos adentraremos en su funcionamiento y configuración.

En cuanto a los parámetros, nos centraremos en dos de ellos por ahora. El más destacado es la opción ‘snapshot’, que se utilizará para ejecutar la construcción de la imagen.

Por otro lado, encontramos las variables, una de las grandes ventajas de Azure DevOps y la forma más sencilla de declarar variables.”

Estas modificaciones buscan mejorar la claridad y la fluidez del texto. Recuerda que puedes personalizarlo según tus necesidades y preferencias.

Imagen library Azure Devops

La sección de “resources” se utiliza para definir y configurar los recursos externos que pueden ser necesarios durante la ejecución de tu canalización de CI/CD.

Por último, la sección de “extends” se emplea para heredar o extender una plantilla de canalización existente en una nueva canalización. Esto te permite reutilizar y extender configuraciones ya definidas, evitando la duplicación de código y simplificando la gestión de tus canalizaciones.

Ahora hablaremos de otro componente importante en Azure DevOps es el Service Connections (conexiones de servicio). Las conexiones de servicio se utilizan para establecer la comunicación y la integración entre Azure DevOps y los servicios externos, como Azure, GitHub, Docker Hub, entre otros.

Una conexión de servicio proporciona las credenciales y la configuración necesaria para que Azure DevOps interactúe con el servicio externo de manera segura. Al configurar una conexión de servicio, puedes establecer la autenticación, definir permisos y establecer los parámetros específicos del servicio.

Para configurar una conexión de servicio en Azure DevOps, sigue estos pasos:

  1. Accede al proyecto de Azure DevOps y selecciona la configuración de Proyecto.
  2. En la sección de Conexiones de servicio, selecciona “Nueva conexión de servicio”.
  3. Elige el tipo de servicio externo que deseas configurar (por ejemplo, Azure, GitHub, Docker Hub, etc.).
  4. Proporciona los detalles y credenciales requeridos por el servicio externo, como tokens de acceso, claves de API o certificados.
  5. Configura los permisos y las opciones adicionales según las necesidades de tu proyecto.
  6. Guarda la conexión de servicio.

Una vez configurada la conexión de servicio, puedes utilizarla en tus canalizaciones de CI/CD para interactuar con el servicio externo. Esto te permite desplegar aplicaciones en Azure, obtener código fuente de GitHub, ejecutar comandos en contenedores de Docker, entre otras acciones.

Las conexiones de servicio de Azure DevOps simplifican la configuración y gestión de la integración con servicios externos, proporcionando una forma segura y centralizada de establecer la comunicación entre Azure DevOps y estos servicios.

Azure service connection

Una vez configuradas todas nuestras conexiones de servicio (service connections), estamos listos para comenzar el análisis del repositorio de plantillas.

La estructura que deseemos darle a nuestros templates dependerá de nuestra forma de trabajo y, sobre todo, de las necesidades de nuestro proyecto. En mi caso, he decidido desacoplarlos en la medida de lo posible, con el objetivo de hacer el laboratorio lo más modular posible para futuras iteraciones.

Al desacoplar los templates, logramos una mayor flexibilidad y reutilización en nuestro flujo de trabajo. Esto nos permite adaptar las canalizaciones según las necesidades específicas de cada proyecto y nos facilita su mantenimiento y evolución a lo largo del tiempo.

Ahora, vamos a analizar el flujo de las canalizaciones paso a paso. Durante este análisis, examinaremos cada etapa del flujo, desde la obtención del código fuente hasta la entrega final del producto. Nos centraremos en comprender cómo se conectan las diferentes etapas y cómo se configuran las acciones y los pasos dentro de cada una de ellas.

azure-pipelines.yml
parameters:
- name: snapshot
type: boolean
stages:
- template: /stages/backend/library/build.yml
- ${{ if eq(parameters.snapshot, true) }}:
- template: /stages/backend/library/snapshot.yml

En esta sección del código podemos observar lo siguiente:

  • Se definen parámetros y etapas para un proceso de construcción de backend.
  • El parámetro “snapshot” se utiliza para tomar decisiones más adelante en el código.
  • La primera etapa utiliza una plantilla para construir el backend.
  • La segunda etapa está condicionada por el valor del parámetro “snapshot”.
  • Si el parámetro es “true”, se ejecuta una plantilla adicional para crear una instantánea del backend.
  • En resumen, este código define un proceso de construcción de backend con la opción de crear una instantánea. La segunda etapa se ejecutará solo si el parámetro “snapshot” es “true”.
build.yml
parameters:
- name: jobTimeoutMinutes
type: string
default: 15
stages:
- stage: scan_and_package
displayName: Scan and package
jobs:
- job: code_analysis_sonarqube
displayName: Run code analysis with SonarQube
continueOnError: false
timeoutInMinutes: ${{ parameters.jobTimeoutMinutes }}
steps:
- template: /stages/steps/security/sonarqube/java/sonarqube.yml
- job: code_analysis_debricked
displayName: Run code analysis with Debricked
continueOnError: false
timeoutInMinutes: ${{ parameters.jobTimeoutMinutes }}
steps:
- template: /stages/steps/security/debricked/java/debricked.yml
- job: code_analysis_spectralops
displayName: Run code analysis with SpectralOps
continueOnError: false
timeoutInMinutes: ${{ parameters.jobTimeoutMinutes }}
steps:
- template: /stages/steps/security/spectralops.yml
- job: package_project
displayName: Build project
continueOnError: false
dependsOn:
- code_analysis_sonarqube
- code_analysis_debricked
- code_analysis_spectralops
timeoutInMinutes: ${{ parameters.jobTimeoutMinutes }}
steps:
- checkout: self
clean: false
- job: maven_for_java
displayName: Run maven
continueOnError: false
condition: eq(variables['framework'], 'java')
dependsOn:
- package_project
timeoutInMinutes: ${{ parameters.jobTimeoutMinutes }}
steps:
- template: /stages/steps/framework/java/maven.yml

En este código se configura un proceso de escaneo y empaquetado con varias etapas y parámetros personalizables. Veamos los detalles más importantes:

  • Los parámetros permiten ajustar el comportamiento del proceso. En este caso, se define un parámetro llamado “jobTimeoutMinutes” con un valor predeterminado de 15 minutos.
  • Las etapas representan las fases del proceso y contienen trabajos específicos.
  • Cada trabajo tiene un nombre descriptivo y una pantalla de visualización asociada. También se definen propiedades como “continueOnError” para controlar errores y “timeoutInMinutes” para establecer límites de tiempo de ejecución.
  • Los trabajos consisten en una secuencia de pasos que se ejecutan en orden. Los pasos están definidos por plantillas ubicadas en rutas específicas.
  • Algunos trabajos tienen dependencias, lo que significa que deben completarse antes de que otros trabajos puedan ejecutarse.

En resumen, este código configura un proceso de escaneo y empaquetado. Los parámetros personalizables permiten ajustar la configuración, mientras que las etapas y trabajos proporcionan una estructura organizada para realizar análisis de código y empaquetado de proyectos. Los límites de tiempo y las dependencias aseguran una ejecución controlada y eficiente del proceso.

snapshot.yml
parameters:
- name: jobTimeoutMinutes
type: string
default: 15
stages:
- stage: snapshot
displayName: Build and publish snapshot
jobs:
- job: build_and_publish_snapshot_java
displayName: Build and publish snapshot (Java)
continueOnError: false
condition: eq(variables['framework'], 'java')
timeoutInMinutes: ${{ parameters.jobTimeoutMinutes }}
steps:
- template: /stages/steps/docker/maven.yml

En este código se configura un proceso de construcción y publicación de una instantánea, con los siguientes aspectos destacados:

  • Se definen parámetros para personalizar el proceso. En este caso, el parámetro “jobTimeoutMinutes” permite especificar la duración máxima en minutos para cada trabajo.
  • El proceso se organiza en etapas. La primera etapa, llamada “snapshot”, se encarga de la construcción y publicación de la instantánea.
  • Dentro de la etapa “snapshot”, se define un trabajo específico llamado “build_and_publish_snapshot_java”, diseñado para manejar la construcción y publicación de la instantánea en proyectos Java.
  • El nombre descriptivo del trabajo se muestra como “Build and publish snapshot (Java)” en el flujo de trabajo.
  • La propiedad “continueOnError” se establece en “false”, lo que significa que si ocurre algún error en el trabajo, la ejecución se detendrá.
  • La propiedad “condition” establece una condición para la ejecución del trabajo. En este caso, el trabajo solo se ejecutará si la variable “framework” tiene el valor “java”.
  • Se establece un límite de tiempo de ejecución utilizando el valor del parámetro “jobTimeoutMinutes”.
  • Los pasos del trabajo están definidos por una plantilla ubicada en “/stages/steps/docker/maven.yml”. Esta plantilla contiene las instrucciones necesarias para realizar la construcción y publicación de la instantánea utilizando Maven y Docker.

En resumen, este código configura un proceso de construcción y publicación de una instantánea para proyectos Java. Los parámetros personalizables y las condiciones permiten adaptar el proceso según las necesidades. La definición del límite de tiempo de ejecución y los pasos de la plantilla garantizan un proceso eficiente y controlado para la construcción y publicación de la instantánea.

No analizaremos la parte de los steps, ya que en algunos casos solo tenemos una tarea. Sin embargo, os recomiendo revisar y comprender por vuestra cuenta lo que se realiza en cada caso. Sería interesante comprender el flujo completo y, si encuentran puntos de mejora, aplicarlos.

También os invito a configurar vuestro Dashboard, ya que en un futuro en el laboratorio podremos ver la visión que nos ofrece Azure DevOps en nuestros proyectos.

Imagen pipeline Azure Devops

0
0