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

问题背景

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

集群污点k8s版本系统版本
master1.14Centos 7.1
work11.14Centos 7.1
work21.14Centos 7.1
work31.14Centos 7.1
work41.14Centos 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、 首先确认污点是否存在,执行如下命令:

[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的污点,执行命令如下所示:

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调度到有这个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状态,状态不正常,如下所示:

[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 -mswap那一行输出为0,则说明已经关闭。

Pod不能正确被调度的原因大多是资源不足造成的,可能是CPU、内存、也可能是超过单个节点容纳Pod最大数量,碰到此类异常,根据异常信息具体分析即可!

 

<think>好的,我现在要解决用户提到的Calico的kube-controllers一直处于Pending状态,并且显示node.kubernetes.io/not-ready的问题。首先,我需要回顾一下用户之前的提问,他们之前询问了如何使用kubeadm reset重装K8S 1.29,而现在遇到了Calico控制器的问题。这可能是在安装网络插件后出现的,用户可能按照之前的步骤安装了Flannel,但这里提到的是Calico,也许用户更换了网络插件,或者在安装过程中出现了问题。 首先,我需要考虑Calico-kube-controllers处于Pending状态的常见原因。Pending状态通常意味着Pod无法被调度到合适的节点上。可能的原因包括节点资源不足、节点选择器不匹配、污点(Taint)的影响,或者节点本身的状态问题。这里的错误信息是node.kubernetes.io/not-ready,说明节点可能被标记为未就绪,导致调度器无法将Pod调度到该节点。 接下来,我需要分步骤分析可能的原因: 1. **节点状态检查**:首先确认节点是否处于Ready状态。如果节点未就绪,任何Pod都无法调度到该节点上。用户可以使用kubectl get nodes查看节点状态,如果节点状态为NotReady,需要进一步排查节点的问题,比如kubelet服务是否运行,容器运行时是否正常,网络配置是否正确等。 2. **污点(Taint)和容忍(Toleration)**:Kubernetes的主节点(Master节点)通常会有污点,防止普通Pod调度到上面。Calico的kube-controllers可能需要特定的容忍才能在主节点上运行。需要检查Deployment或DaemonSet中的容忍配置是否正确,是否匹配节点的污点。 3. **资源配额和限制**:检查是否有资源限制导致Pod无法调度,比如CPU或内存不足。虽然kube-controllers通常资源需求不高,但如果有配置错误可能导致问题。 4. **亲和性(Affinity)设置**:查看Calico的配置是否有节点亲和性设置,导致Pod无法找到合适的节点。 5. **镜像拉取问题**:如果节点无法拉取所需的镜像,Pod会一直处于Pending状态。需要检查Pod的事件日志,查看是否有拉取镜像失败的错误。 6. **网络插件配置错误**:Calico作为网络插件,如果安装过程中配置错误,可能导致控制器无法正常运行,进而影响节点状态。 接下来,我需要指导用户逐步排查这些问题。首先,用户应该检查节点的状态,确认节点是否Ready。如果节点NotReady,需要进一步检查kubelet日志,容器运行时状态,以及网络配置。例如,kubelet无法启动可能是因为证书问题、配置错误或者依赖服务未运行。 如果节点状态正常,那么需要检查Calico的kube-controllers的Pod描述,使用kubectl describe pod命令查看事件和错误信息。这可以帮助确定具体原因,比如是否有污点排斥、资源不足或镜像拉取失败。 关于污点和容忍,需要确认Calico的部署配置中是否包含了对node.kubernetes.io/not-ready污点的容忍,或者是否有其他污点存在。通常,kube-controllers可能需要容忍主节点的污点,例如node-role.kubernetes.io/control-plane:NoSchedule。如果用户的集群是单节点或者控制器需要运行在主节点上,可能需要手动添加容忍。 此外,用户可能在安装Calico时使用了错误的配置文件,或者版本不兼容。需要确认使用的Calico版本是否与Kubernetes 1.29兼容,配置文件中的镜像地址是否正确,以及RBAC配置是否合适。 如果用户之前使用的是Flannel,现在换成Calico,可能存在残留的网络配置冲突。需要确保彻底清理旧CNI插件的配置,并正确安装Calico。 最后,还要考虑权限问题,比如ServiceAccount是否正确,是否有足够的权限创建资源。通过检查Pod的事件日志,可以获取更多线索,例如权限被拒绝的错误。 综合以上可能性,我应该建议用户按照以下步骤排查: 1. 检查节点状态,确认节点是否Ready。 2. 检查kube-controllers Pod的事件和详细信息。 3. 确认节点污点及Pod的容忍配置。 4. 检查资源配额和镜像拉取情况。 5. 验证Calico配置文件的正确性和版本兼容性。 6. 查看kubelet和容器运行时的日志,排除底层服务问题。 在回答时,需要结构清晰,分步骤说明每个排查方法,并提供相应的命令示例,方便用户执行和验证。同时,提醒用户注意版本兼容性和配置文件的正确性,避免常见的配置错误。</think>--- ### Calico `kube-controllers` 一直处于 Pending 状态(`node.kubernetes.io/not-ready`)的排查与解决指南 --- #### 一、现象分析 Calico 的 `calico-kube-controllers` Pod 处于 `Pending` 状态,并显示事件 `node.kubernetes.io/not-ready`。这表明 Kubernetes 节点未就绪,导致调度器无法将 Pod 分配到节点。 --- #### 二、核心排查步骤 ##### 1. **检查节点状态** ```bash kubectl get nodes -o wide ``` - **预期结果**:节点状态应为 `Ready`。 - **问题处理**: - 若节点状态为 `NotReady`,需检查以下内容: ```bash # 查看节点详细信息 kubectl describe node <节点名称> # 检查 kubelet 状态 systemctl status kubelet # 检查容器运行时状态(以 containerd 为例) systemctl status containerd ``` - 修复方法: - 重启 `kubelet`:`systemctl restart kubelet` - 确保容器运行时(如 containerd/docker)正常运行 - 检查节点资源(CPU/内存)是否充足 --- ##### 2. **检查 Pod 事件与详细信息** ```bash kubectl describe pod calico-kube-controllers-xxxx -n kube-system ``` - **关注关键字段**: - `Events`:查看调度失败的具体原因(如污点排斥、资源不足等) - `Conditions`:检查 `PodScheduled` 状态是否为 `False` 及原因 --- ##### 3. **污点(Taint)与容忍(Toleration)配置** - **查看节点污点**: ```bash kubectl describe node <节点名称> | grep Taints ``` - 主节点通常有污点:`node-role.kubernetes.io/control-plane:NoSchedule` - **修改 Calico 容忍配置**(针对污点 `node.kubernetes.io/not-ready`): 编辑 Calico 的 `kube-controllers` 部署文件(例如 `calico.yaml`),在 `spec.template.spec` 下添加容忍: ```yaml tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule - key: node.kubernetes.io/not-ready operator: Exists effect: NoExecute ``` - 应用配置: ```bash kubectl apply -f calico.yaml ``` --- ##### 4. **检查资源配额与镜像拉取** - **资源限制**: - 检查 `calico-kube-controllers` 的 `resources` 配置是否过小: ```bash kubectl describe deployment calico-kube-controllers -n kube-system ``` - 若需调整,编辑部署文件并增加资源限制(示例): ```yaml resources: requests: cpu: 100m memory: 256Mi ``` - **镜像拉取失败**: ```bash # 查看 Pod 事件中是否有镜像拉取错误 kubectl describe pod calico-kube-controllers-xxxx -n kube-system | grep -i "image" # 手动拉取镜像(以 Calico v3.26 为例) crictl pull docker.io/calico/kube-controllers:v3.26.0 ``` --- ##### 5. **验证 Calico 配置与版本兼容性** - **检查 Calico 版本与 Kubernetes 1.29 的兼容性** 参考 [Calico 官方支持矩阵](https://projectcalico.docs.tigera.io/getting-started/kubernetes/requirements),确认版本是否匹配。 - **重新安装 Calico**(推荐使用官方最新配置): ```bash # 删除旧配置 kubectl delete -f calico.yaml # 下载最新配置文件(示例 Calico v3.26) curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml -O # 应用配置 kubectl apply -f calico.yaml ``` --- ##### 6. **检查 CNI 插件冲突** 若之前安装过其他网络插件(如 Flannel),需彻底清理残留文件: ```bash rm -rf /etc/cni/net.d/* systemctl restart kubelet ``` --- #### 三、补充排查工具 - **查看 kubelet 日志**: ```bash journalctl -u kubelet -f --since "5 minutes ago" ``` - **检查网络连通性**: ```bash # 检查 API Server 可达性 curl -k https://<API-Server-IP>:6443 ``` --- #### 四、最终验证 1. 确认节点状态已恢复 `Ready`: ```bash kubectl get nodes ``` 2. 检查 `calico-kube-controllers` 状态: ```bash kubectl get pods -n kube-system | grep calico-kube-controllers ``` --- #### 常见问题总结 | 现象 | 解决方案 | |------|----------| | 节点 `NotReady` | 检查 `kubelet` 和容器运行时状态 | | 污点排斥 | 在 Deployment 中添加容忍配置 | | 镜像拉取失败 | 手动拉取镜像或配置镜像仓库代理 | | CNI 冲突 | 清理旧 CNI 配置并重启 `kubelet` | 建议参考 [Calico 官方故障排查文档](https://projectcalico.docs.tigera.io/maintenance/troubleshoot/troubleshooting) 获取更多帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值