Skip to content

Distroless Images

When we package our application into containers, we have to find a suitable base image.

Normally, we would take an official image containing the needed runtime for our application. For example, the typical base images for a ASP.NET Core Docker images application are bitnami/aspnet-core, ubuntu/dotnet-aspnet or the chainguard/aspnet-runtime.

They are good choice since they are well maintained and battle tested. Nevertheless, they come with some disadvantages. They usually based on known distributions and therefore contain more tools than are actually necessary to just run the application.

Debian comes with some packages which may help with debugging but are not required to run the application, in particular packages like a shell or package managers.

These additional tools bring problems with them:

  • They make the image bigger than really needed.
  • Every tool can bring additional vulnerabilities and therefore increases the attack surface.

The increase in the size of the container image will have a negative impact on operating costs. There will be a data transfer between the container management mechanisms(k8s, openshift, ecs) and the container registry at each image pull stage. Moreover, the CI has to upload container images to the image registry which causes extra time to upload(increase build pipeline execution time), extra load on the network, and possibly inter-AZ or inter-region data transfer cost as well depending on the location of the CI system and container registries.

In short, the extra 100 MiB overhead which may look negligible to a developer who builds the container images, may not be negligible for platform maintainers.

Restricting what’s in your runtime container to precisely what’s necessary for your application is one of the best practices for container image creation.

Distroless container images can help a lot to create a minimalistic and secure container image.

Distroless is not a one-size-fits-all solution.

Building Distroless Images

If you're keen on the idea of carefully crafting your images from some minimal base, you may want to take a look at following options:

Multi-stage Docker builds

You can start FROM SCRATCH and carefully copy over only the needed bits from the build stages to your target image.

The intermediate summary of the "FROM SCRATCH" container pitfalls: - Scratch containers miss proper user management. - Scratch containers miss important folders (/tmp, /home, /var). - Scratch containers miss CA certificates. - Scratch containers miss timezone information. - It does not have any security features or patching mechanisms

Apko and Melange

Uses Alpine as a minimalistic & secure base image, and with the help of two tools, apko and melange, allows to build an application-tailored image containing only the necessary bits. These tools provide for a reproducible, declarative approach to building OCI images.

melange lets you build apks using declarative YAML pipelines. apks are .apk packages compatible with the package manager used by Alpine, similar to .deb or .rpm for instance.

apko lets you bundle a collection of APKs into an OCI image using a declarative YAML manifest.

Chisel

Chisel a somewhat similar idea to the above project, but from Canonical, hence, Ubuntu-based. The project seems very new, but Microsoft has already used it in your production.

DockerSlim

DockerSlim a CLI tool that allows you to automatically convert a "fat" container image into a "slim" one by doing a runtime analysis of the target container and throwing away the unneeded stuff.

Bazel

Google's distroless images one of the first attempts to solve the problem of bloated container images. Debian-based, really small footprint, with the out-of-the-box support of the most popular runtimes (static, Java, Node.js, and experimental Python support).

These images are built using bazel.

References

Distroless: Using Minimal Container Image for Kubernetes Workload.