Volver a Spring Boot Intermedio
Spring Boot
Spring Boot Intermedio
Contenedores y Despliegue de Aplicaciones Spring Boot
Construir una Imagen Docker
Usando los Buildpacks Integrados de Spring Boot
# Construir imagen OCI sin Dockerfile
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=miapp:latest
Dockerfile Optimizado
# Build multi-etapa para imagen mínima
FROM eclipse-temurin:21-jdk-alpine AS constructor
WORKDIR /app
COPY mvnw pom.xml ./
COPY .mvn .mvn
RUN ./mvnw dependency:go-offline -q
COPY src src
RUN ./mvnw package -DskipTests -q
# Extraer JAR por capas
RUN java -Djarmode=layertools -jar target/*.jar extract
# Imagen de ejecución
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# Copiar capas para mejor caché
COPY /app/dependencies ./
COPY /app/spring-boot-loader ./
COPY /app/snapshot-dependencies ./
COPY /app/application ./
# Usuario no-root por seguridad
RUN addgroup -S spring && adduser -S spring -G spring
USER spring
EXPOSE 8080
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
Docker Compose para Producción
version: '3.8'
services:
app:
image: miapp:latest
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/mibd
SPRING_DATASOURCE_USERNAME: ${DB_USUARIO}
SPRING_DATASOURCE_PASSWORD: ${DB_CONTRASENA}
JWT_SECRETO: ${JWT_SECRETO}
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: mibd
POSTGRES_USER: ${DB_USUARIO}
POSTGRES_PASSWORD: ${DB_CONTRASENA}
volumes:
- datos-postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USUARIO}"]
interval: 10s
volumes:
datos-postgres:
Despliegue en Kubernetes
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: servicio-productos
spec:
replicas: 3
selector:
matchLabels:
app: servicio-productos
template:
metadata:
labels:
app: servicio-productos
spec:
containers:
- name: servicio-productos
image: miapp:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: DB_CONTRASENA
valueFrom:
secretKeyRef:
name: secreto-bd
key: contrasena
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
Configuración de Probes en Kubernetes
# application.yml — exponer probes de Kubernetes
management:
endpoint:
health:
probes:
enabled: true
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
CI/CD con GitHub Actions
# .github/workflows/deploy.yml
name: Construir y Desplegar
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurar JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Ejecutar pruebas
run: ./mvnw test
- name: Construir imagen Docker
run: ./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Publicar imagen
run: |
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Desplegar en Kubernetes
run: |
kubectl set image deployment/servicio-productos \
servicio-productos=ghcr.io/${{ github.repository }}:${{ github.sha }}
Imagen Nativa con GraalVM (Opcional)
Para inicio ultra-rápido y bajo consumo de memoria:
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
./mvnw native:compile -Pnative
./target/demo # inicia en ~50ms, usa ~80MB RAM