✦ For everyone, free.

Practical knowledge for real and everyday life

Home

5.3.3.4 Debug Build Stages

A focused guide to Debug Build Stages, connecting core concepts with practical Docker and container operations.

Debug build stages are dedicated stages within a multi-stage Dockerfile, built specifically with troubleshooting in mind, retaining debugging tools, a shell, and other diagnostic capabilities that the final minimal stage deliberately omits.

Defining a Debug Stage

A debug stage typically starts from the same point as the final stage but adds back tools useful for troubleshooting, intended to be built and used only when actually debugging an issue, not as the regularly deployed image.

FROM gcr.io/distroless/python3 AS final
COPY --from=builder /app /app
CMD ["app/main.py"]

FROM final AS debug
USER root
COPY --from=busybox:1.36 /bin/sh /bin/sh
COPY --from=busybox:1.36 /bin/ls /bin/ls

This debug stage builds on top of the minimal final stage, selectively adding back just enough tooling (a shell, basic utilities) to make troubleshooting possible.

Building and Using the Debug Stage When Needed

The debug stage is built explicitly when troubleshooting is actually required, rather than being part of the regular deployment pipeline.

docker build --target debug -t myapp:debug .
docker run -it myapp:debug /bin/sh
Why a Separate Debug Stage Is Better Than a Permanently Included Shell

Keeping debugging tools confined to a dedicated, separately built stage preserves the final production image's minimal size and reduced attack surface, while still making troubleshooting genuinely possible when it's actually needed, rather than forcing a permanent trade-off between the two.

docker images myapp

Comparing myapp:latest (minimal) against myapp:debug (with added tooling) shows the deliberate size difference between the two, each serving a distinct purpose.

Why Debug Build Stages Matter

A dedicated debug stage resolves the tension between wanting a minimal, secure production image and occasionally needing deeper visibility into a running container's internal state, providing both without compromising either.