问题背景
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、 首先确认污点是否存在,执行如下命令:
代码语言:javascript复制[root@work2 log]# kubectl describe node/work2 |grep Taint
Taints: caf=log:NoExecute
node.kubernetes.io/unreachable:NoExecute
node.kubernetes.io/unreachable:NoSchedule
确认污点确实是存在的。
2、查看整个node的污点,执行命令如下所示:
代码语言:javascript复制kubectl describe node work2
......
CreationTimestamp: Thu, 10 Sep 2020 12:05:45 0800
Taints: caf=log:NoExecute
node.kubernetes.io/unreachable:NoExecute
node.kubernetes.io/unreachable:NoSchedule
.....
看到这里,问题原因大概找到了,原因是因为机器在关机同时,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
调度到有这个Taint
的node
上
NoExecute
:定义pod
的驱逐行为,以应对节点故障。
因为无法被删除,所以Pod依然无法被调度到该节点,我又想了,有没有办法删除所有的污点,这样就连带着把这个不可用污点也给删除了,答案找到了,通过如下命令:kubectl patch node k8s-node1 -p '{"spec":{"Taints":[]}}'
事实证明我又异想天开了,所有污点都删除了,但依然无法删除NoExecute
污点。
怎么办,乖乖看官方文档去,这么成熟的k8s怎么会有这种低级问题?
NoExecute
上面提到的污点会影响节点上已经运行的Pod
,如下所示:
- 立即将不能忍受的污点逐出
- 容忍污点但未定义
tolerationSeconds
的Pod
将永远绑定 - 可以忍受指定污点的
Pod
在指定的时间内保持绑定。当某些条件为真时,节点控制器会自动为节点添加污点。内置以下污点:
node.kubernetes.io/not-ready
:节点尚未准备好。这对应于NodeConditionReady
为False
。
node.kubernetes.io/unreachable
:无法从节点控制器访问节点。这对应于NodeConditionReady
为Unknown
。
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
状态,状态不正常,如下所示:
[root@work2 yaml]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; disabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: inactive (dead)
Docs: https://kubernetes.io/docs/
原来如此,k8s
圈内有句话说的比较恰当,如果说APIServer
是整个集群的大脑,那么kubelet
就是每个节点的小脑,它主要用于跟APIServer
交互,让APIServer
获取节点的状态信息,现在kubelet
已经挂了,很自然无法进行Pod
的调度了。直接执行:systemctl start kubelet
再次查看状态,已经正常,如下所示:
[root@work2 yaml]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; disabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Tue 2020-11-17 14:46:35 CST; 1 day 1h ago
Docs: https://kubernetes.io/docs/
Main PID: 15763 (kubelet)
Memory: 65.9M
CGroup: /system.slice/kubelet.service
└─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 -m
若swap
那一行输出为0,则说明已经关闭。
Pod不能正确被调度的原因大多是资源不足造成的,可能是CPU、内存、也可能是超过单个节点容纳Pod最大数量,碰到此类异常,根据异常信息具体分析即可!好了,一篇水文就先说到这里!
推荐
Ingress-nginx灰度发布功能详解
如何使用 Ingress-nginx 进行前后端分离?
深入探究 K8S ConfigMap 和 Secret
Kubernetes入门培训(内含PPT)