無法將映像從 Azure Container Registry 提取到叢集 Azure Kubernetes Service

注意事項

本文是否有幫助? 您的輸入對我們很重要。 請使用此頁面上的 [ 意見反應 ] 按鈕,讓我們知道本文如何為您運作,或我們如何加以改善。

當您將 Microsoft Azure Container Registry 與 Azure Kubernetes Service (AKS) 搭配使用時,必須建立驗證機制。 您可以使用一些簡單的 Azure CLI 或 Azure PowerShell 命令來設定 AKS 與 Container Registry 整合。 此整合會為與 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 相關或與通知相關的錯誤,這並不表示您的問題會影響 Container Registry 或 AKS。 它只表示未安裝 Helm 或 Notary,或 Azure CLI 與目前安裝的 Helm 或 Notary 版本不相容,依此類推。

若要驗證是否可從 AKS 叢集存取容器登錄,請執行下列 az aks check-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>”: 無法解析參考 “<acrname.azurecr.io/>< repository:tag>”: 無法授權: 無法擷取 oauth 令牌: 未預期的狀態: 401 未經授權

有數個解決方案可協助您解決此錯誤,但受限於下列條件約束:

解決方案 1:確定已針對身分識別建立 AcrPull 角色指派

AKS 與 Container Registry 之間的整合會針對 AKS 叢集的 kubelet 身分識別,在容器登錄層級建立 AcrPull 角色指派。 請確定已建立角色指派。

若要檢查是否已建立 AcrPull 角色指派,請使用下列其中一種方法:

  • 執行下列命令:

    az role assignment list --scope /subscriptions/<subscriptionID>/resourceGroups/<resourcegroupname>/providers/Microsoft.ContainerRegistry/registries/<acrname> -o table
    
  • 選取 [Azure Container Registry][訪問控制] (>[IAM ) 角色指派],以簽入 Azure 入口網站>。 如需詳細資訊,請參閱使用 Azure 入口網站 列出 Azure 角色指派

除了 AcrPull 角色之外,某些 內建角色自定義角色 也可以包含 “Microsoft.ContainerRegistry/registries/pull/read” 動作。 如果您有任何角色,請檢查這些角色。

如果未建立 AcrPull 角色指派,請使用下列命令設定 AKS 叢集的 Container Registry 整合 來建立它:

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 層級指派。 如果 kubelet 身分識別從 AKS VMSS 中移除,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 = 無法提取及解壓縮影像 “<acrname.azurecr.io/>< repository:tag>”: 無法解析參考 “<acrname.azurecr.io/>< repository:tag>”: 無法授權: 無法擷取匿名令牌: 未預期的狀態: 403 禁止

如果容器登錄的私人端點和 AKS 叢集的網路介面位於不同的虛擬網路中,請確定 AKS 叢集虛擬網路的虛擬網路連結已在容器登錄的 私用 DNS 區域中設定。 (預設會將該連結命名為 「privatelink.azurecr.io」。。) 如果虛擬網路連結不在容器登錄的 私用 DNS 區域中,請使用下列其中一種方式加以新增:

解決方案 2:將 AKS Load Balancer 的公用 IP 位址新增至容器登錄的允許 IP 位址範圍

如果 AKS 叢集透過私人連結或端點) 公開連線到容器登錄 (NOT,且容器登錄的公用網路存取僅限於選取的網路,請將 AKS Load Balancer 的公用 IP 位址新增至容器登錄的允許 IP 位址範圍:

  1. 確認公用網路存取僅限於選取的網路。

    在 Azure 入口網站 中,流覽至容器登錄。 在 [ 設定] 下,選取 [ 網络]。 在 [ 公用存取] 索引 卷標上, [公用網络存取] 會設定為 [ 選取的網络] 或 [ 已停用]

  2. 使用下列其中一種方式取得 AKS Load Balancer 的公用 IP 位址:

    • 在 Azure 入口網站 中,流覽至 AKS 叢集。 在 [設定] 下,選取 [屬性],選取基礎結構資源群組中的其中一個虛擬機擴展集,然後檢查 AKS Load Balancer 的公用IP 位址。

    • 執行下列命令:

      az network public-ip show --resource-group <infrastructure-resource-group> --name <public-IP-name> --query ipAddress -o tsv
      
  3. 使用下列其中一種方式,允許從 AKS Load Balancer 的公用 IP 位址進行存取:

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

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

      如需詳細資訊,請 參閱將網路規則新增至登錄

    • 在 Azure 入口網站 中,流覽至容器登錄。 在 [ 設定] 下,選取 [ 網络]。 在 [公用存取] 索引卷標的 [防火牆] 底下,將 AKS Load Balancer 的公用 IP 位址新增至 [位址範圍],然後選取 [儲存]。 如需詳細資訊,請參 閱從選取的公用網路存取 - 入口網站

      注意事項

      如果 [公用網络存取] 設定為 [ 已停用],請先將它切換至 [選取的網络]

      如何將 AKS Load Balancer 公用 IP 位址新增至位址範圍的螢幕快照

原因 4:443 逾時錯誤

無法提取影像 “<acrname.azurecr.io/>< repository:tag>”: rpc error: code = Unknown desc = failed to pull and unpack image “<acrname.azurecr.io/>< repository:tag>”: 無法解析參考 “<acrname.azurecr.io/<> repository:tag>”: 無法執行要求:head “https://< acrname.azurecr.io/v2/>< repository>/manifests/v1”: dial tcp <acrprivateipaddress>:443: i/o timeout

注意事項

只有當您使用 Azure Private Link 私下連線到容器登錄時,才會發生「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 層級容器登錄的連線能力。 使用 命令檢查 IP 位址 nslookup <acrname>.azurecr.io ,然後執行 telnet <ip-address-of-the-container-registry> 443 命令。

如需連線到 AKS 節點的詳細資訊,請參閱使用 SSH 連線以 Azure Kubernetes Service (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 community 支援。 您也可以將產品意見反應提交給 Azure 意應見反社群