Docker 启动容器报错 exit code 137 内存不足怎么解决

文章导读
遇到 Docker 容器退出码 137,最直接的办法是检查并调整容器的内存限制,或者排查宿主机的内存压力。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 参考来源
A A

遇到 Docker 容器退出码 137,最直接的办法是检查并调整容器的内存限制,或者排查宿主机的内存压力。

先说结论:退出码 137 通常代表进程被系统 OOM Killer 强制杀死,优先检查内存限制配置和宿主机剩余内存。

  • 先确认:查看容器日志和宿主机 dmesg 确认是否触发 OOM
  • 先处理:调整 Docker 内存限制或优化应用内存占用
  • 再验证:观察容器状态和系统日志不再出现 kills

命令速用版

如果你需要快速查看容器内存限制和系统 OOM 记录,可以使用以下命令:

# 查看容器内存限制
docker inspect `--format`='{{.HostConfig.Memory}}' <容器 ID>

# 查看宿主机内核日志中的 OOM 记录
dmesg -T | grep -i "out of memory"

# 临时调整运行中容器的内存限制(无需重启)
docker update `--memory`=2g <容器 ID>

为什么会这样

在 Linux 系统中,进程退出码 137 是由信号机制决定的。标准退出码 128 加上信号编号 9(SIGKILL)等于 137。SIGKILL 是强制终止信号,无法被进程捕获或忽略。

当容器内的进程占用内存超过设定的限制(memory limit),或者宿主机整体内存不足时,Linux 内核的 OOM Killer(Out Of Memory Killer)机制会被触发。为了保护系统稳定性,内核会选择占用内存较多的进程直接杀死,Docker 容器主进程因此退出并返回 137。

分步处理

按照以下顺序排查和处理,避免盲目增加内存导致宿主机崩溃。

1. 确认 OOM 原因

首先确认是否是内存问题。查看容器最近一次退出的详细信息:

docker inspect <容器 ID> `--format`='{{.State.OOMKilled}}'

如果返回 true,说明确实是被 OOM Killer 杀死。同时检查宿主机日志:

Docker 启动容器报错 exit code 137 内存不足怎么解决
dmesg -T | grep -i "killed process" | tail

2. 检查当前内存配置

查看容器启动时是否设置了内存限制。如果没有设置,容器默认可以使用宿主机所有内存,此时 137 错误通常意味着宿主机本身内存不足。

docker inspect <容器 ID> `--format`='{{.HostConfig.Memory}}'

如果返回 0,表示未限制。如果返回数字,单位是字节。

3. 调整内存限制

如果是容器限制过严,可以适当调大。对于运行中的容器,可以尝试使用 docker update 动态调整;对于新启动的容器,修改 docker run 或 compose 文件:

# 动态调整(注意:部分旧版本 Docker 或特定 cgroup 配置可能不支持热更新,若失败请重启容器)
docker update `--memory`=4g <容器 ID>

# 重新启动时设置
docker run -d `--memory`=4g `--name` myapp image:tag

# Docker Compose 配置示例
version: '3'
services:
  myapp:
    image: image:tag
    mem_limit: 4g

4. 优化应用内存

Docker 启动容器报错 exit code 137 内存不足怎么解决

如果无法增加物理内存,需要优化应用。例如 Java 应用,建议设置堆内存比例,避免 JVM 感知不到容器限制而超额使用:

-XX:MaxRAMPercentage=75.0

怎么验证是否生效

调整后需要观察一段时间,确认问题不再复现。

1. 观察容器状态

使用以下命令监控容器是否频繁重启:

docker stats <容器 ID>

观察 MEM USAGE 是否接近 LIMIT。如果长期接近上限,建议继续调大或优化代码。

2. 检查系统日志

Docker 启动容器报错 exit code 137 内存不足怎么解决

再次运行 dmesg 命令,确认没有新的 OOM kill 记录产生。

3. 业务验证

确认容器内服务端口正常响应,业务日志无异常中断。

常见坑

1. Java 应用特殊配置

旧版本 JVM 可能无法正确识别容器内存限制,导致认为可用内存是宿主机总内存,从而申请过多内存触发 OOM。建议升级 JDK 或使用 -XX:MaxRAMPercentage 参数。

2. 宿主机 Swap 影响

频繁使用 Swap 会导致磁盘 I/O 飙升,显著降低容器响应速度,生产环境建议关闭或严格限制 Swap 使用。

3. 多容器竞争

如果宿主机运行多个容器,单个容器内存增加可能导致其他容器被杀死。需要统筹规划宿主机总内存分配。

参考来源

  • Docker Official Documentation, "Container runtime constraints", https://docs.docker.com/
  • The Linux Kernel Documentation, "Out Of Memory Handling", https://www.kernel.org/doc/html/latest/