init: 클린 아키텍처 백엔드
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
# syntax=docker/dockerfile:1.7-labs@sha256:b99fecfe00268a8b556fad7d9c37ee25d716ae08a5d7320e6d51c4dd83246894
|
||||
# =============================================================================
|
||||
# sample-portfolio standalone demo image — twin of src/Dockerfile.
|
||||
#
|
||||
# Builds and runs the REFERENCE app (SamplePortfolioApplication), not the
|
||||
# production composition root (CaSkeletonApplication) that src/Dockerfile builds.
|
||||
# The sample is the demo-friendly entrypoint: its application.yml self-provides
|
||||
# defaults for every env placeholder, so the only external dependency it needs
|
||||
# to boot is a reachable PostgreSQL (datasource + Flyway sample migrations).
|
||||
#
|
||||
# Build (no build-args required — this is a disposable demo, not a release artifact):
|
||||
# docker build -f src/Dockerfile.sample src/ -t ca-sample:local
|
||||
#
|
||||
# Run (point APP_DATASOURCE_URL at a reachable Postgres; localhost default shown):
|
||||
# docker run --rm -p 8080:8080 -p 9001:9001 \
|
||||
# -e APP_DATASOURCE_URL=jdbc:postgresql://host.docker.internal:5432/ca_skeleton \
|
||||
# ca-sample:local
|
||||
#
|
||||
# The multi-stage build, --parents descriptor glob, STRICT lock verification,
|
||||
# non-root user, read-only-root-fs writable mounts, and JVM container ergonomics
|
||||
# are all identical to src/Dockerfile — only the bootJar target differs. Keep the
|
||||
# two files' builder stages in sync.
|
||||
# =============================================================================
|
||||
|
||||
# Demo defaults so the image builds with zero build-args. Two format constraints from the root
|
||||
# build.gradle configuration guard (feature-build-release-supply-chain-contract D1/D9):
|
||||
# - RELEASE_VERSION must be bare MAJOR.MINOR.PATCH — no pre-release/build suffix (build.gradle L21).
|
||||
# The "-sample" marker therefore lives only on BUILD_VERSION, which is a label, not a gradle prop.
|
||||
# - GIT_SHA must be 7-40 hex chars (build.gradle L35); 0000000 is the placeholder.
|
||||
ARG RELEASE_VERSION=0.0.0
|
||||
ARG BUILD_VERSION=0.0.0-sample
|
||||
ARG GIT_SHA=0000000
|
||||
ARG SOURCE_URL=https://example.invalid/ca-tmpl-sample
|
||||
|
||||
# ---- Stage 1: builder -------------------------------------------------------
|
||||
# Uses the full JDK only in the build stage, never in the final image.
|
||||
FROM eclipse-temurin:21-jdk-jammy@sha256:801b7e1a9c4befaf82bf9a2a58025ef43a7694bbc84779187ad0524d84742772 AS builder
|
||||
|
||||
ARG RELEASE_VERSION
|
||||
ARG GIT_SHA
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Copy the Gradle wrapper and every module's build descriptor + dependency lockfile FIRST,
|
||||
# so the expensive dependency-resolution layer is cached and only re-runs when a build.gradle
|
||||
# or gradle.lockfile changes (D8). `--parents` preserves each file's directory structure, so a
|
||||
# single structure-preserving glob replaces a per-module COPY list: new modules are picked up
|
||||
# automatically and this stage never drifts out of sync with settings.gradle.
|
||||
# (Requires the labs Dockerfile frontend — see the `# syntax` directive at the top of this file.)
|
||||
COPY gradlew ./
|
||||
COPY gradle/ gradle/
|
||||
COPY --parents settings.gradle build.gradle **/build.gradle **/gradle.lockfile ./
|
||||
|
||||
# Resolve every module configuration in STRICT mode (no --write-locks in a demo build either).
|
||||
RUN test -n "${RELEASE_VERSION}" \
|
||||
&& test -n "${GIT_SHA}" \
|
||||
&& ./gradlew verifyDependencyLocks --no-daemon --quiet \
|
||||
-PreleaseVersion="${RELEASE_VERSION}" -PgitRevision="${GIT_SHA}"
|
||||
|
||||
# Copy full source and build the sample JAR.
|
||||
COPY . .
|
||||
RUN ./gradlew :sample-portfolio:bootJar --no-daemon -x test \
|
||||
-PreleaseVersion="${RELEASE_VERSION}" -PgitRevision="${GIT_SHA}"
|
||||
|
||||
# Locate the produced JAR (avoids hardcoding the version string).
|
||||
RUN cp $(ls sample-portfolio/build/libs/*.jar | grep -v plain | head -1) /build/app.jar
|
||||
|
||||
# ---- Stage 2: runtime image -------------------------------------------------
|
||||
# JRE-only slim image (no full JDK in the demo image either).
|
||||
FROM eclipse-temurin:21-jre-jammy@sha256:199aebeb3adcde4910695cdebfe782ada38dadb6cc8013159b58d3724451befd AS runtime
|
||||
|
||||
ARG BUILD_VERSION
|
||||
ARG GIT_SHA
|
||||
ARG SOURCE_URL
|
||||
|
||||
# OCI image labels. Unlike the release image (src/Dockerfile), the demo image does NOT hard-fail
|
||||
# on missing metadata — the ARG defaults above keep it buildable with no build-args.
|
||||
LABEL org.opencontainers.image.title="caskeleton-sample" \
|
||||
org.opencontainers.image.description="ca-tmpl sample-portfolio reference/demo application" \
|
||||
org.opencontainers.image.source="${SOURCE_URL}" \
|
||||
org.opencontainers.image.revision="${GIT_SHA}" \
|
||||
org.opencontainers.image.version="${BUILD_VERSION}"
|
||||
|
||||
# ---- Locale / timezone ------------------------------------------------------
|
||||
ENV TZ=UTC \
|
||||
LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8
|
||||
|
||||
# ---- Writable HOME under read-only root fs ----------------------------------
|
||||
ENV HOME=/tmp
|
||||
|
||||
# ---- JVM ergonomics ---------------------------------------------------------
|
||||
# Identical to src/Dockerfile: container-aware heap, fail-fast on OOM, heap dump to a
|
||||
# writable mount, and Tomcat temp redirected to /tmp for a read-only root filesystem.
|
||||
ENV JAVA_TOOL_OPTIONS="\
|
||||
-XX:MaxRAMPercentage=75 \
|
||||
-XX:+UseContainerSupport \
|
||||
-XX:+ExitOnOutOfMemoryError \
|
||||
-XX:+HeapDumpOnOutOfMemoryError \
|
||||
-XX:HeapDumpPath=/var/tmp/heap \
|
||||
-Dserver.tomcat.basedir=/tmp"
|
||||
|
||||
# ---- Filesystem layout (read-only root filesystem) --------------------------
|
||||
# At runtime /var/tmp/heap and /tmp MUST be writable mounts (tmpfs/emptyDir).
|
||||
RUN mkdir -p /var/tmp/heap && chmod 1777 /var/tmp/heap
|
||||
|
||||
# ---- Non-root user ----------------------------------------------------------
|
||||
RUN groupadd --system --gid 1000 app \
|
||||
&& useradd --system --uid 1000 --gid app --no-create-home --shell /usr/sbin/nologin app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder --chown=app:app /build/app.jar app.jar
|
||||
|
||||
USER app
|
||||
|
||||
# ---- Ports ------------------------------------------------------------------
|
||||
# 8080 — application HTTP port
|
||||
# 9001 — management / actuator port
|
||||
EXPOSE 8080 9001
|
||||
|
||||
# ---- Health check -----------------------------------------------------------
|
||||
# Actuator readiness probe on the management port (9001). Ignored by Kubernetes,
|
||||
# which uses its own probes — kept for docker/compose parity with src/Dockerfile.
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider \
|
||||
http://localhost:9001/actuator/health/readiness || exit 1
|
||||
|
||||
# ---- Entrypoint -------------------------------------------------------------
|
||||
# mainClass (SamplePortfolioApplication) is baked into the bootJar manifest.
|
||||
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
|
||||
Reference in New Issue
Block a user