Actividad 2. API Spring Boot con GitHub Actions y AWS Elastic Beanstalk
Práctica: API REST en Spring Boot con Integración Continua y Despliegue en la nube (GitHub Actions + AWS Elastic Beanstalk)
6. FASE 4: Despliegue Continuo (CD) con AWS Elastic Beanstalk
Objetivo de la fase
El objetivo de esta fase es automatizar el despliegue de una API Spring Boot en la nube, de forma que cada cambio subido a GitHub provoque automáticamente la actualización de la aplicación en producción.
En esta fase se pasa de Integración Continua (CI) a Despliegue Continuo (CD), utilizando:
-
GitHub Actions
-
AWS Elastic Beanstalk (plataforma Java SE)
Flujo completo de CD
A partir de esta fase, el flujo real del proyecto será:
git commit
↓
git push
↓
GitHub Actions
↓
Compilación y empaquetado
↓
Creación del artefacto de despliegue
↓
AWS Elastic Beanstalk
↓
Aplicación actualizada automáticamente
No hay pasos manuales intermedios.
BLOQUE A — Laboratorio (AWS Academy / Learner Lab)
En el laboratorio, el objetivo es desplegar manualmente una versión en Elastic Beanstalk y comprobar que la API funciona.
La automatización completa con IAM + Secrets se verá después (Bloque B).
1 Creación de una API mínima Spring Boot
Se parte de una API REST sencilla, cuyo objetivo no es la funcionalidad, sino validar el proceso de despliegue automático.
Endpoint disponible
-
/api/estado -> Devuelve información básica del estado de la aplicación en formato JSON.
Código principal de la aplicación
src/main/java/com/dam/cicd/Man.java
package com.dam.cicd;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
src/main/java/com/dam/cicd/EstadoControlador.java
package com.dam.cicd;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class EstadoControlador {
@GetMapping("/api/estado")
public Map<String, Object> estado() {
return Map.of(
"estado", "OK",
"servicio", "dam-ci-cd-api-001",
"mensaje", "API operativa"
);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<groupId>com.dam.cicd</groupId>
<artifactId>dam-ci-cd-api-001</artifactId>
<version>1.0.0</version>
<name>dam-ci-cd-api-001</name>
<description>API Spring Boot para CI/CD</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- API REST -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Tests -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Genera JAR ejecutable (bootJar) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Comprobamos que:
java -jar target/*.jar
Paramos el Spring Boot y vamos con el código del main
src/main/resources/application.properties
server.port=${PORT:8080}
Esta configuración permite que la aplicación:
-
use el puerto 8080 en local,
-
respete el puerto dinámico asignado por Elastic Beanstalk en la nube.
2 Empaquetado como JAR ejecutable
Elastic Beanstalk (Java SE) despliega JARs ejecutables, no proyectos completos.
Compilación del proyecto
Desde la raíz del proyecto:
./mvnw clean test
./mvnw clean package
Se genera un JAR ejecutable en:
target/dam-ci-cd-api-001-1.0.0.jar
Prueba en local
java -jar target/*.jar
Acceso desde navegador:
-
http://localhost:8080/api/estado
Deberías ver el JSON con estado, servicio, mensaje.

Con esto se valida que:
-
la aplicación arranca correctamente,
-
el JAR es ejecutable,
-
el endpoint responde como se espera.
3 Preparación del paquete de despliegue para Elastic Beanstalk
Elastic Beanstalk espera un ZIP limpio, con el JAR en la raíz y un comando de arranque claro.
Creación del Procfile
En la raíz del proyecto se crea un archivo llamado Procfile (sin extensión):
web: java -jar app.jar
Este archivo indica a Elastic Beanstalk cómo arrancar la aplicación.

Creación del ZIP de despliegue
mkdir -p deploy
cp target/*.jar deploy/app.jar
cp Procfile deploy/Procfile
(cd deploy && zip -r ../deploy.zip .)
Resultado final:
deploy.zip
├── app.jar
└── Procfile
Este ZIP es el único artefacto que se despliega en AWS.
4 Creación del entorno en Elastic Beanstalk
Desde la consola de AWS:
-
Abrir Elastic Beanstalk
-
Pulsar Create application
-
Configurar:
-
Application name: dam-ci-cd-api-001
-
Platform: Java
-
Platform branch: Java SE
-
Environment tier: Entorno de servidor web
-
Application code: Cargar el código
-
Archivo: deploy.zip
Comprobación final en AWS:
Comprobación final en AWS:
-
Abrir la URL del entorno y verificar:
-
/api/estado responde
-
(opcional) / si lo has añadido como texto “Fin de práctica”.
-








Hemos creado dos roles


El Ngnix de EB intenta conectar por defecto en el 5000, hay que abrirlo



/api/estado

Fin de la práctica para alumnos de laboratorio
A partir de aquí se continúa con cuenta Free Tier, porque el siguiente bloque requiere gestionar IAM + Secrets, algo que en AWS Academy/Learner Lab puede estar limitado.
BLOQUE B — Continuación (Cuenta Free Tier)
Automatizar el CD con GitHub Actions → Elastic Beanstalk
Objetivo: que cada git push despliegue automáticamente en EB.
5 Bucket S3 para versiones (Elastic Beanstalk)
Elastic Beanstalk usa un bucket automático del tipo:
-
elasticbeanstalk-us-east-1-XXXXXXXXXXXX
No es necesario crear un bucket nuevo si vas a desplegar con EB directamente.

6 Credenciales AWS para GitHub Actions (IAM)
-
IAM → Users → Create user github-actions-eb
-
Policies:
-
AWSElasticBeanstalkFullAccess
-
AmazonS3FullAccess
-
-
Create access key → te da:
-
AWS_ACCESS_KEY_ID
-
AWS_SECRET_ACCESS_KEY
-






7 Configurar Secrets en GitHub
-
App Spring Boot empaquetada en JAR
-
Elastic Beanstalk Java SE
-
Secrets en GitHub:
-
AWS_ACCESS_KEY_ID
-
AWS_SECRET_ACCESS_KEY
-
-
Región: us-east-1
-
App/Entorno: los vas a hardcodear (ok)
Secrets necesarios en GitHub
En tu repo → Settings → Secrets and variables → Actions → New repository secret
Crea estos 4:
-
AWS_ACCESS_KEY_ID
-
AWS_SECRET_ACCESS_KEY
-
AWS_SESSION_TOKEN
-
AWS_REGION → pon us-east-1


8 Workflow de CD: .github/workflows/deploy-eb.yml
En tu repo crea este archivo: .github/workflows/deploy-eb.yml
Este workflow hace:
-
build del JAR,
-
crea deploy.zip,
-
despliega en Elastic Beanstalk.
Nota importante: en tu YAML final usa tu app real:
-
application_name: dam-ci-cd-api-001
-
environment_name: dam-ci-cd-api-001-env
name: Despliegue a Elastic Beanstalk
on:
push:
branches:
- main # Se ejecuta cuando haces push a main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# Descargar el código del repositorio
- name: Checkout del repositorio
uses: actions/checkout@v4
# Configurar Java 17 (Corretto)
- name: Configurar Java 17
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '17'
# Compilar el proyecto (ajusta si usas Gradle)
- name: Compilar proyecto con Maven
run: mvn clean package -DskipTests
# Configurar credenciales de AWS
- name: Configurar credenciales de AWS
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
# Crear el paquete para Elastic Beanstalk
- name: Preparar artefacto para Elastic Beanstalk
run: |
mkdir deploy
cp target/*.jar deploy/app.jar
cp Procfile deploy/Procfile
cd deploy
zip -r deploy.zip .
# Subir nueva versión y desplegar en Elastic Beanstalk
- name: Desplegar en Elastic Beanstalk
uses: einaregilsson/beanstalk-deploy@v22
with:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
application_name: dam-ci-cd-api-001
environment_name: Dam-ci-cd-api-001-env
region: us-east-1
version_label: v-${{ github.run_id }}
deployment_package: deploy/deploy.zip
wait_for_environment_recovery: true
9 Reglas de repositorio (evitar subir artefactos)
Comprobamos el estado del git
git status
NO subas deploy.zip ni deploy/
.gitignore
# Maven
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# IntelliJ IDEA
.idea/
*.iml
*.iws
*.ipr
# macOS
.DS_Store
# Artefactos locales de despliegue
/deploy/
/deploy.zip
git status
damiansualdea@Mac-Studio-de-Damian-2 dam-ci-cd-api-001 % git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .github/workflows/deploy-eb.yml
new file: Procfile
new file: src/main/java/com/dam/cicd/EstadoControlador.java
new file: src/main/resources/application.properties
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .github/workflows/deploy-eb.yml
modified: .gitignore
modified: Procfile
modified: pom.xml
modified: src/main/java/com/dam/cicd/EstadoControlador.java
modified: src/main/java/com/dam/cicd/Main.java
modified: src/main/resources/application.properties
git status
damiansualdea@Mac-Studio-de-Damian-2 dam-ci-cd-api-001 % git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .github/workflows/deploy-eb.yml
modified: .gitignore
new file: Procfile
modified: pom.xml
new file: src/main/java/com/dam/cicd/EstadoControlador.java
modified: src/main/java/com/dam/cicd/Main.java
new file: src/main/resources/application.properties
10 Resultado esperado (CD real)
git commit -m "Configurar API y despliegue automático en Elastic Beanstalk"
Push a GitHub (esto dispara TODO)
git push origin main
Ver el pipeline en acción
En cuanto hagas el push, ve a GitHub:

Y en AWS: