Files
autobackup-operator/README.md
T
unkin-agent a3339a30b5
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Fix leader-election RBAC, Go version drift, PVC churn, cron names, apply order
Addresses PR review + acceptance findings:

- Add leader-election RBAC: namespaced Role (coordination leases +
  events) and RoleBinding to the operator ServiceAccount, so controllers
  actually start under --leader-elect instead of looping on "leases
  forbidden". Verified in a kind cluster: lease acquired, both
  controllers start workers.
- Align Go versions: bump Dockerfile.operator to golang:1.26-alpine and
  CI images to golang:1.26 to match go.mod (go 1.26.5); set
  GOTOOLCHAIN=local so the image build stays hermetic (no toolchain
  download).
- PVC controller: add an annotation predicate so only PVCs carrying (or
  transitioning off of) backups.unkin.net/schedule enqueue, eliminating
  reconcile churn from unannotated PVCs while keeping the teardown path.
- Cron validator: accept alphabetic month/day-of-week names (MON, JAN,
  MON-FRI) that k8up and CNPG's robfig/cron accept, still rejecting
  unknown names; add unit tests for both mapping paths.
- Deploy ordering: extract the Namespace into its own manifest and add a
  config/kustomization.yaml so `kubectl apply -k config` creates the
  namespace first; document it in the README.
- Note the credential-less push precedent (jellyfin-ha) in docker.yaml.
2026-08-14 00:33:49 +10:00

80 lines
3.3 KiB
Markdown

# autobackup-operator
A Kubernetes operator that watches for `backups.unkin.net/*` annotations on
**PersistentVolumeClaims** and **CloudNativePG Clusters** and provisions the S3
bucket + backup-schedule resources needed to back them up. No new CRDs — it is
purely annotation-driven on existing objects.
## Annotations
| Annotation | Meaning |
|---|---|
| `backups.unkin.net/schedule` | `@hourly` / `@daily` / `@weekly` (plus `@monthly`/`@yearly`) or a raw cron expression. Absence means "not managed". |
| `backups.unkin.net/destination` | A logical destination name resolved via the destinations ConfigMap. |
| `backups.unkin.net/purge-on-delete` | `"true"` opts into deleting the bucket stack when the schedule annotation is removed (default: retain bucket data). |
## What it does
For every annotated object the operator, in the object's own namespace and
owner-referenced to it:
1. Provisions a cephrgw (`ceph.unkin.net/v1alpha1`) `ObjectStoreUser`, `Bucket`
(`versioning: true`, `retainOnDelete: true`) and read-write `BucketAccess`.
2. Waits for the `BucketAccess` to become `Ready` (requeues until then).
3. Then wires up the backup schedule:
- **PVC → k8up** (`k8up.io/v1` `Schedule`): S3 backend from the cephrgw
credential Secret, an auto-generated restic repo-password Secret, and the
backup scoped to exactly this PVC via
`spec.backup.volumes[].persistentVolumeClaim.claimName`. Sane prune
retention (keepDaily 7, keepWeekly 4).
- **CNPG Cluster** (`postgresql.cnpg.io/v1`): patches
`spec.backup.barmanObjectStore` (idempotently; a user-set different
`destinationPath` is left untouched with a Warning event) and creates a
`ScheduledBackup` with a 6-field (seconds-first) cron.
## Destinations ConfigMap
The operator resolves `destination` names against a ConfigMap in its own
namespace (`autobackup-operator/autobackup-destinations` by default). See
`config/samples/destinations.yaml`.
## Deploy
```sh
kubectl apply -k config
```
The `config/kustomization.yaml` orders the `Namespace` first so the
ServiceAccount, RBAC and Deployment land in an existing namespace. RBAC covers
both the controllers' resources (`config/rbac/role.yaml`) and the leader-election
lease/events the manager needs when run with `--leader-elect`
(`config/rbac/leader_election_role.yaml`). Then create the destinations
ConfigMap (see `config/samples/destinations.yaml`).
## Schedule mapping
- **k8up** accepts cron nicknames natively and 5-field cron expressions; the
value is validated and passed through.
- **CNPG** requires a 6-field (seconds-first) cron: nicknames are expanded and a
5-field cron gains a leading `0` seconds field.
Invalid schedules surface as Warning events on the annotated object.
## Development
```sh
make build # build the operator binary
make test # unit + envtest controller tests (fetches envtest binaries)
make lint # go vet
make generate # regenerate config/rbac/role.yaml from kubebuilder markers
```
Dependencies are vendored so the container build and CI need no access to the
private `cephrgw-operator` module.
## Release
`make patch|minor|major` tags and pushes `vX.Y.Z`. A `v*` tag triggers the
Woodpecker `docker` pipeline, which builds and pushes
`artifactapi.k8s.syd1.au.unkin.net/docker-internal/autobackup-operator:<tag>`.