1、Docker 内存优化概述
说到 Docker 内存优化,我第一反应就是「别让它吃到撑」。容器化部署刚火那几年,我遇到过太多「莫名 OOM」的案例了——进程挂掉、服务中断、半夜被报警吵醒。后来才慢慢摸清,内存问题说白了就是资源争抢和配置不当。这一章咱们先把这个领域的地图画出来。
1.1 为什么内存优化这么重要?
你想想看,一台物理机或虚机上有十几个容器在跑。如果每个容器都不设限制,某个容器内存泄漏,其他容器就跟着遭殃。我最早在生产环境吃过的亏就是:一个 Node.js 容器慢慢吃掉所有内存,最后宿主机 OOM Killer 直接把所有进程干掉了,包括数据库容器。嗯,从那之后我再也不信「默认没限制也无所谓」这种话了。
Docker 的内存管理其实分两层:宿主机内核用 cgroups 做资源隔离,容器内的进程自己管理内存申请。优化要同时看这两层,光调一边往往不够。
核心目标:在保证服务稳定的前提下,降低整体内存占用,避免 OOM,提升容器密度。
我个人习惯把优化方向拆成四个维度:
- 限制配置 – 设置容器内存上限、预留值、swap 策略
- 应用层优化 – 语言运行时、线程数、缓存策略
- 镜像与存储 – 分层缓存、临时文件、overlay2 写时复制
- 监控与调优 – 持续采集指标,识别异常行为
1.2 常见内存问题与症状
| 问题 | 症状 | 常见原因 |
|---|---|---|
| 容器被 OOM Kill | 进程突然消失,`docker logs` 无最后输出 | 内存限制过小,或应用泄漏 |
| 宿主机 SWAP 高 | 容器响应变慢,磁盘 IO 升高 | swap 未限制,内存不足时换页 |
| 容器启动慢/失败 | 启动时申请大内存失败 | 预留值过大,总和要求超过宿主机 |
| 镜像拉取占用内存 | `docker pull` 时宿主机内存飙升 | 分层解压缓存,或并发拉取过多 |
我曾经踩过一个坑:一个 Java 应用容器只设了 --memory=512m,但 JVM 默认堆就 1/4 物理内存,在 2G 宿主机上它申请了 500MB 堆,加上元空间和线程,瞬间突破限制被 Kill。后来加了 -Xmx 参数才解决。这告诉我们:容器限制和应用配置要对齐。
1.3 内存优化的知识体系
下面这张图帮你快速建立整体视角——怎么从「监控发现问题」到「定位根因」再到「实施优化」。
提示:刚开始做优化时,我建议从「监控」入手。先装好 cAdvisor 或者 Prometheus + Node Exporter,把容器内存指标收上来。没有数据做支撑,一切优化都是瞎猜。
1.4 你需要知道的核心概念
在动手之前,几个关键术语必须清楚。记不住没关系,后面每章都会用到。
- memory.limit_in_bytes – cgroups 里限制容器可用内存上限(硬限制),超过后可能触发 OOM Kill。
- memory.soft_limit_in_bytes – 软限制,宿主机内存充足时允许超过,紧张时优先回收。
- swap 限制 – 默认容器可以用宿主机 swap,但生产环境我通常禁掉或设很小的 swap 限制,避免性能抖动。
- RSS vs Page Cache – RSS 是常驻物理内存,Page Cache 是磁盘缓存。Docker 的
--memory限制的是 RSS + Page Cache,不是只算应用自己。 - OOM Score – 内核选择杀哪个进程的优先级,可以调整
--oom-score-adj。
警告:永远不要在关键生产容器上设 --memory-swap=-1(无限 swap)。我曾经见过一台服务器因为 swap 使用过度导致磁盘 IO 打满,所有容器都卡死。宁可 OOM Kill 一个容器,也不要让整个宿主机瘫痪。
1.5 快速上手:用 docker stats 看内存
打开终端,跑个命令感受一下:
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
输出大概长这样:
CONTAINER MEM USAGE / LIMIT MEM %
web-app 128.4MiB / 512MiB 25.08%
redis 4.75MiB / 256MiB 1.86%
nginx 8.12MiB / 128MiB 6.34%
注意看 LIMIT 列,如果显示 -- 表示没设限制。这是个大坑——没限制的容器,一旦泄漏就无上限。我个人习惯每个容器至少设一个 --memory,哪怕设大一点,也比没有强。
快速检查:docker inspect <container> | jq '.[0].HostConfig.Memory' 可以查看限制值,如果是 0 就是没设。
1.6 本章小结与接下来的方向
这一章带你搭了骨架:内存优化到底要优化什么、从哪开始、用什么工具看。我不喜欢一上来就给大堆参数,先理解问题域,后面的章节才有落脚点。
嗯,回头整理一下知识点:
- 优化目标:稳定、低占用、高密度
- 四维度:限制配置、应用层、存储、监控
- 典型问题:OOM Kill、swap 抖动、配置与应用不对齐
- 先上监控,再动手,每轮小步验证
后面我们会依次深入每个维度。从最基础的 --memory 参数开始,到 JVM/Node/Go 的运行内存调优,再到镜像分层缓存优化——一步步把内存吃透。