Quando vários discos sustentam uma aplicação com estado no Container Service for Kubernetes (ACK), criar VolumeSnapshots individuais para cada disco pode gerar pontos de recuperação inconsistentes, pois cada snapshot captura um momento ligeiramente diferente. Os snapshots de grupo resolvem esse problema ao acionar todos os snapshots simultaneamente, garantindo que cada disco do grupo seja capturado no mesmo instante. Isso reduz o risco de inconsistência de dados durante a restauração de uma aplicação em múltiplos volumes.
Como funciona
Os snapshots de grupo baseiam-se nos grupos consistentes de snapshots do ECS. O ACK fornece as seguintes CustomResourceDefinitions (CRDs) para gerenciar esses snapshots:
|
CRD |
Análogo a |
Finalidade |
|
VolumeGroupSnapshotClass |
StorageClass |
Define o driver e a política de exclusão para snapshots de grupo |
|
VolumeGroupSnapshot |
PersistentVolumeClaim (PVC) |
Solicitação para criar snapshot de um conjunto de discos, identificados por um seletor de rótulos |
|
VolumeGroupSnapshotContent |
PersistentVolume (PV) |
Registra o grupo consistente de snapshots do ECS criado para a solicitação |
|
VolumeSnapshot |
— |
Solicitação de snapshot de volume; criada automaticamente para cada disco após a criação do VolumeGroupSnapshot |
|
VolumeSnapshotContent |
— |
Registra informações sobre um snapshot do ECS |
Ao criar um VolumeGroupSnapshot, o plug-in Container Storage Interface (CSI) cria um grupo consistente de snapshots do ECS e gera automaticamente um VolumeSnapshot e um VolumeSnapshotContent para cada disco selecionado. Se houver falha em um disco, restaure-o a partir do VolumeSnapshot correspondente.
Faturamento
Grupos consistentes de snapshots são gratuitos. Os snapshots dentro do grupo são cobrados com base no armazenamento consumido. Para mais detalhes, consulte Faturamento de snapshots.
Limitações
Snapshots de grupo seguem os mesmos limites dos snapshots do ECS. Consulte Limites.
Grupos consistentes de snapshots do ECS não suportam tempos de expiração. Exclua manualmente os snapshots de grupo quando não forem mais necessários.
Pré-requisitos
Antes de começar, verifique se você possui:
Um cluster gerenciado ACK executando Kubernetes 1.28 ou posterior. Consulte Criar um cluster gerenciado ACK.
O plug-in CSI instalado na versão 1.31.4 ou posterior. Para atualizar o csi-plugin e o csi-provisioner, consulte Atualizar csi-plugin e csi-provisioner.
O serviço de Snapshot do Elastic Compute Service (ECS) ativado (ativação gratuita). Consulte Ativar Snapshot do ECS.
Se o cluster utilizar FlexVolume (obsoleto no ACK), faça upgrade para CSI antes de criar snapshots de grupo. Consulte Upgrade de FlexVolume para CSI. Para verificar qual plug-in de volume está instalado, acesse a página de detalhes do cluster no console ACK, escolha Operations > Add-ons no painel de navegação à esquerda e clique na aba Storage.
Etapa 1: Ative o feature gate
Ative o feature gate EnableVolumeGroupSnapshots no csi-provisioner antes de criar snapshots de grupo.
Faça login no console ACK. No painel de navegação à esquerda, clique em Clusters.
Na página Clusters, clique no nome do cluster. No painel de navegação à esquerda, escolha Operations > Add-ons.
Na página Add-ons, localize o cartão csi-provisioner e clique em Configuration no canto inferior direito.
Na caixa de diálogo csi-provisioner Parameters, defina o campo FeatureGate como
EnableVolumeGroupSnapshots=truee clique em OK. Caso outros feature gates já estejam ativados, adicione o novo ao final:xxxxxx=true,yyyyyy=false,EnableVolumeGroupSnapshots=true.
Etapa 2: Implante um StatefulSet MySQL
Este exemplo utiliza um StatefulSet MySQL com duas réplicas. Cada réplica monta um disco ESSD de 20 GiB como PVC, resultando em dois discos para criar snapshot em grupo.
-
Crie o arquivo
mysql.yamlcom o seguinte conteúdo: <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 data directory 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 # Base64-encoded value of "123456" username: cm9vdA== # Base64-encoded value of "root"</details>
-
Implante o StatefulSet:
kubectl apply -f mysql.yaml -
Escreva dados de teste em ambas as réplicas de pod. Acesse o pod
mysql-0e insira uma linha:kubectl exec -it mysql-0 -- bash # Open a shell in the pod mysql -uroot -p123456 # Connect to MySQLCREATE 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;Saída esperada:
+------+-------+ | name | score | +------+-------+ | Amy | 95 | +------+-------+Repita os mesmos passos para o pod
mysql-1.
Etapa 3: Crie snapshots de grupo
Crie um VolumeGroupSnapshotClass
Um VolumeGroupSnapshotClass padrão chamado alibabacloud-disk-group-snapshot já está disponível no cluster. Para usar uma classe personalizada, crie o arquivo 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
O campo deletionPolicy controla o que acontece com o grupo consistente de snapshots do ECS subjacente quando você exclui o VolumeGroupSnapshot:
|
Valor |
Comportamento |
|
|
Exclui o VolumeGroupSnapshotContent e o grupo consistente de snapshots do ECS |
|
|
Mantém o VolumeGroupSnapshotContent e o grupo consistente de snapshots do ECS |
Aplique a classe:
kubectl apply -f group-snapshot-class-demo.yaml
Crie um VolumeGroupSnapshot
Crie o arquivo group-snapshot-demo.yaml para criar snapshot de ambos os PVCs montados na aplicação MySQL:
apiVersion: groupsnapshot.storage.k8s.io/v1alpha1
kind: VolumeGroupSnapshot
metadata:
name: group-snapshot-demo
namespace: default
spec:
source:
selector:
matchLabels:
app: mysql # Selects all PVCs with this label
volumeGroupSnapshotClassName: group-snapshot-class-demo
O campo source.selector usa um seletor de rótulos para identificar os PVCs a serem incluídos no backup. PVCs criados a partir dos volumeClaimTemplates de um StatefulSet recebem automaticamente os rótulos dos pods desse StatefulSet. Se você criou seus PVCs manualmente, adicione os rótulos correspondentes antes de executar esta etapa.
Aplique o VolumeGroupSnapshot:
kubectl apply -f group-snapshot-demo.yaml
Etapa 4: Verifique os snapshots de grupo
-
Monitore o VolumeGroupSnapshot até que
READYTOUSEmude defalseparatrue:kubectl get vgs group-snapshot-demo -w -
Inspecione os detalhes do snapshot para ver qual PVC corresponde a qual VolumeSnapshot:
Campo
Descrição
Bound Volume Group Snapshot Content NameO VolumeGroupSnapshotContent vinculado a este VolumeGroupSnapshot
Persistent Volume Claim RefO nome do PVC que recebeu backup
Volume Snapshot RefO VolumeSnapshot criado para esse PVC
kubectl describe vgs group-snapshot-demoSaída esperada (abreviada):
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 -
Confirme se ambos os VolumeSnapshots estão prontos:
kubectl get volumesnapshotAmbos os snapshots devem exibir
READYTOUSE: true. -
Obtenha o ID do grupo consistente de snapshots do ECS:
kubectl describe vgsc groupsnapcontent-adcef6ef-811a-4e9d-ba51-3927caxxxxxxSaída esperada (abreviada):
Volume Group Snapshot Handle: ssg-2zeg72d1qym6vnxxxxxxPara visualizar o grupo consistente de snapshots no console ECS, acesse o console ECS, escolha Storage & Snapshots > Snapshots no painel de navegação à esquerda, clique na aba Snapshot-consistent Groups e pesquise por
ssg-2zeg72d1qym6vnxxxxxx.
Etapa 5: Restaure volumes de disco a partir de snapshots
Existem duas opções de restauração: restaurar um único volume manualmente ou restaurar todos os volumes em lote usando um script.
Opção 1: Restaure um único volume
O exemplo a seguir restaura o volume de disco anexado ao pod disk-mysql-0.
Crie o arquivo disk-mysql-0-copy.yaml. O campo dataSource instrui o CSI a provisionar um novo disco a partir do VolumeSnapshot especificado:
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] Nome do VolumeSnapshot que contém o backup de
disk-mysql-0(obtido na saída do comandokubectl describe vgsacima).[2] Tipo de recurso — sempre
VolumeSnapshotao restaurar a partir de um snapshot.[3] Grupo de API para os recursos de snapshot do CSI.
Aplique o PVC:
kubectl apply -f disk-mysql-0-copy.yaml
Verifique se o PVC está vinculado:
kubectl get pvc disk-mysql-0-copy
Saída esperada:
disk-mysql-0-copy Bound d-2ze0iwwqg0s6b0xxxxxx 20Gi RWO alicloud-disk-essd <unset> 69s
Para confirmar que o disco foi criado a partir do snapshot, acesse o console ECS, escolha Storage & Snapshots > Block Storage no painel de navegação à esquerda, clique na aba Cloud Disk e pesquise por d-2ze0iwwqg0s6b0xxxxxx. Abra a página de detalhes do disco para verificar que ele foi criado a partir de um snapshot.
Opção 2: Restaure todos os volumes em lote
Utilize o script generate_pvc.sh para gerar automaticamente manifestos de PVC a partir de um VolumeGroupSnapshot e aplicá-los de uma só vez.
-
Instale a ferramenta de linha de comando
jq:CentOS:
yum install jqUbuntu:
apt-get install jq
-
Redimensione o StatefulSet MySQL para zero réplicas a fim de interromper todas as gravações antes da restauração:
kubectl scale sts mysql --replicas=0 -
Exclua os PVCs existentes:
kubectl delete pvc data-mysql-0 data-mysql-1 -
Crie o arquivo
generate_pvc.shcom o seguinte conteúdo: <details><summary>generate_pvc.sh</summary>Parâmetro
Descrição
Exemplo
1
Namespace do VolumeGroupSnapshot
default2
Nome do VolumeGroupSnapshot
group-snapshot-demo3
Nome da StorageClass para os PVCs restaurados
alicloud-disk-essd4
Capacidade do disco
20Gi5
Caminho para o arquivo kubeconfig
.kube/config6
Caminho de saída para o YAML de PVC gerado
./output.yaml#!/bin/bash # Input parameters NAMESPACE=$1 # Namespace of the VolumeGroupSnapshot VGS_NAME=$2 # Name of the VolumeGroupSnapshot STORAGE_CLASS_NAME=$3 # StorageClass for the restored PVCs CAPACITY=$4 # Disk capacity (e.g., 20Gi) KUBECONFIG_PATH=$5 # Path to the kubeconfig file OUTPUT_FILE=$6 # Output path for the generated YAML # Get VolumeGroupSnapshot details VGS_INFO=$(kubectl --kubeconfig=${KUBECONFIG_PATH} -n ${NAMESPACE} get vgs ${VGS_NAME} -o json) # Validate that the PVC-snapshot mapping exists if ! echo ${VGS_INFO} | jq -e '.status.pvcVolumeSnapshotRefList' &>/dev/null; then echo "Error: .status.pvcVolumeSnapshotRefList not found in VolumeGroupSnapshot." exit 1 fi # Extract PVC names and their corresponding snapshot names PVCS=($(echo ${VGS_INFO} | jq -r '.status.pvcVolumeSnapshotRefList[].persistentVolumeClaimRef.name')) SNAPSHOTS=($(echo ${VGS_INFO} | jq -r '.status.pvcVolumeSnapshotRefList[].volumeSnapshotRef.name')) # Clear the output file > ${OUTPUT_FILE} # Generate one PVC manifest per disk 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 files have been written to ${OUTPUT_FILE}"</details> O script aceita seis parâmetros posicionais:
-
Execute o script para gerar os manifestos de PVC:
bash generate_pvc.sh default group-snapshot-demo alicloud-disk-essd 20Gi .kube/config ./output.yamlO arquivo
output.yamlgerado será semelhante a:--- 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.ioEdite o arquivo
output.yamlse necessário e aplique-o:kubectl apply -f output.yaml -
Redimensione o StatefulSet novamente para duas réplicas:
kubectl scale sts mysql --replicas=2 -
Após a reinicialização dos pods, verifique se os dados foram restaurados:
kubectl exec -it mysql-0 -- bash # Open a shell in the pod mysql -uroot -p123456 # Connect to MySQL use test; select * from scores;Saída esperada:
+------+-------+ | name | score | +------+-------+ | Amy | 95 | +------+-------+