映像为何无法从注册表中拉取,出现 ImagePullBackOff 或授权错误?

虚拟私有云 传统基础设施

部署用于从 IBM Cloud Container Registry 拉取映像的工作负载时,pod 失败,并显示 ImagePullBackOff 状态。

oc get pods
NAME         READY     STATUS             RESTARTS   AGE
<pod_name>   0/1       ImagePullBackOff   0          2m

描述 pod 时,您会看到类似于以下内容的认证错误。

oc describe pod <pod_name>
Failed to pull image "<region>.icr.io/<namespace>/<image>:<tag>" ... unauthorized: authentication required
Failed to pull image "<region>.icr.io/<namespace>/<image>:<tag>" ... 401 Unauthorized
...
Failed to pull image "<image>:<tag>" ... Manifest for <image>:<tag> not found

您的群集使用存储在 图像拉伸秘密 中的 API 密钥授权群集从 IBM Cloud Container Registry 中提取图片,或者带有特定标签的图片不存在于资源库中。

默认情况下,新集群的镜像拉取密钥会使用 API 密钥,以便集群能够从任何区域的 icr.io 注册表中拉取镜像,供部署到 default Red Hat OpenShift 项目的容器使用。

  1. 验证在部署 YAML 文件中使用的映像的名称和标记是否正确。

    ibmcloud cr images
    
  2. 检查拉取流量和存储配额。 如果达到限制,请释放已使用的存储器,或者请求注册表管理员增加配额。

    ibmcloud cr quota
    
  3. 获取失败的 pod 的 pod 配置文件,然后查找 imagePullSecrets 部分。

    oc get pod <pod_name> -o yaml
    

    示例输出

    ...
    imagePullSecrets:
    - name: all-icr-io
    ...
    
  4. 如果未列出任何镜像拉取密钥,请在您的项目中设置镜像拉取密钥。

    1. 请确认 default 项目中是否为每个您打算使用的区域注册表配置了 icr-io 镜像拉取密钥。 如果项目中未列出任何 icr-io 密钥, 请使用 ibmcloud oc cluster pull-secret apply --cluster <cluster_name_or_ID> 命令在 default 项目中创建镜像拉取密钥。
      oc get secrets -n default | grep "icr-io"
      
    2. 将 all-icr-io 映像拉取私钥从 default Red Hat OpenShift 项目复制到要在其中部署工作负载的项目。
    3. 将镜像拉取密钥添加到此 Red Hat OpenShift 项目的服务账户中,以便该项目中的所有 Pod 都能使用该镜像拉取密钥的凭据。
  5. 如果 pod 中列出了映像拉取私钥,请确定用于访问 IBM Cloud Container Registry 的凭证类型。

使用 API 密钥的图像拉取密钥故障排除

如果 pod 配置具有使用 API 密钥的映像拉取私钥,请检查是否正确设置了 API 密钥凭证。

以下步骤假定 API 密钥存储服务标识的凭证。 如果将映像拉取私钥设置为使用单个用户的 API 密钥,那么必须验证该用户的 IBM Cloud IAM 许可权和凭证。

  1. 通过查看 Description 来查找 API 密钥用于映像拉取私钥的服务标识。 随集群创建的服务 ID 名为 cluster-<cluster_ID>,并在 default Red Hat OpenShift 项目中使用。 如果您创建了另一个服务 ID(例如,用于访问另一个 Red Hat OpenShift 项目或修改 IBM Cloud 的 IAM 权限),则您已自定义了该描述。

    ibmcloud iam service-ids
    

    示例输出

    UUID                Name               Created At              Last Updated            Description                                                                                                                                                                                         Locked
    ServiceId-aa11...   <service_ID_name>  2019-02-01T19:01+0000   2019-02-01T19:01+0000   ID for <cluster_name>                                                                                                                                         false
    ServiceId-bb22...   <service_ID_name>  2019-02-01T19:01+0000   2019-02-01T19:01+0000   Service ID for IBM Cloud Container Registry in Kubernetes cluster <cluster_name> namespace <project>                                                                                                                                         false
    
  2. 请确认该服务 ID 至少被分配了一个 IBM Cloud IAM 阅读器 服务访问角色策略用于 IBM Cloud Container Registry。 如果服务 ID 没有 “Reader” 服务访问角色,请编辑 IAM 策略。 如果策略正确,请继续执行下一步以查看凭证是否有效。

    ibmcloud iam service-policies <service_ID_name>
    

    示例输出

    Policy ID:   a111a111-b22b-333c-d4dd-e555555555e5
    Roles:       Reader
    Resources:
                  Service Name       container-registry
                  Service Instance
                  Region
                  Resource Type      namespace
                  Resource           <registry_namespace>
    
  3. 检查映像拉取私钥凭证是否有效。

    1. 获取映像拉取私钥配置。 如果该 Pod 不属于 default 项目,请添加 -n 选项。

      oc get secret <image_pull_secret_name> -o yaml [-n <project>]
      
    2. 在输出中,复制 .dockerconfigjson 字段的 Base64 编码值。

      apiVersion: v1
      kind: Secret
      data:
        .dockerconfigjson: eyJyZWdp...==
      ...
      
    3. 对 Base64 字符串解码。 例如,在 OS X 上,可以运行以下命令。

      echo -n "<base64_string>" | base64 --decode
      

      示例输出

      {"auths":{"<region>.icr.io":{"username":"iamapikey","password":"<password_string>","email":"<name@abc.com>","auth":"<auth_string>"}}}
      
    4. 将映像拉取私钥区域注册表域名与在容器映像中指定的域名进行比较。 默认情况下,新创建的集群会为运行在 default Red Hat OpenShift 项目中的容器,针对每个区域注册表域名配置相应的镜像拉取密钥。 但是,如果您修改了默认设置,或者正在使用其他 Red Hat OpenShift 项目,那么您可能没有针对区域注册表的镜像拉取密钥。 请复制映像拉取私钥,即区域注册表域名的映像拉取私钥。

    5. 使用映像拉取私钥中的 username 和 password 从本地计算机登录到注册表。 如果您无法登录,可能需要修复服务 ID。

      docker login -u iamapikey -p <password_string> <region>.icr.io
      
      1. 为在 default Red Hat OpenShift 项目中运行的容器,重新创建集群服务 ID、IBM Cloud IAM 策略、API 密钥以及镜像拉取密钥。
        ibmcloud oc cluster pull-secret apply --cluster <cluster_name_or_ID>
        
      2. 在 default Red Hat OpenShift 项目中重新创建您的部署。 如果仍看到授权错误消息,请使用新映像拉取私钥重复步骤 1-5。 如果仍无法登录,请 打开 IBM Cloud 支持案例。
    6. 如果登录成功,请在本地拉取映像。 如果命令失败并返回 access denied 错误,说明注册表帐户与集群不在同一 IBM Cloud 帐户中。 请创建映像拉取私钥以访问其他帐户中的映像。 如果你能将图片下载到本地机器上,说明你的 API 密钥权限正确,但集群中的 API 配置有误。

      docker pull <region>icr.io/<namespace>/<image>:<tag>
      
    7. 请检查是否直接从部署或从部署使用的服务帐户引用了拉取私钥。 如果仍无法解决问题,请 联系支持人员。