docsOperate

Upgrade barriers

Moving a local cluster to another release is normally a retag: the VS Code extension moves the pinned checkout, reconciles the local overlay from it, and every other install step verifies itself and skips. That is the whole reason one button can honestly offer it.

Between some pairs of releases it is not a retag. This page lists those pairs, says what each one actually changes, and gives the procedure that replaces the button.

WARNING: the procedures on this page are written for a LOCAL cluster. A barrier is a fact about what a release changed, so the extension refuses the crossing on a remote (deploy-control) cluster too — but the steps below assume a k3d cluster on the operator's own machine, and one of them offers to destroy and rebuild it. See Crossing a barrier on a remote cluster before applying any of this to staging or production.

The extension refuses rather than warns. When a move crosses a barrier, the confirmation dialog becomes a refusal and the button does not run. A warning an operator can click past is not a safeguard for a change that can leave a cluster running with an empty graph and no error anywhere.

The barriers

Moving pastWhat changes
v0.18.0The database changes from an in-overlay Postgres Deployment to a CloudNativePG cluster, and the cluster gains an operator stack (cert-manager + CloudNativePG).

The machine-readable copy is editors/vscode/src/version/barriers.ts, and it is the one the extension reads. This table is prose for a human; that file is the table.


Moving past v0.18.0

What changes

At v0.18.0 the local overlay listed postgres.yaml — a plain Deployment/postgres running timescale/timescaledb:2.19.1-pg16, with a PersistentVolumeClaim/postgres-data holding the data and credentials in a memql-local-db-creds Secret.

After it, the overlay composes deploy/k8s/components/cnpg-db instead: a CloudNativePG Cluster/memql-db with its own storage, its own operand image, and its credentials in memql-db-app-creds. scripts/k3d/up.sh gained install_operator_stack, which registers cert-manager and CloudNativePG as ArgoCD Applications and waits for them, because the CNPG manifests are custom resources that nothing serves until the operator is running.

See database-platform.md for what the CloudNativePG platform is and why the cluster runs it.

Why the checkout move cannot carry it

Two different things break, and the second is the dangerous one.

The operator stack has to exist first. The overlay after v0.18.0 contains Cluster and Database resources, which are CloudNativePG CRDs. Applying them to a cluster with no CNPG operator fails on kinds the API server does not recognise — a loud, obvious failure, and not the problem.

The data does not follow. The old postgres-data volume belongs to a Deployment the new overlay does not contain, and the new CNPG cluster initialises an empty database of its own. Nothing in the reconcile reads the old volume, and nothing reports that it did not: the pods come up, the engine migrates a fresh schema, health checks pass, and the operator gets a working cluster containing none of their graph. That is a silent outcome, which is why this is a refusal and not a warning.

WARNING: the old PVC is not deleted by the move, so the data is still on the machine until something removes it. make down PURGE=1 and the extension's uninstall graph both remove it. Take the dump below before either.

Procedure A — discard the data and re-install (the usual choice)

LOCAL ONLY. A local cluster is a development cluster. If nothing in it needs to survive, this is the shortest correct path and the one to prefer. It destroys and re-creates the cluster, so it is not a procedure for anything else -- see Crossing a barrier on a remote cluster.

  • Uninstall the cluster (the extension's Uninstall action, behind its removal preview; or make down PURGE=1 in the checkout).
  • Install again at the new tag (the extension's Create deployment; or make up in a checkout moved to the new tag).

The install graph registers the operator stack and provisions the CNPG cluster as part of a normal first install, so there is nothing barrier-specific to do.

Procedure B — carry the data across

LOCAL ONLY, for the same reason, and because the commands name a Deployment/postgres a cloud overlay may not have.

Run this while the old cluster is still up. Every name below is read off the manifests on each side, but confirm the dump is non-empty before you tear anything down.

  • Dump the old database:

    text
    kubectl exec -n memql deploy/postgres -- \
    sh -c 'pg_dump -U "$POSTGRES_USER" -d memql --no-owner --no-privileges' \
    > memql-pre-cnpg.sql
  • Check the dump. It should be tens of megabytes at minimum for a cluster that has been used, and end in PostgreSQL database dump complete.

  • Uninstall, then install at the new tag, exactly as in Procedure A. The new cluster comes up with an empty memql database owned by memql.

  • Restore into the CloudNativePG cluster:

    text
    kubectl exec -i -n memql memql-db-1 -- \
    psql -U memql -d memql < memql-pre-cnpg.sql
  • Restart the engine pods so they re-read a database that changed underneath them: kubectl rollout restart -n memql deploy.

Notes that matter:

  • --no-owner --no-privileges is not optional. The old Deployment's role name comes from memql-local-db-creds and the CNPG database is owned by memql; a dump carrying the old ownership fails to restore against the new role.
  • TimescaleDB and pgvector extensions are created by the engine's own migrations on first boot against the new cluster, so the dump does not need to carry them. A dump that does will report the extensions already exist; that is benign.
  • The operand image is not the old image. The new cluster runs the operand built in deploy/db-image/, not timescale/timescaledb:2.19.1-pg16. Restoring a logical dump is what makes that a non-issue — a filesystem-level copy of the old PVC is not a supported move and is not offered here.

Moving back before v0.18.0

The extension refuses this direction too, and it is the worse one: it puts a plain Postgres Deployment in front of data that lives in a CloudNativePG cluster, and the CNPG Cluster resource is left behind by an overlay that no longer contains it. There is no supported downgrade procedure. If a release after v0.18.0 has to be backed out of, do it by re-installing at the older tag from empty, restoring a dump you took beforehand.


Crossing a barrier on a remote cluster

The refusal is right; the procedures above are not the answer. The extension refuses this crossing on a remote cluster for the same reason it refuses it locally — the barrier records what the release changed, and that is true wherever the release runs. What differs is everything about how you cross it.

What is established, and what is not:

  • Established: past v0.18.0 the manifests compose deploy/k8s/components/cnpg-db and require the cert-manager + CloudNativePG operators to be registered before they reconcile. That is read off the manifests and holds for any cluster running them.
  • NOT established here: what a safe crossing looks like on a cluster reconciled by ArgoCD against a cloud overlay, with a database that has real data and a backup regime. Nobody has written that procedure down, and this page will not invent one — a procedure that has never been run is worse than an admission that none exists, because it reads as though it has.

So, concretely: do not apply Procedure A or Procedure B to a staging or production cluster. Procedure A destroys and re-creates the cluster, and its justification ("a local cluster is a development cluster") is false of yours. Procedure B's kubectl exec deploy/postgres names a Deployment a cloud overlay may not have.

What to do instead:

  • Confirm the operator stack is registered in the target cluster (cert-manager and cnpg-system namespaces healthy) before anything reconciles the new manifests.
  • Take a backup through the platform's own path and confirm you can restore it, rather than through pg_dump against a pod: database-platform.md covers the backup regime and the restore drill.
  • Cross the barrier as a deliberate, planned migration rather than as a deploy. The extension's button is not going to become the way to do this, and that is the point of the refusal.

If you carry a remote cluster across this barrier, write down what you did and replace this section with it.


Adding a barrier

A barrier entry is written by whoever ships the change, in the release that ships it — not from a plan.

  1. Add an entry to UPGRADE_BARRIERS in editors/vscode/src/version/barriers.ts. afterVersion names the last release before the barrier, so an entry can be written before the release carrying the change has a number.
  2. Add a section to this page and point the entry's docHref at it. The tests assert the file exists; they cannot assert it says anything useful, so this is the part that needs a person.
  3. Keep the table ordered oldest-first. A move can cross two barriers, and the operator performs them in order.

editors/vscode/test/barriers.test.ts holds the newest entry at or below DEFAULT_STACK_TAG (editors/vscode/src/install/stackPin.ts): the pin is bumped by the release that cuts a tag, so an entry ahead of it was written from a plan rather than from a release. Add the barrier in the release that ships it.

This rule's original reason expired in memql#4429. It used to be that DEFAULT_STACK_TAG was the release the installer actually put on a machine, so an entry newer than the pin described a crossing nobody could make -- an unfireable refusal. That is no longer so: the install form is seeded with the newest release the repository lists, and the pin has narrowed to the offline fallback. The practical consequence runs the other way now, and it is worth knowing: a missing barrier entry is reachable BY DEFAULT, not only by an operator who typed a tag by hand. Nothing can test for a barrier nobody wrote, which is why it belongs in the release that ships the change.

  • The recorded cluster version — where the from side of the comparison comes from, and why it is recorded rather than observed
  • Database platform (CloudNativePG) — the platform the v0.18.0 barrier moves onto
  • Reproduce the cloud locally — the local k3d runbook, including backup and restore drills on the CNPG side