Files
project-charlie/docs/strategy.md
T

3.4 KiB

Strategy

Pattern

Pull-based GitOps via Gitea Actions runners on the owner host.

dev box ── git push ──► Gitea (Charlie/<stack>) ── webhook ──► runner on owner host
                                                                   │
                                                                   ▼
                                          git -C /mnt/nas/stacks/<stack> pull --ff-only
                                          docker compose pull && docker compose up -d

The git working tree at /mnt/nas/stacks/<stack>/ is the deployment. Runtime state lives separately under /mnt/nas/data/<stack>/ (see layout.md).

Rules

  • One owner host per stack. Only that host's runner ever touches the working tree.
  • No hand-edits on the host once a stack is repo-managed. git pull --ff-only will refuse to clobber.
  • Runtime state never enters git. Compose files bind into /mnt/nas/data/<stack>/, not into the working tree.
  • .env ignored, .env.example tracked. Secrets stay out.
  • Image tags pinned. No :latest.
  • Cross-host self-update: the runner that deploys Charlie/gitea lives on morgott; the runner that updates morgott's runner lives on melina. A runner never redeploys itself mid-job.

Repo types

Three. (We dropped upstream+overrides — see Why no upstream cloning.)

init

Stack is currently just a NAS folder. git init in the new /mnt/nas/stacks/<stack>/, push to Charlie/<name>. Recipe: migration.md.

rewrite

Code we author, currently a clone of a github.com repo. Move to /mnt/nas/stacks/<stack>/, git remote set-url origin to Charlie. Recipe: migration.md.

mirror

Pull-mirror of an upstream we don't customise (or want as offline backup). Configured via Gitea's pull-mirror feature. Read-only, never deployed from. Naming: Charlie/<name>-mirror.

Why no upstream cloning

Previously we considered cloning upstream's source on the host and layering a docker-compose.override.yml. Dropped because:

  • For every "upstream image" stack (invidious, searxng, victoriametrics, mealie, paperless-ngx), we only ever ran the published image. Their source tree is dead weight on the host.
  • Override-on-template means the upstream's compose can change under us silently.
  • Two-remote / rebase / force-push dance was the price for dubious value.

Instead: our docker-compose.yml references the published image directly. It is the only compose. Upstream's compose is a reference document we read in their mirror repo when we want to see what changed.

Image-update flow (Phase 3)

Diun watches registries; on a tag/digest change it POSTs to a Gitea webhook that triggers a redeploy workflow with force-pull: true on the owner host. Replaces watchtower.

Secrets

Open question. Candidate: vaultwarden as the source, with a runner-side fetch step that materialises .env per job. Decided when we design the runner stack.

Why not Portainer/Komodo/Dockge

  • Portainer Stacks-from-Git: works, but no submodule support, opinionated about working-tree location, adds a control plane on top of git.
  • Komodo: nice, also pull-based, also relocates working trees. Reconsider if we ever want a UI.
  • Dockge: file mgmt only, no git wiring.

The runner-driven pattern keeps us in plain git + docker compose and adds nothing the team doesn't already understand.