Skip to content

Docker

This page covers practical container deployment patterns.

Probe-ready app example

from __future__ import annotations

import time

STARTED_AT = time.time()


async def app(scope, receive, send):
    """Serve liveness and readiness endpoints."""
    if scope["type"] != "http":
        return

    path = scope.get("path", "/")
    if path == "/healthz":
        status = 200
        body = b"ok"
    elif path == "/readyz":
        status = 200
        body = f"ready uptime={time.time() - STARTED_AT:.2f}".encode()
    else:
        status = 404
        body = b"not found"

    await send(
        {
            "type": "http.response.start",
            "status": status,
            "headers": [
                (b"content-type", b"text/plain; charset=utf-8"),
                (b"content-length", str(len(body)).encode("ascii")),
            ],
        }
    )
    await send({"type": "http.response.body", "body": body})

Minimal Dockerfile

FROM python:3.13-slim

WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir palfrey

EXPOSE 8000
CMD ["palfrey", "docs_src.operations.docker_healthcheck:app", "--host", "0.0.0.0", "--port", "8000"]

Use multi-stage builds when compiling optional components or installing build-only dependencies.

Runtime flags often used in containers

  • --host 0.0.0.0
  • --port 8000
  • --workers N (when resource limits justify)
  • proxy flags when behind ingress

Container health checks

Configure orchestrator probes for:

  • liveness
  • readiness

Example endpoint choices:

  • /healthz
  • /readyz

Operational recommendations

  • keep base images pinned
  • keep images minimal
  • avoid embedding secrets in image layers
  • keep startup command explicit and reviewed

Non-technical summary

Containers package runtime behavior into repeatable units. Repeatability is what makes staging and production comparable.