Full in-cluster CD is blocked on headless OpenBao auth (Zitadel machine identity), so the clickable deploy-staging workflow + its runner would be dead config. Drop it; document the manual operator deploy (same secure OpenBao-config path) until the auth flow lands.
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-release -- \
--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-release -- \
--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:<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).