date-website

Kubernetes Deployment Notes (production)

Purpose

Production runs on a Kubernetes cluster (k3s) managed with GitOps: Argo CD watches a private operator repository and applies everything — chart, per-site values, secrets wiring, ingress, blue-green standbys — from git. Nothing is deployed by hand against the cluster.

This guide describes the deployment flow for developers working on date-website. It intentionally does not include cluster addresses, access paths, or secret locations — those live in the private operator repository and its docs. If you are on the ops team, the operator repository is the authoritative source; keep this file in sync with it when the flow changes.

Use this together with:

Environment model

Image pipeline

Trigger Image tags pushed
push to main :qa, :<commit-sha>
SemVer tag vX.Y.Z :vX.Y.Z, :vX.Y, :vX, :prod, :latest
manual promote_production :prod, :latest from a chosen existing tag

Notes:

The Helm chart

The chart lives in charts/date-website/ and is published as an OCI chart to GHCR by helm_chart.yaml whenever chart files change on main. Bump charts/date-website/Chart.yaml version on any template or values change; deployments pin the immutable chart version.

The chart deploys:

The web deployment runs migrateOnStartup in the production values. If the web replica count is ever raised above 1, move migrations out of startup into the migration Job so two pods cannot race.

How production actually runs (summary)

Deploying a release (the flow)

  1. A SemVer tag is cut (or promote_production is run) — the image is now available as prod/latest.
  2. In the operator repository, the site’s values file pins the image tag (image.tag). A release that includes database migrations carries that pin together with its migrations.
  3. Commit + push to the operator repository. Argo CD detects the change and syncs the release.
  4. Verify: site responds over HTTPS, /healthz/ and /readyz/ are green.

The operator repository holds:

Blue-green deploys (zero-downtime)

Every site has a standby release (same chart, fullnameOverride, shares the site’s database and secrets, no ingress) that is scaled to zero between deploys. A deploy:

  1. dumps the site’s database first (the rollback mechanism)
  2. sets the new image tag on the standby → Argo syncs it → the standby runs migrations on startup while the live site keeps serving
  3. smoke-tests the standby, then flips the ingress backend service names to the standby (in-place, no traffic gap)
  4. soaks, keeping the old stack as the rollback target, then scales the old stack to zero

Database migration rule (important): the standby shares the site’s database, so a destructive migration breaks the live site the moment the standby migrates — not at cutover. Therefore:

Secrets

Backups

Operational notes