一、前言
容器和 Kubernetes 的先进性毋庸置疑,但当大量的企业在开始拥抱容器编排领域的事实标准 Kubernetes 时,却陷入了困境。K8s 就像一把双刃剑,既是最佳的容器编排技术,同时也存在相当高的复杂性和应用的高门槛,这个过程中往往会导致一些常见性错误。学会解决k8s常见问题的解决思路与思考方向,能应急处理K8S中常见的问题,是每个运维以及开发都必须掌握的技能。本篇将收集的k8s【集群故障】、【网络故障】、【节点故障】和【应用异常】等几大最常见故障逐一分析。
二、问题列表
1、生产k8s集群故障实例
问题描述
云机房电源过热,导致服务器重启,但是由于k8s的基础环境没有搭建好,即未将selinux未设置为disabled,导致服务器重启后,selinux开启了,导致所有的pod都故障了。
pod错误如下图所示:
Java应用如下图所示:
进入容器后,也显示没有权限:
问题分析
其实上面的错误已经提示的很明显了,就是无法访问宿主机的文件系统,导致所有的容器都没有权限。但是当时未曾往那方面想,一直觉得是服务器挂载的磁盘的问题,因为当时还有个情况就是k8s的其中一个节点重启后,由于挂载磁盘的命令有个单词写错了,导致挂载失败,又重新挂载了一次,所以刚开始误以为是磁盘损坏了部分容器镜像导致的,而且确实是更换了一些基础镜像后,pod也正常了,其实是因为selinux导致的原来的镜像文系统没有权限访问了。
解决方案
#永久关闭selinux sed -i 's/enforcing/disabled/' /etc/selinux/config 注:重启机器后,selinux配置才能永久生效 执行getenforce 显示Disabled说明selinux已经关闭 #临时关闭selinux setenforce 0 注:临时关闭后,服务器重启后selinux还是会开启,不要用这种方式,若是方式服务器无法重启也要把selinux变成Disabled
为什么要关闭selinux?
关闭selinux以允许容器访问宿主机的文件系统,Selinux是内核级别的一个安全模块,通过安全上下文的方式控制应用服务的权限,是应用和操作系统之间的一道ACL,但不是所有的程序都会去适配这个模块,不适配的话开着也不起作用,何况还有规则影响到正常的服务,比如权限等等相关的问题。
2、网络插件Calico故障实例
问题描述
情况1:某个节点的Calico状态是CrashLoopBackOff,即等待中。情况2:其中一个节点的calico是Running 但是not READY。
kubectl get pods -n kube-system
如上图可以看到有个calico状态是CrashLoopBackOff,即等待中
如上图可以其中一个节点的calico是Running 但是not READY
查看属于哪个节点:
kubectl get pods -n kube-system -o wide
如上图可以看到k8s-master1的calico有问题。
查看日志:
kubectl logs -f -n kube-system calico-node-5mzmt -c calico-node
如上图可以看到10.139.0.1被占用了,10.139.0.1是我之前测试其他docker容器新建的自定义网络,把它删除掉试试
问题分析
引发该问题的原因主要是没有指定网络,临时解决方案为删除自定义网络。最好在部署calico的时候指定网络。
解决方案
查看network:
docker network ls
删除自定义网络:
docker network rm pkulaw_net
删除pod:
kubectl delete pod calico-node-5mzmt -n kube-system
再次查看calico:
kubectl get pods -n kube-system
彻底根治:
calico.yaml 文件添加以下两行,网卡使用ifconfig查看宿主机的网卡名称,我的宿主机的网卡名称是 eth0(有的可能是ens33)
在配置文件CALICO_NETWORKING_BACKEND处新增两行配置:
#新增两行配置 直接配置通配符 :value: “interface=eth.*” - name: IP_AUTODETECTION_METHOD value: "interface=eth.*"
更新一下资源清单文件calico.yaml :
kubectl apply -f calico.yaml
3、因系统内核版本低引发的网络插件Calico故障实例
问题描述
某云部署k8s高可用集群,5台服务器中,其中有2台是centos7.5,内核版本是3.10.0-862.el7.x86_64,其余是centos7.6,内核版本是3.10.0-957.el7.x86_64。内核版本3.10.0-862.el7.x86_64不支持calico-v3.23.3,导致安装失败。某些文件无法创建,路径无法挂载。
calico-node pod错误如下图所示:
calico-node pod报错详情如下图所示:
解决方案
请参考:Centos 7.x 升级内核
4、k8s组件不健康问题
问题描述
kubectl get cs 出现Unhealthy,且rancher控制台提示组件不健康。
$ kubectl get cs Warning: v1 ComponentStatus is deprecated in v1.19+ NAME STATUS MESSAGE ERROR controller-manager Unhealthy Get "http://127.0.0.1:10252/healthz": dial tcp 127.0.0.1:10252: connect: connection refused scheduler Unhealthy Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused etcd-0 Healthy {"health":"true"}
这是由于scheduler、controller-manager端口(127.0.0.1:10251),物理机不能监听.
calico-node pod报错详情如下图所示:
解决方案
把scheduler、controller-manager端口变成物理机可以监听的端口,如下:
# 修改kube-scheduler的配置文件 $ vim /etc/kubernetes/manifests/kube-scheduler.yaml # 修改如下内容 把—port=0注释即可 # 重启各个节点的kubelet $ systemctl restart kubelet $ systemctl restart kubelet # 相应的端口已经被物理机监听了 $ ss -antulp | grep :10251 tcp LISTEN 0 128 :::10251 :::* users:(("kube-scheduler",pid=36945,fd=7)) # 修改kube-controller-manager的配置文件 $ vim /etc/kubernetes/manifests/kube-controller-manager.yaml # 修改如下内容 把—port=0注释即可 # 重启各个节点的kubelet $ systemctl restart kubelet $ systemctl restart kubelet # 查看状态 $ kubectl get cs Warning: v1 ComponentStatus is deprecated in v1.19+ NAME STATUS MESSAGE ERROR scheduler Healthy ok controller-manager Healthy ok etcd-0 Healthy {"health":"true"} $ ss -antulp | grep :10252 tcp LISTEN 0 128 :::10252 :::* users:(("kube-controller",pid=41653,fd=7))
5、k8s命名空间或crd资源无法删除
问题描述
有时候我们删除k8s的命名空间或crd资源时一直卡在 Terminating,例如以下场景:
场景一:在KubeSphere中开启了日志服务(KubeSphere Logging System)以后,我并不想使用它,于是我先关闭了日志服务,然后对它进行强制删除。
$ kubectl delete ns kubesphere-logging-system --force --grace-period=0
过了十几分钟,再次查看删除进度:
$ kubectl get ns kubesphere-logging-system NAME STATUS AGE kubesphere-logging-system Terminating 6d19h
卡在了 Terminating 的状态。
解决方案
获取 namespace 的详情信息并转为 json,如下:
$ kubectl get namespace kubesphere-logging-system -o json > kubesphere-logging-system.json
打开 json 文件编辑,找到 spec 将 finalizers 下的 kubernetes 删除:
"spec": { "finalizers": [ "kubernetes" # 将此行删除 ] }
进行替换:
$ kubectl replace --raw "/api/v1/namespaces/kubesphere-logging-system/finalize" -f ./kubesphere-logging-system.json
最后再次查看,发现已经删除了,如下:
$ kubectl get ns kubesphere-logging-system Error from server (NotFound): namespaces "kubesphere-logging-system" not found
场景二:想卸载KubeSphere,执行官方的kubesphere-delete.sh,一直卡在如下所示:
customresourcedefinition.apiextensions.k8s.io "fluentbits.logging.kubesphere.io" deleted
解决方案
#查看 crd资源对象 $ kubectl get crd|grep fluentbits.logging.kubesphere.io fluentbits.logging.kubesphere.io #删除crd $ kubectl patch crd/fluentbits.logging.kubesphere.io -p '{"metadata":{"finalizers":[]}}' --type=merge customresourcedefinition.apiextensions.k8s.io/fluentbits.logging.kubesphere.io patched #再次查看crd资源对象,已经删除了 $ kubectl get crd|grep fluentbits.logging.kubesphere.io