Files
harmony/fleet/deployment-process.md
2026-06-01 11:35:15 -04:00

2.9 KiB

Fleet operator — release & deploy

How the operator ships: build + publish a versioned image and helm chart, then harmony apply (a plain helm upgrade --install of that published chart). No Argo, no GitOps controller — Harmony owns the loop (ADR-012-2). CD is roll-forward only: to back out a bad release, deploy a previous good version.

1. Cut a release (automated on tag)

git tag harmony-fleet-operator-v0.0.2 && git push --tags

The harmony-fleet-operator workflow builds the image and the hydrated helm chart and pushes both to hub.nationtech.io at 0.0.2. No human touches a Dockerfile, chart, or registry.

Laptop fallback (does exactly what the workflow's job does):

# docker + helm must be logged in to hub.nationtech.io first.
cargo run --release -p harmony-fleet-deploy --bin harmony-fleet-publish -- \
  --from-tag harmony-fleet-operator-v0.0.2

# build + package only, no push (local k3d smoke-test):
cargo run -p harmony-fleet-deploy --bin harmony-fleet-publish -- \
  --from-tag harmony-fleet-operator-v0.0.2 --no-push

2. Deploy a published version to staging (manual, for now)

Push to staging is manual until headless OpenBao auth (Zitadel machine identity) lands; secrets still come from shared OpenBao config. Point at your staging kube context and OpenBao, then run the operator deploy:

export OPENBAO_URL=<your OpenBao URL>
export OPENBAO_TOKEN=<scoped read token for secret/<ns>/*>
harmony-fleet-deploy --filter FleetOperatorScore \
  --from-tag <release-tag> --namespace fleet-staging --yes

It installs the published oci://hub.nationtech.io/harmony/harmony-fleet-operator-chart:<version> chart; the version is parsed from the tag in Rust (the tag is the only source of truth). Same command bootstraps and upgrades; re-running the same tag is a no-op. Auth is Zitadel-SSO-only: the operator gets its zitadel-jwt operator_credentials_toml from FleetDeploySecrets in OpenBao (no user/pass on the published-chart path). For manual deploy, store that config without a kubeconfig field so your own kube context is used.

3. Roll forward

Re-run with a newer (or previous-good) tag. helm upgrade --install applies it and fails loudly if convergence fails — no automatic rollback. Fix the spec, bump, re-run.

Automated vs. manual

Step Where
Build + push image + chart on tag CI (release job, on tag)
Push to staging + roll forward Manual (operator runs the deploy)

Future: in-cluster CD (blocked on headless OpenBao auth)

Once harmony_config can authenticate to OpenBao headlessly (Zitadel machine identity), these exports become a deploy-staging workflow on an in-cluster, permissionless Gitea runner that pulls a fleet-deployer kubeconfig + operator credentials from OpenBao at job time (provisioned via a TenantScore with one extra egress CIDR to the OpenBao/Zitadel ingress). Production-gated promotion is a later step (ADR-012-2).