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容器中嵌入子窗体.程序主窗体设计例子 在项目开发中经常遇到父级窗体嵌入子窗体所以写了一个例子程序,顺便大概划分了下界面模块和配色,不足之处还望指点 主窗体窗体采用 ...
随机推荐
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Asset Store Kit
1.问题描述 使用关键资产API需要配置SystemCapability.Security.Asset,但不知道syscap.json文件应该配置在哪里,文档也没找到. 解决方案 新增关键资产等API ...
- 图最短路径之BellmanFord
Bellman–Ford Algorithm 算法参考地址:Bellman–Ford Algorithm | DP-23 - GeeksforGeeks 算法的简介 在图中给定一个图形和一个源顶点 s ...
- Kubernetes(四)Pod详解
Pod详解 本章主要介绍Pod资源的各种配置(yaml文件)和原理 1. Pod介绍 如上图所示,每个Pod中都可以包含一个或多个Container,这些Containers 可以分为2类: 用户程序 ...
- c/c++:带有返回类型的函数没有return语句会怎么样?
c/c++:带有返回类型的函数没有return语句会怎么样 背景 机器有时候启动的时候发现异常,跟踪了代码发现,有人在写一个int函数的时候,有一个分支没有return: 参考:https://www ...
- ReST,以及RESTful的 简单介绍
什么是 ReST 阮一峰说的比较清楚,具体见他的博客文章. 二.名称 ReST这个词,是[Roy Thomas Fielding](http://en.wikipedia.org/wiki/Roy_F ...
- 三层交换机vlan间路由
sw1: [Huawei]vlan batch 10 20 [Huawei]int e0/0/1 [Huawei-Ethernet0/0/1]port link-type access [Huawei ...
- .Net Core WebAPI Swagger Failed to load API definition
1.错误现象 1.1.写完一个测试API,Ctrl+F5运行,提示错误: Failed to load API definition.(如下图) 1.2.点击 http://localhost:516 ...
- [oeasy]python0028_直接运行_修改py文件执行权限_设置py文件打开方式
直接运行 回忆上次内容 我们把两个程序整合起来了 可以持续输出当前时间 每秒都更新 编辑 但是我想在 shell 里面 只输入文件名(./sleep.py)并回车 就能不断输出时间 可能吗? ...
- Python elasticsearch-py类库基础用法
实践环境 https://pypi.org/project/elasticsearch/ pip install elasticsearch==7.6.0 离线安装包及依赖包下载地址: https:/ ...
- git常用代码
//当前文件夹删除的文件恢复git reset Head .// 查看所有分支git branch// 查看本地分支 对应的远程分支git branch -vv//git branch -vv//创建 ...