Core Dump

容器化后 , 容器里面的进程如果出现 core dump , 默认情况下 ,dump 出来的文件是存放在容器内部的根目录的 。 这样会导致以下几个问题

  1. 如果 Docker 使用的 LVM 的驱动 , 每个容器默认大小只有 10G, 很容易占用了全部的容器空间 , 而导致容器不能启动 。
  2. Core Dump 文件存到容器中 , 也很容易被删除掉 , 从而不容易排查问题 。

想要解决这个问题 , 就要先了解什么是 Core Dump。

0x01 - core dump

Core dump 功能能够把进程出问题的时候的信息保存下来 , 方便我们来调试 。 触发方法 , 可以通过给某个进程发送 :code:SIGSEGV 信号

kill -SIGSEGV <pid>
ls core.<pid>

dump 出来的文件可以通过 gdb 来查看内容 , 基本使用方法如下 :

gdb /path/to/binary /path/to/core.dump.file
  • bt commands to get the information.
  • bt full commands to get the detailed backtrace
  • info locals to see all the local variables.
  • print variable-name to print the variables
  • frame frame-number to go to desired frame number.
  • up n and down n commands to select frame n frames up and select frame n frames down respectively.

默认情况下 , 生成的转存文件保存在当前目录下面 , 并且每个文件很大 。 从而占用大量空间 。 通过 ulimit 可以控制 , 但是需要注意的是这种方法只能控制 单个 core 文件的大小 , 并不能控制总 core dump 文件的大小或个数 , 而且也有可能生成不完整的 core dump 文件 。 方法如下 :

//  单位是  KB, 0  意味着关闭 
ulimit -c 0
// or
ulimit -c 100
// or
ulimit -c ulimited

0x02 - 容器化

容器里面 ,ulimit 是由 systemd 及 docker 共同控制的 。 systemd 的 docker.service 可以控制 dockerd 进程的上限

[Service]
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

与此同时 , docker 也可以控制单个容器的 ulimit 大小

docker run --ulimit core=1024000 centos:7

或在 dockerd 启动的时候 , 设置所有容器的默认的 ulimit 大小

dockerd --ulimit core=1024000

但是 , 容器内的进程 core dump 的时候 , 还是保存到了容器内部 , 会严重影响 docker 的运行 。 然后完全关掉 core dump 功能也不是一个好办法 。 这个时候就需要借助 systemd 来转存 。

0x03 - Systemd

现在主流的操作系统都已经转到了 systemd, 所在这个办法适用于大部分操作系统 。

自从 linux 2.6.19, 支持通过 /proc/sys/kernel/core_pattern 来配置转存的 core dump, 方法如下 :

$ cat << EOF >>  /etc/sysctl.conf
kernel.core_pattern = |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %e
EOF

这个是配置到宿主机的内核上 , 因为容器共用宿主机的内核 , 所以当容器里面的进程需要 core dump 时 , 会转存到宿主机上的 systemd。 而且 systemd 在保存的时候 , 经过了压缩 , 还可以控制存储空间的总大小 , 从而避免 core dump 吃掉太多硬盘空间 。 具体参看 /etc/systemd/coredump.conf

0x04 - coredumpctl

转存到宿主机上 , 可以通过 coredumpctl 来进程查看 , 基本操作如下 。

coredumpctl list
coredumpctl dump <match>
coredumpctl info <match>
coredumpctl gdb <match>

使用这种方法 , 可以避免 Core Dump 占用容器空间有问题 , 同时还可以保存转存的文件 , 方便之后的调试查看 。

Comments