Step 10 — Docker multi-stage + compose¶
Obiettivo: immagine Docker piccola, layered, reproducible.
Dockerfile¶
Dockerfile
# Stage 1 — Build
FROM eclipse-temurin:21-jdk AS build
WORKDIR /workspace
COPY .mvn/ .mvn/
COPY mvnw pom.xml ./
RUN chmod +x mvnw && ./mvnw -B -ntp dependency:go-offline
COPY src src
RUN ./mvnw -B -ntp -DskipTests package && \
cp target/*.jar app.jar && \
java -Djarmode=tools -jar app.jar extract --layers --destination extracted
# Stage 2 — Runtime
FROM eclipse-temurin:21-jre AS runtime
RUN groupadd --system spring && useradd --system --gid spring spring
WORKDIR /app
COPY --from=build /workspace/extracted/dependencies/ ./
COPY --from=build /workspace/extracted/spring-boot-loader/ ./
COPY --from=build /workspace/extracted/snapshot-dependencies/ ./
COPY --from=build /workspace/extracted/application/ ./
USER spring:spring
EXPOSE 8080
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "org.springframework.boot.loader.launch.JarLauncher"]
Perché multi-stage¶
- Lo stage 1 ha tutto il JDK + Maven (~500 MB). Si butta via.
- Lo stage 2 ha solo JRE + bytecode (~250 MB).
Perché layered JAR¶
Spring Boot 2.3+ può estrarre il JAR in 4 strati ordinati per "cambiabilità":
dependencies— cambia di rado → cache Docker valida a lungospring-boot-loader— quasi maisnapshot-dependencies— qualche voltaapplication— ogni build
Risultato: rebuild incrementali velocissimi.
Sicurezza¶
- Utente non-root (
spring:spring). MaxRAMPercentage=75per rispettare i limiti del container.- Healthcheck interno.
docker-compose¶
compose.yaml (estratto)
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: sbfs
POSTGRES_USER: sbfs
POSTGRES_PASSWORD: sbfs
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sbfs"]
app:
build: .
depends_on:
postgres:
condition: service_healthy
environment:
SPRING_PROFILES_ACTIVE: prod
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/sbfs
depends_on: condition: service_healthy evita la race condition tra app e DB.
Esercizi¶
- Aggiungi un servizio Grafana al compose con dashboard di base.
- Crea un'immagine distroless sostituendo
eclipse-temurin:21-jrecongcr.io/distroless/java21-debian12. - Confronta dimensioni e tempi di avvio dell'immagine standard vs. distroless.