Миграция из класса хранилища в дерево в драйверы CSI на Служба Azure Kubernetes (AKS)
Реализация драйвера интерфейса хранилища контейнеров (CSI) появилась в Служба Azure Kubernetes (AKS) начиная с версии 1.21. При внедрении и использовании CSI в качестве стандарта существующие рабочие нагрузки с отслеживанием состояния с использованием постоянных томов (PV) в дереве должны быть перенесены или обновлены для использования драйвера CSI.
Чтобы сделать этот процесс максимально простым и обеспечить отсутствие потери данных, эта статья предоставляет различные варианты миграции. К этим параметрам относятся сценарии, которые помогут обеспечить плавное перемещение из дерева на диски Azure и драйверы CSI Файлы Azure.
Подготовка к работе
- Azure CLI версии 2.37.0 или более поздней. Запустите
az --version
, чтобы определить версию и запуститеaz upgrade
для обновления версии. Если вам необходимо выполнить установку или обновление, см. статью Установка Azure CLI 2.0. - Администраторы kubectl и кластеров имеют доступ к созданию, получении, списку, удалению доступа к ПВХ или PV, моментальному снимку тома или содержимому моментального снимка тома. Для кластера с поддержкой Microsoft Entra RBAC вы являетесь членом роли администратора кластера RBAC Служба Azure Kubernetes.
Перенос томов дисков
Примечание.
Метки и failure-domain.beta.kubernetes.io/region
устарели в AKS 1.24 и удалены failure-domain.beta.kubernetes.io/zone
в версии 1.28. Если существующие постоянные тома по-прежнему используют nodeAffinity, соответствующие этим двум меткам, необходимо изменить их на topology.kubernetes.io/zone
и topology.kubernetes.io/region
метки в новом параметре постоянного тома.
Миграция из дерева в CSI поддерживается с помощью двух вариантов миграции:
- Создание статического тома
- Создание динамического тома
Создание статического тома
Используя этот параметр, вы создадите PV путем статического назначения claimRef
новому ПВХ, который вы создадите позже, и укажите volumeName
для PersistentVolumeClaim.
Преимущества этого подхода
- Это простая задача, и ее можно автоматизировать.
- Нет необходимости очищать исходную конфигурацию с помощью класса хранения в дереве.
- Низкий риск, так как вы выполняете только логическое удаление объекта PV или PVC Kubernetes, фактические физические данные не удаляются.
- Дополнительные затраты, связанные с отсутствием необходимости создавать дополнительные объекты Azure, такие как диск, моментальные снимки и т. д.
Ниже приведены важные рекомендации по оценке:
- Чтобы перейти c исходных динамических томов на статические тома, для всех вариантов требуется создать объекты PV и управлять ими вручную.
- При повторном развертывании нового приложения со ссылкой на новый объект PVC может возникнуть простой приложения.
Миграция
Обновите существующий PV
ReclaimPolicy
из delete to Storage , выполнив следующую команду:kubectl patch pv pvName -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
Замените pvName именем выбранного объекта PersistentVolume. Кроме того, если вы хотите обновить reclaimPolicy для нескольких PV, создайте файл с именем patchReclaimPVs.sh и скопируйте его в следующем коде.
#!/bin/bash # Patch the Persistent Volume in case ReclaimPolicy is Delete NAMESPACE=$1 i=1 for PVC in $(kubectl get pvc -n $NAMESPACE | awk '{ print $1}'); do # Ignore first record as it contains header if [ $i -eq 1 ]; then i=$((i + 1)) else PV="$(kubectl get pvc $PVC -n $NAMESPACE -o jsonpath='{.spec.volumeName}')" RECLAIMPOLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" echo "Reclaim Policy for Persistent Volume $PV is $RECLAIMPOLICY" if [[ $RECLAIMPOLICY == "Delete" ]]; then echo "Updating ReclaimPolicy for $pv to Retain" kubectl patch pv $PV -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' fi fi done
Выполните скрипт с параметром
namespace
, чтобы указать пространство./PatchReclaimPolicy.sh <namespace>
имен кластера.Получите список всех pvCs в пространстве имен, отсортированных по созданиюTimestamp , выполнив следующую команду. Задайте пространство имен с помощью аргумента
--namespace
вместе с фактическим пространством имен кластера.kubectl get pvc -n <namespace> --sort-by=.metadata.creationTimestamp -o custom-columns=NAME:.metadata.name,CreationTime:.metadata.creationTimestamp,StorageClass:.spec.storageClassName,Size:.spec.resources.requests.storage
Этот шаг полезен, если у вас есть большое количество PV, которые необходимо перенести, и вы хотите перенести несколько за раз. При выполнении этой команды вы можете определить, какие pvCs были созданы в заданном интервале времени. При запуске скрипта CreatePV.sh два параметра — время начала и окончания, которые позволяют переносить только pvcs в течение этого периода времени.
Создайте файл с именем CreatePV.sh и скопируйте его в следующем коде. Сценарий выполняет следующее:
- Создает новый PersistentVolume с именем
existing-pv-csi
для всех PersistentVolumes в пространствах имен для классаstorageClassName
хранилища. - Настройте новое имя ПВХ как
existing-pvc-csi
. - Создает новый ПВХ с указанным именем PV.
#!/bin/bash #kubectl get pvc -n <namespace> --sort-by=.metadata.creationTimestamp -o custom-columns=NAME:.metadata.name,CreationTime:.metadata.creationTimestamp,StorageClass:.spec.storageClassName,Size:.spec.resources.requests.storage # TimeFormat 2022-04-20T13:19:56Z NAMESPACE=$1 FILENAME=$(date +%Y%m%d%H%M)-$NAMESPACE EXISTING_STORAGE_CLASS=$2 STORAGE_CLASS_NEW=$3 STARTTIMESTAMP=$4 ENDTIMESTAMP=$5 i=1 for PVC in $(kubectl get pvc -n $NAMESPACE | awk '{ print $1}'); do # Ignore first record as it contains header if [ $i -eq 1 ]; then i=$((i + 1)) else PVC_CREATION_TIME=$(kubectl get pvc $PVC -n $NAMESPACE -o jsonpath='{.metadata.creationTimestamp}') if [[ $PVC_CREATION_TIME >= $STARTTIMESTAMP ]]; then if [[ $ENDTIMESTAMP > $PVC_CREATION_TIME ]]; then PV="$(kubectl get pvc $PVC -n $NAMESPACE -o jsonpath='{.spec.volumeName}')" RECLAIM_POLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" STORAGECLASS="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.storageClassName}')" echo $PVC RECLAIM_POLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" if [[ $RECLAIM_POLICY == "Retain" ]]; then if [[ $STORAGECLASS == $EXISTING_STORAGE_CLASS ]]; then STORAGE_SIZE="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.capacity.storage}')" SKU_NAME="$(kubectl get storageClass $STORAGE_CLASS_NEW -o jsonpath='{.parameters.skuname}')" DISK_URI="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.azureDisk.diskURI}')" PERSISTENT_VOLUME_RECLAIM_POLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" cat >$PVC-csi.yaml <<EOF apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: disk.csi.azure.com name: $PV-csi spec: accessModes: - ReadWriteOnce capacity: storage: $STORAGE_SIZE claimRef: apiVersion: v1 kind: PersistentVolumeClaim name: $PVC-csi namespace: $NAMESPACE csi: driver: disk.csi.azure.com volumeAttributes: csi.storage.k8s.io/pv/name: $PV-csi csi.storage.k8s.io/pvc/name: $PVC-csi csi.storage.k8s.io/pvc/namespace: $NAMESPACE requestedsizegib: "$STORAGE_SIZE" skuname: $SKU_NAME volumeHandle: $DISK_URI persistentVolumeReclaimPolicy: $PERSISTENT_VOLUME_RECLAIM_POLICY storageClassName: $STORAGE_CLASS_NEW --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: $PVC-csi namespace: $NAMESPACE spec: accessModes: - ReadWriteOnce storageClassName: $STORAGE_CLASS_NEW resources: requests: storage: $STORAGE_SIZE volumeName: $PV-csi EOF kubectl apply -f $PVC-csi.yaml LINE="PVC:$PVC,PV:$PV,StorageClassTarget:$STORAGE_CLASS_NEW" printf '%s\n' "$LINE" >>$FILENAME fi fi fi fi fi done
- Создает новый PersistentVolume с именем
Чтобы создать новый PersistentVolume для всех PersistentVolumes в пространстве имен, выполните скрипт CreatePV.sh со следующими параметрами:
namespace
— пространство имен кластераsourceStorageClass
— Класс storage на основе драйвера на основе дереваtargetCSIStorageClass
— Класс storage на основе драйвера хранилища CSI, который может быть одним из классов хранилища по умолчанию, для которых задано значение disk.csi.azure.com или file.csi.azure.com. Кроме того, можно создать пользовательский класс хранилища до тех пор, пока он установлен для одного из этих двух средств подготовки.startTimeStamp
— Предоставьте время начала до создания ПВХ в формате гггг-мм-ддthh:мм:sszendTimeStamp
— Укажите время окончания в формате гггг-мм-ддthh:mm:ssz.
./CreatePV.sh <namespace> <sourceIntreeStorageClass> <targetCSIStorageClass> <startTimestamp> <endTimestamp>
Обновите приложение, чтобы использовать новый ПВХ.
Создание динамического тома
С помощью этого параметра динамически создается постоянный том из утверждения постоянного тома.
Преимущества этого подхода
Это менее рискованно, так как все новые объекты создаются при сохранении других копий с моментальными снимками.
Нет необходимости создавать тома PV отдельно и добавлять имя тома в манифест PVC.
Ниже приведены важные рекомендации по оценке:
Этот подход является менее рискованным, но при его применении создается несколько объектов, что увеличивает затраты на хранение.
Во время создания новых томов приложение недоступно.
Действия по удалению следует выполнять с осторожностью. Временные блокировки ресурсов можно применять к группе ресурсов до завершения миграции и успешной проверки приложения.
По мере создания дисков на основе моментальных снимков выполняйте проверку данных.
Миграция
Прежде чем продолжить, проверьте следующее:
Для определенных рабочих нагрузок, в которых данные записываются в память перед записью на диск, приложение должно быть остановлено и разрешить очистку данных в памяти на диск.
VolumeSnapshot
класс должен существовать, как показано в следующем примере YAML:apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata: name: custom-disk-snapshot-sc driver: disk.csi.azure.com deletionPolicy: Delete parameters: incremental: "false"
Получите список всех PVC в указанном пространстве имен, отсортированных по созданиюTimestamp , выполнив следующую команду. Задайте пространство имен с помощью аргумента
--namespace
вместе с фактическим пространством имен кластера.kubectl get pvc --namespace <namespace> --sort-by=.metadata.creationTimestamp -o custom-columns=NAME:.metadata.name,CreationTime:.metadata.creationTimestamp,StorageClass:.spec.storageClassName,Size:.spec.resources.requests.storage
Этот шаг полезен, если у вас есть большое количество PV, которые необходимо перенести, и вы хотите перенести несколько за раз. При выполнении этой команды вы можете определить, какие pvCs были созданы в заданном интервале времени. При запуске скрипта MigrateCSI.sh два параметра — время начала и окончания, которые позволяют переносить только pvcs в течение этого периода времени.
Создайте файл с именем MigrateToCSI.sh и скопируйте его в следующем коде. Сценарий выполняет следующее:
- Создание полного моментального снимка диска с помощью Azure CLI
- Создает
VolumesnapshotContent
- Создает
VolumeSnapshot
- Создает новый ПВХ из
VolumeSnapshot
- Создает новый файл с именем
<namespace>-timestamp
файла, который содержит список всех старых ресурсов, которые необходимо очистить.
#!/bin/bash #kubectl get pvc -n <namespace> --sort-by=.metadata.creationTimestamp -o custom-columns=NAME:.metadata.name,CreationTime:.metadata.creationTimestamp,StorageClass:.spec.storageClassName,Size:.spec.resources.requests.storage # TimeFormat 2022-04-20T13:19:56Z NAMESPACE=$1 FILENAME=$NAMESPACE-$(date +%Y%m%d%H%M) EXISTING_STORAGE_CLASS=$2 STORAGE_CLASS_NEW=$3 VOLUME_STORAGE_CLASS=$4 START_TIME_STAMP=$5 END_TIME_STAMP=$6 i=1 for PVC in $(kubectl get pvc -n $NAMESPACE | awk '{ print $1}'); do # Ignore first record as it contains header if [ $i -eq 1 ]; then i=$((i + 1)) else PVC_CREATION_TIME=$(kubectl get pvc $PVC -n $NAMESPACE -o jsonpath='{.metadata.creationTimestamp}') if [[ $PVC_CREATION_TIME > $START_TIME_STAMP ]]; then if [[ $END_TIME_STAMP > $PVC_CREATION_TIME ]]; then PV="$(kubectl get pvc $PVC -n $NAMESPACE -o jsonpath='{.spec.volumeName}')" RECLAIM_POLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" STORAGE_CLASS="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.storageClassName}')" echo $PVC RECLAIM_POLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" if [[ $STORAGE_CLASS == $EXISTING_STORAGE_CLASS ]]; then STORAGE_SIZE="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.capacity.storage}')" SKU_NAME="$(kubectl get storageClass $STORAGE_CLASS_NEW -o jsonpath='{.parameters.skuname}')" DISK_URI="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.azureDisk.diskURI}')" TARGET_RESOURCE_GROUP="$(cut -d'/' -f5 <<<"$DISK_URI")" echo $DISK_URI SUBSCRIPTION_ID="$(echo $DISK_URI | grep -o 'subscriptions/[^/]*' | sed 's#subscriptions/##g')" echo $TARGET_RESOURCE_GROUP PERSISTENT_VOLUME_RECLAIM_POLICY="$(kubectl get pv $PV -n $NAMESPACE -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" az snapshot create --resource-group $TARGET_RESOURCE_GROUP --name $PVC-$FILENAME --source "$DISK_URI" --subscription ${SUBSCRIPTION_ID} SNAPSHOT_PATH=$(az snapshot list --resource-group $TARGET_RESOURCE_GROUP --query "[?name == '$PVC-$FILENAME'].id | [0]" --subscription ${SUBSCRIPTION_ID}) SNAPSHOT_HANDLE=$(echo "$SNAPSHOT_PATH" | tr -d '"') echo $SNAPSHOT_HANDLE sleep 10 # Create Restore File cat <<EOF >$PVC-csi.yml apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotContent metadata: name: $PVC-$FILENAME spec: deletionPolicy: 'Delete' driver: 'disk.csi.azure.com' volumeSnapshotClassName: $VOLUME_STORAGE_CLASS source: snapshotHandle: $SNAPSHOT_HANDLE volumeSnapshotRef: apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot name: $PVC-$FILENAME namespace: $1 --- apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: $PVC-$FILENAME namespace: $1 spec: volumeSnapshotClassName: $VOLUME_STORAGE_CLASS source: volumeSnapshotContentName: $PVC-$FILENAME --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: csi-$PVC namespace: $1 spec: accessModes: - ReadWriteOnce storageClassName: $STORAGE_CLASS_NEW resources: requests: storage: $STORAGE_SIZE dataSource: name: $PVC-$FILENAME kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io EOF kubectl create -f $PVC-csi.yml LINE="OLDPVC:$PVC,OLDPV:$PV,VolumeSnapshotContent:volumeSnapshotContent-$FILENAME,VolumeSnapshot:volumesnapshot$FILENAME,OLDdisk:$DISK_URI" printf '%s\n' "$LINE" >>$FILENAME fi fi fi fi done
Чтобы перенести тома дисков, выполните скрипт MigrateToCSI.sh со следующими параметрами:
namespace
— пространство имен кластераsourceStorageClass
— Класс storage на основе драйвера на основе дереваtargetCSIStorageClass
— Класс storage на основе драйвера хранилища CSIvolumeSnapshotClass
— Имя класса моментального снимка тома. Например,custom-disk-snapshot-sc
.startTimeStamp
— Укажите время начала в формате гггг-мм-ддthh:mm:ssz.endTimeStamp
— Укажите время окончания в формате гггг-мм-ддthh:mm:ssz.
./MigrateToCSI.sh <namespace> <sourceStorageClass> <TargetCSIstorageClass> <VolumeSnapshotClass> <startTimestamp> <endTimestamp>
Обновите приложение, чтобы использовать новый ПВХ.
Вручную удалите старые ресурсы, включая пвх/ПВ в дереве, VolumeSnapshot и VolumeSnapshotContent. Если этого не сделать, обслуживание встроенных PVC и PV, а также объектов моментальных снимков повлечет за собой дополнительные затраты.
Перенос томов общей папки
Миграция из дерева в CSI поддерживается путем создания статического тома:
- Нет необходимости очищать исходную конфигурацию с помощью класса хранения в дереве.
- Низкий риск, так как вы выполняете только логическое удаление объекта PV или PVC Kubernetes, фактические физические данные не удаляются.
- Дополнительные затраты, связанные с отсутствием необходимости создавать дополнительные объекты Azure, такие как общие папки и т. д.
Миграция
Обновите существующий PV
ReclaimPolicy
из delete to Storage , выполнив следующую команду:kubectl patch pv pvName -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
Замените pvName именем выбранного объекта PersistentVolume. Кроме того, если вы хотите обновить reclaimPolicy для нескольких PV, создайте файл с именем patchReclaimPVs.sh и скопируйте его в следующем коде.
#!/bin/bash # Patch the Persistent Volume in case ReclaimPolicy is Delete namespace=$1 i=1 for pvc in $(kubectl get pvc -n $namespace | awk '{ print $1}'); do # Ignore first record as it contains header if [ $i -eq 1 ]; then i=$((i + 1)) else pv="$(kubectl get pvc $pvc -n $namespace -o jsonpath='{.spec.volumeName}')" reclaimPolicy="$(kubectl get pv $pv -n $namespace -o jsonpath='{.spec.persistentVolumeReclaimPolicy}')" echo "Reclaim Policy for Persistent Volume $pv is $reclaimPolicy" if [[ $reclaimPolicy == "Delete" ]]; then echo "Updating ReclaimPolicy for $pv to Retain" kubectl patch pv $pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' fi fi done
Выполните скрипт с параметром
namespace
, чтобы указать пространство./PatchReclaimPolicy.sh <namespace>
имен кластера.Создайте класс хранилища с заданным параметром
file.csi.azure.com
подготовки или вы можете использовать один из классов storageClasses по умолчанию с помощью средства подготовки файлов CSI.secretName
Получите иshareName
из существующего PersistentVolumes, выполнив следующую команду:kubectl describe pv pvName
Создайте новую ПС с помощью нового класса StorageClass и
shareName
secretName
из дерева PV. Создайте файл с именем azurefile-mount-pv.yaml и скопируйте его в следующем коде. В объектеcsi
изменитеresourceGroup
,volumeHandle
иshareName
. Для параметров подключения значение по умолчанию для fileMode и dirMode равно 0777.Значение по умолчанию для
fileMode
иdirMode
равно 0777.apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: file.csi.azure.com name: azurefile spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: azurefile-csi csi: driver: file.csi.azure.com readOnly: false volumeHandle: unique-volumeid # make sure volumeid is unique for every identical share in the cluster volumeAttributes: resourceGroup: EXISTING_RESOURCE_GROUP_NAME # optional, only set this when storage account is not in the same resource group as the cluster nodes shareName: aksshare nodeStageSecretRef: name: azure-secret namespace: default mountOptions: - dir_mode=0777 - file_mode=0777 - uid=0 - gid=0 - mfsymlinks - cache=strict - nosharesock - nobrl # disable sending byte range lock requests to the server and for applications which have challenges with posix locks
Создайте файл с именем azurefile-mount-pvc.yaml с помощью объекта PersistentVolumeClaim , использующего PersistentVolume с помощью следующего кода.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: azurefile spec: accessModes: - ReadWriteMany storageClassName: azurefile-csi volumeName: azurefile resources: requests: storage: 5Gi
kubectl
Используйте команду для создания PersistentVolume.kubectl apply -f azurefile-mount-pv.yaml
kubectl
Используйте команду для создания Объекта PersistentVolumeClaim.kubectl apply -f azurefile-mount-pvc.yaml
Убедитесь, что объект PersistentVolumeClaim создается и привязан к PersistentVolume, выполнив следующую команду.
kubectl get pvc azurefile
Выходные данные выглядят следующим образом:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE azurefile Bound azurefile 5Gi RWX azurefile 5s
Обновите спецификацию контейнера, чтобы она указывала на PersistentVolumeClaim, и обновите этот объект pod. Например, скопируйте следующий код и создайте файл с именем azure-files-pod.yaml.
... volumes: - name: azure persistentVolumeClaim: claimName: azurefile
Спецификация pod не может быть обновлена. Используйте следующие
kubectl
команды для удаления и повторного создания модуля pod.kubectl delete pod mypod
kubectl apply -f azure-files-pod.yaml
Следующие шаги
- Дополнительные сведения о рекомендациях по хранению см. в Рекомендации по хранению и резервному копированию в службе Azure Kubernetes.
- Защитите недавно перенесенные PV-файлы драйвера CSI, создав их резервную копию с помощью Azure Backup для AKS.
Azure Kubernetes Service