装载 Azure 文件共享时出错

本文提供了导致 Azure 文件共享装载失败的错误的可能原因和解决方案。

症状

可以在 Azure Kubernetes 服务 (AKS) 环境中部署 Kubernetes 资源,例如部署或 StatefulSet。 部署将创建一个 pod,用于装载 PersistentVolumeClaim (PVC) 引用 Azure 文件共享。

但是,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 群集的子网。 在右侧,你将看到路由表。

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

  • 地址前缀: <存储帐户的 s-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 节点池中的节点上计划 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 
    

    SKU 设置为 YAML 文件中Premium_LRS,因为 NFS 需要高级 SKU。 有关详细信息,请参阅 动态预配

    由于高级 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 适用于公共和专用方案。

原因 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 更改为 Running,检查。

    显示当前 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. 选择“确定”。

添加虚拟网络链接后,应通过专用 IP 地址解析 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 加密(SMB 3.1.1) 的最大安全性 (),请执行以下操作:

Linux

如果客户端支持 AES-256-GCM,请使用以下脚本检查,并且仅在客户端支持 AES-256-GCM 时才强制实施它:

cifsConfPath="/etc/modprobe.d/cifs.conf" 
echo "`date` before change ${cifsConfPath}:"
cat ${cifsConfPath}
if !(( grep require_gcm_256 ${cifsConfPath} ))
then
modprobe cifs
echo 1 > /sys/module/cifs/parameters/require_gcm_256
echo "options cifs require_gcm_256=1" > ${cifsConfPath}
echo "`date` after changing ${cifsConfPath}:"
cat ${cifsConfPath}
fi

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) 开始可用。

更多信息

如果遇到其他装载错误,请参阅排查 Linux 中的Azure 文件存储问题

联系我们寻求帮助

如果你有任何疑问或需要帮助,请创建支持请求联系 Azure 社区支持。 还可以向 Azure 反馈社区提交产品反馈。