Background

工作中遇到这样一个问题,运行环境为Docker容器,由于设置了容器的磁盘大小,但是没有设置core dump file的大小(默认为unlimited),当程序收到SIGABRT信号退出时,磁盘容易被撑满。

所以决定不让其产生core dump file。那么问题来了,在Docker容器环境下,该如何实现?

以下记录了围绕这个目的所做的一些尝试与遇到的问题。

Try and try

Method 1: 使用systemd [failed]

Systemd’s default behavior is to generate core dumps for all processes in /var/lib/systemd/coredump. This behavior can be overridden by creating a configuration snippet in the /etc/systemd/coredump.conf.d/ directory with the following content.

1
2
3
/etc/systemd/coredump.conf.d/custom.conf
[Coredump]
Storage=none

然后重载systemd的配置

systemctl daemon-reload

但是,结果是我们会得到一个诸如Failed to get D-Bus connection: Operation not permitted的error。根据14年的issue Failed to get D-Bus connection: No connection to service manager - CentOS 7 #7459,我们并不能在容器中直接使用systemctl,而是需要用我们自己的process manager(supervisor)来管理进程。

这将带来额外更多的工作量,决定放弃这种方法。

Method 2: 使用ulimit,更改/etc/security/limits.conf配置 [failed]

* hard core 0

一般来说,在limits.conf文件中添加如上更改,便不会产生core file。然而我们restart容器之后,发现文件虽然确实被修改过,但是通过ulimit -c发现并没有作用。

根据 Stackoverflow Ref, limits.conf文件是被pam_limits.set读取的, 我们修改/etc/pam.d/su,使得

session         required        pam_xauth.so

然而依然没有任何作用,或许我们还可以尝试通过--priviliged,挂载文件系统等等方法来尝试,但这样依然代价太大,我们放弃。

Method 3:docker run --ulimit core=0:0 [succeed]

通过起容器时添加--ulimit标签无疑是最方便的做法,而最重要的是,它成功了!

当我们进入容器执行ulimit -c,返回0。恭喜我们,目标达成!

Verify and experiment

现在我们想人为造一点core dump出来,来验证这个方法确实起作用了,该怎么办呢?

Method 1:gdb and generate-core-file [failed]

或许我们可以用gdbgenerate-core-file工具。

首先我们执行一个简单的线程

1
2
3
4
5
6
7
8
test.py
#!/usr/bin/env python

import time

while True:
        print 'hi'
        time.sleep(2)

然后通过ps -ef找到这个进程的PID,执行gdb -p PID,然而这时,问题又来了:

1
2
3
4
Attaching to process 145
ptrace: Operation not permitted.
(gdb) generate-core-file
You can't do that without a process to debug.

而通过这个开了又关关了又开的长长的GitHub Issue apparmor denies ptrace to docker-default profile #7276,我大概知道,还是找个别的方法更省力。

Method 2: kill -ABRT PID [succeed]

通过man文档,我们知道这几个signal可以产生core dump文件:

1
2
3
4
   SIGQUIT       3       Core    Quit from keyboard
   SIGILL        4       Core    Illegal Instruction
   SIGABRT       6       Core    Abort signal from abort(3)
   SIGFPE        8       Core    Floating-point exception

这时我们发现,当ulimit -c设为0时,确实不会产生core dump文件;

而当我们把ulimit -c设为4时,产生了core dump,使用gdb ./test.py core.PID debug时,却发现了这样的warning。

BFD: Warning: /root/core.129 is truncated: expected core file size >= 2945024, found: 5488.

我们docker run -it --ulimit core=2945024 ...增加ulimit -c的大小,这次得到大小为2.9M的core dump file,使用gdb也再没有问题。

看来,一个完整的core file至少为2945024 byte,当我们设置的ulimit -c的值小于它时,可能得到不完整的文件,如果设置的更小,比如小于3 * 1024,便不会产生文件,设置为0,便是禁止了。

Conclusion

这便是我解决这个问题的一个过程吧,其中踩过了一些坑,也学到了很多新东西,希望能对你也有帮助。 以下是一些解决问题过程中参考过的,觉得有价值的链接,enjoy!