一个计算机技术爱好者与学习者

0%

K8S问题记录

1. 前言

本文记录使用K8S过程中遇到的问题、解决办法和一些原理。
问题排查方法参考《kubectl命令——故障排查篇》

2. kubelet不停重启

2.1. 问题描述

K8S的一个worker节点磁盘不足,关机进行磁盘扩容,物理扩容后开机,执行esize2fs /dev/vdb,扩容完成。

docker ps,发现没有容器被启动。
kubectl status kubelet,发现kubelet不停进行重启,每次都启动失败。
kubectl status docker,正常docker正常running。

重启机器,问题依旧。

2.2. 排查解决

1
2
journalctl -xeu kubelet -r
journalctl -xeu docker -r

kubelet日志没有报错,docker日志中报错:

1
level=error msg="xxx cleanup: failed to delete container from containerd: no such container

FROM ChatGPT:
该错误日志表示 Docker 清理容器时失败,原因是没有找到相应的容器。

可能原因及解决方法:

  1. 容器不存在:检查容器是否已被删除或者已经退出,如果是则不需要处理该错误。
  2. 容器正在运行:如果容器正在运行,可能是由于正在执行某些任务而无法清理。此时可以尝试停止容器后再进行清理。
  3. Docker daemon 出现故障:在某些情况下,Docker daemon 可能会出现故障导致无法清理容器。尝试重启 Docker daemon 可能会解决问题。
  4. 操作系统出现故障:在某些情况下,操作系统可能会出现故障导致无法清理容器。尝试重启操作系统可能会解决问题。

解决办法:手动清理容器,然后重启机器。

1
2
docker container prune
reboot

3. 新增节点flannel启动失败

3.1. 问题描述

K8S集群新增了一个节点,flannel pod自动调度上去了,但是并没有启动成功。
查看kubelet日志,报错为:
[failed to find plugin “flannel” in path [/opt/cni/bin]]
W0523 20:49:19.343813 12586 cni.go:239] Unable to update cni config: no valid networks found in /etc/cni/net.d

3.2. 解决办法

从其他正常节点拷贝一个flannel文件到这个问题节点上的 /opt/cni/bin 目录。

4. 节点上的pod被驱逐

4.1. 问题描述

因为磁盘压力,节点上的pod被驱逐了。但是,实际上节点还有很多磁盘空间。

4.2. 解决办法

1、查找kubelet配置文件路径

1
systemctl status kubelet -l

找到Drop-In配置文件路径,一般为:

1
2
3
/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
或者:
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf

2、修改kubelet配置文件
配置文件中添加:

1
KUBELET_EXTRA_ARGS="--eviction-hard=memory.available<100Mi,nodefs.available<5%,imagefs.available<15%,nodefs.inodesFree<5%"

3、重启kubelet

1
2
systemctl daemon-reload
systemctl restart kubelet

4.3. 扩展阅读

节点压力驱逐是 kubelet 主动终止 Pod 以回收节点上资源的过程。

kubelet 监控集群节点的内存、磁盘空间和文件系统的 inode 等资源。 当这些资源中的一个或者多个达到特定的消耗水平, kubelet 可以主动地使节点上一个或者多个 Pod 失效,以回收资源防止饥饿。

在节点压力驱逐期间,kubelet 将所选 Pod 的 PodPhase 设置为 Failed。这将终止 Pod。

我们可以为 kubelet 指定自定义驱逐条件,以便在作出驱逐决定时使用。驱逐条件分为软驱逐条件和硬驱逐条件。
软驱逐条件将驱逐条件与管理员所必须指定的宽限期配对。 在超过宽限期之前,kubelet 不会驱逐 Pod。如果没有指定的宽限期,kubelet 会在启动时返回错误。
硬驱逐条件没有宽限期。当达到硬驱逐条件时, kubelet 会立即杀死 pod,而不会正常终止以回收紧缺的资源。

kubelet 具有以下默认硬驱逐条件:

  • memory.available<100Mi
  • nodefs.available<10%
  • imagefs.available<15%
  • nodefs.inodesFree<5%(Linux 节点)

参考文档:节点压力驱逐

5. 业务服务响应很慢

5.1. 问题描述

某个业务服务的Pod响应很慢,发现它的requests资源配置很低,limits资源配置很高。
调大requests后响应速度明显变快了,是什么原理?

5.2. 原理解析

requests是长期允许,保证资源;limits是临时允许,并不保证资源。
上面的问题中,因为requests配置的很低,所以只能保证requests中配置的资源,并不能保证用到用到limits中配置的资源。

5.3. 扩展阅读

“requests”和”limits”在Kubernetes中的原理是通过Linux的cgroups(control groups)来实现资源管理和隔离。cgroups是Linux内核提供的一种机制,它允许对进程组进行资源限制、优先级调整和统计。Kubernetes利用cgroups将资源限制和隔离应用到容器级别。

“requests”定义了容器所需的最小资源数量。Kubernetes调度器使用这个值来决定在哪个节点上运行容器,并确保节点上有足够的资源满足容器的请求。”requests”的目的是为了确保容器能够正常运行而不会遇到资源不足的问题。

而”limits”定义了容器允许使用的资源的上限。Kubernetes使用这个值来监控容器的资源使用情况,并保护节点的稳定性。如果容器试图使用超过其限制的资源量,Kubernetes会采取相应的措施,如终止容器或重新调度到其他节点。”limits”的目的是为了防止容器使用过多的资源,从而保护整个集群的稳定性。

尽管可以在容器中设置超过”requests”的资源使用量,但这并不是一个推荐的做法。当容器超过其”requests”的资源使用量时,它可能会影响其他容器的性能,导致资源竞争和不稳定的情况。超过”requests”的使用量只是暂时允许,Kubernetes会尽力满足容器的需求,但不保证持续提供额外的资源。

6. 节点资源充足但是无法调度

6.1. 问题描述

某个节点CPU、内存资源充足,也没有污点和亲和性配置,但是Pod无法调度到上面。

6.2. 排查解决

除了检查资源之外,再检查下节点上Pod数量的限制。

1
kubectl describe node node01

Non-terminated Pods 要小于 Allocatable.pods ,如果Pod数量已经达到了节点上Pod数量限制,那么需要调大这个上限。

1
2
vim /var/lib/kubelet/config.yaml # maxPods默认110,调大它
systemctl restart kubelet

7. kubectl top命令执行报错

7.1. 问题描述

执行kubectl top pod,报错:
error: Metrics API not available

在Kubernetes Dashboard上,也发现Pod的CPU使用率和内存使用都无法显示。

7.2. 问题分析

参考kubectl top node error: metrics not available yet可知,之所以出现上面的问题,是因为K8S集群没有安装 metrics-server 。

7.3. 解决办法

解决办法:安装 metrics-server 。

通用安装方法:

1
2
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl apply -f components.yaml

如果是sealos安装的K8S集群,那么可以使用 metrics-server 集群镜像安装。

1
2
3
4
sealos run labring/metrics-server:v0.6.2 --cmd="\
helm upgrade -i metrics-server charts/metrics-server \
-n kube-system \
-f /root/metrics-server/values.yaml"

其中 /root/metrics-server/values.yaml 内容为:

1
2
3
4
5
6
defaultArgs:
- --cert-dir=/tmp
- --kubelet-preferred-address-types=InternalIP
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls

8. kubectl get响应慢

8.1. 问题描述

执行 kubectl get xxx ,响应很慢,十几秒,总会几条出现提示:

1
2
I0819 11:17:11.769943 2075052 request.go:668] Waited for 1.159893511s due to client-side throttling, not priority and fairness, request: GET:https://192.168.56.101:6443/apis/enterprisesearch.k8s.elastic.co/v1beta1?timeout=32s
I0819 11:17:31.979933 2075052 request.go:668] Waited for 9.271822241s due to client-side throttling, not priority and fairness, request: GET:https://192.168.56.101:6443/apis/events.openfunction.io/v1alpha1?timeout=32s

而且每次request后面的内容都不同。

8.2. 解决办法

解决办法:kube-apiserver 的启动参数中添加 --feature-gates=APIPriorityAndFairness=false

具体操作方法:

1
2
3
# master节点
cd /etc/kubernetes/manifests
vim kube-apiserver.yaml

添加启动参数:

1
2
3
4
5
6
spec:
containers:
- command:
- kube-apiserver
- --feature-gates=APIPriorityAndFairness=false
- ...

但是,上面的办法只能解决部分问题。kubectl get pod正常了,但是kubectl get all还是有问题。

终极解决办法:升级kubectl到v1.22版本以上。从提示其实也能看出是 client-side 侧的限流,但是 kubectl 并没有修改限流配置的方法,只能升级版本。

参考文档: