装载 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) 命令(如 nslookupdighost)。 例如:

nslookup <storage-account-name>.file.core.windows.net

若要检查 AKS 群集与存储帐户之间是否存在连接,请进入节点Pod 并运行以下 nctelnet 命令:

nc -v -w 2 <storage-account-name>.file.core.windows.net 445
telnet <storage-account-name>.file.core.windows.net 445

装载错误 (2) 的可能原因

注意

  • 原因 1、2 和 4 适用于公共和专用存储帐户方案。
  • 原因 3 仅适用于公共方案。

原因 1:文件共享不存在

若要检查文件共享是否存在,请执行以下步骤:

  1. 在Azure 门户中搜索存储帐户并访问存储帐户。

    Azure 门户中存储帐户列表的屏幕截图。

  2. 选择存储帐户中数据存储下的文件共享,并检查 Pod、部署或有状态集的 yaml 文件中是否存在关联的 PersistentVolumeClaim。

    在存储帐户中选择文件共享的屏幕截图。

解决方案:确保文件共享存在

若要解决此问题,请确保与 PV/PVC 关联的文件共享存在。

原因 2:网络安全组阻止 AKS 与存储帐户之间的流量

检查“初始故障排除”部分中提到的telnet命令的nc输出。 如果显示超时,请检查网络安全组 (NSG) 并确保未阻止存储帐户的 IP 地址。

若要检查 NSG 是否阻止存储帐户的 IP 地址,请执行以下步骤:

  1. 在Azure 门户中,转到网络观察程序并选择 NSG 诊断

  2. 使用以下值填写字段:

    • 协议:任意
    • 方向:出站
    • 源类型:IPv4 地址/CIDR
    • IPv4 地址/CIDR:与 AKS 节点关联的实例的 IP 地址
    • 目标 IP 地址:存储帐户的 IP 地址
    • 目标端口:445
  3. 选择“检查”按钮并检查流量状态。

流量状态可以是“允许”或拒绝”。 “被拒绝”状态表示 NSG 正在阻止 AKS 群集和存储帐户之间的流量。 如果状态为 “拒绝”,将显示 NSG 名称。

解决方案:允许 AKS 和存储帐户之间的连接

若要解决此问题,请在 NSG 级别执行相应的更改,以允许 AKS 群集与端口 445 上的存储帐户之间的连接。

原因 3:虚拟设备阻止 AKS 与存储帐户之间的流量

如果使用虚拟设备(通常为防火墙)来控制 AKS 群集的出站流量(例如,虚拟设备在 AKS 群集的子网中应用了路由表,并且该路由表具有将流量发送到虚拟设备的路由),则虚拟设备可能会阻止 AKS 群集与存储帐户之间的流量。

若要隔离该问题,请在路由表中为存储帐户的 IP 地址添加路由,以便将流量发送到 Internet。

若要确认 AKS 群集的流量由哪个路由表控制,请执行以下步骤:

  1. 转到Azure 门户中的 AKS 群集,然后选择“属性>基础结构”资源组。
  2. 如果使用的是此类 VM 集类型,请访问可用性集中的虚拟机规模集 (VMSS) 或 VM。
  3. 选择虚拟网络/子网>子网并标识 AKS 群集的子网。 可以在右侧看到路由表。

若要在路由表中添加路由,请按照创建路由中的步骤操作并填写以下字段:

  • 地址前缀: <存储帐户的-public-IP>/32
  • 下一跃点类型:Internet

此路由将通过公共 Internet 发送 AKS 群集和存储帐户之间的所有流量。

添加路由后,使用 nctelnet 命令测试连接性,然后再次执行装载操作。

解决方案:确保虚拟设备允许 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,请执行以下步骤:

  1. 使用 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。 有关详细信息,请参阅创建存储类

  2. 创建引用自定义 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 
    
  3. 创建装载 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 适用于公共和专用方案。
  • 原因 2 仅适用于公共方案。
  • 原因 3 仅适用于专用方案。
  • 原因 4 适用于公共和专用方案。
  • 原因 5 适用于公共和专用方案。
  • 原因 6 适用于公共和专用方案。

原因 1:Kubernetes 机密未引用正确的存储帐户名称或密钥

如果动态创建文件共享,则会使用名称“azure-storage-account-storage-account-name-secret<>”自动创建 Kubernetes 机密资源

如果文件共享是手动创建的,则应手动创建 Kubernetes 机密资源。

无论创建方法如何,如果 Kubernetes 机密中引用的存储帐户名称或密钥与实际值不匹配,装载操作将失败并出现“权限被拒绝”错误。

不匹配的可能原因

  • 如果 Kubernetes 机密是手动创建的,则创建过程中可能会出现拼写错误。

  • 如果在存储帐户级别执行“轮换密钥”操作,则更改不会在 Kubernetes 机密级别有所反映。 这将导致存储帐户级别的密钥值与 Kubernetes 机密级别的值不匹配。

    如果发生“轮换密钥”操作,存储帐户的活动日志中会显示名为“重新生成存储帐户密钥”的操作。 请注意活动日志的 90 天保持期

验证不匹配问题

若要验证不匹配,请执行以下步骤:

  1. 在 Azure 门户中搜索并访问存储帐户。 选择“访问密钥>显示存储帐户中的密钥”。 你将看到存储帐户名称和关联的密钥。

    存储帐户名称和密钥的屏幕截图。

  2. 转到 AKS 群集,选择“配置>机密,然后搜索并访问关联的机密。

    搜索并选择存储帐户的屏幕截图。

  3. 选择“显示(眼睛图标),并将存储帐户名称和关联密钥的值与步骤 1 中的值进行比较。

    屏幕截图显示机密中的存储帐户名称和密钥。

    在选择“显示之前,存储帐户名称和关联密钥的值将编码为 base64 字符串。 选择“显示后,将解码值。

如果无权访问 Azure 门户中的 AKS 群集,请在 kubectl 级别执行步骤 2:

  1. 获取 Kubernetes 机密的 YAML 文件,然后运行以下命令,从输出中获取存储帐户名称和密钥的值:

    kubectl get secret <secret-name> -n <secret-namespace> -o <yaml-file-name>
    
  2. 使用 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 和子网

  1. 运行以下命令,确定托管有故障 Pod 的节点:

    kubectl get pod <pod-name> -n <namespace> -o wide
    

    检查命令输出中的节点:

    可以标识节点和输出的命令的屏幕截图。

  2. 转到Azure 门户中的 AKS 群集,选择“属性>基础结构”资源组,访问与节点关联的 VMSS,然后检查虚拟网络/子网以标识 VNET 和子网。

    虚拟网络/子网值的屏幕截图。

  3. 在 Azure 门户中访问存储帐户。 选择“网络”。 如果 “允许访问” 设置为 “所选网络”,请检查是否添加了 AKS 群集的 VNET 和子网。

    空所选网络列表的屏幕截图。

    如果未添加 AKS 群集的 VNET 和子网,请选择“ 添加现有虚拟网络”。 在“添加网络”页上,键入 AKS 群集的 VNET 和子网,然后选择“添加>保存”。

    将网络添加到存储帐户的屏幕截图。

    更改可能需要几分钟才能生效。 添加 VNET 和子网后,检查 Pod 状态是否从 ContainerCreating 更改为 “正在运行”。

    显示当前 Pod 状态的命令输出的屏幕截图。

原因 3:是通过专用链接进行连接的,但节点和专用终结点位于不同的 VNET 中

通过专用链接连接 AKS 群集和存储帐户时,将使用经过审批的专用终结点连接。

专用终结点连接的屏幕截图。

在这种情况下,如果专用终结点和 AKS 节点位于同一个 VNET 中,你将能够装载 Azure 文件共享。

如果专用终结点和 AKS 群集位于不同的 VNET 中,则装载操作将失败并出现“权限被拒绝”错误。

进入节点内部并检查完全限定的域名 (FQDN) 是否通过公共或专用 IP 地址解析。 为此,请运行以下命令:

nslookup <storage-account-name>.privatelink.file.core.windows.net

如果是通过公共 IP 地址解析 FQDN(请参阅以下屏幕截图),请在专用 DNS 区域(“privatelink.file.core.windows.net”)级别为 AKS 群集的 VNET 创建虚拟网络链接。 请注意,已为存储帐户的专用终结点的 VNET 自动创建虚拟网络链接。

显示 FQDN 由公共 IP 地址解析的屏幕截图。

若要创建虚拟网络链接,请执行以下步骤:

  1. 访问私人 DNS区域,然后选择“添加虚拟网络链接>”。

    屏幕截图显示了已添加到存储帐户的虚拟网络链接。

  2. 填写字段,然后选择虚拟网络的 AKS 群集的 VNET。 若要了解如何识别 AKS 群集的 VNET,请参阅解决方案:允许存储帐户使用 AKS 的 VNET 和子网部分。

    屏幕截图显示了如何添加虚拟网络链接。

  3. 选择“确定”

添加虚拟网络链接后,FQDN 应该会通过专用 IP 地址解析,并且装载操作应会成功。 有关示例,请参阅以下屏幕截图:

屏幕截图显示已解析专用 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。 请参阅以下示例:

support-cifs-aes-256-gcm.yaml

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 反馈社区