基础概念

  • core dump
    在绝大多数GNU/Linux系统中,当应用程序发生没有捕获的异常信号ARORT/SEGV时,系统会终止当前进程,并生成core dump文件,它一般在程序执行的主目录下,通常命名为core或者core.PID。通常情况下core dump包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等。在实际的开发场景中,这些信息能够对开发人员调试定位问题提供非常大的帮助,所以在特定场合生成并留存core dump是一件必要而有意义的事情。

  • ulimit
    ulimit是GNU/Linux的一个命令行工具,用于显示或设置用户可以使用的资源限制。在本例中,我们主要关注core文件大小限制的设置或查看。
    使用ulimit -c查看对core文件大小的限制,例如:

# ulimit -c
unlimited

unlimited表示没有限制,这意味着当应用程序异常时,系统能够输出任意大小的core dump文件,如果结果是非零数字,则表示系统只能输出限制大小的core dump文件,如果结果为零,则系统不会输出core dump文件。

设置对core文件大小的限制,如:

# ulimit -c unlimited 不限制
# ulimit -c 1024      限制大小为1024
# ulimit -c 0         限制大小为0,即不输出core文件
  • docker ulimit
    在docker容器中,应用程序随着容器的启动而启动,我们要想在应用程序启动之初就设置好ulimit的设置,可以通过docker run中的--ulimit参数进行设置。

实验步骤

知道了以上基础概念之后,我们可以开始尝试在docker容器中生成core dump文件了,步骤如下:
1、启动容器

docker run -it -d --name=core-dump-test --ulimit core=-1 ubuntu:12.04 /bin/sleep 3600

2、进入容器

docker exec -it core-dump-test bash

3、在容器中查看core文件大小限制

# ulimit -c
unlimited

说明没有core文件大小限制。

3、触发当前shell终端的段错误

kill -s SIGSEGV $$

此时你会发现你刚刚执行的shell终端已经关闭。

4、重新进入容器

docker exec -it core-dump-test bash

查看生成的core文件:

ls | grep core

你会在当前目录下发现刚刚生成的core文件。

最佳实践

在容器中调试应用程序

在这种方式下,你可以按如下方式启动容器,然后进入容器里边进行gdb调试:

docker run -it -d --name=core-dump-test --ulimit core=-1 --security-opt seccomp=unconfined ubuntu:12.04 bash

在这种方式下,docker容器的主进程是bash,你可以再容器里边调试你自己的应用程序,你自己的应用程序中断不会导致容器的退出,生成的core dump默认就在你应用程序启动的主路径下,调试起来非常方便。

在其他环境调试应用程序

在实际的应用场景中,更多的情况下,你的应用程序是作为容器主进程的,当应用程序崩溃的时候,容器也会退出,你基本上很难在容器进行调试。另外,线上容器一般比较精简,肯能不包含你的所需的调试工具,所以你可能需要在其他环境下进行相关调试,那么就需要获取到相关的core dump文件。

1、从容器中拷贝core dump文件

如果你明确知道你的应用程序的core dump文件名称和位置,那么你可以从容器中直接拷贝core dump文件,即使这个容器已经异常退出。例如,core dumo文件在容器core-dump-test中的/tmp/cores路径下,名为core.1,那么你可以用如下命令将core dump拷贝到当前主机的当前目录:

docker cp core-dump-test:/tmp/cores/core.1 .
2、通过目录挂载方式将core dump文件输出到主机目录

通常情况下,你可能既不知道core dump文件的路径在哪里,也不知道core dump文件的确切名称是什么,所以你可能需要设置core dump的输出路径和文件命名规则,并将该路径挂载到本机,实现core dump文件自动输出到主机目录,然后你就可以拿这些core dump文件大大展身手,进行你想要的调试了。

设置core dump文件的输出路径
在主机上执行如下命令:

echo "/tmp/cores/core.%p" > /proc/sys/kernel/core_pattern

以上,将core dump的输出路径修改为/tmp/cores,后续容器中的应用程序core dump文件也将输出到容器的/tmp/cores文件,因为在容器中读取的/proc/sys/kernel/core_pattern文件实质上就是主机的/proc/sys/kernel/core_pattern文件。

下边,我们将容器的/tmp/cores挂载到主机的/var/tmp/cores,那么容器中生成的core dump文件将自动输出到主机的/var/tmp/cores目录。docker容器的启动示例如下:

docker run -it -d --name=core-test --ulimit core=-1 -v /var/tmp/cores:/tmp/cores core-test:v1 /test/core-test

其中镜像core-test:v1是基于ubuntu:12.04镜像构建的一个测试镜像,在/test/core-test程序中中调用abort()模拟程序崩溃生成core dump文件。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐