小言_互联网的博客

k8s Pod调度失败(NoExecute)排查及分析

404人阅读  评论(0)

问题背景

k8s集群,总共5个节点,信息如下所示:

集群 污点 k8s版本 系统版本
master 1.14 Centos 7.1
work1 1.14 Centos 7.1
work2 1.14 Centos 7.1
work3 1.14 Centos 7.1
work4 1.14 Centos 7.1

其中work1 Pod有特殊要求,需要访问外网,在work1节点添加了NoExecute污点,其它不能容忍该污点的Pod不能被调度到该节点。

正常情况下该Pod正常启动和使用,偶尔一次此机器出现断电故障,但是机器重启之后,发现该Pod无法启动,kubectl describe pod发现如下错误:

1 node(s) had taints that the pod didn't tolerate 2 node(s) didn't match node selector

大概意思是说,其中一个节点包含该污点,但是该Pod无法容忍。

既然包含,为什么无法容忍呢?

原因查找过程

1、 首先确认污点是否存在,执行如下命令:


   
  1. [root@work2 log]# kubectl describe node/work2 |grep Taint
  2. Taints:             caf=log:NoExecute
  3.                     node.kubernetes.io/unreachable:NoExecute
  4.                     node.kubernetes.io/unreachable:NoSchedule
  5.                     

确认污点确实是存在的。

2、查看整个node的污点,执行命令如下所示:


   
  1. kubectl describe node work2
  2. ......
  3. CreationTimestamp:  Thu,  10 Sep  2020  12: 05: 45 + 0800
  4. Taints:             caf=log:NoExecute
  5.                     node.kubernetes.io/unreachable:NoExecute
  6.                     node.kubernetes.io/unreachable:NoSchedule
  7. .....

看到这里,问题原因大概找到了,原因是因为机器在关机同时,k8s自动为这个节点添加了不可被调度污点 node.kubernetes.io/unreachable:NoExecute,所以也就导致我的业务Pod不可被调度。

解决过程

一开始个人想法只要把k8s添加的污点给删除了,也就可以被调度了,于是我开始手动删除污点,具体执行命令如下所示:

kubectl taint node k8snode2 node.kubernetes.io/unreachable-

然后再次查看该节点污点是否正常,奇怪的事情发生了,执行kubectl describe node work2查看污点,NoSchedule删除了。但是NoExecute无法删除。

NoSchedule:如果一个pod没有声明容忍这个Taint,则系统不会把该Pod调度到有这个Taintnode

NoExecute:定义pod的驱逐行为,以应对节点故障。

因为无法被删除,所以Pod依然无法被调度到该节点,我又想了,有没有办法删除所有的污点,这样就连带着把这个不可用污点也给删除了,答案找到了,通过如下命令:kubectl patch node k8s-node1 -p '{"spec":{"Taints":[]}}' 事实证明我又异想天开了,所有污点都删除了,但依然无法删除NoExecute污点。

怎么办,乖乖看官方文档去,这么成熟的k8s怎么会有这种低级问题?

NoExecute上面提到的污点会影响节点上已经运行的Pod,如下所示:

  • 立即将不能忍受的污点逐出

  • 容忍污点但未定义tolerationSecondsPod将永远绑定

  • 可以忍受指定污点的Pod在指定的时间内保持绑定。当某些条件为真时,节点控制器会自动为节点添加污点。内置以下污点:

node.kubernetes.io/not-ready:节点尚未准备好。这对应于NodeConditionReadyFalse

node.kubernetes.io/unreachable:无法从节点控制器访问节点。这对应于NodeConditionReadyUnknown

node.kubernetes.io/out-of-disk:节点磁盘不足。

node.kubernetes.io/memory-pressure:节点有内存压力。

node.kubernetes.io/disk-pressure:节点有磁盘压力。

node.kubernetes.io/network-unavailable:节点的网络不可用。

node.kubernetes.io/unschedulable:节点不可调度。

node.cloudprovider.kubernetes.io/uninitialized:当kubelet从外部云服务提供程序启动时,在节点上设置此污点以将其标记为不可用。来自cloud-controller-manager的控制器初始化此节点后,kubelet删除此污点。

如果要逐出节点,则节点控制器或kubelet会添加相关的污点NoExecute。如果故障情况恢复正常,则kubelet或节点控制器可以删除相关的污点。具体文档地址,如下所示:https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/

大概意思是说,之所以出现此污点,是k8s内部认为该节点尚不能工作,所以添加了此污点,防止Pod调度到此节点,看了半天,原来节点底层出现故障了,首先查看下kubelet状态,状态不正常,如下所示:


   
  1. [root@work2 yaml]# systemctl status kubelet                 
  2. ● kubelet.service - kubelet: The Kubernetes Node Agent
  3.    Loaded: loaded (/usr/lib/systemd/system/kubelet.service; disabled; vendor preset: disabled)
  4.   Drop-In: /usr/lib/systemd/system/kubelet.service.d
  5.            └─ 10-kubeadm.conf
  6.    Active: inactive (dead)
  7.      Docs: https: //kubernetes.io/docs/

原来如此,k8s圈内有句话说的比较恰当,如果说APIServer是整个集群的大脑,那么kubelet就是每个节点的小脑,它主要用于跟APIServer交互,让APIServer获取节点的状态信息,现在kubelet已经挂了,很自然无法进行Pod的调度了。直接执行:systemctl start kubelet再次查看状态,已经正常,如下所示:


   
  1. [root@work2 yaml]# systemctl status kubelet
  2. ● kubelet.service - kubelet: The Kubernetes Node Agent
  3.    Loaded: loaded (/usr/lib/systemd/system/kubelet.service; disabled; vendor preset: disabled)
  4.   Drop-In: /usr/lib/systemd/system/kubelet.service.d
  5.            └─ 10-kubeadm.conf
  6.    Active: active (running) since Tue  2020 -11 -17  14: 46: 35 CST;  1 day  1h ago
  7.      Docs: https: //kubernetes.io/docs/
  8.  Main PID:  15763 (kubelet)
  9.    Memory:  65.9M
  10.    CGroup: /system.slice/kubelet.service
  11.            └─ 15763 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernete...

再次执行kubectl describe nodes work2  NoExecute污点已经消失;紧接着Pod已经可以调度到该节点。

总结分析

如上所说的就是一次关机重启kubelet没有启动,导致服务的异常,那么问题原因真正原因又是什么呢?通过查看/var/log/messages内核日志,发现机器启动的时候,并没有启动kubelet,也就是说kubelet没有加到开机启动项里面,于是执行如下命令:systemctl enable kubelet设置开机自启动。

常见的kubelet无法启动大多是因为没有关闭交换内存导致,所以可以执行swapoff -a并且执行vi /etc/fstab将文件中的/dev/mapper/centos-swap swap swap defaults 0 0这一行注释掉,输入free -mswap那一行输出为0,则说明已经关闭。

Pod不能正确被调度的原因大多是资源不足造成的,可能是CPU、内存、也可能是超过单个节点容纳Pod最大数量,碰到此类异常,根据异常信息具体分析即可!好了,一篇水文就先说到这里,如有问题,请关注公众号、加我微信和我一起讨论!

推荐

Ingress-nginx灰度发布功能详解

如何使用 Ingress-nginx 进行前后端分离?

深入探究 K8S ConfigMap 和 Secret

Kubernetes入门培训(内含PPT)


原创不易,随手关注或者”在看“,诚挚感谢!


转载:https://blog.csdn.net/u012516914/article/details/110020568
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场