Files
cms-plugins/deploy/fleet-overlay/README.md
T
Oleks 8c119efff8 harden(deploy): apply safe fixes from review report-only items
- #3 Liveness probe targets full SSR DB-querying / route, coupling pod liveness to SQLite
- #4 Chart values-staging/production.yaml are dead config under Flux; drift trap
- #6 tsconfig includes gitignored emdash-env.d.ts that only the dev server generates
- #7 Dockerfile package-lock glob + npm install fallback can silently build an unlocked image
- #8 Dockerfile creates runtime user without pinning its GID
- #9 entrypoint.sh gates `emdash init` on data.db absence, skipping migrations on PVC reuse
- #10 pullPolicy: Always vs digest pinning
- #11 Dockerfile state symlinks contradict the STATE_DIR contract; Dockerfile does not set ENV STATE_DIR
- #12 astro is a production dependency, so npm prune --omit=dev keeps build-only tooling
- #14 Two ImageUpdateAutomations write back to the same anton-helm-workloads main branch
- #16 memoryCache provider is per-process; correctness depends implicitly on replicas:1
- #17 Root catch-all [slug].astro couples nav links to pages-collection rows + DB hit per unmatched path
- #18 Detail pages render a 200-style body under a 404 status and have no try/catch around getEmDash* calls
- #19 vite allowedHosts hardcodes ddev hostnames (dev-only; no prod impact)
2026-06-02 04:50:54 +03:00

4.0 KiB

Fleet overlay templates

The YAMLs under cms-plugins-staging/ and cms-plugins-production/ are the FluxCD manifests that drive each environment. They are not consumed from this repo — they live here as a versioned blueprint, intended to be copied into the workloads repo that Flux watches:

git.oleks.space/anton/helm-workloads
  ├─ cms-plugins-staging/        ← copy from deploy/fleet-overlay/cms-plugins-staging/
  ├─ cms-plugins-production/     ← copy from deploy/fleet-overlay/cms-plugins-production/
  └─ kustomization.yaml          ← add both directories to `resources:`

See ../../DEPLOYMENT.md for the full pipeline and the first-time setup checklist (deploy keys, sops secrets, Woodpecker secrets, DNS).

Shape

Each env directory contains five files, mirroring the emdash-kotkanagrilli layout in ~/projects/servers/fleet/apps/base/:

  • source.yamlGitRepository pointing at this repo on the matching branch (staging / production), restricted to /deploy/helm via the ignore rule so Flux only pulls the chart.
  • helmrelease.yamlHelmRelease consuming the chart from ./deploy/helm in that GitRepository. Pinned by digest (see image-automation.yaml).
  • image-automation.yamlImageRepository + ImagePolicy + ImageUpdateAutomation. Watches the floating staging / production tag in the Gitea OCI registry, resolves the current digest, and rewrites the digest setter in helmrelease.yaml (which is what actually makes helm upgrade see a change when CI retags the image).
  • secrets.yaml — the pod's env-var secret (cms-plugins-{staging,production}-secrets, in kotkan). The staging overlay's secrets.yaml additionally defines the shared SSH deploy key (cms-plugins-deploy-key, also in kotkan so the GitRepository secretRef resolves same-namespace); production references that same key by name and does NOT redefine it. Templates here are NOT encrypted — sops-encrypt them before pushing to anton-helm-workloads.
  • kustomization.yaml — bundles the above.

Why this lives in two repos

The chart (deploy/helm/) ships with the app — that way a chart change is reviewed and tagged alongside the code that depends on it. The HelmRelease references the chart as a path inside a GitRepository, not as an OCI artifact, so there's no "publish chart" step in CI.

The HelmRelease itself lives in the workloads repo because that repo is the source of truth for what runs on the kotkanagrilli.fi subdomain pool. Same convention as the existing kotkanagrilli/ (legacy WP) and hello-kotkan/ entries there.

Why two image automations share one branch

Both cms-plugins-staging and cms-plugins-production define an ImageUpdateAutomation that checks out, commits to, and pushes the same main branch of anton-helm-workloads on the same interval: 1m. This is intentional and safe:

  • Each automation is scoped to a disjoint update.path (./cms-plugins-staging vs ./cms-plugins-production), so they only ever rewrite the digest setter inside their own helmrelease.yaml. They never touch the same file.
  • strategy: Setters rewrites only the explicitly marked digest setter, not arbitrary YAML — there is no whole-file regeneration that could clobber a sibling's change.
  • The image-automation-controller serializes its git pushes and retries on a non-fast-forward rejection, so two automations landing commits on main in the same reconcile window resolve cleanly rather than racing.

This mirrors the per-env automations under ~/projects/servers/fleet/apps/base/ for emdash-kotkanagrilli-*. The only deviation (justified in image-automation.yaml) is that these reuse the read-side anton-helm-workloads GitRepository as the write-back sourceRef instead of a dedicated image-automation source, because these workloads live in that same repo.

Note for go-live: nothing here reconciles while the HelmReleases are suspend: true (Phase 0). These automations only begin writing back once the releases are deliberately resumed.