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>
92 lines
3.6 KiB
Markdown
92 lines
3.6 KiB
Markdown
# 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.
|
|
|
|
```dockerfile
|
|
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.
|
|
|
|
```dockerfile
|
|
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.
|
|
|
|
```dockerfile
|
|
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](secrets.md)**). Add them to `.dockerignore` so a blanket `COPY . .`
|
|
can't sweep them in.
|
|
|
|
## Faster builds with uv (optional)
|
|
|
|
[uv](https://docs.astral.sh/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:
|
|
|
|
```dockerfile
|
|
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](compose.md)** for the `compose.yaml`, and
|
|
**[Secrets](secrets.md)** for credentials.
|