Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lab: Slim Python images

Build the same tiny Python HTTP script twice: once on the full python:3.12-bookworm image, once ending on python:3.12-slim-bookworm. Compare image size on disk.

Lab objective

  • Create one stdlib-only server file.
  • Build Dockerfile.single and Dockerfile.multi, then compare docker images output.

Application (stdlib only)

mkdir -p ~/peachycloudsecurity-build-lab && cd ~/peachycloudsecurity-build-lab
cat > peachycloudsecurity_httpd.py <<'EOF'
"""Tiny HTTP server for build demos (no third-party packages)."""
from http.server import BaseHTTPRequestHandler, HTTPServer

PORT = 8080


class DemoHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-Type", "text/plain; charset=utf-8")
        self.end_headers()
        self.wfile.write(b"peachycloudsecurity python build lab\n")

    def log_message(self, fmt, *args):
        # suppress per-request console lines so lab output stays clean
        return


if __name__ == "__main__":
    HTTPServer(("0.0.0.0", PORT), DemoHandler).serve_forever()
EOF

Single-stage image (full base)

Everything runs on the full Python image, which is simple to reason about but larger on disk.

cat > Dockerfile.single <<'EOF'
FROM python:3.12-bookworm
WORKDIR /app
COPY peachycloudsecurity_httpd.py .
ENV PYTHONUNBUFFERED=1
EXPOSE 8080
USER nobody
CMD ["python", "peachycloudsecurity_httpd.py"]
EOF
docker build -f Dockerfile.single -t peachycloudsecurity-py:single .

Multi-stage image (slim final)

The first stage copies the app. The final stage uses python:3.12-slim-bookworm which has the same Python runtime but without extra packages that came with the full base.

cat > Dockerfile.multi <<'EOF'
FROM python:3.12-bookworm AS bundle
WORKDIR /app
COPY peachycloudsecurity_httpd.py .

FROM python:3.12-slim-bookworm
WORKDIR /app
COPY --from=bundle /app/peachycloudsecurity_httpd.py .
ENV PYTHONUNBUFFERED=1
EXPOSE 8080
USER nobody
CMD ["python", "peachycloudsecurity_httpd.py"]
EOF
docker build -f Dockerfile.multi -t peachycloudsecurity-py:multi .

Compare size and quick run

docker images peachycloudsecurity-py
docker run --rm -d -p 18080:8080 --name pcs-single peachycloudsecurity-py:single
docker stop pcs-single
docker run --rm -d -p 18081:8080 --name pcs-multi peachycloudsecurity-py:multi
docker stop pcs-multi

Clean up

cd ~
docker rmi peachycloudsecurity-py:single peachycloudsecurity-py:multi 2>/dev/null || true
rm -rf ~/peachycloudsecurity-build-lab

Summary

The slim final image should be noticeably smaller than the full base for the same script. Fewer packages in the final image means fewer things to patch and a smaller attack surface.