ARTICLE / ANALYSIS / DETAIL

深度阅读,
从一篇文章开始。

我们将复杂信息整理成清晰、可读、具有连续价值的内容,陪伴您了解每一个重要变化。

FOCUS
MODE
READ / 05 MIN

Docker默认无资源限制的隐患与修复

Docker 让跑软件这件事显得很轻,但这份轻便藏着一个代价不小的默认设置:容器启动时,内存和 CPU 都没有上限。 用一条普通的 docker run 启动容器,Docker 不会施加任何内存或 CPU 限制,容器能用到内核允许的极限。刚开始学的时候这很合理,可对一个要连续跑几周的服务来说就不合适了。容器给人的感觉是一次性的,于是很多人启动一个数据库、一个测试 API 或一个自托管应用,关掉终端就忘了它。它继续在后台运行,占着内存,还会因为定时任务、健康检查或轮询循环不断唤醒 CPU。 危险的地方在于它不显眼。一个被遗忘的服务可能只占几百兆,但几个加起来就不少了,而单个内存泄漏还能一路涨到把其他东西挤死。在 Linux 上,主机内存耗尽后,内核的 out-of-memory killer 会开始终止进程,它未必挑那个出问题的容器,也可能顺手干掉你的数据库、SSH 会话,甚至 Docker 守护进程本身。 Windows 和 macOS 上这种情况更明显。Docker Desktop 把容器跑在虚拟机里,这个虚拟机不管容器需不需要,都会先占掉一块内存。Windows 配 WSL2 时, vmmem 进程能在请求内存的工作负载停止很久之后,仍然握着几个G不放,笔记本因此变卡、风扇莫名狂转,原因就在这里。 Docker 对这些都不会提醒你。没有弹窗问这个容器该给多少内存,也没有通知说某个东西已经跑了三个月。除非你主动用 docker stats 去看,或者打开 Docker Desktop 面板,唯一的症状就是机器比该有的样子慢,还找不到明确的元凶。 把上限设上,把没用的清掉 别想太复杂,建容器的时候就把限制设好。 --memory 参数限制它能用多少内存, --cpus 限制它能分到多少处理器时间。把内存设成 512 兆、CPU 设成 1.5,一个失控的进程就被圈住了。容器超过内存上限时,Docker 会把它停掉,而不是让它拖垮主机。还可以设一个内存预留值,作为只在内存紧张时才生效的软限制,再加一个 pids 上限,防止某个进程无限生出子进程。 用 Docker Compose 的话,同样的控制写在配置文件里。在服务的 deploy 段下,resources 块接受 CPU 和内存的限制,当前版本的 Compose 不需要 Swarm 也能识别这些值。定义一次,每个同事、每次部署都拿到同样的边界,不用指望谁记得加参数。 限制只有在你知道合理数值时才有用,所以先观察。跑 docker stats 能看到每个容器实时的 CPU 和内存占用,观察几天就知道每个服务实际需要多少。把限制设在观测到的峰值稍高一点,正常的波动就不会触发重启。 最后,清理不再用的东西。 docker ps 列出正在运行的容器, docker stop 关掉不需要的。跑 docker system prune 会清掉已停止的容器、未使用的网络、悬空镜像和构建缓存,加上 volumes 选项还能一并删掉孤立的卷。把它当成习惯而不是一次性操作,每隔几周检查一次,机器就不会慢慢被填满。 日志、重启策略和桌面设置也会叠加 值得改的默认值不止资源限制。Docker 标准的 json-file 日志驱动不做轮转,一个话多的容器能一直往单个日志文件里写,直到吃掉几个G的磁盘。可以给每个容器或守护进程配置文件设 max-size 和 max-file,家庭环境和小服务器上,10 兆、保留三个文件通常就够了。 重启策略带来的问题更安静。把容器设成 always 重启,意味着每次重启、每次崩溃它都会回来,哪怕你是故意停掉的。一个坏掉的容器还可能无限循环,失败、启动、再失败,一路烧 CPU。unless-stopped 策略会尊重你手动关停的操作,on-failure 配上最大重试次数则能挡住无限崩溃循环。 健康检查也值得看一眼。每隔几秒跑一次的检查,尤其是那种要启动脚本或查询数据库的,会制造持续的后台活动。把间隔拉到 30 秒以上,对多数服务够用,开销也小得多。 在 Docker Desktop 里,设置菜单能限制虚拟机可占用的内存、CPU 和磁盘,而这些值往往被设得远高于实际需要。用 WSL2 的 Windows 用户可以在用户目录建一个 .wslconfig 文件,限制整个子系统的内存和处理器数量,然后用 wsl --shutdown 重启它。哪怕只做小幅调整,在笔记本上也能看出差别。 镜像大小长期也有影响。slim 或基于 Alpine 的镜像占的磁盘更少、下载更快,通常还带更少的后台进程,整体更轻。 Docker 的默认值偏向方便而不是效率,容器可以无期限地占用资源。设好内存和 CPU 上限、轮转日志、选合适的重启策略、定期清理,机器就能保持响应,避开那些由无人管理的容器造

about image