Use RollingUpdate unless you need parallel validation or a manual traffic cutover. Both strategies require a healthy
cluster, a supported target version, and a working upgrade identity.
Choose the strategy
| Strategy | Use it when | Failure boundary |
|---|---|---|
RollingUpdate | You want the default, lower-capacity rollout | The operator updates one Pod at a time, coordinates leader step-down, and holds a failed rollout for an explicit retry |
BlueGreen | You need a parallel Green revision, validation hook, or manual promotion | The operator joins Green as non-voters, promotes it, cuts over, and can abort or roll back according to phase |
Check the compatibility matrix and the upstream release notes before choosing the target.
Prepare the rollout
Preflight
Available=True,Degradedis not true, and all declared voter replicas are Ready.status.currentVersionmatches the currentspec.version.- No backup, restore, resize, restart, upgrade, Green revision, or break-glass recovery is active.
- A recent snapshot exists and its restore path has been rehearsed.
- The upgrade JWT role has the health, step-down, and Raft capabilities required by the selected strategy.
- The target version and any explicit image are allowed by the compatibility and image-verification policies.
Enable a mandatory recovery point for the next change:
Require a pre-upgrade snapshot
spec:
upgrade:
preUpgradeSnapshot: trueThis requires a valid spec.backup. The operator acquires an operation lock so an upgrade, backup, and restore do not
perform conflicting long-running work.
Change strategies on an existing cluster
Change only the strategy, then wait for the operator to accept it. Do not combine the strategy transition with a version, image, replica, storage, or restart change.
Switch to rolling update
kubectl -n <namespace> patch openbaocluster <name> --type merge -p '{
"spec": {
"upgrade": {
"strategy": "RollingUpdate"
}
}
}'Wait for strategy acceptance
kubectl -n <namespace> get openbaocluster <name> \
-o jsonpath='{.status.acceptedUpgradeStrategy}{"\n"}'Before switching to BlueGreen, configure spec.upgrade.jwtAuthRole or use the default
openbao-operator-upgrade role created by self-init OIDC bootstrap. A role created for a rolling-only cluster might
need its policy expanded before the switch; self-init requests are not replayed later.
Request the version change
After the strategy is accepted, change spec.version in a separate request:
Request the target version
kubectl -n <namespace> patch openbaocluster <name> --type merge -p '{
"spec": {
"version": "<target-version>"
}
}'The version must be semantic version syntax. The operator blocks downgrades below status.currentVersion. If you set
spec.image, keep a semantic tag aligned with spec.version; digest-pinned images still use spec.version as the
upgrade intent.
Control a blue-green promotion
Set spec.upgrade.blueGreen.autoPromote: false before the upgrade begins to hold a healthy Green revision in
Syncing. Approve it by changing the one-shot request value:
Approve a held promotion
kubectl -n <namespace> patch openbaocluster <name> --type merge -p "{
\"spec\": {
\"upgrade\": {
\"requests\": {
\"promote\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
}
}
}
}"autoPromote is snapshotted when an upgrade starts. Changing it during an in-flight upgrade affects only the next
upgrade.
When a BlueGreen validation hook is configured, the operator verifies its image through
spec.operatorImageVerification before creating the Job and pins a successful result by digest. Block stops the
upgrade when verification fails; Warn keeps the original reference and is not permitted by the Hardened profile.
The Job disables ServiceAccount token automounting, runs non-root with a read-only root filesystem, drops all
capabilities, uses RuntimeDefault seccomp, inherits spec.imagePullSecrets, and receives bounded resources.
Recover a held rolling failure
Fix the cause recorded in status.upgrade.failure, then change spec.upgrade.requests.retry:
Retry a rolling upgrade
kubectl -n <namespace> patch openbaocluster <name> --type merge -p "{
\"spec\": {
\"upgrade\": {
\"requests\": {
\"retry\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
}
}
}
}"Each request is edge-triggered: use a new non-empty value. For blue-green rollback repair failures, use Recover a failed rollback instead of retrying blindly.
A blue-green upgrade can only roll back before the Cleanup phase, because Cleanup removes Blue peers from Raft.
From Cleanup onward, the operator refuses spec.upgrade.requests.rollback and automatic rollback with a
RollbackRefused warning event. It retries the current phase, and applies any spec change made during that time
after the current upgrade completes. The operator records Green’s target image, version, and replica count and Blue’s
original replica count in status.blueGreen. Changes to spec.replicas do not change the active upgrade’s cleanup
checks or rollback quorum. When resuming an older operation without these fields, the operator recovers its image and
replica counts from the existing StatefulSets; it stops if those inputs cannot be recovered.
Verify the result
Watch upgrade state
kubectl -n <namespace> get openbaocluster <name> -w
kubectl -n <namespace> get pods -l openbao.org/cluster=<name> -o wide
kubectl -n <namespace> get events --sort-by=.lastTimestampFinish only when status.currentVersion equals spec.version, status.phase=Running, Available=True, all declared
replicas are Ready, and Raft membership matches the intended topology.