Upgrade a cluster

Select an upgrade strategy, create a recovery point, request a version change, and verify the rollout.

Updated 9 August 2026 · 4 min read

On this page

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

StrategyUse it whenFailure boundary
RollingUpdateYou want the default, lower-capacity rolloutThe operator updates one Pod at a time, coordinates leader step-down, and holds a failed rollout for an explicit retry
BlueGreenYou need a parallel Green revision, validation hook, or manual promotionThe 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, Degraded is not true, and all declared voter replicas are Ready.
  • status.currentVersion matches the current spec.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:

configure

Require a pre-upgrade snapshot

spec:
  upgrade:
    preUpgradeSnapshot: true

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

apply

Switch to rolling update

kubectl -n <namespace> patch openbaocluster <name> --type merge -p '{
  "spec": {
    "upgrade": {
      "strategy": "RollingUpdate"
    }
  }
}'
verify

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:

apply

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:

apply

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:

apply

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

verify

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

Finish only when status.currentVersion equals spec.version, status.phase=Running, Available=True, all declared replicas are Ready, and Raft membership matches the intended topology.

Search the handbook

Try “install”, “threat model”, or “compatibility”.