- 分析ExitCode定位Pod异常退出原因
查看ExitCode
使用kubectl describe pod查看到pod对应退出状态码,如果不为0,表示异常退出
退出状态码区间,0-255,0表示正常退出
外界中断将程序退出的时候状态码区间是129-255
程序自身原因导致的异常退出状态码区间在1-128
常见异常状态码:
137:被SIGKILL中断信号杀死,常为内存溢出,CPU达到限制,在describe pod中的表现就是OOMKilled
- 容器内抓包定位网络问题
在kubernetes中运行容器应用,当容器应用中没有一些常见的问题盘查命令,出现问题后是很难定位的,这个时候,我们就能进入容器的网络命名空间netns,再使用宿主机上的命令进行问题排查。
解决方法:
1、kubectl get pod -o wide查看到应用所在主机节点
2、在应用所在主机节点上docker ps | grep 应用名,定位到应用docker容器,获取docker id
3、docker inspect -f {{.State.Pid}} docker-id获取到应用容器对应的进程pid
4、nsenter -n -t pid进入容器网络命名空间,进行curl,tcpdump,ping等抓包排查操作
- PID耗尽
检查当前PID限制
[root@k8s-master1 ~]# cat /proc/sys/kernel/pid_max
32768
[root@k8s-master1 ~]# cat /proc/sys/kernel/threads-max
14531
检查系统当前进程数量,若超过内核限制则会导致进程无法启动,可以通过调整最大阈值解决
ps aux | wc -l
解决方法:
echo "kernel.pid_mac=65535" >> /etc.sysctl.conf && sysctl -p
echo "kernel.tjreads-max=65535" >> /etc/sysctl.conf && sysctl -p
- 内存碎片化
内存分页失败,内核日志报错如下
page allocate failure
无法申请到内存,pod就会一直维持在ContainerCreating状态
内存碎片化过多会导致,即便现在看上去系统内存很多,但是无法申请到大块的内存给进程使用,系统就会一直杀掉一些进程来释放内存,导致OOM
解决方法:
周期性进行drop cache操作
echo 3 > /proc/sys/vm/drop_caches
- 磁盘爆满
容器运行时的磁盘爆满会导致docker无响应,docker Hang住,kubelet日志也能看到PLEG unhealthy,因为CRI调用timeout,就无法创建或者销毁容器,一直处于ContainerCreating以及Terminating。如果kubelet所在目录磁盘空间不足,Sandbox也会创建失败。
关注路径/var/lib/docker /var/lib/kubelet
解决方法:
手动删除docker log文件,不要将容器日志写在容器内,需要另外挂载数据盘
清理docker无用数据docker system prune -a
设置正确的kubelet gc机制
给docker设置日志归档配置,只保留固定大小的日志内容 - Node NotReady
kubelet,docker异常都会导致Node NotReady
解决方法:
查看docker响应速度是否正常,查看节点是否有大量日志写入,iotop,pidstat进行定位分析
查看kubelet日志journalctl -u kubelet - Pod一直处于Terminating,ContainerCreating,Error,ImagePullBackOff,Pending,Unknown状态
Terminating
进程通过bash -c启动导致kill信号无法传递给进程
进程还存在挂载点,被其他进程占用或者写入,无法卸载
解决方法:
停止数据写入,释放挂载点
ContainerCreating
解决方法:
检查镜像正确性
挂载volume失败
磁盘满了,容器创建失败
节点内存碎片化
拉取镜像失败
CNI网络错误:检查运行节点网络组件是否正常
查看controller-manager是否正常
Error
解决方法:
说明Pod启动过程产生错误
依赖的ConfigMap,Secret,Volume产生错误
违反集群设置的安全策略,比如违反了PodSecurityPolicy等
ImagePullBackOff
解决方法:
镜像拉取失败,认证失败,镜像不存在等
docker默认以https类型的registry拉取。,如果不支持https则必须配置非安全认证docker,如果时https类型,则dockerd会校验registry的证书,在/etc/docker/cert.d/<registry:port>/ca.crt
如果镜像需要认证,但是没有配置ImagePullSecret也会拉取失败
镜像拉取超时中断管,查看镜像仓库前面的负载均衡保持长连接的超时时长,进行调整
Pending
解决方法:
容器没有足够的CPU,内存资源进行调度
nodeSelector,污点容忍,亲和性不匹配
kube-scheduler异常导致
Unknown
通常时节点失联,没法与apiserver通信,到达阈值后,controller-manager认为节点失联,并将其状态置为Unknown
解决方法:
查看节点kubelet状态 - 容器进程主动退出
容器进程主动退出,不是被外界中断杀死的话,退出码一般在0-128,一般都是业务程序的bug
容器启动强依赖于第三方应用以及coredns解析失败,导致的应用重启 - Apiserver响应慢
查看apiserver日志具体问题具体分析
通过VIP访问缓慢,有可能时VIP对应的nginx,LVS异常,可以通过kubectl get pod -s apiserver:8080绕过负载均衡进行验证 - Namespace Terminating
解决方法:
Namespace上存在Finalizers,将其清理后就可以正常删除
高版本的k8s集群不支持在线修改finalizers删除ns,要使用如下方法
curl -H "Content-Type: application/json" -XPUT -d '{"apiVersion":"v1","kind":"Namespace","metadata":{"name":"delete-me"},"spec":{"finalizers":[]}}' http://localhost:8001/api/v1/namespaces/delete-me/finalize - cgroup泄露
在低版本内核(3.10)中,一旦开启了cgroup,就可能会导致不能彻底清理memcg和对应的cssid,也就是说应用即使删除了cgroup(/sys/fs/cgroup/memory下对应的cgroup目录)但在内核中没有释放cssid,导致内核认为的从group实际数量不一致。这个问题会导致容器创建失败,因为创建容器会为其创建cgroup进行隔离,而低版本内核中有个限制:允许创建的cgroup最大数量写死为65535,如果节点上经常创建销毁容器导致创建很多cgroup造成泄露,创建容器的时候就会导致cgroup创建失败并报错“no space left on device”
解决方法:
升级内核到3.10.1064以上版本并且关闭kernel,kmem特性,重启主机
- arp缓存爆满导致健康检查失败
某集群节点数 1200+,用户监控方案是 daemonset 部署 node-exporter 暴露节点监控指标,使用 hostNework 方式,statefulset 部署 promethues 且仅有一个实例,落在了一个节点上,promethues 请求所有节点 node-exporter 获取节点监控指标,也就是或扫描所有节点,导致 arp cache 需要存所有 node 的记录,而节点数 1200+,大于了 net.ipv4.neigh.default.gc_thresh3 的默认值 1024,这个值是个硬限制,arp cache记录数大于这个就会强制触发 gc,所以会造成频繁gc,当有数据包发送会查本地 arp,如果本地没找到 arp 记录就会判断当前 arp cache 记录数+1是否大于 gc_thresh3,如果没有就会广播 arp 查询 mac 地址,如果大于了就直接报 arp_cache: neighbor table overflow!,并且放弃 arp 请求,无法获取 mac 地址也就无法知道探测报文该往哪儿发(即便就在本机某个 veth pair),kubelet 对本机 pod 做存活检查发 arp 查 mac 地址,在 arp cahce 找不到,由于这时 arp cache已经满了,刚要 gc 但还没做所以就只有报错丢包,导致存活检查失败重启 pod
解决方法:
调整gc_thresh阈值
net.ipv4.neigh.default.gc_thresh1 = 128
net.ipv4.neigh.default.gc_thresh2 = 512
net.ipv4.neigh.default.gc_thresh3 = 4096
- DNS解析异常
如果DNS解析经常延时5s才返回,可能时conntrack冲突导致的丢包
解析超时,查看coredns服务是否正常
解析外部域名超时,若容器应用使用的dnspolicy时clusterfirst,则需要查看coredns所在节点的dns解析是否能够解析到外部域名,若dnspolicy为default,则需要查看容器所在主机的dns是否能够解析到外部域名,确认上游dns状态,是否有ACL限制