CI Perf Lint

dockerfile-runtime-image-uses-heavy-base

Why it matters

Full language images and SDK images carry development tools and system packages that may not be needed to run the application. A smaller runtime image can reduce cold pulls, extraction, pushes, and storage. It does not necessarily improve application execution or cached rebuild speed.

What it flags

The final Dockerfile stage has a visible CMD or ENTRYPOINT and uses a known development-heavy base:

This is a warning, included in strict mode, with medium confidence: runtime compatibility and actual image size require verification. Java JDK images are covered by jvm-production-image-uses-jdk-runtime.

When a visible Go/Rust compile output is directly executed in the same stage ancestry, dockerfile-runtime-inherits-build-environment supplies the more specific warning instead.

Suggested action

Choose a lighter base appropriate to the application:

Current base Candidate
node:22 node:22-slim
python:3.12-bookworm python:3.12-bookworm-slim
ruby:3.4-trixie ruby:3.4-trixie-slim, if published for the selected version/platform
Go / Rust build image Minimal OS or compatible distroless runtime; scratch only for verified static binaries
.NET SDK Matching runtime, aspnet, or runtime-deps, depending on deployment type

Keep runtime versions and OS generations where possible. bookworm and trixie describe Debian generations, not image weight. Slim retains glibc compatibility; Alpine uses musl and needs native-dependency verification. Distroless typically removes the shell and package manager. Scratch provides no OS libraries, CA certificates, or timezone data by default. Verify candidate tag/platform availability instead of mechanically rewriting tags or digests.

Keep compilers and SDKs in builder stages. Native extensions may still need compilation even when installation uses a runtime package manager.

Verification

Compare image size and cold pull, extraction, and push times. Test startup, application behavior, native/shared libraries, certificates, timezone data, and operational requirements.

What the scanner does

Uses CI-discovered Dockerfiles and reports once per Dockerfile, at the final FROM. It resolves earlier stage aliases, including chained inheritance such as FROM builder AS prod; switching that pattern requires a separate runtime stage with the necessary artifacts and production dependencies copied in. It skips development/test/build paths or stage aliases and visible compilation/toolchain commands in the final stage. It does not resolve variable-based image references. Already lightweight variants, custom images, unknown tags, and images outside the known families are not flagged. A digest does not suppress a known full-image tag, but digest-only references cannot identify a variant.

Sources