指南/Docker占用内存过多

Mac上Docker占用内存过多?如何找出容器并限制内存

Atta 🐬

Vitals创始人

发布于

简要回答

在Mac上,Docker把所有容器都放在一个Linux虚拟机里运行,所以活动监视器显示的是一个很大的进程(通常是Virtual Machine Service for Docker),而不是各个容器。要查看是哪个容器在占用内存,运行docker stats。要限制总量,在Docker Desktop的Settings → Resources → Advanced中调低Memory limit;默认值是Mac内存的一半。同一处的Resource Saver会在Docker Desktop闲置时关闭虚拟机。Vitals是一款Mac系统监控工具,会在“容器”标签页中显示每个容器的内存、CPU、网络和端口,还能从菜单栏停止容器。

如何查找并限制Docker的内存

  1. 01 打开活动监视器,点按“内存”,在搜索栏中输入Docker。最大的那一行就是运行容器的虚拟机;使用Apple的Virtualization框架时,它名为Virtual Machine Service for Docker。com.docker.backend是Docker Desktop本身。
  2. 02 在“终端”中运行docker stats --no-stream。每一行是一个正在运行的容器,MEM USAGE / LIMIT显示它用了多少以及最多能用多少。
  3. 03 停止不用的容器:docker stop加容器名称,或在Compose项目的文件夹中运行docker compose down。
  4. 04 打开Docker Desktop的Settings → Resources → Advanced,把Memory limit调低到比docker stats在最忙时显示的数值稍高一点。应用更改后,Docker Desktop会重启虚拟机。
  5. 05 在同一部分打开Resource Saver,这样没有容器运行时虚拟机就会关闭。

OrbStack、Colima、Rancher Desktop和Podman也在虚拟机中运行容器,各有各的内存设置。对于Colima,colima start --memory 4会给虚拟机分配4 GB。

容器是Linux的功能,所以在Mac上,每种引擎都在一个小型Linux虚拟机中运行容器。macOS把这台虚拟机视为一个进程,完全不知道里面哪个容器用了什么。这就是为什么活动监视器显示一个占了好几GB的进程,却一个容器都看不到,也是为什么答案要在Docker自己的工具里找。下表把你看到的现象与它是什么以及该怎么做对应起来。

Docker的内存都去哪儿了

你看到的现象它是什么怎么做
Virtual Machine Service for Docker,占好几GB 运行所有容器的Linux虚拟机 在Settings → Resources → Advanced中调低Memory limit
com.docker.backend Docker Desktop自身的进程 通常很小;如果一直增长,就重启Docker Desktop
没有容器运行,内存仍然很高 虚拟机仍占着它用过的内存 打开Resource Saver,或退出Docker Desktop
某个容器接近上限 它需要更多内存,或者存在泄漏 docker stats,并为单个容器设置上限
构建镜像时内存上升 构建在同一台虚拟机中运行 正常;构建结束后会降下来

活动监视器为什么只显示一个很大的Docker进程

虚拟机像任何App一样从macOS获取内存,最多到你设定的Memory limit。在虚拟机内部,Linux把这些内存分给你的容器,剩下的用来缓存文件,就像macOS一样。从外面看,这些都一样:一个进程占着很多内存。

只有引擎知道怎么分的,而docker stats就是向它询问这个。那里的CPU %列是相对于虚拟机CPU的占比,MEM %则是相对于容器上限的占比;如果容器没有设上限,就是相对于整台虚拟机的占比。

该给Docker分配多少内存

Docker Desktop默认占用Mac内存的一半:16 GB的Mac上就是8 GB。一个典型的开发栈(一个应用服务器、一个数据库和一个缓存)通常需要的要少得多。像平时一样运行你的开发栈,观察docker stats在最忙时的总量,把Memory limit设得比它稍高一点。

设得太低,虚拟机里的Linux就会停止耗尽内存的容器。运行docker inspect --format '{{.State.OOMKilled}}'加容器名称:如果发生过这种情况,它会输出true。调高上限,或者给那个容器单独设一个上限,免得它把其他容器也拖垮。

为单个容器设置内存上限

给单个容器设上限,可以防止存在泄漏的服务占满虚拟机。使用docker run时,加上--memory 512m。在Compose文件中,给服务设置mem_limit: 512m。容器一旦超出上限就会被停止,docker stats会在它的用量旁边显示上限。

Docker为什么不归还内存

停止容器会释放虚拟机内部的内存,但虚拟机并不总是马上把它还给macOS,所以它在活动监视器中的数值可能一直很高。Resource Saver会在Docker Desktop闲置时关闭虚拟机,从而归还全部内存;有容器需要时,几秒钟就能重新启动。退出Docker Desktop也有同样的效果。

Docker与磁盘空间

镜像、已停止的容器、卷和构建缓存都存放在一个磁盘映像中,它会随着你的工作不断变大,在Mac上计入系统数据。docker system df会显示每一类占了多少。docker system prune会移除已停止的容器、未使用的网络、悬空镜像和构建缓存;只有确定没有哪个卷存着你需要的数据时,才加上--volumes。Docker Desktop设置中Memory limit旁边的Disk usage limit可以限制它的大小。

Vitals能多做什么

Vitals能显示虚拟机不会告诉macOS的内容:每个容器的内存。

  • “容器”标签页显示每个容器的内存、CPU、网络、磁盘和已发布的端口,Compose项目归在一起
  • 显示占用最多的容器和最接近上限的容器的卡片,以及按容器划分的内存图表
  • Docker Desktop在App列表中占一行,已计入它的虚拟机;点按它即可看到里面的容器
  • 菜单栏下拉面板中也有这些容器,询问后一键即可停止某个容器。请参阅如何停止Docker容器
  • 支持Docker Desktop、OrbStack、Colima、Rancher Desktop和Podman

须知

  • Vitals从引擎读取容器数据,从不启动或移除容器。“停止”是它唯一会做的更改,而且只在你要求时才做。
  • 这个标签页在有引擎运行时显示。
购买Vitals $9 首发期$9,之后$29。14天内可退款。

常见问题

Mac上的Docker为什么占用这么多内存?

Docker在Linux虚拟机中运行容器,虚拟机最多可占用到它的Memory limit,默认是Mac内存的一半。在Settings → Resources → Advanced中调低Memory limit,并运行docker stats查看哪个容器占用最多。

Virtual Machine Service for Docker是什么?

它是Docker Desktop使用Apple的Virtualization框架时运行容器的虚拟机。它的内存就是容器和其中的Linux所用的全部内存,最多到Docker Desktop的Memory limit。

如何在Mac上限制Docker的内存?

在Docker Desktop中打开Settings → Resources → Advanced,调低Memory limit。对于单个容器,使用docker run --memory 512m,或在Compose文件中使用mem_limit: 512m。

停止容器后,Docker为什么不归还内存?

即使容器停止了,虚拟机仍会保留一部分用过的内存。打开Resource Saver,让虚拟机在Docker Desktop闲置时关闭,或者退出Docker Desktop。

Virtual Machine Service for Docker为什么占用这么多CPU?

通常是某个容器在忙,docker stats会显示是哪一个。如果没有容器运行CPU仍然很高,就退出并重新打开Docker Desktop,然后更新它:什么都没运行时CPU也很高,在某些Docker Desktop版本中已被报告为bug。

Mac上该给Docker分配多少内存?

比你的容器在最忙时的用量稍多一点,docker stats会显示这个用量。对于典型的开发栈,这通常是2到4 GB,远低于默认的Mac内存一半。

有没有能显示Mac上Docker容器内存的App?

Vitals有一个“容器”标签页,显示每个容器的内存、CPU、网络、磁盘和端口,支持Docker Desktop、OrbStack、Colima、Rancher Desktop和Podman。它还能在询问后从菜单栏停止容器。

术语表中的相关条目

更多指南