Restore from the GCS copy
Copy a Garage bucket back from the encrypted GCS copy of its site, when Garage has lost the bucket.
Use this runbook when the Garage of a site has lost the bucket that a restore needs. backup-push keeps an encrypted copy of each bucket in GCS. The restore runbooks send you here. The tools come from the repo's mise toolchain.
warning
This procedure changes live state by hand. It is an exception to the GitOps rule because git holds no backup data.
Before you start#
- Sign in to
opandgcloud. - Know the site,
follyoroffsite, and the bucket:velero,cnpgoretcd. The Garage key of the bucket has the same name. - Read
GARAGE_S3_ENDPOINTinclusters/<site>/config/cluster-settings.yaml.
Copy the bucket#
Put the crypt remote in the environment. The values stay out of the shell history.
export RCLONE_CONFIG_GCS_TYPE="google cloud storage" RCLONE_CONFIG_GCS_ENV_AUTH=true RCLONE_CONFIG_GCS_BUCKET_POLICY_ONLY=true export RCLONE_CONFIG_CRYPT_TYPE=crypt RCLONE_CONFIG_CRYPT_REMOTE="gcs:homelab-ng-backups-<site>/garage" export RCLONE_CONFIG_CRYPT_PASSWORD="$(op read 'op://homelab/backup-crypt/rclone-password' | rclone obscure -)" export RCLONE_CONFIG_CRYPT_PASSWORD2="$(op read 'op://homelab/backup-crypt/rclone-salt' | rclone obscure -)" gcloud auth application-default login export GOOGLE_PROJECT_ID=homelab-ngPut the Garage remote in the environment.
export RCLONE_CONFIG_GARAGE_TYPE=s3 RCLONE_CONFIG_GARAGE_PROVIDER=Other RCLONE_CONFIG_GARAGE_REGION=garage export RCLONE_CONFIG_GARAGE_ENDPOINT=<endpoint> export RCLONE_CONFIG_GARAGE_ACCESS_KEY_ID="$(op read 'op://homelab/garage-<site>/<bucket>-access-key-id')" export RCLONE_CONFIG_GARAGE_SECRET_ACCESS_KEY="$(op read 'op://homelab/garage-<site>/<bucket>-secret-access-key')"Copy the bucket into Garage.
rclone copy crypt:<bucket> garage:<bucket> --progressResult: A transfer summary with no errors.
Copy from inside the cluster#
Use this procedure for a large copy, or when your machine sits behind Starlink, which the copy would cross twice. The backup-push CronJob in backups already holds the GCS credential, the crypt remote and a Garage key, so a Job cloned from it does the copy with rclone copy reversed. Its push key reads the buckets only, so grant it write access for the copy and withdraw it after.
Grant the
pushkey write access to each bucket.for b in velero cnpg etcd; do kubectl --context <site> -n garage exec garage-0 -c garage -- /garage bucket allow --read --write "$b" --key push; doneCreate the Job from the CronJob's pod template, with the copy reversed.
kubectl --context <site> -n backups get cronjob backup-push -o json | jq '{apiVersion: "batch/v1", kind: "Job", metadata: {name: "garage-refill", namespace: "backups"}, spec: {backoffLimit: 0, ttlSecondsAfterFinished: 86400, template: (.spec.jobTemplate.spec.template | .spec.containers[0].env += [{name: "RCLONE_CONFIG_GARAGE_NO_CHECK_BUCKET", value: "true"}] | .spec.containers[0].command = ["sh", "-c", "set -eu\nRCLONE_CONFIG_CRYPT_PASSWORD=$(printf %s \"$CRYPT_PASSWORD\" | rclone obscure -)\nRCLONE_CONFIG_CRYPT_PASSWORD2=$(printf %s \"$CRYPT_SALT\" | rclone obscure -)\nexport RCLONE_CONFIG_CRYPT_PASSWORD RCLONE_CONFIG_CRYPT_PASSWORD2\nfor bucket in velero cnpg etcd; do\n rclone copy \"crypt:$bucket\" \"garage:$bucket\" --stats 1m --stats-one-line --stats-log-level NOTICE\n rclone cryptcheck \"garage:$bucket\" \"crypt:$bucket\"\ndone\n"])}}' | kubectl --context <site> create -f - kubectl --context <site> -n backups wait --for=condition=complete job/garage-refill --timeout=1hResult:
job.batch/garage-refill condition met, and the Job's log ends with0 differences foundfor each bucket.Withdraw the write access.
for b in velero cnpg etcd; do kubectl --context <site> -n garage exec garage-0 -c garage -- /garage bucket deny --write "$b" --key push; done
If something goes wrong#
| Symptom | Cause | Action |
|---|---|---|
rclone prints didn't find section in config file. | An environment variable is missing. | Set the remote variables again. |
rclone prints a decryption error. | The crypt password or salt is wrong. | Read both from the backup-crypt item again. |
rclone prints a 403. | The Garage key is for another bucket. | Use the key that has the name of the bucket. |
Related#
Linked from 6
- BackupsHow Garage, Velero, CloudNativePG and etcd snapshots back up the lab's databases, volumes and etcd, and how each site copies them to GCS.
- RunbooksStep-by-step procedures for the hosts, clusters, network, secrets and apps, grouped by area.
- Recover a re-created databaseBring a Postgres database back from its barman backups when its CloudNativePG Cluster is created again under the same name, such as after a Kubernetes cluster rebuild.
- Restore a databaseRecover a Postgres database from its barman backups in Garage into a scratch CloudNativePG cluster, copy the data back, and run the restore drill.
- Restore a volumeRestore the files of a volume from a Velero backup in Garage, or from the encrypted GCS copy, when the volume is lost or damaged.
- Restore etcd on TalosRestore the etcd of a Talos control plane from a snapshot, when the etcd data is lost or corrupt.