Kubenews #8 を視聴していたら Velero というツールの話題が出て、そういえば試そうと思って手付かずのままだったなぁと思い出し、試せるのはいつになるかなぁと Twitter で呟いたら「今でしょ!」とも言われたので、Velero を試してみました。
Velero とは
Velero は、Kubernetes クラスタのリソースと永続データをバックアップ、リカバリ、移行するためのツールです。 VMware のプロジェクトとして管理されており、VMware Tanzu (VMware の Kubernetes 製品群) の一員です。
vmware-tanzu/velero: Backup and migrate Kubernetes applications and their persistent volumes
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 公式サイトに参考手順が載っています。
Velero Docs - Quick start evaluation install with Minio
上記手順でも使われていますが、公式リポジトリに K8s クラスタに MinIO をデプロイするサンプルマニフェストが用意されています。
velero/00-minio-deployment.yaml at main · vmware-tanzu/velero
今回はこちらのサンプルマニフェストを一部変更して 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 については以下の記事を参考にしてください。
自宅 k8s クラスタのサービスに FQDN で繋がるようにした
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 クラスタ内にオブジェクトストレージを用意したため、クラスタが壊れてしまったらバックアップデータも吹き飛ぶ構成となっています。 ちゃんとバックアップとして利用するためには外部ストレージが必要ですので、自宅でも別途ストレージを用意してみたい気持ちが出てきましたので、お財布と相談してみます。