Go 进程在容器中无 coredump 产生问题分析
Go 进程在容器中无 coredump 产生问题分析
0x01 起因
coredump 作为一种非常重要的高度手段,在日常开发中经常用到,切换到容器环境后一直没关注。最近测试了下,发现出不了 core。觉得有些奇怪,抽点时间研究了下。
0x02 实验
一开始认为是 Go 运行时的问题,做了一以下对比。以下实现已保证了 GOTRACEBACK=crash 和 ulimit 和 /proc/sys/kernel/core_pattern 配置是正常的。
1. 以 Go 进程为 init 进程启动容器。
2. 在 上述容器中,额外运行一个 Go 进程。
得到的结果是,第1个不会出 core。第2个可以出 core 。对比了两者的差异,唯一不一样就是在容器里的 pid ,前者是1,后者不是1。
通过 bpftrace 工具外加 Go 运行时抛异常时打日志等调试方法,确认了信号是发给了内核,内核的 kernel/signal.c:get_signal 函数中没有走到 coredump 的分支。又补充了以下实验。用 C 语言写了一个 demo,构造空地址写异常。放在容器中作为 init 进程启动,发现可以正常出 core。
得到的结论就是:Go 作为容器中的1号进程时,无法正常 coredump 出来。
本来是想用 bpftrace 中的 kprobe + 指令偏移,一步步找出信号是在 get_signal 函数中的哪一步被忽略的,经过几次实验后发现这样效率太低了,还要去了解内核的信号处理流程。内核这种级别的项目,如果有什么特殊处理,一定会在代码中详细说明的。果然就在 get_signal 函数中找到了。
0x03 需要特殊对待的 init 进程
注释见如下:
/*
* Global init gets no signals it doesn't want.
* Container-init gets no signals it doesn't want from same
* container.
*
* Note that if global/container-init sees a sig_kernel_only()
* signal here, the signal must have been generated internally
* or must have come
* case, the signal cannot be dropped.
*/
大意是容器里的 init 进程地位跟宿主机的 init 进程地位一样重要,所以不能被自己(自杀)和自己的子孙进程杀死( 计算机世界里的父慈子孝 ),如果收到了这类信号,就会忽略掉。你可以试下能不能把宿主的 init 进程,用 kill -6 1命令杀掉(当然是杀不掉的)。由于 Go 使用的 SIGABRT 信号属于这类信号,所以被忽略了。有了类似的注释,不难搜到当时的 patch 邮件Container-init signal semantics [LWN.net]。
还有问题:为什么 C 语言就可以正常出 core 呢?它不也是自杀吗?
是不一样。细节没有研究的很清楚,大概区别如下:
Go 是自己捕获了 SIGSEGV 信号,因为它要做一层地址转换,以方便调试。之后,自己向内核报告我挂了,请杀掉我。这是明确的 suicide。
C 一般没有注册 SIGSEGV 信号的处理函数,访问非法地址后,直接被内核杀掉,不是 suicide。
内核是假定某些应用可以处理掉 SIGSEGV 的异常,所以应用可以自己捕获这个信号。但 SIGABRT 是明确主动要求终止进程的信号。
0x04 解决方法
我们不大可能改内核的行为,所以只能调整自己。只要让这个进程不是 init 进程就行了。在 k8s 下的方法就是,在 Pod Spec 中,添加 shareProcessNamespace: true,与 infra 容器共享 pid 命名空间即可,让 pause 充当 init 进程。这样就能正常 dump 出 core 了。
同事提供了另外一种方法,使用 tini 作为容器的 init 进程,tini 非常小巧,只有几十 KiB。也是一种不错的思路。
Go 进程在容器中无 coredump 产生问题分析的更多相关文章
- Docker 容器中无ss命令解决方法
在早期运维工作中,查看服务器连接数一般都会用netstat命令.其实,有一个命令比netstat更高效,那就是ss(Socket Statistics)命令!ss命令可以用来获取socket统计信息, ...
- 容器中的JVM资源该如何被安全的限制?
前言 Java与Docker的结合,虽然更好的解决了application的封装问题.但也存在着不兼容,比如Java并不能自动的发现Docker设置的内存限制,CPU限制. 这将导致JVM不能稳定服务 ...
- (spring-第1回【IoC基础篇】)Spring容器中Bean的生命周期
日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回.从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期. 人类大脑对图像的认知能力永远高于文字,因此 ...
- 在 docker 容器中捕获信号
我们可能都使用过 docker stop 命令来停止正在运行的容器,有时可能会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过从主机向容器发送信号 ...
- 在 Docker 容器中运行应用程序
案例说明 运行 3 个容器,实现对网站的监控. 三个容器的说明: 容器 web: 创建自 nginx 映像,使用 80 端口,运行于后台,实现 web 服务. 容器 mailer: 该容器中运行一个 ...
- Docker 案例: 在容器中部署静态网站
----------------知识点------------ 容器的端口映射: docker run [-P] [-p] -P,–publish-all=true | false,大写的P表示为 ...
- 隔离 docker 容器中的用户
笔者在前文<理解 docker 容器中的 uid 和 gid>介绍了 docker 容器中的用户与宿主机上用户的关系,得出的结论是:docker 默认没有隔离宿主机用户和容器中的用户.如果 ...
- 理解 docker 容器中的 uid 和 gid
默认情况下,容器中的进程以 root 用户权限运行,并且这个 root 用户和宿主机中的 root 是同一个用户.听起来是不是很可怕,因为这就意味着一旦容器中的进程有了适当的机会,它就可以控制宿主机上 ...
- 容器中的诊断与分析4——live diagnosis——LTTng
官网地址 LTTng 简介&使用实战 使用LTTng链接内核和用户空间应用程序追踪 简介: LTTng: (Linux Trace Toolkit Next Generation),它是用于跟 ...
- C#WinForm窗体内Panel容器中嵌入子窗体、程序主窗体设计例子
C#WinForm父级窗体内Panel容器中嵌入子窗体.程序主窗体设计例子 在项目开发中经常遇到父级窗体嵌入子窗体所以写了一个例子程序,顺便大概划分了下界面模块和配色,不足之处还望指点 主窗体窗体采用 ...
随机推荐
- 使用bootchart 对 高通Android 进行性能分析
使用bootchart 对 高通Android 进行性能分析 Android版本:7.0 适用平台:高通和MTK 参考: https://blog.csdn.net/qq_19923217/artic ...
- Fake权限验证小例子
前言 关于本地测试如何进行Fake权限验证 正文 在我们使用swagger调试本地接口的时候,我们常常因为每次需要填写token而耽误工作,不可能每次调试的时候都去本地测试环境请求一个token进行验 ...
- 树莓派4B-PCA9685驱动舵机
前言 不知道你们有没有遇到过这么一种情况,直接用树莓派的引脚输出PWM控制舵机,舵机是会出现抖动的.就算代码进行一定的时延迟优化还是会有影响的. 现在我们可以使用PCA9685这个模块去驱动舵机. P ...
- Mac mysql 5.7.x 设置服务开机自启动
在终端输入 sudo vi /Library/LaunchDaemons/com.mysql.mysql.plist 输入以下内容 <?xml version="1.0" e ...
- Mac mysql5.7.x my.cnf默认配置
配置如下 [client] port = 3306 default-character-set=utf8 [mysqld] character_set_server=utf8 datadir=/usr ...
- 在audio DSP中如何做软件固化
在audio DSP中, 软件的code和data主要放在3种不同的memory上,分别是片内的ITCM.DTCM和片外的memory(比如DDR)上.ITCM只能放code,DTCM只能放data, ...
- .NET 9 预览版 5 发布
微软在6月发布了.NET 9预览版的第五个版本.这个新版本的框架预计将在今年晚些时候正式发布,它是一个标准支持(STS)版本,将在2024年11月12日至2026年5月12日期间在多个操作系统上获得1 ...
- Python潮流周刊的优惠券和精美电子书(EPUB、PDF、Markdown)
Python潮流周刊从 2023.05.13 连载至今,本周即将发布第 60 期,这意味着我们又要达成一个小小的里程碑啦! 每周坚持做分享,周复一周,这对自己的精力和意志是一项不小的挑战.于是,为了让 ...
- Day 1 - 二分
整数二分 我们可以做到每次排除一半的答案,时间复杂度 \(O(\log n)\). long long l = L, r = R; while(l <= r) { long long mid = ...
- Web 开发技术栈
Web 开发技术栈 Web 是什么? 简单地说,网络是一个遍布全球的网络,它连接大量设备并允许它们相互通信 Internet 上的网站托管在称为服务器的设备上,当与 Internet 上的网页交互时, ...