Docker 出现“No space left on device”错误,往往发生在最糟糕的时机:部署中途、关键构建期间,或拉取重要镜像时。我也多次遇到过这种情况,可以肯定地说,在未正确诊断前就匆忙删除文件,极易导致数据丢失。
这类错误之所以棘手,往往在于它很少只有单一原因。可能是堆积的 Docker 镜像、失控的容器日志、数百万个小文件耗尽了 inodes,或者是被运行进程占用的已删除文件造成的“幽灵”空间。每种情况都需要不同的解决方案。
因此我总是强调:先诊断,再行动。弄清根因能帮助您更高效地采取针对性措施,并避免干扰生产环境。本文将带您系统化地完成诊断、解决与预防这一恼人问题。
如果您是 Docker 新手,建议先学习我们的动手课程Introduction to Docker,它涵盖容器化入门所需的一切。
什么是 Docker “No Space Left on Device” 错误?
当 Docker 抛出该错误时,表明系统存储出现以下两类根本问题之一:
理解二者区别对于采用正确的解决方案至关重要。
导致“No space left on device”错误的根因
首个、也是最直观的原因是物理磁盘块耗尽。文件系统已没有实际可写入的数据空间。这是更容易理解的情形:磁盘被 Docker 镜像、容器、日志或其他文件占满了。
第二个不那么明显的原因是inode 耗尽。即便仍有数 GB 的可用空间,文件系统也可能耗尽 inodes(用于跟踪文件和目录的元数据结构)。每个文件和目录都会消耗一个 inode,因此当应用创建数百万个小文件(如 PHP 会话文件或 npm 的 node_modules 目录)时,inodes 会被耗尽,而磁盘空间仍有剩余。
了解 overlay2 存储驱动
Docker 通常使用基于 Linux OverlayFS 的 overlay2 存储驱动。OverlayFS 会在单个主机上叠加多个目录,并呈现为统一的文件系统。镜像层以只读的 lower 目录挂载,而每个正在运行的容器会叠加一层很薄的可写 upper 层。容器看到的是合并后的单一目录视图。

overlay2 理论上原生支持最多 128 个 lower 层,但 Docker 的层存储对每个镜像的基底层实际限制为 125 个。它实现了高效的镜像组合,并提升了诸如 docker build 和 docker commit 等操作的性能。
尽管 overlay2 的设计比早期存储驱动更少消耗 inodes,但在频繁构建镜像、拉取层或创建容器的环境中,随着时间推移,尤其当镜像或应用层包含大量小文件时,仍会对磁盘块和 inodes 造成显著压力。
该错误的表现因部署环境而异:
步骤一:诊断根因
在删除任何内容之前,我总会先进行全面诊断。花几分钟做这件事,能为您节省数小时的排错时间,并避免意外的数据丢失。
检查系统层面的容量
先用 df -H(df 即 disk free)检查主机磁盘使用情况:
df -H技术支持

WSL 中检查可用磁盘
该命令以人类可读的格式显示磁盘使用情况。重点关注接近或达到 100% 容量的文件系统。
在原生 Linux 安装中,尤其要留意 /var/lib/docker 所在的分区。它通常位于根分区(/)或专用的 Docker 分区。
在 Docker Desktop(Windows/Mac)中,请关注主要的文件系统挂载(通常为 /dev/sdf 或类似项),它承载 Docker VM 的数据,而非特定的 /var/lib/docker,因为 Docker 运行在虚拟机内。
接着使用 df -i 检查 inode 是否耗尽:
df -i技术支持

检查 inode 是否耗尽
如果某个文件系统的 inode 使用率(IUse%)为 100%,问题就找到了。这在构建服务器和 CI/CD 环境中非常常见,Docker 会反复创建和销毁包含大量小文件的容器。
|
指标
|
命令
|
关注点
|
|
磁盘空间
|
df -H
|
使用率 90%+ 的分区
|
|
Inode
|
df -i
|
IUse% 达到 100%
|
|
Docker 目录
|
du -h /var/lib/docker
|
总占用大小
|
分析 Docker 专项使用情况
确定是磁盘空间还是 inode 问题后,进一步审查 Docker 的资源消耗。docker system df 提供在所有 Docker 安装中通用的高层摘要:
docker system df技术支持
该输出按四类进行空间占用细分:镜像、容器、本地卷和构建缓存。
RECLAIMABLE 列尤为重要。它显示在不影响正在运行的容器前提下,您可以回收的空间量。理解两个指标的区别至关重要:“active” 表示当前被运行的容器使用,“reclaimable” 则表示可以安全释放。
如需更细粒度的细节,可添加 verbose 标志:
docker system df -v技术支持

Docker 使用情况分析
详细输出会逐一列出每个镜像、容器和卷及其大小,帮助您定位“空间大户”。各部分关注要点如下:
-
Images:显示每个镜像大小及是否在用。留意未使用或以不同标签重复的超大镜像。标记为“unused”的镜像可安全删除,不会影响正在运行的容器。
-
Containers:展示每个容器可写层的大小。若某个已停止容器的 SIZE 很大,说明它向文件系统写入了大量数据。CREATED 列可帮助识别可能被遗忘的旧容器。
-
Volumes:列出卷大小及是否在用。未使用的卷可以作为删除候选,但清理前务必确认其中不含重要数据。
-
Build Cache:常见的最大消耗者且易被忽略。它们是 docker build 生成的中间层,用于加速后续构建。
操作系统专项命令
对于原生 Linux 用户,如需更深入的文件系统洞察,可直接检查子目录,查看哪些子目录(overlay2、containers、volumes)占用最多空间:
sudo du -h --max-depth=1 /var/lib/docker | sort -h技术支持
不过,对于 Docker Desktop 用户,/var/lib/docker 位于 Docker 的隐藏虚拟机中,无法直接访问。好消息是,无论平台如何,docker system df -v 都能提供所有可执行的信息,是最可靠的诊断方式。
步骤二:使用 Docker Prune 清理系统
确定空间消耗位置后,可用 Docker 内置的清理命令安全回收空间。这些操作旨在仅移除未使用的资源,从而尽量降低对正在运行服务的影响。
清理悬空资源
Docker 区分“dangling”(悬空)与“unused”(未使用)资源。悬空镜像没有标签,也不被任何容器引用,通常是失败或已被取代的构建中间层。这类镜像始终可以安全删除。
从基础的prune 命令开始:
docker system prune技术支持
此命令会移除所有未使用的容器、网络和悬空镜像。除非明确指定,否则不会动带标签的镜像或卷。执行前 Docker 会提示确认。
如需更激进地删除所有未使用的镜像(不只是悬空的),请添加 --all 标志:
docker system prune --all技术支持

Docker system prune
该命令会删除未与任何容器关联的镜像。请谨慎:后续部署需要重新拉取被删除的镜像。
如果要将卷也纳入清理(卷包含持久化数据),请添加 --volumes 标志:
docker system prune --all --volumes技术支持
警告:这将永久删除未使用卷中的数据。使用该标志前请务必确认卷中不包含重要数据。
管理构建缓存
重点在此:构建缓存会存储 Docker 构建操作的中间层,往往是最大的空间消耗者,但 docker system prune 会有意跳过它,以保留构建性能。
要专门清理构建缓存:
docker builder prune技术支持
如果您想有选择地保留近期缓存层,可用基于时间的过滤器:
docker builder prune --filter "until=24h"技术支持
这将仅删除早于 24 小时的缓存层,保留近期工作。
安全清理卷
卷需要格外谨慎,因为其包含持久化数据,如数据库、上传文件和应用状态。删除错误的卷会造成永久性数据丢失。
首先识别悬空卷(未附加到任何容器的卷):
docker volume ls -f dangling=true技术支持
请仔细核查列表。如果确定这些卷不再需要,执行清理:
docker volume prune技术支持
Docker 会在执行前提示确认。如有不确定,先备份卷再清理。
步骤三:处理 Docker 日志文件膨胀
容器日志可能会在不知不觉中占用大量磁盘空间,有时单个容器就会超过 50 GB。
定位膨胀的日志文件
Docker 默认的 json-file 日志驱动会将容器的 stdout 和 stderr 捕获为 JSON 文件。若未配置最大大小(默认 -1,即无限制),这些文件会无限增长。
在所有环境中检查容器大小:
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Size}}"技术支持
检查特定容器的日志文件大小:
ls -lh $(docker inspect --format='{{.LogPath}}' <container-name>)技术支持
仅适用于原生 Linux,直接查找最大的日志文件:
sudo find /var/lib/docker/containers/ -name "*-json.log" -exec du -h {} + | sort -h | tail -10技术支持
如果 docker logs 变慢或容器无法启动,很可能是日志过大所致。此时可通过截断日志来解决。
安全地截断日志
截断日志可立即释放空间。但切勿在容器运行时用 rm 删除日志文件。Docker 守护进程会持有这些日志文件的打开句柄,直接删除会产生“已删除但仍打开”的文件,直到守护进程重启前都仍占用空间。
安全做法是将日志截断为 0:
sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' <container-name>)技术支持
这会立即释放空间且不会破坏文件句柄。容器会继续往同一文件写入。
步骤四:高级排障与隐性问题
若常规清理无效,您很可能遇到了以下不常见但影响同样巨大的问题:
-
inode 耗尽:尽管仍有可用磁盘空间,但文件系统的文件元数据结构已耗尽
-
已删除但仍打开的文件:进程持有已删除文件的句柄,导致“幽灵”空间占用
-
Docker Desktop 虚拟磁盘膨胀:在 VM 内删除数据后,宿主机上的 .raw 或 .vhdx 文件并不会自动缩小
我们分别系统地处理这些情形。
解决 inode 耗尽
这通常由应用创建海量小文件引起,例如 PHP 会话、npm 的 node_modules 或构建产物,都会以惊人的速度消耗 inodes。
首先确认 inode 是否耗尽:
df -i技术支持
使用 Docker 命令(适用于所有环境):
docker ps -a | wc -l
docker images | wc -l
docker image prune -a 技术支持
对于 Linux 安装,定位 inode 密集的目录:
for dir in /var/lib/docker/*/; do
echo "$dir: $(sudo find $dir -type f 2>/dev/null | wc -l) files"
done技术支持
用 docker rmi 删除未使用的镜像也可释放 inodes。若是应用层面的问题,请在容器内实现清理机制,或将临时文件改用卷挂载。
处理已删除但仍打开的文件(仅限 Linux)
当某个文件在仍被进程打开时被删除,文件系统不会释放空间,直到进程关闭该文件句柄(形成“幽灵”空间占用)。
Linux 用户可以通过在打开文件列表中搜索“deleted”条目来验证是否发生了这种情况。
首先识别这些文件:
sudo lsof | grep deleted 技术支持

Docker 已删除文件
然后,重启对应进程(使用 lsof 输出的 PID)或重启 Docker 以释放空间。完成后再次运行该命令,若不再出现这些文件,说明已被正确移除。
接下来探讨最后一个仅适用于 Docker Desktop 的高级排障策略:管理虚拟磁盘。
管理 Docker Desktop 虚拟磁盘
Docker Desktop 会将数据存储在一个虚拟磁盘文件中(Mac 为 .raw,Windows 为 .vhdx),该文件会按需增大,但当您在 VM 内删除数据时并不会自动缩小。您可能清理了镜像和容器,在 VM 内看到可用空间增加,但宿主机磁盘仍然很满。
为此,最安全的做法是使用 fstrim 在不丢失数据的情况下压缩磁盘:
docker run --privileged --pid=host alpine nsenter -t 1 -m -u -i -n fstrim /技术支持
该命令会修剪 Docker Desktop VM 的文件系统,将未使用的块回收至宿主机。您的镜像、容器和卷均保持不变。
如果您希望完全从头开始(这会删除所有数据),也可以通过Docker Desktop Settings → Troubleshoot → Reset to factory defaults 来实现。
警告:这是破坏性操作,将移除所有镜像、容器、卷和设置。仅在其他方法全部无效时作为最后选项。

恢复出厂设置
步骤五:预防 Docker “No Space Left on Device” 错误
在解决燃眉之急后,我们来实施结构性改进以防复发。这些配置需要规划,但能显著提升系统稳定性。
移动 Docker 根目录(仅限 Linux)
Docker Desktop 用户无法轻松更改数据根位置。可选择:
但如果您在 Linux 上,且根分区受限,而另有更大的分区(如专用数据盘),将 Docker 数据目录迁移过去是一个长期方案。
首先停止 Docker:
sudo systemctl stop docker技术支持
编辑 /etc/docker/daemon.json 指定新位置:
{
"data-root": "/mnt/docker-data"
}技术支持
迁移现有数据以保留镜像和容器:
sudo rsync -aP /var/lib/docker/ /mnt/docker-data/技术支持
最后重启 Docker:
sudo systemctl start docker技术支持
Docker 现已在新位置存储所有数据。可通过 docker info | grep "Docker Root Dir" 验证新目录路径。
配置全局日志轮转
日志轮转是我实施过的最有效预防策略。默认情况下,Docker 的 json-file 驱动 max-size: -1(无限制),在生产环境中极易埋下隐患。
对于原生 Linux 安装,在 /etc/docker/daemon.json 中全局施加限制:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}技术支持
修改完成后重启 Docker。
对于 Docker Desktop 用户,不要直接编辑 /etc/docker/daemon.json。请按以下步骤:
- 打开 Docker Desktop
- 进入 Settings → Docker Engine
- 您会看到一个 daemon 配置的 JSON 编辑器
- 在现有 JSON 中添加日志轮转设置:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}技术支持
最后点击Apply & Restart。
该示例将每个容器的日志限制为 3 个文件、每个 10MB(总计 30MB)。
重要提示:这些设置仅对新创建的容器生效。现有容器保留原始日志配置,需重新创建容器以应用新限制。
如需更佳的压缩与性能,可考虑使用 local 日志驱动:
{
"log-driver": "local",
"log-opts": {
"max-size": "10m",
"max-file": "3",
"compress": "true"
}
}技术支持
此外,您也可以在 docker-compose.yml 中为每个服务覆盖日志设置:
services:
web:
image: nginx
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"技术支持
自动化维护
另一个良好做法是将部分流程自动化。常言道,预防胜于危机处理。因此,我建议在维护时段通过 cron 任务自动清理:
sudo cat > /usr/local/bin/docker-cleanup.sh << 'EOF'
#!/bin/bash
docker system prune -f
docker builder prune -f --filter "until=168h"
EOF
sudo chmod +x /usr/local/bin/docker-cleanup.sh
echo "0 2 * * 0 /usr/local/bin/docker-cleanup.sh" | sudo crontab -技术支持
上述脚本会创建一个计划任务,每周日凌晨 2 点自动移除已停止的容器和未使用的数据。同时,它也会安全清理一周(168 小时)以前的构建缓存层,防止磁盘使用无限增长。
此外,请通过多阶段构建优化 Dockerfile,以最小化镜像大小。多阶段构建允许在一个阶段中编译/构建(包含所有开发工具),然后仅将最终产物复制到干净、精简的生产阶段。
这样可将构建依赖、源代码和中间文件排除在最终镜像之外,显著缩减体积并降低攻击面。
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]技术支持
该模式通过排除构建工具和源代码来缩小生产镜像。
结语
修复“No space left on device”遵循可预期的流程:先诊断,明确是磁盘块还是 inodes;再安全清理,在不丢数据的前提下回收空间;最后优化配置,预防复发。
多年管理 Docker 环境的经验告诉我,日志轮转是最有效的预防策略。一个简单的 daemon.json 配置,足以避免大多数空间耗尽事故。
我建议您现在就审查 daemon.json 配置。如果尚未为日志驱动设置 max-size 和 max-file,请立即添加。当您成功避开下一次空间危机时,会感谢现在的自己。
准备好成为 Docker 高手了吗?下一步,报名我们的Containerization and Virtualization with Docker and Kubernetes 技能路径,我强烈推荐。
Docker 出现“No space left on device”错误,往往发生在最糟糕的时机:部署中途、关键构建期间,或拉取重要镜像时。我也多次遇到过这种情况,可以肯定地说,在未正确诊断前就匆忙删除文件,极易导致数据丢失。
这类错误之所以棘手,往往在于它很少只有单一原因。可能是堆积的 Docker 镜像、失控的容器日志、数百万个小文件耗尽了 inodes,或者是被运行进程占用的已删除文件造成的“幽灵”空间。每种情况都需要不同的解决方案。
因此我总是强调:先诊断,再行动。弄清根因能帮助您更高效地采取针对性措施,并避免干扰生产环境。本文将带您系统化地完成诊断、解决与预防这一恼人问题。
如果您是 Docker 新手,建议先学习我们的动手课程Introduction to Docker,它涵盖容器化入门所需的一切。
什么是 Docker “No Space Left on Device” 错误?
当 Docker 抛出该错误时,表明系统存储出现以下两类根本问题之一:
理解二者区别对于采用正确的解决方案至关重要。
导致“No space left on device”错误的根因
首个、也是最直观的原因是物理磁盘块耗尽。文件系统已没有实际可写入的数据空间。这是更容易理解的情形:磁盘被 Docker 镜像、容器、日志或其他文件占满了。
第二个不那么明显的原因是inode 耗尽。即便仍有数 GB 的可用空间,文件系统也可能耗尽 inodes(用于跟踪文件和目录的元数据结构)。每个文件和目录都会消耗一个 inode,因此当应用创建数百万个小文件(如 PHP 会话文件或 npm 的
node_modules目录)时,inodes 会被耗尽,而磁盘空间仍有剩余。了解 overlay2 存储驱动
Docker 通常使用基于 Linux OverlayFS 的 overlay2 存储驱动。OverlayFS 会在单个主机上叠加多个目录,并呈现为统一的文件系统。镜像层以只读的 lower 目录挂载,而每个正在运行的容器会叠加一层很薄的可写 upper 层。容器看到的是合并后的单一目录视图。
overlay2 理论上原生支持最多 128 个 lower 层,但 Docker 的层存储对每个镜像的基底层实际限制为 125 个。它实现了高效的镜像组合,并提升了诸如
docker build和docker commit等操作的性能。尽管 overlay2 的设计比早期存储驱动更少消耗 inodes,但在频繁构建镜像、拉取层或创建容器的环境中,随着时间推移,尤其当镜像或应用层包含大量小文件时,仍会对磁盘块和 inodes 造成显著压力。
该错误的表现因部署环境而异:
在原生 Linux 系统上,它影响支撑 /var/lib/docker 的文件系统。
在Windows 或 macOS 的 Docker Desktop上,限制存在于 Docker 的虚拟机磁盘镜像文件(如
.raw或.vhdx)内,回收或调整存储大小时还需额外考虑。步骤一:诊断根因
在删除任何内容之前,我总会先进行全面诊断。花几分钟做这件事,能为您节省数小时的排错时间,并避免意外的数据丢失。
检查系统层面的容量
先用
df -H(df 即 disk free)检查主机磁盘使用情况:WSL 中检查可用磁盘
该命令以人类可读的格式显示磁盘使用情况。重点关注接近或达到 100% 容量的文件系统。
在原生 Linux 安装中,尤其要留意
/var/lib/docker所在的分区。它通常位于根分区(/)或专用的 Docker 分区。在 Docker Desktop(Windows/Mac)中,请关注主要的文件系统挂载(通常为
/dev/sdf或类似项),它承载 Docker VM 的数据,而非特定的/var/lib/docker,因为 Docker 运行在虚拟机内。接着使用
df -i检查 inode 是否耗尽:检查 inode 是否耗尽
如果某个文件系统的 inode 使用率(
IUse%)为 100%,问题就找到了。这在构建服务器和 CI/CD 环境中非常常见,Docker 会反复创建和销毁包含大量小文件的容器。指标
命令
关注点
磁盘空间
df -H使用率 90%+ 的分区
Inode
df -iIUse%达到 100%Docker 目录
du -h /var/lib/docker总占用大小
分析 Docker 专项使用情况
确定是磁盘空间还是 inode 问题后,进一步审查 Docker 的资源消耗。
docker system df提供在所有 Docker 安装中通用的高层摘要:该输出按四类进行空间占用细分:镜像、容器、本地卷和构建缓存。
RECLAIMABLE列尤为重要。它显示在不影响正在运行的容器前提下,您可以回收的空间量。理解两个指标的区别至关重要:“active” 表示当前被运行的容器使用,“reclaimable” 则表示可以安全释放。如需更细粒度的细节,可添加 verbose 标志:
Docker 使用情况分析
详细输出会逐一列出每个镜像、容器和卷及其大小,帮助您定位“空间大户”。各部分关注要点如下:
Images:显示每个镜像大小及是否在用。留意未使用或以不同标签重复的超大镜像。标记为“unused”的镜像可安全删除,不会影响正在运行的容器。
Containers:展示每个容器可写层的大小。若某个已停止容器的
SIZE很大,说明它向文件系统写入了大量数据。CREATED列可帮助识别可能被遗忘的旧容器。Volumes:列出卷大小及是否在用。未使用的卷可以作为删除候选,但清理前务必确认其中不含重要数据。
Build Cache:常见的最大消耗者且易被忽略。它们是
docker build生成的中间层,用于加速后续构建。操作系统专项命令
对于原生 Linux 用户,如需更深入的文件系统洞察,可直接检查子目录,查看哪些子目录(
overlay2、containers、volumes)占用最多空间:不过,对于 Docker Desktop 用户,
/var/lib/docker位于 Docker 的隐藏虚拟机中,无法直接访问。好消息是,无论平台如何,docker system df -v都能提供所有可执行的信息,是最可靠的诊断方式。步骤二:使用 Docker Prune 清理系统
确定空间消耗位置后,可用 Docker 内置的清理命令安全回收空间。这些操作旨在仅移除未使用的资源,从而尽量降低对正在运行服务的影响。
清理悬空资源
Docker 区分“dangling”(悬空)与“unused”(未使用)资源。悬空镜像没有标签,也不被任何容器引用,通常是失败或已被取代的构建中间层。这类镜像始终可以安全删除。
从基础的prune 命令开始:
此命令会移除所有未使用的容器、网络和悬空镜像。除非明确指定,否则不会动带标签的镜像或卷。执行前 Docker 会提示确认。
如需更激进地删除所有未使用的镜像(不只是悬空的),请添加
--all标志:Docker system prune
该命令会删除未与任何容器关联的镜像。请谨慎:后续部署需要重新拉取被删除的镜像。
如果要将卷也纳入清理(卷包含持久化数据),请添加
--volumes标志:警告:这将永久删除未使用卷中的数据。使用该标志前请务必确认卷中不包含重要数据。
管理构建缓存
重点在此:构建缓存会存储 Docker 构建操作的中间层,往往是最大的空间消耗者,但
docker system prune会有意跳过它,以保留构建性能。要专门清理构建缓存:
如果您想有选择地保留近期缓存层,可用基于时间的过滤器:
这将仅删除早于 24 小时的缓存层,保留近期工作。
安全清理卷
卷需要格外谨慎,因为其包含持久化数据,如数据库、上传文件和应用状态。删除错误的卷会造成永久性数据丢失。
首先识别悬空卷(未附加到任何容器的卷):
请仔细核查列表。如果确定这些卷不再需要,执行清理:
Docker 会在执行前提示确认。如有不确定,先备份卷再清理。
步骤三:处理 Docker 日志文件膨胀
容器日志可能会在不知不觉中占用大量磁盘空间,有时单个容器就会超过 50 GB。
定位膨胀的日志文件
Docker 默认的
json-file日志驱动会将容器的stdout和stderr捕获为 JSON 文件。若未配置最大大小(默认 -1,即无限制),这些文件会无限增长。在所有环境中检查容器大小:
检查特定容器的日志文件大小:
仅适用于原生 Linux,直接查找最大的日志文件:
如果
docker logs变慢或容器无法启动,很可能是日志过大所致。此时可通过截断日志来解决。安全地截断日志
截断日志可立即释放空间。但切勿在容器运行时用
rm删除日志文件。Docker 守护进程会持有这些日志文件的打开句柄,直接删除会产生“已删除但仍打开”的文件,直到守护进程重启前都仍占用空间。安全做法是将日志截断为 0:
这会立即释放空间且不会破坏文件句柄。容器会继续往同一文件写入。
步骤四:高级排障与隐性问题
若常规清理无效,您很可能遇到了以下不常见但影响同样巨大的问题:
inode 耗尽:尽管仍有可用磁盘空间,但文件系统的文件元数据结构已耗尽
已删除但仍打开的文件:进程持有已删除文件的句柄,导致“幽灵”空间占用
Docker Desktop 虚拟磁盘膨胀:在 VM 内删除数据后,宿主机上的
.raw或.vhdx文件并不会自动缩小我们分别系统地处理这些情形。
解决 inode 耗尽
这通常由应用创建海量小文件引起,例如 PHP 会话、npm 的
node_modules或构建产物,都会以惊人的速度消耗 inodes。首先确认 inode 是否耗尽:
使用 Docker 命令(适用于所有环境):
对于 Linux 安装,定位 inode 密集的目录:
用
docker rmi删除未使用的镜像也可释放 inodes。若是应用层面的问题,请在容器内实现清理机制,或将临时文件改用卷挂载。处理已删除但仍打开的文件(仅限 Linux)
当某个文件在仍被进程打开时被删除,文件系统不会释放空间,直到进程关闭该文件句柄(形成“幽灵”空间占用)。
Linux 用户可以通过在打开文件列表中搜索“deleted”条目来验证是否发生了这种情况。
首先识别这些文件:
Docker 已删除文件
然后,重启对应进程(使用
lsof输出的 PID)或重启 Docker 以释放空间。完成后再次运行该命令,若不再出现这些文件,说明已被正确移除。接下来探讨最后一个仅适用于 Docker Desktop 的高级排障策略:管理虚拟磁盘。
管理 Docker Desktop 虚拟磁盘
Docker Desktop 会将数据存储在一个虚拟磁盘文件中(Mac 为
.raw,Windows 为.vhdx),该文件会按需增大,但当您在 VM 内删除数据时并不会自动缩小。您可能清理了镜像和容器,在 VM 内看到可用空间增加,但宿主机磁盘仍然很满。为此,最安全的做法是使用
fstrim在不丢失数据的情况下压缩磁盘:该命令会修剪 Docker Desktop VM 的文件系统,将未使用的块回收至宿主机。您的镜像、容器和卷均保持不变。
如果您希望完全从头开始(这会删除所有数据),也可以通过Docker Desktop Settings → Troubleshoot → Reset to factory defaults 来实现。
警告:这是破坏性操作,将移除所有镜像、容器、卷和设置。仅在其他方法全部无效时作为最后选项。
恢复出厂设置
步骤五:预防 Docker “No Space Left on Device” 错误
在解决燃眉之急后,我们来实施结构性改进以防复发。这些配置需要规划,但能显著提升系统稳定性。
移动 Docker 根目录(仅限 Linux)
Docker Desktop 用户无法轻松更改数据根位置。可选择:
增加磁盘空间:使用步骤四所述的虚拟磁盘压缩方法
对于 WSL2 后端:通过
.wslconfig文件进行管理,路径见 Docker Desktop Settings → Resources但如果您在 Linux 上,且根分区受限,而另有更大的分区(如专用数据盘),将 Docker 数据目录迁移过去是一个长期方案。
首先停止 Docker:
编辑
/etc/docker/daemon.json指定新位置:迁移现有数据以保留镜像和容器:
最后重启 Docker:
Docker 现已在新位置存储所有数据。可通过
docker info | grep "Docker Root Dir"验证新目录路径。配置全局日志轮转
日志轮转是我实施过的最有效预防策略。默认情况下,Docker 的
json-file驱动max-size: -1(无限制),在生产环境中极易埋下隐患。对于原生 Linux 安装,在
/etc/docker/daemon.json中全局施加限制:修改完成后重启 Docker。
对于 Docker Desktop 用户,不要直接编辑
/etc/docker/daemon.json。请按以下步骤:最后点击Apply & Restart。
该示例将每个容器的日志限制为 3 个文件、每个 10MB(总计 30MB)。
重要提示:这些设置仅对新创建的容器生效。现有容器保留原始日志配置,需重新创建容器以应用新限制。
如需更佳的压缩与性能,可考虑使用 local 日志驱动:
此外,您也可以在
docker-compose.yml中为每个服务覆盖日志设置:自动化维护
另一个良好做法是将部分流程自动化。常言道,预防胜于危机处理。因此,我建议在维护时段通过 cron 任务自动清理:
上述脚本会创建一个计划任务,每周日凌晨 2 点自动移除已停止的容器和未使用的数据。同时,它也会安全清理一周(168 小时)以前的构建缓存层,防止磁盘使用无限增长。
此外,请通过多阶段构建优化 Dockerfile,以最小化镜像大小。多阶段构建允许在一个阶段中编译/构建(包含所有开发工具),然后仅将最终产物复制到干净、精简的生产阶段。
这样可将构建依赖、源代码和中间文件排除在最终镜像之外,显著缩减体积并降低攻击面。
该模式通过排除构建工具和源代码来缩小生产镜像。
结语
修复“No space left on device”遵循可预期的流程:先诊断,明确是磁盘块还是 inodes;再安全清理,在不丢数据的前提下回收空间;最后优化配置,预防复发。
多年管理 Docker 环境的经验告诉我,日志轮转是最有效的预防策略。一个简单的
daemon.json配置,足以避免大多数空间耗尽事故。我建议您现在就审查
daemon.json配置。如果尚未为日志驱动设置max-size和max-file,请立即添加。当您成功避开下一次空间危机时,会感谢现在的自己。准备好成为 Docker 高手了吗?下一步,报名我们的Containerization and Virtualization with Docker and Kubernetes 技能路径,我强烈推荐。