使用 `apport` 在 Ubuntu 容器内自动收集 core dump
解读
国内线上环境 90% 以上跑的是 Ubuntu 20.04/22.04 容器镜像,业务进程一旦崩溃,宿主机默认的 systemd-coredump 或 ABRT 对容器内 PID Namespace 不可见,导致 “容器里段错误,宿主机看不到 core”。面试官真正想确认的是:
- 你是否理解 容器 PID/Mount Namespace 隔离 导致 apport 传统机制失效;
- 能否在不破坏镜像轻量原则的前提下,让 apport 把 core 自动落到 宿主机可采集 的路径,并兼容国内私有云常用的 Jenkins+Harbor+ELK 闭环;
- 是否知道 国内监管要求(等保 2.0)对“故障可追溯”的审计点,core 文件必须带容器标签、构建版本、时间戳。
知识点
- apport 触发链:/proc/sys/kernel/core_pattern → apport → /var/crash/xxx → whoopsie(若启用);
- 容器 Namespace 隔离:Mount Namespace 让 /var/crash 写在容器可写层,宿主机默认拿不到;
- core_pattern 管道限制:内核要求管道程序必须在宿主机根文件系统可见,否则返回 EACCES;
- Ubuntu 最小镜像(ubuntu:22.04)默认不带 apport,需显式安装 apport 与 apport-retrace;
- 国内镜像源(清华、阿里、中科大)对 apport 的 GPG 签名与官方一致,可放心替换;
- 安全加固:core 文件可能包含敏感内存,需 400 权限 + 宿主机临时加密盘;
- 等保审计:core 文件名必须包含 container_id、image_tag、git_commit 三段信息。
答案
-
构建阶段:在 Dockerfile 中 仅安装 apport 与调试符号,不启动服务,保持镜像最小。
FROM ubuntu:22.04 RUN sed -i 's@http://archive.ubuntu.com@http://mirrors.aliyun.com@g' /etc/apt/sources.list \ && apt-get update \ && apt-get install -y --no-install-recommends apport apport-retrace gdb \ && apt-get clean && rm -rf /var/lib/apt/lists/* -
运行阶段:
a. 在宿主机准备 全局管道脚本 /opt/apport-wrapper.sh,内容如下:#!/bin/bash # 接收内核管道传来的 core CONTAINER_ID=$(cat /proc/$PPID/cgroup | grep -oP 'docker/+\K[0-9a-f]{64}' | head -n1) IMAGE_TAG=$(docker inspect -f '{{index .Config.Labels "org.opencontainers.image.version"}}' $CONTAINER_ID) GIT_COMMIT=$(docker inspect -f '{{index .Config.Labels "git.commit"}}' $CONTAINER_ID) TIMESTAMP=$(date +%Y%m%d%H%M%S) CORE_FILE="/cores/core_${CONTAINER_ID:0:12}_${IMAGE_TAG}_${GIT_COMMIT}_${TIMESTAMP}" cat > $CORE_FILE chmod 400 $CORE_FILEb. 宿主机 echo 管道路径:
echo "|/opt/apport-wrapper.sh %p %s %c %d %P" > /proc/sys/kernel/core_patternc. 启动容器时 挂载 /cores 并继承 core_pattern:
docker run -d --rm \ --ulimit core=-1 \ -v /cores:/cores \ -v /proc/sys/kernel/core_pattern:/proc/sys/kernel/core_pattern:ro \ --security-opt seccomp=unconfined \ --name myapp \ myimage:latestd. 容器内 确认 apport 被禁用,避免双重处理:
echo "enabled=0" > /etc/default/apport -
验证:容器内执行
kill -SIGSEGV $$,宿主机 /cores 立即出现 带容器 ID、镜像版本、commit 的 core 文件,满足国内审计要求。
拓展思考
- 若集群使用 containerd + cri-o,需把管道脚本放到 kubelet 根路径 /var/lib/kubelet/core_pattern,并通过 Kubernetes hostPath + DaemonSet 统一维护,避免逐节点手工配置;
- 对 多租户场景,可在管道脚本中调用 国密 SM4 加密 后再落盘,防止 core 被其他租户截获;
- 结合 Jenkins 流水线,在构建时把
git.commit与build.number注入 OCI Label,core 文件名即天然携带 CI 追溯链,后续通过 ELK Filebeat 采集 /cores,即可在 Kibana 一键定位 “哪次构建、哪行代码” 引发崩溃; - 若业务对延迟敏感,可把 coredump_filter 置为 0x33 只 dump 匿名私有段,降低 IO 抖动,满足国内金融级 RT<5ms 要求。