k8s 常见故障和解决思路及方法
K8S 之连接异常——【集群故障】
Pod问题思考思路
Kubernetes集群中Pod一般哪些方面容易出现问题呢?
- Kubernetes资源配置错误:例如在部署Deployment和Statefulset时,资源清单书写有问题,导致Pod无法正常创建
- 代码问题:应用程序代码在容器启动后失败,那就需要通过排查代码查找错误
- 网络问题:网络插件部署有问题,导致Pod启动之后无法相互通信
- 存储问题:Pod挂载存储,但是需要共享的存储连接不上导致Pod启动异常
Pod 状态异常排查问题集
- Running
- Pending
- Waiting
- ContainerCreating
- ImagePullBackOff
- CrashLoopBackOff
- Error
- Terminating
- Unknown
- Evicted
如何查看pod状态:
|
|
Pod状态异常排查思路
一般来说,无论 Pod 处于什么异常状态,都可以执行以下命令来查看 Pod 的状态:
- 查看Pod的配置是否正确
|
|
- 查看 Pod 的详细信息
|
|
- 查看Pod里对应容器的日志
|
|
部分节点无法启动Pod:ContainerCreating状态
诊断方法
- 查看pod
|
|
- 查看pod 详情信息
|
|
- 显示
|
|
总结:pod 异常需要通过 describe 查看具体报错信息,根据具体报错信息再进行处理,以上是遇到同类问题的一种排查思路,问题各种各样,排查问题的思路确是可以有迹可循的
Pod状态异常排查问题集-pending状态排查思路
Pending是挂起状态:表示创建的Pod找不到可以运行它的物理节点,不能调度到相应的节点上运行,那么这种情况如何去排查呢?可以从两个层面分析问题:
1. 物理节点层面分析
- 查看节点资源使用情况:如free -m查看内存、top查看CPU使用率、df –h查看磁盘使用情况,这样就可以快 速定位节点资源情况,判断是不是节点有问题
- 查看节点污点:kubectl describe nodes master1(控制节点名字),如果节点定义了污点,那么Pod不能容 忍污点,就会导致调度失败,如下:
- Taints: node-role.kubernetes.io/master:NoSchedule
- 这个看到的是控制节点的污点,表示不允许Pod调度(如果Pod定义容忍度,则可以实现调度)
**1. Pod 本身分析 **
- 在定义pod时,如果指定了nodeName是不存在的,那也会调度失败
- 在定义Pod时,如果定义的资源请求比较大,导致物理节点资源不够也是不会调度的
Pod状态异常排查问题集- ImagePullBackOff状态
问题分析
- 拉取镜像时间长导致超时
- 配置的镜像有错误:如镜像名字不存在等
- 配置的镜像无法访问:如网络限制无法访问hub上的镜像
- 配置的私有镜像仓库参数错误:如imagePullSecret没有配置或者配置错误
- dockerfile打包的镜像不可用
Pod状态异常排查问题集- CrashLoopBackOff状态
K8s中的pod正常运行,但是里面的容器可能退出或者多次重启或者准备删除,导致出现这个状态,这个状态具有偶发性,可能上一秒还是running状态,但是突然就变成CrashLoopBackOff状态了。
Pod状态异常排查问题集- Error状态
这种状态主要是Pod启动过程会出现:
原因分析:
1)依赖的ConfigMap、Secret、PV、StorageClass等不存在;
2)请求的资源超过了管理员设置的限制,比如超过了limits等;
3)无法操作集群内的资源,比如开启RBAC后,需要为ServiceAccount配置权限。
排查思路:
|
|
Pod状态异常排查问题集- Terminating或Unknown状态
原因:Terminated是因为容器里的应用挂了。
从k8s v1.5开始,Kubernetes不会因为Node失联而删除其上正在运行的Pod,而是将其标记为Terminating 或 Unknown 状态。想要删除这些状态的Pod有 3 种方法:
- 手动删除node: 手动删除kubectl delete nodes node节点名字
- 恢复正常可选择性删除: 若node恢复正常,kubelet会重新跟kube-apiserver通信 确认这些Pod的期待状态,进而再决定删除或者继续运行这些Pod,如果删除可以通过kubectl delete pods pod-name –grace-period=0 –force强制删除
- 使用参数重建容器
Pod行为异常,Pod没有按预期的行为执行,比如没有运行podSpec里面设置的命令行参数,这一般是podSpec yaml文件内容有误,可以尝试使用 validate 参数重建容器, 比如(kubectl delete pod mypod 和 kubectl create – validate -f mypod.yaml);也可以查看创建后的 podSpec 是否是对的,比如(kubectl get pod mypod -o yaml)
Unknown是pod状态不能通过kubelet汇报给apiserver,这很有可能是主从节点(Master和Kubelet)间的通信出现了问题。
解决思路:
- 查看kubectl 状态
- 查看节点状态
- 查看apiserver是否异常
- 查看 kubelet 日志
Pod健康检查:存活性探测&就绪性探测
为什么需要探针?
如果没有探针,k8s无法知道应用是否还活着,只要pod还在运行,k8s则认为容器是健康的。但实际上,pod虽然运行了,但里面容器中的应用可能还没提供服务,那就需要做健康检查,健康检查就需要探针,常见的探针有如下几种:
- httGet 对容器的ip地址(指定的端口和路径)执行http get请求 如果探测器收到响应,并且响应码是2xx,则认为探测成功。如果服务器没有响应或者返回错误响 应码则说明探测失败,容器将重启。
- tcpSock
探针与容器指定端口建立tcp连接,如果连接建立则探测成功,否则探测失败容器重启。 - exec
在容器内执行任意命令,并检查命令退出状态码,如果状态码为0,则探测成功,否则探测失败 容器重启
LivenessProbe和ReadinessProbe区别:
- LivenessProbe决定是否重启容器
- ReadinessProbe主要来确定容器是否已经就绪: 只有当Pod里的容器部署的应用都处于就绪状态,也就是pod的Ready为true(1/1)时,才会将请求转发给容器。
coredns或者kube-dns经常重启和报错
问题描述:
在k8s中部署服务,服务之间无法通过dns解析,coredns一直处于CrashLoopBackOff状态
查看日志,报错如下:
|
|
解决思路:
coredns主要和resolv.conf打交道,会读取宿主机的/etc/resolv.conf中的nameserver内容,查询
resolv.conf文件,如果里面存在本地回环如127.0.0.1或者127.0.0.53那么就容易造成死循环
解决步骤:
修改resolv.conf文件:
将nameserver临时修改为114.114.114.114之后:kubectl edit deployment coredns -n kube-system
将replicates改为0,从而停止已经启动的coredns pod 再将replicates改为2, 这样会触发coredns重新读取系统配置,此时服务的状态为Running
kubectl执行异常:无权限问题定位
描述
|
|
这是因为安装k8s之后,默认是没有权限操作k8s资源的,可用如下方法解决
|
|
K8S 之统信异常——【网络故障】
网络故障原因
Kubernetes中的网络是非常重要的,整个k8s集群的通信调度都是通过网络插件实现的,kubernetes之上的网路通信主要有如下几种:
- 容器间的通信: 同一个pod内的多个容器间的通信,lo
- pod 通信: 从一个pod Ip到另一个pod Ip
- Pod与service通信: pod ip 到 cluster ip
- 外部通信: Service与集群外部客户端的通信
通信需要依赖网络插件,如calico、flannel、canel等,通信过程最常见的故障如下
- Pod 自身网络故障
- Pod 间通信故障
- Pod 和物理节点通信故障
K8S 之内部异常——【节点故障】
节点异常1: 集群节点NotReady
一般是该节点上的kubelet 挂掉了,查看kubelet 状态
|
|
如果挂掉需要重启一下kubelet
扩展:为什么要重启kubelet?
- 监视分配给该Node节点的pods
- 挂载pod所需要的volumes
- 下载pod的secret
- 通过docker/rkt来运行pod中的容器
- 周期的执行pod中为容器定义的liveness探针
- 上报pod的状态给系统的其他组件
- 上报Node的状态
节点异常2: pod调度失败故障排查
在k8s集群中,pod是最小单元,需要调度到具体的物理节点上运行,那么为了更好排查问题,了解pod的调度流程是重中之重,接下来介绍下pod工作和调度流程:
创建pod过程:
1、用户创建pod的信息通过API Server存储到etcd中,etcd记录pod的元信息并将结果返回API Server
2、API Server告知调度器请求资源调度分配,调度器通过计算,将优先级高的node与pod绑定并告知API Server
3、API Server将此信息写入etcd,得到etcd回复后调用kubelet创建pod
4、kubelet使用docker run创建pod内的容器,得到反馈信息后将容器信息告知API Server
5、API Server将收到的信息写入etcd并得到回馈
6、此时使用kubectl get pod就可以查看到信息了
调度方式:
1、当我们发送请求创建Pod,调度器就会把pod调度到合适的物理节点,大致分为以下过程:
Scheduler根据预选策略和优选函数,选额合适的noed节点调度
2、可以通过定义nodeName和nodeSelector进行调度
3、可以通过节点亲和性进行调度
Pod在调度的时候会找到一个合适的节点,所以如果节点资源不足;pod定义了指定的节点,但是指定的节点出现故障,或者pod定义了亲和性,但是节点没有满足的条件,都会导致调度失败。
排查思路
- describe pod 查看是否节点加了污点,pod 无法容忍,当然还要根据报错信息进行定位
- 查看目标节点 kubelet 服务的状态
pod调度失败内置污点
当某些条件为真时,节点控制器会自动为节点添加污点:
- node.kubernetes.io/ NoSchedule:如果一个pod没有声明容忍这个Taint,则系统不会把该Pod调度到有这个Taint的node上
- node.kubernetes.io/NoExecute:定义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:节点不可调度。
节点资源不足:Pod超过节点资源限制
Pod超过节点资源限制分两种情况: 情况一:Pod数量太多超过物理节点限制,较少见 情况二:Pod资源超过物理节点资源限制,相对频繁一些,requests 资源申请过多
K8S之内部异常 【节点故障】 排查思路总结
节点状态查询:kubectl get nodes
常见异常现象:1、节点状态NotReady 2、调度到该节点的pod显示Unkonwn、Pending等
常见故障:kubelet进程异常、未安装cni网络插件、docker异常、磁盘空间不足、内存不足、cpu不足
排查排查:
kubectl describe nodes 查看node节点信息kubectl describe pods <pod 名字> 查看pod节点信息systemctl status 查看kubelet状态Journalctl查看系统日志free查看内存top查看cpu
K8S 之应用故障——【应用故障】
故障排查:Service访问异常
Service是什么?为什么容易出现问题?
在kubernetes中,Pod是有生命周期的,如果Pod重启IP很有可能会发生变化。如果我们的服务都是将Pod的IP地址写死,Pod的挂掉或者重启,和刚才重启的pod相关联的其他服务将会找不到它所关联的Pod,为了解决这个问题,在kubernetes中定义了service资源对象,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,Service是一组Pod的逻辑集合,这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector实现的。
情况一: service 和 pod labels 没有匹配 情况二:service 和 pod 正确关联,kube-proxy 异常
kube-proxy 导致Service 访问异常
kube-proxy 是什么?
service 为一组相同的 pod 提供了统一的入口,起到负载均衡的效果。service 具有这样的功能,正是 kube-proxy 的功劳,kube-proxy是一个代理,安装在每一个k8s节点,当我们暴露一个 service 的时候,kube-proxy 会在iptables中追加一些规则,为我们实现路由与负载均衡的功能。
背景:查看 Service、pod、endpoint 是否正常关联
|
|
查看iptables 是否正常创建规则
|
|
通过上面可以看到之前创建的service,会通过kube-proxy在iptables中生成一个规则,来实现流量路由。
通过上面可以看到,有一系列目标为 KUBE-SVC-xxx 链的规则,每条规则都会匹配某个目标 ip 与端口。也就是说访问某个 ip:port 的请求会由 KUBE-SVC-xxx 链来处理。这个目标 IP 其实就是service ip。
|
|
|
|
通过上面分析可以知道,kube-proxy在service请求中起到流量路由转发的作用: kube-proxy 会为我们暴露的service追加iptables规则,具体流程如下:
- 所有进出请求都会经过 KUBE-SERVICES 链
- KUBE-SERVICES 链有我们发布的每一个服务,每个服务的链会对应到 DNAT 到 service 的 endpoint
- KUBE-SERVICES 链最后的是 KUBE-NODEPORTS 链,会匹配请求本主机的一些端口,这就是我们通过 NODEPORT 类型发布服务能在集群外部访问的原因。
经过上面的分析,service和pod正确关联,pod也处于运行状态,那请求service还是访问不到pod,90%就是kube-proxy引起的。查看kube-proxy是否在机器上正常运行。
kube-proxy如果在节点上运行,下一步,确认它有没有出现其他异常,比如连接主节点失败。要做到这一点,必须查看日志:如 /var/log/messages或者/var/log/kube-proxy.log(二进制安装的时候可以指定的),也使用 journalctl 访问日志、kube-proxy如果是在k8s中以pod形式运行的,可以通过kubectl logs
故障排查:Pod删除失败
故障描述:在k8s中,可能会产生很多垃圾pod,也就是有些pod虽然是running状态,可是其所调度到的k8s node节点已经从k8s集群删除了,但是pod还是在这个node上,没有被驱逐,针对这种情况就需要把pod删除。
删除pod的几种方法:
- 删除pod所在的namespace
- 如果pod是通过控制器管理的,可以删除控制器资源
- 如果pod是自主式管理,直接删除pod资源就可以了
但是我们常常遇见这样一种情况,我们在删除pod资源的时候,pod会一直terminate状态,很长时间无法删除
解决方案:
可以通过如下方法强制删除:
加参数 --force --grace-period=0,grace-period表示过渡存活期,默认
30s,在删除POD之前允许POD慢慢终止其上的容器进程,从而优雅退出,0表示立即终止POD
kubectl delete pod <pod名字> -n --force --grace-period=0