TECHSTEP

ITインフラ関連の記事を公開してます。

Veleroに入門する

今回はKubernetesリソースのバックアップ・リストアを実現するVeleroを使ってみます。

Cloud Nativeな世界のバックアップ・リストア

Veleroを動かす前に、バックアップ・リストアについていくつか書いておきます。

そもそもバックアップ・リストアを実現する理由としては、大きく以下の3つの理由があるかと思います。

  • DR: システムの稼働する主要サイトで災害等が発生し、システムとしての機能を失ったときに、別のサイトにてシステムを再稼働させる。
  • オペレーションのリカバリ: 業務の中でデータの紛失や論理的破壊が発生したときに、バックアップデータから対象のデータを復旧する。
  • アーカイブ: 法規制などに対応するため長期的なデータ保存が必要となるときに、バックアップデータを使用する。

また、これらの目的を達成することに加え、「Cloud Nativeな世界でのバックアップ・リストア」という観点で調べてみると、以下のような観点を合わせて検討することが重要となるようです。

サーバーでなくワークロード単位でバックアップ

Cloud Nativeな世界では、アーキテクチャ疎結合化により、それにかかわる組織やチームも疎結合となり、各チームが自律的に動けることを目指します。自律的なチームが複数に分かれると、各チームはそれぞれ独自のデータやワークロードをもつことになり、これらが分散して存在することになります。そのため、これまでの、データが一極集中管理されたシステムではなく、各チームごとにデータを所持するシステムでは、サーバー単位でなくワークロード単位でのバックアップが求められます。

例えば1つのKubernetesクラスター上で複数チームがワークロードを載せている場合、クラスターやNode単位でバックアップを取ると、バックアップデータには自分たちのワークロード以外のものも多く含まれ、そこから必要なものを探す手間が発生します。またリストアの際にクラスター・Node単位で実行するとなると、他のチームへの影響も発生し、組織全体のパフォーマンスが低下する要因となりえます。ワークロード単位でバックアップを取ることで、必要なものを見つけやすく、また自チーム内にのみ影響範囲を抑えることが可能となります。

データに着目してバックアップする

現在はCloud Nativeに関わらずインフラリソースのIaC化が進んでおり、必要なリソースはIaCファイルから作成することができます。バックアップを取得する際も、インフラリソースは定義ファイルから再現できるため、重要度は高くありません。一方で、そこに含まれる動的なデータは復元が難しいため、バックアップデータとして重要度が高くなります。

例としては以下のようなものが挙げられます。

  • ソースコードやビルドによる成果物など
  • アプリケーションの設定情報
  • インフラリソースの「状態」:インスタンス数やポート番号など
  • アプリ起動中に保存されたデータを含むデータベース
  • オブジェクトストレージに保存されたファイル

その他

その他、Cloud Nativeな環境で利用するバックアップ・リストアツールには、以下のような要素が含まれているとなお良いでしょう。

  • 複数環境・プロバイダーへの汎用性: オンプレやクラウドなど複数の環境で動作するシステムに対し、汎用的なツールを利用することで、不要な学習コストの削減やリストアのスピードアップにつながるでしょう。一方で、一つのクラウドプロバイダーのみを利用する予定の場合、各プロバイダーの提供するバックアップソリューションを利用することが、最も手軽かつ安全な場合もあります。

  • スケーラビリティ: システムの構成や規模が動的に変化するCloud Nativeなアーキテクチャでは、システムの構成変更に追従する、あるいは新規追加が容易なツールであるほど利用価値が高いといえるでしょう。


※参考ドキュメント:


バックアップ・リストアで考えること

バックアップ・リストアを設計・実装するうえで考えなければならないことは色々とあります。以下にその一例を記載します。

  • 利用目的
  • 取得頻度
  • バックアップ手法
  • 保存場所
  • 保存期間
  • 対象リソース

これらの観点に対して、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が作成されると、 BackupControllerKubernetes APIにクエリを投げてバックアップデータを収集し、オブジェクトストレージへバックアップデータのアップロードを行います。

velero

Veleroドキュメントより

Veleroを使ってみる

ここからVeleroを実際に動かしてみます。利用した環境は以下の通りです。

Amazon EKS上でVeleroを動かす際は、EKS Workshopのページに手順がコンパクトにまとまっているので楽です。

www.eksworkshop.com

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では重複排除に言及した部分があるため、内部的には実装しているのかもしれません。

参考ドキュメント