Kubernetes クラスタのバックアップツール Velero を試してみた
Kubenews #8 を視聴していたら Velero というツールの話題が出て、そういえば試そうと思って手付かずのままだったなぁと思い出し、試せるのはいつになるかなぁと Twitter で呟いたら「今でしょ!」とも言われたので、Velero を試してみました。
Velero とは
Velero は、Kubernetes クラスタのリソースと永続データをバックアップ、リカバリ、移行するためのツールです。 VMware のプロジェクトとして管理されており、VMware Tanzu (VMware の Kubernetes 製品群) の一員です。
Velero は Kubernetes クラスタに対して以下のような使い方ができます。
Velero の特徴としては、Kubernetes API を使ってバックアップ・リストアをする API-driven な点があります。 他の Kubernetes 用バックアップツールはクラスタ内の etcd を直接参照してバックアップ・リストアするようで、その点が異なります。
API-driven なバックアップツールには以下のようなメリットがあります。
- 名前空間、リソースタイプ、ラベルによってバックアップ・リストア対象を柔軟に選択可能
- マネージド K8s クラスタの場合、etcd を直接参照できずバックアップ・リストアできないことがあるが、API 経由なら可能
- 別の etcd にリソースが保存されていてもバックアップ・リストア可能
正直なところ、3点目はどのような場合を想定しているのか理解できていません…。
また、Velero は Kubernetes のリソースだけでなく、永続データもバックアップ・リストアの対象とすることができますが、今回はリソースを対象にしたバックアップ・リストアのみ試しています。
オブジェクトストレージの用意
Velero はバックアップデータをオブジェクトストレージに格納します。
Amazon S3 や Azure Blob Storage といったクラウドサービスとしてのオブジェクトストレージを使ってもよいのですが、今回はオンプレ環境の K8s クラスタ内に2種類のオブジェクトストレージを用意しました。
対応しているストレージプロバイダの一覧は以下に記載されていますが、今回使用する S3 互換のオブジェクトストレージは十分なテストはされていない点は要注意です。
MinIO
まずは S3 互換のオブジェクトストレージとしてよく使われているであろう MinIO です。(今回、初めて存在を知りました…)
MinIO の場合は Velero 公式サイトに参考手順が載っています。
上記手順でも使われていますが、公式リポジトリに K8s クラスタに MinIO をデプロイするサンプルマニフェストが用意されています。
今回はこちらのサンプルマニフェストを一部変更して MinIO を用意しました。
変更箇所は kind: Service
に対する以下の2点です。
- ExternalDNS 用に
external-dns.alpha.kubernetes.io/hostname
アノテーションを付与 spec.type: ClusterIP
からspec.type: LoadBalancer
へ変更
以下は変更済みサンプルマニフェストのデプロイ結果です。
$ kubectl apply -f examples/minio/00-minio-deployment.yaml $ kubectl get all -n velero NAME READY STATUS RESTARTS AGE pod/minio-5b84955bdd-2qh6f 1/1 Running 0 26h pod/minio-setup-nfcjq 0/1 Completed 0 26h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/minio LoadBalancer 10.103.161.124 192.168.2.244 9000:31475/TCP 26h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/minio 1/1 1 1 26h NAME DESIRED CURRENT READY AGE replicaset.apps/minio-5b84955bdd 1 1 1 26h NAME COMPLETIONS DURATION AGE job.batch/minio-setup 1/1 13s 26h
service/minio
は type: LoadBalancer に変更したため External-IP が振られており、 ExternalDNS による DNS 登録もされている状態です。
デプロイから数分待てば、アノテーションで指定したホスト名で MinIO のサービスにアクセスできるようになります。
ExternalDNS については以下の記事を参考にしてください。
Rook Ceph
もう一つは、Rook Ceph のオブジェクトストレージです。
既にクラスタ用のブロックストレージとして Rook Ceph は使っていたのですが、オブジェクトストレージとしての利用はしていなかったので今回を機に用意してみました。
Rook Ceph オブジェクトストレージのデプロイには、公式ドキュメントと以下の記事を参考にしました。
$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/object-test.yaml $ kubectl apply -f rook/cluster/examples/kubernetes/ceph/storageclass-bucket-delete.yaml $ kubectl apply -f rook/cluster/examples/kubernetes/ceph/object-bucket-claim-delete.yaml
既に Rook が入っていれば、これだけでオブジェクトストレージが使えるようになります。
が、自分の環境では OBC (Object Bucket Claim ) の status が Pending からずっと変わらない事象が発生しました。 (正しく動けば Bound になるはず)
Pending の状態だからオブジェクトストレージとしては使えないだろう、と思い数日原因を探っていたのですが、結局分からないままでした。
試しに Rook 公式ドキュメントに記載されている s3cmd
を使ってテストしたところ、Pending の状態でもオブジェクトの格納や取得はできてしまいました。
今回の検証は上記のような状態でおこなっていますが、後日ちゃんと対応しようと思います。
また本筋から逸れますが、なぜ MinIO 以外のオブジェクトストレージを用意したのかというと「K8s クラスタ上に MinIO をデプロイしても内部では Rook Ceph のブロックストレージを使うためオーバーヘッドが掛かるのでは」と考えたからです。
Ceph のアーキテクチャ図を見ると分かりやすいのですが、Ceph 自体は RADOS (Reliable Autonomic Distributed Object Store) というオブジェクトストアを土台として構築し、その上で S3 互換オブジェクトストレージの RADOSGW
や ブロックストレージの RDB
、ファイルストレージの CephFS
が動いています。
そのため、MinIO を使って K8s クラスタ内にオブジェクトストレージを構築しても、Rook Ceph の StorageClass (ブロックストレージ) を使っていては「オブジェクトストレージ on ブロックストレージ on オブジェクトストア」のようになってしまうのでは、RADOSGW を使ってオブジェクトストレージを使ったほうが性能が良いのでは、と考えました。
考えました……。
が、執筆時に MinIO のサンプルマニフェストを見返して気付いたのですが、MinIO の volumes では emptyDir を使っていました。 つまり、Rook Ceph のブロックストレージを使っていませんでした。
最初に試した MinIO のデプロイは上記サンプルのものではなく別の方のマニフェストを参考にしていて、そちらでは PVC を使っていたので Rook Ceph を使っているものと勘違いしたまま考察してしまいました。
上記の考察は、Velero 公式リポジトリの MinIO サンプルマニフェストでは意味がないです。
こちらも後日 PVC を使った MinIO を用意して RADOSGW との性能差を測定をしてみます。
Velero を試す
オブジェクトストレージの用意ができたので、いよいよ Velero を試してみます。
インストール
Velero を K8s クラスタにインストールする方法は以下の2通りあります。
- velero コマンドを使った
velero install
- Helm chart
今回は、velero コマンドを Linux クライアント環境にインストールする方法で試しました。 (Helm に苦手意識があるので…)
まずは velero コマンドを準備します。
Mac や Windows だと Homebrew や Chocolatey といったパッケージマネージャが使えるのですが、Linux のため公式からバイナリをダウンロードしてきました。
velero
ファイルを PATH の通ったとこに配置するだけで完了です。
次に、オブジェクトストレージの認証情報を記載したファイル (./credentials-velero) を用意します。
[default] aws_access_key_id = minio aws_secret_access_key = minio123
上記の認証情報は MinIO (サンプルマニフェスト)の場合ですが、Rook Ceph の場合は以下のコマンドで認証情報を取得できます。
$ kubectl get secret ceph-delete-bucket -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 --decode $ kubectl get secret ceph-delete-bucket -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 --decode
velero コマンドの準備ができたらクライアントから velero install
すればよいのですが、MinIO と Rook Ceph の場合でバケット名や s3Url など微妙に異なるので、適宜変更してください。
- MinIO
$ velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.0.0 \ --bucket velero \ --secret-file ./credentials-velero \ --use-volume-snapshots=false \ --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.minio.svc:9000
- Rook Ceph
$ velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.0.0 \ --bucket ceph-bkt-c71df44b-8657-4f02-b680-fe0894debc07 \ --secret-file ./credentials-velero \ --use-volume-snapshots=false \ --backup-location-config region=us-east-1,s3ForcePathStyle="true",s3Url=http://rook-ceph-rgw-my-store.rook-ceph.svc
namespace: velero
に velero Pod がデプロイされていればインストール完了です。
バックアップ
Velero 公式リポジトリに用意された Nginx のサンプルマニフェストを使って、バックアップ・リストアの確認をします。
# テスト用リソースの準備 $ kubectl apply -f https://github.com/vmware-tanzu/velero/blob/main/examples/nginx-app/base.yaml $ kubectl get deployments -l component=velero --namespace=velero NAME READY UP-TO-DATE AVAILABLE AGE velero 1/1 1 1 24h $ kubectl get all --namespace=nginx-example NAME READY STATUS RESTARTS AGE pod/nginx-deployment-57d5dcb68-tks6f 1/1 Running 0 24h pod/nginx-deployment-57d5dcb68-wd456 1/1 Running 0 24h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-nginx LoadBalancer 10.101.167.57 192.168.2.242 80:32308/TCP 24h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-deployment 2/2 2 2 24h NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-57d5dcb68 2 2 2 24h # バックアップ $ velero backup create nginx-backup --selector app=nginx Backup request "nginx-backup" submitted successfully. Run `velero backup describe nginx-backup` or `velero backup logs nginx-backup` for more details. # バックアップリソースの確認 $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR nginx-backup Completed 0 0 2021-02-13 00:05:24 +0900 JST 29d default app=nginx
無事にバックアップは取れたようです。
リストア
Velero によるバックアップが成功したら、サンプルリソースを削除してバックアップデータからリストアできるか確認します。
# テスト用リソースの削除 $ kubectl delete namespace nginx-example namespace "nginx-example" deleted $ kubectl get all --namespace=nginx-example No resources found in nginx-example namespace. # リストア $ velero restore create --from-backup nginx-backup Restore request "nginx-backup-20210213000816" submitted successfully. Run `velero restore describe nginx-backup-20210213000816` or `velero restore logs nginx-backup-20210213000816` for more details. # リストアリソースの確認 $ velero restore get NAME BACKUP STATUS STARTED COMPLETED ERRORS WARNINGS CREATED SELECTOR nginx-backup-20210213000816 nginx-backup Completed 2021-02-13 00:08:16 +0900 JST 2021-02-13 00:08:16 +0900 JST 0 0 2021-02-13 00:08:16 +0900 JST <none> $ kubectl get all --namespace=nginx-example NAME READY STATUS RESTARTS AGE pod/nginx-deployment-57d5dcb68-tks6f 1/1 Running 0 29s pod/nginx-deployment-57d5dcb68-wd456 1/1 Running 0 29s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-nginx LoadBalancer 10.109.90.104 192.168.2.242 80:30316/TCP 29s NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-57d5dcb68 2 2 2 29s
一部リストアもできたようですが、Deployments だけがリストアできていません。
これは Nginx サンプルマニフェストで Deployments にラベルが設定されておらず、バックアップ対象のリソースとして選択されなかったからです。 Nginx サンプルマニフェストを弄ってラベルをつけてあげると、ちゃんとバックアップ・リストアされるようになりました。
おわりに
今回は Kubernetes クラスタのバックアップツール Velero
を試してみました。
Velero 自身はとても簡単に使えるのですが、オブジェクトストレージへの理解が低いためか、オブジェクトストレージの準備にとても時間が掛かってしまいました。 記事もオブジェクトストレージ中心で Velero はオマケ程度になってしまいました。
また、K8s クラスタ内にオブジェクトストレージを用意したため、クラスタが壊れてしまったらバックアップデータも吹き飛ぶ構成となっています。 ちゃんとバックアップとして利用するためには外部ストレージが必要ですので、自宅でも別途ストレージを用意してみたい気持ちが出てきましたので、お財布と相談してみます。