问题定位
工作负载详情中,若事件中提示“启动容器失败”,请按照如下方式来初步排查原因:
- 登录异常工作负载所在的节点。
- 查看工作负载实例非正常退出的容器ID。
docker ps -a | grep $podName
- 查看退出容器的错误日志。
docker logs $containerID
根据日志提示修复工作负载本身的问题。
- 查看操作系统的错误日志。
cat /var/log/messages | grep $containerID | grep oom
根据日志判断是否触发了系统OOM。
排查思路
根据具体事件信息确定具体问题原因,如表1所示。
表1 容器启动失败
日志或事件信息 |
问题原因与解决方案 |
日志中存在exit(0) |
容器中无进程。
请调试容器是否能正常运行。
排查项一:(退出码:0)容器中无持续运行的进程 |
事件信息:Liveness probe failed: Get http…
日志中存在exit(137) |
健康检查执行失败。
排查项二:(退出码:137)健康检查执行失败 |
事件信息:
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 |
磁盘空间不足,需要清理磁盘空间。
排查项三:容器所在磁盘空间不足 |
日志中存在OOM字眼 |
内存不足。
排查项四:达到容器资源上限
排查项五:工作负载的容器规格设置较小导致 |
Address already in use |
Pod中容器端口冲突。
排查项六:同一pod中container端口冲突导致 |
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加密。
排查项七:工作负载挂载的密钥值不符合要求 |
除上述可能原因外,还可能存在如下原因,请根据顺序排查。
图1 重新启动容器失败排查思路
排查项一:(退出码:0)容器中无持续运行的进程
- 登录异常工作负载所在的节点。
- 查看容器状态。
docker ps -a | grep $podName
如下图所示:
当容器中无持续运行的进程时,会出现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
解决方案:
方案一:清理镜像
您可以执行以下步骤清理未使用的镜像:
- 使用containerd容器引擎的节点:
- 查看节点上的本地镜像。
crictl images -v
- 确认镜像无需使用,并通过镜像ID删除无需使用的镜像。
crictl rmi {镜像ID}
- 使用docker容器引擎的节点:
- 查看节点上的本地镜像。
docker images
- 确认镜像无需使用,并通过镜像ID删除无需使用的镜像。
docker rmi {镜像ID}
请勿删除cce-pause等系统镜像,否则可能导致无法正常创建容器。
方案二:扩容磁盘
扩容磁盘的操作步骤如下:
- 在EVS控制台扩容数据盘。详情请参见扩容云硬盘容量。
在EVS控制台扩容成功后,仅扩大了云硬盘的存储容量,还需要执行后续步骤扩容逻辑卷和文件系统。
- 登录CCE控制台,进入集群,在左侧选择“节点管理”,单击节点后的“同步云服务器”。
- 登录目标节点。
- 使用lsblk命令查看节点块设备信息。
这里存在两种情况,根据容器存储Rootfs而不同。
Overlayfs:没有单独划分thinpool,在dockersys空间下统一存储镜像相关数据。
- 查看设备的磁盘和分区大小。
# 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
- 扩容磁盘。
将新增的磁盘容量加到容器引擎使用的dockersys逻辑卷上。
- 扩容物理卷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
- 将空闲容量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.
- 调整文件系统的大小。其中/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.
- 检查是否扩容成功。
# 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存储镜像相关数据。
- 查看设备的磁盘和分区大小。
# 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
- 扩容磁盘。
选项一:将新增的磁盘容量加到thinpool盘上。
- 扩容物理卷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
- 将空闲容量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.
- 由于thinpool未挂载到设备,因此无需调整文件系统的大小。
- 检查是否扩容成功。使用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盘上。
- 扩容物理卷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
- 将空闲容量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.
- 调整文件系统的大小。其中/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.
- 检查是否扩容成功。使用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
创建工作负载时,设置的限制资源若小于实际所需资源,会触发系统OOM,并导致容器异常退出。
排查项五:工作负载的容器规格设置较小导致
工作负载的容器规格设置较小导致,若创建工作负载时,设置的限制资源少于实际所需资源,会导致启动容器失败。
排查项六:同一pod中container端口冲突导致
- 登录异常工作负载所在的节点。
- 查看工作负载实例非正常退出的容器ID。
docker ps -a | grep $podName
- 查看退出容器的错误日志。
docker logs $containerID
根据日志提示修复工作负载本身的问题。如下图所示,即同一Pod中的container端口冲突导致容器启动失败。
图2 container冲突导致容器启动失败
解决方案:
重新创建工作负载,并配置正确的端口,确保端口不冲突。
排查项七:工作负载挂载的密钥值不符合要求
事件详情中出现以下错误:
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
排查项八:容器启动命令配置有误导致
错误信息如下图所示:
解决方案:
请在工作负载详情页中,切换至“容器管理”页签,核查容器的“生命周期 > 启动命令”配置信息,确保启动命令配置正确。
排查项九:JAVA探针的版本选择latest导致
K8s事件为Created container init-pinpoint
解决方案:
- 在创建工作负载时,在“高级设置”步骤下的“性能管理配置”项目下,JAVA探针版本请选择最新的版本(例如:1.0.36),不要选择latest版本。
- 如果工作负载创建时的JAVA探针版本已经选择了latest版本,可以更新工作负载配置,将JAVA探针版本请选择为最新的版本(例如:1.0.36)。
排查项十:用户自身业务BUG
请检查工作负载启动命令是否正确执行,或工作负载本身bug导致容器不断重启。
- 登录异常工作负载所在的节点。
- 查看工作负载实例非正常退出的容器ID。
docker ps -a | grep $podName
- 查看退出容器的错误日志。
docker logs $containerID
注意:这里的containerID为已退出的容器的ID
图3 容器启动命令配置不正确
如上图所示,容器配置的启动命令不正确导致容器启动失败。其他错误请根据日志提示修复工作负载本身的BUG问题。
解决方案:
重新创建工作负载,并配置正确的启动命令。