The kafka and nats walkthroughs put steps 03, 04, 06, 07 and cleanup under the tenant persona, and the scenario docs and helper comments had the tenant create the backup Secret. The scripts read, create and delete Secrets, wait on HelmReleases, COSI objects and operator resources, exec into a CLI Pod, read Pod logs, and delete the Backup and the cluster-scoped BackupClass and strategy. The tenant roles grant none of that, so a tenant following the docs hit Forbidden at the first read. The tables now say admin and name the part a tenant admin can do on its own, and the scenario docs say the same. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la>
NATS JetStream backup/restore example
This directory shows how to back up and restore a Cozystack-managed NATS
application using the generic Job backup strategy. Unlike the
app-specific drivers (Altinity for ClickHouse, CNPG for Postgres, ...), the
Job strategy has no built-in knowledge of the application: it runs a Pod the
operator supplies. Here that Pod is a stock natsio/nats-box image
(which carries the nats CLI plus curl and tar) running one shell script:
- backup:
nats stream backup→tar→PUTthe tarball to S3. - restore:
GETthe tarball from S3 →tar -x→nats stream restore.
The same PodTemplateSpec serves both directions. The strategy engine
templates each string field independently — it cannot add or remove containers
per mode — so the single image branches at runtime on {{ .Mode }} (rendered
into the MODE env var). Backup pushes to a key scoped by the source app
({{ .Release.Name }}); restore reads the key scoped by the backup's source
({{ .Backup.ApplicationRef.Name }}), so a to-copy restore lands the source's
data into a differently-named target.
The upload uses curl --aws-sigv4, so no purpose-built backup image is needed
— a stock client image plus a shell one-liner is the whole driver. This is the
point of the generic Job strategy: back up an app that has no dedicated
driver, with tools you already have.
Step order
| File | Role | Triggered by |
|---|---|---|
00-helpers.sh |
Shared bash helpers, env defaults, and the nats/S3-secret helpers; sourced by every step. |
n/a |
01-create-strategy.sh |
Creates the cluster-scoped Job strategy (the nats-box PodTemplateSpec). |
admin |
02-create-backupclass.sh |
Maps apps.cozystack.io/NATS to that strategy, with stream/natsUser parameters. |
admin |
03-create-bucket.sh |
Provisions a Bucket and caches its S3 coordinates into .bucket-info.env (chmod 600; raw access keys). cleanup.sh removes this file. |
admin. A tenant admin can create the Bucket itself, but the script also waits on its HelmRelease and COSI objects and reads the bucket-<name>-backup Secret; no tenant role grants access to helmreleases or objectstorage.k8s.io, or get on that Secret |
04-create-nats.sh |
Provisions a NATS instance, creates the <app>-backup-s3 Secret, seeds a JetStream stream with sentinel messages. |
admin. A tenant admin can create the NATS itself, but the script also waits on its HelmRelease and StatefulSet, creates the Secret, and seeds the stream through a CLI Pod it execs into; no tenant role grants access to helmreleases or statefulsets, create on secrets or pods, or pods/exec |
05-create-backupjob.sh |
Submits a BackupJob and waits for Succeeded. |
tenant |
06-restore-in-place.sh |
Deletes the stream and restores it into the same instance via RestoreJob. |
admin. A tenant admin can submit the RestoreJob, but the script deletes and checks the stream through the CLI Pod; no tenant role grants create on pods or pods/exec |
07-restore-to-copy.sh |
Provisions a second NATS and restores into it via RestoreJob.spec.targetApplicationRef. |
admin, for the same reasons as step 04. The tenant admin's part is the second NATS and the RestoreJob |
cleanup.sh |
Removes everything created by the demo. | admin: it deletes Secrets, the Backup, and the cluster-scoped BackupClass and strategy, and no tenant role grants delete on any of them |
run-all.sh |
Convenience runner that executes 01..07 in order. | demo |
90-scenario-admin-prepare.md |
Narrative for the admin preparation steps. | docs |
91-scenario-user-backup.md |
Narrative for the user backup flow. | docs |
92-scenario-user-restore.md |
Narrative for the user restore flow (in-place and to-copy). | docs |
Environment variables (overrides)
All variables come from 00-helpers.sh:
| Variable | Default | Description |
|---|---|---|
NAMESPACE |
tenant-test |
Tenant namespace for the demo. |
NATS_NAME |
nats-test |
Source NATS application name. |
NATS_RESTORE_NAME |
nats-restore |
Target NATS for the to-copy restore. |
NATS_USER |
backup |
NATS user the strategy authenticates as. |
NATS_PASSWORD |
jetstream-demo-pw |
Password set on that user (kept fixed for a deterministic demo). |
STREAM_NAME |
ORDERS |
JetStream stream to back up. |
MESSAGE_COUNT |
10 |
Sentinel messages published before backup. |
BUCKET_NAME |
nats-backups |
Cozystack Bucket to provision. |
BACKUPCLASS_NAME |
nats-backup |
BackupClass name (cluster-scoped). |
STRATEGY_NAME |
nats-job |
Strategy name (cluster-scoped). |
BACKUPJOB_NAME |
nats-backup-job |
BackupJob name. |
RESTOREJOB_INPLACE_NAME |
nats-restore-inplace |
In-place RestoreJob name. |
RESTOREJOB_TOCOPY_NAME |
nats-restore-to-copy |
To-copy RestoreJob name. |
NATS_BOX_IMAGE |
natsio/nats-box:0.14.5 |
Image with the nats CLI used by the strategy and the seed/verify helpers. |
Prerequisites
- Cozystack cluster with the backup-controller and backupstrategy-controller installed.
kubectlandjqlocally.- Egress to pull
natsio/nats-box(used both by the strategy Pod and by the demo's seed/verify helpers).
Notes / caveats
- Not run in CI. Like every other directory under
examples/backups/, this demo is a runnable reference, not an automated regression test — the e2e harness (hack/e2e-chainsaw/) does not exercise backup examples. Run it by hand against a cluster. natsCLI specifics. The strategy invokesnats stream backup/nats stream restore; flag names can vary acrossnatsCLI versions. PinNATS_BOX_IMAGEto a version whose CLI matches if the defaults drift.- Self-signed S3. The COSI/seaweedfs S3 endpoint uses an internal CA, so
the strategy passes
-ktocurl. A production strategy should mount the tenant CA and drop-k. - Definitions vs. data. This backs up a JetStream stream's messages and
configuration via
nats stream backup; it does not capture NATS account or KV/object-store state beyond the named stream.