Upgrade from NVCF Self-Managed 0.6.1 to 0.6.2
The 0.6.2 patch refreshes OpenBao’s JWT plugin catalog before the 0.6.2 to 1.0.1 upgrade. It changes the OpenBao chart from 0.30.25 to 0.32.6 while retaining runtime 2.5.5-nv-1.3.1 and migrations 0.16.2.
An installation upgraded from 0.6.0 can still run 2.5.4-nv-1.3.0 in every
OpenBao server pod. OnDelete updates the StatefulSet template without
replacing pods. An unchanged template in the 0.6.2 diff does not mean those
pods are current. Do not restart them at 0.6.1: refresh the catalog with 0.6.2
first, then replace the stale members using this procedure.
This procedure supports three healthy voting members, a Shamir seal, the
standard /openbao/data volume layout, and one CPU architecture across every
cluster node. The refresh hook has no architecture selector, so a cluster with
mixed architectures is unsupported even if all OpenBao servers share one.
It preserves the StatefulSet, PVCs, credentials and Raft node IDs.
Use a separately tested site procedure for other layouts. Allow a maintenance
window for member restarts and leadership transfer. Clients can see transient
authentication failures while members restart. Never reload the plugin while
binaries differ, change to RollingUpdate, force-delete a pod, or delete
multiple members together.
Keep other operators and automation from changing this release or node
architecture during the procedure. Data PVCs must be retained, have no deletion
timestamp and have no garbage-collection owner references.
1. Record and check the source deployment
Every source Helm release must be deployed, every OpenBao member initialized and unsealed, and every Cassandra migration ledger clean. Complete the 0.6.0 to 0.6.1 checks if upgrading from 0.6.0. The checks below are required; Kubernetes Ready alone accepts sealed or uninitialized responses with these charts.
Use Bash, Python 3.9 or later, jq, curl, kubectl, Helm 3 and Helmfile 1.1.x.
Download the read-only validator.
It reads the captured files and never contacts or changes a cluster.
Run every block in the same Bash session. Supply the control-plane API base URL
without /v2/nvcf, the function’s NVIDIA Cloud Account (NCA) ID, function ID and
version ID, and its normal synchronous invocation URL and JSON request file.
The commands construct the administrative read URL with the account in its
path: /v2/nvcf/accounts/{ncaId}/functions/{functionId}/versions/{functionVersionId}.
This route accepts the admin JWT without an extra account header. The ordinary
/v2/nvcf/functions/... read route requires user scopes and rejects this JWT.
Provide an existing API key authorized to invoke that function in a private
header file containing one line: Authorization: Bearer <api-key>.
Set INVOCATION_AUTH_HEADER to that file’s absolute path. Keep the key out of
command arguments, shell history and logs. These probes must succeed before
maintenance; use a deterministic test function whose response you can verify.
Protect their outputs as application data.
The private kubeconfig contains only the selected context. The bundle’s Makefile accepts a kubeconfig but no context flag, so all syncs below use this copy. Record the existing function/deployment IDs, cluster ID, worker pod UID, container IDs and restart counts for comparison after the patch.
Capture health and test fresh authentication
These helpers use the chart-managed root token over stdin for OpenBao
administrative reads. Each call to fresh_auth runs two separate probes:
- Create a fresh service-account JWT, log in with the existing bootstrap role, sign a new NVCF JWT, and use it for the administrative function read. Signing exercises the JWT secrets plugin; a successful read proves the API accepts the newly signed JWT. A cached token cannot establish fresh signing works.
- Invoke the same function through its normal synchronous invocation URL using
the existing invocation-scoped API key from
INVOCATION_AUTH_HEADER. This checks invocation continuity; it does not prove fresh JWT signing works.
The nvcf-api-admin signing role grants admin:list_functions_details but not
invoke_function, so its JWT cannot authorize normal invocation. Keep the
existing role and scopes unchanged. Both probes must return HTTP 200 before
fresh-auth-passed.txt is written. The example uses the standard bootstrap
service account, role and audience. Stop if your deployment uses different
identities or cannot pass either probe.
The validator requires exactly the expected owned pods and container statuses, three matching healthy Raft voters, a single active member, Bound data PVCs, and matching source catalog/binary checksums. Both healthy sources are supported: all live servers already on 2.5.5, or all still on 2.5.4 despite a 2.5.5 template. After the patch, only pods whose live images, image IDs, plugin checksum or revision differ from the reviewed target need replacement.
Keep this original baseline when resuming a partially completed rotation. Do not overwrite it with mixed-version state or treat a post-refresh catalog mismatch on retained old pods as a new healthy source baseline.
2. Back up state
Save the source environment values and secrets securely, then take an OpenBao
Raft snapshot. Run these commands in Bash on the operator host, using the kcp
helper and $BACKUP_DIR from section 1. You need jq installed locally and
Kubernetes permissions to read the two Secrets, list the server pods, and
execute commands in the OpenBao containers. The bao CLI runs inside the
selected pod, so it does not need to be installed on your host.
The snapshot request must reach the active member because, with the bundled
OpenBao 2.5.5, a request through a standby’s localhost address fails with
incomplete snapshot. This example authenticates with the existing
chart-managed root token; a token granting read on
sys/storage/raft/snapshot is also sufficient for snapshot download. The token
is passed over stdin to keep it out of command arguments and shell history.
Do not enable shell tracing or print the credential files.
The standard chart uses a Shamir seal with one key share and a threshold of one, so recovery requires the single unseal key that matches the snapshot. Back up both chart-managed Secrets alongside it: the unseal key unlocks the restored state, while the root token authenticates the chart’s hooks and migrations. The root token cannot replace the unseal key. These exports contain usable credentials, so keep them in protected recovery storage and out of shared logs.
The following example runs after the required source health checks. It saves
the credentials and finds the active member, but does not establish whether
any expected members are missing. Complete the health checks in section 1
before upgrading. Each backup attempt uses a new private directory under
$BACKUP_DIR and a unique temporary file in the active pod, so retries do not
overwrite earlier backups.
Continue only after the block succeeds and the printed directory contains
openbao.snap and openbao-secrets.json. The commands check that the host copy
is nonempty before removing the pod copy. If snapshot creation or transfer
fails, stop and investigate; any pod-side temporary file is left in place.
The checks detect missing backup files and an absent or empty unseal key, but do not prove that the key matches the snapshot. Verify recovery in an isolated environment using your site’s restore procedure, and keep the backup in protected recovery storage. File permissions restrict access but do not encrypt these files. If your deployment uses a different seal or credential arrangement, follow its tested recovery procedure instead of assuming these two Secrets are sufficient.
Take a Cassandra snapshot on every member using your site’s backup procedure. Save the migration ledgers, database topology, and persistent-volume identities. Keep the source bundle and mirrored images with the recovery baseline so a restore does not depend on a later registry lookup. Verify your restore procedure before continuing. Do not put tokens, unseal material, or rendered secrets into shared logs.
3. Prepare the patch bundle
Obtain the nvcf-self-managed-stack 0.6.2 Helmfile bundle through your
NVCF artifact distribution channel. Confirm access to that exact version before
scheduling the upgrade. Compare its contents and source commit with the
stable 0.6.2 release
and its
artifact inventory.
The recorded source commit is 55803ad7cb647de45cf29415cfd3766225534617.
Verify the bundle checksum supplied by your distribution channel, then extract
it into $TARGET_CONTROL; keep $SOURCE_CONTROL intact for recovery.
Use the Image Mirroring process with the versions in that inventory. The current documentation manifest describes the 1.0.1 stack; do not substitute its artifact versions for this legacy patch.
Start with the target templates and carry your settings into these files:
Preserve registry and pull-secret settings, endpoints, certificates, storage classes and sizes, replica counts, scheduling constraints, Cassandra passwords, OpenBao configuration, and injector webhook scope. Keep enabled optional components and existing secret and cluster identities.
Keep the target global.yaml.gotmpl. It contains the runtime pinning fix, so
copying the source file over it would remove part of the patch. Mirror required
artifacts at the exact versions listed in the 0.6.2 inventory.
4. Review the rendered change
Render the OpenBao release into the private backup directory and inspect its diff before applying it:
Check these pins against the recorded source overrides:
The StatefulSet must keep OnDelete. The catalog refresh Job must run before
migrations. Review changes to RBAC, hooks, webhook configuration, probes, and
pod templates. Stop if the diff changes a volume, identity, runtime image, or
credential that you did not intend to change.
Record the reviewed target image
Convert the rendered resources to JSON without creating them. Extract the one server StatefulSet and verify the migration image. Do not use chart 0.32.6’s newer default runtime or migration versions.
Run a short image-check Job on the same architecture. It has no credentials or Raft volumes and only hashes the plugin. Its resolved image ID and plugin hash are the expected values for server replacements; this also checks image-pull access before changing the release. The pod inherits the reviewed image pull Secrets. Use unique generated names and retain the result with the backup.
5. Refresh the catalog, then replace stale members
Apply the selected release and prove the hooks ran
The refresh hook uses the target image and registers its checksum without reloading existing plugins. Migrations run afterward. The old active process can keep serving during this transition, but an old plugin process that restarts can fail against the new catalog. Do not leave the upgrade here or start another maintenance operation.
Start a bounded Job watch before sync. It records completion even when Helm deletes the successful refresh Job. The validator requires a fresh completed refresh and a different, completed migrations Job created after it. Missing watch evidence stops rotation; a successful Helm status alone is insufficient.
If sync fails, stop before deletion. The function stops its local watcher and
retains evidence in $SYNC_DIR. Do not skip hooks or repeatedly resync while
replacing servers.
Guard each replacement
The gate below checks the original PVC/node identities, every container and member, the frozen target specification, and the target catalog. An unchanged source pod is allowed temporarily; every replacement must have the target image ID, revision, version and plugin hash. A changed but incorrect pod is rejected. Each successful gate also reads the function with a newly signed JWT and invokes it separately with the existing API key.
If stale is empty, skip replacement and run the final checks. This handles
already-current sources and a rerun after convergence. Otherwise, discover
stale standbys and replace one at a time. The commands recheck the original
active UID and leadership before every deletion. A replacement failure or
unexpected leader change stops the loop before another deletion.
Inspect each replacement’s startup and previous pod’s saved logs. Require no plugin checksum errors, failed secret mounts, or forced termination. The 60-second deletion grace allows orderly shutdown; do not shorten it to force progress. Keep the two upgraded standbys healthy before the last replacement.
Transfer leadership by replacing the old active
When only the old active remains stale, both standbys have passed the target
checks. Gracefully terminate that old active and let an upgraded member take
over. A standalone bao operator step-down leaves the old binary eligible to
regain leadership, so it is not used here. Never force a new-version leader to
fail back to an old version.
The final gate requires three target members, one active member, the original
PVCs and node IDs, matching catalog/binary hashes, and fresh authentication and
invocation. Every pod’s controller-revision-hash must equal updateRevision,
the controller must have observed the generation, and updatedReplicas must
be three. currentRevision can remain historical with OnDelete; do not rotate
again just to make the two StatefulSet status revision fields equal.
6. Validate injection and repeat the upgrade checks
Compare the function/deployment records and invocation result with the baseline, including original worker pod UID, container IDs and restart counts. Record transient probe failures even if final checks pass. At every gate, the function read validates a freshly signed JWT, and the separate API-key request checks invocation. Retain the timestamped result files privately.
Admit a new workload through the injector
This short test uses the existing nvcf-api identity in namespace nvcf and
its signing policy. Its application container checks that the injected init
container wrote a nonempty signed token, without printing it. It creates only
a uniquely named ConfigMap and Pod. Confirm that this namespace is within the
existing webhook scope; do not broaden webhook selectors for the test.
The matching image pull Secrets must already exist in nvcf. A completed Pod
without the injected init container does not pass. Preserve its result, then
remove only these generated test resources when finished:
Repeat sync and prove no additional replacement is needed
Repeat the selected sync. The same function creates a new evidence directory, captures the previous migrations UID, and requires fresh completed hooks. The complete gate must select no stale members and preserve every current UID.
Review the full target diff, then apply the remaining changes and repeat the full sync. Explicitly clear the selector. Each pass must create a new completed migration Job, retain the same server UIDs, and pass fresh authentication.
Repeat the new-injection block with its new unique resource names. Verify Cassandra ledgers remain clean, credentials and records are retained, and the original function still serves before continuing to 1.0.1. A rerun of the replacement decision must select no pods; do not rotate already-current pods.
Record the topology, released image IDs, member replacement and leadership transfer observations, and probe results from your rehearsal before production use.
Stop and recover
Stop on a failed hook or health/authentication gate, unexpected leader or UID change, missing member/PVC, changed target, dirty migration ledger, or failed replacement. Preserve evidence, credentials and all persistent volumes. Do not retry pod deletion to work around an unexplained failure.
Retain the original baseline and frozen target when resuming after a successful standby replacement. Rerun the transition gate with the saved original leader and UID; it selects only remaining stale members. After an unexpected leader change, establish the current version and recovery state before proceeding. Never force leadership back to an old binary.
Once refresh changes the catalog, a Helm rollback does not restore that state or the OnDelete pods. After a new-version member becomes active, downgrading its binary against the current data store is not a supported rollback. Prefer repairing forward; otherwise use your site’s tested coordinated snapshot, matching credential and source-runtime restore procedure. This guide does not provide destructive restore automation or claim that backup transfer proves recoverability. Keep snapshot recovery and other topologies separately qualified.