在 Azure Kubernetes 服务 (AKS) 中通过 Azure 文件存储创建并使用卷
永久性卷表示已经过预配可以用于 Kubernetes Pod 的存储块。 永久性卷可供一个或多个 Pod 使用,并可动态或静态预配。 如果多个 Pod 需要同时访问同一存储卷,则可以使用 Azure 文件存储通过服务器消息块 (SMB) 协议进行连接。 本文介绍如何动态创建 Azure 文件共享以供 Azure Kubernetes 服务 (AKS) 群集中的多个 Pod 使用。
本文介绍如何:
- 通过安装容器存储接口 (CSI) 驱动程序并动态创建一个或多个要附加到 Pod 的 Azure 文件共享来使用动态永久性卷 (PV)。
- 通过创建一个或多个 Azure 文件共享来使用静态 PV,或者使用现有 Azure 文件共享并将其附加到 Pod。
有关 Kubernetes 卷的详细信息,请参阅 AKS 中应用程序的存储选项。
准备阶段
- 需要一个 Azure 存储帐户。
- 确保已安装且已配置 Azure CLI 版本 2.0.59。 运行
az --version
即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI。 - 在标准文件共享和高级文件共享之间进行选择时,请务必了解计划针对 Azure 文件存储运行的预期使用模式的预配模型和要求。 有关详细信息,请参阅根据使用模式选择 Azure 文件存储性能层。
动态预配卷
本部分为想要预配一个或多个永久性卷的群集管理员提供指导,这些卷中包含 Azure 文件存储上的一个或多个共享的详细信息。 永久性卷声明 (PVC) 使用存储类对象来动态预配 Azure 文件存储文件共享。
动态 PersistentVolume 的存储类参数
下表包含可用于为 PersistentVolumeClaim 定义自定义存储类的参数。
名称 | 含义 | 可用值 | 必需 | 默认值 |
---|---|---|---|---|
accountAccessTier | 存储帐户的访问层 | 标准帐户可以选择 Hot 或 Cool ,高级帐户只能选择 Premium 。 |
否 | 空白。 对不同的存储帐户类型使用默认设置。 |
accountQuota | 限制帐户的配额。 可以 GB 为单位指定最大配额(默认值为 102400GB)。 如果帐户超过指定的配额,驱动程序将跳过选择该帐户的步骤。 | 否 | 102400 |
|
allowBlobPublicAccess | 允许或禁止公共访问驱动程序创建的存储帐户的所有 Blob 或容器。 | true 或 false |
否 | false |
disableDeleteRetentionPolicy | 指定是否为驱动程序创建的存储帐户禁用 DeleteRetentionPolicy。 | true 或 false |
否 | false |
enableLargeFileShares | 指定是否使用启用了大文件共享的存储帐户。 如果此标志设置为 true ,并且没有启用了大文件共享的存储帐户,则会创建一个启用了大文件共享的新存储帐户。 此标志应与标准 sku 一起使用,因为使用高级 sku 创建的存储帐户默认启用 largeFileShares 选项。 |
true 或 false |
否 | false |
folderName | 在 Azure 文件共享中指定文件夹名称。 | Azure 文件共享中的现有文件夹名称。 | 否 | 如果文件共享中不存在文件夹名称,则装载失败。 |
getLatestAccount | 确定是否根据创建时间获取最新的帐户密钥。 默认情况下,此驱动程序将获取第一个密钥。 | true 或 false |
否 | false |
location | 指定 Azure 存储帐户的 Azure 区域。 | 例如,eastus 。 |
否 | 如果为空,驱动程序将使用与当前 AKS 群集相同的位置名称。 |
matchTags | 驱动程序尝试查找合适的存储帐户时匹配标记。 | true 或 false |
否 | false |
networkEndpointType | 为驱动程序创建的存储帐户指定网络终结点类型。 如果指定 privateEndpoint ,则为存储帐户创建专用终结点。 对于其他情况,默认创建服务终结点。 |
"",privateEndpoint |
否 | "" |
protocol | 指定文件共享协议。 | smb ,nfs |
否 | smb |
requireInfraEncryption | 指定服务是否使用平台托管密钥为驱动程序创建的存储帐户的静态数据应用第二层加密。 | true 或 false |
否 | false |
resourceGroup | 指定 Azure 磁盘的资源组。 | 现有资源组名称 | 否 | 如果为空,驱动程序将使用与当前 AKS 群集相同的资源组名称。 |
selectRandomMatchingAccount | 确定是否随机选择匹配帐户。 默认情况下,驱动程序始终按字母顺序选择第一个匹配的帐户(注意:此驱动程序使用帐户搜索缓存,这会导致多个帐户之间的文件创建分布不均匀)。 | true 或 false |
否 | false |
server | 指定 Azure 存储帐户服务器地址。 | 现有服务器地址,例如 accountname.privatelink.file.core.chinacloudapi.cn 。 |
否 | 如果为空,驱动程序使用默认的 accountname.file.core.chinacloudapi.cn 或其他主权云帐户地址。 |
shareAccessTier | 文件共享的访问层 | 常规用途 v2 帐户可以在 TransactionOptimized (默认)、Hot 和 Cool 之间进行选择。 仅适用于文件共享的高级存储帐户类型。 |
否 | 空白。 对不同的存储帐户类型使用默认设置。 |
shareName | 指定 Azure 文件共享名称。 | 现有或新的 Azure 文件共享名称。 | 否 | 如果为空,驱动程序将生成一个 Azure 文件共享名称。 |
shareNamePrefix | 指定由驱动程序创建的 Azure 文件共享名称前缀。 | 共享名只能包含小写字母、数字、连字符,长度应少于 21 个字符。 | 否 | |
skuName | Azure 文件存储存储帐户类型(别名:storageAccountType ) |
Standard_LRS ,Standard_ZRS ,Standard_GRS ,Standard_RAGRS ,Standard_RAGZRS ,Premium_LRS ,Premium_ZRS |
否 | StandardSSD_LRS 高级帐户类型的最小文件共享大小为 100 GB。 ZRS 帐户类型在有限区域内受支持。 NFS 文件共享仅支持高级帐户类型。 |
storageAccount | 指定 Azure 存储帐户名称。 | storageAccountName | 否- | 如果未提供特定的存储帐户名称,驱动程序将查找与同一资源组中的帐户设置匹配的合适存储帐户。 如果驱动程序找不到匹配的存储帐户,则将创建新的存储帐户。 但是,如果指定了存储帐户名称,则存储帐户必须已经存在。 |
storageEndpointSuffix | 指定 Azure 存储终结点后缀。 | core.chinacloudapi.cn 、core.chinacloudapi.cn 等 |
否 | 如果为空,驱动程序将根据云环境使用默认存储终结点后缀。 例如 core.chinacloudapi.cn 。 |
标记 | 标记是在新的存储帐户中创建的。 | 标记格式:“foo=aaa,bar=bbb” | 否 | "" |
--- | 以下参数仅适用于 SMB 协议 | --- | --- | |
subscriptionID | 指定在其中创建 Azure 文件共享的 Azure 订阅 ID。 | Azure 订阅 ID | 否 | 如果不为空,则必须提供 resourceGroup 。 |
storeAccountKey | 指定是否将帐户密钥存储到 Kubernetes 机密。 | true 或 false false 表示驱动程序使用 kubelet 标识获取帐户密钥。 |
否 | true |
secretName | 指定用于存储帐户密钥的机密名称。 | 否 | ||
secretNamespace | 指定用于存储帐户密钥的机密的命名空间。 注意: 如果未指定 secretNamespace ,则会在 Pod 所在的同一命名空间中创建机密。 |
default 、kube-system 等。 |
否 | PVC 命名空间,例如 csi.storage.k8s.io/pvc/namespace |
useDataPlaneAPI | 指定是否使用数据平面 API进行文件共享的创建/删除/调整大小,这可以解决 SRP API 限制问题,因为数据平面 API 几乎没有限制,当存储帐户上存在防火墙或 Vnet 设置,将会失败。 | true 或 false |
否 | false |
--- | 以下参数仅适用于 NFS 协议 | --- | --- | |
mountPermissions | 装载的文件夹权限。 默认为 0777 。 如果设置为 0 ,则驱动程序在装载后不会执行 chmod 。 |
0777 |
否 | |
rootSquashType | 指定共享上的根压缩行为。 默认值为 NoRootSquash |
AllSquash ,NoRootSquash ,RootSquash |
否 | |
--- | 以下参数仅适用于 VNet 设置。 例如,NFS、专用终结点 | --- | --- | |
fsGroupChangePolicy | 指示驱动程序如何更改卷的所有权。 Pod securityContext.fsGroupChangePolicy 将被忽略。 |
OnRootMismatch (默认)、Always 、None |
否 | OnRootMismatch |
subnetName | 子网名称 | 代理节点的现有子网名称。 | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中的 subnetName 值。 |
vnetName | 虚拟网络名称 | 现有虚拟网络名称。 | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中的 vnetName 值。 |
vnetResourceGroup | 指定在其中定义虚拟网络的 VNet 资源组。 | 现有资源组名称。 | 否 | 如果为空,驱动程序将使用 Azure 云配置文件中的 vnetResourceGroup 值。 |
创建存储类
存储类定义如何创建 Azure 文件共享。 系统会在节点资源组中自动创建一个存储帐户,以便与存储类一起用来保存 Azure 文件存储文件共享。 为 skuName
选择以下 Azure 存储冗余 SKU 之一:
Standard_LRS
:标准本地冗余存储 (LRS)Standard_GRS
:标准异地冗余存储 (GRS)Standard_ZRS
:标准区域冗余存储 (ZRS)Standard_RAGRS
:标准读取访问异地冗余存储 (RA-GRS)
注意
最小的高级文件共享为 100 GB。
有关 Azure 文件存储的 Kubernetes 存储类的详细信息,请参阅 Kubernetes 存储类。
创建名为
azure-file-sc.yaml
的文件,并将其复制到以下示例清单中。 有关mountOptions
的详细信息,请参阅装载选项部分。kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: my-azurefile provisioner: file.csi.azure.com # replace with "kubernetes.io/azure-file" if aks version is less than 1.21 allowVolumeExpansion: true mountOptions: - dir_mode=0777 - file_mode=0777 - uid=0 - gid=0 - mfsymlinks - cache=strict - actimeo=30 - nobrl # disable sending byte range lock requests to the server and for applications which have challenges with posix locks parameters: skuName: Premium_LRS
使用
kubectl apply
命令创建存储类。kubectl apply -f azure-file-sc.yaml
创建永久性卷声明
永久性卷声明 (PVC) 使用存储类对象来动态预配 Azure 文件共享。 可以使用以下 YAML 创建大小为 100 GB、访问权限为 ReadWriteMany 的永久性卷声明。 有关访问模式的详细信息,请参阅 Kubernetes 永久性卷。
创建名为
azure-file-pvc.yaml
的文件,并将其复制到以下 YAML 中。 请确保storageClassName
与上一步骤中创建的存储类匹配。apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-azurefile spec: accessModes: - ReadWriteMany storageClassName: my-azurefile resources: requests: storage: 100Gi
注意
如果将
Premium_LRS
SKU 用于存储类,则storage
最小值必须为100Gi
。使用
kubectl apply
命令创建永久性卷声明。kubectl apply -f azure-file-pvc.yaml
完成此步骤后,文件共享即创建完毕。 同时还会创建一个包含连接信息和凭据的 Kubernetes 机密。 可以使用
kubectl get
命令查看 PVC 的状态:kubectl get pvc my-azurefile
该命令的输出类似于以下示例:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-azurefile Bound pvc-8436e62e-a0d9-11e5-8521-5a8664dc0477 100Gi RWX my-azurefile 5m
使用永久性卷
以下 YAML 创建的 Pod 使用永久性卷声明 my-azurefile 将 Azure 文件存储文件共享装载到 /mnt/azure 路径。 对于 Windows Server 容器,请使用 Windows 路径约定指定 mountPath
,例如“D:”。
创建名为
azure-pvc-files.yaml
的文件,并将其复制到以下 YAML 中。 请确保claimName
与上一步骤中创建的 PVC 匹配。kind: Pod apiVersion: v1 metadata: name: mypod spec: containers: - name: mypod image: mcr.azk8s.cn/oss/nginx/nginx:1.15.5-alpine resources: requests: cpu: 100m memory: 128Mi limits: cpu: 250m memory: 256Mi volumeMounts: - mountPath: /mnt/azure name: volume readOnly: false volumes: - name: volume persistentVolumeClaim: claimName: my-azurefile
使用
kubectl apply
命令创建 Pod。kubectl apply -f azure-pvc-files.yaml
现有一个正在运行的 Pod,其中的 Azure 文件存储文件共享已装载到 /mnt/azure 目录中。 使用
kubectl describe
命令检查 Pod 时,可以看到此配置。 以下精简示例输出显示容器中装载的卷。Containers: mypod: Container ID: docker://053bc9c0df72232d755aa040bfba8b533fa696b123876108dec400e364d2523e Image: mcr.azk8s.cn/oss/nginx/nginx:1.15.5-alpine Image ID: docker-pullable://nginx@sha256:d85914d547a6c92faa39ce7058bd7529baacab7e0cd4255442b04577c4d1f424 State: Running Started: Fri, 01 Mar 2019 23:56:16 +0000 Ready: True Mounts: /mnt/azure from volume (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-8rv4z (ro) [...] Volumes: volume: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: my-azurefile ReadOnly: false [...]
装载选项
对于 Kubernetes 版本 1.13.0 及更高版本,fileMode
和 dirMode
的默认值为 0777。 如果使用存储类动态创建永久性卷,则可以在存储类对象上指定装载选项。 有关详细信息,请参阅装载选项。 以下示例设置 0777:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: my-azurefile
provisioner: file.csi.azure.com # replace with "kubernetes.io/azure-file" if aks version is less than 1.21
allowVolumeExpansion: true
mountOptions:
- dir_mode=0777
- file_mode=0777
- uid=0
- gid=0
- mfsymlinks
- cache=strict
- actimeo=30
- nobrl # disable sending byte range lock requests to the server and for applications which have challenges with posix locks
parameters:
skuName: Premium_LRS
使用 Azure 标记
有关使用 Azure 标记的详细信息,请参阅在 Azure Kubernetes 服务 (AKS) 中使用 Azure 标记。
静态预配卷
本部分为想要创建一个或多个永久性卷的群集管理员提供指导,其中包含供工作负载使用的现有 Azure 文件存储共享的详细信息。
PersistentVolume 的静态预配参数
下表包含可用于定义 PersistentVolume 的参数。
名称 | 含义 | 可用值 | 必需 | 默认值 |
---|---|---|---|---|
volumeAttributes.resourceGroup | 指定 Azure 资源组名称。 | myResourceGroup | 否 | 如果为空,驱动程序将使用与当前群集相同的资源组名称。 |
volumeAttributes.storageAccount | 指定现有的 Azure 存储帐户名称。 | storageAccountName | 是 | |
volumeAttributes.shareName | 指定 Azure 文件共享名称。 | fileShareName | 是 | |
volumeAttributes.folderName | 在 Azure 文件共享中指定文件夹名称。 | folderName | 否 | 如果文件共享中不存在文件夹名称,装载将失败。 |
volumeAttributes.protocol | 指定文件共享协议。 | smb ,nfs |
否 | smb |
volumeAttributes.server | 指定 Azure 存储帐户服务器地址 | 现有服务器地址,例如 accountname.privatelink.file.core.chinacloudapi.cn 。 |
否 | 如果为空,驱动程序使用默认的 accountname.file.core.chinacloudapi.cn 或其他主权云帐户地址。 |
--- | 以下参数仅适用于 SMB 协议 | --- | --- | --- |
volumeAttributes.secretName | 指定用于存储帐户名称和密钥的机密名称。 | 否 | ||
volumeAttributes.secretNamespace | 指定机密命名空间。 | default 、kube-system 等。 |
否 | PVC 命名空间 (csi.storage.k8s.io/pvc/namespace ) |
nodeStageSecretRef.name | 指定用于存储帐户名称和密钥的机密名称。 | 现有机密名称。 | 否 | 如果为空,驱动程序则使用 kubelet 标识获取帐户密钥。 |
nodeStageSecretRef.namespace | 指定机密命名空间。 | Kubernetes 命名空间 | 否 | |
--- | 以下参数仅适用于 NFS 协议 | --- | --- | --- |
volumeAttributes.fsGroupChangePolicy | 指示驱动程序如何更改卷的所有权。 Pod securityContext.fsGroupChangePolicy 将被忽略。 |
OnRootMismatch (默认)、Always 、None |
否 | OnRootMismatch |
volumeAttributes.mountPermissions | 指定装载的文件夹权限。 默认值为 0777 |
否 |
创建 Azure 文件共享
必须先创建 Azure 存储帐户和文件共享,然后才能将 Azure 文件存储文件共享用作 Kubernetes 卷。
使用具有
--query nodeResourceGroup
参数的az aks show
命令获取资源组名称。az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv
该命令的输出类似于以下示例:
MC_myResourceGroup_myAKSCluster_chinaeast2
使用具有
--sku
参数的az storage account create
命令创建存储帐户。 以下命令使用Standard_LRS
SKU 创建存储帐户。 确保替换以下占位符:- 将
myAKSStorageAccount
替换为存储帐户的名称 - 将
nodeResourceGroupName
替换为托管 AKS 群集节点的资源组的名称 - 将
location
替换为要在其中创建资源的区域的名称。 它应与 AKS 群集节点为同一区域。
az storage account create -n myAKSStorageAccount -g nodeResourceGroupName -l location --sku Standard_LRS
- 将
使用以下命令将连接字符串导出为环境变量,该命令用于创建文件共享。
export AZURE_STORAGE_CONNECTION_STRING=$(az storage account show-connection-string -n storageAccountName -g resourceGroupName -o tsv)
使用
az storage share create
命令创建文件共享。 确保将shareName
替换为你的共享名。az storage share create -n shareName --connection-string $AZURE_STORAGE_CONNECTION_STRING
运行以下命令,将存储帐户密钥导出为环境变量。
STORAGE_KEY=$(az storage account keys list --resource-group nodeResourceGroupName --account-name myAKSStorageAccount --query "[0].value" -o tsv)
运行以下命令以回显存储帐户名称和密钥。 复制这些信息,创建 Kubernetes 卷时需要用到这些值。
echo Storage account key: $STORAGE_KEY
创建 Kubernetes 机密
Kubernetes 需要使用凭据访问上一步骤中创建的文件共享。 这些凭据存储在 Kubernetes 机密中,创建 Kubernetes Pod 时将引用它。
使用
kubectl create secret
命令创建机密。 以下示例创建一个名为 azure-secret 的机密并填充上一步骤中的 azurestorageaccountname 和 azurestorageaccountkey。 若要使用现有 Azure 存储帐户,请提供帐户名称和密钥。kubectl create secret generic azure-secret --from-literal=azurestorageaccountname=myAKSStorageAccount --from-literal=azurestorageaccountkey=$STORAGE_KEY
将文件共享装载为永久性卷
新建名为
azurefiles-pv.yaml
的文件,并将以下内容复制到其中。 在csi
下,更新resourceGroup
、volumeHandle
和shareName
。 对于装载选项,fileMode
和dirMode
的默认值为 0777。apiVersion: v1 kind: PersistentVolume metadata: name: azurefile spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: azurefile-csi csi: driver: file.csi.azure.com volumeHandle: "{resource-group-name}#{account-name}#{file-share-name}" # make sure this volumeid is unique for every identical share in the cluster volumeAttributes: resourceGroup: resourceGroupName # optional, only set this when storage account is not in the same resource group as node 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
使用
kubectl create
命令创建永久性卷。kubectl create -f azurefiles-pv.yaml
新建名为“azurefiles-mount-options-pvc.yaml”的文件,并将以下内容复制到其中。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: azurefile spec: accessModes: - ReadWriteMany storageClassName: azurefile-csi volumeName: azurefile resources: requests: storage: 5Gi
使用
kubectl apply
命令创建 PersistentVolumeClaim。kubectl apply -f azurefiles-mount-options-pvc.yaml
使用
kubectl get
命令验证 PersistentVolumeClaim 是否已创建并绑定到 PersistentVolume。kubectl get pvc azurefile
命令的输出如下例所示:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE azurefile Bound azurefile 5Gi RWX azurefile 5s
更新容器规范以引用 PersistentVolumeClaim 以及 YAML 文件中的 Pod。 例如:
... volumes: - name: azure persistentVolumeClaim: claimName: azurefile
由于无法就地更新 Pod 规范,因此请使用
kubectl delete
命令删除 Pod,然后使用kubectl apply
命令重新创建 Pod。kubectl delete pod mypod kubectl apply -f azure-files-pod.yaml
装载文件共享作为内联卷
注意
为了避免性能问题,建议在大量 Pod 访问同一文件共享时使用永久性卷而不是内联卷。 内联卷只能访问与 Pod 相同的命名空间中的机密。 若要指定其他机密命名空间,请使用永久性卷。
若要将 Azure 文件存储文件共享装载到 Pod 中,请在容器规范中配置卷。
- 新建名为
azure-files-pod.yaml
的文件,并将以下内容复制到其中。 如果更改了文件共享名称或机密名称,请更新shareName
和secretName
。 也可以更新mountPath
,这是文件共享在 Pod 中的装载路径。 对于 Windows Server 容器,请使用 Windows 路径约定指定mountPath
,例如“D:”。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- image: 'mcr.azk8s.cn/oss/nginx/nginx:1.15.5-alpine'
name: mypod
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
volumeMounts:
- name: azure
mountPath: /mnt/azure
readOnly: false
volumes:
- name: azure
csi:
driver: file.csi.azure.com
volumeAttributes:
secretName: azure-secret # required
shareName: aksshare # required
mountOptions: 'dir_mode=0777,file_mode=0777,cache=strict,actimeo=30,nosharesock,nobrl' # optional
使用
kubectl apply
命令创建 Pod。kubectl apply -f azure-files-pod.yaml
现在你有一个正在运行的 Pod,其中 Azure 文件存储文件共享装载在 /mnt/azure 处。 可以使用
kubectl describe
命令验证是否已成功装载共享。kubectl describe pod mypod
后续步骤
有关 Azure 文件存储 CSI 驱动程序参数,请参阅 CSI 驱动程序参数。
如需相关的最佳做法,请参阅 AKS 中的存储和备份最佳做法。