Actividad 2. API Spring Boot con GitHub Actions y AWS Elastic Beanstalk
| Sitio: | Campus virtual DAW - damiansu |
| Curso: | Despliegue de Aplicaciones Web |
| Libro: | Actividad 2. API Spring Boot con GitHub Actions y AWS Elastic Beanstalk |
| Imprimido por: | Invitado |
| Día: | jueves, 22 de enero de 2026, 04:40 |
Descripción
Práctica: API REST en Spring Boot con Integración Continua y Despliegue en la nube (GitHub Actions + AWS Elastic Beanstalk)
1. Explicación
Contexto de la práctica
En esta práctica se trabaja con un flujo real de desarrollo profesional, similar al que se utiliza en entornos empresariales.
El objetivo no es solo crear una aplicación, sino aprender cómo se integra, prueba y despliega automáticamente un proyecto Java en la nube a partir de cambios en el repositorio.
La práctica combina tres elementos clave:
-
Desarrollo local con Spring Boot
-
Integración continua mediante GitHub Actions
-
Despliegue automático en la nube con AWS Elastic Beanstalk
Idea fundamental
El principio base de esta práctica es el siguiente:
El código se escribe y se prueba en local.
El pipeline valida y despliega automáticamente.
Nunca se programa dentro del pipeline.
El pipeline no arregla errores, solo los detecta.
Si el proyecto no funciona en local, no funcionará en la nube.
Flujo real de trabajo (visión general)
El flujo completo que se sigue es el siguiente:
-
El desarrollador trabaja en su ordenador
-
Los cambios se suben al repositorio
-
GitHub ejecuta el pipeline automáticamente
-
Si todo es correcto, la aplicación se despliega en AWS
Este flujo se repite en cada cambio del proyecto.
Fase 1: Desarrollo en local
Todo comienza en el entorno local del alumno.
En esta fase se realizan las siguientes tareas:
-
Creación de una API REST mínima con Spring Boot
-
Configuración del proyecto con Maven
-
Ejecución de pruebas locales con:
mvn test
Debemos de comprobar que:
-
El proyecto compila correctamente
-
La aplicación arranca sin errores
-
Los endpoints funcionan en local
Esta fase es obligatoria antes de continuar.
Fase 2: Control de versiones (Git)
Una vez validado el proyecto en local:
-
Se registran los cambios con git commit
-
Se suben al repositorio remoto con git push
Cada push al repositorio principal es el disparador del pipeline.
Aquí no se ejecuta nada manualmente: todo el proceso posterior es automático.
Fase 3: Integración Continua con GitHub Actions
Cuando se realiza un push, GitHub ejecuta el workflow definido en el repositorio.
Este workflow realiza las siguientes acciones:
-
Descarga el código del repositorio
-
Configura Java 17
-
Compila el proyecto con Maven
-
Ejecuta los tests
-
Genera el artefacto (JAR)
Si alguna de estas fases falla, el pipeline se detiene y no se despliega nada.
Este proceso garantiza que solo código válido llegue a producción.
Fase 4: Despliegue Continuo en AWS Elastic Beanstalk
Cuando el pipeline finaliza correctamente:
-
El JAR generado se empaqueta
-
Se despliega automáticamente en un entorno de Elastic Beanstalk
-
AWS se encarga de:
-
La máquina virtual
-
El servidor web
-
El arranque de la aplicación
-
La exposición del servicio por HTTP
-
El alumno no gestiona servidores, solo su aplicación.
El resultado final es una API accesible públicamente desde Internet.
El objetivo principal es...
Con esta práctica el alumno demuestra que:
-
Sabe desarrollar una API REST real
-
Entiende el concepto de Integración Continua (CI)
-
Comprende el Despliegue Continuo (CD)
-
Es capaz de trabajar con pipelines automáticos
-
Puede desplegar aplicaciones en la nube de forma profesional
No es una simulación: es un flujo real de CI/CD.
Idea clave final
El desarrollador controla el código.
El pipeline controla la calidad.
La nube ejecuta la aplicación.
Este es el mismo modelo que se utiliza en proyectos profesionales.
2. Fase 1: Desarrollo en local
Antes de automatizar cualquier proceso de integración o despliegue, es imprescindible preparar correctamente el entorno de desarrollo.
El objetivo de esta fase es garantizar que el proyecto se comporta de la misma forma en local, en el pipeline de Integración Continua y en la nube.
En esta fase no se busca desarrollar una aplicación funcional, sino validar que:
-
el proyecto se construye correctamente,
-
el entorno es reproducible,
-
y el repositorio está listo para ser automatizado.
Se trabajará con el código de ejemplo inicial, que servirá como base para las siguientes fases de la práctica.
1 Creación del proyecto base
Se crea un proyecto Java con Maven, que será la base del proceso de automatización posterior.
Este proyecto contendrá únicamente la estructura mínima necesaria para:
-
compilar código Java,
-
ejecutar la fase de tests,
-
y generar un artefacto reproducible.

2. Configuración de un entorno de construcción reproducible
El objetivo de este apartado es asegurar que el proyecto se construye siempre con la misma versión de Java, independientemente del entorno donde se ejecute.
Configuración de Java en el proyecto
Desde la configuración del proyecto se establece:
-
SDK: Amazon Corretto 17
-
Language level: 17
De este modo:
-
el entorno local,
-
el pipeline de Integración Continua,
-
y el entorno en la nube
utilizarán exactamente la misma versión de Java.
Project structure (Local, pipeline y nube usan el mismo Java)

Comprobamos el Maven:

Incorporación del Maven Wrapper
Para evitar depender de una instalación global de Maven en cada máquina, se añade el Maven Wrapper, que será el utilizado posteriormente por el pipeline.
Desde IntelliJ IDEA, utilizando la opción Run Anything (pulsando dos veces la tecla Ctrl), se ejecuta:
Pulsamos dos veces seguidas la tecla Ctrl:
mvn -N io.takari:maven:wrapper

Tras ejecutar el comando, se comprueba que se ha generado la siguiente estructura:
mvnw
mvnw.cmd
pom.xml
src
target

El uso del Maven Wrapper garantiza que todos los entornos utilizan la misma versión de Maven, independientemente de la configuración local del sistema.
Verificación de versiones
Se comprueba la versión de Java activa en el sistema:
java -version

-
SDK: Amazon Corretto 17
-
Language level: 17
Y se verifica la versión de Java utilizada por el Maven Wrapper:
./mvnw -v
-
Maven Wrapper (mvnw): 25... hay que cambiar
En este punto puede ocurrir que las versiones no coincidan. Por ejemplo, el proyecto puede estar configurado con Java 17 en IntelliJ, mientras que el sistema utiliza otra versión diferente.

Ajuste temporal del Java del sistema
En caso de discrepancia, se ajusta temporalmente la variable JAVA_HOME solo para el proyecto, sin afectar al entorno global:
/usr/libexec/java_home -V

export JAVA_HOME=$(/usr/libexec/java_home -v 17)
Tras el ajuste, se vuelve a comprobar:
java -version
./mvnw -v

Resultado final
Una vez realizadas las comprobaciones, el entorno queda alineado:
-
IntelliJ → Java 17
-
Maven Wrapper → Java 17
-
Sistema (temporal) → Java 17
-
Pipeline futuro → Java 17
El proyecto queda preparado para ejecutarse de forma consistente en cualquier entorno (lo que afecta a todo el pipeline)
3. Fase 2: Control de versiones (Git)
Una vez preparado el entorno de construcción reproducible, es necesario integrar un sistema de control de versiones.
La Integración Continua depende directamente de Git, ya que los pipelines se ejecutan a partir de eventos como commits o push al repositorio remoto.
Por tanto, esta fase es imprescindible antes de automatizar cualquier proceso.
Inicialización del repositorio Git
Durante la creación del proyecto se ha inicializado un repositorio Git local, lo que permite registrar la evolución del código desde el primer momento.
En este punto:
-
el repositorio no contiene aún ningún commit,
-
pero Git ya detecta los archivos del proyecto.
Se comprueba el estado inicial del repositorio con:
git status
En este punto, el repositorio no contiene aún ningún commit, pero ya se encuentran detectados los archivos del proyecto.
Configuración del archivo .gitignore
Antes de realizar el primer commit, se configura el archivo .gitignore para evitar subir al repositorio:
-
archivos generados por el proceso de compilación,
-
configuraciones específicas del IDE,
-
ficheros del sistema operativo.
Un .gitignore que tenemos es algo parecido a esto:
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
.kotlin
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
Se configura .gitignore para excluir configuraciones del IDE (carpeta .idea/) y artefactos generados (target/).
Un .gitignore mínimo y adecuado para este proyecto es:
# Maven
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# IntelliJ IDEA
.idea/
*.iml
*.iws
*.ipr
# macOS
.DS_Store
Revisión del estado del repositorio
Hago el git status y necesito cambiar cosillas:
damiansualdea@Mac-Studio-de-Damian-2 dam-ci-cd-api-001 % git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: .idea/.gitignore
new file: .idea/misc.xml
new file: .idea/vcs.xml
new file: pom.xml
new file: src/main/java/com/dam/cicd/Main.java
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: pom.xml
Untracked files:
(use "git add <file>..." to include in what will be committed)
.mvn/
mvnw
mvnw.cmd
Viendo esto necesito quitar .idea del índice
git rm -r --cached .idea
Unificar pom.xml, Para que no esté “new” y “modified” a la vez:
git add pom.xml
Añadir Maven Wrapper (imprescindible para CI)
git add mvnw mvnw.cmd .mvn
Asegurar lo básico
git add .gitignore src
Revisión final
git status
damiansualdea@Mac-Studio-de-Damian-2 dam-ci-cd-api-001 % git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: .mvn/wrapper/MavenWrapperDownloader.java
new file: .mvn/wrapper/maven-wrapper.jar
new file: .mvn/wrapper/maven-wrapper.properties
new file: mvnw
new file: mvnw.cmd
new file: pom.xml
new file: src/main/java/com/dam/cicd/Main.java
Este git status es exactamente el estado ideal para el primer commit de un proyecto preparado para CI/CD.
Damos nuestro datos:
git config --global user.name "Damián"
git config --global user.email "info@damiansu.com"
git config --global --list
Primer commit del proyecto
Se registra el primer commit del proyecto:
git commit -m "Configuración inicial del proyecto para CI/CD"
Se verifica el historial:
git log --oneline
Validación final del entorno local
Como última comprobación antes de automatizar, se valida que el proyecto puede construirse y ejecutar su fase de tests usando el Maven Wrapper:
./mvnw test
La ejecución finaliza correctamente con:
-
BUILD SUCCESS
Ejecución de la fase test mediante maven-surefire-plugin
damiansualdea@Mac-Studio-de-Damian-2 dam-ci-cd-api-001 % ./mvnw test
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.dam.cicd:dam-ci-cd-api-001 >-------------------
[INFO] Building dam-ci-cd-api-001 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ dam-ci-cd-api-001 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ dam-ci-cd-api-001 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ dam-ci-cd-api-001 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/damiansualdea/IdeaProjects/dam-ci-cd-api-001/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ dam-ci-cd-api-001 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ dam-ci-cd-api-001 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
Aunque todavía no existan tests implementados, esta validación garantiza que:
-
el proyecto compila correctamente,
-
Maven funciona mediante wrapper,
-
y el entorno local queda preparado para integrarlo en un pipeline de Integración Continua.
En la siguiente fase se configurará GitHub Actions, donde cada push al repositorio activará automáticamente el proceso de Integración Continua.
4. FASE 3A: Creación del repositorio en GitHub
Pipeline real en un proyecto Spring Boot

Objetivo de la fase:
Subir el proyecto a GitHub y configurar un pipeline de Integración Continua que ejecute automáticamente:
./mvnw test
cada vez que se produce un cambio en el repositorio.
A partir de esta fase:
-
no se ejecutan validaciones manuales,
-
el proyecto se valida automáticamente,
-
los errores se detectan antes del despliegue.
1. Creación del repositorio en GitHub
Desde GitHub se crea un nuevo repositorio:
-
Repository name: dam-ci-cd-api-001
-
Visibility: Public o Private (indiferente)
No marcar ninguna de estas opciones:
-
Add a README
-
Add .gitignore
-
Add a license
El repositorio debe crearse vacío, ya que el código ya existe en local.


2 Conectar el repositorio local con GitHub
Desde el terminal de IntelliJ, en la raíz del proyecto:
Comprobación de remotos
git remote -v
Si el proyecto no está conectado a ningún repositorio remoto, no debe aparecer nada.
Añadir remoto
Utilizando el Quick setup, ya nos deja todo preparado:

Utilizando la URL del repositorio recién creado:
git remote add origin https://github.com/damiansu/dam-ci-cd-api-001.git
Se verifica la conexión:
git remote -v

Nota sobre la rama main
En la documentación de GitHub puede aparecer el comando:
git branch -M main
Este comando sirve para renombrar la rama actual a main.
En este proyecto no es necesario, ya que la rama principal ya se llama main.
Subir el proyecto a GitHub
Para realizar el primer push es necesario:
-
el nombre de usuario de GitHub (no el correo),
-
un Personal Access Token.
Un token de acceso personal:
-
solo se muestra una vez al crearse,
-
si se pierde, debe generarse uno nuevo.
Configuración recomendada del token:
-
Expiration: 30 o 90 días
-
Scope: repo (solo este)

git push -u origin main

Verificación visual
En GitHub:
-
Abre el repositorio dam-ci-cd-api-001
-
Refresca la página
-
-
pom.xml
-
mvnw
-
.mvn/
-
src/
Debes ver:
-
Si esto aparece, el repositorio está correctamente sincronizado.

5. FASE 3B: Creación del pipeline de Integración Continua con GitHub Actions
Configurar un pipeline de Integración Continua (CI) que se ejecute automáticamente en GitHub cada vez que se suben cambios al repositorio.
El pipeline debe:
-
descargar el código,
-
configurar el entorno,
-
compilar el proyecto,
-
ejecutar los tests.
A partir de este momento, cada push validará automáticamente el proyecto
1 Creación del archivo de workflow
GitHub Actions detecta los pipelines definidos en la ruta:
.github/workflows/
Desde el panel Project de IntelliJ (lado izquierdo):
-
Clic derecho sobre el proyecto
-
New → Directory
-
Nombre: .github
-
Dentro de .github:
-
New → Directory
-
Nombre: workflows
-
Dentro de workflows:
-
New → File
-
Nombre exacto: ci.yml
-

La ruta debe quedar exactamente así:
.github/workflows/ci.yml
2 Definición del pipeline de Integración Continua
En el archivo ci.yml se define el comportamiento del pipeline.
Contenido completo del archivo (copiar tal cual):
name: CI - Construcción con Maven
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- name: Clonar repositorio
uses: actions/checkout@v4
- name: Configurar JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
cache: maven
- name: Compilar y ejecutar tests con Maven Wrapper
run: ./mvnw -B clean test
Este archivo no ejecuta nada en local.
Define qué debe hacer GitHub cuando detecta cambios en el repositorio.
4 Subir el workflow y lanzar el pipeline
Una vez creado el archivo ci.yml, se incorpora al repositorio remoto para que GitHub pueda ejecutarlo.
Revisión del estado del repositorio
Antes de realizar el commit del workflow, se revisa el estado del repositorio para comprobar qué archivos han cambiado:
git status
Debe aparecer el archivo del workflow como pendiente de añadir:
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/ci.yml
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/ci.yml

Añadir el workflow al control de versiones
Una vez verificado el estado, se añade el archivo del pipeline al control de versiones:
git add .github/workflows/ci.yml
Se vuelve a comprobar el estado:
git status

Y se realiza el commit correspondiente:
git commit -m "Añadir pipeline de integración continua con GitHub Actions"
Finalmente, se suben los cambios al repositorio remoto:
git push

Tras el push, GitHub Actions detecta automáticamente el pipeline y lo ejecuta.

5 Ver el pipeline en acción
Desde GitHub:
-
Acceder al repositorio
-
Abrir la pestaña Actions
-
Seleccionar el workflow CI - Construcción con Maven
Se comprueba:
-
Evento: push sobre la rama main
-
Estado: Success
-
Ejecución correcta de:
-
checkout del repositorio
-
configuración de Java
-
compilación y tests
-
7 Forzar un fallo del pipeline (CI en rojo)
Objetivo: Comprobar que el pipeline detecta errores y marca la ejecución como Failure.
Procedimiento
-
Introducir un error de compilación en Main.java (por ejemplo, eliminar un ;).
-
Verificar en local:
./mvnw test
-
Subir el cambio:
git add src/main/java/com/dam/cicd/Main.java
git commit -m "Romper compilación para demostrar CI en rojo"
git push
El pipeline fallará automáticamente.
Volver a verde
-
Corregir el error
-
Commit y push:
git commit -am "Arreglar error de compilación y restaurar CI"
git push
El pipeline volverá a ejecutarse correctamente.
Conclusión
Con esta fase queda implementada una Integración Continua real, donde:
-
cada push valida el proyecto,
-
los errores se detectan automáticamente,
-
el entorno es reproducible y externo.
“A partir de ahora, cada push valida automáticamente el proyecto.”
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:
7. Todo en producción
Código final del controlador
Se actualiza el controlador para incluir un endpoint raíz (/) accesible públicamente, que servirá como verificación visual del despliegue en producción, además del endpoint de estado de la API.
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("/")
public String inicio() {
return "Fin de la práctica: CI/CD con GitHub Actions y AWS Elastic Beanstalk";
}
@GetMapping("/api/estado")
public Map<String, Object> estado() {
return Map.of(
"estado", "OK",
"servicio", "dam-ci-cd-api-001",
"mensaje", "API operativa"
);
}
}
Publicación del cambio en producción
Una vez modificado el código, se registra el cambio y se envía al repositorio remoto:
git add src/main/java/com/dam/cicd/EstadoControlador.java
git commit -m "Añadir endpoint raíz y estado de la API"
git push origin main
Verificación final en producción
Una vez finalizado el pipeline, se comprueba el correcto funcionamiento de la aplicación accediendo a:
-
Endpoint raíz / → Muestra el mensaje de fin de práctica.
-
Endpoint de estado /api/estado → Devuelve un JSON con el estado del servicio.
Con esto se confirma que:
-
El despliegue automático funciona correctamente.
-
La aplicación está accesible públicamente.
-
El entorno de producción se ha actualizado sin intervención manual.

Conclusión de la práctica
Se ha implementado un sistema completo de Integración y Despliegue Continuo (CI/CD) utilizando:
-
GitHub Actions para la automatización del pipeline.
-
Maven para la construcción reproducible del proyecto.
-
AWS Elastic Beanstalk como plataforma de despliegue en producción.
Cada cambio enviado al repositorio activa automáticamente un pipeline que:
-
compila la aplicación,
-
genera el artefacto,
-
y lo despliega en AWS.
El correcto funcionamiento del sistema se valida mediante un endpoint raíz accesible públicamente y un endpoint adicional de estado del servicio.
Regla de oro (la más importante)
Si no estás usando la aplicación → el entorno debe estar apagado o terminado.
AWS cobra por recursos activos, no por código.
Terminar el entorno cuando no se use
No basta con detener la instancia: hay que terminar el entorno.
Pasos:
-
AWS Console
-
Elastic Beanstalk
-
Aplicación → Entorno
-
Actions → Terminate environment
-
Confirmar
Coste tras terminar el entorno
-
0 €
-
No queda EC2 activa.
-
No hay balanceador.
-
No hay servicios ejecutándose.
Si no estás usando la aplicación → el entorno debe estar apagado o terminado
¿Es complicado volver a lanzarlo? No.
-
Crear el entorno de nuevo: 5–10 minutos
-
El código ya está en GitHub.
-
GitHub Actions vuelve a desplegar automáticamente.
Coste real aproximado (orientativo)
Si se deja un entorno activo por error:
-
Elastic Beanstalk + EC2 24/7 → 5–10 € al mes
-
Con varios entornos o errores → puede subir más
En cloud:
Los entornos se crean para usarse y se destruyen cuando se termina.
Ahorro de costes en AWS
Una vez comprobado que la aplicación funciona correctamente en Elastic Beanstalk, el entorno debe ser terminado para evitar costes innecesarios.
Elastic Beanstalk permite crear el entorno de nuevo en cualquier momento, por lo que no es necesario mantenerlo activo permanentemente.
Mantener entornos cloud encendidos sin uso genera cargos económicos evitables