使用Kubernetes环境来检测cgroupOOM并将其与Pod和容器连接起来

关于为容器创建子进程的内部讨论。

环境

Kubernetes版本:EKS 1.21
节点操作系统:Amazon Linux 2内核5.4

前提等 tí

在kubernetes环境中,内存不足(OOM)主要分为两种情况。

    • cgroupOOM

podのresourcesに設定したlimitにより引き起こされたOOM
コンテナのmemoryがlimitに達すると再起動されるが、その際にOOMが発生している

systemOOM

cgroupOOMでない、kernelがまずいと判断して引き起こすOOM

スクリーンショット 2021-12-22 23.25.01.png

不方便的事情

在cgroupOOM中,只有当主进程(容器内的pid:1)被kill时,容器才会被重新启动。
基本上这就足够了,但是对于像php-fpm或python的celery这样从主进程生成子进程并运行的东西可能不够。

当子进程由于内存使用过多而被OOMkilled时,主进程会创建一个新的子进程并退出。
实际上,我正在处理php-fpm和celery容器,当主进程被杀死并重新启动容器时,有时只有子进程被杀死而容器并不会重新创建。

而且,只有杀掉这个子进程的状态,你才无法通过不采取任何措施来知道它的发生。你可以通过查看指标、观察内存的变化或查看Node的syslog等方法来得知不正常的动作。

因此,我们考虑设计一个机制来检测并通知这些事情。

选项1:节点问题检测器

您可以监控syslog和stats等以便检测异常情况。一旦检测到异常,您可以通过事件通知或生成prometheus的指标进行通知。

这个方法很简单,但还有一些不足的地方。
当检测到OOM时,我们可以立即看出OOM发生了以及进程的名称,但是,比如说php-fpm进程崩溃的情况下,我们只知道php-fpm进程崩溃了,却不知道是哪个容器的php-fpm进程崩溃了。需要通过查看syslog并对比容器ID,然后进行匹配来确定该ID的容器是哪一个…
如果您不介意这些问题,那么设置也很简单,我觉得这样就可以了。

第二项。Loki的录音规则。

与上述相比,设置会稍微复杂一些,但这是一种可以自动连接的方法。
除了Loki之外,还需要kube-state-metrics和prometheus,但作为Kubernetes的基本监控设置,希望你能理解。
支持使用recording rules的Loki版本是2.3及以上。

作为一个流程

    • promtailでnodeのsyslogをtargetに追加して保存する

 

    • recording rulesでoomのログをメトリクス化してprometheusに保存

 

    • kube-state-metricsのメトリクス kube_pod_container_info とjoinしてoomkilledのメトリクスとコンテナを紐付ける

 

    あとはそれを元に通知するなりなんなり

这是其中的一个趋势,我们将仔细分析。

将syslog添加到目标中

对于journal的情况,您可以在promtail的配置中添加类似的内容进行获取。

    - job_name: journal
      journal:
        path: /var/log/journal
        max_age: 12h
        labels:
          job: systemd-journal
      relabel_configs:
        - source_labels: ['__journal__systemd_unit']
          target_label: 'unit'
        - source_labels: ['__journal__hostname']
          target_label: 'hostname'

如果不是期刊,我就不知道了。

设置Loki的录音规则。

假设已经完成了启用录制规则的设置,关于此可能会写另一篇文章。

我会设定这样的规则。

groups:
  - name: oomkilling
    rules:
      - record: oom_killed_container_count_info
        expr: sum by(uid,cid)(count_over_time({job="systemd-journal"} |~ "^oom-kill:" | regexp ".+task_memcg=/kubepods(/burstable)?/pod(?P<uid>[0-9,a-f].+)/(?P<cid>[0-9,a-f].+),task.+" [1m]))

当发生OOM时,将创建一个名为oom_killed_container_count_info的计数器(准确来说是仪表盘)指标,它的标签为uid(等于pod的id)和cid(等于容器的id),用于记录OOMKiller杀死了哪个进程(这次没有使用uid)。

将kube-state-metrics与指标连接。

使用以下查询连接kube-state-metrics产生的容器信息指标。

avg by(pod,container)(
  label_replace(kube_pod_container_info,"cid","$2","container_id","(docker|containerd)://(.+)")
  * on(cid) group_left
  oom_killed_container_count_info
)

kube_pod_container_info的container_id以docker://或containerd://开头,因此需要使用label_replace将其移除

现在,已经完成了一个能够立即判断发生了OOMKilled的pod和容器的指标。

スクリーンショット 2021-12-23 0.33.50.png

另外还存在一个问题
更进一步的问题

这个方法的一个相当大的问题是在对syslog进行grep和解析的过程中,由于LOG导致的输出很可能会出现频繁的变化,所以有很大可能突然无法检测到。

在中文中,你可以这样来解释:“根本解决是”

有一个关于kubernetes的问题,要求cgroupOOM提供信息。
https://github.com/kubernetes/kubernetes/issues/100483

bannerAds