Velero復元テスト

経緯

veleroのバックアップの復元テストをしたかったのだけれども、 あまりにも面倒くさくて、Claude Codeに丸投げした。

復元完了後、veleroのrestores/ に復元レポートが保存される。

使用モデル、かかったコストは以下。CLIからは、/statusからのSessionで表示可能。

/status
  Total cost:            $2.81
  Total duration (API):  8m 28s
  Total duration (wall): 36m 20s
  Total code changes:    362 lines added, 0 lines removed
  Usage by model:
      claude-haiku-4-5:  303 input, 24 output, 0 cache read, 0 cache write ($0.0004)
     claude-sonnet-4-5:  281 input, 22.3k output, 5.1m cache read, 252.0k cache write ($2.80)

500円近くの出費はまあまあ痛いが、人間がやっていると、2時間近く消費するわけで。 AIを積極的に使用した方がいいと思われる。

余談だが、復元したPodの削除もAIに任せたら、コストが約1.5倍まで跳ね上がってしまった。

人でできる作業は、人でした方がいい。 普通に、Docker Desktopの歯車から、リセット->k8sの機能無効すればいいだけだった。 削除指示なんかするんじゃなかった。

以下、ほぼ完全にAI生成の文章になる。 次の手順でこしらえた。Claude Code 生成 -> Claude Code で秘匿情報等をマスク -> kiro で再度マスク -> 私が確認 別にこの手順自体に意味はない。記録として残しておく。

実施日時

2026年6月13日

概要

Cloudflare R2に保存されたVeleroバックアップからKubernetesクラスターへの復元テストを実施しました。


Velero復元テスト レポート(公開版)

環境情報

バックアップソース

  • S3エンドポイント: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
  • バケット名: <BUCKET_NAME>
  • プロバイダー: Cloudflare R2 (S3互換)
  • 利用可能なバックアップ: 23個(velero-mybackup-20260529XXXXXX ~ 20260611XXXXXX)

ターゲット環境

  • Kubernetesクラスター: Docker Desktop for Windows
  • ノード: 1台 (docker-desktop)
  • ストレージクラス: hostpath (デフォルト)
  • Veleroバージョン: v1.18.1
  • Velero Plugin: velero-plugin-for-aws:v1.11.0

実施した手順と対応

1. Veleroのインストール

1.1 認証情報とnamespaceの作成

kubectl create namespace velero
kubectl create secret generic cloud-credentials -n velero \
  --from-literal=cloud='[default]
aws_access_key_id=<ACCESS_KEY_ID>
aws_secret_access_key=<SECRET_ACCESS_KEY>'

1.2 Veleroサーバーのインストール

./velero-v1.18.1-windows-amd64/velero-v1.18.1-windows-amd64/velero.exe install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.11.0 \
  --bucket <BUCKET_NAME> \
  --secret-file credentials/cloud \
  --backup-location-config region=auto,s3Url=https://<ACCOUNT_ID>.r2.cloudflarestorage.com,s3ForcePathStyle=true \
  --use-node-agent \
  --namespace velero

重要: 初期設定では誤ってバケット名を<ACCOUNT_ID>(アカウントID)に設定していましたが、正しいバケット名は<BUCKET_NAME>でした。


2. 発生した問題と解決策

問題1: BackupStorageLocationがUnavailable

症状:

BackupStorageLocation "default" is unavailable: 
rpc error: code = Unknown desc = operation error S3: ListObjectsV2, 
https response error StatusCode: 403, RequestID: , HostID: , 
api error AccessDenied: Access Denied

原因: バケット名が間違っていた(アカウントIDではなく実際のバケット名<BUCKET_NAME>を指定する必要があった)

解決策:

kubectl patch backupstoragelocation default -n velero --type merge \
  -p '{"spec":{"objectStorage":{"bucket":"<BUCKET_NAME>"}}}'

結果: BackupStorageLocationがAvailableになり、30個のバックアップが同期された


問題2: node-agentがCreateContainerErrorで起動失敗

症状:

Error: Error response from daemon: invalid volume specification: 
'\var\lib\kubelet\pods:/host_pods:rslave': invalid mount config for type "volume": 
field BindOptions must not be specified

原因: Windows環境でのパス表記の問題。Velero installコマンドがWindowsパス形式(\var\lib\kubelet\pods)を設定してしまった

解決策:

kubectl patch daemonset node-agent -n velero --type='json' -p='[
  {"op": "replace", "path": "/spec/template/spec/volumes/0/hostPath/path", "value": "/var/lib/kubelet/pods"},
  {"op": "replace", "path": "/spec/template/spec/volumes/1/hostPath/path", "value": "/var/lib/kubelet/plugins"}
]'

kubectl delete pod -n velero -l name=node-agent

結果: node-agentが正常に起動し、ボリューム復元が可能になった


問題3: PVCがPending状態

症状:

storageclass.storage.k8s.io "local-path" not found

原因: バックアップ元のクラスターではlocal-pathストレージクラスを使用していたが、復元先のクラスターにはhostpathしか存在しなかった

解決策: local-pathストレージクラスを作成

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-path
provisioner: docker.io/hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: false
kubectl apply -f local-path-storageclass.yaml

結果: すべてのPVCがBound状態になり、Podが起動可能になった


問題4: PodVolumeRestoreがFailed

症状:

error to expose PVR: error to get pod volume path: 
error identifying unique volume path on host for volume database in pod <commafeed-postgresql-pod>: 
expected one matching path: /host_pods/.../volumes/*/pvc-..., got 0

原因: PVCがPending状態だったため、Podが起動前にPodVolumeRestoreが実行され、ボリュームパスが見つからなかった

解決策: ストレージクラス作成後、失敗したPodを削除して再作成

kubectl delete pod -n <commafeed_ns> <commafeed-postgresql-pod> --force --grace-period=0
kubectl delete pod -n <redmine_ns> <redmine-pod> <redmine-mariadb-pod> --force --grace-period=0
kubectl delete pod -n <commafeed_ns> <commafeed-main-pod> --force --grace-period=0

結果: 新しいPodが作成され、ボリューム復元が正常に実行された


問題5: Redmine Podがイメージ取得エラー

症状:

Failed to pull image "docker.io/bitnami/redmine:6.0.6-debian-12-r6": 
Error response from daemon: manifest for bitnami/redmine:6.0.6-debian-12-r6 not found: 
manifest unknown: manifest unknown

原因: バックアップ時に使用していたBitnamiのRedmineイメージタグが、Docker Hubから削除されたか存在しない

対応: 本レポート作成時点では未解決。MariaDBは正常に復元・起動済み


復元結果

最終ステータス

  • 復元名: restore-velero-mybackup-XXXXXXXXXXXXXXXX-XXXXXXXX-XXXXXX
  • バックアップ名: velero-mybackup-20260611XXXXXX
  • フェーズ: PartiallyFailed
  • 開始時刻: 2026-06-13 00:52:25 JST
  • 完了時刻: 2026-06-13 01:05:48 JST
  • 所要時間: 約13分
  • エラー数: 7
  • 警告数: 107

復元されたリソース

  • 総アイテム数: 694個 (すべて復元完了)
  • PersistentVolumeRestore: 11個中5個完了、4個失敗、2個その他

正常に復元されたアプリケーション

Commafeed (<commafeed_ns> namespace)

✅ <commafeed-postgresql-pod>   1/1 Running
✅ <commafeed-main-pod>         1/1 Running
✅ Service: <commafeed-main-svc> (LoadBalancer)
✅ Service: <commafeed-postgresql-svc> (ClusterIP)
✅ PVC: <commafeed-postgresql-pvc> (Bound)
✅ PVC: <commafeed-data-pvc> (Bound)

Redmine MariaDB

✅ <redmine-mariadb-pod>  1/1 Running
✅ PVC: <redmine-mariadb-pvc> (Bound)
✅ PVC: <redmine-pvc> (Bound)

未解決の問題

❌ <redmine-pod> - ImagePullBackOff (Bitnami Redmineイメージが利用不可)

警告とエラーの詳細

警告 (107件)

主に既存のクラスターリソース(CRD、ClusterRole等)が既に存在していたための警告。これは正常な動作。

例:

  • CustomResourceDefinition:backuprepositories.velero.io already exists
  • ClusterRole:cluster-admin already exists
  • 等々

エラー (7件)

主にPodVolumeRestoreの失敗:

  • ボリュームパスが見つからない(Pod再作成で解決)
  • イメージ取得エラー(Redmine - 未解決)

ベストプラクティスと推奨事項

1. 事前準備

  • ✅ ストレージクラスの互換性確認
  • ✅ 使用するDockerイメージの可用性確認
  • ✅ S3バケット名とエンドポイントの正確な情報

2. Windows環境での注意点

  • node-agentのボリュームマウントパスがWindowsパス形式になる問題に注意
  • インストール後、必ずDaemonSetの設定を確認・修正

3. 復元手順

  1. Veleroサーバーをインストール
  2. BackupStorageLocationの設定と検証
  3. node-agentのパス修正(Windows環境の場合)
  4. 必要なストレージクラスの作成
  5. 復元実行
  6. 失敗したPodの削除と再作成

4. トラブルシューティング

  • BackupStorageLocationのステータス確認: velero backup-location get
  • node-agentのログ確認: kubectl logs -n velero -l name=node-agent
  • PodVolumeRestoreの状態確認: kubectl get podvolumerestore -n velero
  • 失敗したPodは削除して再作成することで解決する場合が多い

必須の設定変更まとめ

1. BackupStorageLocationのバケット名修正

kubectl patch backupstoragelocation default -n velero --type merge \
  -p '{"spec":{"objectStorage":{"bucket":"<BUCKET_NAME>"}}}'

2. node-agentのボリュームパス修正(Windows環境)

kubectl patch daemonset node-agent -n velero --type='json' -p='[
  {"op": "replace", "path": "/spec/template/spec/volumes/0/hostPath/path", "value": "/var/lib/kubelet/pods"},
  {"op": "replace", "path": "/spec/template/spec/volumes/1/hostPath/path", "value": "/var/lib/kubelet/plugins"}
]'

3. local-pathストレージクラスの作成

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-path
provisioner: docker.io/hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate

結論

Veleroによる復元はほぼ成功しました。以下の点が確認できました:

成功した点

✅ S3(Cloudflare R2)からのバックアップ同期
✅ 694個のKubernetesリソースの復元
✅ Persistent Volumeデータの復元
✅ アプリケーション(Commafeed)の完全復元と起動
✅ データベース(PostgreSQL、MariaDB)の復元と起動

課題

⚠️ Windows環境特有のパス問題(対応方法確立)
⚠️ ストレージクラスの互換性問題(対応方法確立)
❌ 廃止されたDockerイメージへの依存(別の問題)

総評

本復元テストにより、Cloudflare R2に保存されたVeleroバックアップからの復元が可能であることが実証されました。Windows Docker Desktop環境特有の問題については、本レポートに記載した対応方法で解決可能です。