[大厂实践] Netflix容器平台内核panic可观察性实践

news2024/9/25 17:15:38

在某些情况下,K8S节点和Pod会因为出错自动消失,很难追溯原因,其中一种情况就是发生了内核panic。本文介绍了Netflix容器平台针对内核panic所做的可观测性增强,使得发生内核panic的时候,能够导出信息,帮助排查问题。原文: Kubernetes And Kernel Panics

最近,我们为了减轻容器平台Titus客户(工程师,而不是最终用户)的痛苦,开始调查"孤儿(Orphaned)"pod。有些pod从不会结束,只能被垃圾收集,没有真正令人满意的最终状态。我们的服务任务(比如ReplicatSet)所有者不会太在意,但Batch用户会非常在意。如果没有真正的返回码,怎么才能知道重试是否安全?

即使只占系统中总pod的一小部分,这些孤儿pod对用户来说也是真正的痛苦。这些pod到底去哪儿了?为什么不见了?

本文展示了如何将最坏情况(内核panic)与Kubernetes(k8s)联系起来,并最终与我们的运维人员联系起来,这样我们就可以跟踪k8s节点是如何以及为什么消失的。

孤儿Pod从何而来?

因为底层k8s节点对象消失了,所以孤儿pod也消失了。一旦发生这种情况,GC[1]进程将删除该pod。在Titus上,我们运行自定义控制器来存储Pod和Node对象的历史,这样我们就可以保存一些解释并将其显示给用户。对应的失败模式在我们的UI中是这样的:

当k8s节点和它的pod消失时,用户会看到什么
当k8s节点和它的pod消失时,用户会看到什么

这是一种解释,但我和用户都不太满意。为什么代理丢失了?

丢失的节点从何而来?

节点可能因为任何原因消失,尤其是在"云"中。当这种情况发生时,通常是云供应商提供的k8s云控制器检测到实际的服务器(在我们的例子中是EC2实例)已经消失,并反过来删除k8s节点对象。这仍然没有真正回答为什么。

如何确保每个消失的实例都有原因,提供解释,并和pod关联在一起?这一切都始于一个注释:

{
     "apiVersion": "v1",
     "kind": "Pod",
     "metadata": {
          "annotations": {
               "pod.titus.netflix.com/pod-termination-reason": "Something really bad happened!",
...

创建存放这些数据的地方就是一个很好的开始。现在我们所要做的就是让GC控制器意识到这个注释,然后将其分发给任何可能导致pod或节点意外消失的进程中。添加注释(而不是修补状态)可以保留pod的其余部分。(我们还为终止原因添加了注释,并为标记添加了简短的reason-code)

pod-termination-reason注释对于填充人类可读的消息非常有用,例如:

  • "此pod被更高优先级的作业($id)抢占了"
  • "由于底层硬件失败,必须终止此pod ($failuretype) "
  • "这个pod必须被终止,因为$user在节点上运行sudo halt "
  • "这个pod意外死亡,因为底层节点内核panic了!"

但是等等,我们如何为内核panic的节点注释pod呢?

捕获内核Panic

当Linux内核出现问题时,能做的就不多了。但是,如果可以发出某种"在我的最后一口气中,诅咒Kubernetes!"UDP数据包呢?

受这篇Google Spanner论文的启发,Spanner节点发出"最后一口气"UDP数据包来释放租约和锁,也可以配置服务器在内核panic时使用一个常用的Linux模块netconsole来做同样的事情。

配置Netconsole

事实上,Linux内核甚至可以发送带有字符串"kernel panic"的UDP数据包,而它正在panic,这有点令人惊讶。能做到这一点是因为netconsole需要配置实现填写好的整个IP头。没错,必须告诉Linux源MAC、IP和UDP端口是什么,以及目标MAC、IP和UDP端口是什么,实际上是在为内核构造UDP数据包。但是,有了这些准备工作,当时机成熟时,内核可以很容易的构造[2]数据包,并在系统崩溃时将其从(预配置的)网络接口中取出。幸运的是,netconsole-setup命令使设置变得非常简单,所有配置选项可以动态[3]设置,这样当端点发生变化时,就可以指向新的IP。

一旦设置完成,内核消息将在modprobe之后开始流动。想象一下,整个操作就像执行dmesg | netcat -u $destination 6666,只不过是在内核空间中。

Netconsole"最后的怒吼"数据包

通过netconsole设置,内核panic的最后怒吼看起来就像一组UDP数据包,就像人们可能期望的那样,其中UDP数据包的数据只是内核消息的文本。在内核panic的情况下,看起来像这样(每行一个UDP数据包):

Kernel panic - not syncing: buffer overrun at 0x4ba4c73e73acce54
[ 8374.456345] CPU: 1 PID: 139616 Comm: insmod Kdump: loaded Tainted: G OE
[ 8374.458506] Hardware name: Amazon EC2 r5.2xlarge/, BIOS 1.0 10/16/2017
[ 8374.555629] Call Trace:
[ 8374.556147] <TASK>
[ 8374.556601] dump_stack_lvl+0x45/0x5b
[ 8374.557361] panic+0x103/0x2db
[ 8374.558166] ? __cond_resched+0x15/0x20
[ 8374.559019] ? do_init_module+0x22/0x20a
[ 8374.655123] ? 0xffffffffc0f56000
[ 8374.655810] init_module+0x11/0x1000 [kpanic]
[ 8374.656939] do_one_initcall+0x41/0x1e0
[ 8374.657724] ? __cond_resched+0x15/0x20
[ 8374.658505] ? kmem_cache_alloc_trace+0x3d/0x3c0
[ 8374.754906] do_init_module+0x4b/0x20a
[ 8374.755703] load_module+0x2a7a/0x3030
[ 8374.756557] ? __do_sys_finit_module+0xaa/0x110
[ 8374.757480] __do_sys_finit_module+0xaa/0x110
[ 8374.758537] do_syscall_64+0x3a/0xc0
[ 8374.759331] entry_SYSCALL_64_after_hwframe+0x62/0xcc
[ 8374.855671] RIP: 0033:0x7f2869e8ee69
...
连接到Kubernetes

最后要连接的是Kubernetes (k8s),需要k8s控制器完成以下工作:

  1. 监听端口6666上的netconsole UDP数据包,观察来自节点的类似内核panic的情况。
  2. 在内核出现故障时,查找与传入netconsole数据包的IP地址相关联的k8s节点对象。
  3. 对于该k8s节点,找到绑定到它的所有pod,注释,然后删除这些pod。
  4. 对于k8s节点,注释节点,然后删除。

第1步和第2步可能是这样的:

for {
    n, addr, err := serverConn.ReadFromUDP(buf)
    if err != nil {
        klog.Errorf("Error ReadFromUDP: %s", err)
    } else {
        line := santizeNetConsoleBuffer(buf[0:n])
        if isKernelPanic(line) {
            panicCounter = 20
            go handleKernelPanicOnNode(ctx, addr, nodeInformer, podInformer, kubeClient, line)
        }
    }
    if panicCounter > 0 {
        klog.Infof("KernelPanic context from %s: %s", addr.IP, line)
        panicCounter++
    }
}

然后第3和第4步:

func handleKernelPanicOnNode(ctx context.Context, addr *net.UDPAddr, nodeInformer cache.SharedIndexInformer, podInformer cache.SharedIndexInformer, kubeClient kubernetes.Interface, line string) {
    node := getNodeFromAddr(addr.IP.String(), nodeInformer)
    if node == nil {
        klog.Errorf("Got a kernel panic from %s, but couldn't find a k8s node object for it?", addr.IP.String())
    } else {
        pods := getPodsFromNode(node, podInformer)
        klog.Infof("Got a kernel panic from node %s, annotating and deleting all %d pods and that node.", node.Name, len(pods))
        annotateAndDeletePodsWithReason(ctx, kubeClient, pods, line)
        err := deleteNode(ctx, kubeClient, node.Name)
        if err != nil {
            klog.Errorf("Error deleting node %s: %s", node.Name, err)
        } else {
            klog.Infof("Deleted panicked node %s", node.Name)
        }
    }
}

有了这些代码,一旦检测到内核故障,pod和节点就会立即消失。不需要等待任何GC进程。注释帮助记录发生在节点和pod上的事情:

真实的pod在真实的k8s节点上丢失了,这个节点发生了真实的内核panic!
真实的pod在真实的k8s节点上丢失了,这个节点发生了真实的内核panic!
结论

将作业标记为由于内核panic而失败可能不会让客户满意。但当他们知道我们现在有必要的可观察性工具来开始修复这些内核panic时,就会感到满意!


你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

参考资料
[1]

Pod garbage collection: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-garbage-collection

[2]

Linux netconsole.c: https://github.com/torvalds/linux/blob/94f6f0550c625fab1f373bb86a6669b45e9748b3/drivers/net/netconsole.c#L932

[3]

Initialize netconsole at boot time: https://wiki.ubuntu.com/Kernel/Netconsole#Step_3:_Initialize_netconsole_at_boot_time

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1439796.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java ieda 抽风报错导致无法正常启动项目

Java ieda 抽风报错导致无法正常启动项目 问题描述&#xff1a;新建模块运行时出现下面报错&#xff0c;不能正常启动程序。 Error:Module 你的项目名 production: java.lang.ClassCastException: class org.jetbrains.jps.builders.java.dependencyView.TypeRepr$PrimitiveT…

适用于 Windows 11/10/8.1/8/7 的最佳 SD 卡恢复软件

丢失了 SD 卡中的一些重要照片或文档&#xff0c;并且不知道如何恢复&#xff1f;好吧&#xff0c;别担心&#xff01;&#xff01;以下是一些适用于 Windows 的最佳 SD 卡恢复工具&#xff0c;可增加您检索意外删除、丢失或丢失数据的机会。 什么是 SD 卡恢复软件&#xff1f;…

华为配置访客接入WLAN网络示例(MAC优先的Portal认证)

配置访客接入WLAN网络示例&#xff08;MAC优先的Portal认证&#xff09; 组网图形 图1 配置WLAN MAC优先的Portal认证示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 某企业为了提高WLAN网络的安全性&#xff0c;采用MAC优先的外置Portal认…

JVM-运行时数据区程序计数器

运行时数据区 Java虚拟机在运行Java程序过程中管理的内存区域&#xff0c;称之为运行时数据区。《Java虚拟机规范》中规定了每一部分的作用。 程序计数器的定义 程序计数器&#xff08;Program Counter Register&#xff09;也叫PC寄存器&#xff0c;每个线程会通过程序计数器…

从Unity到Three.js(安装启动)

发现在3D数字孪生或模拟仿真方向&#xff0c;越来越多的公司倾向使用Web端程序&#xff0c;目前一直都是使用的Unity进行的Web程序开发&#xff0c;但是存在不少问题&#xff0c;比如内存释放、shader差异化、UI控件不支持复制或输入中文等。虽然大多数问题都可以找到解决方案&…

什么是制动电阻器?工作及其应用

电梯、风力涡轮机、起重机、升降机和电力机车的速度控制是非常必要的。因此&#xff0c;制动电阻器是这些应用不可或缺的一部分&#xff0c;因为它们是电动机驱动器中最常用的高功率电阻器&#xff0c;用于控制其速度&#xff0c;在运输、海事和建筑等行业中。 电动火车主要比柴…

【蓝桥杯冲冲冲】Invasion of the Milkweed G

【蓝桥杯冲冲冲】Invasion of the Milkweed G 蓝桥杯备赛 | 洛谷做题打卡day30 文章目录 蓝桥杯备赛 | 洛谷做题打卡day30[USACO09OCT] Invasion of the Milkweed G题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 题解代码我的一些话 [USACO09OCT] Invasion of the Mi…

NIS服务器搭建(管理账户密码验证)

理解&#xff1a;新进100台服务器&#xff0c;通过nis服务器设置各个服务器的用户和密码&#xff0c;而不是分别到100台机器前设置用户名密码&#xff0c;服务器可以统一管理用户名密码&#xff0c;更新等操作 第一&#xff1a;服务器端设置 1.域名设置&#xff1a;dongfang …

(每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第10章 项目进度管理(三)

博主2023年11月通过了信息系统项目管理的考试&#xff0c;考试过程中发现考试的内容全部是教材中的内容&#xff0c;非常符合我学习的思路&#xff0c;因此博主想通过该平台把自己学习过程中的经验和教材博主认为重要的知识点分享给大家&#xff0c;希望更多的人能够通过考试&a…

格子表单GRID-FORM | 文档网站搭建(VitePress)与部署(Github Pages)

格子表单/GRID-FORM已在Github 开源&#xff0c;如能帮到您麻烦给个星&#x1f91d; GRID-FORM 系列文章 基于 VUE3 可视化低代码表单设计器嵌套表单与自定义脚本交互文档网站搭建&#xff08;VitePress&#xff09;与部署&#xff08;Github Pages&#xff09; 效果预览 格…

【芯片设计- RTL 数字逻辑设计入门 11.1 -- 状态机实现 移位运算与乘法 1】

文章目录 移位运算与乘法状态机简介SystemVerilog中的测试平台VCS 波形仿真 阻塞赋值和非阻塞赋值有限状态机&#xff08;FSM&#xff09;与无限状态机的区别 本篇文章接着上篇文章【芯片设计- RTL 数字逻辑设计入门 11 – 移位运算与乘法】 继续介绍&#xff0c;这里使用状态机…

LeetCode 0993. 二叉树的堂兄弟节点:深度优先搜索(BFS)

【LetMeFly】993.二叉树的堂兄弟节点&#xff1a;深度优先搜索(BFS) 力扣题目链接&#xff1a;https://leetcode.cn/problems/cousins-in-binary-tree/ 在二叉树中&#xff0c;根节点位于深度 0 处&#xff0c;每个深度为 k 的节点的子节点位于深度 k1 处。 如果二叉树的两个…

使用SM4国密加密算法对Spring Boot项目数据库连接信息以及yaml文件配置属性进行加密配置(读取时自动解密)

一、前言 在业务系统开发过程中,我们必不可少的会使用数据库,在应用开发过程中,数据库连接信息往往都是以明文的方式配置到yaml配置文件中的,这样有密码泄露的风险,那么有没有什么方式可以避免呢?方案当然是有的,就是对数据库密码配置的时候进行加密,然后读取的时候再…

25、数据结构/二叉树相关练习20240207

一、二叉树相关练习 请编程实现二叉树的操作 1.二叉树的创建 2.二叉树的先序遍历 3.二叉树的中序遍历 4.二叉树的后序遍历 5.二叉树各个节点度的个数 6.二叉树的深度 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h> ty…

生物——文献笔记

生物——文献笔记 文章目录 前言藻类群体遗传学研究和进展&#xff08;综述&#xff09;海洋动物群体遗传学的研究进展1. 影响群体基因频率的因素2. 根据自然群体的繁殖体系&#xff0c;海洋动物群体遗传类型可分为以下几类3. 海洋动物群体遗传研究中常用的遗传标记4. 研究展望…

UML 2.5图形库

UML 2.5图形库 drawio是一款强大的图表绘制软件&#xff0c;支持在线云端版本以及windows, macOS, linux安装版。 如果想在线直接使用&#xff0c;则直接输入网址drawon.cn或者使用drawon(桌案), drawon.cn内部完整的集成了drawio的所有功能&#xff0c;并实现了云端存储&#…

幻兽帕鲁服务器全自动部署教程,小白也能轻松上手

幻兽帕鲁太火了&#xff0c;官方palworld服务器不稳定&#xff1f;不如自建服务器&#xff0c;基于腾讯云幻兽帕鲁服务器成本32元全自动部署幻兽帕鲁服务器&#xff0c;超简单有手就行&#xff0c;全程自动化一键部署10秒钟即可搞定&#xff0c;无需玩家手动部署幻兽帕鲁游戏程…

深入探究 HTTP 简化:httplib 库介绍

✏️心若有所向往&#xff0c;何惧道阻且长 文章目录 简介特性主要类介绍httplib::Server类httplib::Client类httplib::Request类httplib::Response类 示例服务器客户端 总结 简介 在当今的软件开发中&#xff0c;与网络通信相关的任务变得日益普遍。HTTP&#xff08;Hypertext…

面向智算服务,构建可观测体系最佳实践

作者&#xff1a;蓟北 构建面向 AI、大数据、容器的可观测体系 &#xff08;一&#xff09;智算服务可观测概况 对于越来越火爆的人工智能领域来说&#xff0c;MLOps 是解决这一领域的系统工程&#xff0c;它结合了所有与机器学习相关的任务和流程&#xff0c;从数据管理、建…

K8s环境下rook-v1.13.3部署Ceph-v18.2.1集群

文章目录 1.K8s环境搭建2.Ceph集群部署2.1 部署Rook Operator2.2 镜像准备2.3 配置节点角色2.4 部署operator2.5 部署Ceph集群2.6 强制删除命名空间2.7 验证集群 3.Ceph界面 1.K8s环境搭建 参考&#xff1a;CentOS7搭建k8s-v1.28.6集群详情&#xff0c;把K8s集群完成搭建&…