Skip to content

Commit fd2dcbc

Browse files
mitchrossclaude
andcommitted
fix(volsync): remove dataSourceRef from PVCs (immutable field)
PVC specs are immutable after creation - dataSourceRef cannot be added to existing PVCs. Removed from all 18 PVC files. The Volume Populator pattern only works for NEW PVC creation. For existing clusters, restore is triggered manually via: kubectl patch replicationdestination <app>-restore ... Updated docs to reflect manual restore process. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e8582ae commit fd2dcbc

19 files changed

Lines changed: 36 additions & 99 deletions

File tree

docs/storage-architecture.md

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ container-registry, redis, mqtt, searxng, fizzy, nginx, jellyfin, nestmtx, homep
103103

104104
Each app has:
105105
- `ReplicationSource` - Defines backup schedule and retention
106-
- `ReplicationDestination` - Dormant restore definition (no trigger)
107-
- `PVC` - References ReplicationDestination via `dataSourceRef`
106+
- `ReplicationDestination` - Dormant restore definition (triggered manually when needed)
108107
- `ExternalSecret` - Pulls S3 credentials from 1Password
109108

110109
### Database Backups (Native)
@@ -124,44 +123,54 @@ PostgreSQL databases use their native backup tools:
124123

125124
## 3. Disaster Recovery
126125

127-
### Volume Populator Pattern (Automatic Restore)
126+
### Defense Layers
128127

129-
PVCs use the **Volume Populator** pattern for automatic restore:
128+
- **Layer 1 (Longhorn)**: Runtime replication across nodes - survives single node failure
129+
- **Layer 2 (VolSync)**: S3 backups to RustFS - survives complete cluster loss
130130

131-
```yaml
132-
# In each app's PVC
133-
spec:
134-
dataSourceRef:
135-
kind: ReplicationDestination
136-
apiGroup: volsync.backube
137-
name: <app>-restore
138-
```
131+
### Restoring a PVC (VolSync)
139132

140-
**How it works:**
141-
1. PVC references a dormant ReplicationDestination (no trigger)
142-
2. When PVC is newly created (no existing Longhorn volume), Kubernetes uses the dataSourceRef
143-
3. VolSync automatically restores from S3 backup to populate the new PVC
144-
4. If Longhorn already has the data, dataSourceRef is ignored
133+
When you need to restore a PVC from backup:
145134

146-
**This enables zero-intervention restore:**
147-
- Deploy app → PVC created → auto-restore from S3 → app starts with data
148-
- Longhorn replication is Layer 1 (node failure)
149-
- S3 backup is Layer 2 (cluster loss)
150-
151-
### Manual Restore (if needed)
135+
1. **Scale down the application** (to release the PVC):
136+
```bash
137+
kubectl scale deployment <app> -n <namespace> --replicas=0
138+
```
152139

153-
For manual restore scenarios, you can trigger the ReplicationDestination:
140+
2. **Delete the existing PVC** (if corrupted/lost):
141+
```bash
142+
kubectl delete pvc <pvc-name> -n <namespace>
143+
```
154144

145+
3. **Trigger the ReplicationDestination**:
155146
```bash
156-
# Add manual trigger to force restore
157147
kubectl patch replicationdestination <app>-restore -n <namespace> \
158148
--type merge \
159149
-p '{"spec":{"trigger":{"manual":"restore-'$(date +%s)'"}}}'
150+
```
160151

161-
# Wait for restore to complete
152+
4. **Wait for restore to complete** (creates a new PVC with restored data):
153+
```bash
162154
kubectl get replicationdestination <app>-restore -n <namespace> -w
155+
# Look for: latestImage showing the restored snapshot
163156
```
164157

158+
5. **Rename/recreate the PVC** to match what the app expects, or update app to use the restored PVC name.
159+
160+
6. **Scale up the application**:
161+
```bash
162+
kubectl scale deployment <app> -n <namespace> --replicas=1
163+
```
164+
165+
### Full Cluster Rebuild
166+
167+
After a complete cluster rebuild:
168+
169+
1. Deploy infrastructure (ArgoCD, External Secrets, Longhorn, VolSync)
170+
2. Deploy apps - PVCs will be created empty
171+
3. For each app needing data, trigger ReplicationDestination restore
172+
4. Apps will start with restored data
173+
165174
### Restoring a Database
166175

167176
**CloudNativePG:**
@@ -191,7 +200,7 @@ After a complete cluster rebuild:
191200
|---------|-------------------|---------------|
192201
| Backup tool | Longhorn built-in | VolSync + Restic |
193202
| Backup schedule | RecurringJobs (tiered) | Tiered: hourly (critical) + daily (non-critical) |
194-
| Restore method | Hardcoded restore-job.yaml | Volume Populator (automatic on PVC create) |
203+
| Restore method | Hardcoded restore-job.yaml | Trigger ReplicationDestination manually |
195204
| Database backups | PVC snapshots (inconsistent) | Native WAL archiving (consistent) |
196205
| Complexity | Multiple tiers, shell scripts | Declarative YAML per app |
197206

infrastructure/database/redis/redis-instance/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,3 @@ spec:
1818
requests:
1919
storage: 10Gi
2020
storageClassName: longhorn
21-
dataSourceRef:
22-
kind: ReplicationDestination
23-
apiGroup: volsync.backube
24-
name: redis-data-restore

infrastructure/storage/container-registry/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,3 @@ spec:
1818
resources:
1919
requests:
2020
storage: 10Gi
21-
dataSourceRef:
22-
kind: ReplicationDestination
23-
apiGroup: volsync.backube
24-
name: container-registry-restore

my-apps/ai/khoj/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ spec:
1616
requests:
1717
storage: 1Gi
1818
storageClassName: longhorn
19-
dataSourceRef:
20-
kind: ReplicationDestination
21-
apiGroup: volsync.backube
22-
name: khoj-config-restore
2319
---
2420

2521

my-apps/ai/open-webui/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ spec:
1616
requests:
1717
storage: 5Gi
1818
storageClassName: longhorn
19-
dataSourceRef:
20-
kind: ReplicationDestination
21-
apiGroup: volsync.backube
22-
name: open-webui-data-restore
2319
---
2420
# Add the missing PVC that the deployment is referencing
2521
apiVersion: v1

my-apps/development/fizzy/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,3 @@ spec:
1313
resources:
1414
requests:
1515
storage: 5Gi
16-
dataSourceRef:
17-
kind: ReplicationDestination
18-
apiGroup: volsync.backube
19-
name: fizzy-data-restore

my-apps/development/n8n/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,3 @@ spec:
1313
resources:
1414
requests:
1515
storage: 10Gi
16-
dataSourceRef:
17-
kind: ReplicationDestination
18-
apiGroup: volsync.backube
19-
name: n8n-data-restore

my-apps/development/nginx/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,3 @@ spec:
1515
resources:
1616
requests:
1717
storage: 1Gi
18-
dataSourceRef:
19-
kind: ReplicationDestination
20-
apiGroup: volsync.backube
21-
name: nginx-storage-restore

my-apps/home/frigate/mqtt/mqtt.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ spec:
2828
requests:
2929
storage: 1Gi
3030
storageClassName: longhorn
31-
dataSourceRef:
32-
kind: ReplicationDestination
33-
apiGroup: volsync.backube
34-
name: mosquitto-storage-pvc-restore
3531

3632
---
3733
apiVersion: apps/v1

my-apps/home/home-assistant/pvc.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,3 @@ spec:
1616
requests:
1717
storage: 10Gi
1818
storageClassName: longhorn
19-
dataSourceRef:
20-
kind: ReplicationDestination
21-
apiGroup: volsync.backube
22-
name: home-assistant-config-restore

0 commit comments

Comments
 (0)