# 工作负载异常：实例拉取镜像失败
#### 问题定位
当工作负载状态显示"实例未就绪：Back-off pulling image "xxxxx""，该状态下工作负载实例K8s事件名称为"实例拉取镜像失败"或"重新拉取镜像失败"。查看K8s事件的方法请参见[查看Pod事件](https://support.huaweicloud.com/cce_faq/cce_faq_00134.html#cce_faq_00134__section13566155892120)。
#### 排查思路
根据具体事件信息确定具体问题原因，如[表1]所示。
 表1实例拉取镜像失败 
| 事件信息                                                                                                                                                                                                                                                                            | 问题原因与解决方案                                                                                                                                                                                                        |
|:---|:---|
| Failed to pull image "xxx": rpc error: code = Unknown desc = Error response from daemon: Get xxx: denied: You may not login yet                                                                                                                                                  | 没有登录镜像仓库，无法拉取镜像。 [排查项一：kubectl创建工作负载时未指定imagePullSecret]                                                                                       |
| Failed to pull image "nginx:v1.1": rpc error: code = Unknown desc = Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: no such host                                                                                          | 镜像地址配置有误找不到镜像导致失败。 [排查项二：填写的镜像地址错误（使用第三方镜像时）] [排查项三：使用错误的密钥（使用第三方镜像时）] |
| Failed create pod sandbox: rpc error: code = Unknown desc = failed to create a sandbox for pod "nginx-6dc48bf8b6-l8xrw": Error response from daemon: mkdir xxxxx: no space left on device                                                                                       | 磁盘空间不足。 [排查项四：节点磁盘空间不足]                                                                                                                        |
| Failed to pull image "xxx": rpc error: code = Unknown desc = error pulling image configuration: xxx x509: certificate signed by unknown authority                                                                                                                                | 从第三方仓库下载镜像时，第三方仓库使用了非知名或者不安全的证书. [排查项五： 远程镜像仓库使用非知名或不安全的证书]                                                                                 |
| Failed to pull image "XXX": rpc error: code = Unknown desc = context canceled                                                                                                                                                                                                    | 镜像体积过大。 [排查项六： 镜像过大导致失败]                                                                                                                     |
| Failed to pull image "docker.io/bitnami/nginx:1.22.0-debian-11-r3": rpc error: code = Unknown desc = Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) | [排查项七：无法连接镜像仓库]                                                                                                                                                           |
| ERROR: toomanyrequests: Too Many Requests. 或 you have reached your pull rate limit, you may increase the limit by authenticating an upgrading                                                                     | 由于拉取镜像次数达到上限而被限速。 [排查项八：拉取公共镜像达上限]                                                                                                        |
   
 #### 排查项一：kubectl创建工作负载时未指定imagePullSecret
当工作负载状态异常并显示"实例拉取镜像失败"的K8s事件时，请排查yaml文件中是否存在**imagePullSecrets**字段。
**排查事项：**
- 当Pull SWR容器镜像仓库的镜像时，name参数值需固定为default-secret。
  ```
  apiVersion: extensions/v1beta1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    replicas: 1
    selector:
      matchLabels:
        app: nginx
    strategy:
      type: RollingUpdate
    template:
      metadata:
        labels:
          app: nginx
      spec:
        containers:
        - image: nginx 
          imagePullPolicy: Always
          name: nginx
        imagePullSecrets:
        - name: default-secret
  ```
  
- Pull第三方镜像仓库的镜像时，需设置为创建的secret名称。 kubectl创建工作负载拉取第三方镜像时，需指定的imagePullSecret字段，name表示pull镜像时的secret名称，创建密钥的方法请参见[使用kubectl创建第三方镜像仓库的密钥](https://support.huaweicloud.com/usermanual-cce/cce_10_0009.html#section2)。
  
 
 #### 排查项二：填写的镜像地址错误（使用第三方镜像时）
CCE支持拉取第三方镜像仓库中的镜像来创建工作负载。
在填写第三方镜像的地址时，请参照要求的格式来填写。镜像地址格式为：domainname/organization/imagename:tag，若没标注版本号则默认版本号为latest。
- 若是私有仓库，请填写domainname/organization/imagename:tag。
- 若是docker开源仓库，请填写name:version，例如nginx:latest。
  图1第三方镜像   
  ![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002272948181.png "点击放大")
  
  
镜像地址配置有误找不到镜像导致失败，Kubernetes Event中提示如下信息：
```
Failed to pull image "nginx:v1.1": rpc error: code = Unknown desc = Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: no such host
```
**解决方案：**
可编辑yaml修改镜像地址，也可在工作负载详情页面更新升级页签单击更换镜像。
 #### 排查项三：使用错误的密钥（使用第三方镜像时）
通常第三方镜像仓库都必须经过认证（账号密码）才可以访问，而CCE中容器拉取镜像是使用密钥认证方式，这就要求在拉取镜像前必须先创建镜像仓库的密钥。
**解决方案：**
若您的密钥错误将会导致镜像拉取失败，请重新获取密钥。
创建密钥的方法请参见[使用kubectl创建第三方镜像仓库的密钥](https://support.huaweicloud.com/usermanual-cce/cce_10_0009.html#section2)。
 #### 排查项四：节点磁盘空间不足
当k8s事件中包含以下信息，表明节点上用于存储镜像的磁盘空间已满，会导致重新拉取镜像失败。您可以通过清理镜像或扩容磁盘解决该问题。
```
Failed create pod sandbox: rpc error: code = Unknown desc = failed to create a sandbox for pod "nginx-6dc48bf8b6-l8xrw": Error response from daemon: mkdir xxxxx: no space left on device
```
您可以执行以下命令，确认节点上存储镜像的磁盘空间：
```
lvs
```
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0235257509.jpg "点击放大")
**方案一：清理镜像**
您可以执行以下步骤清理未使用的镜像：
- 使用containerd容器运行时的节点：
  1. 查看节点上的本地镜像。
     ```
     crictl images -v
     ```
     
  
  2. 确认镜像无需使用，并通过镜像ID删除无需使用的镜像。
     ```
     crictl rmi {镜像ID}
     ```
     
   
- 使用docker容器运行时的节点：
  1. 查看节点上的本地镜像。
     ```
     docker images
     ```
     
  
  2. 确认镜像无需使用，并通过镜像ID删除无需使用的镜像。
     ```
     docker rmi {镜像ID}
     ```
     
   
![](https://support.huaweicloud.com/cce_faq/public_sys-resources/note_3.0-zh-cn.png)
请勿删除cce-pause等系统镜像，否则可能导致无法正常创建容器。
**方案二：扩容磁盘**
扩容磁盘的操作步骤如下：
1. 在EVS控制台扩容数据盘。详情请参见[扩容云硬盘容量](https://support.huaweicloud.com/usermanual-evs/evs_01_0007.html)。
   
   在EVS控制台扩容成功后，仅扩大了云硬盘的存储容量，还需要执行后续步骤扩容逻辑卷和文件系统。
   
   
2. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，进入集群，在左侧选择"节点管理"，单击节点后的"同步云服务器"。
3. 登录目标节点。
4. 使用**lsblk** 命令查看节点块设备信息。
   
   这里存在两种情况，根据容器存储Rootfs而不同。
   **Overlayfs：**没有单独划分thinpool，在dockersys空间下统一存储镜像相关数据。
   1. 查看设备的磁盘和分区大小。
      ```
      # lsblk
      NAME                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
      sda                   8:0    0   50G  0 disk 
      └─sda1                8:1    0   50G  0 part /
      sdb                   8:16   0  150G  0 disk      # 数据盘已扩容至150G，存在50G空间仍未分配
      ├─vgpaas-dockersys  253:0    0   90G  0 lvm  /var/lib/containerd
      └─vgpaas-kubernetes 253:1    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
      ```
      
   
   2. 扩容磁盘。 将新增的磁盘容量加到容器运行时使用的dockersys逻辑卷上。
      1. 扩容物理卷PV，让LVM识别EVS新增的容量。其中*/dev/sdb* 为dockersys逻辑卷所在的物理卷。
         ```
         pvresize /dev/sdb
         ```
         回显如下：
         ```
         Physical volume "/dev/sdb" changed
         1 physical volume(s) resized or updated / 0 physical volume(s) not resized
         ```
         
      
      2. 将空闲容量100%扩容到逻辑卷LV。其中*vgpaas/dockersys* 为容器运行时使用的逻辑卷。
         ```
         lvextend -l+100%FREE -n vgpaas/dockersys
         ```
         回显如下：
         ```
         Size of logical volume vgpaas/dockersys changed from <90.00 GiB (23039 extents) to 140.00 GiB (35840 extents).
         Logical volume vgpaas/dockersys successfully resized.
         ```
         
      
      3. 调整文件系统的大小。其中*/dev/vgpaas/dockersys* 为容器运行时的文件系统路径。
         ```
         resize2fs /dev/vgpaas/dockersys
         ```
         回显如下：
         ```
         Filesystem at /dev/vgpaas/dockersys is mounted on /var/lib/containerd; on-line resizing required
         old_desc_blocks = 12, new_desc_blocks = 18
         The filesystem on /dev/vgpaas/dockersys is now 36700160 blocks long.
         ```
         
       
   
   3. 检查是否扩容成功。
      ```
      # lsblk
      NAME                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
      sda                   8:0    0   50G  0 disk 
      └─sda1                8:1    0   50G  0 part /
      sdb                   8:16   0  150G  0 disk
      ├─vgpaas-dockersys  253:0    0   140G  0 lvm  /var/lib/containerd
      └─vgpaas-kubernetes 253:1    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
      ```
      
    
   **Devicemapper：**单独划分了thinpool存储镜像相关数据。
   1. 查看设备的磁盘和分区大小。
      ```
      # lsblk
      NAME                                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
      vda                                   8:0    0   50G  0 disk 
      └─vda1                                8:1    0   50G  0 part /
      vdb                                   8:16   0  200G  0 disk 
      ├─vgpaas-dockersys                  253:0    0   18G  0 lvm  /var/lib/docker    
      ├─vgpaas-thinpool_tmeta             253:1    0    3G  0 lvm                   
      │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm                   # thinpool空间
      │   ...
      ├─vgpaas-thinpool_tdata             253:2    0   67G  0 lvm  
      │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm  
      │   ...
      └─vgpaas-kubernetes                 253:4    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
      ```
      
   
   2. 扩容磁盘。
      **选项一：**将新增的磁盘容量加到thinpool盘上。
      1. 扩容物理卷PV，让LVM识别EVS新增的容量。其中*/dev/vdb* 为thinpool空间所在的物理卷。
         ```
         pvresize /dev/vdb
         ```
         回显如下：
         ```
         Physical volume "/dev/vdb" changed
         1 physical volume(s) resized or updated / 0 physical volume(s) not resized
         ```
         
      
      2. 将空闲容量100%扩容到逻辑卷LV。其中*vgpaas/thinpool* 为容器运行时使用的逻辑卷。
         ```
         lvextend -l+100%FREE -n vgpaas/thinpool
         ```
         回显如下：
         ```
         Size of logical volume vgpaas/thinpool changed from <67.00 GiB (23039 extents) to <167.00 GiB (48639 extents).
         Logical volume vgpaas/thinpool successfully resized.
         ```
         
      
      3. 由于thinpool未挂载到设备，因此无需调整文件系统的大小。
      
      4. 检查是否扩容成功。使用lsblk命令查看设备的磁盘和分区大小，若新增的磁盘容量已经加到thinpool盘，则表示扩容成功。
         ```
         # lsblk
         NAME                                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
         vda                                   8:0    0   50G  0 disk 
         └─vda1                                8:1    0   50G  0 part /
         vdb                                   8:16   0  200G  0 disk 
         ├─vgpaas-dockersys                  253:0    0   18G  0 lvm  /var/lib/docker    
         ├─vgpaas-thinpool_tmeta             253:1    0    3G  0 lvm                   
         │ └─vgpaas-thinpool                 253:3    0   167G  0 lvm             # 扩容后的thinpool空间
         │   ...
         ├─vgpaas-thinpool_tdata             253:2    0   67G  0 lvm  
         │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm  
         │   ...
         └─vgpaas-kubernetes                 253:4    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
         ```
         
       
      **选项二：**将新增的磁盘容量加到dockersys盘上。
      1. 扩容物理卷PV，让LVM识别EVS新增的容量。其中*/dev/vdb* 为dockersys逻辑卷所在的物理卷。
         ```
         pvresize /dev/vdb
         ```
         回显如下：
         ```
         Physical volume "/dev/vdb" changed
         1 physical volume(s) resized or updated / 0 physical volume(s) not resized
         ```
         
      
      2. 将空闲容量100%扩容到逻辑卷LV。其中*vgpaas/dockersys* 为容器运行时使用的逻辑卷。
         ```
         lvextend -l+100%FREE -n vgpaas/dockersys
         ```
         回显如下：
         ```
         Size of logical volume vgpaas/dockersys changed from <18.00 GiB (4607 extents) to <118.00 GiB (30208 extents).
         Logical volume vgpaas/dockersys successfully resized.
         ```
         
      
      3. 调整文件系统的大小。其中*/dev/vgpaas/dockersys* 为容器运行时的文件系统路径。
         ```
         resize2fs /dev/vgpaas/dockersys
         ```
         回显如下：
         ```
         Filesystem at /dev/vgpaas/dockersys is mounted on /var/lib/docker; on-line resizing required
         old_desc_blocks = 3, new_desc_blocks = 15
         The filesystem on /dev/vgpaas/dockersys is now 30932992 blocks long.
         ```
         
      
      4. 检查是否扩容成功。使用lsblk命令查看设备的磁盘和分区大小，若新增的磁盘容量已经加到dockersys盘，则表示扩容成功。
         ```
         # lsblk
         NAME                                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
         vda                                   8:0    0   50G  0 disk 
         └─vda1                                8:1    0   50G  0 part /
         vdb                                   8:16   0  200G  0 disk 
         ├─vgpaas-dockersys                  253:0    0   118G  0 lvm  /var/lib/docker     # 扩容后的dockersys盘
         ├─vgpaas-thinpool_tmeta             253:1    0    3G  0 lvm                   
         │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm             
         │   ...
         ├─vgpaas-thinpool_tdata             253:2    0   67G  0 lvm  
         │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm  
         │   ...
         └─vgpaas-kubernetes                 253:4    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
         ```
         
        
    
   
   
 
 #### 排查项五： 远程镜像仓库使用非知名或不安全的证书
从第三方仓库下载镜像时，若第三方仓库使用了非知名或者不安全的证书，节点上会拉取镜像失败，Pod事件列表中有"实例拉取镜像失败"事件，报错原因为"x509: certificate signed by unknown authority"。
![](https://support.huaweicloud.com/cce_faq/public_sys-resources/note_3.0-zh-cn.png)
当前EulerOS 2.9镜像中有进行安全增强，移除系统中部分非安全或过期知名证书配置，部分第三方镜像在其他类型节点上未报错，在EulerOS 2.9系统报此错误属正常现象，也可通过下述解决方案进行处理。
**解决方案**：
1. 确认报错unknown authority的第三方镜像服务器地址和端口。 
   从"实例拉取镜像失败"事件信息中能够直接看到报错的第三方镜像服务器地址和端口，如上图中错误信息为：
   ```
   Failed to pull image "bitnami/redis-cluster:latest": rpc error: code = Unknown desc = error pulling image configuration: Get https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/e8/e83853f03a2e792614e7c1e6de75d63e2d6d633b4e7c39b9d700792ee50f7b56/data?verify=1636972064-AQbl5RActnudDZV%2F3EShZwnqOe8%3D: x509: certificate signed by unknown authority
   ```
   对应的第三方镜像服务器地址为 *production.cloudflare.docker.com* ，端口为https默认端口*443*。
   
   
2. 在需要下载第三方镜像的节点上加载第三方镜像服务器的根证书。 
   EulerOS, CentOS节点执行如下命令，{server_url}:{server_port}需替换成步骤1中地址和端口，如 production.cloudflare.docker.com:443。
   若节点的容器运行时为containerd，最后一步"systemctl restart docker"命令替换为"systemctl restart containerd"。
   ```
   openssl s_client -showcerts -connect {server_url}:{server_port} < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /etc/pki/ca-trust/source/anchors/tmp_ca.crt
   update-ca-trust
   systemctl restart docker
   ```
   ubuntu节点执行如下命令。
   ```
   openssl s_client -showcerts -connect {server_url}:{server_port} < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /usr/local/share/ca-certificates/tmp_ca.crt
   update-ca-trust
   systemctl restart docker
   ```
   
   
 
 #### 排查项六： 镜像过大导致失败
Pod事件列表中有"实例拉取镜像失败"事件，报错原因如下。这可能是镜像较大导致的情况。
```
Failed to pull image "XXX": rpc error: code = Unknown desc = context canceled
```
登录节点使用**docker pull**命令手动下拉镜像，镜像拉取成功。
**问题根因：**
Kubernetes默认存在拉取镜像超时时间，如果一定时间内镜像下载没有任何进度更新，下载动作就会取消。在节点性能较差或镜像较大时，可能出现镜像无法成功下载，负载启动失败的现象。
**解决方案：**
- 方案一**（推荐）** ：
  1. 登录节点手动下载镜像。
     - Containerd节点：
       ```
       crictl pull <image-address>
       ```
       
     
     - Docker节点：
       ```
       docker pull <image-address>
       ```
       
      
  
  2. 创建负载时，确认负载的镜像拉取策略imagePullPolicy为IfNotPresent（默认策略配置），此时负载会使用已拉取到本地的镜像。
   
- 方案二（仅支持v1.25及以上版本的集群）：修改节点池的配置参数。DefaultPool节点池中的节点不支持修改该参数。
  1. 登录CCE控制台。
  
  2. 单击集群名称进入集群，在左侧选择"节点管理"，在右侧选择"节点池"页签。
  
  3. 单击节点池名称后的"更多 \> 配置管理"。
  
  4. 在侧边栏滑出的"配置管理"窗口中，修改"容器运行时Docker/Containerd配置"的image-pull-progress-timeout参数。该参数用于设置镜像拉取的超时时长。
  
  5. 单击"确定"，完成配置操作。
   
 
 #### 排查项七：无法连接镜像仓库
**问题现象**
创建工作负载时报如下错误。
```
Failed to pull image "docker.io/bitnami/nginx:1.22.0-debian-11-r3": rpc error: code = Unknown desc = Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
```
**问题原因**
无法连接镜像仓库，网络不通。SWR仅支持直接拉取Docker官方的镜像，其他仓库的镜像需要连接公网。
**解决方案：**
- 方案一：给需要下载镜像的节点绑定公网IP。
- 方案二：先将镜像上传到SWR，然后从SWR拉取镜像。
 
 #### 排查项八：拉取公共镜像达上限
**问题现象**
创建工作负载时报如下错误。
```
ERROR: toomanyrequests: Too Many Requests.
```
或
```
you have reached your pull rate limit, you may increase the limit by authenticating an upgrading: https://www.docker.com/increase-rate-limits.
```
**问题原因**
DockerHub对用户拉取容器镜像请求设定了上限，详情请参见[Understanding Docker Hub Rate Limiting](https://docs.docker.com/docker-hub/usage/pulls/)。
**解决方案：**
将常用的镜像上传到SWR，然后从SWR拉取镜像。
