Skip to content

dtyq/boomwatcher

Repository files navigation

boomwatcher

为docker设计的早期OOM killer

背景

当程序写歪了或者故意的,在某一刻开始分配巨量内存并fork自己,它就会光速消耗完内存,内存耗尽进入交换时会将IO和CPU占满,最终拖垮系统让人ssh连不上tty打不开,没办法软重启。

我们构建机器上的node/npm/vite/composer在安装包/构建时就有这样的行为,经过很长时间的调查,我们最终还是没能确定问题在哪,怎么修复。

于是就有了这个简单的早期oom killer

机制

  1. 将自己所有的内存页从file backed变成anonymous,防止IO队列满时无法访问内存
  2. mlock所有页,防止被交换出内存
  3. 设置nice和ionice
  4. 每1s扫描一次所有docker容器的cgroup,如果容器内存占用(memory.current)超过设定值,向cgroup.kill写1

讨论

无法处理的情况:

  • 恶意进程通过各种手段直接将CPU吃满而不提高内存占用
  • 多个docker容器一同触发问题,每个docker容器的内存占用低于阈值

问题:

  • 扫描的路径是docker.service所在的scope,docker会将它的构建容器放在同级scope里,这导致了如果同级有需要占用超过阈值内存的服务,会被它杀掉
  • 暂不确认如果拒绝服务已经发生,IO队列满的情况下,VFS延迟会不会爆炸,会不会导致读取cgroupfs卡住或者向cgroup.kill写1无法生效

可能的解决方案:

  • 写一个内核模块来监视cgroup
  • 使用eBPF(同样不知道能不能绕过IO)

构建与使用

先递归带submodule clone

需要musl gcc wrapper

make
sudo /path/to/boomwatcher /path/to/scope number

例如,对于系统dockerd,限制4G内存:

sudo ./boomwatcher /sys/fs/cgroup/system.slice 4294967296

提供了钉钉通知的简单实现:设置自定义机器人,关键词为boomwatcher,设置环境变量NOFITY_TOKEN为access_token。

memoryeater

提供了一个赛博电灯泡,请不要放进嘴里

memoryeater是模拟恶意程序的,不要在没有准备的情况下运行

memoryeater是模拟恶意程序的,不要在没有准备的情况下运行

memoryeater是模拟恶意程序的,不要在没有准备的情况下运行

可以构建Dockerfile.memoryeater来模拟构建内存爆炸的情况,在构建前请保证构建机器上所有工作已保存,sync已执行,有备份并可以物理重启

About

Early OOM Killer for docker

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published