Share via


從樹狀內儲存體類別移轉至 Azure Kubernetes Service 上的 CSI 驅動程式 (AKS)

從 1.21 版開始,Azure Kubernetes Service (AKS) 引進容器儲存體介面 (CSI) 驅動程式的實作。 藉由採用 CSI 做為標準,您應該移轉或升級使用樹狀內永續性磁碟區 (PV) 的現有具狀態工作負載,以使用 CSI 驅動程式。

為了讓此流程盡可能簡單,並確保不會遺失任何資料,本文提供不同的移轉選項。 這些選項包括指令碼,有助於確保從樹狀內順利移轉至 Azure 磁碟和 Azure 檔案服務 CSI 驅動程式。

開始之前

  • Azure CLI 版本 2.37.0 或更新版本。 執行 az --version 以尋找版本,然後執行 az upgrade 以升級版本。 如果您需要安裝或升級,請參閱安裝 Azure CLI
  • Kubectl 和叢集系統管理員可以存取建立、取得、列出、刪除對 PVC 或 PV、磁碟區快照集或磁碟區快照集內容的存取權。 針對已啟用 Microsoft Entra RBAC 的叢集,您是 Azure Kubernetes Service RBAC 叢集管理員角色的成員。

移轉磁碟區

注意

failure-domain.beta.kubernetes.io/zonefailure-domain.beta.kubernetes.io/region 標籤 在 AKS 1.24 中已淘汰,並在 1.28 中移除。 如果您的現有永續性磁碟區仍在使用符合這兩個標籤的 nodeAffinity,您必須在新的永續性磁碟區設定中將其變更為 topology.kubernetes.io/zonetopology.kubernetes.io/region 標籤。

使用兩個移轉選項支援從樹狀內移轉至 CSI:

  • 建立靜態磁碟區
  • 建立動態磁碟區

建立靜態磁碟區

使用此選項時,您會以靜態方式將 claimRef 指派給稍後建立的新 PVC 以建立 PV,並對於 PersistentVolumeClaim 指定 volumeName

Static volume workflow diagram.

此方法的優點包括:

  • 很簡單而且可以自動化。
  • 不需要使用樹狀結構內儲存類別清除原始組態。
  • 低風險,因為您只會執行 Kubernetes PV/PVC 的邏輯刪除,所以不會刪除實際的實體資料。
  • 由於不需要建立其他 Azure 物件,例如磁碟、快照集等,因此不會產生額外費用。

以下是評估的重要考量:

  • 從原始動態樣式磁碟區轉換至靜態磁碟區,需要針對所有選項手動建構和管理 PV 物件。
  • 重新部署參考新 PVC 物件的新應用程式時,會有潛在的應用程式停機時間。

遷移

  1. 執行下列命令,將現有的 PV ReclaimPolicy 從「刪除」更新為「保留」

    kubectl patch pv pvName -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
    

    pvName 取代 為您選取的 PersistentVolume 名稱。 或者,如果您想要更新多個 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>

  2. 執行下列命令,取得以 creationTimestamp 排序的命名空間中全部 PVC 的清單。 使用 --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,而且您想要一次移轉一些,此步驟會很有幫助。 執行此命令可讓您識別在指定時間範圍內建立哪些 PVC。 您執行 CreatePV.sh 指令碼時,其中兩個參數是開始時間和結束時間,可讓您在該期間只移轉 PVC。

  3. 建立名為 CreatePV.sh 的檔案,然後在下列程式碼中複製。 指令碼會執行下列作業:

    • 在儲存體類別 storageClassName 的命名空間中,對於全部 PersistentVolume,以名稱 existing-pv-csi 建立新的 PersistentVolume。
    • 將新的 PVC 名稱設定為 existing-pvc-csi
    • 使用您指定的 PV 名稱建立新的 PVC。
    #!/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
    
  4. 若要為命名空間中的全部 PersistentVolume 建立新的 PersistentVolume,請使用下列參數執行指令碼 CreatePV.sh

    • namespace - 叢集命名空間
    • sourceStorageClass - 樹狀內儲存體驅動程式型 StorageClass
    • targetCSIStorageClass - CSI 儲存體驅動程式型 StorageClass,這可以是其中一個預設儲存體類別,其佈建器設定為 disk.csi.azure.comfile.csi.azure.com。 或者,只要這設定為這兩個佈建器的其中一個,您也可以建立自訂儲存體類別。
    • startTimeStamp - 以 yyyy-mm-ddthh:mm:ssz 格式提供 PVC 建立時間之前的開始時間
    • endTimeStamp - 以 yyyy-mm-ddthh:mm:ssz 格式提供結束日期。
    ./CreatePV.sh <namespace> <sourceIntreeStorageClass> <targetCSIStorageClass> <startTimestamp> <endTimestamp>
    
  5. 更新應用程式以使用新的 PVC。

建立動態磁碟區

您可以使用此選項,從永續性磁碟區宣告動態建立永續性磁碟區。

Dynamic volume workflow diagram.

此方法的優點包括:

  • 風險較低,因為所有新物件都會建立,同時保留具有快照集的其他複本。

  • 不需要個別建構 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"
    
  1. 執行下列命令,取得以 creationTimestamp 排序的指定命名空間中全部 PVC 的清單。 使用 --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,而且您想要一次移轉一些,此步驟會很有幫助。 執行此命令可讓您識別在指定時間範圍內建立哪些 PVC。 您執行 MigrateCSI.sh 指令碼時,其中兩個參數是開始時間和結束時間,可讓您在該期間只移轉 PVC。

  2. 建立名為 MigrateToCSI.sh 的檔案,然後在下列程式碼中複製。 指令碼會執行下列作業:

    • 使用 Azure CLI 建立完整磁碟快照集
    • 建立 VolumesnapshotContent
    • 建立 VolumeSnapshot
    • VolumeSnapshot 建立新的 PVC
    • 使用檔案名稱 <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
    
  3. 若要移轉磁碟區,請使用下列參數執行指令碼 MigrateToCSI.sh

    • namespace - 叢集命名空間
    • sourceStorageClass - 樹狀內儲存體驅動程式型 StorageClass
    • targetCSIStorageClass - CSI 儲存體驅動程式型 StorageClass
    • volumeSnapshotClass - 磁碟區快照集類別的名稱。 例如: custom-disk-snapshot-sc
    • startTimeStamp - 以 yyyy-mm-ddthh:mm:ssz 格式提供開始時間。
    • endTimeStamp - 以 yyyy-mm-ddthh:mm:ssz 格式提供結束日期。
    ./MigrateToCSI.sh <namespace> <sourceStorageClass> <TargetCSIstorageClass> <VolumeSnapshotClass> <startTimestamp> <endTimestamp>
    
  4. 更新應用程式以使用新的 PVC。

  5. 手動刪除較舊的資源,包括樹狀內 PVC/PV、VolumeSnapshot 和 VolumeSnapshotContent。 否則,維護樹狀結構內 PVC/PC 和快照集物件會產生更多成本。

移轉檔案共用磁碟區

建立靜態磁碟區支援從樹狀內移轉至 CSI:

  • 不需要使用樹狀結構內儲存類別清除原始組態。
  • 低風險,因為您只會執行 Kubernetes PV/PVC 的邏輯刪除,所以不會刪除實際的實體資料。
  • 由於不需要建立其他 Azure 物件,例如檔案共用等,因此不會產生額外費用。

遷移

  1. 執行下列命令,將現有的 PV ReclaimPolicy 從「刪除」更新為「保留」

    kubectl patch pv pvName -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
    

    pvName 取代 為您選取的 PersistentVolume 名稱。 或者,如果您想要更新多個 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>

  2. 建立新的儲存體類別,並將佈建程式設定為 file.csi.azure.com,或者您可以使用其中一個預設 StorageClass 搭配 CSI 檔案佈建器。

  3. 執行下列命令,從現有的 PersistentVolumes 取得 secretNameshareName

    kubectl describe pv pvName
    
  4. 使用新的 StorageClass 建立新的 PV,並從樹狀內 PV 建立 shareNamesecretName。 建立名為 azurefile-mount-pv.yaml 的檔案,並在下列程式碼中複製。 在 csi 之下,更新 resourceGroupvolumeHandleshareName。 針對掛接選項,fileModedirMode 的預設值為 0777

    fileModedirMode 的預設值為 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
    
  5. 使用下列程式碼,藉由使用 PersistentVolumePersistentVolumeClaim 建立名為 azurefile-mount-pvc.yaml 的檔案。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: azurefile
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: azurefile-csi
      volumeName: azurefile
      resources:
        requests:
          storage: 5Gi
    
  6. 使用 kubectl 命令建立 PersistentVolume

    kubectl apply -f azurefile-mount-pv.yaml
    
  7. 使用 kubectl 命令建立 PersistentVolumeClaim

    kubectl apply -f azurefile-mount-pvc.yaml
    
  8. 若要驗證 PersistentVolumeClaim 已建立並繫結至 PersistentVolume,請執行下列命令。

    kubectl get pvc azurefile
    

    輸出類似下列:

    NAME        STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    azurefile   Bound    azurefile   5Gi        RWX            azurefile      5s
    
  9. 將您的容器規格更新為參考 PersistentVolumeClaim 並更新 Pod。 例如,複製下列程式碼,並建立名為 azure-files-pod.yaml 的檔案。

    ...
      volumes:
      - name: azure
        persistentVolumeClaim:
          claimName: azurefile
    
  10. Pod 規格無法就地更新。 使用下列 kubectl 命令刪除,然後重新建立 Pod。

    kubectl delete pod mypod
    
    kubectl apply -f azure-files-pod.yaml
    

下一步