diff --git a/docs/deploy.md b/docs/deploy.md index d3122d2..5399063 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -14,7 +14,7 @@ - service key is always **`svc`** - named volumes use **bare names** (`cache`, not `myapp_cache`) - - host paths come from **`${LOGS_DIR}` / `${CONFIG_DIR}` / `${MOUNTS_DIR}`** + - host paths come from **`${LOGS_DIR}` / `${CONFIG_DIR}`** Naming things after your repo used to cause **container-name collisions** at fleet scale — two repos shipping the same name clashed. The generic compose @@ -79,6 +79,45 @@ CMD ["python", "-m", "yourapp"] 3. `--system` installs into the image's Python (no venv needed — the container *is* the isolation); reads `pyproject.toml`, no `uv.lock` required. +### 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. `COPY `: +`` is relative to the build context (your repo), `` is a path in the +image. + +=== "A single file" + + ```dockerfile + COPY ./config.toml /app/config.toml # (1)! + ``` + + 1. One file into a specific path. The app reads it at `/app/config.toml`. + +=== "A directory" + + ```dockerfile + COPY ./assets /app/assets # (1)! + ``` + + 1. A whole tree. Trailing paths are dirs — `/app/assets/` mirrors `./assets/`. + +=== "Deps first (layer caching)" + + ```dockerfile + COPY requirements.txt . # (1)! + RUN pip install --no-cache-dir -r requirements.txt + COPY . . # (2)! + ``` + + 1. Copy just the deps file first, install, **then** copy the code. + 2. See [layer caching](#layer-caching) — this ordering is why. + +!!! 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)). + Add them to `.dockerignore` so a blanket `COPY . .` can't sweep them in. + ## Your `compose.yaml` Copy this verbatim. It names nothing repo-specific — the deploy layer fills in @@ -95,7 +134,6 @@ services: volumes: - ${LOGS_DIR:-./logs}:/app/logs # (4)! - ${CONFIG_DIR:-./config}:/app/config # (5)! - - ${MOUNTS_DIR:-./mounts}:/app/mounts - cache:/app/cache # (6)! volumes: @@ -112,16 +150,21 @@ volumes: what recovers a crashed container. 4. Logs → host, path **injected** by the deploy layer. The `:-./logs` default lets you `docker compose up` locally with nothing set and still work. -5. Config → host, likewise injected. Same pattern for `${MOUNTS_DIR}`. +5. Config → host, likewise injected. 6. Named volume with a **bare name** — ephemeral, auto-namespaced per service at deploy time so it can't collide. 7. Declare bare (`cache`, not `myapp_cache`). Deploy auto-prefixes it. +!!! tip "Logs and config are ours; the rest is yours" + **We handle `logs` and `config`** — the two `${...}` host mounts above are + injected and managed at deploy time. **Everything else is yours:** anything + your service needs to persist (caches, profiles, scratch) goes in a **named + volume**, which Docker owns — no host paths for you to manage. + !!! tip "The `${VAR:-./default}` pattern" - Every host path uses a variable with a local fallback. Locally, `docker compose - up` needs nothing set — it uses `./logs`, `./config`, `./mounts`. On the fleet, - the deploy layer sets the real values (below), so the same file works both - places. + Both host paths use a variable with a local fallback. Locally, `docker compose + up` needs nothing set — it uses `./logs` and `./config`. On the fleet, the + deploy layer sets the real values (below), so the same file works both places. ## How deploy fills it in @@ -132,7 +175,6 @@ are injected — not baked into your file. You can rely on these being present: COMPOSE_PROJECT_NAME=- LOGS_DIR=/srv/logs// CONFIG_DIR=/srv/config// -MOUNTS_DIR=/srv/mounts// ``` Which makes ownership obvious and collisions impossible: @@ -150,9 +192,9 @@ Which makes ownership obvious and collisions impossible: - **``** — the git repo name, lowercased, by default. Overridable at deploy time. -Host paths live under `/srv////` (config, logs, mounts), all -owned by the `services` user (uid/gid **1337**). You never write these paths in your -compose — you read the injected `${...}` variables. +Host paths live under `/srv////` (config, logs), all owned by +the `services` user (uid/gid **1337**). You never write these paths in your compose — +you read the injected `${...}` variables. ## Onboarding a service @@ -227,7 +269,7 @@ services: - service key `svc` — **no `container_name`**, no repo-specific names - `user: "1337:1337"` — the shared `services` account - `restart: unless-stopped` -- host paths via `${LOGS_DIR}` / `${CONFIG_DIR}` / `${MOUNTS_DIR}` — never hardcoded +- host paths via `${LOGS_DIR}` / `${CONFIG_DIR}` — never hardcoded - named volumes with **bare names** (`cache`, not `myapp_cache`) - for browser/subprocess workloads: `init: true`, `shm_size`, `mem_limit` diff --git a/docs/environments.md b/docs/environments.md index 0f4b391..c989b08 100644 --- a/docs/environments.md +++ b/docs/environments.md @@ -68,8 +68,8 @@ happens, depending on where the project runs: ``` This is how things run in production — see the [Deploy guide](deploy.md) for the - full container standard (uid 1337, mounts, layer caching, and the uv image - setup). + full container standard (uid 1337, the compose convention, layer caching, and the + uv image setup). !!! tip "Which one?" **Local `.venv`** for quick iteration, **Makefile** when you want repeatable diff --git a/docs/index.md b/docs/index.md index e361996..611a86d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -70,7 +70,7 @@ out of it; examples use placeholders like ``, ``, and --- - How to get a project running on **rethink-net** — containers, paths and - mounts, permissions, and secrets. + How to get a project running on **rethink-net** — the compose convention, + the one-command deploy, and secrets.