物理主机进程崩溃取证:建立可验证的 core dump 采集链

物理主机进程崩溃取证:建立可验证的 core dump 采集链

业务进程突然退出,服务重启只能恢复运行,无法解释崩溃原因。日志若只留下信号编号,定位还需要崩溃时的调用栈和对应构建。本文在 Ubuntu Server 24.04 上建立受控的核心转储采集链,先用隔离进程验收,再决定是否为业务服务启用。

AMDSSH 物理主机可选 128GB 或 256GB ECC 内存,但进程转储不应按整机容量无条件保存。core 文件可能包含密码、请求正文与业务数据;采集范围、容量限制和访问权限必须一起配置。

一、确认崩溃类型与现有采集器

付款后在控制台查看连接凭据,以 SSH 登录。以下操作需要管理员权限,测试前先确认系统、磁盘空间和核心转储入口:

cat /etc/os-release
df -h /var/lib
sysctl kernel.core_pattern
sudo journalctl -b -p warning --no-pager

kernel.core_pattern 以竖线开头时,内核把转储交给用户态处理程序,不是直接写进当前目录。系统可能已有其他崩溃收集器,必须记录原值和相关软件包,不能叠加两套入口后假定都能工作。

先区分主动退出、信号终止和内存不足杀进程。SIGSEGV、SIGABRT 通常触发核心转储,SIGKILL 不会。服务状态显示异常退出,并不等于已经生成可下载的文件。

core dump 是进程内存证据,不是普通运行日志。不得放入公开目录,也不应未经检查就附到工单或代码仓库。

安装本文使用的工具;若包管理器提示替换已有收集器,应先核对影响,再明确选择一种机制:

sudo apt-get update
sudo apt-get install systemd-coredump gdb gcc
sysctl kernel.core_pattern
systemctl status systemd-coredump.socket --no-pager

安装后入口应指向 systemd 的转储处理程序。套接字负责接收,处理服务按需启动;没有常驻采集进程不代表功能失效。

二、给采集链设置容量边界

创建 /etc/systemd/coredump.conf.d/60-controlled-capture.conf,写入以下配置:

[Coredump]
Storage=external
Compress=yes
ProcessSizeMax=256M
ExternalSizeMax=256M
MaxUse=512M
KeepFree=2G

这是小型测试进程的验收配额,不是大内存业务的推荐值。ProcessSizeMax 限制参与处理的转储大小,ExternalSizeMax 限制外部保存大小;超过限制时可能只有事件元数据,没有完整内存文件。

MaxUse 与 KeepFree 用于控制外部转储目录占用,不是磁盘预留保证,也不控制日志数据库的容量。并发崩溃仍可能形成空间压力,需要同时观察所在文件系统余量。

配置由后续处理进程读取,可用下面的命令核对合并结果:

systemd-analyze cat-config systemd/coredump.conf

业务启用前,应测量代表性进程的内存规模和实际转储大小,再调整上限。不能因为测试程序通过,就认为占用大量内存的数据库也能完整保存。

三、用隔离服务验证真实崩溃

构建不含业务数据的测试程序

在 /tmp/crash-lab.c 写入最小程序:

#include <stdlib.h>

int main(void)
{
    abort();
}

建立专用系统账户并编译,-g 保留调试信息,-O0 便于观察测试调用栈:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin crashlab
sudo install -d -m 0755 /usr/local/libexec
sudo gcc -g -O0 -o /usr/local/libexec/crash-lab /tmp/crash-lab.c

账户若已存在,先确认其用途,不重复创建。随后建立 /etc/systemd/system/crash-lab.service:

[Unit]
Description=Isolated core dump capture test

[Service]
Type=oneshot
User=crashlab
ExecStart=/usr/local/libexec/crash-lab
LimitCORE=infinity
Restart=no

此处的 infinity 只开放测试服务的进程限制,采集器仍受上一节配额约束。不要把它写成所有服务的全局默认值。

sudo systemctl daemon-reload
sudo systemctl start crash-lab.service
sudo systemctl status crash-lab.service --no-pager
sudo coredumpctl --no-pager list /usr/local/libexec/crash-lab

启动命令报告失败是预期结果。应看到与测试可执行文件匹配的崩溃记录;若没有,依次检查入口、服务限制、采集器日志和磁盘空间,而不是对线上进程发送崩溃信号。

四、验收转储文件与调试材料

从列表记录本次测试 PID,在同一个管理员 shell 中输入,导出到专用私有目录:

sudo -i
read -r -p 'Crash PID: ' CRASH_PID
umask 077
install -d -m 0700 /root/crash-evidence
coredumpctl info "$CRASH_PID"
coredumpctl dump "$CRASH_PID" --output=/root/crash-evidence/test.core
gdb -q -batch \
  -ex 'set pagination off' \
  -ex 'thread apply all bt' \
  /usr/local/libexec/crash-lab /root/crash-evidence/test.core
exit

先核对事件时间、可执行文件、信号和存储状态,避免 PID 重用时取错记录。验收结果应显示 SIGABRT,调用栈可关联到测试程序的 main;系统库帧缺少源码,不妨碍验证测试链。

只有元数据、文件不可导出或出现截断提示,都不能算完整采集成功。coredumpctl 能列出事件,也不保证外部文件仍然存在。

真实业务还需归档崩溃时的可执行文件、共享库和对应调试符号。更新后的同名二进制不等于原构建,可用 readelf -n 核对 Build ID,并记录包版本与构建标识。

不要直接使用 bt full 输出局部变量。先查看基本调用栈;确需检查变量时,在受限环境操作,并对导出的文本逐项审查。复制二进制也应保存哈希,避免分析期间材料被替换。

五、业务接入与撤销验收

为业务服务启用时,通过该服务自己的 drop-in 设置 LimitCORE,执行 daemon-reload 后,在受控变更中重启服务。已有进程不会因为配置文件修改就自动获得新限制,应检查实际进程的 /proc/PID/limits。

接入检查至少包括四项:

测试结束后,删除测试服务文件、程序与源码,执行 daemon-reload 和 reset-failed。测试转储按 coredumpctl info 给出的实际路径单独处理,不使用通配符清空整个转储目录。

如撤销采集策略,移除本文新增的配置文件;如需恢复原采集器,使用软件包配置恢复并再次核对 kernel.core_pattern,不能凭记忆拼接入口。最后记录一次完整验收:崩溃事件可查询、文件可导出、调用栈对应正确构建、材料访问受限。这样留下的是可复核的故障证据,而不是无人验证的开关。

常见问题

启用核心转储后,所有异常退出都会留下 core 文件吗?

不会。程序主动退出和 SIGKILL 通常不产生核心转储;具有转储动作的信号也可能受进程限制、采集器策略、文件大小与磁盘空间影响。应使用隔离测试进程验证整条链。

GDB 能打开 core 文件,是否就说明取证完整?

不能。还需匹配崩溃时的可执行文件、共享库与调试符号,并确认转储没有被截断。只有调用栈能对应到正确构建,才具备可靠定位条件。

EPYC 7543P 独享物理主机$450.2/月起

从资源规划进入整机配置

机型与选配按月合计计费,配置页列出完整明细;连接凭据在交付后的控制台查看。