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

74 lines
2.9 KiB
Markdown

# 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)
```sh
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):
```sh
# 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:
```sh
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).