容器因为内存不足被杀,到底留下哪些证据?谁被杀、容器退不退出、怎么在 docker 和内核两边查到?这篇逐项复现:退出码、OOMKilled 标志、docker events、dmesg、cgroup 的 memory.events,以及 --oom-kill-disable 的下场。
docker run 退出码 137;State.OOMKilled=True ExitCode=137 Error='' docker events:create → attach → start → oom → die 虚拟机内核日志(dmesg)里的相关行:[13225.072532] Memory cgroup out of memory: Killed process 70745 (python) total-vm:144460kB, anon-rss:64508kB, file-rss:5472kB, shmem-rss:0kB, UID:0 pgtables:316kB oom_score_adj:0 ; [13272.476306] Memory cgroup out of memory: Killed process 74249 (python) total-vm:41996kB, anon-rss:32104kB, file-rss:5432kB, shmem-rss:0kB, UID:0 pgtables:124kB oom_score_adj:0
docker 这边:退出码 137、State.OOMKilled=True、events 里有 oom。内核这边:虚拟机的 dmesg 里有 Memory cgroup out of memory: Killed process … (python),anon-rss 约 32 MB,与容器的上限吻合。cgroup 这边:memory.events 的 oom_kill 计数。
5 秒后容器 Status=running OOMKilled=True;日志:子进程 python 结束 状态 137 | Killed 容器里还活着的进程:PID COMMAND | 1 sleep | 7 sleep | 9 ps
内核杀的是进程,不是容器。容器里有 sleep 和吃内存的 python,只有 python 被杀,容器还在运行,但 OOMKilled 已经是 True。如果被杀的恰好是 PID 1,容器才会退出。看到 OOMKilled=True 不代表容器已经停了(我没有测被杀的是 PID 1 以外且容器继续服务的情形对应用的实际影响)。
memory.events:low 0;high 0;max 37;oom 1;oom_kill 1;oom_group_kill 0;sock_throttled 0; memory.events.local 里 oom_kill:oom_kill 1
max 是碰到上限的次数(37 次),不代表被杀;按我的理解,内核会先尝试回收内存,回收不了才 OOM,最终 oom_kill 为 1(回收的过程我没有观察)。
docker run -d 退出码 0;输出:369adf5dbf7d8083935afdc7e5a7d0175d7d1e5f8e6d8c20c79017f4deda1756 | WARNING: Your kernel does not support OomKillDisable. OomKillDisable discarded. 4 秒后 Status=exited OOMKilled=True;HostConfig.OomKillDisable=<nil>
这个环境(cgroup v2)下 --oom-kill-disable 会被丢弃,docker 打印 WARNING,容器照样被杀。cgroup v1 的行为我没有测。