CoursesAdvanced container securityMinimal & secure images

Slimming & layer hygiene

Measure the image, then cut every wasted byte.

Advanced12 min · lesson 8 of 25

Minimizing an image is a measure-then-cut loop, not a guess. You cannot shrink what you cannot see, so the first move is always to inspect where the bytes and the risk are — layer by layer — and then attack the biggest, most dangerous contributors. dive and docker history are the microscopes; the cuts are layer hygiene, a tight build context, and dropping anything the runtime does not need.

terminal
$ docker history --no-trunc svc:1.0 # size added by each instruction
$ dive svc:1.0 # interactive: wasted space, per-layer files
# "Image efficiency score: 61 %" -> a lot of duplicated / deleted-but-shipped content
$ docker run --rm wagoodman/dive svc:1.0 --ci # fail a build below an efficiency threshold

Layer hygiene

Each RUN is a layer, and a file deleted in a later layer still ships in the earlier one — so cleanup only helps when it happens inside the same RUN that created the mess. Chain the install, use, and cleanup in one instruction; use --no-install-recommends (apt) or --no-cache (apk) so you never pull extras; and remove package caches in the same step. This is where careless Dockerfiles hide hundreds of wasted megabytes and, worse, leftover secrets.

Dockerfile
# BAD: three layers, cache shipped, "removed" apt lists still in an earlier layer
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# GOOD: one layer, no recommends, cache gone before the layer is sealed
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*

Shrink the context, not just the image

A .dockerignore keeps junk and secrets out of the build context entirely — .git (which can carry history and tokens), node_modules, local .env files, test fixtures. That speeds the build, prevents accidental COPY . . leaks, and keeps the image lean. Combined with a minimal base and multi-stage, the ignore file is the cheapest slimming and security win there is.

.dockerignore
.git
.env
**/node_modules
**/*.test.*
Dockerfile
README.md
# nothing here can be COPY-ed in by accident or bloat the context
Smaller is a security outcome, not just a speed one
Every package you remove is a CVE you no longer patch and a tool an attacker no longer finds. Do not chase bytes for their own sake — chase them because a 6MB distroless image with two dependencies has a fraction of the vulnerability surface of a 900MB image with a full distro. Slimming and hardening are the same activity measured two ways.