# Spring Boot

# Continuous Deployment

# Docker

# PaaS

# Render

# GitHub

clock

17 de sep de 2023

Despliegue continuo en Render de una aplicación Spring Boot

David Gracia

David Gracia

5 min de lectura

.

Software Engineering & Computer Science

Article
Destacado

En este artículo voy a explicar cómo configurar el despliegue continuo en Render basado en imágenes Docker de una aplicación Spring Boot.

Herramientas y tecnologías usadas en este ejemplo:

Puedes encontrar el código de esta guía en mi repositorio de GitHub.

Crear un repositorio GitHub donde subir el código

Empecemos por lo básico. Creamos un repositorio de GitHub donde subir el código de la aplicación.

Generamos una aplicación Spring Boot en spring initializr con la siguiente configuración. Lo descargamos y lo subimos al repositorio de GitHub.

Containerización

Tenemos que containerizar nuestra aplicación para que Render pueda ejecutarla como un contenedor de Docker. Para conseguirlo, necesitamos añadir un fichero Dockerfile apropiado para nuestra aplicación Spring Boot en el directorio raíz del repositorio. El siguiente fichero Dockerfile servirá para alcanzar nuestro objetivo (si estás interesado/a en los detalles de este Dockerfile, puedes consultar la guía oficial de Spring Boot Docker que he seguido).

1FROM eclipse-temurin:17.0.6_10-jre-jammy
2
3VOLUME /tmp
4ARG JAR_FILE
5COPY ${JAR_FILE} spring-boot.jar
6ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /spring-boot.jar ${0} ${@}"]
7EXPOSE 8080

Publicación de una nueva imagen de Docker cuando ocurra un push a la rama principal

Ahora que ya tenemos nuestro Dockerfile listo, vamos a publicar una imagen de Docker cada vez que ocurra un push a la rama principal de nuestro repositorio. De eso se va a encargar un workflow de GitHub Actions que situaremos en la ruta «.github/workflows/on-push-to-main.yaml».

1name: On push to main
2
3on:
4 push:
5   branches:
6     - main
7
8jobs:
9 deploy_to_production:
10   runs-on: ubuntu-latest
11
12   env:
13     REGISTRY: ghcr.io
14     IMAGE_LATEST_URL: ghcr.io/dgraciac/guide-cd-render-docker-based-spring-boot:latest
15     IMAGE_COMMIT_SHA_URL: ghcr.io/dgraciac/guide-cd-render-docker-based-spring-boot:${{ github.sha }}
16
17   permissions:
18     contents: read
19     packages: write
20
21   steps:
22     - name: Checkout
23       uses: actions/checkout@v3
24
25     - name: Set up JDK
26       uses: actions/setup-java@v3
27       with:
28         distribution: 'temurin'
29         java-version: 17
30
31     - name: Gradle build
32       run: ./gradlew build -x check
33
34     - name: Build Docker images
35       run: |
36         docker build \
37         --build-arg JAR_FILE=build/libs/guide-cd-render-docker-based-spring-boot-0.0.1-SNAPSHOT.jar \
38         -t ${{ env.IMAGE_LATEST_URL }} \
39         -t ${{ env.IMAGE_COMMIT_SHA_URL }} \
40         --platform=linux/amd64 \
41         .
42
43     - name: Log in to the Container registry
44       uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
45       with:
46         registry: ${{ env.REGISTRY }}
47         username: ${{ github.actor }}
48         password: ${{ secrets.GITHUB_TOKEN }}
49
50     - name: Push image with "commit sha" version
51       run: docker push ${{ env.IMAGE_COMMIT_SHA_URL }}
52
53     - name: Push image with "latest" version
54       run: docker push ${{ env.IMAGE_LATEST_URL }}

Subimos este cambio a la rama principal y esto iniciará un workflow run que publicará una nueva imágen de Docker de la aplicación Spring Boot en el container registry de nuestra cuenta de GitHub con dos etiquetas: «latest» y otra con el commit SHA.

Conectar Render a nuestras imágenes de Docker

Ahora que ya tenemos una URL para nuestras imágenes de Docker, vamos a configurar un servicio web en Render y vamos a conectarlo a «ghcr.io/dgraciac/guide-cd-render-docker-based-spring-boot:latest».

Seleccionamos «Deploy an existing image from a registry».

Render
Fig.1 - Desplegando una imágen Docker de un container registry

En el campo «Image URL» ponemos la URL con la etiqueta «latest»: ghcr.io/dgraciac/guide-cd-render-docker-based-spring-boot:latest.

Si tu repositorio es privado, tu container registry también lo es y tendrás que añadir unas credenciales en tu cuenta de Render para que pueda descargarse las imágenes del container registry.

Render
Fig.2 - Configurando la URL de la imágen Docker

Elegimos nombre del servicio web, región geográfica e «Instance Type».

En la sección «Advanced»,

  • añadimos una variable de entorno «PORT» (reservada por Render) con el valor «8080» para decirle a Render que redirija las peticiones que llegan al servicio web al puerto 8080 del contenedor Docker donde se está ejecutando la aplicación Spring Boot (Spring Boot escucha el puerto 8080 por defecto).
  • en el campo «Health Check Path» añadimos «/actuator/health»

Por último, creamos el servicio web.

Render
Fig.3 - Configuración avanzada de un servicio web en Render

Al cabo de unos minutos, el servicio web estará disponible en «https://guide-cd-render-docker-based-spring-boot.onrender.com». Para comprobar que la aplicación Spring Boot es accesible públicamente, pega esta URL en tu navegador: https://guide-cd-render-docker-based-spring-boot.onrender.com/actuator/health. Si todo ha ido bien, deberías ver el siguiente mensaje: {"status":"UP","groups":["liveness","readiness"]}

Ahora ya podemos deplegar manualmente la versión «latest» de nuestra aplicación Spring Boot desde el dashboard de Render.

Render
Fig.4 - Panel de control de un servicio web en Render

Pero lo que realmente nos va a facilitar la vida es que nuestro servicio web se despliegue automáticamente cada vez que se publique una nueva imágen Docker de la aplicación. Es decir, despliegue continuo.

Despliegue continuo

Para configurar el despliegue continuo vamos a usar el webhook que nos ofrece Render para iniciar un nuevo despliegue.

Tenemos que añadir un paso más al final de nuestro workflow de GitHub para que llame al webhook con la URL de la imagen Docker que tiene la etiqueta commit SHA (tiene que ser URL encoded).

1- name: Trigger deploy in Render
2  run: |
3    status_code="$(curl --silent --output /dev/null --get -w "%{http_code}" --data-urlencode "imgURL=${{ env.IMAGE_COMMIT_SHA_URL }}" ${{ secrets.RENDER_DEPLOY_WEBHOOK }})"
4    echo $status_code
5    expected_status_code="200"
6    if [ $status_code != $expected_status_code ]; then
7    exit 1
8    fi

Las opciones que se pasan al comando curl sirven para codificar la URL que añadimos al query string y poder obtener el código de respuesta para hacer fallar el workflow en caso de que Render nos conteste con un error.

Solo falta mantener la URL del webhook en secreto para evitar riesgos. Así que creamos un secreto «RENDER_DEPLOY_WEBHOOK» en nuestro repositorio de GitHub (ver documentación oficial).

En mi caso, también añado esto al job del workflow porque he configurado el secreto como un secreto del entorno de producción.

1environment:
2  name: production
3  url: https://guide-cd-render-docker-based-spring-boot.onrender.com

Índice de Contenidos