Distroless Containers

Distroless Containers

- 5 mins

Distroless Containers Explained: A Practical Guide to Minimal, Secure Images

1. Introduction

Container images based on full Linux distributions like Ubuntu or Debian come packed with utilities, libraries, shells, and other tools that most applications don’t actually need at runtime. While that makes them convenient during development, it also leads to:

To solve this, many teams look to trim the fat by using minimal base images. Two common approaches emerge: starting FROM scratch or using distroless images. Both aim for minimalism, but they take different paths.


2. Why a Pure FROM scratch Image Can Be Painful

Starting with an empty image sounds ideal — no unnecessary packages, tiny size, and complete control. However, a scratch-based image is missing critical runtime components by default:

You end up manually recreating the environment your app expects. This is where distroless images step in — still minimal, but more complete.


3. What Distroless Images Actually Are

Distroless images (maintained under gcr.io/distroless) are designed to be “as close to scratch as possible” but still functional for production workloads. They:

Think of them as curated minimal roots that remove operational junk while preserving essential structure.


4. Level 1: gcr.io/distroless/static

This is the ideal choice for statically compiled apps (Go is the classic example).

Key traits:

This makes it a more realistic and secure drop-in replacement for FROM scratch when your binary has no dynamic dependencies.


5. Level 2: gcr.io/distroless/base and base-nossl

If your application is dynamically linked (e.g., CGO-enabled Go, some Rust builds, C/C++ apps), you’ll need shared libraries.

Two options exist:

gcr.io/distroless/base-nossl (~15MB)

Includes:

gcr.io/distroless/base (~20MB)

Same as above, but adds:

These images are lightweight compared to full distros, and any remaining CVEs are usually limited to common libs like glibc and OpenSSL.


6. Level 3: gcr.io/distroless/cc

Some applications (like Rust programs) require libgcc_s.so.1 at runtime. If you try running these on base and get missing lib errors, distroless/cc is your fix.

Highlights:

It solves the shared-library problem without bloating your image.


7. Distroless Images for Runtime-Based Languages

For interpreted or VM-based languages, distroless provides prebuilt images with embedded runtimes:

Under the hood:

These images remove shells and package managers but supply the necessary runtime engines.


8. Building on Distroless: Multi-Stage Is Mandatory

Since distroless images have no shell and no package manager, you can’t install or build anything inside them directly. Instead, use a multi-stage build:

FROM node:22 AS build
COPY . /app
WORKDIR /app
RUN npm ci --omit=dev

FROM gcr.io/distroless/nodejs22:nonroot
COPY --from=build /app /app
WORKDIR /app
CMD ["hello.js"]

distro

# 1. Build the Docker image
docker build -t my-node-app .

# 2. Run the container
docker run -d -p 3000:3000 my-node-app

# 3. Try access sheel of container
docker exec -it ab83751f34a3 /bin/bash

docker exec -it ab83751f34a3 sh

distro

distro

Tag Variants You Should Know:

For production, nonroot is generally recommended.

9. DISTROLESS - I GOT NO SHELL, WHAT CAN I DO?

Because distroless containers don’t ship with a shell, commands like this won’t work:

nsenter -t $(docker inspect -f '\{\{.State.Pid\}\}' <container>) -u hostname

nsenter -t $(docker inspect -f '\{\{.State.Pid\}\}' <container>) -n ip a

nsenter -t $(docker inspect -f '\{\{.State.Pid\}\}' <container>) -n netstat -tulpn

nsenter -t $(docker inspect -f '\{\{.State.Pid\}\}' 22cd91504233) -n ss -tulpn

distro

Instead, you can debug using nsenter, which runs tools from the host inside the container’s namespaces.

Here’s what it does:

You are not running the command inside the container directly. You are entering its namespaces from the host, so you don’t need a shell inside the container.

This works for monitoring network, inspecting processes, or doing other namespace-level operations without requiring /bin/sh.

This approach allows you to:

REF NSENTER: https://www.redhat.com/en/blog/container-namespaces-nsenter


Thanks for reading!

Guneycan Sanli

Guneycan Sanli

Guneycan Sanli

A person who like learning, music, travelling and sports.

comments powered by Disqus