[{"data":1,"prerenderedAt":383},["ShallowReactive",2],{"blog-ja-k3s-velero-backup-restore-local-path-provisioner-empty-pvc":3,"blog-related-ja-k3s-velero-backup-restore-local-path-provisioner-empty-pvc":322,"blog-ja-k3s-velero-backup-restore-local-path-provisioner-empty-pvc-alt":310},{"id":4,"title":5,"author":6,"body":7,"date":304,"description":305,"extension":306,"image":307,"locale":308,"meta":309,"navigation":310,"path":311,"seo":312,"stem":313,"tags":314,"__hash__":321},"blog\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc.md","毎晩\"Completed\"と出ていたVeleroのバックアップ。K3sでリストアしたらPVCが空だった理由","Kubo Team",{"type":8,"value":9,"toc":294},"minimark",[10,15,19,22,25,29,36,39,61,68,71,80,84,90,93,117,125,154,157,170,178,182,188,191,199,202,214,218,224,232,235,238,245,248,251,254,275],[11,12,14],"h2",{"id":13},"ある朝k3sの本番ノードが壊れてわかったこと","ある朝、K3sの本番ノードが壊れてわかったこと",[16,17,18],"p",{},"本番のK3sクラスタで、Veleroによる日次バックアップを半年以上運用していたチームがありました。Slackに流れる通知は毎晩「Completed」。誰もバックアップの失敗を疑ったことはありませんでした。",[16,20,21],{},"ところがある朝、ワーカーノードの1台がディスク障害で起動しなくなり、そのノード上のPostgreSQLのPodも一緒に失われました。慌ててVeleroでリストアを実行すると、PodもPVCも問題なく作成されます。しかし中身を見ると、テーブルは空っぽ。データが1行も入っていませんでした。",[16,23,24],{},"K3sとVeleroの組み合わせでバックアップ\u002Fリストア運用を設計している方であれば、他人事ではないはずです。この記事では、K3sでVeleroのバックアップが「成功したのに復元できない」事態がなぜ起きるのか、その切り分け方と、本番環境で取るべき恒久対策を整理します。",[11,26,28],{"id":27},"なぜcompletedなのにデータが無かったのか-k3s標準ストレージという前提","なぜ\"Completed\"なのにデータが無かったのか — K3s標準ストレージという前提",[16,30,31],{},[32,33],"img",{"alt":34,"src":35},"section01","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc\u002Fsection01.webp",[16,37,38],{},"原因は、K3sが標準で同梱しているストレージプロビジョナーにありました。",[16,40,41,42,46,47,54,55,60],{},"K3sにはRancher製の「Local Path Provisioner」がデフォルトで組み込まれており、PersistentVolumeClaimを作成すると、Podがスケジュールされたノード上の",[43,44,45],"code",{},"\u002Fvar\u002Flib\u002Francher\u002Fk3s\u002Fstorage","配下にディレクトリを掘って割り当てます（",[48,49,53],"a",{"href":50,"rel":51},"https:\u002F\u002Fdocs.k3s.io\u002Fadd-ons\u002Fstorage",[52],"nofollow","K3s公式ドキュメント","）。",[48,56,59],{"href":57,"rel":58},"https:\u002F\u002Fgithub.com\u002Francher\u002Flocal-path-provisioner",[52],"Local Path ProvisionerのGitHubリポジトリ","でも、これは分散アプリケーション向けのボリューム移行・レプリケーション・スナップショットを想定した設計ではなく、開発環境や単一ノード構成での「ノード固有データの永続化で十分な場面」を想定したツールだと明記されています。",[16,62,63,64,67],{},"つまりLocal Path Provisionerは、Kubernetesの用語で言うCSIドライバとしてのスナップショット機能（",[43,65,66],{},"CREATE_DELETE_SNAPSHOT","ケーパビリティ）を持っていません。VeleroがCSI連携モードでバックアップを取ろうとしても、スナップショットを作成する相手がそもそも存在しないのです。",[16,69,70],{},"それでもVeleroのバックアップジョブは「Completed」のステータスを返し続けます。Velero自身はKubernetesリソース定義（YAMLの中身）のバックアップには成功しているため、ジョブとしては正常終了だからです。ボリュームの実データが保護されているかどうかは、また別の話だということを、運用者が気づきにくい形で切り離されています。",[16,72,73,74,79],{},"序盤でこの前提に気づいていれば、",[48,75,78],{"href":76,"rel":77},"https:\u002F\u002Fkubo.hexabase.io\u002F",[52],"Kubo","のようにLonghorn等のCSI対応ストレージを標準搭載したマネージドK3s基盤を選ぶという選択肢も検討できたはずです。",[11,81,83],{"id":82},"csiスナップショットのサイレント失敗ポイントを切り分ける","CSIスナップショットのサイレント失敗ポイントを切り分ける",[16,85,86],{},[32,87],{"alt":88,"src":89},"section02","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc\u002Fsection02.webp",[16,91,92],{},"Local Path Provisioner特有の話を抜きにしても、CSIスナップショットの仕組みそのものに、気づきにくい失敗ポイントが複数あります。",[16,94,95,96,99,100,99,103,106,107,110,111,116],{},"まず大前提として、",[43,97,98],{},"VolumeSnapshot"," \u002F ",[43,101,102],{},"VolumeSnapshotContent",[43,104,105],{},"VolumeSnapshotClass"," はKubernetesのコアAPIには含まれない、",[43,108,109],{},"snapshot.storage.k8s.io","グループのCRDです。これらのCRDとsnapshot-controllerのインストールは、Kubernetesディストリビューション側の責任とされています（",[48,112,115],{"href":113,"rel":114},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fvolume-snapshots\u002F",[52],"Kubernetes公式ドキュメント","）。K3sのような軽量ディストリビューションでは、ここが未導入のまま運用されているケースも珍しくありません。",[16,118,119,120,54],{},"その上で、よくある失敗パターンとして以下が挙げられます（",[48,121,124],{"href":122,"rel":123},"https:\u002F\u002Fwww.netdata.cloud\u002Fguides\u002Fkubernetes\u002Fkubernetes-volume-snapshot-failures\u002F",[52],"Netdataのガイド",[126,127,128,136,142,148],"ul",{},[129,130,131,135],"li",{},[132,133,134],"strong",{},"CRD・snapshot-controllerの未導入",": VolumeSnapshotが永遠にVolumeSnapshotContentとバインドされない",[129,137,138,141],{},[132,139,140],{},"VolumeSnapshotClassのdriver名の不一致",": イベントすら出ないまま、サイドカーが完全に沈黙する",[129,143,144,147],{},[132,145,146],{},"CSIドライバがスナップショット未対応",": サイドカーのリクエストがドライバ側で「未実装」として拒否される",[129,149,150,153],{},[132,151,152],{},"リストア時のstorageClassName指定ミス",": スナップショット復元ではなく、空のボリュームが新規プロビジョニングされる",[16,155,156],{},"最後の「storageClassName指定ミス」が特に厄介です。PVCもPodも正常に作成されるため見た目には問題がなく、実際にデータを確認するまで誰も気づけません。",[16,158,159,160,163,164,169],{},"Veleroを使う場合はさらに、対象のVolumeSnapshotClassに",[43,161,162],{},"velero.io\u002Fcsi-volumesnapshot-class: \"true\"","というラベルを付与しておく必要があります（",[48,165,168],{"href":166,"rel":167},"https:\u002F\u002Fvelero.io\u002Fdocs\u002Fv1.13\u002Fcsi\u002F",[52],"Velero公式CSIドキュメント","）。このラベルが抜けていると、「対象プロビジョナーのVolumeSnapshotClassが見つからない」というエラーでスナップショット作成自体が失敗します。",[16,171,172,173,177],{},"こうした構成の整合性チェックを毎回自分たちで維持し続けるのは、小さなチームには重い負担です。",[48,174,176],{"href":76,"rel":175},[52],"Kubo Cloud","はCSI対応ストレージとモニタリングを標準搭載しているため、この手の「ラベル1つの付け忘れ」に起因する事故のリスクをそもそも減らせます。",[11,179,181],{"id":180},"正しい代替策-file-system-backupとその限界","正しい代替策 — File System Backupとその限界",[16,183,184],{},[32,185],{"alt":186,"src":187},"section03","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc\u002Fsection03.webp",[16,189,190],{},"Local Path Provisionerのようにスナップショット非対応のストレージでボリュームデータを守るには、Veleroの File System Backup（FSB）を使う必要があります。",[16,192,193,194,54],{},"FSBは、ノードごとに動くnode-agentのDaemonSetが、Pod volumeをhostPathマウント経由で読み取り、Kopia（旧Resticから移行）でオブジェクトストレージへアップロードする仕組みです。EFSやAzureFile、NFS、そしてLocal Path Provisionerのようなローカルストレージなど、CSIスナップショットに対応していないボリュームに対しては、FSBが現実的な選択肢になります（",[48,195,198],{"href":196,"rel":197},"https:\u002F\u002Fvelero.io\u002Fdocs\u002Fv1.13\u002Ffile-system-backup\u002F",[52],"Velero公式File System Backupドキュメント",[16,200,201],{},"ただしFSBにも限界があります。FSBは稼働中のファイルシステムから直接ファイルを読み取るため、スナップショット方式のような「ある瞬間の状態」をそのまま切り取ることができません。公式ドキュメントでも、スナップショット方式に比べて一貫性が劣ることが明記されています。データベースのようにファイルが頻繁に書き換わるワークロードでは、バックアップの瞬間にクラッシュコンシステント（突然電源を切ったのと同程度の整合性）止まりになる可能性があります。",[16,203,204,205,54,210,213],{},"アプリケーション一貫性のあるバックアップが必要な場合は、Veleroのバックアップフック機能で、直前にファイルシステムをフリーズする、あるいはデータベース自身のダンプコマンドを実行するといった対応が必要です（",[48,206,209],{"href":207,"rel":208},"https:\u002F\u002Fvelero.io\u002Fdocs\u002Fv1.9\u002Fbackup-hooks\u002F",[52],"Velero公式バックアップフックドキュメント",[43,211,212],{},"fsfreeze","のコマンドをPodアノテーションで指定するだけで実現できますが、裏を返せば「フックを自分で書いて動作確認までする」という追加の運用タスクが発生するということでもあります。",[11,215,217],{"id":216},"バックアップ成功ログを信じない運用-リストアドリルを仕組み化する","\"バックアップ成功\"ログを信じない運用 — リストアドリルを仕組み化する",[16,219,220],{},[32,221],{"alt":222,"src":223},"section04","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc\u002Fsection04.webp",[16,225,226,227,54],{},"ここまで見てきたように、Veleroの「Completed」というステータスは、あくまで「バックアップコントローラがワークフローを最後まで処理できた」ことの証明にすぎません。実際にそのバックアップでアプリケーションを復元できるかどうかは、別の軸で検証する必要があります（",[48,228,231],{"href":229,"rel":230},"https:\u002F\u002Fvelero.io\u002Fblog\u002Fcsi-integration",[52],"Velero公式CSI統合解説",[16,233,234],{},"よくある誤解として、「K3sのetcdスナップショットを取っているから、バックアップは万全」という思い込みがあります。etcdスナップショットが保護するのはKubernetesのリソース定義（PodやServiceのYAML相当の情報）であって、PersistentVolume上のアプリケーションデータそのものは含みません。データベースのPVがノード障害で失われれば、etcdスナップショットからクラスタ状態を復元しても、データベースの中身は空のまま起動します。",[16,236,237],{},"この落とし穴を避けるために有効なのが、定期的な「リストアドリル」です。本番とは隔離されたnamespaceやクラスタにVeleroで実際にリストアし、アプリケーションが正しく起動してデータが読み込めるかを確認します。これを月次、少なくとも四半期に1回は実施し、実測のRTO（目標復旧時間）・RPO（目標復旧時点）を記録しておくことで、「バックアップが取れている」という状態と「実際に復旧できる」という状態のギャップを事前に発見できます。",[16,239,240,241,244],{},"こうした検証サイクルを人手で回し続けるのは、ただでさえ手一杯なインフラチームには重荷です。",[48,242,78],{"href":76,"rel":243},[52],"なら、K3sベースの本格的なKubernetes環境にCSI対応ストレージと運用監視が組み込まれており、バックアップ設計そのものを自前でゼロから作り込む必要がなくなります。コスト面でも、Kubo Cloudは月額48,000円〜とEKSの約58%のコストで運用できるため、バックアップ基盤にかける検証工数を他の開発に振り向けやすくなります。",[11,246,247],{"id":247},"まとめ",[16,249,250],{},"K3s標準のLocal Path Provisionerは、開発・CI用途に最適化されたシンプルなストレージであり、CSIスナップショットには対応していません。これを本番環境でそのまま使い続けると、Veleroのバックアップジョブが「Completed」を返し続けていても、実際にはボリュームデータが保護されていないという状態に陥りがちです。",[16,252,253],{},"対策の要点は3つです。",[255,256,257,263,269],"ol",{},[129,258,259,262],{},[132,260,261],{},"本番環境ではLocal Path Provisionerをそのまま使わない",": LonghornなどCSI対応ストレージへの移行を検討する",[129,264,265,268],{},[132,266,267],{},"CSIスナップショットが使えない場合はFile System Backupを使い、限界を理解する",": クラッシュコンシステント止まりであることを前提に、必要ならバックアップフックを併用する",[129,270,271,274],{},[132,272,273],{},"バックアップは「取れているか」ではなく「戻せるか」で評価する",": 定期的なリストアドリルをスケジュール化し、RTO\u002FRPOを実測する",[16,276,277,278,281,282,287,288,293],{},"バックアップ・ディザスタリカバリの設計と検証を継続的に回し続ける負荷を減らしたい場合は、CSI対応ストレージを標準搭載した",[48,279,78],{"href":76,"rel":280},[52],"や、データを完全に自社管理したい場合の",[48,283,286],{"href":284,"rel":285},"https:\u002F\u002Fwww.hexabase.com\u002Fproduct\u002Fkubo\u002Fon-premise",[52],"Kubo On-Premise","の構成も選択肢の一つです。まずは",[48,289,292],{"href":290,"rel":291},"https:\u002F\u002Fwww.hexabase.com\u002Fcontact-us\u002F",[52],"お問い合わせ","から、現在のバックアップ構成を相談してみてください。",{"title":295,"searchDepth":296,"depth":296,"links":297},"",2,[298,299,300,301,302,303],{"id":13,"depth":296,"text":14},{"id":27,"depth":296,"text":28},{"id":82,"depth":296,"text":83},{"id":180,"depth":296,"text":181},{"id":216,"depth":296,"text":217},{"id":247,"depth":296,"text":247},"2026-10-13","K3s標準のlocal-path-provisionerはCSIスナップショット非対応。Veleroのバックアップが\"Completed\"でも、障害時のリストアでPVCが空になることがある。原因の切り分けとFile System Backup・リストアドリルによる対策を解説する。","md","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc\u002Ftitle.webp","ja",{},true,"\u002Fblog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc",{"title":5,"description":305},"blog\u002Fja\u002Fk3s-velero-backup-restore-local-path-provisioner-empty-pvc",[315,316,317,318,319,320],"k3s","kubernetes","velero","backup","disaster-recovery","csi","OwZgycyvtJb9bkvJdMnSC-qVUYURDe2HrzeIHwb3czk",[323,332,341,351,363,373],{"path":324,"title":325,"description":326,"date":327,"tags":328},"\u002Fblog\u002Fja\u002Fk3s-sealed-secrets-gitops-rebuild-private-key-lost","GitOpsで全部コード化してたのに。K3sクラスタを作り直したら、Sealed Secretsが一つも復号できなくなった理由","K3sクラスタをGitOpsで再構築したらSealed Secretsが全て復号できない状態に陥った。原因は秘密鍵の扱いにある。障害の仕組みと復旧手順、再発防止の運用設計を解説する。","2026-10-15",[315,316,329,330,331,319],"sealed-secrets","secrets-management","gitops",{"path":333,"title":334,"description":335,"date":336,"tags":337},"\u002Fblog\u002Fja\u002Fk3s-etcd-snapshot-restore-token-cluster-reset-pitfalls","自動etcdスナップショットは毎日取れていた。K3sのリストアが本番障害で動かなかった理由","K3sのetcdスナップショットは正常に取れていたのに、本番障害でリストアが失敗した——トークン管理、S3リストア事故、cluster-resetの落とし穴という3つの実例から、embedded etcdバックアップの本当のリスクを解説する。","2026-09-21",[315,316,338,339,319,340],"etcd","backup-restore","high-availability",{"path":342,"title":343,"description":344,"date":345,"tags":346},"\u002Fblog\u002Fja\u002Fk3s-hpa-containerresource-sidecar-utilization-dilution","HPAがサイドカーの分まで合算してスケールしていた。KubernetesのContainerResourceという盲点","KubernetesのHPAはPod内の全コンテナの使用量を合算して利用率を計算するため、Istioサイドカーやログエージェントの負荷が判定を薄める。ContainerResourceメトリクスで解決する方法をK3s\u002FKubo文脈で解説する。","2026-10-21",[315,316,347,348,349,350],"hpa","containerresource","autoscaling","service-mesh",{"path":352,"title":353,"description":354,"date":355,"tags":356},"\u002Fblog\u002Fja\u002Fk3s-vs-kubernetes-cni-flannel-default-comparison","K3s vs 標準Kubernetes、CNIの出発点はここまで違う。Flannel標準搭載とCNI選択制が生む差","K3sはFlannelをデフォルト同梱し、標準KubernetesはCNI未選定の状態から始まる。この出発点の違いがNetworkPolicyの可否や通信性能にどう影響するかを、K3s\u002FKubernetes\u002FCalico\u002FCiliumの公式ドキュメントをもとに比較・解説する。","2026-10-20",[315,316,357,358,359,360,361,362],"cni","flannel","calico","cilium","networkpolicy","networking",{"path":364,"title":365,"description":366,"date":367,"tags":368},"\u002Fblog\u002Fja\u002Fk3s-topology-spread-constraints-poddisruptionbudget-node-drain-pending","ノードをdrainしたらPodがPendingのまま戻らなかった。K3sでTopology Spread ConstraintsとPodDisruptionBudgetが衝突する理由","K3s本番でノードをdrainしたら一部PodがPendingのまま戻らなかった。原因はTopology Spread ConstraintsのmaxSkewとPodDisruptionBudgetの衝突。drainがノード数不足を自ら作り出す仕組みを公式ドキュメントベースで検証する。","2026-10-19",[315,316,369,370,371,372],"topology-spread-constraints","poddisruptionbudget","scheduling","node-drain",{"path":374,"title":375,"description":376,"date":377,"tags":378},"\u002Fblog\u002Fja\u002Fkyverno-validatingadmissionpolicy-cel-migration-silent-bypass","CELに書き換えたポリシーは、本当に同じ意味なのか。KyvernoからValidatingAdmissionPolicyへの移行で\"黙って素通り\"したリソースの正体","KyvernoのClusterPolicyが廃止へ向かう中、ValidatingAdmissionPolicy（CEL）に移行したら一部リソースだけ検証が素通りしていた。原因のCELランタイムエラーとfailurePolicyの罠、安全な移行手順を解説する。","2026-10-18",[315,316,379,380,381,382],"validatingadmissionpolicy","kyverno","cel","admission-control",1792592611942]