Files
handbook/docs/deploy/dockerfile.md
T
dsql f9e5e4f24d split Deploy into a hub + 3 sub-pages; inline comments over annotations
The Deploy page got long and the code annotations rendered inconsistently
(some as (n) numbers, some as clickable +, and a marker on a fully-commented
line made that line vanish). Fix both:

- Deploy is now a HUB (docs/deploy/index.md): the intro + collision rule +
  central-deploy note, then card links to three focused sub-pages. Deploy
  stays the single global-nav entry; sub-pages are not_in_nav, reached from
  the hub cards.
  - deploy/compose.md — compose convention, storage tiers, how deploy fills
    it in, subprocess/browser knobs, checklist
  - deploy/dockerfile.md — services-account image, COPY, layer caching, uv
  - deploy/secrets.md — keeping secrets out of the image
- Replace code annotations with INLINE COMMENTS on the compose/Dockerfile
  examples: everything visible at once, no + to click, and the commented
  MOUNTS_DIR line no longer disappears.
- Update inbound links (index card, standards, workflow, environments) to
  deploy/ and deploy/compose.md; nav Deploy -> deploy/index.md with
  not_in_nav for the sub-pages.

Verified in-browser: hub cards link correctly, sub-pages render with visible
inline comments (0 annotation markers), left nav shows only Deploy;
mkdocs build --strict clean (validates not_in_nav + all cross-links).

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-01 02:32:16 -04:00

3.6 KiB

Dockerfile & build

Every service runs containerized as the shared services account: uid/gid 1337, fixed fleet-wide. Build your image to be uid-agnostic so it runs cleanly as that account.

FROM python:3.12-slim
ENV HOME=/tmp                                  # services account has no home dir; $HOME must be writable

WORKDIR /app
RUN apt-get update \
    && apt-get install -y --no-install-recommends git \
    && rm -rf /var/lib/apt/lists/*             # include git ONLY if the container itself needs it

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt   # deps before code — see layer caching

COPY . .
RUN chmod -R a+rwX /app                         # writable by any uid — this is "uid-agnostic"
CMD ["python", "-m", "yourapp"]
  • HOME=/tmp — the services account has no home dir; anything writing to $HOME (caches, configs) needs a writable target.
  • git — include it only if the container itself needs it (e.g. you pip install from git, or the app shells out to git). The build and host always have git; this is about what's inside the image.
  • chmod -R a+rwX /app — makes the app tree writable by any uid, so it runs as 1337.

Layer caching

Copy the deps file and install before COPY . .. Docker caches layers in order, so deps only reinstall when the deps file changes — not on every code edit. Get this backwards and every one-line change triggers a full dependency reinstall.

COPY requirements.txt .                              # pip baseline
RUN pip install --no-cache-dir -r requirements.txt   # cached until deps change
COPY . .                                             # changes every build

Getting your files into the image

COPY . . grabs the whole repo, but be explicit about anything that needs its own place — assets, templates, a config the app reads at runtime. In COPY <src> <dest>, <src> is relative to the build context (your repo) and <dest> is a path in the image.

COPY ./config.toml /app/config.toml   # a single file into a specific path
COPY ./assets /app/assets             # a whole directory (tree mirrors ./assets/)

!!! warning "Don't COPY secrets into the image" Anything sensitive stays out of the image — no COPY ./secrets.env. Secrets live on the host and are injected read-only at runtime (see Secrets). Add them to .dockerignore so a blanket COPY . . can't sweep them in.

Faster builds with uv (optional)

uv is a drop-in for pip that reads the same pyproject.toml — no lockfile needed in the image. Swap the deps layer and add UV_COMPILE_BYTECODE so containers don't pay the first-import .pyc compile cost:

FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/   # pull the uv binary from its image
ENV HOME=/tmp
ENV UV_COMPILE_BYTECODE=1                                # compile bytecode at build, not first cold start

WORKDIR /app
COPY pyproject.toml .
RUN uv pip install --system .                            # --system: into the image's Python, no venv/lock
COPY . .
RUN chmod -R a+rwX /app
CMD ["python", "-m", "yourapp"]

Checklist

  • HOME=/tmp
  • chmod -R a+rwX /app (uid-agnostic; runs as the services account, 1337)
  • deps installed before the code copy (layer caching) — pip or uv pip install
  • git in the image if the container needs it
  • using uv? add ENV UV_COMPILE_BYTECODE=1

See Compose convention for the compose.yaml, and Secrets for credentials.