【容器】k8s获取的节点oom事件并输出到node事件

devtools/2024/10/23 17:07:08/

在debug k8s node不可用过程中,有可能会看到:

System OOM encountered, victim process: xx

为了搞清楚oom事件是什么,以及如何产生的,我们做了一定探索,并输出了下面的信息。(本文关注oom事件是如何生成&传输的,具体cadvisor如何判定oom不在本片的讨论范围)

解析

主要代码文件:

1)pkg.kubelet.oom.oom_watcher_linux.go

oom_watcher主要描述了kubelet是如何接受并log系统产生的oom事件的

2)oom_watcher_linux.go:

NewWatcher方法会返回一个Watcher类型的对象,该对象包含recorder和oomStreamer。recorder用于记录,oomStreamer是一个OomParser(Cadvisor)类型的对象, 用于将OomInstance类型的对象写入outStream管道(channel)

package oomimport ("fmt"v1 "k8s.io/api/core/v1""k8s.io/apimachinery/pkg/util/runtime""k8s.io/client-go/tools/record""k8s.io/klog/v2""github.com/google/cadvisor/utils/oomparser"
)// streamer 接口定义了一个 StreamOoms 函数,
// 它接收一个 oomparser.OomInstance 类型的 channel,存储OomInstance类型数据
type streamer interface {StreamOoms(chan<- *oomparser.OomInstance)
}var _ streamer = &oomparser.OomParser{}type realWatcher struct {recorder    record.EventRecorderoomStreamer streamer
}var _ Watcher = &realWatcher{}// NewWatcher creates and initializes a OOMWatcher backed by Cadvisor as
// the oom streamer.
// 启动一个新的OOM watcher, 参数是一个 EventRecorder
// EventRecorder 是一个能够存储event并记录到一个queue里的Interface
// 函数声明中前面的括号里面是函数形参列表;后面的括号里面是函数返回值列表。
func NewWatcher(recorder record.EventRecorder) (Watcher, error) {
// 生成一个oomStreamer,由cadvisor的oomparser创建oomStreamer, err := oomparser.New()if err != nil {return nil, err}
// 生成一个watcher,包含上面的两个对象: recorder 和 oomStreamerwatcher := &realWatcher{recorder:    recorder,oomStreamer: oomStreamer,}return watcher, nil
}// Start watches for system oom's and records an event for every system oom encountered.
func (ow *realWatcher) Start(ref *v1.ObjectReference) error {
// 这段代码用来创建一个outStream channel,它是一个由 oomparser.OomInstance 
// 类型指针元素的channel,并可以向channel中传输10个元素。接着就启动了一个goroutine,
// 该goroutine调用ow.oomStreamer.StreamOoms方法并将outStream作为参数传入。该方法会往outStream channel中不断地写数据(即oom instance对象)outStream := make(chan *oomparser.OomInstance, 10)go ow.oomStreamer.StreamOoms(outStream)go func() {defer runtime.HandleCrash()
// 从outStream 读取event,并根据判断条件做是否oom。并输出相应的logfor event := range outStream {if event.VictimContainerName == recordEventContainerName {klog.V(1).InfoS("Got sys oom event", "event", event)eventMsg := "System OOM encountered"if event.ProcessName != "" && event.Pid != 0 {eventMsg = fmt.Sprintf("%s, victim process: %s, pid: %d", eventMsg, event.ProcessName, event.Pid)}ow.recorder.Eventf(ref, v1.EventTypeWarning, systemOOMEvent, eventMsg)}}klog.ErrorS(nil, "Unexpectedly stopped receiving OOM notifications")}()return nil
}

再来看下kubelet.go中如何应用
kubelet.go:
创建oomWatcher

# 通过上面的NewWathcher方法创建一个新的oomWatcher
oomWatcher, err := oomwatcher.NewWatcher(kubeDeps.Recorder)
# 如果创建新的oomWatcher报错,则查看原因
if err != nil {if libcontaineruserns.RunningInUserNS() {if utilfeature.DefaultFeatureGate.Enabled(features.KubeletInUserNamespace) {// oomwatcher.NewWatcher returns "open /dev/kmsg: operation not permitted" error,// when running in a user namespace with sysctl value `kernel.dmesg_restrict=1`.klog.V(2).InfoS("Failed to create an oomWatcher (running in UserNS, ignoring)", "err", err)oomWatcher = nil} else {klog.ErrorS(err, "Failed to create an oomWatcher (running in UserNS, Hint: enable KubeletInUserNamespace feature flag to ignore the error)")return nil, err}} else {return nil, err}
}

启动oomWatcher

    // Start out of memory watcher.if kl.oomWatcher != nil {if err := kl.oomWatcher.Start(kl.nodeRef); err != nil {return fmt.Errorf("failed to start OOM watcher: %w", err)}}

图示

在这里插入图片描述

上面的代码体现的就是如下流程,下图较完整描述了oom事件是如何被cAdvisor读取最终输出到node的事件的。

图片参考:启动oomWatcher

参考

1)https://www.jianshu.com/p/ef524b0b0119

2)启动oomWatcher


http://www.ppmy.cn/devtools/39366.html

相关文章

python使用API实现word文档翻译

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享,包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概述Visual St…

如何确保UDP文件传输工具有最低稳定的传输速度?

在当前日新月异的数字时代背景下&#xff0c;文件传输工具已经成为我们日常生活与工作中不可或缺的一部分&#xff0c;尤其针对那些频繁涉及即时数据交互与多媒体流通的场景。 UDP协议&#xff0c;以其突出的高速传输与低延迟特性&#xff0c;脱颖而出成为众多用户的首选。不过…

代码审计之浅谈RASP技术

前言&#xff1a; 想摆会烂&#xff0c;所以就落个笔吧。 其实本来是想写关于iast技术的&#xff0c;但是认真思考了下&#xff0c;感觉笔者自己本身也不太能讲清楚iast技术&#xff0c;怕误人子弟。 所以最后还是基于笔者的理解以及实际应用写一篇关于RASP技术的文章&#xf…

虚幻引擎中的投影技术主要用于创建多屏交互式内容和沉浸式显示环境

首先&#xff0c;在虚幻引擎&#xff08;UE4&#xff09;中&#xff0c;nDisplay插件是一个强大的工具&#xff0c;它允许开发者创建多屏投影系统。这种系统可以是由多个相邻的物理屏幕组成&#xff0c;例如Powerwall显示器&#xff0c;或者使用多个投影仪将3D环境投射到物理表…

芋道系统springcloud模块启动报错,枚举类不能为空

问题描述&#xff1a; Error starting ApplicationContext. To display the conditions report re-run your application with debug enabled. 2024-05-10 15:50:15.756 | ERROR 9120 | main [TID: N/A] o.s.b.d.LoggingFailureAnalysisReporter | ************************…

邻域注意力Transformer

邻域注意力&#xff08;NA&#xff09;&#xff0c;这是第一个高效且可扩展的视觉滑动窗口注意力机制&#xff0c;NA是一种逐像素操作&#xff0c;将自注意力&#xff08;SA&#xff09;定位到最近的相邻像素&#xff0c;因此与SA的二次复杂度相比&#xff0c;具有线性时间和空…

【NLP练习】使用seq2seq实现文本翻译

使用seq2seq实现文本翻译 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 from __future__ import unicode_literals, print_function, division from io import open import unicodedata import string impo…

MYSQL DBA运维实战

1.数据库系统DBS 数据库管理系统 DBA:工程师 2.SQL语言:机构化查询语言 DDL语句 数据库定义语言(create,drop,alter) DML语句 数据库操纵语言:插入数据:insert 删除数据:delete 更新数据:update DQL语句 数据库查询语言:查询数据select DCL语句 数据库控制语言:控…