Hard15 minContainerization
UpdatedAug 2, 2026
Edit

Scratch vs. Distroless Images

CONCEPTS:Minimal Base Images (Scratch & Distroless)Multi-stage Builds

Why This Is Asked

This is a deep-dive question into container security and optimization. It tests if the candidate knows how to build “enterprise-grade” images that are not just small, but also hardened against common attacks by removing every unnecessary binary.

Key Concepts

  • Attack Surface: How removing shells and package managers improves security.
  • Static vs. Dynamic Linking: Why scratch only works for some languages.
  • Debugging: The trade-off between security and ease of troubleshooting.
  • CA Certificates: A common pitfall when using ultra-minimal images.

Answers by Technology

+ Add Variant
DockerImprove this answer ✏️

Expected Answer

Scratch and Distroless are techniques for creating the smallest and most secure Docker images possible.

  • FROM scratch is an empty base image. It is mostly used for statically compiled binaries (like those written in Go or Rust). The resulting image contains nothing but your binary.
  • Distroless images (maintained by Google) go one step further than Alpine. They include only your app and its runtime dependencies (like libssl or glibc). They specifically do not include a shell (/bin/sh) or a package manager (apt, apk).

Summary: If you have a static binary, use scratch. If you need a runtime like Node or Java but want high security, use Distroless.

Why It Matters

Standard images (like node or python) are convenient but bloated and insecure. They contain hundreds of binaries that an attacker can use once they’ve compromised your application (e.g., using curl to download a rootkit or sh to explore your network). By using minimal bases, you remove these tools, making a successful exploit much harder to execute.

Example Code

Go app using scratch

# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# Final stage
FROM scratch
COPY --from=builder /app/main /main
# Important: you may also need to copy CA certs if making HTTPS calls
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/main"]

Node app using distroless

FROM node:20 AS build-env
WORKDIR /app
COPY . .
RUN npm ci --only=production

FROM gcr.io/distroless/nodejs20-debian12
COPY --from=build-env /app /app
WORKDIR /app
CMD ["index.js"]

Common Mistakes

  • Forgetting CA Certificates: Statically linked binaries often fail to make HTTPS requests in a scratch image because there are no root certificates. You must copy them from the build stage.
  • Trying to docker exec: Developers often get frustrated when they can’t log into a distroless container to debug. (Solution: Use ephemeral debug containers in Kubernetes or temporary “debug” builds).
  • Not using static linking for scratch: If your binary is dynamically linked to libc, it will crash in scratch with a “file not found” error.

Follow-up Questions

  • How do you debug a scratch or Distroless container? (Answer: In Kubernetes, use kubectl debug. In local Docker, you might need to rebuild with a shell or use a tool like dive to inspect layers).
  • What is the difference between alpine and distroless? (Answer: Alpine is a full Linux distro with a shell and package manager (apk). Distroless has neither).
  • What is CGO_ENABLED=0? (Answer: A Go environment variable that ensures the resulting binary is statically linked and doesn’t depend on system libraries like libc).

References