Jesús Pérez a395bd972f
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
mdBook Build & Deploy / Build mdBook (push) Has been cancelled
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
mdBook Build & Deploy / Documentation Quality Check (push) Has been cancelled
mdBook Build & Deploy / Deploy to GitHub Pages (push) Has been cancelled
mdBook Build & Deploy / Notification (push) Has been cancelled
chore: add cd/ci ops
2026-01-12 03:36:55 +00:00

320 lines
7.2 KiB
Markdown

# VAPORA Backup & Recovery Scripts
Automated backup and recovery procedures for VAPORA using Nushell 0.109.0+.
**Dual Backup Strategy**:
- **S3**: Direct file uploads with AES-256 encryption
- **Restic**: Incremental, deduplicated backups with compression
---
## Scripts Overview
### Backup Scripts
| Script | Purpose | Schedule | Target |
|--------|---------|----------|--------|
| `database-backup.nu` | Export SurrealDB to S3 (compressed + encrypted) | Manual or Hourly | S3 |
| `config-backup.nu` | Backup Kubernetes ConfigMaps/Secrets | Manual or Daily | S3 |
| `restic-backup.nu` | Incremental backup to Restic repository | Manual | Restic |
| `orchestrate-backup-recovery.nu` | Coordinate all backup types | CronJob | S3 + Restic |
### Recovery Scripts
| Script | Purpose | Input |
|--------|---------|-------|
| `database-recovery.nu` | Restore SurrealDB from S3 backup | Encrypted S3 file |
| `orchestrate-backup-recovery.nu` | One-command recovery | S3 or Restic location |
### Verification
| Script | Purpose | Checks |
|--------|---------|--------|
| `verify-backup-health.nu` | Health check for backup infrastructure | S3, Restic, DB, freshness, rotation |
---
## Quick Start
### Local Backup
```bash
# Set environment
export SURREAL_URL="ws://localhost:8000"
export SURREAL_PASS="your-password"
export S3_BUCKET="vapora-backups"
export ENCRYPTION_KEY_FILE="/path/to/key"
# Run full backup
nu scripts/orchestrate-backup-recovery.nu \
--operation backup \
--mode full \
--surreal-url "$SURREAL_URL" \
--surreal-pass "$SURREAL_PASS" \
--s3-bucket "$S3_BUCKET" \
--encryption-key "$ENCRYPTION_KEY_FILE" \
--iac-dir "provisioning"
```
### Local Recovery
```bash
# Restore from S3 backup
nu scripts/orchestrate-backup-recovery.nu \
--operation recovery \
--s3-location "s3://vapora-backups/backups/database/database-20260112-010000.sql.gz.enc" \
--encryption-key "$ENCRYPTION_KEY_FILE" \
--surreal-url "$SURREAL_URL" \
--surreal-pass "$SURREAL_PASS"
```
### Health Check
```bash
nu scripts/verify-backup-health.nu \
--s3-bucket "$S3_BUCKET" \
--surreal-url "$SURREAL_URL" \
--surreal-pass "$SURREAL_PASS"
```
---
## Kubernetes Automation
CronJobs defined in `kubernetes/09-backup-cronjobs.yaml`:
- **Hourly** (00:00 UTC): Database backup (S3 + Restic)
- **Daily** (02:00 UTC): Configuration backup
- **Daily** (03:00 UTC): Health verification
- **Monthly** (04:00 first day): Snapshot rotation/cleanup
**Deploy**:
```bash
kubectl apply -f kubernetes/09-backup-cronjobs.yaml
```
**Monitor**:
```bash
kubectl get cronjobs -n vapora
kubectl logs -n vapora -l backup-type=database -f
```
---
## Features
**Dual backup approach** (S3 + Restic)
**Encryption** (AES-256 at rest, encrypted transfer)
**Compression** (gzip for S3, built-in for Restic)
**Incremental** (Restic only - no duplicate data)
**Verification** (post-backup integrity checks)
**Retention** (daily/weekly/monthly policies)
**Health checks** (automated daily verification)
**Recovery** (one-command restore)
**Kubernetes native** (CronJobs, RBAC, secrets)
---
## Implementation Details
All scripts follow **NUSHELL_GUIDELINES.md (0.109.0+)** strictly:
✓ Function signatures with BOTH `:` and `->`
✓ NO mutable variables (use `reduce --fold`)
✓ External commands with `^` prefix
✓ Error handling with `do { } | complete`
✓ Variable interpolation with `[$var]` for variables, `($expr)` for expressions
✓ NO try-catch blocks
✓ NO type annotations on boolean flags
✓ Pipelines in conditionals are parenthesized
---
## Configuration
### Environment Variables
**SurrealDB**:
```bash
SURREAL_URL=ws://localhost:8000
SURREAL_USER=root
SURREAL_PASS=<password>
```
**AWS S3**:
```bash
S3_BUCKET=vapora-backups
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=<key>
AWS_SECRET_ACCESS_KEY=<secret>
```
**Restic**:
```bash
RESTIC_REPO=s3:s3.amazonaws.com/vapora-backups/restic
RESTIC_PASSWORD=<password>
```
**Encryption**:
```bash
ENCRYPTION_KEY_FILE=/path/to/encryption.key
```
### Kubernetes Secrets
```bash
# Database credentials
kubectl create secret generic vapora-secrets \
--from-literal=surreal_password="$SURREAL_PASS" \
--from-literal=restic_password="$RESTIC_PASSWORD" \
-n vapora
# AWS credentials
kubectl create secret generic vapora-aws-credentials \
--from-literal=access_key_id="$AWS_ACCESS_KEY_ID" \
--from-literal=secret_access_key="$AWS_SECRET_ACCESS_KEY" \
-n vapora
# Encryption key
kubectl create secret generic vapora-encryption-key \
--from-file=encryption.key=/path/to/encryption.key \
-n vapora
```
---
## Backup Locations
### S3 Paths
```
s3://vapora-backups/
├── backups/
│ ├── database/
│ │ └── database-20260112-010000.sql.gz.enc
│ └── config/
│ └── configs-20260112-020000.tar.gz
└── restic/
├── data/
├── index/
├── snapshots/
└── config
```
### Restic Repository
```
s3://vapora-backups/restic/
├── data/ # Backup data files
├── index/ # Index files
├── snapshots/ # Snapshot metadata
└── config # Repository config
```
---
## Recovery Procedures
### Database Recovery (S3)
1. Download encrypted backup from S3
2. Decrypt with AES-256 key
3. Decompress backup
4. Scale down StatefulSet
5. Delete current PVC
6. Scale up StatefulSet (creates new PVC)
7. Import backup to database
8. Verify data integrity
**Time**: 30-60 seconds (depends on backup size)
### Restic Recovery
```bash
# List available snapshots
restic -r "$RESTIC_REPO" snapshots
# Restore specific snapshot to directory
restic -r "$RESTIC_REPO" restore <snapshot-id> --target /recovery
```
---
## Troubleshooting
### Backup Fails
**Check logs**:
```bash
kubectl logs -n vapora -l backup-type=database --tail=100
```
**Verify credentials**:
```bash
# S3
aws s3 ls s3://vapora-backups/
# Restic
RESTIC_PASSWORD="$RESTIC_PASSWORD" restic -r "$RESTIC_REPO" list snapshots
```
### Recovery Fails
**Ensure database is stopped**:
```bash
kubectl scale statefulset surrealdb --replicas=0 -n vapora
```
**Verify PVC deleted**:
```bash
kubectl get pvc -n vapora
```
**Check encryption key exists**:
```bash
kubectl get secrets -n vapora vapora-encryption-key
```
### Health Check Fails
**Run detailed check**:
```bash
nu scripts/verify-backup-health.nu \
--s3-bucket "$S3_BUCKET" \
--surreal-url "$SURREAL_URL" \
--surreal-pass "$SURREAL_PASS" \
--max-age-hours 25
```
---
## Integration with Disaster Recovery
These scripts implement the backup strategy defined in:
- `docs/disaster-recovery/backup-strategy.md`
- `docs/disaster-recovery/database-recovery-procedures.md`
See `docs/operations/backup-recovery-automation.md` for comprehensive integration guide.
---
## Support
**Documentation**:
- Backup Strategy: `docs/disaster-recovery/backup-strategy.md`
- Disaster Recovery: `docs/disaster-recovery/README.md`
- Operations Guide: `docs/operations/README.md`
**Issues**:
- Check logs: `kubectl logs -n vapora -l backup-type=database`
- Verify configuration: Check all environment variables are set
- Test connectivity: `aws s3 ls`, `surreal list namespaces`
---
**Last Updated**: January 12, 2026
**Nushell Version**: 0.109.0+
**Status**: Production-Ready