Upgrades and air-gap

Moving to a new release, and running with no route to the internet.

Supported window

Within a minor version, upgrade from any release to any later one. Across minor versions, two back — upgrade within the window, then upgrade again. Do not jump.

v0.34.12 → v0.34.28   supported
v0.34.x  → v0.36.x    supported
v0.33.x  → v0.36.x    not supported. Step through v0.34 or v0.35.

Before every upgrade

  1. Read the release notes for breaking changes.
  2. Back up the database and the key volume together, and check the backup. A database backup taken without the key material is not restorable into a working system — the rows are there and nothing can sign or decrypt them.
  3. Download and verify the new release.

Schema migrations are forward-only and run before the new application code serves traffic. A migration that fails leaves its Job in place on purpose, so its logs survive for you to read.

Docker Compose

A single host, so there is a short outage — the stack stops, then starts on the new images. From your install directory, with NEW set to the new version:

oras pull registry.lutralabs.io/customers/$SLUG/lutralabs/lutra-id-selfhosted-bundle:$NEW -o .
./verify-release.sh $NEW --registry registry.lutralabs.io/customers/$SLUG

That replaces the bundle's files and leaves your .env and secrets/ alone. Compare .env.example with your .env for settings the release added, then set all four *_TAG values in .env to the new version and run:

docker compose pull
docker compose --profile migration run --rm migrator
docker compose --profile migration run --rm migrator seed-base
docker compose up -d --wait

To roll back, put the previous tags back and repeat — but only if the release notes say the migrations were backward compatible. Otherwise restore from backup; a schema migration is not automatically reversible.

Helm

Install the new chart version over the old one. Migrations run as a pre-upgrade Job before any pod is replaced:

helm upgrade lutraid oci://registry.lutralabs.io/customers/$SLUG/lutralabs/charts/lutraid \
  --version ${NEW#v} -n lutraid --reuse-values

Collect the migration Job's logs before retrying a failed upgrade.

Air-gapped installation

Mirror the release into whatever registry your site can reach, from the bundle directory on a connected machine:

./mirror-images.sh $VERSION \
  --from registry.lutralabs.io/customers/$SLUG \
  --to harbor.internal.gov.si/lutraid \
  --include-chart

That copies by digest, never by tag, and re-points the mirrored tag at the same digest — so a mirror cannot serve different bytes than the release it claims to be. Signatures and SBOM attestations are copied with every artifact, so the mirror verifies exactly like the source. Leave out --include-chart if you install with Compose.

Then change one value:

PackageSetting
Helm--set global.imageRegistry=harbor.internal.gov.si/lutraid, and global.imageMap if your registry flattens paths. Install the chart from oci://harbor.internal.gov.si/lutraid/lutralabs/charts/lutraid
ComposeREGISTRY=harbor.internal.gov.si/lutraid in .env

No chart template and no Compose file hardcodes a registry host. That is the whole change.

Verifying without internet access

cosign verify normally reaches Fulcio and Rekor, which an air-gapped site cannot. Releases are therefore signed twice — keyless, and with a long-lived key whose public half ships with the release:

./verify-release.sh $VERSION \
  --registry harbor.internal.gov.si/lutraid \
  --key cosign.pub --offline

What needs no egress

License verification is offline by design. Telemetry is off unless you configure it. The Trust Validator is optional and off by default. Mail goes to your relay, and image storage is a local volume unless you point it at S3.

If your registry credential lapses

Pulls stop working. Your running deployment is unaffected — images already on your hosts keep running, and your license is a separate system entirely. What you lose is the ability to fetch new versions, including security patches.

Was this page helpful?