docker排查OOM Killer
文章目录
- 一.检查
- 1.内存不足 (OOM Killer)
- 2. CPU 资源限制
- 3. 存储空间不足
- 4. 应用自身崩溃
- 5. 健康检查失败
- 针对性建议
- 二.内存不足
- 问题根源
- 解决方案(按优先级排序)
- 1. 紧急措施:立即释放内存
- 2. 启用 Swap 交换空间(必须做!)
- 3. 降低容器内存限制(关键调整)
- 4. 优化 Java 应用
- 5. 终极方案:升级服务器配置
- 验证是否解决
- 注意事项
- 三.总结
一.检查
1.内存不足 (OOM Killer)
- 最常见原因:当容器内存超过限制或宿主机内存不足时,Linux 的 OOM Killer 会强制终止进程。
- 检查方法:
docker stats # 查看容器资源使用情况 dmesg | grep -i kill # 查看系统日志是否有OOM记录 journalctl -k | grep -i oom
- 解决方案:
- 增加容器内存限制:
docker run -m 2g ...
- 优化应用内存使用(如调整 JVM 堆大小,如果是 Java 应用)
- 增加宿主机内存或减少其他容器资源占用
- 增加容器内存限制:
2. CPU 资源限制
- 如果容器 CPU 使用率持续 100%,可能被调度器终止
- 检查:
docker stats top
- 解决:
- 增加 CPU 份额:
docker run --cpu-shares=512 ...
- 限制 CPU 核心数:
docker run --cpus=1.5 ...
- 增加 CPU 份额:
3. 存储空间不足
- 磁盘写满会导致各种异常
- 检查:
df -h docker system df
4. 应用自身崩溃
- 查看应用日志:
docker logs <container_id> --tail 100 -f
- 检查是否有未捕获的异常
5. 健康检查失败
- 如果配置了健康检查且失败,Docker 会重启容器
- 检查:
docker inspect <container_id> | grep -A 10 Healthcheck
针对性建议
-
优先检查内存:
# 查看被杀死容器的退出代码 docker inspect <container_id> | grep -i exitcode# 如果退出码是137(128+9=SIGKILL),通常是OOM
-
如果是 Java 应用:
- 确保设置了合理的 JVM 内存参数(如
-Xmx
) - 添加
-XX:+ExitOnOutOfMemoryError
让 JVM 主动退出而不是被杀死
- 确保设置了合理的 JVM 内存参数(如
-
临时解决方案(测试用):
# 完全禁用OOM Killer(不推荐生产环境) docker run --oom-kill-disable ...
二.内存不足
从 free -h
的输出可以看到,你的 宿主机内存已经几乎耗尽(1.7G
总量中 1.5G
已使用,仅剩 70M
空闲),并且 注意 Swap 交换空间(我的是 Swap: 0B
)。这是导致 OOM Killer 频繁杀死容器的直接原因!
问题根源
-
宿主机内存严重不足:
- 物理内存剩余仅 70MB,任何突发内存需求都会触发 OOM Killer。
- 没有 Swap 空间,系统无法将冷内存换出到磁盘,加剧了内存压力。
-
容器内存限制未生效:
- 虽然你为容器设置了内存限制(如 Halo 1.715GiB),但 宿主机总内存仅 1.7GiB,容器限制总和已超过物理内存。
解决方案(按优先级排序)
1. 紧急措施:立即释放内存
# 查找占用内存最多的进程并终止(慎重操作!)
top -o %MEM # 按内存排序,记录PID后按 `k` 输入PID终止# 清理缓存(临时释放部分内存)
sync && echo 3 > /proc/sys/vm/drop_caches
2. 启用 Swap 交换空间(必须做!)
# 创建 2GB Swap 文件(根据磁盘空间调整大小)
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile# 永久生效(写入 /etc/fstab)
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab# 验证
free -h # 应显示 Swap > 0
3. 降低容器内存限制(关键调整)
# 必须保证所有容器内存限制总和 < 1.5GiB(预留空间给系统)
docker update --memory 1G --memory-swap 1G mysql # Halo 限制为1GB
4. 优化 Java 应用
# 确保 JVM 堆内存小于容器限制(例如限制为800MB)
java -Xms512m -Xmx800m -jar app.jar
5. 终极方案:升级服务器配置
- 如果是云服务器(如阿里云),至少升级到 2.5GB 或 4GB 内存。
- 1.7GB 内存运行多个容器(尤其是 Java 应用)本身就很吃力。
验证是否解决
# 1. 确认 Swap 已启用
free -h # 查看 Swap 列是否 > 0# 2. 监控容器内存
watch -n 1 "docker stats --no-stream"# 3. 检查 OOM 事件
dmesg | grep -i oom # 应该不再有新的记录
注意事项
-
不要依赖 Swap 长期解决内存不足
Swap 性能远低于物理内存,频繁交换会导致服务卡顿。 -
MySQL 特殊处理:
如果 MySQL 因内存限制频繁崩溃,需要优化配置:docker exec mysql mysql -e "SET GLOBAL innodb_buffer_pool_size=128*1024*1024;"
三.总结
你的问题本质是 “1.7GB 内存的宿主机试图运行超过自身容量的服务”。按以下顺序操作:
1️⃣ 立即启用 Swap → 2️⃣ 大幅降低容器内存限制 → 3️⃣ 优化 容器内存分配 → 4️⃣ 尽快升级服务器。
如果内存不足问题持续,最终只有升级硬件才能彻底解决。