如果多个 Pod 需要并发访问同一存储卷,则可以使用 Azure Blob 存储通过 blobfuse 或 网络文件系统(NFS)进行连接。
本文介绍如何动态和静态创建 Azure Blob 存储容器,供 Azure Kubernetes 服务 (AKS) 群集中的多个 Pod 使用。
先决条件
在你的 AKS 集群上启用了 Azure Blob 存储 CSI 驱动程序。
若要在使用 blobfuse 装载时支持 Azure DataLake Gen2 存储帐户,需要执行以下操作:
- 若要在动态预配中使用驱动程序创建 ADLS 帐户,请在存储类参数中指定
isHnsEnabled: "true"。 - 若要在静态预配中启用对 ADLS 帐户的 blobfuse 访问,请在持久卷中指定装载选项
--use-adls=true。 - 如果要启用具有分层命名空间的存储帐户,应使用
--use-adls=true装载选项重新装载现有永久性卷。
- 若要在动态预配中使用驱动程序创建 ADLS 帐户,请在存储类参数中指定
默认情况下,blobfuse 缓存位于
/mnt目录中。 如果 VM SKU 提供临时磁盘,则会将/mnt目录装载到临时磁盘上。 但是,如果 VM SKU 不提供临时磁盘,则会将/mnt目录装载到 OS 磁盘上,可以设置--tmp-path=装载选项来指定不同的缓存目录。
使用内置存储类,通过 Azure Blob 存储创建动态 PV
storage类用于定义如何创建Azure Blob storage容器。 存储帐户会自动在节点资源组中创建,以便与存储类一起使用来保存 Azure Blob 存储容器。 在 AKS 上使用存储 CSI 驱动程序时,有两个额外的内置 StorageClasses,它们使用 Azure Blob 存储的 CSI 驱动程序。
这两种存储类的回收策略可确保当删除相应的持久卷时删除底层的 Azure Blob 存储。 默认情况下,storage类还会将容器配置为可扩展,因为 set allowVolumeExpansion 参数设置为 true。
注释
不支持收缩永久性卷。
可以为存储类定义中的参数选择以下 Azure 存储冗余 SKUskuname 之一:
- Standard_LRS:标准本地冗余存储
- Premium_LRS:高级本地冗余存储
- Standard_ZRS:标准区域冗余存储
- Premium_ZRS:高级区域冗余存储
- Standard_GRS:标准异地冗余存储
- Standard_RAGRS:标准只读访问地理冗余存储
使用 Azure Blob 存储为动态 PV 创建自定义存储类
默认存储类适用于大多数方案。 在某些情况下,你可能想要使用自己的参数自定义自己的存储类。 在本部分中,我们提供了两个示例:一个使用 NFS 协议 ,一个使用 blobfuse。
使用 NFS 协议的自定义存储类示例
此示例中的清单使用 NFS 协议装载 Blob 存储容器。 可以使用它添加 tags 参数。
在以下示例清单中创建一个名为
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
使用 Azure Blob 存储的动态 PV 的存储类参数
下表包括可用于为 Azure Blob 存储上的持久性卷声明(PVC)定义自定义存储类的参数:
| 名称 | 含义 | 可用值 | 必需 | 默认值 |
|---|---|---|---|---|
skuName |
指定 Azure 存储帐户类型(别名: storageAccountType) 。 |
Standard_LRS、Premium_LRS、Standard_GRS、Standard_RAGRS |
否 | Standard_LRS |
location |
指定 Azure 位置。 | chinanorth3 |
否 | 如果为空,驱动程序使用与当前群集相同的位置名称。 |
resourceGroup |
指定Azure资源组名称。 | myResourceGroup | 否 | 如果为空,驱动程序将使用与当前群集相同的资源组名称。 |
storageAccount |
指定Azure storage帐户名称。 | storageAccountName | 否 | 如果未提供特定的存储帐户名称,驱动程序将查找与同一资源组中的帐户设置匹配的合适存储帐户。 如果找不到匹配的存储帐户,则会创建一个新帐户。 但是,如果指定了存储帐户名,则存储帐户必须已存在。 |
networkEndpointType |
为由驱动创建的存储帐户指定网络终结点类型。 如果指定 privateEndpoint,则会为存储帐户创建私有终结点。 对于其他情况,将为 NFS 协议创建服务终结点。 | privateEndpoint |
否 | 对于 AKS 群集,请将 AKS 群集名称添加到托管 VNet 的资源组的“参与者”角色中。 |
protocol |
指定 blobfuse 装载或 NFSv3 装载。 |
fuse、nfs |
否 | fuse |
containerName |
指定现有容器(目录)名称。 | 容器 | 否 | 如果为空,驱动程序将创建一个新的容器名称,从 pvc-fuse blobfuse 或 pvc-nfs NFS v3 开始。 |
containerNamePrefix |
指定驱动程序创建的 Azure 存储目录前缀。 | 我 | 只能包含小写字母、数字、连字符和长度应少于 21 个字符。 | 否 |
server |
指定 Azure 存储帐户域名。 | 现有存储帐户的 DNS 域名,例如 <storage-account>.blob.core.chinacloudapi.cn。 |
否 | 如果为空,驱动程序使用默认 <storage-account>.blob.core.chinacloudapi.cn 或其他主权云存储帐户 DNS 域名。 |
allowBlobPublicAccess |
允许或禁止对驱动程序创建的存储帐户中的所有 blob 或容器进行公共访问。 |
true、false |
否 | false |
storageEndpointSuffix |
指定 Azure 存储终结点后缀。 | core.chinacloudapi.cn |
否 | 如果为空,驱动程序会根据云环境使用默认的存储终结点后缀。 |
tags |
标记 将在新的存储帐户中创建。 | 标记格式:“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 |
注释
如果存储帐户由驱动程序创建,则只需在存储类中指定 networkEndpointType: privateEndpoint 参数。 CSI 驱动程序将创建专用终结点和专用 DNS 区域(命名 privatelink.blob.core.chinacloudapi.cn)以及帐户。 如果自带存储帐户,则需要为存储帐户 创建专用终结点 。 如果在网络隔离群集中使用 Azure Blob 存储,则必须使用“networkEndpointType: privateEndpoint”创建自定义存储类。 可以使用以下示例清单作为参考:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: blob-fuse
provisioner: blob.csi.azure.com
parameters:
skuName: Premium_LRS # available values: Standard_LRS, Premium_LRS, Standard_GRS, Standard_RAGRS, Standard_ZRS, Premium_ZRS
protocol: fuse2
networkEndpointType: privateEndpoint
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.
使用 Azure Blob 存储创建 PVC
PVC 使用存储类对象动态预配 Azure Blob 存储。 可以使用本部分中的示例 YAML 清单创建大小 为 5 GB 且具有 ReadWriteMany 访问权限的 PVC。 有关访问模式的详细信息,请参阅 Kubernetes PV 访问模式。
创建一个名为
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以下命令创建 PVC:kubectl create -f blob-nfs-pvc.yaml使用 [
kubectl get pvc][kubectl-get-pvc] 命令查看 PVC 的状态:kubectl get pvc azure-blob-storage输出应类似于以下示例输出,其中显示 PVC 处于
Bound状态:NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE azure-blob-storage Bound pvc-aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb 5Gi RWX azureblob-nfs-premium 92m
在 Pod 中使用 PVC 装载 Azure Blob 存储
以下 YAML 创建一个 Pod,该 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使用以下命令验证磁盘是否已正确装载,以列出装载的目录中的文件:
kubectl exec mypod -- ls /mnt/blob输出应类似于以下示例输出,它展示了您在已挂载的 Azure Blob 存储中创建的
test.txt文件:test.txt
使用 StatefulSet 管理利用 Azure Blob 存储的卷的生命周期
若要使存储卷在工作负载中持久存在,可以使用 StatefulSet。 这样,将现有卷与替换任何失败的 Pod 相匹配就更容易了。 以下示例演示如何使用 NFS 协议或 Blobfuse 为 Blob 存储设置 StatefulSet。
注释
如果使用 NFS 协议,则需要将 AKS 群集 控制平面 标识(即 AKS 群集名称)添加到 VNet 和网络安全组上的 参与者 角色。
创建一个名为
azure-blob-nfs-ss.yaml的文件,并在其中粘贴以下 YAML 清单:apiVersion: apps/v1 kind: StatefulSet metadata: name: statefulset-blob-nfs labels: app: nginx spec: serviceName: statefulset-blob-nfs replicas: 1 template: metadata: labels: app: nginx spec: nodeSelector: "kubernetes.io/os": linux containers: - name: statefulset-blob-nfs image: mcr.azk8s.cn/azurelinux/base/nginx:1.25 volumeMounts: - name: persistent-storage mountPath: /mnt/blob updateStrategy: type: RollingUpdate selector: matchLabels: app: nginx volumeClaimTemplates: - metadata: name: persistent-storage spec: storageClassName: azureblob-nfs-premium accessModes: ["ReadWriteMany"] resources: requests: storage: 100Gi使用
kubectl create以下命令创建 StatefulSet:kubectl create -f azure-blob-nfs-ss.yaml
使用 Azure Blob 存储创建静态 PV
以下部分提供有关使用 Azure Blob 存储创建静态 PV 的说明。 静态 PV 是管理员手动创建的持久卷。 此 PV 可供集群中的 Pods 使用。 若要使用静态 PV,请创建引用 PV 的 PVC,然后创建引用 PVC 的 Pod。
使用 Azure Blob 存储的静态 PV 的存储类参数
下表包含可用于使用 Azure Blob 存储针对静态 PVC 定义自定义存储类的参数:
| 名称 | 含义 | 可用值 | 必需 | 默认值 |
|---|---|---|---|---|
volumeHandle |
指定一个值,以供驱动程序在群集中唯一识别存储 Blob 容器。 | 生成唯一值的建议方法是组合全局唯一存储帐户名称和容器名称: {account-name}_{container-name}注意:字符 #和/仅保留供内部使用,不能用于卷句柄。 |
是的 | |
volumeAttributes.resourceGroup |
指定 Azure 资源组名称。 | myResourceGroup | 否 | 如果为空,驱动程序将使用与当前群集相同的资源组名称。 |
volumeAttributes.storageAccount |
指定现有的Azure storage帐户名称。 | storageAccountName | 是的 | |
volumeAttributes.containerName |
指定现有的容器名称。 | 容器 | 是的 | |
volumeAttributes.protocol |
指定 blobfuse 装载或 NFS v3 装载。 |
fuse、nfs |
否 | fuse |
| --- | 以下参数仅适用于 blobfuse | --- | --- | --- |
volumeAttributes.secretName |
用于存储帐户名称和密钥的机密名称(仅适用于 SMB)。 | 否 | ||
volumeAttributes.secretNamespace |
指定用于存储帐户密钥的机密命名空间。 | default |
否 | PVC 命名空间 |
nodeStageSecretRef.name |
指定存储以下内容之一的机密名称:azurestorageaccountkeyazurestorageaccountsastokenmsisecretazurestoragespnclientsecret。 |
否 | 现有 Kubernetes 机密名称 | |
nodeStageSecretRef.namespace |
指定机密的命名空间。 | Kubernetes 命名空间 | 是的 | |
| --- | 以下参数仅适用于 NFS 协议 | --- | --- | --- |
volumeAttributes.mountPermissions |
指定装载的文件夹权限。 | 0777 |
否 | |
| --- | 以下参数仅适用于 NFS VNet 设置 | --- | --- | --- |
vnetResourceGroup |
指定托管虚拟网络的 VNet 资源组。 | myResourceGroup | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中指定的 vnetResourceGroup 值。 |
vnetName |
指定该虚拟网络的名称。 | aksVNet | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中指定的 vnetName 值。 |
subnetName |
指定代理节点的现有子网名称。 | aksSubnet | 否 | 如果为空,驱动程序将更新群集虚拟网络下的所有子网。 |
| --- |
以下参数仅适用于 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 Storage 资源时,可以在节点资源组中创建该资源。 此方法允许 AKS 群集访问和管理 Blob 存储资源。
使用命令
az aks show通过参数--query nodeResourceGroup获取 AKS 群集的节点资源组的名称。az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv该命令的输出类似于以下示例:
MC_myResourceGroup_myAKSCluster_chinanorth3按照 “管理 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 容器的唯一的 volumeID。 字符#并/保留供内部使用,不能使用。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仅用于 PV 和 PVC 之间的大小匹配。 建议使用虚构的较高数值。 Pod 看到一个装载的卷,其虚构大小为 5 PB。使用以下命令创建 PV:
kubectl createkubectl create -f pv-blob-nfs.yaml创建一个名为
pvc-blob-nfs.yaml的文件,并粘贴以下 YAML 内容。 在volumeName下,将该值更新为匹配在上一步中创建的 PV 的名称。kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-blob spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi volumeName: pv-blob storageClassName: azureblob-nfs-premium使用
kubectl create以下命令创建 PVC:kubectl create -f pvc-blob-nfs.yaml
使用永久性卷
以下 YAML 创建一个 Pod,它使用之前创建的名为 pvc-blob 的 PV 或 PVC 在路径 /mnt/blob 装载 Azure Blob 存储。
创建一个名为
nginx-pod-blob.yaml的文件,并将以下 YAML 清单粘贴进去。 请确保在为 NFS 或 Blobfuse 创建 PV 时,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:kubectl create -f nginx-pod-blob.yaml使用
kubectl exec以下命令创建与 Pod 的 shell 会话,验证是否已正确装载 Blob 存储:kubectl exec -it nginx-blob -- df -h输出应类似于以下示例输出,其中显示了 Blob 存储装载在
/mnt/blob路径上:Filesystem Size Used Avail Use% Mounted on ... blobfuse 14G 41M 13G 1% /mnt/blob ...