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.
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.