无法将映像从Azure 容器注册表拉取到群集Azure Kubernetes 服务

注意

本文是否有帮助? 你的输入对我们很重要。 请使用此页面上的 “反馈 ”按钮,让我们了解本文对你的影响,或者我们如何改进它。

将 Microsoft Azure 容器注册表 与 Azure Kubernetes 服务 (AKS) 结合使用时,必须建立身份验证机制。 可以使用一些简单的 Azure CLI 或Azure PowerShell命令来设置 AKS 到容器注册表的集成。 此集成为与 AKS 群集关联的 kubelet 标识分配 AcrPull 角色 ,以从容器注册表拉取映像。

在某些情况下,尝试将映像从容器注册表拉取到 AKS 群集失败。 本文提供有关排查将映像从容器注册表拉取到 AKS 群集时遇到的最常见错误的指南。

开始之前

本文假定你已有一个 AKS 群集和一个现有的容器注册表。 请参阅以下快速入门:

还需要安装和配置 Azure CLI 2.0.59 或更高版本。 运行 az version 以确定版本。 如果必须安装或升级,请参阅 安装 Azure CLI

症状和初始故障排除

Kubernetes Pod 的 STATUSImagePullBackOffErrImagePull。 若要获取详细的错误信息,请运行以下命令并从输出检查事件

kubectl describe pod <podname> -n <namespace>

建议通过检查 容器注册表的运行状况 并检查是否可以从 AKS 群集访问容器注册表来开始进行故障排除。

若要检查容器注册表的运行状况,请运行以下命令:

az acr check-health --name <myregistry> --ignore-errors --yes

如果检测到问题,它将提供错误代码和说明。 有关错误和可能的解决方案的详细信息,请参阅运行状况检查错误参考

注意

如果收到与 Helm 相关的错误或与公证相关的错误,并不意味着问题正在影响容器注册表或 AKS。 它仅指示未安装 Helm 或 Notary,或者 Azure CLI 与当前安装的 Helm 或 Notary 版本不兼容,等等。

若要验证是否可以从 AKS 群集访问容器注册表,请运行以下 az aks 检查-acr 命令:

az aks check-acr --resource-group <MyResourceGroup> --name <MyManagedCluster> --acr <myacr>.azurecr.io

以下部分可帮助你排查命令输出kubectl describe pod中的“事件”中显示的最常见错误。

原因 1:401 未授权错误

AKS 群集需要标识。 此标识可以是托管标识或服务主体。 如果 AKS 群集使用托管标识,则 kubelet 标识用于通过 ACR 进行身份验证。 如果 AKS 群集使用服务主体作为标识,则服务主体本身用于对 ACR 进行身份验证。 无论标识是什么,都需要用于从容器注册表拉取映像的适当授权。 否则,可能会收到以下“401 未授权”错误:

未能拉取映像“<acrname.azurecr.io/>< repository:tag>”: [rpc error: code = Unknown desc = failed to pull and unpack image “<acrname.azurecr.io/>< repository:tag>”: failed to resolve reference “<acrname.azurecr.io/<> repository:tag>”: failed to authorize: failed: failed to fetch oauth token: unexpected status: 401 Unauthorized

根据以下约束,多种解决方案可帮助你解决此错误:

解决方案 1:确保为标识创建了 AcrPull 角色分配

AKS 与容器注册表之间的集成为 AKS 群集的 kubelet 标识在容器注册表级别创建 AcrPull 角色分配。 请确保已创建角色分配。

若要检查是否创建了 AcrPull 角色分配,请使用以下方法之一:

  • 运行以下命令:

    az role assignment list --scope /subscriptions/<subscriptionID>/resourceGroups/<resourcegroupname>/providers/Microsoft.ContainerRegistry/registries/<acrname> -o table
    
  • 通过选择“Azure 容器注册表>Access 控件 (IAM) 角色分配”来签入Azure 门户>。 有关详细信息,请参阅使用 Azure 门户列出 Azure 角色分配

除了 AcrPull 角色,某些 内置角色自定义角色 还可以包含“Microsoft.ContainerRegistry/registries/pull/read”操作。 如果有这些角色,请检查这些角色。

如果未创建 AcrPull 角色分配,请使用以下命令 为 AKS 群集配置容器注册表集成 来创建它:

az aks update -n <myAKSCluster> -g <myResourceGroup> --attach-acr <acr-resource-id>

解决方案 2:确保服务主体未过期

确保与 AKS 群集关联的服务主体的机密未过期。 若要检查服务主体的到期日期,请运行以下命令:

SP_ID=$(az aks show --resource-group <myResourceGroup> --name <myAKSCluster> \
    --query servicePrincipalProfile.clientId -o tsv)

az ad sp credential list --id "$SP_ID" --query "[].endDate" -o tsv

有关详细信息,请参阅 检查服务主体的到期日期

如果机密已过期, 请更新 AKS 群集的凭据

解决方案 3:确保将 AcrPull 角色分配给正确的服务主体

在某些情况下,容器注册表角色分配仍引用旧的服务主体。 例如,当 AKS 群集的服务主体替换为新群集时。 若要确保容器注册表角色分配引用正确的服务主体,请执行以下步骤:

  1. 若要检查 AKS 群集所使用的服务主体,请运行以下命令:

    az aks show --resource-group <myResourceGroup> \
        --name <myAKSCluster> \
        --query servicePrincipalProfile.clientId \
        --output tsv
    
  2. 若要检查容器注册表角色分配引用的服务主体,请运行以下命令:

    az role assignment list --scope /subscriptions/<subscriptionID>/resourceGroups/<resourcegroupname>/providers/Microsoft.ContainerRegistry/registries/<acrname> -o table
    
  3. 比较这两个服务主体。 如果不匹配,请再次将 AKS 群集与容器注册表集成。

解决方案 4:确保在 AKS VMSS 中引用 kubelet 标识

使用托管标识通过 ACR 进行身份验证时,托管标识称为 kubelet 标识。 默认情况下,kubelet 标识在 AKS VMSS 级别分配。 如果从 AKS VMSS 中删除 kubelet 标识,则 AKS 节点无法从 ACR 拉取映像。

若要查找 AKS 群集的 kubelet 标识,请运行以下命令:

az aks show --resource-group <MyResourceGroup> --name <MyManagedCluster> --query identityProfile.kubeletidentity

然后,可以通过从节点资源组打开 VMSS 并选择在 Azure 门户中分配标识>用户,或者运行以下命令来列出 AKS VMSS 的标识:

az vmss identity show --resource-group <NodeResourceGroup> --name <AksVmssName>

如果 AKS 群集的 kubelet 标识未分配给 AKS VMSS,请重新分配它。

注意

不支持使用 IaaS API 或从Azure 门户修改 AKS VMSS,并且任何 AKS 操作都无法从 AKS VMSS 中删除 kubelet 标识。 这意味着意外删除了它,例如,由团队成员执行的手动删除。 若要防止此类删除或修改,可以考虑使用 NRGLockdown 功能

由于不支持对 AKS VMSS 的修改,因此它们不会在 AKS 级别传播。 若要将 kubelet 标识重新分配到 AKS VMSS,需要执行对帐操作。 为此,请运行下列命令:

az aks update --resource-group <MyResourceGroup> --name <MyManagedCluster>

解决方案 5:确保服务主体正确且机密有效

如果使用映像 拉取机密拉取映像,并且 Kubernetes 机密是使用服务主体的值创建的,请确保关联的服务主体正确且机密仍然有效。 请按照下列步骤操作:

  1. 运行以下 kubectl getbase64 命令以查看 Kubernetes 机密的值:

    kubectl get secret <secret-name> --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
    
  2. 通过运行以下 az ad sp credential list 命令来检查到期日期。 用户名是服务主体值。

    az ad sp credential list --id "<username>" --query "[].endDate" --output tsv
    
  3. 如有必要,请运行以下 az ad sp credential reset 命令来重置该服务主体的机密:

    az ad sp credential reset --name "$SP_ID" --query password --output tsv
    
  4. 相应地更新或重新创建 Kubernetes 机密。

解决方案 6:确保 Kubernetes 机密具有容器注册表管理员帐户的正确值

如果使用映像 拉取机密拉取映像,并且 Kubernetes 机密是使用 容器注册表管理员帐户的值创建的,请确保 Kubernetes 机密中的值与容器注册表管理员帐户的值相同。 请按照下列步骤操作:

  1. 运行以下 kubectl getbase64 命令以查看 Kubernetes 机密的值:

    kubectl get secret <secret-name> --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
    
  2. Azure 门户中,搜索并选择“容器注册表”。

  3. 在容器注册表列表中,选择容器注册表。

  4. 在容器注册表的导航窗格中,选择“ 访问密钥”。

  5. 在容器注册表的 “访问密钥 ”页中,将容器注册表值与 Kubernetes 机密中的值进行比较。

  6. 如果值不匹配,请相应地更新或重新创建 Kubernetes 机密。

注意

如果发生 “重新生成 密码”操作,则名为“重新生成容器注册表登录凭据”的操作将显示在容器注册表 的“活动日志 ”页中。 活动日志保留期为 90 天

原因 2:找不到图像错误

无法拉取映像“<acrname.azurecr.io/>< repository:tag>”: [rpc error: code = NotFound desc = 未能拉取和解压缩映像“<acrname.azurecr.io/>< repository:tag>”: 无法解析引用“<acrname.azurecr.io/>< repository:tag>”: <acrname.azurecr.io/>< repository:tag>: 未找到

解决方案:确保映像名称正确

如果看到此错误,请确保映像名称完全正确。 应检查注册表名称、注册表登录服务器、存储库名称和标记。 一个常见错误是,登录服务器被指定为“azureacr.io”而不是“azurecr.io”。

如果映像名称不正确,则 401 未授权错误 也可能发生,因为无论容器注册表是否启用了匿名拉取访问,AKS 始终尝试匿名拉取。

原因 3:403 禁止访问错误

无法拉取映像“<acrname.azurecr.io/>< repository:tag>”: rpc error: code = Unknown desc = failed to pull and unpack image “<acrname.azurecr.io/>< repository:tag>”: failed to resolve reference “<acrname.azurecr.io/<> repository:tag>”: failed to authorize: failed: failed to fetch anonymous token: unexpected status: 403 Forbidden

如果容器注册表的专用终结点和 AKS 群集的网络接口位于不同的虚拟网络中,请确保在容器注册表的 专用 DNS 区域中设置了 AKS 群集虚拟网络的虚拟网络链接。 (默认情况下,该链接名为“privatelink.azurecr.io”。) 如果虚拟网络链接不在容器注册表的专用 DNS区域中,请使用以下方法之一添加它:

解决方案 2:将 AKS 负载均衡器的公共 IP 地址添加到容器注册表允许的 IP 地址范围

如果 AKS 群集 (非通过专用链接或终结点) 公开连接到容器注册表,并且容器注册表的公用网络访问仅限于所选网络,请将 AKS 负载均衡器的公共 IP 地址添加到容器注册表允许的 IP 地址范围:

  1. 验证公用网络访问是否仅限于所选网络。

    在Azure 门户中,导航到容器注册表。 在 “设置”下,选择“ 网络”。 在“ 公共访问 ”选项卡上, “公用网络访问 ”设置为 “所选网络”“已禁用”。

  2. 使用以下方法之一获取 AKS 负载均衡器的公共 IP 地址:

    • 在Azure 门户中,导航到 AKS 群集。 在“设置”下,选择“属性”,在基础结构资源组中选择一个虚拟机规模集,检查 AKS 负载均衡器的公共 IP 地址。

    • 运行以下命令:

      az network public-ip show --resource-group <infrastructure-resource-group> --name <public-IP-name> --query ipAddress -o tsv
      
  3. 使用以下方法之一,允许从 AKS 负载均衡器的公共 IP 地址进行访问:

    • 运行 az acr network-rule add 命令,如下所示:

      az acr network-rule add --name acrname --ip-address <AKS-load-balancer-public-IP-address>
      

      有关详细信息,请参阅 将网络规则添加到注册表

    • 在Azure 门户中,导航到容器注册表。 在 “设置”下,选择“ 网络”。 在“公共访问”选项卡上的“防火墙”下,将 AKS 负载均衡器的公共 IP 地址添加到“地址范围”,然后选择“保存”。 有关详细信息,请参阅 从所选公用网络 - 门户访问

      注意

      如果 “公用网络访问 ”设置为 “已禁用”,请首先将其切换到 “所选网络 ”。

      有关如何将 AKS 负载均衡器的公共 IP 地址添加到地址范围的屏幕截图

原因 4:443 超时错误

无法拉取映像“<acrname.azurecr.io/>< repository:tag>”: rpc 错误: 代码 = 未知 desc = 无法拉取和解压缩映像“<acrname.azurecr.io/<> repository:tag>”: 无法解析引用“<acrname.azurecr.io/> 请求>失败:<头”https://< acrname.azurecr.io/v2/<> repository>/manifests/v1“: dial tcp <acrprivateipaddress>:443: i/o timeout

注意

仅当使用 Azure 专用链接 以私密方式连接到容器注册表时,才会发生“443 超时”错误。

解决方案 1:确保使用虚拟网络对等互连

如果容器注册表的专用终结点和 AKS 群集的网络接口位于不同的虚拟网络中,请确保这两个虚拟网络都使用 虚拟网络对等互连 。 可以通过运行 Azure CLI 命令az network vnet peering list --resource-group <MyResourceGroup> --vnet-name <MyVirtualNetwork> --output table或在Azure 门户中通过选择“设置”面板下的 VNET>对等互连来检查虚拟网络对等互连。 有关列出指定虚拟网络的所有对等互连的详细信息,请参阅 az network vnet peering list

如果两个虚拟网络都使用虚拟网络对等互连,请确保状态为“已连接”。 如果状态为 “已断开连接”,请从两个虚拟网络中删除对等互连,然后重新创建它。 如果状态为“已连接”,请参阅故障排除指南:对等互连状态为“已连接”。

若要进一步进行故障排除,请连接到其中一个 AKS 节点或 Pod,然后使用 Telnet 或 Netcat 实用工具在 TCP 级别测试与容器注册表的连接。 使用 nslookup <acrname>.azurecr.io 命令检查 IP 地址,然后运行 命令 telnet <ip-address-of-the-container-registry> 443

有关连接到 AKS 节点的详细信息,请参阅使用 SSH 连接到 Azure Kubernetes 服务 (AKS) 群集节点进行维护或故障排除

解决方案 2:使用 Azure 防火墙 服务

如果容器注册表的专用终结点和 AKS 群集的网络接口位于不同的虚拟网络中,则除了虚拟网络对等互连外,还可以使用 Azure 防火墙 服务在 Azure 中设置中心辐射型网络拓扑。 设置防火墙规则时,需要使用网络规则显式允许到容器注册表专用终结点 IP 地址的 出站连接

原因 5:清单中平台没有匹配项

主机操作系统 (节点 OS) 与用于 Pod 或容器的映像不兼容。 例如,如果计划 Pod 以在 Windows 节点上运行 Linux 容器,或在 Linux 节点上运行 Windows 容器,则会发生以下错误:

无法拉取映像“<acrname.azurecr.io/>< repository:tag>”:
[
  rpc 错误:
  code = NotFound
  desc = 无法拉取和解压缩映像“<acrname.azurecr.io/>< repository:tag>”:清单中没有平台匹配项:找不到,
]

只要映像与主机 OS 不兼容,从任何源拉取的映像都可能发生此错误。 此错误不限于从容器注册表拉取的映像。

解决方案:在 Pod 或部署中正确配置 nodeSelector 字段

在 Pod 或部署的配置设置中指定正确的 nodeSelector 字段。 此字段 kubernetes.io/os 设置的正确值可确保在正确的节点类型上计划 Pod。 下表显示了如何在 YAML 中设置 kubernetes.io/os 设置:

容器类型 YAML 设置
Linux 容器 "kubernetes.io/os": linux
Windows 容器 "kubernetes.io/os": windows

例如,以下 YAML 代码描述需要在 Linux 节点上计划的 Pod:

apiVersion: v1
kind: Pod
metadata:
  name: aspnetapp
  labels:
    app: aspnetapp
spec:
  containers:
  - image: "mcr.microsoft.com/dotnet/core/samples:aspnetapp"
    name: aspnetapp-image
    ports:
    - containerPort: 80
      protocol: TCP
  nodeSelector:
    "kubernetes.io/os": linux

更多信息

如果本文中的故障排除指南无法帮助你解决问题,请考虑以下其他事项:

  • 如果具有其中任何项,请检查与子网关联的网络安全组和路由表。

  • 如果虚拟设备(如防火墙)控制子网之间的流量,检查防火墙和防火墙访问规则

第三方信息免责声明

本文中提到的第三方产品由 Microsoft 以外的其他公司提供。 Microsoft 不对这些产品的性能或可靠性提供任何明示或暗示性担保。

联系我们寻求帮助

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