Kubernetesで実現するCassandraのシームレスなバックアップ戦略

## はじめに
Cassandraは高可用性のあるスケーラブルなデータベースとして広く利用されていますが、そのデータを安全に保つためには定期的なバックアップが不可欠です。この記事では、KubernetesのReconcilerを用いて、Cassandraのバックアップをシームレスに自動化し、バックアップツールであるMedusaとどのように連携するかについて説明します。
## 背景
### Cassandraのバックアップの重要性
データベースのバックアップは、データ損失を防ぐために非常に重要です。特にCassandraのような分散データベースでは、データの整合性と可用性を確保するために定期的なバックアップが必要です。バックアップが適切に行われていないと、障害発生時にデータを復元できず、サービスに大きな影響を及ぼす可能性があります。
### Medusaとは？
[Medusa](https://docs.k8ssandra.io/components/medusa/
)はCassandraのバックアップを簡単に行うためのツールです。ローカルでのバックアップ取得のみならず、S3やGCSといったクラウドストレージにバックアップを保存することもできます。Medusaは、Cassandraのスナップショットを取得し、ローカル、またはクラウドストレージに安全に保存するための機能を提供します。
### Reconcilerとは？
Reconcilerは、Kubernetes上でカスタムコントローラーを開発するためのOperator SDKの機能の一つです。Reconcilerは、リソースの現在の状態と望ましい状態を比較し、必要に応じて調整を行います。これにより、システムの状態を常に望ましい状態に保つことができます。

Reconcilerは、リソースの変更を監視し、必要なアクションを実行することで、リソースが常に期待される状態にあることを保証します。具体的には、リソースの作成、更新、削除などの操作を自動化し、システムの安定性と効率性を向上させます。

## 我々のバックアップアプローチ
### アーキテクチャの概要
我々のアプローチでは、Cassandraは仮想マシン（VM）上で動作し、バックアッププロセスはKubernetes上で管理されています。具体的には、バックアッププロセス自体はVM上で実行されますが、その管理とオーケストレーションはKubernetesによって行われます。また、VM内部ではCassandraAgentがControllerからバックアップスケジュールや各種設定ファイルのインポート、およびMedusaを実行するエージェントの役割を担い、バックアップ処理を行っています。
![スクリーンショット 2024-09-12 14.54.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883163/a3f35812-8801-fef1-4192-1c8ef7fb6d6a.png)


### 分散モデルのメリット
この分散モデルでは、各Cassandraノードにエージェント（CassandraAgent）が配置され、バックアップのスケジュールや実行を管理します。各エージェントは独立して動作し、バックアップの進行状況を監視し、必要に応じて調整を行います。これにより、以下のようなメリットがあります。

- スケーラビリティ : 大規模なクラスタでも効率的にバックアップを管理することができます。各エージェントが独立して動作するため、中央集権的な管理に伴うボトルネックを回避
- 柔軟性 : 各ノードが独自にバックアップを管理するため、特定のノードに対するカスタマイズや調整が容易
- 信頼性 : 分散モデルにより、特定のノードやエージェントの障害が全体のバックアッププロセスに影響を与えにくい

## バックアップのスケジュール管理
定期的なバックアップを実現するため、BackupSchedule CRを作成し、スケジュールを管理しています。BackupSchedule CRは以下のようなspecになっており、スケジュールを設定できます。
```yaml

kind: CassandraBackupSchedule
spec:
  schedule: "* 0 * * 1"
  retentionPeriod: 7
```
- 'schedule' : Cron形式でバックアップのスケジュールを指定します。上記の例では、毎週月曜日の午前0時にバックアップ処理が実行されます。
- 'retentionPeriod' : バックアップの保持期間を指定できます。上記の例では、7世代分管理することができます。

## 実装概要
以下の図は1つのノードに絞ったバックアップ処理の詳細な流れです。この流れが各ノードで行われています。
1. バックアップスケジュールの確認 : KubernetesのカスタムリソースであるbackupscheduleCRをCassandraAgentが確認し、バックアップ時間かどうかを判定します。
2. Medusaの設定 : ConfigMap上で管理しているMedusaの設定ファイルテンプレートを取得します。
3. Medusa設定ファイルの作成 : 2.で取得したテンプレートに環境変数を埋め込み2つの設定ファイル(medusa-s3-credentials、medusa.ini)を作成します。
4. Medusaの起動 : 3.で作成した設定ファイルを元にMedusaを起動します。
5. スナップショットの作成 : Medusaを用いスナップショットを非同期で作成します。
6. バックアップ情報の更新 : 非同期で作成されたスナップショットの進行状況を確認し、進行中 (In_progress) なのか完了 (Success) なのかの情報を確認します。この情報はKubernetesのカスタムリソースであるnodestateCRに送信されます。
7. スナップショットのアップロード : 6で完了 (Success) になった後、スナップショットをオブジェクトストレージにアップロードし、nodestateCRの情報を更新します。
8. Medusaの停止 : Medusaを停止します。
9. 設定ファイルの削除 : 設定ファイル(medusa-s3-credentials、medusa.ini)はクレデンシャル情報を保持しているため削除します。

![スクリーンショット 2024-09-13 14.49.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883163/08d11786-6cb8-2044-52c9-2d1504d8b506.png)

## KubernetesとCassandraAgentの役割
Kubernetesと、Medusaを利用するCassandraAgentの役割を説明します。

### Kubernetesの役割
Kubernetesは以下のタスクを実行します。
- クラスタの状態を監視し、バックアップが必要かどうかを判断。
- バックアップの進行状況を監視し、完了後に状態を更新。

### CassandraAgentの役割
CassandraAgentは以下のタスクを実行します。
- Medusaを通じてCassandraのデータをバックアップ。
- Medusaを通じてクラウドストレージにバックアップをアップロード。
- バックアップの進行状況をKubernetesに提供。

## メリット
### 自動化
KubernetesのReconcilerを用いることで、バックアッププロセスを完全に自動化することができます。これにより、手動でバックアップを管理する手間を省くことができます。自動化されたプロセスは、人為的なミスを減少させ、バックアップの信頼性を向上させます。
### 同時刻のバックアップ
Reconcilerを利用することで、各ノードのバックアップを同時刻に取得することができます。これにより、バックアップの整合性型持たれ、全ノードのデータが同じ時点でのスナップショットとして保存されます。これは、順番にバックアップを取る場合に発生するタイムラグを防ぎ、より有益なバックアップを提供します。
### スケーラビリティ
Kubernetes上で動作するため、クラスタの規模に応じて容易にスケールアウトすることが可能です。新しいノードが追加されても、Reconcilerが自動的にバックアッププロセスを管理するため、手動での設定変更が不要です。

## K8ssandraとの違い
[K8ssandra](https://docs.k8ssandra.io/components/k8ssandra-operator/)は、CassandraクラスタをKubernetes上で完全にコンテナ化して管理するソリューションの一つです。K8ssandraでは、MedusaはCassandraと同様にコンテナとしてデプロイされます。KubernetesのCronJobやPodのライフサイクル管理機能を利用して、Medusaの起動や設定が自動化されています。以下はk8ssandra公式ドキュメントによるMedusaのデプロイ方法を抜粋したものです。
```yaml
apiVersion: k8ssandra.io/v1alpha1
kind: K8ssandraCluster
metadata:
  name: demo
spec:
  cassandra:
    ...
    ...
  medusa:
    storageProperties:
      # Can be either of google_storage, azure_blobs, s3, s3_compatible, s3_rgw or ibm_storage
      storageProvider: s3_compatible
      # Name of the secret containing the credentials file to access the backup storage backend
      storageSecretRef:
        name: medusa-bucket-key
      # Name of the storage bucket
      bucketName: k8ssandra-medusa
      # Prefix for this cluster in the storage bucket directory structure, used for multitenancy
      prefix: test
      # Host to connect to the storage backend (Omitted for GCS, S3, Azure and local).
      host: minio.minio.svc.cluster.local
      # Port to connect to the storage backend (Omitted for GCS, S3, Azure and local).
      port: 9000
      # Region of the storage bucket
      # region: us-east-1
      ...
      ...
```
K8ssandraのアプローチでは、CronJobを用いてバックアップスケジュールを管理します。CronJobは指定された時間にバックアップジョブを実行し、中央集権的にバックアップを管理します。
我々は数百クラスタ・数万ノードを管理しており、これらを効率的に管理し、かつ、CassandraがVM上で動作しているため、k8ssandraではなく、内製をしました。これにより、分散モデルでの効率的なバックアップ管理が可能となります。

## 終わりに
この記事では、KubernetesのReconcilerを使ってCassandraクラスタのバックアップをシームレスに自動化する方法を紹介しました。Medusaを利用することで、バックアップの設定や実行が非常に簡単になり、データの安全性を高めることができます。

特に、Reconcilerを利用することで、各ノードのバックアップを同時刻に取得することができ、バックアップの整合性が保たれる点は大きなメリットです。また、K8ssandraとの違いを理解することで、どちらのアプローチが自分たちの環境に適しているかを判断する助けになります。このアプローチを活用して、Cassandraクラスタの運用を効率的に行いましょう。

## 参考文献
- https://docs.k8ssandra.io/tasks/backup-restore/