0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

马哥Linux运维 来源:博客园 2024-01-18 09:57 次阅读

问题描述

今天下午运维反馈说我们这一个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 1101 +0800
    Last State:     Terminated
      Reason:       Error
      Exit Code:    137
      Started:      Fri, 05 Jan 2024 1138 +0800
      Finished:     Fri, 05 Jan 2024 1158 +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, theoom_killercalculates anoom_scorebased on the percentage of memory it's using on the node, and then adds theoom_score_adjto get an effectiveoom_scorefor 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被杀的几率。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JVM
    JVM
    +关注

    关注

    0

    文章

    152

    浏览量

    12130
  • QoS机制
    +关注

    关注

    0

    文章

    2

    浏览量

    4940

原文标题:记录一次K8s pod被杀的排查过程

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    全面提升,阿里云Docker/Kubernetes(K8S) 日志解决方案与选型对比

    。根据不同Pod需求设置对应的采集配置,所有涉及容器采集的配置均支持IncludeLabel、ExcluseLabel过滤同配置可应用到多个k8s集群。如果您有多个的k8s集群,若其
    发表于 02-28 12:49

    全面提升,阿里云Docker/Kubernetes(K8S) 日志解决方案与选型对比

    。根据不同Pod需求设置对应的采集配置,所有涉及容器采集的配置均支持IncludeLabel、ExcluseLabel过滤同配置可应用到多个k8s集群。如果您有多个的k8s集群,若其
    发表于 02-28 12:50

    K8S容器编排的互通测试

    K8S容器编排之NetWorkPolicy官方实例
    发表于 06-06 11:28

    从零开始入门 K8s| 阿里技术专家详解 K8s 核心概念

    的资料中也会看到“ks”这个词,也就是“K8s”,它是通过将 8 个字母“ubernete ”替换为“8”而导致的个缩写。Kubernetes 为什么要用“舵手”来命名呢?大家可以看
    发表于 09-20 14:52

    从零开始入门 K8s| 详解 Pod 及容器设计模式

    的信息,其实全是份,这份都来自于 Pod一次创建的这个 Infra container。这就是 Pod 解决网络共享的
    发表于 09-20 15:12

    k8s核心原理学习指南3

    k8s学习3 - 核心原理
    发表于 09-25 16:37

    K8s 从懵圈到熟练 – 集群网络详解

    导读:阿里云 K8S 集群网络目前有两种方案:种是 flannel 方案;另外种是基于 calico 和弹性网卡 eni 的 terway 方案。Terway 和 flannel 类似
    发表于 10-14 15:06

    K8s 从懵圈到熟练 – 镜像拉取这件小事

    致。进阶方式上边的功能,定程度上解决了集群节点登录镜像仓库不方便的问题。但是我们在创建 Pod 的时候,仍然需要给 Pod 指定 imagePullSecrets。
    发表于 10-14 15:38

    从零开始入门 K8s | 应用存储和持久化数据卷:核心知识

    pod 删掉之后的情况。先删 Pod,接着再删下对应的 PVC(K8s 内部对 pvc 对象由保护机制,在删除 pvc 对象时如果发现有 pod
    发表于 10-15 14:55

    从零开始入门 K8s | 应用存储和持久化数据卷:存储快照与拓扑调度

    上我才能使用那块 PV,而对第二个问题场景就是说跨可用区的话,必须要在将使用该 PV 的 pod 调度到同个可用区的 node 上才能使用阿里云云盘服务,那 K8s 中怎样去解决这个问题呢?简单
    发表于 10-15 15:07

    从零开始入门 K8s | 可观测性:你的应用健康吗?

    时候需要自己对业务场景上来判断,这种的链接是否会对业务造成影响。 三、问题诊断接下来给大家讲解下在 K8s 中常见的问题诊断。应用故障排查-了解状态机制首先要了解
    发表于 10-15 15:32

    从零开始入门 K8s | 应用存储和持久化数据卷:核心知识

    首先看Pod Volumes 的常见类型:本地存储,常用的有 emptydir/hostpath;网络存储:网络存储当前的实现方式有两种,种是 in-tree,它的实现代码是放在 K8
    发表于 10-16 10:10

    k8s volume中的本地存储和网络存储

    八 、 k8s volume 本地存储和网络存储
    发表于 03-25 08:44

    搭建K8s环境平台的步骤

    1 搭建K8s环境平台规划1.1 单master集群1.2 多master集群
    发表于 11-04 06:03

    glibc导致的堆外内存泄露的排查过程

    本文记录一次glibc导致的堆外内存泄露的排查过程
    的头像 发表于 09-01 09:43 411次阅读
    glibc导致的堆外内存泄露的<b class='flag-5'>排查过程</b>