# syntax=docker/dockerfile:1 # ── Stage 1: Builder ────────────────────────────────────────────────────────── # eclipse-temurin:21-jdk-noble FROM eclipse-temurin@sha256:81cecb98bcca2d5d5c3d496e71779073865db0d0bd776ecf434e017f20dac638 AS builder WORKDIR /workspace COPY gradle/ gradle/ COPY gradlew gradlew COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties RUN chmod +x gradlew && ./gradlew dependencies --no-daemon # Source build COPY src/ src/ RUN ./gradlew bootJar --no-daemon -x test -x ktlintCheck # ── Stage 2: Runtime ───────────────────────────────────────────────────────── # gcr.io/distroless/java21-debian12 — no shell, no package manager, minimal attack surface # Predefined nonroot user UID/GID: 65532 FROM gcr.io/distroless/java21-debian12@sha256:f34fd3e4e2d7a246d764d0614f5e6ffb3a735930723fac4cfc25a72798950262 AS runtime WORKDIR /app # Glob matches fat jar (kotlin-api-0.0.1-SNAPSHOT.jar) but not -plain.jar # --chown uses numeric UID:GID since distroless has no shell to resolve names COPY --from=builder --chown=65532:65532 /workspace/build/libs/kotlin-api-*SNAPSHOT.jar app.jar USER 65532 EXPOSE 8080 # Leave empty so Spring fails fast with a clear error if not provided at runtime. ENV MONGODB_URI="" ENV JWT_ENCRYPTION_SECRET="" ENTRYPOINT ["/usr/bin/java", \ "-XX:+UseContainerSupport", \ "-XX:MaxRAMPercentage=75.0", \ "-Djava.security.egd=file:/dev/./urandom", \ "-jar", "/app/app.jar"]