ワンクリックで
migrate-volsync-to-kopiur
Migrate an app's PVC backup from VolSync to Kopiur with zero data loss
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Migrate an app's PVC backup from VolSync to Kopiur with zero data loss
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Enforces staged execution discipline on large tasks: a written stage plan, delegation to named fable agents where the runtime supports it, a failable verification check at each stage, and a skeptical self-review before delivery. Trigger when the user explicitly asks ("do this thoroughly", "be systematic", "deep work mode") OR when the task objectively spans multiple files, multiple sources, or multiple sessions. Do NOT trigger on ordinary multi-step requests that a direct attempt handles fine. For a run pinned to a specific model, use fable-opus, fable-sonnet, or fable-haiku instead. Always-on guardrails (verify-before-flag, warning batching, sed safety) live in the companion execution-guardrails skill.
Run Kopiur S3 backups alongside VolSync NFS, verify over days, then cutover with full restore from S3
Scaffold a new app-template application for this home-ops repository
Systematically investigate cluster issues starting from events, following the Flux pipeline down to pod logs
Analyze GitOps repo structure for ordering issues, broken references, missing dependencies, and anti-patterns
Safely upgrade an app's image or chart version, checking for breaking changes and updating the HelmRelease
| name | migrate-volsync-to-kopiur |
| description | Migrate an app's PVC backup from VolSync to Kopiur with zero data loss |
This skill migrates an app's PVC backup from VolSync (perfectra1n/volsync fork with kopia mover) to Kopiur. The existing kopia repository is adopted in place — all snapshots are preserved.
Before migrating any app, verify:
# Kopiur operator healthy
kubectl get helmrelease -n kopiur-system kopiur
# ClusterRepository ready
kubectl get clusterrepository truenas -o jsonpath='{.status.phase}'
# Should output: Ready
The target namespace must include the kopiur/secret component in its kustomization.yaml:
components:
- ../../components/kopiur/secret
Namespaces already configured: services, system-controllers.
Namespaces that need it added before migration: downloads, media, home, ai, database, games, security, storage.
Check kubernetes/apps/<namespace>/kustomization.yaml has:
components:
- ../../components/kopiur/secret
If missing, add it and commit. Verify the secret exists:
kubectl get secret kopiur-repository-secret -n <namespace>
ks.yamlReplace the volsync component with kopiur:
# Before
spec:
dependsOn:
- name: volsync
namespace: storage
components:
- ../../../../components/volsync
postBuild:
substitute:
APP: *app
VOLSYNC_CAPACITY: 5Gi
# After
spec:
dependsOn:
- name: kopiur
namespace: kopiur-system
- name: rook-ceph-cluster
namespace: rook-ceph
components:
- ../../../../components/kopiur/backup
postBuild:
substitute:
APP: *app
KOPIUR_CAPACITY: 5Gi
Variable mapping:
| VolSync | Kopiur | Default |
|---|---|---|
VOLSYNC_CAPACITY | KOPIUR_CAPACITY | 5Gi |
VOLSYNC_ACCESSMODES | KOPIUR_ACCESSMODES | ReadWriteOnce |
VOLSYNC_STORAGECLASS | KOPIUR_STORAGECLASS | ceph-block |
VOLSYNC_CACHE_CAPACITY | (not needed) | — |
CLAIM | (not needed, always ${APP}) | — |
Remove any extra volsync vars (VOLSYNC_CACHE_CAPACITY, CLAIM).
Optional overrides (only if non-default):
KOPIUR_SNAPSHOTCLASS: csi-ceph-blockpool (default)KOPIUR_PUID: 1000 (default)KOPIUR_PGID: 1000 (default)If the helmrelease uses existingClaim: ${CLAIM:=${APP}} or similar, simplify to:
persistence:
data:
existingClaim: ${APP}
The kopiur component creates the PVC named ${APP} automatically.
The kopiur backup component creates a PVC with dataSourceRef pointing to the Restore CR. The old VolSync PVC (which has no dataSourceRef or a different one) must be deleted:
kubectl -n <namespace> delete pvc <app>
If the PVC is stuck in Terminating:
kubectl -n <namespace> patch pvc <app> -p '{"metadata":{"finalizers":null}}' --type=merge
The app pod will restart. Kopiur's Restore with onMissingSnapshot: Continue means:
git add kubernetes/apps/<namespace>/<app>/
git commit -m "feat(<app>): migrate backup from volsync to kopiur"
git push
flux reconcile source git flux-system
flux reconcile ks <app> -n <namespace>
# Kustomization reconciled
kubectl get kustomization -n <namespace> <app>
# Kopiur CRDs created
kubectl get snapshotpolicy,snapshotschedule,restore -n <namespace> | grep <app>
# PVC bound
kubectl get pvc -n <namespace> <app>
# Pod running
kubectl get pods -n <namespace> -l app.kubernetes.io/name=<app>
# First snapshot (after cron fires, usually within the hour)
kubectl get snapshot -n <namespace> -l kopiur.home-operations.com/policy=<app>
kubectl -n <namespace> delete replicationsource <app> 2>/dev/null
kubectl -n <namespace> delete replicationdestination <app>-dst 2>/dev/null
The per-app volsync ExternalSecret (<app>-volsync) can be removed from git later during full decommission.
For each app, the component generates 4 resources (all named ${APP}):
H * * * * (hourly with jitter)onMissingSnapshot: ContinuedataSourceRef pointing to the Restore CR, sized by KOPIUR_CAPACITYIf something goes wrong:
../../../../components/volsync in ks.yamlkubectl -n <namespace> delete pvc <app>VolSync's repository is untouched during the entire migration.
Migrate one app per commit. Verify each before proceeding.
| Issue | Cause | Fix |
|---|---|---|
SnapshotPolicy dry-run failed: field not declared | Component template field in wrong location | Check component YAML against CRD schema |
PVC is invalid: spec is immutable | Old PVC exists without dataSourceRef | Delete the old PVC |
credentials Secret does not exist | Missing kopiur/secret component in namespace | Add to namespace kustomization.yaml |
Restore phase: Pending | No snapshot yet OR missing credentials | Check secret exists, wait for first cron |