在 Azure Kubernetes 服务 (AKS) 中通过 Azure Blob 存储创建和使用卷
基于容器的应用程序通常需要访问数据并将数据保存在外部数据卷中。 如果多个 Pod 需要同时访问同一存储卷,则可以通过 blobfuse 或网络文件系统 (NFS) 使用 Azure Blob 存储进行连接。
本文介绍如何:
- 通过安装容器存储接口 (CSI) 驱动程序并动态创建要附加到 Pod 的 Azure Blob 存储容器来使用动态永久性卷 (PV)。
- 通过创建 Azure Blob 存储容器来使用静态 PV,或者使用现有容器并将其附加到 Pod。
有关 Kubernetes 卷的详细信息,请参阅 AKS 中应用程序的存储选项。
开始之前
在 AKS 群集上启用 Blob 存储 CSI 驱动程序。
若要在使用 blobfuse 装载时支持 Azure DataLake Gen2 存储帐户,你需要执行以下操作:
- 若要在动态预配中使用驱动程序创建 ADLS 帐户,需要在存储类参数中指定
isHnsEnabled: "true"
。 - 若要在静态预配中启用对 ADLS 帐户的 blobfuse 访问,请在永久性卷中指定装载选项
--use-adls=true
。 - 如果要启用具有分层命名空间的存储帐户,应使用
--use-adls=true
装载选项重新装载现有永久性卷。
- 若要在动态预配中使用驱动程序创建 ADLS 帐户,需要在存储类参数中指定
关于 blobfuse 缓存
- 默认情况下,blobfuse 缓存位于
/mnt
目录中。 如果 VM SKU 提供了临时磁盘,则/mnt
目录将装载在临时磁盘上。 但是,如果 VM SKU 不提供临时磁盘,则/mnt
目录装载在 OS 磁盘上,可以设置--tmp-path=
装载选项以指定不同的缓存目录
- 默认情况下,blobfuse 缓存位于
动态预配卷
本部分为想要预配一个或多个永久性卷的群集管理员提供指导,这些卷中包含供工作负载使用的 Blob 存储的详细信息。 永久性卷声明 (PVC) 使用存储类对象来动态预配 Azure Blob 存储容器。
动态永久性卷的存储类参数
下表包含可用于为永久性卷声明定义自定义存储类的参数。
名称 | 步骤 | 示例 | 必需 | 默认值 |
---|---|---|---|---|
skuName | 指定 Azure 存储帐户类型(别名:storageAccountType )。 |
Standard_LRS 、Premium_LRS 、Standard_GRS 、Standard_RAGRS |
否 | Standard_LRS |
location | 指定 Azure 位置。 | chinaeast2 |
否 | 如果为空,驱动程序将使用与当前群集相同的位置名称。 |
resourceGroup | 指定 Azure 资源组名称。 | myResourceGroup | 否 | 如果为空,驱动程序将使用与当前群集相同的资源组名称。 |
storageAccount | 指定 Azure 存储帐户名称。 | storageAccountName | 否- | 如果未提供特定的存储帐户名称,驱动程序将查找与同一资源组中的帐户设置匹配的合适存储帐户。 如果驱动程序找不到匹配的存储帐户,则将创建新的存储帐户。 但是,如果指定了存储帐户名称,则存储帐户必须已经存在。 |
networkEndpointType | 为驱动程序创建的存储帐户指定网络终结点类型。 如果指定 privateEndpoint,则会为存储帐户创建专用终结点。 对于其他情况,将为 NFS 协议创建服务终结点。1 | privateEndpoint |
否 | 对于 AKS 群集,请将 AKS 群集名称添加到托管 VNET 的资源组中的“参与者”角色。 |
protocol | 指定 blobfuse 装载或 NFSv3 装载。 | fuse 、nfs |
否 | fuse |
containerName | 指定现有容器(目录)名称。 | container | 否 | 如果为空,驱动程序会创建一个新的容器名称,对于 blobfuse 以 pvc-fuse 开头,对于 NFS v3 以 pvc-nfs 开头。 |
containerNamePrefix | 指定驱动程序创建的 Azure 存储目录前缀。 | my | 只能包含小写字母、数字、连字符,且字符长度不能超过 21 个字符。 | 否 |
server | 指定 Azure 存储帐户域名。 | 现有存储帐户 DNS 域名,例如 <storage-account>.privatelink.blob.core.chinacloudapi.cn 。 |
否 | 如果为空,驱动程序将使用默认 <storage-account>.blob.core.chinacloudapi.cn 或其他主权云存储帐户 DNS 域名。 |
allowBlobPublicAccess | 允许或禁止公共访问驱动程序创建的存储帐户的所有 Blob 或容器。 | true 、false |
否 | false |
storageEndpointSuffix | 指定 Azure 存储终结点后缀。 | core.chinacloudapi.cn |
否 | 如果为空,驱动程序将根据云环境使用默认存储终结点后缀。 |
标记 | 将在新的存储帐户中创建标记。 | 标记格式:“foo=aaa,bar=bbb” | 否 | "" |
matchTags | 驱动程序尝试查找合适的存储帐户时匹配标记。 | true 、false |
否 | false |
--- | 以下参数仅适用于 blobfuse | --- | --- | --- |
subscriptionID | 指定要创建 blob 存储目录的 Azure 订阅 ID。 | Azure 订阅 ID | 否 | 如果不为空,则必须提供 resourceGroup 。 |
storeAccountKey | 指定 Kubernetes 机密的存储帐户密钥。 请注意: false 表示驱动程序使用 kubelet 标识获取帐户密钥。 |
true 、false |
否 | true |
secretName | 指定用于存储帐户密钥的机密名称。 | 否 | ||
secretNamespace | 指定用于存储帐户密钥的机密的命名空间。 | default 、kube-system 等。 |
否 | Pvc 命名空间 |
isHnsEnabled | 为 Azure Data Lake 存储帐户启用 Hierarchical namespace 。 |
true 、false |
否 | false |
--- | 以下参数仅适用于 NFS 协议 | --- | --- | --- |
mountPermissions | 指定装载的文件夹权限。 | 默认为 0777 。 如果设置为 0 ,驱动程序在装载后将不执行 chmod 。 |
0777 |
否 |
1 如果存储帐户由驱动程序创建,则只需在存储类中指定 networkEndpointType: privateEndpoint
参数。 CSI 驱动程序与帐户一起创建专用终结点。 如果自带存储帐户,则需要为该存储帐户创建专用终结点。
使用内置存储类创建永久性卷声明
永久性卷声明 (PVC) 使用存储类对象来动态预配 Azure Blob 存储容器。 可使用以下 YAML,通过内置存储类创建具有 ReadWriteMany 访问权限的永久性卷,其大小为 5 GB。 有关访问模式的详细信息,请参阅 Kubernetes 永久性卷文档。
创建名为
blob-nfs-pvc.yaml
的文件,并将其复制到以下 YAML 中。apiVersion: v1 kind: PersistentVolumeClaim metadata: name: azure-blob-storage spec: accessModes: - ReadWriteMany storageClassName: azureblob-nfs-premium resources: requests: storage: 5Gi
使用 kubectl create 命令创建永久性卷声明:
kubectl create -f blob-nfs-pvc.yaml
完成后,将创建 Blob 存储容器。 可以使用 kubectl get 命令查看 PVC 的状态:
kubectl get pvc azure-blob-storage
该命令的输出类似于以下示例:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
azure-blob-storage Bound pvc-b88e36c5-c518-4d38-a5ee-337a7dda0a68 5Gi RWX azureblob-nfs-premium 92m
使用永久性卷声明
以下 YAML 创建的 Pod 使用永久性卷声明 azure-blob-storage 将 Azure Blob 存储装载到 /mnt/blob 路径。
创建名为
blob-nfs-pv
的文件,并将其复制到以下 YAML 中。 请确保 claimName 与上一步骤中创建的 PVC 匹配。kind: Pod apiVersion: v1 metadata: name: mypod spec: containers: - name: mypod image: mcr.azk8s.cn/oss/nginx/nginx:1.17.3-alpine resources: requests: cpu: 100m memory: 128Mi limits: cpu: 250m memory: 256Mi volumeMounts: - mountPath: "/mnt/blob" name: volume readOnly: false volumes: - name: volume persistentVolumeClaim: claimName: azure-blob-storage
使用 kubectl apply 命令创建 Pod:
kubectl apply -f blob-nfs-pv.yaml
Pod 处于运行状态后,运行以下命令创建名为
test.txt
的新文件。kubectl exec mypod -- touch /mnt/blob/test.txt
若要验证磁盘是否已正确装载,请运行以下命令并验证输出是否出现
test.txt
文件:kubectl exec mypod -- ls /mnt/blob
该命令的输出类似于以下示例:
test.txt
创建自定义存储类
默认存储类适合最常见的方案,但并非适合所有方案。 在某些情况下,你可能想要使用自己的参数来自定义自己的存储类。 在本部分中,我们提供了两个示例。 第一个示例使用 NFS 协议,第二个使用 blobfuse。
使用 NFS 协议的存储类
在此示例中,以下清单使用 NFS 协议配置装载 Blob 存储容器。 使用它添加 tag 参数。
创建名为
blob-nfs-sc.yaml
的文件,并粘贴以下示例清单:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: azureblob-nfs-premium provisioner: blob.csi.azure.com parameters: protocol: nfs tags: environment=Development volumeBindingMode: Immediate allowVolumeExpansion: true mountOptions: - nconnect=4
使用 kubectl apply 命令创建存储类:
kubectl apply -f blob-nfs-sc.yaml
该命令的输出类似于以下示例:
storageclass.storage.k8s.io/blob-nfs-premium created
使用 blobfuse 的存储类
在此示例中,以下清单使用 blobfuse 进行配置并装载 Blob 存储容器。 使用它更新 skuName 参数。
创建名为
blobfuse-sc.yaml
的文件,并粘贴以下示例清单:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: azureblob-fuse-premium provisioner: blob.csi.azure.com parameters: skuName: Standard_GRS # available values: Standard_LRS, Premium_LRS, Standard_GRS, Standard_RAGRS reclaimPolicy: Delete volumeBindingMode: Immediate allowVolumeExpansion: true mountOptions: - -o allow_other - --file-cache-timeout-in-seconds=120 - --use-attr-cache=true - --cancel-list-on-mount-seconds=10 # prevent billing charges on mounting - -o attr_timeout=120 - -o entry_timeout=120 - -o negative_timeout=120 - --log-level=LOG_WARNING # LOG_WARNING, LOG_INFO, LOG_DEBUG - --cache-size-mb=1000 # Default will be 80% of available memory, eviction will happen beyond that.
使用 kubectl apply 命令创建存储类:
kubectl apply -f blobfuse-sc.yaml
该命令的输出类似于以下示例:
storageclass.storage.k8s.io/blob-fuse-premium created
静态预配卷
本部分为想要创建一个或多个永久性卷的群集管理员提供指导,这些卷中包含供工作负载使用的 Blob 存储的详细信息。
永久性卷的静态预配参数
下表包含可用于定义永久性卷的参数。
名称 | 步骤 | 示例 | 必需 | 默认值 |
---|---|---|---|---|
volumeHandle | 指定一个值,该值可供驱动程序用来唯一标识群集中的存储 blob 容器。 | 生成唯一值的推荐方法是组合全局唯一存储帐户名称和容器名称:{account-name}_{container-name} 。注意: # 、/ 字符保留供内部使用,不能在卷句柄中使用。 |
是 | |
volumeAttributes.resourceGroup | 指定 Azure 资源组名称。 | myResourceGroup | 否 | 如果为空,驱动程序将使用与当前群集相同的资源组名称。 |
volumeAttributes.storageAccount | 指定现有的 Azure 存储帐户名称。 | storageAccountName | 是 | |
volumeAttributes.containerName | 指定现有的容器名称。 | container | 是 | |
volumeAttributes.protocol | 指定 blobfuse 装载或 NFS v3 装载。 | fuse 、nfs |
否 | fuse |
--- | 以下参数仅适用于 blobfuse | --- | --- | --- |
volumeAttributes.secretName | 存储存储帐户名称和密钥的机密名称(仅适用于 SMB)。 | 否 | ||
volumeAttributes.secretNamespace | 指定用于存储帐户密钥的机密的命名空间。 | default |
否 | Pvc 命名空间 |
nodeStageSecretRef.name | 指定用于存储下列其中一项的机密名称:azurestorageaccountkey azurestorageaccountsastoken msisecret azurestoragespnclientsecret 。 |
否 | 现有 Kubernetes 机密名称 | |
nodeStageSecretRef.namespace | 指定机密的命名空间。 | Kubernetes 命名空间 | 是 | |
--- | 以下参数仅适用于 NFS 协议 | --- | --- | --- |
volumeAttributes.mountPermissions | 指定装载的文件夹权限。 | 0777 |
否 | |
--- | 以下参数仅适用于 NFS VNet 设置 | --- | --- | --- |
vnetResourceGroup | 指定托管虚拟网络的 VNet 资源组。 | myResourceGroup | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中指定的 vnetResourceGroup 值。 |
vnetName | 指定虚拟网络名称。 | aksVNet | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中指定的 vnetName 值。 |
subnetName | 指定代理节点的现有子网名称。 | aksSubnet | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中的 subnetName 值。 |
--- | 以下参数仅适用于功能:blobfuse 托管标识和服务主体名称身份验证 |
--- | --- | --- |
volumeAttributes.AzureStorageAuthType | 指定身份验证类型。 | Key 、SAS 、MSI 、SPN |
否 | Key |
volumeAttributes.AzureStorageIdentityClientID | 指定标识客户端 ID。 | 否 | ||
volumeAttributes.AzureStorageIdentityResourceID | 指定标识资源 ID。 | 否 | ||
volumeAttributes.MSIEndpoint | 指定 MSI 终结点。 | 否 | ||
volumeAttributes.AzureStorageSPNClientID | 指定 Azure 服务主体名称 (SPN) 客户端 ID。 | 否 | ||
volumeAttributes.AzureStorageSPNTenantID | 指定 Azure SPN 租户 ID。 | 否 | ||
volumeAttributes.AzureStorageAADEndpoint | 指定 Microsoft Entra 终结点。 | 否 | ||
--- | 以下参数仅适用于功能:blobfuse 从密钥保管库读取帐户密钥或 SAS 令牌 | --- | --- | --- |
volumeAttributes.keyVaultURL | 指定 Azure Key Vault DNS 名称。 | {vault-name}.vault.azure.cn | 否 | |
volumeAttributes.keyVaultSecretName | 指定 Azure Key Vault 机密名称。 | 现有 Azure Key Vault 机密名称。 | 否 | |
volumeAttributes.keyVaultSecretVersion | Azure Key Vault 机密版本。 | 现有版本 | 否 | 如果为空,驱动程序将使用当前版本。 |
创建 Blob 存储容器
创建用于 AKS 的 Azure Blob 存储资源时,可以在节点资源组中创建该资源。 此方法允许 AKS 群集访问和管理 Blob 存储资源。
对于本文,请在节点资源组中创建容器。 首先,使用 az aks show 命令获取资源组名称并添加 --query nodeResourceGroup
查询参数。 以下示例在名为 myResourceGroup 的资源组中获取名为 myAKSCluster 的 AKS 群集的节点资源组:
az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv
该命令的输出类似于以下示例:
MC_myResourceGroup_myAKSCluster_chinaeast2
接下来,按照管理 Blob 存储中的步骤创建一个用于存储 Blob 的容器来授权访问,然后创建容器。
装载卷
在本部分,你将使用 NFS 协议或 Blobfuse 装载永久性卷。
如果通过 NFS v3 协议装载 Blob 存储,则不使用帐户密钥进行身份验证。 AKS 群集需要驻留在与代理节点位置相同或对等的虚拟网络中。 保护存储帐户中的数据的唯一方法是使用虚拟网络和其他网络安全设置。 若要详细了解如何设置对存储帐户的 NFS 访问,请参阅使用网络文件系统 (NFS) 3.0 协议装载 Blob 存储。
以下示例演示如何使用 NFS 协议将 Blob 存储容器装载为永久性卷。
创建名为
pv-blob-nfs.yaml
的文件,并将其复制到以下 YAML 中。 在storageClass
下,更新resourceGroup
、storageAccount
和containerName
。注意
volumeHandle
值应是群集中每个相同存储 Blob 容器的唯一卷 ID。 字符#
和/
保留供内部使用,不能使用它。apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: blob.csi.azure.com name: pv-blob spec: capacity: storage: 1Pi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain # If set as "Delete" container would be removed after pvc deletion storageClassName: azureblob-nfs-premium mountOptions: - nconnect=4 csi: driver: blob.csi.azure.com # make sure volumeid is unique for every identical storage blob container in the cluster # character `#` and `/` are reserved for internal use and cannot be used in volumehandle volumeHandle: account-name_container-name volumeAttributes: resourceGroup: resourceGroupName storageAccount: storageAccountName containerName: containerName protocol: nfs
注意
虽然 Kubernetes API 容量特性是必需的,但 Azure Blob 存储 CSI 驱动程序不使用此值,因为你可灵活写入数据,直到达到存储帐户的容量限制。
capacity
特性的值仅用于在 PersistentVolumes 与 PersistentVolumeClaims 之间进行大小匹配。 建议使用虚构的较大值。 Pod 将看到虚构大小为 5 PB 的已装载卷。运行以下命令以使用 kubectl create 命令创建永久性卷,该命令引用之前创建的 YAML 文件:
kubectl create -f pv-blob-nfs.yaml
创建包含 PersistentVolumeClaim 的
pvc-blob-nfs.yaml
文件。 例如:kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-blob spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi volumeName: pv-blob storageClassName: azureblob-nfs-premium
运行以下命令以使用 kubectl create 命令创建永久性卷声明,该命令引用之前创建的 YAML 文件:
kubectl create -f pvc-blob-nfs.yaml
使用永久性卷
以下 YAML 创建一个 Pod,该 Pod 使用前面创建的名为 pvc-blob 的永久性卷或永久性卷声明,在 /mnt/blob
路径中装载 Azure Blob 存储。
创建名为
nginx-pod-blob.yaml
的文件,并将其复制到以下 YAML 中。 确保在为 NFS 或 Blobfuse 创建永久性卷时,claimName 与上一步中创建的 PVC 相匹配。kind: Pod apiVersion: v1 metadata: name: nginx-blob spec: nodeSelector: "kubernetes.io/os": linux containers: - image: mcr.azk8s.cn/oss/nginx/nginx:1.17.3-alpine name: nginx-blob volumeMounts: - name: blob01 mountPath: "/mnt/blob" readOnly: false volumes: - name: blob01 persistentVolumeClaim: claimName: pvc-blob
运行以下命令以使用 kubectl create 命令创建 Pod 并装载 PVC,该命令引用之前创建的 YAML 文件:
kubectl create -f nginx-pod-blob.yaml
运行以下命令来创建与 Pod 的交互式 shell 会话,从而确认 Blob 存储已装载:
kubectl exec -it nginx-blob -- df -h
命令的输出如下例所示:
Filesystem Size Used Avail Use% Mounted on ... blobfuse 14G 41M 13G 1% /mnt/blob ...
后续步骤
- 若要了解如何将 CSI 驱动程序用于 Azure Blob 存储,请参阅将 Azure Blob 存储与 CSI 驱动程序配合使用。
- 如需相关的最佳做法,请参阅 AKS 中的存储和备份最佳做法。