Upgrades
Upgrade a Membrane deployment without downtime. Patch and minor releases roll out one node at a time while the cluster keeps serving; major releases are planned migrations. Read the CHANGELOG before every upgrade, because it lists breaking changes under a Breaking heading.
Release types
Membrane follows Semantic Versioning.
| Release | What changes | Procedure |
|---|---|---|
| Patch | Bug fixes | Rolling upgrade |
| Minor | Features; operator-visible changes are called out | Rolling upgrade, after reading Breaking |
| Major | The wire format (SCHEMA_VERSION) or the API | Planned migration |
Nodes of adjacent minor versions interoperate during a rolling upgrade.
Before you upgrade
- The CHANGELOG’s Breaking section is read.
- A backup is taken, for major upgrades. See Backup and restore.
-
quorum_countleaves headroom for one node being replaced. - The rollback command is ready.
Rolling upgrade
Kubernetes
kubectl set image statefulset/membrane membrane=ghcr.io/sachncs/membrane:X.Y.Z -n membranekubectl rollout status statefulset/membrane -n membraneThe StatefulSet replaces one pod at a time, highest ordinal first. Each pod drains on SIGTERM (readiness turns 503 and its primaries are handed off), keeps its data volume, restores its fragments from Redis on start, and rejoins its peers. The PodDisruptionBudget keeps two pods available.
With three nodes and the default quorum_count of 2, strong writes keep succeeding while one node is being replaced. CI verifies this on every change: a rolling restart under continuous strong writes completes with no failed writes.
Docker Compose and systemd
git fetch --tags && git checkout vX.Y.Zdocker compose up -d --build membrane # Docker Composeuv sync --frozen --no-dev --extra server && sudo systemctl restart membrane # systemdRelease notes for operators
Upgrading to the current release
- Tenant-scoped keys. Each tenant now keeps its own copy of a content hash.
/inventory, persistence records, warm-tier entries, and fragment events name a non-publictenant’s fragment<tenant>:<hash>. Records persisted by an earlier version are re-keyed when a node restores them. /admin/policynow reads and changes the live promotion thresholds, and answers409when promotion is off.- Vault:
VaultSecretProviderreads thesecretmount by default (asecret/dataprefix still works).
Upgrading to the Python 3.14 release
This release requires Python 3.14. Rebuild virtual environments (uv sync --frozen installs 3.14 automatically) and images (the Dockerfile already uses python:3.14-slim). Before rolling it out:
chmod 600your API keyfile, TLS private key, and data key. The server refuses secret files that other users can read.- Optionally convert the keyfile to hashed lines. Plaintext lines still work but log a warning. For each key,
printf '%s' "$KEY" | sha256sum | cut -d' ' -f1(on macOS,shasum -a 256) gives the digest forsha256:<digest>:<subject>:<scopes>. - FastAPI’s
/docs,/redoc, and/openapi.jsonare served only with--enable-api-docs. - The LMCache integration and the
vllm,sglang, andtrtllmextras were removed; see Compatibility. - Scripts that parse CLI output: results still go to stdout, while status and errors go to stderr as log records.
Major upgrades
- Take a backup (Backup and restore).
- Read the CHANGELOG’s migration notes.
- Stop all nodes. Nodes of different major versions do not interoperate.
- Convert stored envelopes if the notes say so. For v2 to v5:
python tools/upgrade_v2_to_v5.py. - Deploy the new version, and verify with
membrane client inventory.
Roll back
kubectl rollout undo statefulset/membrane -n membraneWithin a major version, data written by the newer version is readable by the older one. Across major versions, restore the pre-upgrade backup.