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 产生问题分析的更多相关文章

  1. Docker 容器中无ss命令解决方法

    在早期运维工作中,查看服务器连接数一般都会用netstat命令.其实,有一个命令比netstat更高效,那就是ss(Socket Statistics)命令!ss命令可以用来获取socket统计信息, ...

  2. 容器中的JVM资源该如何被安全的限制?

    前言 Java与Docker的结合,虽然更好的解决了application的封装问题.但也存在着不兼容,比如Java并不能自动的发现Docker设置的内存限制,CPU限制. 这将导致JVM不能稳定服务 ...

  3. (spring-第1回【IoC基础篇】)Spring容器中Bean的生命周期

    日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回.从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期. 人类大脑对图像的认知能力永远高于文字,因此 ...

  4. 在 docker 容器中捕获信号

    我们可能都使用过 docker stop 命令来停止正在运行的容器,有时可能会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过从主机向容器发送信号 ...

  5. 在 Docker 容器中运行应用程序

    案例说明 运行 3 个容器,实现对网站的监控. 三个容器的说明: 容器 web: 创建自 nginx 映像,使用 80 端口,运行于后台,实现 web 服务. 容器 mailer: 该容器中运行一个 ...

  6. Docker 案例: 在容器中部署静态网站

    ----------------知识点------------ 容器的端口映射: docker  run  [-P] [-p] -P,–publish-all=true | false,大写的P表示为 ...

  7. 隔离 docker 容器中的用户

    笔者在前文<理解 docker 容器中的 uid 和 gid>介绍了 docker 容器中的用户与宿主机上用户的关系,得出的结论是:docker 默认没有隔离宿主机用户和容器中的用户.如果 ...

  8. 理解 docker 容器中的 uid 和 gid

    默认情况下,容器中的进程以 root 用户权限运行,并且这个 root 用户和宿主机中的 root 是同一个用户.听起来是不是很可怕,因为这就意味着一旦容器中的进程有了适当的机会,它就可以控制宿主机上 ...

  9. 容器中的诊断与分析4——live diagnosis——LTTng

    官网地址 LTTng 简介&使用实战 使用LTTng链接内核和用户空间应用程序追踪 简介: LTTng: (Linux Trace Toolkit Next Generation),它是用于跟 ...

  10. C#WinForm窗体内Panel容器中嵌入子窗体、程序主窗体设计例子

    C#WinForm父级窗体内Panel容器中嵌入子窗体.程序主窗体设计例子 在项目开发中经常遇到父级窗体嵌入子窗体所以写了一个例子程序,顺便大概划分了下界面模块和配色,不足之处还望指点 主窗体窗体采用 ...

随机推荐

  1. 阿里云 腾讯云上搭建Samba服务

    对于这个主题,鄙人走了很久的坑,最后很抱歉的告诉你. 运营商把Samba服务的端口全部封掉了,所以你根本就没办法访问! 那怎么办,我Windows空间不够,又不想浪费云上的资源. 那就用FTP代替它吧 ...

  2. MoneyPrinterPlus:AI自动短视频生成工具-腾讯云配置详解

    MoneyPrinterPlus可以使用大模型自动生成短视频,其中的语音合成和语音识别部分需要借助于一些第三发云厂商的语音服务. 很多小伙伴可能不知道应该如何配置,这里给大家提供一个详细的腾讯云语音服 ...

  3. 在Gerrit中修改project.config

    reference:https://blog.bruin.sg/2013/04/19/how-to-edit-the-project-config-for-all-projects-in-gerrit ...

  4. 分享两个内置Google广告位的Typecho主题

    前言 很多项目的开始都是因为情怀和热爱,"为爱发电"是一件很值得尊敬的事情,然而大量"为爱发电"的项目最后却不得不因"难以为继"而被迫停服. ...

  5. 没想你是这样的AI。。。

  6. Java常用JDK类库和第三方类库

    以下是收集的一些有用的第三方库,Java开发人员可以在其应用程序中使用它们来完成许多有用的任务.为了使用这些库,Java开发人员也应该熟悉这些类库. jdk自带的常用类库 java.lang包 jav ...

  7. 洛谷P1043

    [NOIP2003 普及组] 数字游戏 题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前 ...

  8. 用 Git 操作的数据库?这个项目火了!

    # 用 Git 操作的数据库?这个项目火了!> 超级特别又实用的数据库,快来补课!Git 是一个开源的分布式版本控制系统,可以敏捷高效地管理代码,让项目代码支持同时存在多个不同的版本和分支,是程 ...

  9. oeasy教您玩转vim - 9 - # 换行插入

    插入新行 回忆上节课内容 上上次是 i.I 在光标前面插入 又加了 a.A 可以在光标后面插入 a 是在光标后插入 A 是在当前行最后插入 关于插入,还有什么命令吗? 我们继续去查阅 help :h ...

  10. 毕设项目:springboot+vue实现的在线求职平台

    一.前言 随着信息技术的飞速发展和互联网的普及,线上求职已成为众多求职者和企业招聘的重要渠道.为满足市场需求,我们利用Spring Boot和Vue技术栈,开发了一款功能全面.用户友好的在线求职平台. ...