使用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

不方便的事情
在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和容器的指标。

另外还存在一个问题
更进一步的问题
这个方法的一个相当大的问题是在对syslog进行grep和解析的过程中,由于LOG导致的输出很可能会出现频繁的变化,所以有很大可能突然无法检测到。
在中文中,你可以这样来解释:“根本解决是”
有一个关于kubernetes的问题,要求cgroupOOM提供信息。
https://github.com/kubernetes/kubernetes/issues/100483