Distroless Containers
Table of Contents
- Table of Contents
- Introduction
- What are Distroless Containers?
- Benefits
- Implementation
- Best Practices
- 2025 Considerations
- Limitations and Challenges
- Alternatives
- References
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.
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).
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 imageFROM node:20 AS buildWORKDIR /appCOPY package*.json ./RUN npm install --productionCOPY . .
# Final stage - using distrolessFROM gcr.io/distroless/nodejs20-debian12WORKDIR /appCOPY --from=build /app /app# The ENTRYPOINT is already configured as "node"CMD ["app.js"]
This two-stage process allows:
- Building/preparing the application in a complete environment
- Copying only the necessary artifacts to the final distroless image
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 stageFROM node:20 AS buildWORKDIR /appCOPY package*.json ./RUN npm install --productionCOPY . .
# Final stageFROM gcr.io/distroless/nodejs20-debian12:nonrootWORKDIR /appCOPY --from=build /app /appEXPOSE 3000CMD ["index.js"]
Python
# Build stageFROM python:3.11 AS buildWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .
# Final stageFROM gcr.io/distroless/python3-debian12:nonrootWORKDIR /appCOPY --from=build /app /appCOPY --from=build /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packagesEXPOSE 5000CMD ["app.py"]
Java
# Build stageFROM maven:3.9-eclipse-temurin-21 AS buildWORKDIR /appCOPY pom.xml .COPY src ./srcRUN mvn package -DskipTests
# Final stageFROM gcr.io/distroless/java21-debian12:nonrootWORKDIR /appCOPY --from=build /app/target/*.jar /app/app.jarEXPOSE 8080CMD ["app.jar"]
Best Practices
Security
-
Use the
:nonroot
tag:FROM gcr.io/distroless/nodejs20-debian12:nonroot -
Pin specific versions:
# BetterFROM gcr.io/distroless/nodejs20-debian12:nonroot# AvoidFROM gcr.io/distroless/nodejs:latest -
Use integrity verification:
Terminal window # Verify image signatures with cosigncosign verify gcr.io/distroless/nodejs20-debian12 -
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
-
Optimize dependencies:
Terminal window # For Node.js, remove development dependenciesnpm install --production# Or use yarnyarn install --production -
Minimize layers: Combine RUN commands to reduce the number of layers in the image.
-
Use
.dockerignore
: Avoid copying unnecessary files to the image.node_modules.git.githubtestsdocs
Maintenance
-
Use debug images when necessary:
Terminal window # For temporary debuggingFROM gcr.io/distroless/nodejs20-debian12:debug -
Automate security analysis:
Terminal window # Example with Trivytrivy image gcr.io/your-project/your-app:latest -
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:
-
Configure probes properly:
livenessProbe:exec:command: ['node', 'healthcheck.js']initialDelaySeconds: 10periodSeconds: 30 -
Use security policies:
securityContext:runAsNonRoot: truereadOnlyRootFilesystem: trueallowPrivilegeEscalation: false
Modern DevSecOps
-
Continuous scanning: Integrate tools like Trivy, Grype, or Snyk into the CI/CD pipeline to check for vulnerabilities in distroless images.
-
Signing and verification: Use Cosign/Sigstore to sign and verify images.
-
Software Bill of Materials (SBOM): Generate and maintain SBOMs for your distroless images.
New Technologies
-
Chainguard Images: An alternative to Google Distroless images, focusing on “wolfi-base”.
-
Jetpack.io Devbox: Integration of development environments with distroless containers.
Limitations and Challenges
-
Complex debugging: The absence of shell and diagnostic tools makes it difficult to debug problems in production.
-
Learning curve: Adoption requires advanced knowledge of Docker and containerization practices.
-
Additional package configuration: Adding extra packages to distroless images can be complicated.
-
System dependencies: Applications that heavily depend on system utilities may be incompatible.
Alternatives
-
Alpine Linux: A lightweight alternative (~5 MiB) with a minimal shell and package manager.
-
Slim variants: Official images with the
-slim
suffix offer a balance between size and functionality. -
Chainguard Images: Minimalist images focusing on compliance and security.
-
Buildpacks: An alternative approach to building images without explicit Dockerfiles.
References
- GoogleContainerTools/distroless - GitHub
- Dockerfiles for Node and TypeScript with Distroless - DEV Community
- Distroless Containers - Contrast Security
- Dockerize a Node.js App using a Distroless Image - AlphaSec
- Docker healthchecks in distroless Node.js - Matt Knight
- What’s Inside Distroless Container Images - iximiuz Labs
- Choosing the best Node.js Docker image - Snyk
- Why distroless containers aren’t the security solution you think they are - Red Hat