Dockerfile pro
The largest community-driven library of Agent Skills (SKILL.md + scripts/references/examples) for Claude, Codex, Gemini CLI, Cursor and friends.
npx -y skills add JayRHa/AgentSkills --skill dockerfile-proAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 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 author says it does
Copied from the file, not written here
Authors small, secure, reproducible multi-stage Dockerfiles with build-cache optimization, pinned base images, non-root runtime users, and minimal attack surface. Use this skill when writing, reviewing, hardening, or shrinking a Dockerfile or container image — e.g. "write a Dockerfile", "containerize this app", "my image is too big", "make this container secure / non-root", "optimize Docker build cache", "multi-stage build", "reduce image layers", "fix Docker best practices", or "review my Dockerfile".
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
7.5 KB, as published. Nobody here has run it
dockerfile-pro
Overview
Produce production-grade Dockerfiles that are small (minimal final image), secure (non-root, pinned, no secrets, minimal surface), and reproducible (deterministic builds with effective layer caching). Applies to any language runtime (Go, Rust, Node, Python, Java, .NET, etc.) and any registry.
Keywords: Dockerfile, container, multi-stage build, build cache, BuildKit, non-root user, distroless, alpine, slim, image size, layer caching, .dockerignore, HEALTHCHECK, OCI image, supply chain, reproducible build, hadolint, Trivy.
The three goals (small / secure / reproducible) often align, but when they conflict, prioritize security > reproducibility > size.
Workflow
Follow these steps in order when authoring or reviewing a Dockerfile.
- Identify the app shape. Compiled binary (Go/Rust/C++) → use a
FROM scratchordistrolessfinal stage. Interpreted/runtime (Node/Python/Java/.NET) → use the matching-slim/distrolessruntime image. JVM/CLR may need a JRE-only final image. - Always use multi-stage. A
builderstage installs toolchains and compiles/installs dependencies; the final stage copies only the runtime artifacts. Never ship compilers, package caches, or dev headers. - Pin everything. Pin the base image by tag and digest (
image:tag@sha256:...). Pin OS and language package versions. This is what makes builds reproducible. - Order layers from least- to most-frequently-changing. Copy dependency manifests (
package.json,go.mod,requirements.txt,*.csproj) and install deps before copying application source. Source changes then don't bust the dependency layer. - Use BuildKit cache mounts (
RUN --mount=type=cache,...) for package-manager caches so repeated builds are fast without bloating the image. - Drop to a non-root user in the final stage with an explicit numeric UID/GID. Make the filesystem read-only-friendly.
- Minimize layers and surface. Combine related
RUNsteps, clean package caches in the same layer, and copy with--chowninstead of a separatechownlayer. - Add operational metadata.
WORKDIR,EXPOSE,ENV, OCILABELs,HEALTHCHECK, and an exec-formENTRYPOINT/CMD. - Add a
.dockerignore. Exclude.git,node_modules, build output, secrets, and CI files so the build context stays small and secrets never enter an image. - Lint and scan. Run
hadolint Dockerfileand a vulnerability scan (e.g.trivy image). Seescripts/check_dockerfile.pyfor a fast static audit you can run with zero dependencies.
Decision frameworks
Which final base image?
| App type | Recommended final base | Notes |
|---|---|---|
| Static Go / Rust binary | gcr.io/distroless/static or scratch | Add CA certs + /etc/passwd if using scratch. |
| Dynamically-linked binary | gcr.io/distroless/base or *-slim | Needs libc. |
| Node.js | gcr.io/distroless/nodejs22-debian12 or node:22-slim | Distroless has no shell — great for prod, harder to debug. |
| Python | python:3.12-slim or gcr.io/distroless/python3 | Prefer slim + venv copy. |
| Java | eclipse-temurin:21-jre or gcr.io/distroless/java21 | JRE only, never the JDK, in the final stage. |
| .NET | mcr.microsoft.com/dotnet/aspnet:8.0 (or -chiseled) | chiseled images are distroless-style and non-root by default. |
| Needs a shell/debug | *-slim or *-alpine | Alpine uses musl — watch for glibc-specific bugs. |
Rule of thumb: distroless or scratch for compiled apps; -slim for interpreted apps. Avoid full :latest / fat base images.
Alpine vs slim?
- Alpine: smallest, but
musllibc can break native deps (Python wheels, glibc binaries) and complicate DNS/locale handling. - Debian
-slim: slightly larger but maximally compatible. Default to-slimunless you have measured a real size win and tested compatibility.
Best Practices
- Pin base by digest:
FROM node:22.11.0-slim@sha256:<digest>. Tags are mutable; digests are not. - One concern per stage, named with
AS builder,AS deps,AS runtime. - Exec form only:
CMD ["node","server.js"]— never the shell formCMD node server.js(it breaks signal handling and PID 1 semantics). - Non-root with numeric UID:
USER 10001:10001. A numeric UID lets Kubernetes enforcerunAsNonRooteven without/etc/passwd. COPY --chown=10001:10001to set ownership without an extra layer; neverchmod -R 777.- Clean in the same layer:
apt-get update && apt-get install -y --no-install-recommends X && rm -rf /var/lib/apt/lists/*. --no-install-recommends(apt) /--no-cache(apk) /--frozen-lockfile(npm ci) for determinism.- Pass secrets via
RUN --mount=type=secret, neverARG/ENV(they persist in image history anddocker historyleaks them). - Add
HEALTHCHECKfor long-running services so orchestrators can detect liveness. - Set
WORKDIRexplicitly; never rely on/. - Use
tinior--init(or a runtime that reaps zombies) when your process spawns children. - See
references/best-practices.mdfor the full annotated checklist and rationale.
Common Pitfalls
- ❌ Running as root in the final image (the default). Always add
USER. - ❌
ADDfor local files — useCOPY. ReserveADDfor remote URLs/tar auto-extraction (and prefer not to). - ❌ Secrets in
ARG/ENVor copied.envfiles — they leak viadocker historyand image layers. - ❌
apt-get upgrade/ unpinnedlatest— destroys reproducibility. - ❌ Separate
RUN chmod/chownafterCOPY— doubles the data on disk across layers. UseCOPY --chown. - ❌ Copying the whole context first (
COPY . .) before installing deps — busts the cache on every source edit. - ❌ Shell-form
CMD/ENTRYPOINT— your process won't receiveSIGTERM, so graceful shutdown breaks. - ❌ No
.dockerignore— bloats context, slows builds, risks leaking.git/credentials. - ❌ Shipping the build toolchain in the final image — keep it in the builder stage only.
Supporting files
references/best-practices.md— exhaustive, annotated best-practice checklist with rationale, BuildKit cache-mount and secret-mount recipes, and a security/supply-chain section.examples/go-multistage.Dockerfile— minimal scratch-based Go image (non-root, pinned, static).examples/node-multistage.Dockerfile— Node.js multi-stage withnpm ci, cache mounts, distroless final.examples/python-multistage.Dockerfile— Python slim with venv copy and non-root user.templates/Dockerfile.template— language-agnostic fill-in-the-blanks multi-stage template.templates/dockerignore.template— sensible default.dockerignore.scripts/check_dockerfile.py— zero-dependency static auditor that flags root users, unpinned bases, secrets in ARG, shell-form CMD, missing.dockerignore, and more.
Use the examples/templates as the starting skeleton, then apply the workflow and run scripts/check_dockerfile.py plus hadolint before finishing.