こんにちは、テクマトリックスの酒井です。

Kubernetes クラスターにアプリケーションをデプロイすることは、マニフェストや Helm チャート、 Argo CD などを利用して比較的簡単にできます。しかしそれでも、万が一のシステム障害への備えや、 Kubernetes クラスターのバージョンアップのような重要な操作の前に、 Kubernetes クラスターのバックアップを取得することは依然として重要です。そこで今回は Velero というツールを利用して、 Kubernetes クラスターのリソースをローカルのオブジェクトストレージにバックアップし、復元してみます。

Velero とは

Velero のドキュメントを引用します。

Velero (旧 Heptio Ark) は、Kubernetes クラスター リソースと永続ボリュームをバックアップおよび復元するためのツールを提供します。 Velero はクラウド プロバイダーまたはオンプレミスで実行できます。 Velero では次のことが可能になります。

  • クラスターのバックアップを作成し、紛失した場合には復元してください。
  • クラスターのリソースを他のクラスターに移行します。
  • 実稼働クラスターを開発クラスターとテストクラスターにレプリケートします。

Velero は次のもので構成されています。

  • クラスター上で実行されるサーバー
  • ローカルで実行されるコマンドライン クライアント
https://velero.io/docs/v1.13/ の Google 翻訳による翻訳,最終確認日:2024年1月24日

本記事では、 Kubernetes クラスターが完全に失われることを想定して、 Kubernetes クラスターとは別のマシンにバックアップを保存します。また障害のレベルに応じて、アプリケーションの復元および Kubernetes クラスター全体の復元の 2 種類を試してみます。

アーキテクチャー

Windows 10 のローカル PC 上に Kubernetes クラスターを作成し、このクラスターに Velero をインストールします。またバックアップと復元の検証のため、アプリケーションとして Jenkins もクラスターにインストールします。 Jenkins のホームディレクトリとして利用されるボリュームのバックアップのためにボリュームのスナップショットを作成したいため、 Kubernetes クラスターにてボリュームのスナップショット機能を有効にします。

Velero は作成したバックアップをオブジェクトストレージに保存します。今回はローカル PC とは別の Linux マシンに MinIO をセットアップし、ここにバックアップを保存します。 MinIO の概要については以前の記事をご参照ください。

以上を図にすると次のようになります。

今回のアーキテクチャー

準備

Kubernetes クラスターおよびクラスターのバックアップ・復元に必要なものを用意します。そのために以下を行います。

  • MinIO のセットアップ
  • ローカル PC への各ツールのインストール
  • Kubernetes クラスターの作成
  • Velero のインストール
  • Kubernetes 上で実行するアプリケーション(Jenkins)のインストール

MinIO のセットアップ

Velero が作成したバックアップを保存するオブジェクトストレージとして MinIO をセットアップします。セットアップの手順は以前の記事の「MinIO の実行と設定」の節と同様です。ただし、バケット名は velero とします。以前の記事と同様、アクセスキーを生成した後に Access Key および Secret Key をメモしておきます。

ローカル PC への各ツールのインストール

ローカル PC にて Hyper-V を有効化します。また環境構築に利用する Chocolatey, Minikube, Kubernetes CLI, Helm をインストールします。この手順については以前の記事を参照してください。

本記事の執筆時に利用した各ツールのバージョンは次のとおりです。

> choco --version
2.2.2
> minikube version
minikube version: v1.32.0
commit: 8220a6eb95f0a4d75f7f2d7b14cef975f050512d
> kubectl version --client --short
Client Version: v1.27.3
Kustomize Version: v5.0.1
> helm version --short
v3.12.3+g3a31588

Kubernetes クラスターの作成

次に Minikube を利用して、 VM および Kubernetes クラスターを作成します。加えてボリュームのスナップショットを有効にします。 PowerShell にて以下のスクリプトを実行します。

# Kubernetes クラスターを作成
minikube start --driver=hyperv --cpus=4 --memory=8g --disk-size=40gb --addons ingress

# ボリュームのスナップショットを有効にし、デフォルトのストレージクラスとして利用する
minikube addons enable volumesnapshots
minikube addons enable csi-hostpath-driver
minikube addons disable storage-provisioner
minikube addons disable default-storageclass
kubectl patch storageclass csi-hostpath-sc -p $('{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' | ConvertTo-Json)

Velero のインストール

まずはコマンドラインクライアントをインストールします。 PowerShell を管理者として実行して、次のコマンドを実行します。

choco install velero

以降は管理者として実行した PowerShell は不要なため、この PowerShell は閉じてしまって構いません。

次にこのコマンドラインクライアントを利用して、 Kubernetes クラスターに Velero のサーバーコンポーネントをインストールします。コマンドラインクライアントの実行に先立って、 MinIO の認証情報をファイルに保存する必要があります。MinIO のセットアップの結果に応じて下記のスクリプトの先頭 4 行を変更し、その後スクリプトを実行します。

$MinioHost       = 'e.f.g.h' # MinIO をセットアップしたマシンの名前または IP アドレス
$MinioBucketName = 'velero'  # MinIO のバケット名
$MinioAccessKey  = '...'     # MinIO の Access Key
$MinioSecretKey  = '...'     # MinIO の Secret Key

# MinIO の認証情報をファイルに保存(BOM を付けない)
@"
[default]
aws_access_key_id = ${MinioAccessKey}
aws_secret_access_key = ${MinioSecretKey}
"@ |
% { [Text.Encoding]::ASCII.GetBytes($_) } |
Set-Content -Path ".\credentials-velero" -Encoding Byte

# Velero のサーバーコンポーネントをインストール
velero install `
  --provider aws `
  --plugins velero/velero-plugin-for-aws:v1.2.1 `
  --bucket ${MinioBucketName} `
  --secret-file ./credentials-velero `
  --use-node-agent `
  --use-volume-snapshots `
  --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://${MinioHost}:9000

なお今回インストールした Velero のバージョンは次のとおりです。

> velero version
Client:
        Version: v1.12.2
        Git commit: 06d12dec4030703cb46b2699ca434cdabd9edbb0
Server:
        Version: v1.12.2

アプリケーションのインストール

バックアップと復元の検証のために、クラスターに Jenkins をインストールします。次のコマンドを実行します。

# Jenkins のインストール
helm repo add jenkinsci https://charts.jenkins.io
helm repo update
helm upgrade jenkins jenkinsci/jenkins --install --namespace jenkins --create-namespace --wait `
  --set controller.ingress.enabled=true `
  --set controller.podAnnotations.'backup\.velero\.io/backup-volumes'=jenkins-home `
  --set persistence.enabled=true

# 'admin' ユーザーのパスワードを取得
kubectl get secret jenkins -n jenkins -o jsonpath='{.data.jenkins-admin-password}' |
  % { [System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String($_)) }

# ブラウザで Jenkins のページを開く
Start-Process "http://$(minikube ip)/"

Jenkins ホームディレクトリ用のボリューム(jenkins-home)を Velero でバックアップするために、上記のスクリプトの 6 行目にて backup.velero.io/backup-volumes アノテーションを追加しています。

Jenkins にログインして、ジョブを作成して実行したりプラグインをインストールしたりして、復元したときに間違いなくバックアップから復元したものだと分かるようにします。

Jenkins のダッシュボード

これで準備は完了です!

バックアップと復元を試してみる

Velero で Kubernetes クラスター全体をバックアップします。その後、 Jenkins だけを失った場合、 Kubernetes クラスター全体を失った場合の 2 パターンを想定して復元してみます。復元できることが確認できたら、バックアップを定期的に作成するように設定します。

バックアップを作成する

早速バックアップを作成します。ローカル PC で次のコマンドを実行するだけです。コマンド中の oneshot は任意の名前に変更できます。

velero backup create oneshot --snapshot-volumes --include-cluster-resources

コマンドを実行すると次のように出力され、バックアップの作成が開始されます。

Backup request "oneshot" submitted successfully.
Run `velero backup describe oneshot` or `velero backup logs oneshot` for more details.

バックアップの作成状況は次のコマンドで確認できます。

velero backup describe oneshot

すると次のような出力が得られます。

Name:         oneshot
Namespace:    velero
Labels:       velero.io/storage-location=default
Annotations:  velero.io/resource-timeout=10m0s
              velero.io/source-cluster-k8s-gitversion=v1.28.3
              velero.io/source-cluster-k8s-major-version=1
              velero.io/source-cluster-k8s-minor-version=28

Phase:  Completed

(以下省略)

Phase が Completed になっていれば、バックアップの作成は完了しています。私の環境では約 15 秒で完了しました。

Jenkins を破棄して復元してみる

次に Jenkins だけが壊れた場合に復元できるかを試してみます。 Jenkins が災害に見舞われたことを想定して Jenkins 関連のリソースをすべて削除します。

kubectl delete namespace jenkins

このコマンドを実行すると、 jenkins 名前空間のリソースが削除されるだけでなく、 Jenkins ホームディレクトリとして利用していた永続ボリュームも失われます。

> kubectl get persistentvolumes
No resources found

ではバックアップから Jenkins を復元してみます。単に次のコマンドを実行するだけです。

velero restore create --from-backup oneshot --include-namespaces jenkins --restore-volumes

コマンドを実行すると次のように出力され、復元が開始されます。

Restore request "oneshot-20240119144025" submitted successfully.
Run `velero restore describe oneshot-20240119144025` or `velero restore logs oneshot-20240119144025` for more details.

復元の状況は velero restore describe 復元リクエスト名 コマンドで確認できます。

> velero restore describe oneshot-20240119144025
Name:         oneshot-20240119144025
Namespace:    velero
Labels:       <none>
Annotations:  <none>

Phase:                       Completed
Total items to be restored:  24
Items restored:              24

(以下省略)

今回の Velero による復元は 15 秒程度で完了しました。その後ポッドが起動するまでもう少し時間がかかります。ポッドの起動後に Jenkins のページを再読み込みしてログインすると、無事ジョブやプラグインが表示され、バックアップ時点の Jenkins が無事に復元されたことが確認できました。

Kubernetes クラスターを破棄して復元してみる

ここからが本番です。 Kubernetes クラスターが丸ごと失われたことを想定して復元してみます。

まずは災害をシミュレーションするため、 Kubernetes クラスターを削除します。

minikube delete

Kubernetes クラスターは失われましたが、バックアップは MinIO のマシンに残っています。希望を持って、準備の段階で実施した「Kubernetes クラスターの作成」と「Velero のサーバーコンポーネントのインストール」を再度実施します。 Velero が起動すると、 velero backup get コマンドを実行することでバックアップの存在を確認できます。

> velero backup get
NAME       STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
oneshot    Completed   0        0          2024-01-17 15:48:24 +0900 JST   28d       default            <none>

ここまできたら、あとは先程と同じくバックアップから復元するだけです。 Jenkins 以外も復元したいので、先程の復元時に指定した --include-namespaces jenkins オプションは指定しません。

velero restore create --from-backup oneshot --restore-volumes

Velero による復元が完了し、 Jenkins のポッドが起動すれば、 ブラウザで Jenkins にアクセスできます。 Kubernetes クラスターの VM を再作成したことにより IP アドレスが変わっているため、次のコマンドで Jenkins のページを開きます。

Start-Process "http://$(minikube ip)/"

Jenkins にログインすると、作成したジョブやプラグインが元通りなことを確認できます。これで災害復旧が完了です。お疲れ様でした!

定期的にバックアップする

災害はいつ発生するか分かりません。予期せぬ事故が発生したときに以前の状態に戻せるよう、 リソースを定期的にバックアップするべきです。そのためには例えば次のコマンド実行すると、 24 時間ごとにバックアップを作成できます。コマンド中の daily は任意の名前に変更できます。また --schedule オプションにて定期的なスケジュールを cron 式で指定できます。

velero schedule create daily --schedule=”@every 24h” --snapshot-volumes --include-cluster-resources

作成されたバックアップは daily-TIMESTAMP (TIMESTAMP はバックアップされた日時)という名前で保存されます(この名前を使って復元できます)。またバックアップの保存期間はデフォルトで 30 日となっており、 --ttl オプションで変更可能です。

気づいたこと

Velero はボリュームのバックアップについて、 Velero は指定したボリュームのみバックアップを作成する(オプトイン)か、あるいは指定したボリュームを除外する(オプトアウト)かを指定可能です。 Jenkins のポッドはいくつものボリュームをマウントしますがバックアップが必要なボリュームは一つだけ(jenkins-home)のため、今回はオプトインの方を選択しました。ただどちらを選択すると良いかはアプリケーションや運用方法などによって変わってくるかと思います。

まとめ

Velero を利用して Kubernetes クラスターのバックアップと復元を試しました。 Velero のバックエンドに MinIO を使うことによって、オンプレミス環境でも比較的簡単に Kubernetes クラスターのリソースと永続ボリュームをバックアップ・復元できました。今後はデータベースを利用するアプリケーションのバックアップと復元も試してみたいと思います。

参考

By tsakai

Jenkins関連のサービスやCloudBees製品を主に担当しています。 Certified CloudBees Jenkins Engineer (CCJE) および CloudBees CI DevOps Associate です。