今回はKubernetesリソースのバックアップ・リストアを実現するVeleroを使ってみます。
Cloud Nativeな世界のバックアップ・リストア
Veleroを動かす前に、バックアップ・リストアについていくつか書いておきます。
そもそもバックアップ・リストアを実現する理由としては、大きく以下の3つの理由があるかと思います。
- DR: システムの稼働する主要サイトで災害等が発生し、システムとしての機能を失ったときに、別のサイトにてシステムを再稼働させる。
- オペレーションのリカバリ: 業務の中でデータの紛失や論理的破壊が発生したときに、バックアップデータから対象のデータを復旧する。
- アーカイブ: 法規制などに対応するため長期的なデータ保存が必要となるときに、バックアップデータを使用する。
また、これらの目的を達成することに加え、「Cloud Nativeな世界でのバックアップ・リストア」という観点で調べてみると、以下のような観点を合わせて検討することが重要となるようです。
サーバーでなくワークロード単位でバックアップ
Cloud Nativeな世界では、アーキテクチャの疎結合化により、それにかかわる組織やチームも疎結合となり、各チームが自律的に動けることを目指します。自律的なチームが複数に分かれると、各チームはそれぞれ独自のデータやワークロードをもつことになり、これらが分散して存在することになります。そのため、これまでの、データが一極集中管理されたシステムではなく、各チームごとにデータを所持するシステムでは、サーバー単位でなくワークロード単位でのバックアップが求められます。
例えば1つのKubernetesクラスター上で複数チームがワークロードを載せている場合、クラスターやNode単位でバックアップを取ると、バックアップデータには自分たちのワークロード以外のものも多く含まれ、そこから必要なものを探す手間が発生します。またリストアの際にクラスター・Node単位で実行するとなると、他のチームへの影響も発生し、組織全体のパフォーマンスが低下する要因となりえます。ワークロード単位でバックアップを取ることで、必要なものを見つけやすく、また自チーム内にのみ影響範囲を抑えることが可能となります。
データに着目してバックアップする
現在はCloud Nativeに関わらずインフラリソースのIaC化が進んでおり、必要なリソースはIaCファイルから作成することができます。バックアップを取得する際も、インフラリソースは定義ファイルから再現できるため、重要度は高くありません。一方で、そこに含まれる動的なデータは復元が難しいため、バックアップデータとして重要度が高くなります。
例としては以下のようなものが挙げられます。
- ソースコードやビルドによる成果物など
- アプリケーションの設定情報
- インフラリソースの「状態」:インスタンス数やポート番号など
- アプリ起動中に保存されたデータを含むデータベース
- オブジェクトストレージに保存されたファイル
その他
その他、Cloud Nativeな環境で利用するバックアップ・リストアツールには、以下のような要素が含まれているとなお良いでしょう。
複数環境・プロバイダーへの汎用性: オンプレやクラウドなど複数の環境で動作するシステムに対し、汎用的なツールを利用することで、不要な学習コストの削減やリストアのスピードアップにつながるでしょう。一方で、一つのクラウドプロバイダーのみを利用する予定の場合、各プロバイダーの提供するバックアップソリューションを利用することが、最も手軽かつ安全な場合もあります。
スケーラビリティ: システムの構成や規模が動的に変化するCloud Nativeなアーキテクチャでは、システムの構成変更に追従する、あるいは新規追加が容易なツールであるほど利用価値が高いといえるでしょう。
※参考ドキュメント:
The New Stack - Cloud Native Backups, Disaster Recovery and Migrations on Kubernetes
HYCU blog - Why Cloud Architects Need to Care About Cloud-Native Backup & Recovery
バックアップ・リストアで考えること
バックアップ・リストアを設計・実装するうえで考えなければならないことは色々とあります。以下にその一例を記載します。
- 利用目的
- 取得頻度
- バックアップ手法
- 保存場所
- 保存期間
- 対象リソース
これらの観点に対して、Veleroはどのように対応しているかを見ていきます。
利用目的
バックアップ・リストアは、その利用目的を明確にすることが重要です。バックアップ・リストアを用いる理由は既に記載しましたが、Veleroでは以下のような用途を想定しています(Veleroドキュメントより)。
取得頻度
バックアップデータをどのような頻度で取得するかは、バックアップの利用目的によって変わります。作業前にバックアップデータを取得する、スケジュール実行で1日1回取得する、など、複数のタイミングでデータ取得を実行できる必要があります。
Veleroではコマンドからバックアップ・リストアを実行することができます。また velero schedule
コマンドにより、Cron形式で指定したスケジュール実行も可能です。
バックアップ手法
バックアップの取得方式としては、以下のようなものがあります。
- 完全バックアップ:バックアップ対象のすべてのデータをバックアップする
- 増分バックアップ:前回のバックアップ以降に更新されたデータのみをバックアップする
- 差分バックアップ:前回の完全バックアップ以降に更新されたデータのみをバックアップする
Veleroでは明確にどの手法か書かれてはいないように見えますが、実際に試したところでは完全バックアップしか提供していないように見えます。
保存場所
Veleroではオブジェクトストレージバケットをバックアップ・リストアデータの保存先として利用できます。オンプレ・クラウドどちらも利用可能です。
保存期間
Veleroではバックアップデータの保存期間は --ttl
で設定することができます(Veleroドキュメントより)。デフォルトの保存期間は30日間です。またオブジェクトストレージに保存されたデータが削除されると、Veleroがそれを検知・同期して、クラスター上のバックアップデータを削除する動きになります。
対象リソース
VeleroではKubernetesクラスターリソース及びPersistent Volumeが保存対象です。Podなどのワークロードはjson形式で保存します。
PersistentVolumeでクラウドプロバイダーの提供するブロックストレージを利用している場合、PersistentVolumeに格納されたデータをスナップショットとして保存します。
Velero docs - Output file format
Veleroの紹介
構成
veleroの構成は以下の図のようになります。Veleroでは BackupController
というControllerが中心となってバックアップ・リストア機能を提供します。Backup
というCustom Resourceが作成されると、 BackupController
はKubernetes APIにクエリを投げてバックアップデータを収集し、オブジェクトストレージへバックアップデータのアップロードを行います。
※Veleroドキュメントより
Veleroを使ってみる
ここからVeleroを実際に動かしてみます。利用した環境は以下の通りです。
- Kubernetes Version: ver 1.19
- Kubernetes Cluster: Amazon EKSを利用
- Velero version: v1.5.3
- S3 bucket:
velero-backup-20210523
※Amazon EKS上でVeleroを動かす際は、EKS Workshopのページに手順がコンパクトにまとまっているので楽です。
Veleroを利用するには、 velero
CLIのインストールと、クラスター上へのController等リソースの配置が必要になります。CLIのインストールはこちらのページから行い、Controllerなどのデプロイは、マニフェストファイルを用意するほか、velero
CLIからも実行することが可能です。今回はCLIを利用する方法で準備を行いました。
$ velero install \ > --provider aws \ > --plugins velero/velero-plugin-for-aws:v1.1.0 \ > --bucket velero-backup-20210523 \ > --backup-location-config region=ap-northeast-1 \ > --snapshot-location-config region=ap-northeast-1 \ > --secret-file ./credentials-velero $ kubectl get all -n velero NAME READY STATUS RESTARTS AGE pod/velero-679457dc45-hfn9f 1/1 Running 0 101s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/velero 1/1 1 1 101s NAME DESIRED CURRENT READY AGE replicaset.apps/velero-679457dc45 1 1 1 101s
今回はAWSを利用するため --plugins velero/velero-plugin-for-aws:v1.1.0
というオプションを指定しています。指定するバージョンはこちらのページを見て変更してください。また --secret-file
で指定したファイルには、AWSにアクセスするのに必要な秘匿情報を記載しています。
※その他の利用可能なプロバイダーはこちらのページに記載されています。
Veleroのインストールが完了したので、バックアップの取得とリストアを試します。今回はEKSクラスターをもう一つ作成し、異なるクラスター上に同じワークロードを作成できるか試しました。
バックアップの取得
# バックアップ対象 $ kubectl get pods NAME READY STATUS RESTARTS AGE velero-testpod 1/1 Running 0 29s $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-4b04c94b-c9bd-4206-8806-0e783b5ccce4 8Gi RWO Delete Bound default/velero-pvc gp2 2m45s $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE velero-pvc Bound pvc-4b04c94b-c9bd-4206-8806-0e783b5ccce4 8Gi RWO gp2 81s # バックアップの作成 $ velero backup create velero-backup-`date +%Y%m%d%H%M` Backup request "velero-backup-202105230844" submitted successfully. Run `velero backup describe velero-backup-202105230844` or `velero backup logs velero-backup-202105230844` for more details. # バックアップ作成結果の確認 $ velero backup describe velero-backup-202105230844 Name: velero-backup-202105230844 Namespace: velero Labels: velero.io/storage-location=default Annotations: velero.io/source-cluster-k8s-gitversion=v1.19.8-eks-96780e velero.io/source-cluster-k8s-major-version=1 velero.io/source-cluster-k8s-minor-version=19+ Phase: Completed Errors: 0 Warnings: 0 Namespaces: Included: * Excluded: <none> Resources: Included: * Excluded: <none> Cluster-scoped: auto Label selector: <none> Storage Location: default Velero-Native Snapshot PVs: auto TTL: 720h0m0s Hooks: <none> Backup Format Version: 1.1.0 Started: 2021-05-23 08:44:43 +0900 JST Completed: 2021-05-23 08:44:50 +0900 JST Expiration: 2021-06-22 08:44:43 +0900 JST Total items to be backed up: 353 Items backed up: 353 Velero-Native Snapshots: 1 of 1 snapshots completed successfully (specify --details for more information)
クラスターの用意
# 別クラスターの用意 $ eksctl create cluster -f eks-clusterconfig-2.yml $ eksctl get cluster 2021-05-23 10:18:20 [ℹ] eksctl version 0.40.0 2021-05-23 10:18:20 [ℹ] using region ap-northeast-1 NAME REGION EKSCTL CREATED eks-cluster ap-northeast-1 True eks-cluster-2 ap-northeast-1 True★ # 別クラスターでのVeleroインストール # バックアップデータの保存されているオブジェクトストレージを指定 $ velero install \ > --provider aws \ > --plugins velero/velero-plugin-for-aws:v1.1.0 \ > --bucket velero-backup-20210523 \ > --backup-location-config region=ap-northeast-1 \ > --snapshot-location-config region=ap-northeast-1 \ > --secret-file ./credentials-velero # 作成したバックアップが確認できる $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-202105230844 Completed 0 0 2021-05-23 08:44:43 +0900 JST 29d default <none>
リストアによるリソース作成
# リストアの実行 $ velero restore create --from-backup velero-backup-202105230844 Restore request "velero-backup-202105230844-20210523095302" submitted successfully. Run `velero restore describe velero-backup-202105230844-20210523095302` or `velero restore logs velero-backup-202105230844-20210523095302` for more details. # リストア結果の確認 $ velero restore describe velero-backup-202105230844-20210523095302 Name: velero-backup-202105230844-20210523095302 Namespace: velero Labels: <none> Annotations: <none> Phase: Completed Started: 2021-05-23 09:53:13 +0900 JST Completed: 2021-05-23 09:53:44 +0900 JST Warnings: Velero: <none> Cluster: could not restore, customresourcedefinitions.apiextensions.k8s.io "backups.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "backupstoragelocations.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "deletebackuprequests.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "downloadrequests.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "podvolumebackups.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "podvolumerestores.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "resticrepositories.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "restores.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "schedules.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "serverstatusrequests.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, customresourcedefinitions.apiextensions.k8s.io "volumesnapshotlocations.velero.io" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, mutatingwebhookconfigurations.admissionregistration.k8s.io "pod-identity-webhook" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, mutatingwebhookconfigurations.admissionregistration.k8s.io "vpc-resource-mutating-webhook" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, validatingwebhookconfigurations.admissionregistration.k8s.io "vpc-resource-validating-webhook" already exists. Warning: the in-cluster version is different than the backed-up version. Namespaces: default: could not restore, endpoints "kubernetes" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, endpointslices.discovery.k8s.io "kubernetes" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, services "kubernetes" already exists. Warning: the in-cluster version is different than the backed-up version. kube-system: could not restore, configmaps "aws-auth" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, configmaps "cp-vpc-resource-controller" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, configmaps "eks-certificates-controller" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, configmaps "extension-apiserver-authentication" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, configmaps "kube-proxy" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, endpoints "kube-controller-manager" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, endpoints "kube-dns" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, endpoints "kube-scheduler" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, leases.coordination.k8s.io "kube-controller-manager" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, leases.coordination.k8s.io "kube-scheduler" already exists. Warning: the in-cluster version is different than the backed-up version. could not restore, services "kube-dns" already exists. Warning: the in-cluster version is different than the backed-up version. Backup: velero-backup-202105230844 Namespaces: Included: all namespaces found in the backup Excluded: <none> Resources: Included: * Excluded: nodes, events, events.events.k8s.io, backups.velero.io, restores.velero.io, resticrepositories.velero.io Cluster-scoped: auto Namespace mappings: <none> Label selector: <none> Restore PVs: auto $ kubectl get pods NAME READY STATUS RESTARTS AGE velero-testpod 1/1 Running 0 22m $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-4b04c94b-c9bd-4206-8806-0e783b5ccce4 8Gi RWO Delete Bound default/velero-pvc gp2 23m $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE velero-pvc Bound pvc-4b04c94b-c9bd-4206-8806-0e783b5ccce4 8Gi RWO gp2 23m
取得頻度
velero schedule
コマンドを実行すると、Cron形式で指定したサイクルでバックアップを取得することができます。
$ velero schedule create velero-backup-shcedule-`date +%Y%m%d` --schedule="*/10 * * * *" Schedule "velero-backup-shcedule-20210523" created successfully. # 初回バックアップの取得 $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-shcedule-20210523-20210523013142 Completed 0 0 2021-05-23 10:31:42 +0900 JST 30d default <none> # 10分後 $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-shcedule-20210523-20210523014027 Completed 0 0 2021-05-23 10:40:27 +0900 JST 29d default <none> velero-backup-shcedule-20210523-20210523013142 Completed 0 0 2021-05-23 10:31:42 +0900 JST 29d default <none>
対象リソース
Veleroのバックアップには複数のオプションがあります。以下のコマンドでは、指定のNamespace上にあるリソースのうち、Secret
リソースをバックアップ対象から除外しています。
$ velero backup create velero-backup-exclude-`date +%Y%m%d%H%M%S` --include-namespaces default --exclude-resources secret $ velero backup describe velero-backup-exclude-20210523112153 <中略> Namespaces: Included: default★ Excluded: <none> Resources: Included: * Excluded: secret★ Cluster-scoped: auto
Secret
リソースには秘匿情報が記載されており、このデータをストレージ上に保管することがセキュリティリスクとなる可能性があります。そのため、上記コマンドのような形でリソースを除外し、セキュリティリスクを軽減することが可能です。
保存期間
バックアップ取得時は --ttl
オプションで保存期間を指定することができます。指定した保存期間を経過すると、そのバックアップデータは削除対象となり、しばらくすると削除されます。
$ velero backup create velero-backup-20210529-ttl-minutes --ttl 0h1m0s $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-20210529 Completed 0 0 2021-05-29 09:21:55 +0900 JST 29d default <none> velero-backup-20210529-ttl-minutes Completed 0 0 2021-05-29 09:28:42 +0900 JST 43m ago default <none> $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-20210529 Completed 0 0 2021-05-29 09:21:55 +0900 JST 29d default <none> $
またバックアップデータを保存しているオブジェクトストレージ側のデータを削除すると、クラスター上の backup
リソースも削除されます。
$ velero backup create velero-backup-20210529-object-storage-test $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-20210529 Completed 0 0 2021-05-29 09:21:55 +0900 JST 29d default <none> velero-backup-20210529-object-storage-test Completed 0 0 2021-05-29 10:10:09 +0900 JST 30d default <none> # S3バケットの削除 $ aws s3 rm s3://velero-backup-20210523/backups/velero-backup-20210529-object-storage-test --recursive $ aws s3 rm s3://velero-backup-20210523/backups/velero-backup-20210529-object-storage-test # Backupが削除される $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR velero-backup-20210529 Completed 0 0 2021-05-29 09:21:55 +0900 JST 29d default <none>
※参考ドキュメント:
その他
その他、Veleroを利用するうえで気を付けたほうがよさそうな点についても書き残しておきます。
Veleroのバックアップは厳密にはatomicでないため、バックアップ中に作成されたリソースがデータに含まれない場合もあります(Veleroドキュメントより)
バックアップ前にPodでコマンドを実行したい場合もあると思います(例:DBでインメモリデータをディスクに吐き出すなど)が、その場合はbackup hooksを利用して、バックアップデータ取得前に特定のコマンドを実行することができます。
Veleroでは現在、複数ロケーションに同時にバックアップ・スナップショットを保存することはできません。一方でスケジュール実行で場所だけを変更して、複数ロケーションへの保存を実現することはできるようです(Veleroドキュメントより)。
バックアップデータの容量という観点から、重複排除の機能があるか、という点も重要となるかと思います。Veleroのドキュメントからは、重複排除の有無を見つけることができませんでしたが、resticでは重複排除に言及した部分があるため、内部的には実装しているのかもしれません。
参考ドキュメント
FOURCO blog - Backup and restore a Kubernetes cluster with Velero
- Amazon EKS上でIRSA (IAM Role for Service Account)を利用してVeleroをインストールする手順が紹介されています
SlideShare - KubernetesバックアップツールVeleroとちょっとした苦労話
- Veleroを利用した際のトラブルなどが紹介されています