deploy: re-add mounts as optional (commented) third storage tier

The deploy scripts already handle mounts (dir creation + MOUNTS_DIR
injection); only the docs had dropped it. Re-add it as opt-in so scripts
and docs agree:

- compose: a commented '# - ${MOUNTS_DIR:-./mounts}:/app/data' line — the
  dir is auto-created and MOUNTS_DIR injected, but the mount line stays
  dev-opted (container-side path is app-specific, can't be auto-mounted)
- reframe the storage tip as 'Three tiers of storage': logs+config (ours),
  mounts (optional, injected + auto-created, mount line opt-in), named
  volumes (yours)
- re-add MOUNTS_DIR to the injected env vars (noted opt-in) and mention it
  in the local-fallback tip, paths line, and checklist as optional

Verified in-browser; mkdocs build --strict clean.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
2026-07-01 01:39:52 -04:00
parent 8c56fd98a8
commit 08ad37eddc
+31 -19
View File
@@ -134,10 +134,11 @@ services:
volumes: volumes:
- ${LOGS_DIR:-./logs}:/app/logs # (4)! - ${LOGS_DIR:-./logs}:/app/logs # (4)!
- ${CONFIG_DIR:-./config}:/app/config # (5)! - ${CONFIG_DIR:-./config}:/app/config # (5)!
- cache:/app/cache # (6)! # - ${MOUNTS_DIR:-./mounts}:/app/data # (6)!
- cache:/app/cache # (7)!
volumes: volumes:
cache: # (7)! cache: # (8)!
``` ```
1. The service key is always **`svc`** — never a repo-specific name, never a 1. The service key is always **`svc`** — never a repo-specific name, never a
@@ -148,23 +149,32 @@ volumes:
line that stays; it's not repo-specific. line that stays; it's not repo-specific.
3. **Required.** The host-side service is oneshot; Docker's own restart policy is 3. **Required.** The host-side service is oneshot; Docker's own restart policy is
what recovers a crashed container. what recovers a crashed container.
4. Logs → host, path **injected** by the deploy layer. The `:-./logs` default lets 4. Logs → host (**output**), path **injected** by the deploy layer. The `:-./logs`
you `docker compose up` locally with nothing set and still work. default lets you `docker compose up` locally with nothing set and still work.
5. Config → host, likewise injected. 5. Config → host (**input you edit**), likewise injected.
6. Named volume with a **bare name** — ephemeral, auto-namespaced per service at 6. **Optional, commented by default.** A host dir for arbitrary read/write data.
The deploy layer injects `MOUNTS_DIR` and auto-creates the dir — but you
**uncomment** the line and pick the container path (`/app/data` here), since
that's app-specific and can't be auto-mounted.
7. Named volume with a **bare name** — ephemeral, auto-namespaced per service at
deploy time so it can't collide. deploy time so it can't collide.
7. Declare bare (`cache`, not `myapp_cache`). Deploy auto-prefixes it. 8. Declare bare (`cache`, not `myapp_cache`). Deploy auto-prefixes it.
!!! tip "Logs and config are ours; the rest is yours" !!! tip "Three tiers of storage"
**We handle `logs` and `config`** — the two `${...}` host mounts above are - **`logs`** (output) and **`config`** (input you edit) — **we handle these**:
injected and managed at deploy time. **Everything else is yours:** anything injected and managed at deploy time.
your service needs to persist (caches, profiles, scratch) goes in a **named - **`mounts`** (optional) — a host dir for arbitrary read/write data. The deploy
volume**, which Docker owns — no host paths for you to manage. layer **injects `MOUNTS_DIR` and auto-creates the dir**, but the mount line is
**opt-in**: uncomment it and choose the container path yourself (it's
app-specific, so it can't be auto-mounted).
- **Named volumes** (`cache`, …) — **yours**: anything else your service
persists. Docker owns them, no host paths to manage.
!!! tip "The `${VAR:-./default}` pattern" !!! tip "The `${VAR:-./default}` pattern"
Both host paths use a variable with a local fallback. Locally, `docker compose Host paths use a variable with a local fallback. Locally, `docker compose up`
up` needs nothing set — it uses `./logs` and `./config`. On the fleet, the needs nothing set — it uses `./logs`, `./config` (and `./mounts` if you enable
deploy layer sets the real values (below), so the same file works both places. it). On the fleet, the deploy layer sets the real values (below), so the same
file works both places.
## How deploy fills it in ## How deploy fills it in
@@ -175,6 +185,7 @@ are injected — not baked into your file. You can rely on these being present:
COMPOSE_PROJECT_NAME=<workspace>-<name> COMPOSE_PROJECT_NAME=<workspace>-<name>
LOGS_DIR=/srv/logs/<workspace>/<name> LOGS_DIR=/srv/logs/<workspace>/<name>
CONFIG_DIR=/srv/config/<workspace>/<name> CONFIG_DIR=/srv/config/<workspace>/<name>
MOUNTS_DIR=/srv/mounts/<workspace>/<name> # dir auto-created; mount line opt-in
``` ```
Which makes ownership obvious and collisions impossible: Which makes ownership obvious and collisions impossible:
@@ -192,9 +203,9 @@ Which makes ownership obvious and collisions impossible:
- **`<name>`** — the git repo name, lowercased, by default. Overridable at - **`<name>`** — the git repo name, lowercased, by default. Overridable at
deploy time. deploy time.
Host paths live under `/srv/<kind>/<workspace>/<name>/` (config, logs), all owned by Host paths live under `/srv/<kind>/<workspace>/<name>/` (config, logs, and mounts if
the `services` user (uid/gid **1337**). You never write these paths in your compose — enabled), all owned by the `services` user (uid/gid **1337**). You never write these
you read the injected `${...}` variables. paths in your compose — you read the injected `${...}` variables.
## Onboarding a service ## Onboarding a service
@@ -269,7 +280,8 @@ services:
- service key `svc` — **no `container_name`**, no repo-specific names - service key `svc` — **no `container_name`**, no repo-specific names
- `user: "1337:1337"` — the shared `services` account - `user: "1337:1337"` — the shared `services` account
- `restart: unless-stopped` - `restart: unless-stopped`
- host paths via `${LOGS_DIR}` / `${CONFIG_DIR}` — never hardcoded - host paths via `${LOGS_DIR}` / `${CONFIG_DIR}` (and optional `${MOUNTS_DIR}`) —
never hardcoded
- named volumes with **bare names** (`cache`, not `myapp_cache`) - named volumes with **bare names** (`cache`, not `myapp_cache`)
- for browser/subprocess workloads: `init: true`, `shm_size`, `mem_limit` - for browser/subprocess workloads: `init: true`, `shm_size`, `mem_limit`