
# 工作负载异常：启动容器失败
#### 问题定位
工作负载详情中，若事件中提示"启动容器失败"，请按照如下方式来初步排查原因：
1. 登录异常工作负载所在的节点。
2. 查看工作负载实例非正常退出的容器ID。 
   如果节点为docker，请执行docker命令：
   ```
   docker ps -a | grep $podName
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl ps -a | grep $podName
   ```
   
   
3. 查看退出容器的错误日志。 
   如果节点为docker，请执行docker命令：
   ```
   docker logs $containerID
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl logs $containerID
   ```
   根据日志提示修复工作负载本身的问题。
   
   
4. 查看操作系统的错误日志，例如查询日志中是否存在OOM信息。 
   ```
   cat /var/log/messages | grep $containerID  | grep oom
   ```
   根据日志判断是否触发了系统OOM。
   
   
 
#### 排查思路
根据具体事件信息确定具体问题原因，如[表1]所示。
 表1容器启动失败 
| 日志或事件信息                                                                                                                                                                                                                                                                                                                                                                                                              | 问题原因                                                    | 排查与解决方案                                                                                                  |
|:---|:---|:---|
| Pod日志中存在exit(0)                                                                                                                                                                                                                                                                                                                                                                                                      | 容器中无进程。                                                 | 请调试容器是否能正常运行，详情请参见[容器中无持续运行的进程（退出码：0）]。                            |
| - Kubernetes事件信息： ``` Liveness probe failed: Get http… ```   - Pod日志中存在exit(137)                                                                                                                                                                  | 健康检查执行失败。                                               | 检查Pod中所配置的容器健康检查（Liveness Probe）策略是否符合预期，详情请参见[健康检查执行失败（退出码：137）]。 |
| - Kubernetes事件信息如下： ``` Thin Pool has 15991 free data blocks which is less than minimum required 16383 free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior ```   - Pod日志中存在no left space   | 磁盘空间不足。                                                 | 您需要扩容或清理磁盘空间，详情请参见[容器所在磁盘空间不足]。                                  |
| Pod日志中存在OOM字眼                                                                                                                                                                                                                                                                                                                                                                                                        | Pod内存不足。                                                | 检查Pod的资源配置是否正确，详情请参见[容器资源配置过小]。                                     |
| Pod日志中存在Address already in use                                                                                                                                                                                                                                                                                                                                                                                       | Pod中容器端口冲突。                                             | 检查Pod是否出现容器端口冲突，详情请参见[同一Pod中container端口冲突]。                       |
| Kubernetes事件信息如下： ``` Error: failed to start container "filebeat": Error response from daemon: OCI runtime create failed: container_linux.go:330: starting container process caused "process_linux.go:381: container init caused \"setenv: invalid argument\"": unknown ```                                                                                                         | 负载中挂载了Secret，Secret对应的值没有进行base64加密。                    | 解决方案详情请参见[工作负载挂载的密钥值不符合要求]。                                       |
| Kubernetes事件信息如下： ``` the failed container exited with ExitCode: 255 ```                                                                                                                                                                                                                                                                                                               | 可能是在ARM架构的节点上运行x86的容器镜像。                                | 解决方案详情参见[容器镜像版本与节点架构不符]。                                           |
| Kubernetes事件信息如下： ``` the failed container exited with ExitCode: 141 ```                                                                                                                                                                                                                                                                                                              | containerd版本与tail版本不兼容导致。                               | 解决方案详情参见[容器启动命令中执行tail -f xx退出（退出码：141）]。                         |
| Kubernetes事件信息如下： ``` Created container init-pinpoint ```                                                                                                                                                                                                                                                                                                                             | Java探针的版本不兼容导致。  | 解决方案详情参见[JAVA探针的版本不兼容]。                                            |
| 其他Pod日志                                                                                                                                                                                                                                                                                                                                                                                                              | 请结合业务进行排查。                                              | 排查方案请参见[业务配置问题排查]。                                                |
   
 #### 容器中无持续运行的进程（退出码：0）
1. 登录异常工作负载所在的节点。
2. 查看容器状态。 
   如果节点为docker，请执行docker命令：
   ```
   docker ps -a | grep $podName
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl ps -a | grep $podName
   ```
   如下图所示：
   ![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002330277765.png "点击放大")
   当容器中无持续运行的进程时，会出现exit(0)的状态码，此时说明容器中无进程。
   
   
 
 #### 健康检查执行失败（退出码：137）
工作负载配置的健康检查会定时检查业务，异常情况下pod会报实例不健康的事件且pod一直重启失败。
工作负载若配置liveness型（工作负载存活探针）健康检查，当健康检查失败次数超过阈值时，会重启实例中的容器。在工作负载详情页面查看事件，若K8s事件中出现"Liveness probe failed: Get http..."时，表示健康检查失败。
**解决方案：**
请在工作负载详情页中，切换至"容器管理"页签，核查容器的"健康检查"配置信息，排查健康检查策略是否合理或业务是否已异常。
 #### 容器所在磁盘空间不足
如下磁盘为创建节点时选择的docker专用盘分出来的thinpool盘，以root用户执行**lvs**命令可以查看当前磁盘的使用量。
```
Thin Pool has 15991 free data blocks which is less than minimum required 16383 free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior
```
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002296198514.png "点击放大")
**解决方案：**
**方案一：清理镜像**
您可以执行以下步骤清理未使用的镜像：
- 使用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
         ```
         
        
    
   
   
 
 #### 容器资源配置过小
事件详情中有OOM字样。并且，在日志中也会有记录：
```
cat /var/log/messages | grep 96feb0a425d6 | grep oom
```
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000001182783964.png "点击放大")
创建工作负载时，设置的限制资源若小于实际所需资源，会触发系统OOM，并导致容器异常退出。
 #### 同一Pod中container端口冲突
1. 登录异常工作负载所在的节点。
2. 查看工作负载实例非正常退出的容器ID。 
   如果节点为docker，请执行docker命令：
   ```
   docker ps -a | grep $podName
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl ps -a | grep $podName
   ```
   
   
3. 查看退出容器的错误日志。 
   如果节点为docker，请执行docker命令：
   ```
   docker logs $containerID
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl logs $containerID
   ```
   根据日志提示修复工作负载本身的问题。如下图所示，即同一Pod中的container端口冲突导致容器启动失败。
   图1container冲突导致容器启动失败   
   ![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0183019747.png "点击放大")
   
   
**解决方案：**
配置正确的容器端口，确保端口不冲突，然后重新创建工作负载。
如果Pod使用主机网络（即配置**hostNetwork: true**）也可能会出现容器端口冲突，这是因为Pod内的容器会直接与宿主机共享网络接口和端口空间，多个使用相同端口的Pod无法运行在同一节点上。
 #### 工作负载挂载的密钥值不符合要求
事件详情中出现以下错误：
```
Error: failed to start container "filebeat": Error response from daemon: OCI runtime create failed: container_linux.go:330: starting container process caused "process_linux.go:381: container init caused \"setenv: invalid argument\"": unknown
```
出现以上问题的根因是由于工作负载中挂载了Secret，但Secret对应的值没有进行base64加密。
**解决方案：**
通过控制台创建Secret，Secret对应的值会自动进行base64加密。
如果通过YAML进行创建，需要手动对密钥值进行base64加密：
```
echo -n "待编码内容" | base64
```
 #### 容器镜像版本与节点架构不符
在ARM架构的节点上创建工作负载时未使用正确的镜像版本，使用正确的镜像版本即可解决该问题。
如果您需要构建x86和ARM双架构镜像，请参考[CCE中使用x86和ARM双架构镜像](https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_0305.html)。
 #### 容器启动命令中执行tail -f xx退出（退出码：141）
Kubernetes事件为：
```
the failed container exited with ExitCode: 141
```
**问题根因：**
containerd历史版本和容器镜像中tail\>=8.28版本不兼容，导致tail -f 命令退出，退出码为141。
**解决方案：**
- 方案一：将集群升级到v1.25.16-r20、v1.27.16-r20、v1.28.15-r10、v1.29.10-r10、v1.30.6-r10、v1.31.4-r0版本及以上。
- 方案二：重置节点，将容器运行时切换为docker。
 
 #### JAVA探针的版本不兼容
Kubernetes事件为：
```
Created container init-pinpoint
```
**解决方案：**
1. 在创建工作负载时，在"高级配置"步骤下的"性能管理配置"项目下，JAVA探针版本请选择最新的版本（例如：1.0.36），不要选择latest版本。
2. 如果工作负载创建时的JAVA探针版本已经选择了latest版本，可以更新工作负载配置，将JAVA探针版本请选择为最新的版本（例如：1.0.36）。
 
 #### 业务配置问题排查
请检查工作负载启动命令是否正确执行，或工作负载本身bug导致容器不断重启。
1. 登录异常工作负载所在的节点。
2. 查看工作负载实例非正常退出的容器ID。 
   如果节点为docker，请执行docker命令：
   ```
   docker ps -a | grep $podName
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl ps -a | grep $podName
   ```
   
   
3. 查看退出容器的错误日志。 
   如果节点为docker，请执行docker命令：
   ```
   docker logs $containerID
   ```
   如果节点为containerd，请执行containerd命令：
   ```
   crictl logs $containerID
   ```
   注意：这里的containerID为已退出的容器的ID
   请根据日志提示修复工作负载本身的BUG问题。
   
   
 
#### 常见问题一：容器启动命令配置不正确
如下图所示，容器配置的启动命令不正确导致容器启动失败。
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002612267607.png "点击放大")
**解决方案：**
重新创建工作负载，并配置正确的启动命令。
#### 常见问题二：启动报错"fatal error: procresize: invalid arg"
创建工作负载后无法正常启动，查看日志报错：
```
fatal error: procresize: invalid arg
runtime stack:
runtime.throw(0x75be20, 0x17)
/usr/lib/google-golang/src/runtime/panic.go:530 +0x99
runtime.procresize(0x180, 0x0)
/usr/lib/google-golang/src/runtime/proc1.go:2735 +0xba6
runtime.schedinit()
/usr/lib/google-golang/src/runtime/proc1.go:72 +0x110
runtime.rt0_go(0x7ffcd751f9f8, 0x1, 0x7ffcd751f9f8, 0x0, 0x0, 0x1, 0x7ffcd7520b77, 0x0, 0x7ffcd7520b81, 0x7ffcd7520bc3, ...)
/usr/lib/google-golang/src/runtime/asm_amd64.s:109 +0x132
```
根据日志报错判断是Go程序在容器内启动时，runtime尝试调整线程数（GOMAXPROCS）传入了非法参数导致的崩溃，一般是由于容器资源限制或Go版本兼容问题导致，查看镜像里Go程序的版本，发现是1.10老版本。
Go1.9和1.10旧版本存在一个硬编码bug：Go runtime里最大支持255核CPU，超过255核的机器，它会计算溢出，传给procresize非法参数，导致直接崩溃。
通过命令排查节点CPU限制：
```
cat /sys/fs/cgroup/cpuset/cpuset.cpus
```
结果为0-383，发现确实大于255，可确定是该问题导致。
**解决方案：**
您可以参考以下两个方案之一进行解决：
- 升级镜像里Go程序的版本大于1.10版本（建议升级到最新版本），然后重新制作镜像部署。
- 您可以通过在工作负载的YAML增加环境变量解决：
  ```
  - env:
    - name: GOMAXPROCS
      value: "1"
  ```
  
 
