Files
Aleksei Sviridkin 534f8f1db9 docs(backups): stop presenting admin-only demo steps as tenant work
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>
2026-10-03 01:43:02 +03:00
..

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 → PUT the tarball to S3.
  • restore: GET the 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.
  • kubectl and jq locally.
  • 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.
  • nats CLI specifics. The strategy invokes nats stream backup/nats stream restore; flag names can vary across nats CLI versions. Pin NATS_BOX_IMAGE to 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 -k to curl. 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.