Docker容器突然退出,查看状态时出现 OOMKilled=true 或退出码137,很容易直接归因于内存不足。两者有关联,但不能完全画等号:137表示进程收到SIGKILL,而OOMKilled才是Docker记录的内存回收结果。
先保存容器状态、内核日志和资源限制,再决定扩容或修改参数。 只重启容器可能暂时恢复,却会丢失最有价值的现场证据。

先确认是不是OOM杀死了容器
用容器名称或ID读取退出状态:
docker inspect --format '{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}' app
docker ps -a --filter name=app --no-trunc
若 OOMKilled 为 true,说明容器内进程因内存不足被内核终止。退出码137只能说明收到了SIGKILL,也可能来自 docker kill、超时强制停止或外部管理程序。
同时查看宿主机内核日志
容器记录之外,还要检查宿主机是否发生全局OOM:
journalctl -k --since '-30 min' --grep='Out of memory|Killed process|oom-kill'
dmesg -T | grep -Ei 'out of memory|killed process|oom-kill'
需要root权限才能读取完整内核日志。若日志显示Docker之外的进程也被终止,问题可能是宿主机整体内存耗尽,而不只是单个容器限制过小。
核对容器实际内存限制
查看运行时限制和当前用量:
docker inspect --format 'memory={{.HostConfig.Memory}} swap={{.HostConfig.MemorySwap}}' app
docker stats --no-stream app
free -h
数值以字节显示,0表示未设置对应硬限制。未限制容器并不等于不会OOM,它可能持续占用宿主机内存并触发系统级回收。 free 在容器内看到的交换空间也不一定代表该容器实际可用额度。
找出内存增长来自哪里
结合应用日志、请求量和进程指标判断是峰值、泄漏还是缓存策略:
docker logs --since 30m app
docker top app -eo pid,ppid,cmd,rss,vsz
docker stats --no-stream --format 'table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}'
重点核对批处理、并发、JVM堆、PHP worker、数据库缓存和一次性大对象。容器被杀后指标会归零,因此应把内存使用率接入持续监控,而不是只看故障后的瞬时值。
谨慎调整memory与swap
确认业务确实需要更多内存后,可以调整现有容器:
docker update --memory 1g --memory-swap 2g app
Compose环境应把限制写回配置并重新部署,避免下次创建时丢失:
services:
app:
mem_limit: 1g
memswap_limit: 2g
memory-swap 表示内存与交换空间的总和。不要在没有设置memory上限时关闭OOM killer,这可能把单个容器故障扩大为整台服务器失去响应。
优化应用而不是只加内存
限制并发、缩小批次、设置连接池上限、修复泄漏和控制缓存,比无限提高上限更可靠。需要复制生产负载做压测时,可以使用 萤光云 或 LightNode 建立隔离环境,但只使用脱敏数据和受控流量。
内存上限应高于正常峰值并保留余量,同时不能挤占宿主机、Docker守护进程和其他容器的基本空间。
修复后怎样验收
重新部署后检查容器状态、内存曲线和内核日志:
docker inspect --format '{{.State.Running}} {{.State.OOMKilled}} {{.State.ExitCode}}' app
docker stats --no-stream app
journalctl -k --since '-10 min' --grep='Out of memory|Killed process|oom-kill'
验收标准是容器在真实峰值下保持运行,OOMKilled为false,内存不长期贴近硬限制,宿主机仍保留安全余量。
FAQ
退出码137一定是内存不足吗? 不一定。它表示SIGKILL,需要结合OOMKilled字段、内核日志和操作记录判断来源。
设置swap就能解决吗? swap只能提供缓冲,频繁换页会显著降低性能。应先找出内存增长原因,再决定额度。
温馨提示
生产环境修改内存限制前先保存原配置,并在低峰期观察完整业务周期。不要为了让容器不退出而取消所有保护上限。


