Operate

Upgrade

Bump the chart version, run helm upgrade, and check that the platform came back licensed and serving.

Upgrade

An upgrade is a new chart version and the images that ship with it. There is no separate migration step to run: the platform API applies its own boot migrations when the new pod starts.

Run it

Keep your install values in a file rather than repeating --set flags, so an upgrade is a one-line command that cannot accidentally drop a value:

helm upgrade my-mvno oci://ghcr.io/solvegio/charts/platform \
  --version <new-version> \
  --namespace my-mvno \
  -f my-values.yaml

If you installed with --set flags instead, pass every one of them again, or use --reuse-values and add only what changes. A helm upgrade that omits platform.host or platform.kind re-renders the release without them and the install breaks.

For a production release, pin images by digest so an upgrade is reproducible and a re-pushed tag cannot change what runs:

--set image.digest=sha256:<api-image-digest> \
--set images.licenseAgent=ghcr.io/solvegio/license-agent@sha256:<digest>

See Helm values for the full set.

What survives an upgrade

The secrets the chart generated for you. The JWT secret, the age KEK keypair, the Postgres and Redis passwords, the session password, the downstream service key: all of these are looked up from the live Secret on every render and reused. An upgrade never rotates a value a running platform depends on. If you supply your own Secret through secrets.existingSecret, the chart does not touch it at all.

Your data. The bundled Postgres, Redis and Kafka StatefulSets keep their PersistentVolumeClaims. An external or operator-mode database is not touched by Helm in the first place.

Your license. SIGNING_SEED, POP_SIGNING_SEED and PARENT_LEASE_TOKEN live in the platform Secret and are written there by the license agent, not by Helm. The new agent pod reads the lease it already holds and carries on renewing from where the old one left off. Nothing re-enrolls, and no activation code is spent.

Leaving the original (now consumed) activation.code in your values file is harmless. The agent recognises a code it has already used and does nothing with it.

What to check afterwards

The license agent runs a Recreate rollout, so the old pod goes away before the new one arrives. A gap of a few seconds with no agent running is expected. The API keeps serving through it: it reads the lease from a mounted file and does not need the agent to be up in order to answer requests.

kubectl -n my-mvno rollout status deploy/my-mvno-platform-api --timeout=180s
kubectl -n my-mvno rollout status deploy/my-mvno-platform-license-agent --timeout=120s
kubectl -n my-mvno logs deploy/my-mvno-platform-license-agent --since=5m
curl -sf https://api.acme.com/health

In the agent's log you want to see its state line reporting a healthy lease:

level=INFO msg="agent: state" state=licensed

state=unenrolled or state=renew_failing after an upgrade means something about the licensing path changed. Licensing failures has the specific log lines. If the API pod is stuck in Init, start at Install failures instead.

Watch license_expiry_seconds for a few minutes after the rollout as well. It should keep counting down and then jump back up at the next renewal. See Observability.

If the upgrade goes wrong

helm rollback my-mvno -n my-mvno puts the previous release back. Take a copy of the platform Secret before any upgrade you are nervous about. It is the one object in the namespace that the chart cannot regenerate for you, because it holds the deployment's signing key. Backup and restore covers the command and what to do if the Secret is gone.

Copyright © 2026