Container Service for Kubernetes (ACK) のステートフルアプリケーションが複数のディスクで構成されている場合、各ディスクから個別に VolumeSnapshot を作成すると、各スナップショットがわずかに異なる時点のデータをキャプチャするため、リカバリーポイントに不整合が生じる可能性があります。グループスナップショットは、すべてのスナップショットを同時にトリガーすることでこの問題を解決し、グループ内のすべてのディスクが同じ瞬間にキャプチャされるようにします。これにより、複数のボリュームにまたがるアプリケーションを復元する必要がある場合に、データの不整合のリスクを低減できます。
仕組み
グループスナップショットは、ECS スナップショット整合性グループをベースに構築されています。ACK は、グループスナップショットの管理に使用できる以下の CustomResourceDefinitions (CRD) を提供します。
| CRD | 類似リソース | 目的 |
|---|---|---|
| VolumeGroupSnapshotClass | StorageClass | グループスナップショットのドライバーと削除ポリシーを定義します |
| VolumeGroupSnapshot | PersistentVolumeClaim (PVC) | ラベルセレクターによって識別されるディスクセットのスナップショットをリクエストします |
| VolumeGroupSnapshotContent | PersistentVolume (PV) | リクエストに応じて作成された ECS スナップショット整合性グループを記録します |
| VolumeSnapshot | — | ボリュームスナップショットのリクエストです。VolumeGroupSnapshot の作成後に各ディスクに対して自動的に作成されます |
| VolumeSnapshotContent | — | ECS スナップショットに関する情報を記録します |
VolumeGroupSnapshot を作成すると、Container Storage Interface (CSI) プラグインが ECS スナップショット整合性グループを作成し、選択された各ディスクに対して VolumeSnapshot と VolumeSnapshotContent を自動的に生成します。ディスクに障害が発生した場合は、対応する VolumeSnapshot から復元します。
課金
スナップショット整合性グループは無料です。グループ内のスナップショットは、ストレージ使用量に基づいて課金されます。詳細については、「スナップショットの課金」をご参照ください。
制限事項
-
グループスナップショットは、ECS スナップショットと同じ制限に従います。詳細については、「使用制限」をご参照ください。
-
ECS スナップショット整合性グループでは、有効期限はサポートされていません。不要になったグループスナップショットは手動で削除してください。
前提条件
開始する前に、以下のものが揃っていることを確認してください。
-
Kubernetes 1.28 以降を実行している ACK マネージドクラスター。詳細については、「ACK マネージドクラスターの作成」をご参照ください。
-
バージョン 1.31.4 以降がインストールされた CSI プラグイン。csi-plugin と csi-provisioner を更新するには、「csi-plugin と csi-provisioner の更新」をご参照ください。
-
有効化された Elastic Compute Service (ECS) スナップショットサービス (有効化は無料)。詳細については、「ECS スナップショットの有効化」をご参照ください。
クラスターが FlexVolume (ACK では非推奨) を使用している場合は、グループスナップショットを作成する前に CSI にアップグレードしてください。詳細については、「FlexVolume から CSI へのアップグレード」をご参照ください。どのボリュームプラグインがインストールされているかを確認するには、ACK コンソールのクラスター詳細ページに移動し、左側のナビゲーションウィンドウで [運用管理] > [アドオン] を選択し、[ストレージ] タブをクリックします。
ステップ 1:機能ゲートの有効化
グループスナップショットを作成する前に、csi-provisioner で EnableVolumeGroupSnapshots 機能ゲートを有効にします。
-
ACK コンソールにログインします。左側のナビゲーションウィンドウで、[クラスター] をクリックします。
-
[クラスター] ページで、クラスター名をクリックします。左側のナビゲーションウィンドウで、[運用管理] > [アドオン] を選択します。
-
[アドオン] ページで、csi-provisioner カードを見つけ、右下隅の [設定] をクリックします。
-
[csi-provisioner パラメーター] ダイアログボックスで、FeatureGate フィールドを
EnableVolumeGroupSnapshots=trueに設定し、[OK] をクリックします。他の機能ゲートがすでに有効になっている場合は、新しいゲートを追加します:xxxxxx=true,yyyyyy=false,EnableVolumeGroupSnapshots=true。
ステップ 2:MySQL StatefulSet のデプロイ
この例では、2 つのレプリカを持つ MySQL StatefulSet を使用します。各レプリカは 20 GiB の ESSD ディスクを PVC としてマウントし、グループとしてスナップショットを作成するための 2 つのディスクを提供します。
-
次の内容で
mysql.yamlを作成します:<details><summary>mysql.yaml</summary>apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: selector: matchLabels: app: mysql serviceName: "mysql" replicas: 2 template: metadata: labels: app: mysql spec: containers: - name: mysql image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/mysql:8.0.30-8.6 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-pass key: password imagePullPolicy: IfNotPresent volumeMounts: - name: data mountPath: /var/lib/mysql # MySQL データディレクトリ subPath: mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "alicloud-disk-essd" resources: requests: storage: 20Gi --- apiVersion: v1 kind: Secret metadata: name: mysql-pass type: Opaque data: password: MTIzNDU2 # "123456" の Base64 エンコード値 username: cm9vdA== # "root" の Base64 エンコード値</details>
-
StatefulSet をデプロイします:
kubectl apply -f mysql.yaml -
両方の Pod レプリカにテストデータを書き込みます。
mysql-0Pod にログインし、行を挿入します:kubectl exec -it mysql-0 -- bash # Pod 内でシェルを開く mysql -uroot -p123456 # MySQL に接続するCREATE DATABASE test; USE test; CREATE TABLE scores ( name VARCHAR(50) NOT NULL, score INT AUTO_INCREMENT PRIMARY KEY ); INSERT INTO scores(name, score) VALUES ("Amy", 95); SELECT * FROM scores;期待される出力:
+------+-------+ | name | score | +------+-------+ | Amy | 95 | +------+-------+mysql-1Pod についても同じ手順を繰り返します。
ステップ 3:グループスナップショットの作成
VolumeGroupSnapshotClass の作成
クラスターには、alibabacloud-disk-group-snapshot という名前のデフォルトの VolumeGroupSnapshotClass がすでに利用可能です。カスタムクラスを使用するには、group-snapshot-class-demo.yaml を作成します:
apiVersion: groupsnapshot.storage.k8s.io/v1alpha1
kind: VolumeGroupSnapshotClass
metadata:
name: group-snapshot-class-demo
deletionPolicy: Delete
driver: diskplugin.csi.alibabacloud.com
deletionPolicy フィールドは、VolumeGroupSnapshot を削除したときに、基盤となる ECS スナップショット整合性グループがどうなるかを制御します:
| 値 | 動作 |
|---|---|
Delete |
VolumeGroupSnapshotContent と ECS スナップショット整合性グループを削除します |
Retain |
VolumeGroupSnapshotContent と ECS スナップショット整合性グループを保持します |
クラスを適用します:
kubectl apply -f group-snapshot-class-demo.yaml
VolumeGroupSnapshot の作成
MySQL アプリケーションにマウントされた両方の PVC のスナップショットを作成するために、group-snapshot-demo.yaml を作成します:
apiVersion: groupsnapshot.storage.k8s.io/v1alpha1
kind: VolumeGroupSnapshot
metadata:
name: group-snapshot-demo
namespace: default
spec:
source:
selector:
matchLabels:
app: mysql # このラベルを持つすべての PVC を選択します
volumeGroupSnapshotClassName: group-snapshot-class-demo
source.selector フィールドは、ラベルセレクターを使用してバックアップする PVC を識別します。StatefulSet の volumeClaimTemplates から作成された PVC には、StatefulSet の Pod ラベルが自動的に付与されます。PVC を手動で作成した場合は、このステップを実行する前に対応するラベルを追加してください。
VolumeGroupSnapshot を適用します:
kubectl apply -f group-snapshot-demo.yaml
ステップ 4:グループスナップショットの確認
-
VolumeGroupSnapshot を監視し、
READYTOUSEがfalseからtrueに変わるまで待ちます:kubectl get vgs group-snapshot-demo -w -
スナップショットの詳細を調べて、どの PVC がどの VolumeSnapshot にマッピングされているかを確認します:
フィールド 説明 Bound Volume Group Snapshot Content Nameこの VolumeGroupSnapshot にバインドされた VolumeGroupSnapshotContent Persistent Volume Claim Refバックアップされた PVC の名前 Volume Snapshot Refその PVC のために作成された VolumeSnapshot kubectl describe vgs group-snapshot-demo期待される出力 (省略):
Status: Bound Volume Group Snapshot Content Name: groupsnapcontent-adcef6ef-811a-4e9d-ba51-3927caxxxxxx Creation Time: 2024-11-27T06:02:56Z Pvc Volume Snapshot Ref List: Persistent Volume Claim Ref: Name: disk-mysql-0 Volume Snapshot Ref: Name: snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7xxxxxx-2024-11-27-6.4.7 Persistent Volume Claim Ref: Name: disk-mysql-1 Volume Snapshot Ref: Name: snapshot-37a2fbf634d68cd2103f261313c2ed781fbd2bd52b5a0d0e0c0ef7c339xxxxxx-2024-11-27-6.4.9 -
両方の VolumeSnapshot が準備完了であることを確認します:
kubectl get volumesnapshot両方のスナップショットで
READYTOUSE: trueが表示されるはずです。 -
ECS スナップショット整合性グループ ID を取得します:
kubectl describe vgsc groupsnapcontent-adcef6ef-811a-4e9d-ba51-3927caxxxxxx期待される出力 (省略):
Volume Group Snapshot Handle: ssg-2zeg72d1qym6vnxxxxxxECS コンソールでスナップショット整合性グループを表示するには、ECS コンソールに移動し、左側のナビゲーションウィンドウで [ストレージとスナップショット] > [スナップショット] を選択し、[スナップショット整合性グループ] タブをクリックして、
ssg-2zeg72d1qym6vnxxxxxxを検索します。
ステップ 5:スナップショットからのディスクボリュームの復元
2 つの復元オプションが利用可能です。1 つのボリュームを手動で復元するか、スクリプトを使用してすべてのボリュームを一度にバッチで復元します。
オプション 1:単一ボリュームの復元
次の例では、disk-mysql-0 Pod にアタッチされたディスクボリュームを復元します。
disk-mysql-0-copy.yaml を作成します。dataSource フィールドは、指定された VolumeSnapshot から新しいディスクをプロビジョニングするように CSI に指示します:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: disk-mysql-0-copy
spec:
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: "alicloud-disk-essd"
dataSource:
name: snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7xxxxxx-2024-11-27-6.4.7 # [1]
kind: VolumeSnapshot # [2]
apiGroup: snapshot.storage.k8s.io # [3]
-
[1]
disk-mysql-0をバックアップする VolumeSnapshot の名前 (上記のkubectl describe vgsの出力から)。 -
[2] リソースの種類 — スナップショットから復元する場合は常に
VolumeSnapshotです。 -
[3] CSI スナップショットリソースの API グループ。
PVC を適用します:
kubectl apply -f disk-mysql-0-copy.yaml
PVC がバインドされていることを確認します:
kubectl get pvc disk-mysql-0-copy
期待される出力:
disk-mysql-0-copy Bound d-2ze0iwwqg0s6b0xxxxxx 20Gi RWO alicloud-disk-essd <unset> 69s
ディスクがスナップショットから作成されたことを確認するには、ECS コンソールに移動し、左側のナビゲーションウィンドウで [ストレージとスナップショット] > [ブロックストレージ] を選択し、[クラウドディスク] タブをクリックして、d-2ze0iwwqg0s6b0xxxxxx を検索します。ディスク詳細ページを開くと、スナップショットから作成されたことがわかります。
オプション 2:すべてのボリュームを一度にバッチで復元
generate_pvc.sh スクリプトを使用して、VolumeGroupSnapshot から PVC マニフェストを自動的に生成し、一度にすべて適用します。
-
jqコマンドラインツールをインストールします:-
CentOS:
yum install jq -
Ubuntu:
apt-get install jq
-
-
MySQL StatefulSet のレプリカ数を 0 にスケールダウンして、復元前にすべての書き込みを停止します:
kubectl scale sts mysql --replicas=0 -
既存の PVC を削除します:
kubectl delete pvc data-mysql-0 data-mysql-1 -
次の内容で
generate_pvc.shを作成します:<details><summary>generate_pvc.sh</summary>パラメーター 説明 例 1 VolumeGroupSnapshot の名前空間 default2 VolumeGroupSnapshot の名前 group-snapshot-demo3 復元された PVC の StorageClass 名 alicloud-disk-essd4 ディスク容量 20Gi5 kubeconfig ファイルへのパス .kube/config6 生成された PVC YAML の出力パス ./output.yaml#!/bin/bash # 入力パラメーター NAMESPACE=$1 # VolumeGroupSnapshot の名前空間 VGS_NAME=$2 # VolumeGroupSnapshot の名前 STORAGE_CLASS_NAME=$3 # 復元された PVC の StorageClass CAPACITY=$4 # ディスク容量 (例:20Gi) KUBECONFIG_PATH=$5 # kubeconfig ファイルへのパス OUTPUT_FILE=$6 # 生成された YAML の出力パス # VolumeGroupSnapshot の詳細を取得 VGS_INFO=$(kubectl --kubeconfig=${KUBECONFIG_PATH} -n ${NAMESPACE} get vgs ${VGS_NAME} -o json) # PVC とスナップショットのマッピングが存在することを確認 if ! echo ${VGS_INFO} | jq -e '.status.pvcVolumeSnapshotRefList' &>/dev/null; then echo "エラー: .status.pvcVolumeSnapshotRefList が VolumeGroupSnapshot に見つかりません。" exit 1 fi # PVC 名とそれに対応するスナップショット名を取得 PVCS=($(echo ${VGS_INFO} | jq -r '.status.pvcVolumeSnapshotRefList[].persistentVolumeClaimRef.name')) SNAPSHOTS=($(echo ${VGS_INFO} | jq -r '.status.pvcVolumeSnapshotRefList[].volumeSnapshotRef.name')) # 出力ファイルをクリア > ${OUTPUT_FILE} # ディスクごとに 1 つの PVC マニフェストを生成 for i in "${!PVCS[@]}"; do PVC_NAME=${PVCS[$i]} SNAPSHOT_NAME=${SNAPSHOTS[$i]} cat <<EOF >> ${OUTPUT_FILE} --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: ${PVC_NAME} spec: volumeMode: Filesystem accessModes: - ReadWriteOnce resources: requests: storage: ${CAPACITY} storageClassName: "${STORAGE_CLASS_NAME}" dataSource: name: ${SNAPSHOT_NAME} kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io EOF done echo "PVC YAML ファイルが ${OUTPUT_FILE} に書き込まれました"</details> このスクリプトは、6 つの位置パラメーターを受け取ります:
-
スクリプトを実行して PVC マニフェストを生成します:
bash generate_pvc.sh default group-snapshot-demo alicloud-disk-essd 20Gi .kube/config ./output.yaml生成された
output.yamlは次のようになります:--- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: disk-mysql-0 spec: volumeMode: Filesystem accessModes: - ReadWriteOnce resources: requests: storage: 20Gi storageClassName: "alicloud-disk-essd" dataSource: name: snapshot-1c2c5bcaf47ee2bffcc5b2f52dff65a4aacaaea38032c05d75acd536f7adb850-2024-11-27-6.4.7 kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: disk-mysql-1 spec: volumeMode: Filesystem accessModes: - ReadWriteOnce resources: requests: storage: 20Gi storageClassName: "alicloud-disk-essd" dataSource: name: snapshot-37a2fbf634d68cd2103f261313c2ed781fbd2bd52b5a0d0e0c0ef7c3396fea1c-2024-11-27-6.4.9 kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io必要に応じて
output.yamlを編集し、適用します:kubectl apply -f output.yaml -
StatefulSet のレプリカ数を 2 に戻します:
kubectl scale sts mysql --replicas=2 -
Pod が再起動した後、データが復元されたことを確認します:
kubectl exec -it mysql-0 -- bash # Pod 内でシェルを開く mysql -uroot -p123456 # MySQL に接続する use test; select * from scores;期待される出力:
+------+-------+ | name | score | +------+-------+ | Amy | 95 | +------+-------+