Why Dockerfiles Prefer apk

Every file a package manager leaves behind ends up in an image layer, so container builds reward the smallest install. Compare three ways to add curl 3,008 to a base image. The Alpine 13,255 file is two lines, FROM alpine:3.24 and RUN apk add --no-cache curl; the careful Debian 319 version needs more ceremony, and a naive one drops the last two lines of the RUN.

debian.Dockerfile: the careful apt installDockerfile
FROM debian:trixie-slim
RUN apt-get update && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/*
Building the three images and comparing time and sizeShell
cd ~/v5-ch1/os-images
for f in alpine debian debian-naive; do
  s=$(date +%s.%N)
  docker build -q --no-cache -f $f.Dockerfile -t l1-curl-$f . >/dev/null
  printf '%-13s %5.1fs\n' $f $(echo "$(date +%s.%N) - $s" | bc)
done
docker image ls --format '{{.Repository}}:{{.Tag}} {{.Size}}' \
  | grep -E '^(alpine:3.24|debian:trixie-slim|l1-curl)'
Output
alpine          4.1s
debian         13.4s
debian-naive   20.4s
l1-curl-debian-naive:latest 184MB
l1-curl-debian:latest 136MB
l1-curl-alpine:latest 20.8MB
debian:trixie-slim 119MB
alpine:3.24 13MB

On this shared 4-CPU machine Alpine finished in under a third of the careful Debian build's time, and its image is about a sixth of the size. The naive Debian build pays twice: apt-get update leaves its indexes in the layer, and without --no-install-recommends apt adds "recommended" packages (108 installed against 101). Node.js 2,131 images follow suit: node:24-alpine 242 MB, node:24-slim 332 MB, full node:24 1.65 GB. Docker 29 514 's containerd 234,762 image store counts compressed and unpacked layers together, so compare ratios, not Docker Hub 514 's figures.

Alpine's size has a price, and it is musl:

Docker weighs these trade-offs when it picks BookNest's base image (Planning Images), and Multi-Stage and BuildKit's multi-stage builds keep compilers out of the final image when you do need them.