Docker 退出 137,OOMKilled 却为 false:区分 SIGKILL 与内存不足
Docker 退出 137 并不直接证明内存耗尽。结合容器状态、事件、停止操作与实际宿主机记录,区分强杀、停止超时和 OOM,再决定修复与验收范围。
容器运行一段时间后变成 Exited (137),docker inspect 中的 OOMKilled 却是 false。这两项并不矛盾:137 通常对应进程被 SIGKILL 终止,内存不足只是可能触发强制终止的一种原因。手动强杀、停止超时等也可能产生这个退出码。
本文针对 Docker 的 Linux 容器。应用也能主动返回 137,因此只有退出码、没有事件和日志时,还不能确定是谁终止了进程,更不能直接认定需要加内存。
保存故障容器的状态,再核对同一时间段
先不要删除或重建容器。以下只读命令中的 db-app 是示例名称,应换成发生故障的那个容器:
docker inspect --format '{{json .State}}' db-app
docker inspect --format '{{.Id}}' db-app
docker logs --timestamps --tail 200 db-app
记录容器 ID、ExitCode、OOMKilled、StartedAt 和 FinishedAt。如果自动重启已开始,当前状态可能属于后一次运行,应结合先前事件判断,不能把不同运行时间的值拼成同一次故障。
OOMKilled=false 表示当前状态没有记录为 OOMKilled;它不能代替对宿主机、其他进程及历史记录的检查。退出前应用日志戛然而止,也只说明它没留下完整退出过程,不能单独证明内存耗尽。
可以查看故障附近的 Docker 事件。下面的时间是示例,需改成覆盖实际故障的时间段;Z 表示 UTC:
docker events --filter container=db-app \
--since '2026-10-05T12:00:00Z' \
--until '2026-10-05T12:15:00Z'
重点核对 kill、oom、die、stop 与退出时间,kill 事件中的信号也有帮助。事件只保留最近 256 条,查询没有结果不等于事件从未发生;部署记录、daemon 日志和宿主机记录可能需要一起查看。
出现在发布或停止之后:先查停止超时
Docker 停止容器时,通常先向主进程发送 SIGTERM,也可能使用镜像或容器配置指定的停止信号。等待超时后仍未退出,才发送 SIGKILL。因此,一次常规停止也可能最终留下 137。
如果故障时间紧跟发布、重启脚本或管理平台的停止操作,而且事件显示先发停止信号、随后出现信号 9,应检查应用是否收到停止信号,以及退出过程是否超过配置的等待时间。按应用支持的方式处理停机和超时,比先扩大内存更符合这条证据。
调整停止等待时间会延长发布或维护过程,不能掩盖死锁或永不退出的进程。先保存现有启动与停止配置,在可接受的窗口验证;不符合预期时恢复原配置。数据库容器尤其需要遵循其正常关闭与数据恢复流程,不要用强杀来测试“能否自动重启”。
有 OOM 证据:再决定调整哪一层资源
如果同一容器、同一时段存在 oom 事件,或运行 Docker 的 Linux 主机内核记录了对应进程被 OOM killer 终止,再检查容器内存限制、实际内存峰值及宿主机其他负载。
容器达到自己的限制,与整个宿主机内存不足,需要不同的处理。只增加单个容器限额可能挤占其他服务;资源已足够却持续增长时,还要检查应用内存使用。不要为保住一个容器关闭 OOM 保护,也不要在没有容量判断时直接开启或扩大 swap。
Docker Desktop 中的 Linux 容器运行在虚拟机内,物理机的剩余内存并不等于虚拟机可用内存。Desktop 产品版本与其中的 Engine 版本也不是同一组版本号,核对缺陷或配置边界时应分别记录。
证据不足时,先保留下一次退出记录
没有 OOM、停止或强杀记录时,137 只能作为线索。保留应用日志、Docker 事件与实际 daemon 所在主机的监控,再关联下一次退出;不要凭同一个数字套用别人的版本缺陷或磁盘故障结论。
修复后的成功标准应与已确认原因相对应:正常停止时应用能完成关闭,不再等到强杀;确认 OOM 的场景则需在代表性负载下检查峰值、限额和宿主机余量。容器重新启动成功,只证明当前能启动,不能证明上一次的退出原因已经消失。


