Dockerfile
Dockerfile best practices including multi-stage builds, layer caching, security, JVM/Spring Boot containerization patterns, BuildKit features (cache/secret mounts), multi-architecture builds, signal handling, and image provenance (cosign, SBOM). Use when writing or reviewing Dockerfiles.From its SKILL.md
npx -y skills add iceflower/agent-skills --skill dockerfileAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
6.4 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
Dockerfile Rules
1. Multi-Stage Build Pattern
Separate build dependencies from runtime to minimize image size and attack surface.
# Stage 1: Build
FROM builder-image AS build
WORKDIR /app
COPY dependency-files ./
RUN install-dependencies
COPY src ./src
RUN build-command
# Stage 2: Runtime
FROM runtime-image AS runtime
WORKDIR /app
COPY --from=build /app/output ./
ENTRYPOINT ["./app"]
2. Base Image Selection Criteria
- Use minimal runtime images (not build images) in production
- Prefer Alpine/slim/distroless variants for smaller image size
- Always pin to a specific tag — never use
latest - Choose images with active security maintenance
- Use distroless when shell access is not needed
3. Layer Caching Optimization
Copy Order (least changing → most changing)
- Build tool config files (rarely changes)
- Dependency lock files → install dependencies (changes on dep update)
- Source code (changes frequently)
- Build command
Cache Rules
- Separate dependency download from source compilation
- Copy only necessary files at each layer
- Avoid
COPY . .— it invalidates cache on any file change - Use
.dockerignoreto exclude unnecessary files
4. .dockerignore
Required Entries
.git
.gitignore
build
out
node_modules
*.md
docker-compose*.yml
Dockerfile*
.env*
.idea
*.iml
*.log
5. Security Best Practices
Non-Root User
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
Minimal Permissions
- Use read-only filesystem where possible
- Do not install unnecessary packages in runtime stage
- Remove build tools and caches from final image
- Never copy secrets into the image — use runtime environment variables
Image Scanning
- Scan images for vulnerabilities before pushing (Trivy, Snyk)
- Update base images regularly for security patches
- Pin dependency versions for reproducible builds
6. JVM/Spring Boot Multi-Stage Build
Standard Pattern
# Stage 1: Build
FROM gradle:8-jdk21 AS build
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
RUN gradle dependencies --no-daemon
COPY src ./src
RUN gradle bootJar --no-daemon -x test
# Stage 2: Runtime
FROM eclipse-temurin:21-jre-alpine AS runtime
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=build /app/build/libs/*.jar app.jar
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]
Multi-Module Project Pattern
FROM gradle:8-jdk21 AS build
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
COPY buildSrc ./buildSrc
COPY modules/app/build.gradle.kts modules/app/
COPY modules/domain/build.gradle.kts modules/domain/
RUN gradle dependencies --no-daemon
COPY modules ./modules
RUN gradle :modules:app:bootJar --no-daemon -x test
FROM eclipse-temurin:21-jre-alpine AS runtime
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=build /app/modules/app/build/libs/*.jar app.jar
USER appuser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
7. JVM Base Image Selection
| Image | Size | Use Case |
|---|---|---|
eclipse-temurin:21-jre-alpine | ~100MB | General production (recommended) |
gcr.io/distroless/java21-debian12 | ~100MB | Maximum security (no shell) |
eclipse-temurin:21-jre | ~250MB | When Alpine compatibility issues |
eclipse-temurin:21-jdk | ~450MB | Build stage only |
Selection Criteria
- Production: Use JRE, not JDK
- Prefer Alpine variants for smaller image size
- Use distroless when shell access is not needed
- Always pin to specific tag, never use
latest
8. Gradle Layer Caching
# 1. Build tool config (rarely changes)
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
# 2. Download dependencies (changes on dependency update)
RUN gradle dependencies --no-daemon
# 3. Source code (changes frequently)
COPY src ./src
# 4. Build
RUN gradle bootJar --no-daemon -x test
9. JVM Runtime Options
Production Defaults
ENTRYPOINT ["java", \
"-XX:MaxRAMPercentage=75.0", \
"-XX:InitialRAMPercentage=50.0", \
"-Djava.security.egd=file:/dev/./urandom", \
"-jar", "app.jar"]
Container-Aware Settings
| Option | Purpose |
|---|---|
MaxRAMPercentage=75 | Use up to 75% of container memory for heap |
InitialRAMPercentage=50 | Start with 50% heap allocation |
UseContainerSupportis enabled by default since JDK 11 — no need to set explicitly
JVM Memory Rules
- Always leave 25%+ memory for non-heap (metaspace, thread stacks, GC)
- Do not set fixed
-Xmx— use percentage-based options for container flexibility - Use
JAVA_OPTSorJAVA_TOOL_OPTIONSenvironment variable for runtime overrides
10. Anti-Patterns
- Using
latesttag for base images - Running as root in production
- Copying entire project with
COPY . . - Installing build tools in runtime image
- Hardcoding secrets or config values in Dockerfile
- Skipping
.dockerignore - Single-stage build including build tools in final image
- Using
ADDwhenCOPYsuffices (ADDhas extra behavior: URL fetch, tar extraction)
Additional References
- For BuildKit, multi-arch builds, signal handling, and image provenance, see references/advanced-patterns.md
- For building OCI images without Docker daemon or Dockerfile (Jib, Buildpacks, Kaniko, Shipwright), see references/dockerless-builds.md
What ships with it: 7 files
36.9 KB alongside SKILL.md, 1 of them executable
assets/
references/
- advanced-patterns.md7.8 KB
- dockerless-builds.md15.6 KB
scripts/
- lint_dockerfile.pyruns8.9 KB
- README.md730 B