退出码137表示容器被sigkill(信号9)强制终止,主因是oom killer触发:若docker inspect显示"oomkilled": true,系容器超内存limit被cgroup杀;若为false,则多因宿主机全局oom或节点memorypressure驱逐。
容器内存溢出被 kill(退出码 137)不是镜像问题,而是运行时资源管控失效的信号。镜像只是静态模板,真正消耗内存的是容器里启动的进程;解决关键不在重做镜像,而在启动容器时就设对限制、配好运行时参数、盯住隐性内存源。
必须设置硬限制 --memory,禁用 swap
没设 --memory,等于没上锁。内核只在超限时才触发 OOM Killer,不限制就是把“生杀大权”交给系统。
- --memory=2g:强制上限 2GB,超限即进入 OOM 判定
- --memory-swap=2g:让 swap 等于物理内存,实质禁用 swap(避免延迟掩盖真实压力)
- 绝对不要写 --memory=0 或干脆不写,这等同于不限制
JVM 类应用要留足堆外内存余量
JVM 占用 ≠ -Xmx 设置值。堆外内存(Metaspace、线程栈、直接内存、JIT 缓存)同样计入容器总内存,超了就直接被杀。
- 容器限制 2G → JVM 堆建议设为 -Xmx1200m,再加 -XX:MaxMetaspaceSize=256m
- 进容器执行 java -XshowSettings:vm -version,确认 JVM 实际识别的内存是否受容器限制影响(JDK8u131+ 已支持自动适配,旧版本需加 -XX:+UseContainerSupport)
- 用 jstat -gcutil 1 1000 观察 GC 频率和堆外增长趋势
检查 /dev/shm 和软限制 memory-reservation
很多 OOM 并非主内存爆了,而是 /dev/shm 默认仅 64MB 被撑满——Chrome Headless、PyTorch、PostgreSQL 都会高频使用它。
- 进容器运行 df -h /dev/shm,若使用率 >90%,大概率是根因
- 启动时加 --shm-size=1g,对图像处理、无头浏览器类场景很关键
- 配 --memory-reservation=1.5g(硬限制的 70%~80%),让 Docker 在接近阈值时主动回收,避免突刺触碰硬限
靠监控和日志快速确认是不是真 OOM
别猜,用命令实锤:
- docker inspect 容器名 --format='{{.State.OOMKilled}}' → 返回 true 就是 OOM
- docker inspect 容器名 --format='{{.State.ExitCode}}' → 137 是典型信号
- dmesg -T | grep -i "killed process" → 查内核级日志,看哪个进程被杀、占了多少 anon-rss
- docker stats --no-stream 容器名 → 持续观察 MEM USAGE / LIMIT 比值,>95% 就该预警











