装载 Azure 文件共享时出错
本文提供了可能导致 Azure 文件共享装载失败的错误的原因和解决方案。
现象
在 Azure Kubernetes 服务 (AKS) 环境中部署 Kubernetes 资源,例如 Deployment 或 StatefulSet。 在部署过程中,需创建一个 Pod,用于装载引用 Azure 文件共享的 PersistentVolumeClaim (PVC)。
但是,Pod 会一直处于 ContainerCreating 状态。 运行该 kubectl describe pods
命令时,命令输出中可能会出现以下错误之一,这会导致装载操作失败:
请参考以下输出示例:
MountVolume.MountDevice failed for volume "\<pv-fileshare-name>"
rpc error: code = Internal desc =
volume(\<storage-account's-resource-group>#\<storage-account-name>#\<pv/fileshare-name>#) > mount "//\<storage-account-name>.file.core.windows.net/\<pv-fileshare-name>" on "/var/lib/kubelet/plugins/kubernetes.io/csi/pv/\<pv-fileshare-name>/globalmount" failed with
mount failed: exit status 32
Mounting command: mount
Mounting arguments: -t cifs -o dir_mode=0777,file_mode=0777,uid=0,gid=0,mfsymlinks,cache=strict,actimeo=30,\<masked> //\<storage-account-name>.file.core.windows.net/\<pv-name> /var/lib/kubelet/plugins/kubernetes.io/csi/pv/\<pv-name>/globalmount
Output: mount error(\<error-id>): \<error-description>
Refer to the mount.cifs(8) manual page (e.g. man mount.cifs) and kernel log messages (dmesg)
注意
- 如果可公开访问存储帐户,输出中显示的主机名将是 storage-account-name.file.core.windows.net>。<
- 如果使用专用链接、终结点或 DNS 区域私下配置存储帐户,主机名将为 storage-account-name.privatelink.file.core.windows.net>。<
故障排除准备工作
根据输出中的消息,如以下示例所示,标识存储帐户和文件共享,这些值将用于后面的故障排除步骤。
mount “//<storage-account-name.file.core.windows.net/>< pv-fileshare-name>”
有关可能的原因和解决方法,请查看下列部分。
装载错误(2):没有此类文件或目录
此错误表示 AKS 群集与存储帐户之间没有连接。
初始故障排除
Azure 文件依赖 SMB 协议(端口 445)。 确保未阻止端口 445 和/或存储帐户的 IP 地址。
若要检查存储帐户的 IP 地址,请运行域名系统 (DNS) 命令(如 nslookup
、dig
或 host
)。 例如:
nslookup <storage-account-name>.file.core.windows.net
若要检查 AKS 群集与存储帐户之间是否存在连接,请进入节点或 Pod 并运行以下 nc
或 telnet
命令:
nc -v -w 2 <storage-account-name>.file.core.windows.net 445
telnet <storage-account-name>.file.core.windows.net 445
装载错误 (2) 的可能原因
- 原因 1:文件共享不存在
- 原因 2:NSG 阻止 AKS 和存储帐户之间的流量
- 原因 3:虚拟设备阻止 AKS 与存储帐户之间的流量
- 原因 4:使用了已启用 FIPS 的节点池
注意
- 原因 1、2 和 4 适用于公共和专用存储帐户方案。
- 原因 3 仅适用于公共方案。
原因 1:文件共享不存在
若要检查文件共享是否存在,请执行以下步骤:
解决方案:确保文件共享存在
若要解决此问题,请确保与 PV/PVC 关联的文件共享存在。
原因 2:网络安全组阻止 AKS 与存储帐户之间的流量
检查“初始故障排除”部分中提到的或telnet
命令的nc
输出。 如果显示超时,请检查网络安全组 (NSG) 并确保未阻止存储帐户的 IP 地址。
若要检查 NSG 是否阻止存储帐户的 IP 地址,请执行以下步骤:
在Azure 门户中,转到网络观察程序并选择 NSG 诊断。
使用以下值填写字段:
- 协议:任意
- 方向:出站
- 源类型:IPv4 地址/CIDR
- IPv4 地址/CIDR:与 AKS 节点关联的实例的 IP 地址
- 目标 IP 地址:存储帐户的 IP 地址
- 目标端口:445
选择“检查”按钮并检查流量状态。
流量状态可以是“允许”或“拒绝”。 “被拒绝”状态表示 NSG 正在阻止 AKS 群集和存储帐户之间的流量。 如果状态为 “拒绝”,将显示 NSG 名称。
解决方案:允许 AKS 和存储帐户之间的连接
若要解决此问题,请在 NSG 级别执行相应的更改,以允许 AKS 群集与端口 445 上的存储帐户之间的连接。
原因 3:虚拟设备阻止 AKS 与存储帐户之间的流量
如果使用虚拟设备(通常为防火墙)来控制 AKS 群集的出站流量(例如,虚拟设备在 AKS 群集的子网中应用了路由表,并且该路由表具有将流量发送到虚拟设备的路由),则虚拟设备可能会阻止 AKS 群集与存储帐户之间的流量。
若要隔离该问题,请在路由表中为存储帐户的 IP 地址添加路由,以便将流量发送到 Internet。
若要确认 AKS 群集的流量由哪个路由表控制,请执行以下步骤:
- 转到Azure 门户中的 AKS 群集,然后选择“属性>基础结构”资源组。
- 如果使用的是此类 VM 集类型,请访问可用性集中的虚拟机规模集 (VMSS) 或 VM。
- 选择虚拟网络/子网>子网并标识 AKS 群集的子网。 可以在右侧看到路由表。
若要在路由表中添加路由,请按照创建路由中的步骤操作并填写以下字段:
- 地址前缀: <存储帐户的-public-IP>/32
- 下一跃点类型:Internet
此路由将通过公共 Internet 发送 AKS 群集和存储帐户之间的所有流量。
添加路由后,使用 nc
或 telnet
命令测试连接性,然后再次执行装载操作。
解决方案:确保虚拟设备允许 AKS 和存储帐户之间的流量
如果装载操作成功,建议咨询网络团队,确保虚拟设备可以允许 AKS 群集与端口 445 上的存储帐户之间的流量。
原因 4:使用了已启用 FIPS 的节点池
如果使用已启用美国联邦信息处理标准 (FIPS) 的节点池,装载操作将失败,因为 FIPS 禁用了某些身份验证模块,这会阻止装载 CIFS 共享。 此行为是预期行为,并非特定于 AKS。
若要解决此问题,请使用以下解决方案之一:
解决方案 1:在非 FIPS 节点池中的节点上计划 Pod
默认情况下,FIPS 在 AKS 节点池上处于禁用状态,并且只能在创建节点池期间使用 --enable-fips-image
参数启用 FIPS。
若要解决此错误,可以在非 FIPS 节点池中的节点上计划 Pod。
解决方案 2:创建可在启用了 FIPS 的节点上计划的 Pod
若要创建可在启用了 FIPS 的节点上计划的 Pod,请执行以下步骤:
使用 Azure 文件 CSI 驱动程序创建使用 NFS 协议的自定义 StorageClass。
请参阅以下 YAML 文件示例:
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: azurefile-sc-fips provisioner: file.csi.azure.com reclaimPolicy: Delete volumeBindingMode: Immediate allowVolumeExpansion: true parameters: skuName: Premium_LRS protocol: nfs
由于 NFS 需要高级 SKU,因此 YAML 文件中的 SKU 设置为 Premium_LRS。 有关详细信息,请参阅动态预配。
出于高级 SKU 的原因,文件共享的最小大小为 100GB。 有关详细信息,请参阅创建存储类。
创建引用自定义 StorageClass azurefile-sc-fips 的 PVC。
请参阅以下 YAML 文件示例:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: azurefile-pvc-fips spec: accessModes: - ReadWriteMany storageClassName: azurefile-sc-fips resources: requests: storage: 100Gi
创建装载 PVC azurefile-pvc-fips 的 Pod。
请参阅以下 YAML 文件示例:
kind: Pod apiVersion: v1 metadata: name: azurefile-pod-fips spec: containers: - name: azurefile-pod-fips image: mcr.microsoft.com/oss/nginx/nginx:1.15.5-alpine resources: requests: cpu: 100m memory: 128Mi limits: cpu: 250m memory: 256Mi volumeMounts: - mountPath: "/mnt/azure" name: volume volumes: - name: volume persistentVolumeClaim: claimName: azurefile-pvc-fips
装载错误(13):权限被拒绝
可能导致此错误的原因包括:
- 原因 1:Kubernetes 机密未引用正确的存储帐户名称或密钥
- 原因 2:存储帐户不允许使用 AKS 的 VNET 和子网
- 原因 3:连接通过专用链接,但节点和专用终结点位于不同的 VNET 中
- 原因 4:存储帐户设置为要求客户端不支持的加密
- 原因 5:不符合存储帐户的最低加密要求
- 原因 6:在未启用 NTLM v2 身份验证的情况下使用安全配置文件
注意
- 原因 1 适用于公共和专用方案。
- 原因 2 仅适用于公共方案。
- 原因 3 仅适用于专用方案。
- 原因 4 适用于公共和专用方案。
- 原因 5 适用于公共和专用方案。
- 原因 6 适用于公共和专用方案。
原因 1:Kubernetes 机密未引用正确的存储帐户名称或密钥
如果动态创建文件共享,则会使用名称“azure-storage-account-storage-account-name-secret<>”自动创建 Kubernetes 机密资源。
如果文件共享是手动创建的,则应手动创建 Kubernetes 机密资源。
无论创建方法如何,如果 Kubernetes 机密中引用的存储帐户名称或密钥与实际值不匹配,装载操作将失败并出现“权限被拒绝”错误。
不匹配的可能原因
如果 Kubernetes 机密是手动创建的,则创建过程中可能会出现拼写错误。
如果在存储帐户级别执行“轮换密钥”操作,则更改不会在 Kubernetes 机密级别有所反映。 这将导致存储帐户级别的密钥值与 Kubernetes 机密级别的值不匹配。
如果发生“轮换密钥”操作,存储帐户的活动日志中会显示名为“重新生成存储帐户密钥”的操作。 请注意活动日志的 90 天保持期。
验证不匹配问题
若要验证不匹配,请执行以下步骤:
在 Azure 门户中搜索并访问存储帐户。 选择“访问密钥>显示存储帐户中的密钥”。 你将看到存储帐户名称和关联的密钥。
转到 AKS 群集,选择“配置>机密”,然后搜索并访问关联的机密。
选择“显示”(眼睛图标),并将存储帐户名称和关联密钥的值与步骤 1 中的值进行比较。
在选择“显示”之前,存储帐户名称和关联密钥的值将编码为 base64 字符串。 选择“显示”后,将解码值。
如果无权访问 Azure 门户中的 AKS 群集,请在 kubectl 级别执行步骤 2:
获取 Kubernetes 机密的 YAML 文件,然后运行以下命令,从输出中获取存储帐户名称和密钥的值:
kubectl get secret <secret-name> -n <secret-namespace> -o <yaml-file-name>
使用
echo
命令解码存储帐户名称和密钥的值,并将其与存储帐户级别的值进行对比。下面是解码存储帐户名称的示例:
echo -n '<storage account name>' | base64 --decode ;echo
解决方案:调整 Kubernetes 机密并重新创建 Pod
如果 Kubernetes 机密中的存储帐户名称或密钥的值与存储帐户中 访问密钥 中的值不匹配,请运行以下命令来调整 Kubernetes 机密级别的 Kubernetes 机密:
kubectl edit secret <secret-name> -n <secret-namespace>
在 Kubernetes 机密配置中添加的存储帐户名称或密钥的值应为 base64 编码值。 若要获取编码值,请使用 echo
命令。
下面是对存储帐户名称进行编码的示例:
echo -n '<storage account name>'| base64 | tr -d '\n' ; echo
有关详细信息,请参阅使用 kubectl 管理机密。
Kubernetes 机密 azure-storage-account-<storage-account-name>-secret
有正确值后,请重新创建 Pod。 否则,这些 Pod 将继续使用不再有效的旧值。
原因 2:不允许存储帐户使用 AKS 的 VNET 和子网
如果存储帐户的网络仅限于所选网络,但 AKS 群集的 VNET 和子网未添加到所选网络,装载操作便会失败并出现“权限被拒绝”错误。
解决方案:允许存储帐户使用 AKS 的 VNET 和子网
运行以下命令,确定托管有故障 Pod 的节点:
kubectl get pod <pod-name> -n <namespace> -o wide
检查命令输出中的节点:
转到Azure 门户中的 AKS 群集,选择“属性>基础结构”资源组,访问与节点关联的 VMSS,然后检查虚拟网络/子网以标识 VNET 和子网。
在 Azure 门户中访问存储帐户。 选择“网络”。 如果 “允许访问” 设置为 “所选网络”,请检查是否添加了 AKS 群集的 VNET 和子网。
如果未添加 AKS 群集的 VNET 和子网,请选择“ 添加现有虚拟网络”。 在“添加网络”页上,键入 AKS 群集的 VNET 和子网,然后选择“添加>保存”。
更改可能需要几分钟才能生效。 添加 VNET 和子网后,检查 Pod 状态是否从 ContainerCreating 更改为 “正在运行”。
原因 3:是通过专用链接进行连接的,但节点和专用终结点位于不同的 VNET 中
通过专用链接连接 AKS 群集和存储帐户时,将使用经过审批的专用终结点连接。
在这种情况下,如果专用终结点和 AKS 节点位于同一个 VNET 中,你将能够装载 Azure 文件共享。
如果专用终结点和 AKS 群集位于不同的 VNET 中,则装载操作将失败并出现“权限被拒绝”错误。
解决方案:在专用 DNS 区域为 AKS 群集的 VNET 创建虚拟网络链接
进入节点内部并检查完全限定的域名 (FQDN) 是否通过公共或专用 IP 地址解析。 为此,请运行以下命令:
nslookup <storage-account-name>.privatelink.file.core.windows.net
如果是通过公共 IP 地址解析 FQDN(请参阅以下屏幕截图),请在专用 DNS 区域(“privatelink.file.core.windows.net”)级别为 AKS 群集的 VNET 创建虚拟网络链接。 请注意,已为存储帐户的专用终结点的 VNET 自动创建虚拟网络链接。
若要创建虚拟网络链接,请执行以下步骤:
访问私人 DNS区域,然后选择“添加虚拟网络链接>”。
填写字段,然后选择虚拟网络的 AKS 群集的 VNET。 若要了解如何识别 AKS 群集的 VNET,请参阅解决方案:允许存储帐户使用 AKS 的 VNET 和子网部分。
选择“确定”。
添加虚拟网络链接后,FQDN 应该会通过专用 IP 地址解析,并且装载操作应会成功。 有关示例,请参阅以下屏幕截图:
原因 4:存储帐户设置为要求客户端不支持的加密
Azure 文件存储安全设置包含许多用于控制存储帐户安全和加密设置的选项。 限制允许的方法和算法可以阻止客户端连接。
低于 1.25 的 AKS 版本基于 Ubuntu 18.04 LTS,它使用 Linux 5.4 内核,仅支持 AES-128-CCM 和 AES-128-GCM 加密算法。 最大安全配置文件或禁用 AES-128-GCM 的自定义配置文件将导致共享映射失败。
AKS 1.25 及更高版本基于 Ubuntu 22.04,它使用 Linux 5.15 内核,支持 AES-256-GCM。
解决方案:允许使用 AES-128-GCM 加密算法
通过使用最大兼容性配置文件或启用 AES-128-GCM 的自定义配置文件来启用 AES-128-GCM 算法。 有关详细信息,请参阅 Azure 文件存储安全设置。
原因 5:不符合存储帐户的最低加密要求
解决方案:为所有存储帐户启用 AES-128-GCM 加密算法
若要成功装载或访问文件共享,应为所有存储帐户启用 AES-128-GCM 加密算法。
如果只想使用 AES-256-GCM 加密,请执行以下操作:
Linux
使用以下脚本检查客户端是否支持 AES-256-GCM,并仅在执行以下命令时强制实施:
cifsConfPath="/etc/modprobe.d/cifs.conf"
echo "$(date) before change ${cifsConfPath}:"
cat ${cifsConfPath}
# Check if 'require_gcm_256' is already present in the configuration file
if ! grep -q "require_gcm_256" "${cifsConfPath}"; then
# Load the CIFS module
modprobe cifs
# Set the parameter at runtime
echo 1 > /sys/module/cifs/parameters/require_gcm_256
# Persist the configuration
echo "options cifs require_gcm_256=1" >> "${cifsConfPath}"
echo "$(date) after changing ${cifsConfPath}:"
cat "${cifsConfPath}"
else
echo "require_gcm_256 is already set in ${cifsConfPath}"
fi
还可以使用 Kubernetes DaemonSet 在每个节点上强制实施 AES-256。 请参阅以下示例:
Windows
使用 Set-SmbClientConfiguration PowerShell 命令指定 SMB 客户端使用的加密密码和首选加密类型,而无需用户确认:
Set-SmbClientConfiguration -EncryptionCiphers "AES_256_GCM" -Confirm:$false
注意
该 EncryptionCiphers
参数从 2022-06 Windows Server 版本 21H2(基于 x64 的系统)的累积更新(KB5014665)和 Windows 11 版本 22H2 的累积更新(KB5014668)开始提供。
原因 6:在未启用 NTLM v2 身份验证的情况下使用安全配置文件
如果在未启用 NTLM v2 身份验证机制的情况下使用最大安全配置文件或自定义安全配置文件,装载操作将失败,并显示“装载错误(13):权限被拒绝”错误。
解决方案:启用 NTLM v2 身份验证或使用“最大兼容性”配置文件
若要在 AKS 中正确装载它,必须为自定义安全配置文件启用 NTLM v2 身份验证机制或使用最大兼容性安全配置文件。
详细信息
如果遇到其他一些装载错误,请参阅 Linux 中Azure 文件存储问题疑难解答。
联系我们寻求帮助
如果你有任何疑问或需要帮助,请创建支持请求或联系 Azure 社区支持。 你还可以将产品反馈提交到 Azure 反馈社区。