Commit inicial
This commit is contained in:
parent
239fc27a6f
commit
11660cb2b2
2
.project
2
.project
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<projectDescription>
|
<projectDescription>
|
||||||
<name>aaee_ra4_proy1</name>
|
<name>aaee_ra4_proy2</name>
|
||||||
<comment></comment>
|
<comment></comment>
|
||||||
<projects>
|
<projects>
|
||||||
</projects>
|
</projects>
|
||||||
|
|||||||
@ -20,6 +20,10 @@ WORKDIR /app
|
|||||||
# LA idea es simplificar el comando de arranque
|
# LA idea es simplificar el comando de arranque
|
||||||
COPY --from=imagen_construccion /app/target/*.jar app.jar
|
COPY --from=imagen_construccion /app/target/*.jar app.jar
|
||||||
|
|
||||||
|
# Variables de entorno (se cargan en fichero .env)
|
||||||
|
ENV DB_USER="nombre_usuario_bbdd"
|
||||||
|
ENV DB_PASSWORD="contraseña_usuario_bbdd"
|
||||||
|
|
||||||
# Puerto típico de Spring Boot (se podría cambiar si la aplicación usa otro)
|
# Puerto típico de Spring Boot (se podría cambiar si la aplicación usa otro)
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
|
|||||||
274
README.md
274
README.md
@ -1,113 +1,169 @@
|
|||||||
# Uso de Docker
|
# Gestión de secretos en distintos entornos (Java + Docker + CI/CD)
|
||||||
|
|
||||||
Este proyecto utiliza Docker para empaquetar y ejecutar la aplicación Spring Boot de forma aislada, garantizando que funcione igual en cualquier entorno.
|
Este documento resume cómo manejar de manera segura credenciales y secretos en distintos entornos: desarrollo local, Docker, docker-compose y CI/CD (GitHub Actions).
|
||||||
|
|
||||||
## Conceptos principales
|
|
||||||
|
|
||||||
### Docker Engine
|
|
||||||
Es el motor de Docker, el servicio que construye imágenes, ejecuta contenedores y gestiona recursos (redes, volúmenes, etc.). Es el "runtime" que hace que todo funcione.
|
|
||||||
|
|
||||||
### Imagen (`image`)
|
|
||||||
Plantilla inmutable que contiene el sistema base, el entorno de ejecución (JDK/JRE) y la aplicación (`.jar`). Se crea a partir de un `Dockerfile`.
|
|
||||||
|
|
||||||
### Contenedor (`container`)
|
|
||||||
Instancia en ejecución de una imagen. Es aislado del sistema, ligero (comparte el kernel del host) y efímero (se puede borrar y recrear fácilmente).
|
|
||||||
|
|
||||||
### Dockerfile
|
|
||||||
Un [Dockerfile](./Dockerfile) es un fichero de texto que contiene las instrucciones para construir una imagen Docker.
|
|
||||||
|
|
||||||
- Define el entorno de ejecución de la aplicación: sistema base, dependencias y cómo arrancar la app.
|
|
||||||
- Es reproducible y versionable, lo que garantiza que la imagen se construya igual en cualquier máquina.
|
|
||||||
- En proyectos Spring Boot, suele usar multi-stage build para separar la fase de compilación de la de ejecución.
|
|
||||||
|
|
||||||
#### Dockerfile (multi-stage)
|
|
||||||
|
|
||||||
- **Etapa 1 (construcción):** compila la aplicación con Maven
|
|
||||||
- **Etapa 2 (ejecución):** ejecuta solo el `.jar` con un entorno ligero
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
# Etapa 1: construcción
|
|
||||||
FROM maven:3.9-eclipse-temurin-23 AS imagen_construccion
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY pom.xml .
|
|
||||||
COPY src ./src
|
|
||||||
|
|
||||||
RUN mvn clean package
|
|
||||||
|
|
||||||
# Etapa 2: ejecución
|
|
||||||
FROM eclipse-temurin:23-jre AS imagen_ejecucion
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --from=imagen_construccion /app/target/*.jar app.jar
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Qué está pasando:**
|
|
||||||
|
|
||||||
1. **Build:** se compila el proyecto y se genera el `.jar`
|
|
||||||
2. **Separación de responsabilidades:** Maven y el código fuente quedan solo en la etapa de build; el runtime solo contiene JRE y el `.jar`
|
|
||||||
3. **Optimización:** la imagen final es más ligera, con menor superficie de error y mayor seguridad
|
|
||||||
|
|
||||||
## Ejecución y conceptos prácticos
|
|
||||||
|
|
||||||
**Puertos** — permiten acceder a la aplicación desde fuera del contenedor:
|
|
||||||
```bash
|
|
||||||
-p 8080:8080
|
|
||||||
```
|
|
||||||
|
|
||||||
**Variables de entorno** — configuran la aplicación sin modificar el código:
|
|
||||||
```bash
|
|
||||||
-e SPRING_DATASOURCE_URL=...
|
|
||||||
```
|
|
||||||
|
|
||||||
**Volúmenes** — persisten datos fuera del contenedor:
|
|
||||||
```bash
|
|
||||||
-v /ruta/local:/ruta/contenedor
|
|
||||||
```
|
|
||||||
|
|
||||||
## Comandos básicos
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Construir la imagen Docker a partir del Dockerfile
|
|
||||||
# -t mapamundi-app → asigna un nombre (tag) a la imagen
|
|
||||||
# . → indica el contexto de construcción (directorio actual, donde está el Dockerfile)
|
|
||||||
docker build -t mapamundi-app .
|
|
||||||
|
|
||||||
# Ejecutar un contenedor a partir de la imagen creada
|
|
||||||
# -p 8080:8080 → mapea el puerto 8080 del host al 8080 del contenedor
|
|
||||||
# --name mapamundi_sb → asigna un nombre al contenedor para poder gestionarlo fácilmente
|
|
||||||
# mapamundi-app → nombre de la imagen que se va a ejecutar
|
|
||||||
docker run -p 8080:8080 --name mapamundi_sb mapamundi-app
|
|
||||||
|
|
||||||
# Ver contenedores (en ejecución / todos)
|
|
||||||
docker ps
|
|
||||||
docker ps -a
|
|
||||||
|
|
||||||
# Ver logs
|
|
||||||
docker logs -f mapamundi_sb
|
|
||||||
|
|
||||||
# Detener y eliminar contenedores
|
|
||||||
docker stop mapamundi_sb
|
|
||||||
docker rm mapamundi_sb
|
|
||||||
|
|
||||||
# Eliminar imagen
|
|
||||||
docker rmi mapamundi-app
|
|
||||||
```
|
|
||||||
|
|
||||||
## Resumen rápido
|
|
||||||
|
|
||||||
| Concepto | Descripción |
|
|
||||||
|---|---|
|
|
||||||
| Docker Engine | Ejecuta y gestiona todo |
|
|
||||||
| Imagen | Plantilla inmutable de la aplicación |
|
|
||||||
| Contenedor | Instancia en ejecución de una imagen |
|
|
||||||
| Dockerfile | Instrucciones para construir la imagen |
|
|
||||||
| Multi-stage | Imágenes más ligeras y eficientes |
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Desarrollo local (Java)
|
||||||
|
|
||||||
|
Leer secretos usando `System.getenv()`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
String user = System.getenv("DB_USER");
|
||||||
|
String password = System.getenv("DB_PASSWORD");
|
||||||
|
|
||||||
|
if (user == null || password == null) {
|
||||||
|
throw new RuntimeException("Faltan variables de entorno DB_USER / DB_PASSWORD");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Definir las variables en la sesión activa:
|
||||||
|
|
||||||
|
**Windows (PowerShell):**
|
||||||
|
```powershell
|
||||||
|
$env:DB_USER="mi_usuario"
|
||||||
|
$env:DB_PASSWORD="mi_password"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux / Mac / WSL:**
|
||||||
|
```bash
|
||||||
|
export DB_USER=mi_usuario
|
||||||
|
export DB_PASSWORD=mi_password
|
||||||
|
```
|
||||||
|
|
||||||
|
> Las variables solo existen en la sesión activa. Configura persistencia si es necesario (`.bashrc`, `.zshrc`, variables de entorno del sistema).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Dockerfile
|
||||||
|
|
||||||
|
Nunca incluir secretos directamente. Solo se declaran variables vacías como documentación:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# Documentación de variables esperadas en runtime
|
||||||
|
ENV DB_USER=""
|
||||||
|
ENV DB_PASSWORD=""
|
||||||
|
```
|
||||||
|
|
||||||
|
Los valores reales se pasan al ejecutar el contenedor. La aplicación sigue usando `System.getenv()` para leerlos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Docker (runtime)
|
||||||
|
|
||||||
|
**Opción A — En línea:**
|
||||||
|
```bash
|
||||||
|
docker run -e DB_USER=mi_usuario -e DB_PASSWORD=mi_password -p 8080:8080 mi-imagen
|
||||||
|
```
|
||||||
|
|
||||||
|
**Opción B — Archivo `.env` (recomendado):**
|
||||||
|
|
||||||
|
Archivo `.env`:
|
||||||
|
```
|
||||||
|
DB_USER=mi_usuario
|
||||||
|
DB_PASSWORD=mi_password
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --env-file .env -p 8080:8080 mi-imagen
|
||||||
|
```
|
||||||
|
|
||||||
|
> Añade `.env` a `.gitignore` para que nunca se suba al repositorio.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Docker Compose
|
||||||
|
|
||||||
|
**Opción A — `env_file`:**
|
||||||
|
```yaml
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:8
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
MYSQL_DATABASE: mi_base_datos
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Opción B — Interpolación de variables:**
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
environment:
|
||||||
|
- DB_USER=${DB_USER}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD}
|
||||||
|
```
|
||||||
|
|
||||||
|
> `depends_on` solo espera a que el contenedor arranque, no a que MySQL esté listo para aceptar conexiones. Considera usar healthchecks o lógica de retry en la aplicación.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. CI/CD — GitHub Actions
|
||||||
|
|
||||||
|
Definir los secretos en el repositorio: **Settings → Secrets and variables → Actions**.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Build & Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
run: docker build -t mi-app .
|
||||||
|
|
||||||
|
- name: Run container with secrets
|
||||||
|
run: |
|
||||||
|
docker run \
|
||||||
|
-e DB_USER=${{ secrets.DB_USER }} \
|
||||||
|
-e DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
|
||||||
|
mi-app
|
||||||
|
```
|
||||||
|
|
||||||
|
> Nunca uses `echo ${{ secrets.DB_PASSWORD }}` en los logs: GitHub lo enmascara, pero es una mala práctica.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Buenas prácticas generales
|
||||||
|
|
||||||
|
- No subir `.env` al repositorio.
|
||||||
|
- No hardcodear credenciales en `config.properties` ni en el código.
|
||||||
|
- No incluir secretos en la imagen Docker.
|
||||||
|
- Documentar las variables necesarias sin poner valores reales (p. ej., en el `README`).
|
||||||
|
- Para producción avanzada: considerar **Secret Manager** (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Tabla comparativa por entorno
|
||||||
|
|
||||||
|
| Entorno | Mecanismo | Dónde se definen | ¿Se sube al repo? |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Desarrollo local | `System.getenv()` | Variables de sesión / sistema | No |
|
||||||
|
| Dockerfile | `ENV` (vacío) | El propio Dockerfile | Sí (sin valores) |
|
||||||
|
| Docker runtime | `-e` / `--env-file` | Línea de comandos / `.env` | No (`.env` en `.gitignore`) |
|
||||||
|
| Docker Compose | `env_file` / `environment` | `.env` / `docker-compose.yml` | No (`.env` en `.gitignore`) |
|
||||||
|
| GitHub Actions | `secrets.*` | Settings del repositorio | No (gestionado por GitHub) |
|
||||||
---
|
---
|
||||||
Fuentes: [ChatGPT](https://chat.openai.com) + [Claude](https://claude.ai)
|
Fuentes: [ChatGPT](https://chat.openai.com) + [Claude](https://claude.ai)
|
||||||
@ -15,10 +15,12 @@ services:
|
|||||||
hostname: mysql.vdlp
|
hostname: mysql.vdlp
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: mysql_123
|
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||||
MYSQL_USER: isidoronm
|
MYSQL_USER: ${DB_USER}
|
||||||
MYSQL_PASSWORD: mm123
|
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||||
MYSQL_DATABASE: mapa_mundi
|
MYSQL_DATABASE: mapa_mundi
|
||||||
volumes:
|
volumes:
|
||||||
- ./mysql/conf.d:/etc/mysql/conf.d
|
- ./mysql/conf.d:/etc/mysql/conf.d
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@ -2,7 +2,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.lapaloma.mapamundi</groupId>
|
<groupId>org.lapaloma.mapamundi</groupId>
|
||||||
<artifactId>aaee_mapamundi</artifactId>
|
<artifactId>aaee_mapamundi</artifactId>
|
||||||
<version>0.0.1</version>
|
<version>0.0.2</version>
|
||||||
|
|
||||||
<name>Prueba de Springboot</name>
|
<name>Prueba de Springboot</name>
|
||||||
<description>Proyecto para poder probar el funcionamiento de SpringBoot</description>
|
<description>Proyecto para poder probar el funcionamiento de SpringBoot</description>
|
||||||
|
|||||||
@ -15,8 +15,8 @@ public class GestorConexionJDBC {
|
|||||||
// Datos URL
|
// Datos URL
|
||||||
String urlBBDD = GestorFicheroConfiguracion.obtenerValor("jdbc.url");
|
String urlBBDD = GestorFicheroConfiguracion.obtenerValor("jdbc.url");
|
||||||
|
|
||||||
String usuario = GestorFicheroConfiguracion.obtenerValor("jdbc.usuario");
|
String usuario = System.getenv("DB_USER");
|
||||||
String contrasenya = GestorFicheroConfiguracion.obtenerValor("jdbc.password");
|
String contrasenya = System.getenv("DB_PASSWORD");
|
||||||
|
|
||||||
String claseDriver = GestorFicheroConfiguracion.obtenerValor("jdbc.driver");
|
String claseDriver = GestorFicheroConfiguracion.obtenerValor("jdbc.driver");
|
||||||
Class.forName(claseDriver);
|
Class.forName(claseDriver);
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
# Parámetros de conexión a la base de datos MapaMundi en SGDB MySQL
|
# Parámetros de conexión a la base de datos MapaMundi en SGDB MySQL
|
||||||
jdbc.driver = com.mysql.cj.jdbc.Driver
|
jdbc.driver = com.mysql.cj.jdbc.Driver
|
||||||
jdbc.url = jdbc:mysql://192.168.1.36:3306/mapa_mundi
|
jdbc.url = jdbc:mysql://172.16.0.181:3306/Mapa_Mundi
|
||||||
jdbc.usuario = isidoronm
|
|
||||||
jdbc.password = 1234
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user