Distroless Container Images

repository·main·Indexed 12 days ago

https://github.com/googlecontainertools/distroless

Minimal container images containing only an application and its runtime dependencies, excluding shells and package managers to improve security and reduce image size. Provides base images for static binaries, C++, Rust, Java (OpenJDK 17, 21, 25), Node.js (v22, v24, v26), and Python 3.13, with support for Debian 12 and 13.

Tokens
4.2K
Snippets
17
Records
27
Agent score
97%

What's inside Distroless

  1. What are Distroless images?

    main
    Distroless images contain only your application and its runtime dependencies. They do not include package managers, shells, or other standard Linux distribution programs. This minimalism improves security by reducing the attack surface and making vulnerability (CVE) scanning more efficient.
  2. Understand the `dpkg` metadata structure in Distroless images

    main

    Google Distroless Debian-based images use a non-standard dpkg metadata structure to facilitate CVE scanning and package analysis while minimizing image footprint. Unlike traditional Debian images that use a single /var/lib/dpkg/status file and an /var/lib/dpkg/info/ directory, Distroless images consolidate all package information into the /var/lib/dpkg/status.d/ directory.

    To identify installed packages and their versions, tools should scan /var/lib/dpkg/status.d/ instead of looking for the standard /var/lib/dpkg/status file.

    /var/lib/dpkg/
        └── status.d/
                    ├── <package>
                    └── <package>.md5sums
  3. Choose the right distroless base image

    main

    Distroless provides three primary base images depending on your application's requirements for libc and SSL support. Choose based on your language and compilation strategy:

    1. gcr.io/distroless/static: For statically compiled applications (e.g., Go) that do not require libc. Includes ca-certificates, /etc/passwd (root), /tmp, and tzdata.
    2. gcr.io/distroless/base-nossl: For applications that require libc but do not need libssl. Includes everything in static plus glibc.
    3. gcr.io/distroless/base: For most other applications, including Go apps that require libc/cgo. Includes everything in static, glibc, and libssl (plus zlib and libzstd for Debian 13+).

    Important Note on OpenSSL: Debian 13+ base images do not include OpenSSL legacy algorithms. If your application requires them, you must add openssl-legacy-provider manually.

  4. Configure ENTRYPOINT and CMD for Distroless

    main

    Because distroless images do not contain a shell, you must use the vector (exec) form for ENTRYPOINT and CMD in your Dockerfile. Using the shell form will cause the container to fail because the runtime will attempt to prefix the command with /bin/sh.

    # Correct: uses vector form
    ENTRYPOINT ["myapp"]
    
    # Incorrect: will fail (attempts to use shell)
    ENTRYPOINT "myapp"
  5. Handle library discovery with `ctypes.util.find_library()`

    main

    The image includes a pre-generated ld.so.cache to support calls to ctypes.util.find_library().

    Important: If you modify the image by adding new shared libraries (e.g., via a multi-stage build), these new libraries will not be found by ctypes unless you run ldconfig to refresh the cache.

  6. Use the `gcr.io/distroless/cc` image for C++ or Rust applications

    main

    The gcr.io/distroless/cc image is a minimal Linux runtime based on glibc. It is designed for "mostly-statically compiled" languages such as Rust, D, or C++ that require specific shared libraries not present in the standard base image.

    This image includes everything found in the distroless/base image, plus:

    • libgcc1 and its dependencies.

    To use this image, you must copy your compiled application binary into the image and specify the correct CMD (command) to execute your application.

    # Example Dockerfile usage
    FROM gcr.io/distroless/cc
    COPY my-compiled-app /my-compiled-app
    CMD ["/my-compiled-app"]
  7. Add a new JAVA version to distroless

    main

    To support a new OpenJDK version within the distroless repository, follow these steps:

    1. Update ADOPTIUM_DEB_PER_DISTRO in java/BUILD with the new version.
    2. Update JAVA_MAJOR_VERSIONS in java/config.bzl.
    3. Add two YAML files to the java/testdata folder to prepare the necessary test data (refer to existing files in that directory for the required format).
    4. Verify the changes by running the Bazel build command for the java directory.
    bazel build //java:...
  8. Use the `gcr.io/distroless/python3` image

    main

    The gcr.io/distroless/python3 image provides a minimal Linux runtime containing Python 3.13 and its dependencies. It does not include a shell.

    The image's entrypoint is set to python. To run a script, you must provide the path to your .py file in the CMD instruction of your Dockerfile.

    FROM gcr.io/distroless/python3
    COPY my_script.py /app/my_script.py
    CMD ["/app/my_script.py"]
  9. Ensure compatibility in multi-stage builds

    main

    To prevent ABI-related errors when using distroless Python images in multi-stage builds, use a compatible build image.

    For example, if targeting python3-debian13, use python:3.13-slim-trixie as your build stage.

    Additionally, because the distroless Python path is /usr/bin/python, ensure your build environment matches this path to avoid broken internal links in virtual environments. If your build image uses a different path (like /usr/local/bin/python), create a symlink during the build stage:

    # Example symlink fix in build stage
    RUN ln -s /usr/local/bin/python /usr/bin/python
  10. Implement package scanning for Distroless tool authors

    main

    When developing security scanners, vulnerability analyzers, or package management tools intended to run against Distroless images, follow these implementation guidelines:

    • Scan Directory: Target /var/lib/dpkg/status.d/ to find installed packages.
    • Retrieve Metadata: Read the <package> file for version and dependency details.
    • Retrieve File Lists/Checksums: Use the <package>.md5sums file to identify which files belong to a package and verify their integrity.
    • Avoid Standard Paths: Do not attempt to access or rely on the following paths, as they are intentionally omitted:
      • /var/lib/dpkg/status
      • /var/lib/dpkg/info/<package>.list
      • /var/lib/dpkg/info/<package>.md5sums
      • Any other files in /var/lib/dpkg/info/
  11. Use `gcr.io/distroless/java` images

    main

    The gcr.io/distroless/java images provide a minimal Linux runtime based on OpenJDK.

    Entrypoint Behavior: The image's entrypoint is configured to execute the equivalent of java -jar. Consequently, when using this image, you must provide the path to your application's JAR file via the CMD instruction in your Dockerfile or as an argument to your container runtime.

    Available Versions: Depending on the specific tag used, the image includes Temurin OpenJDK versions:

    • gcr.io/distroless/java17-debian13 (OpenJDK 17)
    • gcr.io/distroless/java21-debian13 (OpenJDK 21)
    • gcr.io/distroless/java25-debian13 (OpenJDK 25)
    # Example usage in a Dockerfile
    FROM gcr.io/distroless/java21-debian13
    COPY my-app.jar /app/my-app.jar
    CMD ["/app/my-app.jar"]
  12. Use distroless Node.js images

    main

    Distroless Node.js images provide a minimal Linux runtime containing only the necessary dependencies for Node.js. The entrypoint is pre-configured to node, meaning you must provide the path to your application's entrypoint file (e.g., app.js) using the CMD instruction in your Dockerfile.

    # Example usage pattern
    FROM gcr.io/distroless/nodejs22-debian13
    COPY app.js /app/app.js
    CMD ["/app/app.js"]