From 0e33c66fe7c41717b93e6fb133727e2bdfd04cbf Mon Sep 17 00:00:00 2001 From: Alexandru Macocian Date: Sun, 3 May 2026 20:22:41 +0200 Subject: [PATCH] Document docker-compose..yml fallback for list-replacement deltas --- docs/strategy.md | 64 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/docs/strategy.md b/docs/strategy.md index 8df1919..cb39fd8 100644 --- a/docs/strategy.md +++ b/docs/strategy.md @@ -46,38 +46,64 @@ Some stacks run on **multiple hosts** with the same image but slightly different ``` Charlie// -├── docker-compose.yml # the "what" — same on every host +├── docker-compose.yml # the "what" — default, used by hosts without an override +├── docker-compose..yml # full per-host compose (when the delta is structural) ├── envs/ │ ├── morgott.env # per-host env (Ansible host_vars equivalent) │ ├── melina.env │ ├── mohg.env │ └── miquella.env -├── overrides/ # only when env can't express it (volumes, services) -│ └── miquella.yml # Kustomize overlay equivalent — usually absent -├── deploy.sh # picks env + override based on `hostname -s` +├── overrides/ # additive overlay deltas (when env can't express it) +│ └── .yml +├── deploy.sh # picks env + compose file based on `hostname -s` └── README.md ``` -### Rules +### Resolution order in `deploy.sh` (per host) -- `docker-compose.yml` is **canonical** and works on every host as long as the right env file is loaded. Use `${VAR:-default}` liberally. -- `envs/.env` is tracked in git (no secrets). Secrets-bearing values come from a separate gitignored `.env` (host-local) merged in at deploy time, OR from runtime secret sourcing (vaultwarden, deferred). -- `overrides/.yml` only exists when env vars genuinely can't bridge the difference (e.g. extra volume bind, service add/remove, network change). Aim for zero override files; one or two is acceptable. -- `deploy.sh` is the host-side entrypoint. Always: - ```bash - HOST=$(hostname -s) - args=(--env-file "envs/$HOST.env" -f docker-compose.yml) +1. If `docker-compose..yml` exists → use **only** that (full per-host compose). +2. Else `docker-compose.yml` + (if present) `overrides/.yml` layered on top. +3. If `envs/.env` exists → loaded with `--env-file` in either case. + +Hostname is lowercased (`hostname -s | tr '[:upper:]' '[:lower:]'`). + +### When to use which + +| Delta type | Use | +|---|---| +| Different scalar value (port, env var, URL) | `envs/.env` | +| Add an extra service or scalar field | `overrides/.yml` (compose merges additively) | +| **Replace** a list (volumes, command, networks) | `docker-compose..yml` (full file) | +| Different image | `docker-compose..yml` | + +Compose's `!override` and `!reset` YAML tags exist for list-replacement, but support is uneven across compose versions (notably broken on Synology DSM's bundled compose). Prefer the full-file approach when replacing lists. + +### Canonical `deploy.sh` + +```bash +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")" +HOST=$(hostname -s | tr '[:upper:]' '[:lower:]') + +if [ -f "docker-compose.$HOST.yml" ]; then + args=(-f "docker-compose.$HOST.yml") +else + args=(-f docker-compose.yml) [ -f "overrides/$HOST.yml" ] && args+=(-f "overrides/$HOST.yml") - sudo docker compose "${args[@]}" "$@" # forward `up -d` / `pull` / `down` / etc. - ``` +fi +[ -f "envs/$HOST.env" ] && args=(--env-file "envs/$HOST.env" "${args[@]}") + +exec sudo docker compose "${args[@]}" "$@" +``` ### Mental model -- "What" = `docker-compose.yml` -- "Where" = the host running `./deploy.sh` (no inventory file needed; the host knows its own name) -- Per-host vars = `envs/.env` (Ansible `host_vars`) -- Per-host structural deltas = `overrides/.yml` (Kustomize overlay) -- Group defaults = compose env-var defaults (`${VAR:-default}`) +- "What" = `docker-compose.yml` (or per-host file). +- "Where" = the host running `./deploy.sh` (no inventory file; the host knows its own name). +- Per-host vars = `envs/.env`. +- Per-host structural deltas = `overrides/.yml` for additive, `docker-compose..yml` for replacement. +- Group defaults = compose env-var defaults (`${VAR:-default}`). ### Once runners exist (Phase 2)