Skip to content

Distroless Containers

Table of Contents

Introduction

Containers have revolutionized how we develop, package, and deploy applications. However, standard containers based on full Linux distributions often include unnecessary components for running applications, increasing the attack surface and image size. Distroless containers emerged as a solution to these problems.

What are Distroless Containers?

Distroless containers are language-focused Docker images that contain only the application and its runtime dependencies, removing operating system components like package managers, shells, and other general-purpose tools.

Despite the name “distroless” (without distribution), these images are still based on Linux distributions (usually Debian), but with most components removed, keeping only what’s essential to run the application.

Traditional Docker Image

Full Operating System

System Libraries

Package Manager

Shells and Utilities

Language Runtime

Application

Distroless Docker Image

Minimal Operating System

Essential Libraries

Language Runtime

Application

The smallest distroless image, gcr.io/distroless/static-debian12, is approximately 2 MiB. That’s about 50% of the size of Alpine (~5 MiB) and less than 2% of the size of a full Debian (124 MiB).

distroless

Benefits

1. Enhanced Security

Reducing non-essential components significantly decreases the attack surface:

  • Fewer vulnerabilities: Fewer installed packages means fewer components that might contain vulnerabilities.
  • No shell: Most attacks depend on the existence of a shell inside the container.
  • Reduced permissions: Options to run as a non-root user are included by default.

2. Reduced Size

Smaller images bring several benefits:

  • Faster deployment: Less data to transfer between registries and hosts.
  • Less disk space: Saves resources in environments with many containers.
  • Faster startup: Less data to load into memory.

3. Simplified Auditing

With fewer components, it becomes easier to:

  • Track dependencies: Clear visibility of the libraries used.
  • Verify security: Fewer components to analyze for vulnerabilities.

Implementation

Multi-stage Builds

The recommended way to use distroless containers is through Docker multi-stage builds:

# Build stage - using a complete image
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
# Final stage - using distroless
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=build /app /app
# The ENTRYPOINT is already configured as "node"
CMD ["app.js"]

This two-stage process allows:

  1. Building/preparing the application in a complete environment
  2. Copying only the necessary artifacts to the final distroless image

multi-stage build

Supported Technologies

The Google Distroless project supports various languages/runtimes:

  • Node.js: Versions 18, 20, and 22
  • Python: Versions 3.9, 3.10, 3.11
  • Java: Versions 11, 17, 21
  • Go: Through the static image (for compiled binaries)
  • Base: A minimal image with glibc, libssl, openssl, ca-certificates, and tzdata

Each image is available in several variants:

  • gcr.io/distroless/<technology>-debian<version> (default)
  • gcr.io/distroless/<technology>-debian<version>:nonroot (run as non-root user)
  • gcr.io/distroless/<technology>-debian<version>:debug (includes shell for debugging)

Practical Examples

Node.js

# Build stage
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
# Final stage
FROM gcr.io/distroless/nodejs20-debian12:nonroot
WORKDIR /app
COPY --from=build /app /app
EXPOSE 3000
CMD ["index.js"]

Python

# Build stage
FROM python:3.11 AS build
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Final stage
FROM gcr.io/distroless/python3-debian12:nonroot
WORKDIR /app
COPY --from=build /app /app
COPY --from=build /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
EXPOSE 5000
CMD ["app.py"]

Java

# Build stage
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn package -DskipTests
# Final stage
FROM gcr.io/distroless/java21-debian12:nonroot
WORKDIR /app
COPY --from=build /app/target/*.jar /app/app.jar
EXPOSE 8080
CMD ["app.jar"]

Best Practices

Security

  1. Use the :nonroot tag:

    FROM gcr.io/distroless/nodejs20-debian12:nonroot
  2. Pin specific versions:

    # Better
    FROM gcr.io/distroless/nodejs20-debian12:nonroot
    # Avoid
    FROM gcr.io/distroless/nodejs:latest
  3. Use integrity verification:

    Terminal window
    # Verify image signatures with cosign
    cosign verify gcr.io/distroless/nodejs20-debian12
  4. Implement healthchecks via code: Since there’s no curl/wget in distroless images, implement healthchecks using the application language.

    For Node.js:

    healthcheck.js
    const http = require('http');
    const options = {
    host: 'localhost',
    port: process.env.PORT || 3000,
    path: '/health',
    timeout: 2000,
    };
    const request = http.get(options, (res) => {
    process.exit(res.statusCode === 200 ? 0 : 1);
    });
    request.on('error', (err) => {
    process.exit(1);
    });

    In Dockerfile:

    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD ["healthcheck.js"]

Performance

  1. Optimize dependencies:

    Terminal window
    # For Node.js, remove development dependencies
    npm install --production
    # Or use yarn
    yarn install --production
  2. Minimize layers: Combine RUN commands to reduce the number of layers in the image.

  3. Use .dockerignore: Avoid copying unnecessary files to the image.

    node_modules
    .git
    .github
    tests
    docs

Maintenance

  1. Use debug images when necessary:

    Terminal window
    # For temporary debugging
    FROM gcr.io/distroless/nodejs20-debian12:debug
  2. Automate security analysis:

    Terminal window
    # Example with Trivy
    trivy image gcr.io/your-project/your-app:latest
  3. Maintain documentation: Document the process of building and maintaining distroless images.

2025 Considerations

Kubernetes Integration

In 2025, Kubernetes has become even more central to container deployments. When using distroless containers with Kubernetes:

  1. Configure probes properly:

    livenessProbe:
    exec:
    command: ['node', 'healthcheck.js']
    initialDelaySeconds: 10
    periodSeconds: 30
  2. Use security policies:

    securityContext:
    runAsNonRoot: true
    readOnlyRootFilesystem: true
    allowPrivilegeEscalation: false

Modern DevSecOps

  1. Continuous scanning: Integrate tools like Trivy, Grype, or Snyk into the CI/CD pipeline to check for vulnerabilities in distroless images.

  2. Signing and verification: Use Cosign/Sigstore to sign and verify images.

  3. Software Bill of Materials (SBOM): Generate and maintain SBOMs for your distroless images.

New Technologies

  1. Chainguard Images: An alternative to Google Distroless images, focusing on “wolfi-base”.

  2. Jetpack.io Devbox: Integration of development environments with distroless containers.

Limitations and Challenges

  1. Complex debugging: The absence of shell and diagnostic tools makes it difficult to debug problems in production.

  2. Learning curve: Adoption requires advanced knowledge of Docker and containerization practices.

  3. Additional package configuration: Adding extra packages to distroless images can be complicated.

  4. System dependencies: Applications that heavily depend on system utilities may be incompatible.

Alternatives

  1. Alpine Linux: A lightweight alternative (~5 MiB) with a minimal shell and package manager.

  2. Slim variants: Official images with the -slim suffix offer a balance between size and functionality.

  3. Chainguard Images: Minimalist images focusing on compliance and security.

  4. Buildpacks: An alternative approach to building images without explicit Dockerfiles.

Maximum Security

Balance

Ease of Use

Yes

No

Project Needs

Main Priority?

Distroless

Alpine/Slim

Standard Images

Needs Shell/Debug?

Temporary use of :debug

Tag :nonroot

References