0%
Containers and Kubernetes: From cgroups to Operators
What a Container Actually Is
Kubernetes Architecture
Workloads
Scheduling and Resources
Networking and Storage
Extending Kubernetes
Image Size and Base Image Choices
A base image is a filesystem, and the choice between the families on offer is a choice about which parts of a conventional operating system you are keeping. Knowing what each one contains makes the decision mechanical rather than cultural.
The parts, and which are load-bearing
A conventional base image holds about six things, and only some of them are needed to run a program.
There is a C library, which every dynamically linked binary needs. There is a shell and a set of core utilities. There is a package manager with its database. There is a certificate bundle for verifying outbound connections. There is timezone data. And there are the account files that map user and group identifiers to names.
The first is load-bearing for almost everything. The fourth, fifth and sixth are load-bearing for specific behaviours that are easy to forget until they break. The second and third are needed only at build time, which is the whole argument for a different final image.
The families, by size
Five families cover the landscape, and their sizes differ by two orders of magnitude.
A full distribution image is a hundred to two hundred megabytes uncompressed, with everything above plus development headers and documentation. A slim variant of the same distribution is sixty to eighty, with documentation and some tooling removed. A musl-based minimal distribution is five to ten, achieved by a different C library and a combined utilities binary. A distroless image is twenty to thirty, holding a C library, certificates, timezone data and account files and nothing else. An empty image is zero and holds nothing at all.
Where the bytes are in a full image
Breaking a full base down explains why the slim variants exist and how much further they can go.
The largest single consumers are documentation and locale data, which together are frequently a third of the image. Development headers and static libraries are another large block in images intended for building. The package manager's own database and cached lists are tens of megabytes. The shell and utilities are small by comparison, a few megabytes. The C library itself is a handful.
So removing documentation, locales and headers gets most of the way from a full image to a slim one without changing anything functional, which is exactly what the slim variants do. Going further means removing the package manager and the shell, which changes what the image can do.
The question that actually decides it
Rather than arguing about families, the decision follows from two properties of the thing being shipped.
First, is the binary statically or dynamically linked. A statically linked binary needs no C library, so it can run on an empty image. A dynamically linked one needs a C library and specifically needs the one it was linked against. Second, does the program require an interpreter or a language runtime. If it does, that runtime and its dependencies are the floor, and the base must provide them.
Those two answers eliminate most options. A static binary goes on an empty or static base. A dynamically linked compiled binary goes on a distroless or slim base matching its C library. An interpreted application goes on the smallest image that carries a working runtime for it, which is usually a slim variant or a language-specific distroless image.
What the orchestrator cares about
The reason size matters at all is worth stating precisely, because it is not the registry bill.
Every node that runs a pod pulls the image once, and the pull is on the critical path for the pod becoming ready. Images also consume node disk, where they count against the ephemeral storage thresholds that trigger eviction. And image contents are the input to vulnerability scanning, which is a workload for people rather than for machines.
So size translates into cold start latency, into how many distinct images a node can hold before pressure, and into how much security noise a team processes. None of those is the transfer cost, which for most organisations is negligible.
Reading what is actually in an image
All of this is inspectable without running anything, which is the right way to settle an argument about a base image.
The last command needs a shell, so it does not work on a minimal image, which is itself informative. For those, extracting the layers locally and measuring directories is the equivalent, and the first command works on anything because it reads the manifest rather than the contents.
Language-specific base images
Most ecosystems publish their own images, and understanding what they are saves a lot of guessing.
A language image is a distribution base with the runtime, its package manager and often a build toolchain added, published in the same variants as the distribution: a full tag, a slim tag and sometimes a minimal distribution tag. So the size differences between them are the distribution differences, plus the runtime, which for a managed runtime is substantial.
The ones worth knowing about separately are the language-specific distroless images, which carry a runtime and the four small content pieces and nothing else. Those are the natural final-stage target for an interpreted or bytecode application, and they are frequently overlooked because teams assume distroless means no runtime.
The uncompressed cost of a package manager
It is worth putting a number on the package manager, because it is the part people are most reluctant to remove.
The manager's binary is small. Its package database, its cached index of available packages, and the metadata for installed packages together run to tens of megabytes on a typical distribution, and the cached index is pure build-time state. An image that installs packages and does not clean the cache in the same instruction carries that index forever.
Beyond size, the package manager is the main reason a compromised container can install tooling, so removing it is both a size and a hardening measure. The build stage keeps it; the final stage does not need it, and the only reason to keep it there is a pattern of patching running containers, which is not how any of this is supposed to work.
Operating system variants and the host kernel
One constraint is easy to forget and produces a confusing scheduling failure.
The image declares an operating system, and a node can only run images matching its own kernel family. A cluster with both kinds of node needs images for both, selected by the scheduler through node labels and the workload's selector. The image index can carry both, so one reference serves both kinds.
What catches people is the version constraint on one of the families, where the image's version must match the host's closely rather than merely being the same family. A pod that will not schedule, or schedules and fails with a version mismatch, is this, and the index's platform entries are where the required version is visible.
The annotations worth setting
A base image choice is also a documentation decision, and a few standard annotations carry most of the value.
The source repository, the revision, the build timestamp and the base image's digest are the four that matter in an incident. With them, an unfamiliar image in production can be traced back to the commit that produced it and the base it derived from, in one command and without asking anyone.
The base digest in particular is what makes a fleet-wide question answerable: given a vulnerable base, which deployed images derive from it. Without the annotation, the answer requires guessing from tags, and tags move. It is one line in the build and it converts a half-day investigation into a query.
A strong answer skips the cultural argument about base image families and derives the choice from two properties: whether the binary is statically or dynamically linked, and whether a language runtime is required. Those two answers eliminate most options. The candidate should also name why size matters, which is cold start latency, node disk pressure and scanner noise, not the registry bill.