無法將映像從 Azure Container Registry 提取至 Azure Kubernetes Service 叢集
注意
本篇文章實用嗎? 您的輸入對我們很重要。 請使用此頁面上的 [ 意見反應 ] 按鈕,讓我們知道這篇文章為您運作得有多好,或我們如何加以改善。
當您搭配 Azure Kubernetes Service (AKS) 使用 Microsoft Azure Container Registry 時,必須建立驗證機制。 您可以使用幾個簡單的 Azure CLI 或 Azure PowerShell 命令來設定 AKS 至 Container Registry 整合。 此整合會 為與 AKS 叢集相關聯的 kubelet 身分識別指派 AcrPull 角色 ,以從容器登錄提取映像。
在某些情況下,嘗試將映像從容器登錄提取到AKS叢集失敗。 本文提供將映像從容器登錄提取至 AKS 叢集時所遇到的最常見錯誤的疑難解答指引。
開始之前
本文假設您有現有的 AKS 叢集和現有的容器登錄。 請參閱下列快速入門:
如果您需要 AKS 叢集,請使用 Azure CLI 或 Azure 入口網站 來部署一個叢集。
如果您需要 Azure Container Registry (ACR),請使用 Azure CLI 或 Azure 入口網站 建立一個。
您也需要安裝及設定 Azure CLI 2.0.59 版或更新版本。 執行 az version 以判斷版本。 如果您必須安裝或升級,請參閱 安裝 Azure CLI。
徵兆和初始疑難解答
Kubernetes Pod 的狀態為 ImagePullBackOff 或 ErrImagePull。 若要取得詳細的錯誤資訊,請執行下列命令,並從輸出中檢查 事件 。
kubectl describe pod <podname> -n <namespace>
建議您先檢查 容器登錄的健康 情況,並檢查容器登錄是否可從 AKS 叢集存取容器登錄,以開始進行疑難解答。
若要檢查容器登錄的健康情況,請執行下列命令:
az acr check-health --name <myregistry> --ignore-errors --yes
若偵測到問題,便會提供錯誤碼和描述。 如需錯誤和可能解決方案的詳細資訊,請參閱 健康情況檢查錯誤參考。
注意
如果您收到 Helm 相關或 Notary 相關錯誤,這並不表示問題會影響 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 token: 未預期狀態: 401 未經授權<<
數個解決方案可協助您解決此錯誤,但受限於下列條件約束:
解決方案 1、2、3 和 4 適用於在 AKS 身分識別的 Container Registry 層級建立角色指派的 Azure 方法。
解決方案 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 app credential list --id "SP_ID" --query "[].endDateTime" --output tsv
如需詳細資訊,請參閱 檢查服務主體的到期日。
如果密碼已過期, 請更新 AKS 叢集的認證。
解決方案3:確定已將 AcrPull 角色指派給正確的服務主體
在某些情況下,容器登錄角色指派仍然參考舊的服務主體。 例如,當 AKS 叢集的服務主體取代為新的叢集時。 若要確定容器登錄角色指派參考正確的服務主體,請遵循下列步驟:
若要檢查 AKS 叢集所使用的服務主體,請執行下列命令:
az aks show --resource-group <myResourceGroup> \ --name <myAKSCluster> \ --query servicePrincipalProfile.clientId \ --output tsv
若要檢查容器登錄角色指派所參考的服務主體,請執行下列命令:
az role assignment list --scope /subscriptions/<subscriptionID>/resourceGroups/<resourcegroupname>/providers/Microsoft.ContainerRegistry/registries/<acrname> -o table
比較兩個服務主體。 如果不符合,請再次整合 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 秘密是使用服務主體的值所建立,請確定相關聯的服務主體正確且秘密仍然有效。 執行下列步驟:
執行下列 kubectl get 和 base64 命令來查看 Kubernetes 秘密的值:
kubectl get secret <secret-name> --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
執行下列 az ad sp credential list 命令來檢查到期日。 用戶名稱是服務主體值。
az ad sp credential list --id "<username>" --query "[].endDate" --output tsv
如有必要,請執行下列 az ad sp credential reset 命令來重設該服務主體的秘密:
az ad sp credential reset --name "$SP_ID" --query password --output tsv
據以更新或重新建立 Kubernetes 秘密。
解決方案 6:確定 Kubernetes 秘密具有容器登錄管理員帳戶的正確值
如果您使用映像提取密碼來提取映像,而且 Kubernetes 秘密是使用容器登錄管理員帳戶的值所建立,請確定 Kubernetes 秘密中的值與容器登錄管理員帳戶的值相同。 執行下列步驟:
執行下列 kubectl get 和 base64 命令來查看 Kubernetes 秘密的值:
kubectl get secret <secret-name> --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
在 Azure 入口網站 中,搜尋並選取 [容器登錄]。
在容器登錄清單中,選取您的容器登錄。
在容器登錄的瀏覽窗格中,選取 [存取金鑰]。
在容器登錄的 [ 存取金鑰 ] 頁面中,比較容器登錄值與 Kubernetes 秘密中的值。
如果值不相符,請據以更新或重新建立 Kubernetes 秘密。
注意
如果發生重新產生密碼作業,名為 「重新產生容器登錄登入認證」的作業將會顯示在容器登錄的活動記錄頁面中。 活動 記錄 具有 90天的保留期間。
原因 2:找不到影像錯誤
無法提取映射 “acrname.azurecr.io/< repository:tag>”: [rpc error: code = NotFound desc = failed to pull and unpack image “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 錯誤: code = Unknown desc = failed to pull and unpack image “acrname.azurecr.io/> repository:tag>”: 無法解析參考 “<<acrname.azurecr.io/>><< repository:tag>”: 無法授權: 無法擷取匿名令牌: 未預期狀態: 403 禁止<<
解決方案 1:確定容器登錄 私用 DNS 區域中已設定 AKS 虛擬網路連結
如果容器登錄的私人端點和 AKS 叢集的網路介面位於不同的虛擬網路中,請確定 AKS 叢集虛擬網路的虛擬網路連結是在容器登錄的 私用 DNS 區域中設定。 (預設會將該連結命名為 “privatelink.azurecr.io”。如果虛擬網路連結不在容器登錄的 私用 DNS 區域中,請使用下列其中一種方式加以新增:
在 Azure 入口網站 中,選取私人 DNS 區域 「privatelink.azurecr.io」,選取 [設定] 面板下的 [新增虛擬網路連結>],然後選取 AKS 叢集的名稱和虛擬網路。 選取 [確定]。
注意
選取 [啟用自動註冊] 功能是選擇性的。
使用 Azure CLI 建立指定 私用 DNS 區域的虛擬網路連結。
解決方案 2:將 AKS Load Balancer 的公用 IP 位址新增至容器登錄允許的 IP 位址範圍
如果 AKS 叢集公開連線到容器登錄(不是透過私人連結或端點),且容器登錄的公用網路存取僅限於選取的網路,請將 AKS Load Balancer 的公用 IP 位址新增至容器登錄允許的 IP 位址範圍:
確認公用網路存取僅限於選取的網路。
在 Azure 入口網站 中,流覽至容器登錄。 在 [設定] 底下,選取 [網路]。 在 [公用存取] 索引卷標上,[公用網络存取] 會設定為 [選取的網络] 或 [已停用]。
使用下列其中一種方式取得 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
使用下列其中一種方式,允許從 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 位址新增至 [位址範圍],然後選取 [儲存]。 如需詳細資訊,請參閱 從選取的公用網路存取 - 入口網站。
注意
如果 [公用網络存取 ] 設定為 [已停用],請先將它切換至 [選取的網络 ]。
原因 4:“i/o 逾時錯誤”
無法提取映射 “<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 resolve reference “<<acrname.azurecr.io/> azurecr.io/< repository:tag>”: 無法執行要求:前端 “https:// acrname.azurecr.io/v2/<>< repository>/manifests/v1”: dial tcp <acrprivateipaddress>:443: i/o timeout
注意
只有在您使用 Azure Private Link 私下連線到容器登錄時,才會發生「i/o 逾時」錯誤。
解決方案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 Service (AKS) 叢集節點以進行維護或疑難解答。
解決方案 2:使用 Azure 防火牆 服務
如果容器登錄私人端點和 AKS 叢集的網路介面位於不同的虛擬網路中,除了虛擬網路對等互連之外,您也可以使用 Azure 防火牆 服務在 Azure 中設定中樞輪輻網路拓撲。 當您設定防火牆規則時,必須使用網路規則來明確允許 對容器登錄私人端點 IP 位址的輸出連線 。
原因 5:指令清單中的平台沒有相符專案
主機操作系統 (node 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 意見反應社群提交產品意見反應。