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.singleandDockerfile.multi, then comparedocker imagesoutput.
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.
- Next step: Runtime Risk, starting with Theory: Host boundary.