A production image should contain the reviewed runtime artifact and the minimum files and privileges required to execute it. It should also be traceable back to source and forward to the exact digest deployed.
Quick answer
Use a multi-stage build, deterministic dependency inputs, a narrow build context, a maintained minimal runtime base, and a numeric non-root user. Promote by digest and attach provenance, SBOM, scan, and signature evidence to that immutable identity. A clean scan is one bounded signal; it does not prove safe application behavior, correct configuration, or an uncompromised build system.
Learning objectives
- Design a Java container build that separates compilation tools from the runtime image and avoids accidental secret or source inclusion.
- Evaluate provenance, SBOM, scanning, signing, and admission evidence without treating any single supply-chain control as complete proof.
Prerequisites
Review OCI Container Images and Runtime Boundaries. Follow the course or topic cluster.
A bounded image build
FROM eclipse-temurin:21-jdk AS build
WORKDIR /workspace
COPY gradlew settings.gradle build.gradle ./
COPY gradle ./gradle
RUN ./gradlew --no-daemon dependencies
COPY src ./src
RUN ./gradlew --no-daemon clean bootJar
FROM eclipse-temurin:21-jre
RUN addgroup --system app && adduser --system --ingroup app --uid 10001 app
WORKDIR /app
COPY --from=build --chown=10001:10001 /workspace/build/libs/app.jar ./app.jar
USER 10001
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
The example is explanatory, not a pinned production image. A real release must pin approved base identities, verify licensing and patch policy, prevent credentials from entering build arguments or layers, and test the resulting process under its runtime security context. .dockerignore narrows context but is not a secret-management system.
Production failure scenario
A CI job copies the repository before running the build. A developer credential file enters an early layer and is later deleted. The final filesystem looks clean, but the secret remains recoverable from image history. The vulnerability scan reports no known CVEs, so the release is incorrectly approved.
Revoke the credential, remove it from build context and history, rebuild from reviewed source, produce a new digest, and verify registry retention and consumers. Deleting a file in a later layer or rescanning the old image does not repair disclosure.
Common misconceptions
- Smaller images reduce surface and transfer cost but are not automatically secure.
- Deleting a secret in a later Dockerfile step does not erase an earlier layer.
- Running as non-root does not remove the need for capabilities, filesystem, and network controls.
- An SBOM inventories components; it does not prove those components are safe at runtime.
- A valid signature proves the signer approved a digest under a policy, not that the software is bug-free.
Decision checklist
- Keep build and runtime stages separate and pin reviewed dependencies.
- Exclude credentials, local caches, test output, and VCS metadata from the context.
- Run with a non-root identity and a read-only filesystem where the application contract permits it.
- Bind provenance, SBOM, scan, and signature records to the promoted digest.
- Rebuild rather than relabel when source, base image, or policy changes.
- Test application startup and required writes under the final runtime restrictions.
Continue with Kubernetes Pods, Deployments, and Services for Backend Apps.
Related reading
- OCI Container Images and Runtime Boundaries defines the immutable artifact and runtime contracts used here.
- Secret Management Explained covers credential ownership beyond build context exclusion.
- Kubernetes Configuration, Secrets, and Workload Identity carries the secret boundary into runtime delivery and rotation.
Official sources
- Docker build best practices, accessed August 18, 2026.
- Docker multi-stage builds, accessed August 18, 2026.
- OCI Image Specification, accessed August 18, 2026.