首页 > 其他分享 >记录一次K8s pod被杀的排查过程

记录一次K8s pod被杀的排查过程

时间:2024-01-05 16:36:30浏览次数:40  
标签:k8s QoS oom 排查 score 内存 pod K8s

问题描述

今天下午运维反馈说我们这一个pod一天重启了8次,需要排查下原因。一看Kiban日志,jvm没有抛出过任何错误,服务就直接重启了。显然是进程被直接杀了,初步判断是pod达到内存上限被K8s oomkill了。
因为我们xmx和xsx设置的都是3G,而pod的内存上限设置的是6G,所以出现这种情况还挺诡异的。

排查过程

初步定位

先找运维拉了一下pod的描述,关键信息在这里

Containers:
  container-prod--:
    Container ID:   --
    Image:          --
    Image ID:       docker-pullable://--
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 05 Jan 2024 11:40:01 +0800
    Last State:     Terminated
      Reason:       Error
      Exit Code:    137
      Started:      Fri, 05 Jan 2024 11:27:38 +0800
      Finished:     Fri, 05 Jan 2024 11:39:58 +0800
    Ready:          True
    Restart Count:  8
    Limits:
      cpu:     8
      memory:  6Gi
    Requests:
      cpu:        100m
      memory:     512Mi
  • 可以看到Last State:Terminated,Exit Code: 137。这个错误码表示的是pod进程被SIGKILL给杀掉了。一般情况下是因为pod达到内存上限被k8s杀了。
    因此得出结论是生产环境暂时先扩大下pod的内存限制,让服务稳住。然后再排查为啥pod里会有这么多的堆外内存占用。

进一步分析

但是运维反馈说无法再扩大pod的内存限制,因为宿主机的内存已经占到了99%了。
然后结合pod的内存监控,发现pod被杀前的内存占用只到4G左右,没有达到上限的6G,pod就被kill掉了。

于是问题就来了,为啥pod没有达到内存上限就被kill了呢。
带着疑问,我开始在google里寻找答案,也发现了一些端倪:

  • 如果是pod内存达到上限被kill,pod的描述里会写Exit Code: 137,但是Reason不是Error,而是OOMKilled
  • 宿主机内存已经吃满,会触发k8s的保护机制,开始evict一些pod来释放资源
  • 但是为什么整个集群里,只有这个pod被反复evict,其他服务没有影响?

谜题解开

最终还是google给出了答案:
Why my pod gets OOMKill (exit code 137) without reaching threshold of requested memory

链接里的作者遇到了和我一样的情况,pod还没吃到内存上限就被杀了,而且也是:

  Last State:     Terminated
      Reason:       Error
      Exit Code:    137

作者最终定位的原因是因为k8s的QoS机制,在宿主机资源耗尽的时候,会按照QoS机制的优先级,去杀掉pod来释放资源。

什么是k8s的QoS?

QoS,指的是Quality of Service,也就是k8s用来标记各个pod对于资源使用情况的质量,QoS会直接影响当节点资源耗尽的时候k8s对pod进行evict的决策。官方的描述在这里.

k8s会以pod的描述文件里的资源限制,对pod进行分级:

QoS 条件
Guaranteed 1. pod里所有的容器都必须设置cpu和内存的request和limit,2. pod里所有容器设置的cpu和内存的request和容器设置的limit必须相等(容器自身相等,不同容器可以不等)
Burstable 1. pod并不满足Guaranteed的条件,2. 至少有一个容器设置了cpu或者内存的request或者limit
BestEffort pod里的所有容器,都没有设置任何资源的request和limit

当节点资源耗尽的时候,k8s会按照BestEffort->Burstable->Guaranteed这样的优先级去选择杀死pod去释放资源。

从上面运维给我们的pod描述可以看到,这个pod的资源限制是这样的:

    Limits:
      cpu:     8
      memory:  6Gi
    Requests:
      cpu:        100m
      memory:     512Mi

显然符合的是Burstable的标准,所以宿主机内存耗尽的情况下,如果其他服务都是Guaranteed,那自然会一直杀死这个pod来释放资源,哪怕pod本身并没有达到6G的内存上限。

QoS相同的情况下,按照什么优先级去Evict?

但是和运维沟通了一下,我们集群内所有pod的配置,limit和request都是不一样的,也就是说,大家都是Burstable。所以为什么其他pod没有被evict,只有这个pod被反复evict呢?

QoS相同的情况,肯定还是会有evict的优先级的,只是需要我们再去寻找下官方文档。

关于Node资源耗尽时候的Evict机制,官方文档有很详细的描述。

其中最关键的一段是这个:

If the kubelet can't reclaim memory before a node experiences OOM, the oom_killer calculates an oom_score based on the percentage of memory it's using on the node, and then adds the oom_score_adj to get an effective oom_score for each container. It then kills the container with the highest score.

This means that containers in low QoS pods that consume a large amount of memory relative to their scheduling requests are killed first.

简单来说就是pod evict的标准来自oom_score,每个pod都会被计算出来一个oom_score,而oom_score的计算方式是:pod使用的内存占总内存的比例加上pod的oom_score_adj值

oom_score_adj的值是k8s基于QoS计算出来的一个偏移值,计算方法:

QoS oom_score_adj
Guaranteed -997
BestEffort 1000
Burstable min(max(2, 1000 - (1000 × memoryRequestBytes) / machineMemoryCapacityBytes), 999)

从这个表格可以看出:

  • 首先是BestEffort->Burstable->Guaranteed这样的一个整体的优先级
  • 然后都是Burstable的时候,pod实际占用内存/pod的request内存比例最高的,会被优先Evict

总结

至此已经可以基本上定位出Pod被反复重启的原因了:

  • k8s节点宿主机内存占用满了,触发了Node-pressure Eviction
  • 按照Node-pressure Eviction的优先级,k8s选择了oom_score最高的pod去evict
  • 由于所有pod都是Burstable,并且设置的request memery都是一样的512M,因此内存占用最多的pod计算出来的oom_score就是最高的
  • 所有pod中,这个服务的内存占用一直都是最高的,所以每次计算出来,最后都是杀死这个pod

那么如何解决呢?

  • 宿主机内存扩容,不然杀死pod这样的事情无法避免,无非就是杀哪个的问题
  • 对于关键服务的pod,要把request和limit设置为完全一致,让pod的QoS置为Guaranteed,尽可能降低pod被杀的几率

标签:k8s,QoS,oom,排查,score,内存,pod,K8s
From: https://www.cnblogs.com/xtf2009/p/17947545

相关文章

  • Pod Init Error: force_encoding': can't modify frozen String (FrozenError)
    热烈欢迎,请直接点击!!!进入博主AppStore主页,下载使用各个作品!!!注:博主将坚持每月上线一个新app!! 如下图所示,切换Xcode为Xcode13。 ......
  • linux如何排查cpu持续飙高原因
    一、检查CPU使用率首先在Linux系统中检查CPU使用率。可以通过在命令行中输入top或htop命令来查看当前系统中各个进程的CPU使用率。如果CPU使用率大于80%,则可以考虑进行排查。$top二、检查系统负载另外可以使用uptime命令来查看系统的平均负载情况。$uptime如果系统负载超过CPU内......
  • 支付系统日志设计完全指南:构建高效监控和问题排查体系的关键基石
    这是《百图解码支付系统设计与实现》专栏系列文章中的第(7)篇。在一家头部互联网公司发现一些工作多年的同学打印的日志也是乱七八糟的,所以聊聊这个话题。本文主要讲结构清晰的日志在支付系统中的重要作用,设计日志规范需要遵守的一些基本原则,以及接口摘要日志、业务摘要日志、详细日......
  • 虚机 启动问题排查
    现象解决方法[root@mahuateng/etc/essd.d]$mount-thugetlbfsnone/mnt/huge_2MB_essd[root@mahuateng/etc/essd.d]$umount/mnt/huge_2MB_essd[root@mahuateng/etc/essd.d]$mount|grephugecgroupon/sys/fs/cgroup/hugetlbtypecgroup(rw,nosuid,nodev,noexec......
  • k8s集群部署报错问题合集
    1、报错-- thenumberofavailableCPUs1islessthantherequired2解决方法:如图中报错,至少需要2核CPU,增加CPU核数2、报错kubeletserviceisnotenabled###解决方法:kubelet没有开启开机自启动,按照提示运行:systemctlenablekubelet.service3、thisversionofkubeadm......
  • 部署Kubernetes(K8s)高可用群集需要多个步骤和考虑因素
    部署一个Kubernetes(K8s)高可用群集需要多个步骤和考虑因素。以下是详细步骤:规划和准备:评估集群需求,包括资源(CPU、内存、存储)、网络、安全和可扩展性。选择部署环境:公有云、私有云、混合云或本地数据中心。选择合适的Kubernetes发行版,例如kubeadm、Kops、Rancher或云提供商的托管服务......
  • k8s多集群管理工具--kuboard v3
    docker拉取镜像安装部署kuboard:v31、###docker拉取镜像dockerpullswr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v32、###启动kuboard容器dockerrun-d\--restart=unless-stopped\--name=kuboard\-p8081:80/tcp\-p30081:10081/tcp\-eKUBOARD_EN......
  • Kubernetes 配置Pod使用代理上网
    配置KubernetesPod使用代理上网在企业网络环境中进行Kubernetes集群的管理时,经常会遇到需要配置Pods通过HTTP代理服务器访问Internet的情况。这可能是由于各种原因,如安全策略限制、网络架构要求或者访问特定资源的需要。本文将介绍配置Kubernetes中Pod使用代理的两种常见方式:通过......
  • CCS2023--从0到1打造k8s威胁检测可信纵深体系
    本议题公开发布于CCS-2023成都网络安全大会云安全论坛。......
  • K8S_IPV6 POD与数据库联通方法以及快速网络调试的一个思路
    K8S_IPV6POD与数据库联通方法以及快速网络调试的一个思路背景前端时间搭建了一套K8SonlyIPV6SingleStack的测试环境因为自己长时间不搞K8S了,并且IPV6的搭建方法墙内的文档很不完整我这边仅是搭建了一套比较基本的K8S_calico_ingress的单栈IPV6的环境但是同事一直要求......