1 需求描述
- 个人服务器的磁盘空间不足了,恍然发现主要是 docker 占用了太多空间。那么如何安全地清理Docker服务占用的磁盘空间呢?
2 解决方案
检查磁盘空间情况
- 检查磁盘空间,确认
overlay2占用的空间
# df -h
Filesystem Size Used Avail Use% Mounted on
udev 7.9G 0 7.9G 0% /dev
tmpfs 1.6G 2.1M 1.6G 1% /run
/dev/sda1 197G 59G 131G 32% /
tmpfs 7.9G 0 7.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda15 124M 12M 113M 10% /boot/efi
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/3ea43957615f592f2a7b28512fd7f344ac762bfc80a4a964ac467b17f562203e/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/bd8702eb9dcc24aff1a54387374f6609b431aabb1c7131359296867986dc84a0/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/b6b66bb24dc1186c12f18ddb3487a3b81ef40767993a722b08359808635461bd/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/0bf724bd62f24f7411c573b03fef2816c0b14a696ce04e8b78c4616b704b1b86/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/d7caeb11110a19f032d90855ae491c9cb35c5cbbd57daf266e5b12c3494ba21e/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/e4ec25032cb6814980100348c68e937bb4b9e48c098dbf99c5a543428f73e8b7/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/53277c320141d4efa122ad91fe38fe9e7362d29d2cdabb5c3d8c2a1bdea12120/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/b5b65a3ebe16e33091590dbdbea7c51b6ffc8ab894358d9cb7d95934a14a8579/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/864d8e14ba8c74bc627a35847aff844e45acc43686abc7d81c471969fe2b8386/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/5d0d903a3ccd4b5b2cd6741d4eb9654b10667fd5707c13d3d51f2678b5c4d7a2/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/4c2bf66ffcd7f2a8bb03dcee3f5d445c4be9c56b899aaea319689a92193fbaf4/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/3a9e03fd9038307f133da2800527610a6334e458d42d8a406ea30e108dd8ec58/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/4c509ec79872340afca9c9a763782005fa043f5e4c988acc9f24f371d7c79b5c/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/d9bad19c0ce3f9ff18364ee882e52bb9fef3db1c5a99bdbfb97fe4dbbea6f985/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/492549dc47bc8b55a73c945ad3eb699fe34c5e563d22cf4b16383048420fbffe/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/31a7a2393fa100d485b852cda049e4efe7e2d57240a638bde911901a9878e6bd/merged
overlay 197G 59G 131G 32% /var/lib/docker/overlay2/c56e33e03da1a8e849eb8d02a660cfdbf1b21774a99adb8bb1435e072ead0eaf/merged
tmpfs 1.6G 0 1.6G 0% /run/user/0# cd /var/lib/docker/overlay2
# du --max-depth=1 -ah ./
...
3.9G ./cbd00072f337eac535231f5070dd185eb5396a2a38f503a180d85f4c3dfd56dc
52K ./492f6bb1fa6939b3b4c9bde42c488e821e39dc284a506a69009232666b3b646e
24K ./4ac719b443482d3094f55f87465fd0a2e055e03d8884aab104c9a9b749b6a888
311M ./98f0e8fe08003084033830be8d14843ab31751dd66abec2a859e1123bd4264cf
4.1M ./d569993160caa256ff9578a2e2c88a809eb94cbdb19b42bcf789ade5e3ede6f2
6.8M ./40cfa823fdcda9ddd582bc3ae8c2e2409f53c2484488b919dd0c90b35759500e
56K ./ff0d25275d523771576a3e7ef0249fbcf88e7b94ca0f2e4bc806a2bbcf1391be
28K ./c04b54aa554e1a1c82ba1d3af8effefd02d4f1aa2b246b6f863e6643fad56fb8
4.1G ./2e645b5187bc64ae8bcd1eb93c70343c68bd94c610681b37faf486b4015eb62e
...
786M ./c195dcf2dc6fc330b450cfdf76066d661bbd9c8c306e68de8c183c9786ee82d8
如果看到 overlay
Use%这一栏占用百分比过高,说明确实是docker的overlay目录占用过高导致服务器磁盘空间过小的问题
检查容器的占用情况
- 检查docker 各模块(镜像、容器、本地卷、缓存)中的占用情况
# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 20 18 8.739GB 684.5MB (7%)
Containers 18 17 11.12MB 6.23kB (0%)
Local Volumes 7 6 348.8MB 72.39MB (20%)
Build Cache 754 0 40.38GB 40.38GB
- 行说明
- Images: 镜像的数量及占用大小
- Containers: 容器的数量及占用大小
- Local Volumes: 本地卷数量及占用大小
- Build Cache: 打包构建时的缓存大小
我们主要是清理
Images、Containers和Build Cache中的文件
- 列说明
RECLAIMABLE列:英译"可收回的;可教化的",此处指的是“未使用”的镜像或镜像占用的空间(意思是:没有基于这些镜像运行的容器)。
这是您可以删除而不会破坏任何内容的镜像总大小。
这正是为什么如果您运行docker system prune -a或docker image prune -a,Docker 会删除它们。
-a 告诉 Docker 删除所有未使用的镜像,没有它,Docker 只会删除悬挂(未标记)的镜像。
执行清理操作
清理无用的Images
- 先查看一下目前存在的镜像
docker images
结果
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> defd79220cd6 2 months ago 239MB
可以看到有很多到
<none>字样的镜像。这里我只截取一个作为参考。发现数量和占用大小都挺多的。
none镜像被官方称为dangling镜像————代表没有标签且没有被使用过的镜像,可以安全放心的清理。
- 清理方法也很简单,执行下面命令:
docker image prune
这条命令会自动帮我们清除带有
<none>的无效镜像。
命令执行完毕会提示释放了多少个空间。
然后,我们再来执行docker images命令会发现带有<none>的镜像全部被清理干净了磁盘空间也得到了释放!
清理Containers容器中的日志
Containers容器占用最多的基本上就是日志文件Docker日志(也就是 docker logs 输出的东西) 默认存放在:
这个日志文件可能会越积越大,需要定期清理。
/var/lib/docker/containers/<container-id>/<container-id>-json.log
例如:
[root@xxx yy]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS 675c9b2dcccd nginx:1.24.0 "/docker-entrypoint.…" 9 months ago Up 54 minutes 0.0.0.0:80-81->80-81/tcp, 0.0.0.0:443->443/tcp nginx[root@xxx yy]# ls -la /var/lib/docker/containers/675c9b2dcccd648a2f36f70348cc0c2c43cc3de80a51b0ac47215b5044175f42/
total 35744
drwx--x--- 4 root root 4096 Dec 31 23:19 .
drwx--x--- 7 root root 4096 Sep 19 23:22 ..
-rw-r----- 1 root root 36556073 Dec 31 23:37 675c9b2dcccd648a2f36f70348cc0c2c43cc3de80a51b0ac47215b5044175f42-json.log
drwx------ 2 root root 4096 Mar 23 2025 checkpoints
-rw------- 1 root root 3821 Dec 31 23:19 config.v2.json
-rw------- 1 root root 1740 Dec 31 23:19 hostconfig.json
-rw-r--r-- 1 root root 13 Dec 31 23:19 hostname
-rw-r--r-- 1 root root 206 Dec 31 23:19 hosts
drwx--x--- 2 root root 4096 Mar 23 2025 mounts
-rw-r--r-- 1 root root 306 Dec 31 23:19 resolv.conf
-rw-r--r-- 1 root root 71 Dec 31 23:19 resolv.conf.hash
- 从根源限制Docker日志大小(一劳永逸的方法 推荐)
我们可以设置限制日志大小从而不用每次都来手动删除日志
vim /etc/docker/daemon.json //编辑内容:{"log-driver": "json-file","log-opts": {"max-size": "10m","max-file": "3"}
}
这样,每个容器最多只会占用30MB的日志空间。
写入完成后并不会立刻生效,需要重启运行中的容器。
如果有条件的情况下,建议重启docker会对所有容器都生效:
systemctl restart docker
- 解决方法1:
- 先找到日志文件路径:
docker inspect <容器名或ID> --format='{{.LogPath}}'
- 然后清空它
truncate -s 0 "$(docker inspect <容器名或ID> --format='{{.LogPath}}')"
- 解决方法2: 还有另一种方式可以一次性清理所有容器
find /var/lib/docker/containers/ -name "*-json.log" -exec truncate -s 0 {} \;
不删除文件、不重启服务,不影响任何容器运行。
清理构建缓存(Clear Build Cache)
Build Cache主要是构建时的缓存,清理它们下次打包构建时速度可能会慢点,对于系统没有任何影响。
如果磁盘占用过高需要及时清理。清理方法也特别简单就一行命令
docker builder prune
执行完成后,可以发现服务器的内存又可以释放一截。
3 Docker 服务的文件目录体系
/var/lib/docker/overlay2
Docker Overlay2 : 基于内核的图层存储驱动程序
Docker的Overlay2【存储驱动程序】是一个基于内核的图层存储驱动程序,用于创建和管理Docker容器。
- 它通过将多个【只读层】叠加到单个【可写层】来实现这一功能,这使得
Docker可以高效地共享和复用【镜像层】,从而减小了【镜像大小】并加速了【容器的启动速度】。/var/lib/docker/overlay2是Overlay2存储驱动程序的【默认存储目录】,用于保存Docker【容器镜像】和【容器数据】。这个目录的结构和用途如下:
lower目录:这个目录包含了所有基础镜像层,它们是只读的并且被叠加在一起。每个基础镜像层都有一个对应的子目录,例如“sha256:c77159850506976d0a9b83b21155b51d88e49c72b1f09493e80d8c664f44a4c41”。upper目录:这个目录包含了所有叠加的读写层,它们位于基础镜像层之上。这些读写层通常包含容器的修改和新增内容,例如容器的配置文件、日志等。merged目录:这个目录包含了最终的容器镜像,它是所有叠加层内容的聚合。Docker 使用这个目录来提供容器运行时所需要的文件系统视图。diff目录:这个目录包含了叠加层的差异内容,即哪些文件或目录在叠加过程中发生了变化。这些差异内容对于 Docker 的备份和迁移操作非常有用。
Overlay2驱动程序使用了基于inode的存储模型,它将不同的【图层】都挂载到【相同的文件系统目录】下,同时使用不同的【命名空间】来进行隔离。
这种设计使得
Overlay2能够高效地管理【容器】、【镜像】和【数据】,并且能够实现快速的【数据恢复】和【备份】。
在实际应用中,/var/lib/docker/overlay2目录的大小可能会随着容器的数量和大小而增长。
如果服务器磁盘空间不足,可能会导致容器无法正常启动或运行。因此,定期监控和管理/var/lib/docker/overlay2目录的大小是非常重要的。
在管理/var/lib/docker/overlay2目录时,可以通过删除不必要的容器、清理旧的镜像层或增加磁盘空间等方法来减小其大小。
另外,也可以考虑使用 Docker 的磁盘清理工具或第三方工具来帮助管理 Docker 存储空间。
用生活类比理解 overlay2 的本质
想象你有一叠透明的画画纸:
- 最下面一张是「基础画纸」(相当于 Docker 镜像),上面画着固定的图案(程序和系统文件)。
- 每次在上面盖一张新的「透明纸」(相当于容器的层),你可以在新纸上修改或添加图案,不会破坏下面的纸。
overlay2就是管理这叠纸的「文件夹」,让所有纸看起来像一张完整的画(容器运行时的文件系统)。
overlay2 的核心组成部分及作用
- 目录结构总览
/var/lib/docker/overlay2/
├── l # 软链接文件夹,指向具体层的路径
├── mnt # 容器挂载点,合并所有层的文件
├── <hash1>/ # 镜像层(只读)
│ ├── diff/ # 存储该层的文件变更
│ ├── link # 层的唯一标识
│ └── lower # 记录下层的路径
└── <hash2>/ # 容器层(可写)├── diff/ # 存储容器运行时的修改├── link # 层的唯一标识├── lower # 记录所有下层镜像的路径└── work # 临时工作目录,用于文件修改
- 关键部分详解
- 镜像层(只读层):
像图书馆的书,多个容器可以共享同一本书(镜像层),节省空间。
- 容器层(可写层):
像在书上贴便签,容器运行时的修改(如新建文件、修改内容)都存在这里,不影响原书。
mnt目录:像「魔法桌面」,把所有层的文件合并显示,容器看到的就是这个合并后的文件系统
例如:
(base) [root@xxxxx halo]# ls -la /var/lib/docker/overlay2/98f0e8fe08003084033830be8d14843ab31751dd66abec2a859e1123bd4264cf
total 52
drwx--x--- 4 root root 4096 Feb 15 2025 .
drwx--x--- 160 root root 28672 Dec 31 23:07 ..
drwxr-xr-x 8 root root 4096 Feb 15 2025 diff
-rw-r--r-- 1 root root 26 Feb 15 2025 link
-rw-r--r-- 1 root root 260 Feb 15 2025 lower
drwx------ 2 root root 4096 Feb 15 2025 work
overlay2 背后的工作原理
┌──────────────────────────────────────────────────────────┐
│ 当启动容器时,overlay2 做了这些事: │
├───────────────────┬──────────────────────────────────────┤
│ 1. 找到镜像的所有只读层(如 A、B、C 层) │
│ ▼ │
│ 2. 创建一个新的可写层 D,用于存储容器的修改 │
│ ▼ │
│ 3. 在 mnt 目录中,用「联合文件系统」把 A+B+C+D 合并成一个 │
│ ▼ │
│ 4. 容器访问的就是这个合并后的文件系统,修改会存在 D 层 │
└──────────────────────────────────────────────────────────┘
- 联合文件系统原理:
就像叠透明纸,下面的层(镜像)是只读的,上面的层(容器)可以修改。当修改一个文件时:
- 先把原文件从下层「复制」到上层(称为「写时复制」)
- 在上层修改这个复制后的文件,下层文件保持不变
使用场景
- 多个容器共享同一镜像
场景:运行 10 个 Nginx 容器,每个容器共享同一个 Nginx 镜像层,只需要存储一次镜像文件。
好处:节省磁盘空间,像 10 个人看同一本漫画书,不用每人买一本。
- 容器快速创建和删除
场景:测试环境中频繁创建、删除容器(如 CI/CD 部署)。
原理:删除容器只需要删除可写层,镜像层不受影响,像撕掉便签,书还在。
- 数据持久化
场景:容器中数据库的数据需要保存,即使容器删除也不丢失。
做法:把数据目录挂载到宿主机(绕过 overlay2 的层机制),像把重要的便签单独贴在书桌抽屉里。
底层技术关键点(用代码比喻)
- 虽然 overlay2 是用 C 语言写的,但可以用 PHP 逻辑理解核心思想:
// 模拟 overlay2 的核心逻辑(非实际代码,仅用于理解)
class Overlay2 {// 存储所有层的信息private $layers = [];// 添加一个镜像层(只读)public function addImageLayer($layerHash, $parentLayers) {$this->layers[$layerHash] = ['type' => 'read-only', // 标记为只读'parent' => $parentLayers, // 记录下层是谁'path' => "/var/lib/docker/overlay2/$layerHash/diff" // 层的文件路径];echo "创建镜像层 {$layerHash},像添加一本新漫画书\n";}// 创建容器的可写层public function createContainerLayer($containerId, $imageLayers) {$layerHash = md5(uniqid()); // 生成唯一标识$this->layers[$layerHash] = ['type' => 'read-write', // 标记为可写'parent' => $imageLayers, // 下层是所有镜像层'path' => "/var/lib/docker/overlay2/$layerHash/diff",'work_path' => "/var/lib/docker/overlay2/$layerHash/work" // 临时工作目录];// 创建软链接,方便快速找到层symlink($this->layers[$layerHash]['path'], "/var/lib/docker/overlay2/l/$containerId");echo "为容器 {$containerId} 创建可写层 {$layerHash},像准备一张空白便签\n";}// 合并所有层,生成容器看到的文件系统public function mountContainer($containerId, $mountPath) {// 获取所有下层(镜像层)的路径$lowerPaths = [];foreach ($this->layers as $hash => $layer) {if (in_array($hash, $this->layers[$containerId]['parent'])) {$lowerPaths[] = "lowerdir={$layer['path']}";}}// 添加当前可写层的路径$lowerPaths[] = "upperdir={$this->layers[$containerId]['path']}";$lowerPaths[] = "workdir={$this->layers[$containerId]['work_path']}";// 用联合文件系统挂载(实际是调用 Linux 的 mount 命令)$command = "mount -t overlay overlay -o " . implode(',', $lowerPaths) . " $mountPath";exec($command);echo "把所有层合并到 {$mountPath},像把所有透明纸叠在一起\n";}// 当容器修改文件时(写时复制)public function modifyFile($containerId, $filePath) {$layer = $this->layers[$containerId];$sourceLayer = $this->findFileSourceLayer($filePath, $layer['parent']);if ($sourceLayer) {// 从下层复制文件到当前可写层$sourceFile = "{$sourceLayer['path']}/" . substr($filePath, 1);$targetFile = "{$layer['path']}/" . substr($filePath, 1);copy($sourceFile, $targetFile);echo "从下层复制文件到可写层,像把书上的内容抄到便签\n";} else {// 文件是新建的,直接存在可写层touch($targetFile);echo "新建文件,存在便签上\n";}}// 查找文件在哪个下层private function findFileSourceLayer($filePath, $parentHashes) {foreach ($parentHashes as $hash) {$layerPath = "{$this->layers[$hash]['path']}/" . substr($filePath, 1);if (file_exists($layerPath)) {return $this->layers[$hash];}}return false;}
}
思维导图:overlay2 的全貌
/var/lib/docker/overlay2 的世界
├── 核心作用:管理容器和镜像的文件层,像叠透明纸
├── 组成部分:
│ ├── 镜像层(只读):多个容器共享的「基础画纸」
│ ├── 容器层(可写):每个容器独有的「便签纸」
│ ├── mnt 目录:合并所有层的「魔法桌面」
│ └── work 目录:临时修改文件的「草稿本」
├── 工作原理:
│ ├── 联合文件系统:把多层文件合并显示
│ ├── 写时复制:修改时先复制到可写层,不影响下层
│ └── 软链接:快速找到层的路径,像书签
├── 使用场景:
│ ├── 多容器共享镜像:节省空间,像多人看同一本书
│ ├── 快速创建容器:只加便签,不复制整本书
│ └── 数据持久化:重要数据单独存,不放在便签上
└── 底层技术:├── Linux 内核的 overlay 或 overlay2 驱动├── mount 命令实现文件系统挂载└── 写时复制(Copy-on-Write)机制
总结:透过现象看本质
overlay2 就像一个「文件层管理员」,它的核心魔法是:
- 用「透明纸叠放」的方式管理镜像和容器的文件,让它们共享底层资源又互不干扰;
- 当你修改文件时,它偷偷把修改内容放到最上面的「便签纸」上,不破坏下面的「原书」;
- 最终呈现给容器的,是所有纸叠在一起的「完整画面」,但实际存储的是每一层的差异,节省了大量空间。
/var/lib/docker/containers/<container-id>/<container-id>-json.log
需求参见:本文的第2章 清理容器的日志
Y 推荐文献
- [Docker] Docker 基础教程(概念/原理/基础操作) - 博客园/千千寰宇
- [Linux]常用命令之【du/fdisk/df/ls】#磁盘管理/文件管理# - 博客园/千千寰宇
- /var/lib/docker/overlay2到底是干什么的? - CSDN
X 参考文献
- Docker中overlay2磁盘占用爆满清理方案 - segmentfault.com
- 在docker system df中显示的“RECLAIMABLE”空间是什么? - dev59.com
- 深入了解容器 overlay 文件系统和 /var/lib/docker/overlay2 下的目录作用 - 腾讯云
- /var/lib/docker/overlay2 占用很大,清理Docker占用的磁盘空间,迁移 /var/lib/docker 目录... - 阿里云