Kubernetes容器生成core文件

 1、概述

  • 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文件,如果结果为0,则系统不会输出core dump文件。

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

# ulimit -c unlimited 不限制
# ulimit -c 1024      限制大小为1024
# ulimit -c 0         限制大小为0,即不输出core dump文件

centos7操作系统默认不输出core dump文件。

# ulimit -c
0
  • docker ulimit
    在docker容器中,ulimit的限制由dockerd进程控制,用户可以通过参数--default-ulimit进行配置,默认时,不会限制core文件生成大小,如果用户在dockerd进程启动时,对core文件生成大小进行了限制,用户依然可以在docker run的时候通过--ulimit参数进行修改,docker run中的--ulimit参数会优先生效。容器 core dump文件生成不依赖宿主机core文件大小限制,即使宿主机设置了不输出core dump文件,如果dockerd进程不限制容器core文件生成的话,容器照样可以输出core dump文件。

  • kubernetes ulimit
    在kubernetes中,容器core文件生成大小的限制依赖dockerd进程--default-ulimit参数对core文件生成大小的配置。(本文中以docker作为k8s容器运行时)

注意:即使在 CentOS 7 操作系统上配置了 ulimit -c 0 来限制生成 core dump 文件,容器进程仍然可能会产生 core 文件,可能有以下几种原因:

  1. Docker容器本身的配置: Docker容器的运行时环境可以影响容器内进程的资源限制。即使宿主机上已经限制了 core dump 文件的生成,容器内部的进程也可能具有自己的资源限制,可能会导致 core 文件的生成。要解决这个问题,需要确保 Docker 容器本身的配置也禁止了 core dump 文件的生成。

  2. 进程配置: 容器内的应用程序可能会在运行时修改其资源限制,覆盖了默认的 ulimit 设置。检查容器内部的应用程序是否通过编程方式设置了 core dump 行为,如果是,需要修改应用程序的配置以遵守限制。

  3. Linux内核问题: 在某些情况下,特定的 Linux 内核版本可能存在 bug,导致忽略了资源限制,从而生成 core 文件。确保你的操作系统内核是最新版本,并考虑升级或修复内核问题。

  4. 其他因素: 如果容器内的应用程序存在问题,例如 bug 或者异常情况,它们可能会导致 core 文件的生成,而无视资源限制。在这种情况下,需要排查应用程序的问题并解决之。

总之,要解决容器内产生 core 文件的问题,需要综合考虑容器运行时、容器内部进程、宿主机的设置以及应用程序的配置。确保所有层面都遵循了禁止生成 core 文件的规则,并排查可能导致异常的情况。如果问题仍然存在,可能需要更详细的调查和分析以确定问题的根本原因。

2、配置dockerd参数,限制docker生成core文件

在centos7安装完docker后,通过systemctl进行管理,修改其参数即修改相应的serivce配置文件。
可以通过systemctl cat docker命令查看配置文件位置及配置文件内容,其中docker配置文件位置为:/usr/lib/systemd/system/docker.service

修改步骤:

打开文件,编辑ExecStart项,如限制core文件生成大小为0,则在该项后边添加--default-ulimit core=0:0参数,其他参数保持不变,修改后如下所示:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit core=0:0
  • 重新加载docker.service配置文件
# systemctl daemon-reload
  • 重启docker服务
# systemctl restart docker
  • 查看重启后的配置参数
# ps -ef | grep dockerd
root      1436     1 17 10:29 ?        00:00:01 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit core=0:0

3、验证

1)、dockerd限制core文件生成大小为0,docker run默认启动容器,容器中限制core文件的大小为0。

# docker run -it --name=core-dump-test tomcat bash
root@a87b45dcf45b:/usr/local/tomcat# ulimit -c
0 

2)、dockerd限制core文件生成大小为0,docker run通过--ulimit修改为不限制,容器中不限制core文件的大小。

# docker run -it --name=core-dump-test-2 --ulimit core=-1 tomcat bash
root@c37e89ce47b2:/usr/local/tomcat# ulimit -c
unlimited

3)、dockerd限制core文件生成大小为0,kubernetes启动容器,容器限制core文件生成大小为0 。(容器core文件生成大小的限制依赖dockerd进程)

编写yaml文件core-test.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: core-test
spec:
  nodeSelector:
    kubernetes.io/hostname: kubetest-2
  containers:
  - name: ubuntu
    image: ubuntu:12.04
    command: ["/bin/sleep","3600"]

创建pod,并进入容器,并验证core文件大小的限制:

# kubectl create -f core-test.yaml
pod "core-test" created
# kubectl exec -it core-test bash
# ulimit -c
0

4)、dockerd不限制core文件生成大小,kubernetes启动容器,容器不限制core文件的大小

修改docker.service文件,将启动命令修改为如下:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit core=-1

重新启动docker,并验证启动参数是否生效:

# systemctl daemon-reload
# systemctl restart docker
# ps -ef | grep docker
root     10960     1 25 11:40 ?        00:00:01 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit core=-1

删除刚刚创建的core-test pod,并重新创建:

# kubectl delete -f core-test.yaml
pod "core-test" deleted
# kubectl create -f core-test.yaml
pod "core-test" created

进入容器并验证core文件大小的限制:

# kubectl exec -it core-test bash
# ulimit -c
unlimited

5)、dockerd不限制core文件的大小,docker run默认启动容器,容器中不限制core文件的大小

# docker run -it --name=core-dump-test3 tomcat bash
# ulimit -c
unlimited

4、设置core dump文件的输出路径

默认情况下,core dump文件生成在应用程序的主路径下边,在kubernetes环境下,一般将业务应用程序作为容器主程序,程序崩溃后容器直接退出,且被回收销毁,所以即使应用程序生成了core文件,一般你不容易拿到core文件。你可能会想,通过目录挂载的方式让core文件直接输出到本机磁盘或者网络存储上,然而一般情况下是不会将应用程序的主目录挂载出来的。所以,为了拿到core文件,我们可能需要修改core cump文件的输出路径,并将该输出路径挂载到本地磁盘或者网络存储,从而获取到相应的core文件。

在主机上执行如下命令(示例中在node1主机上执行):

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文件。

5、kubernetes容器中获取core文件

创建core-volume.yaml文件:

apiVersion: v1
kind: Pod
metadata:
  name: core-volume
spec:
  nodeSelector:
    kubernetes.io/hostname: kubetest-2
  volumes:
  - name: core-path
    hostPath:
      path: /home/core-dump
  containers:
  - name: ubuntu
    image: ubuntu:12.04
    command: ["/bin/sleep","3600"]
    volumeMounts:
    - mountPath: /tmp/cores
      name: core-path

创建并进入pod:

# kubectl create -f core-volume.yaml
pod "core-volume" created
# kubectl exec -it core-volume bash

触发当前shell终端的段错误(会自动退出终端):

# kill -s SIGSEGV $$
command terminated with exit code 139

查看/home/core-dump目录下是否生成core文件(容器实际运行的主机上查看,本例中为node1)

# ls /home/core-dump
core.5

6、总结

在实际的开发场景中,容器生成的core dump文件能够对开发人员调试定位问题提供非常大的帮助,所以在特定场合生成并留存core dump是一件必要而有意义的事情。但是一般生产环境容器是不需要生成core dump文件的,生产环境dokcerd开启core可能会造成服务器节点io负载很高,如果检测到服务器磁盘中容器下生成的core文件占用的磁盘比较大则建议把docker的core给禁用。

参考:https://cxymm.net/article/u013774469/82595988

posted @ 2022-09-15 14:04  人艰不拆_zmc  阅读(2248)  评论(0编辑  收藏  举报