Docker 主机磁盘突然告警,往往不是镜像本身太大,而是某个容器持续写入日志、缓存、临时文件或应用数据,最终撑满可写层。🚨 如果只执行清理命令而不定位写入源,空间很快还会再次失控。下面从配额配置、占用识别、文件定位和长期治理四个方面给出一套可直接执行的排查方案。
一、先分清 Docker 空间由谁占用
Docker 磁盘占用主要包括镜像层、容器可写层、数据卷、构建缓存以及容器日志。镜像层通常可被多个容器共享,容器运行期间新建或修改的文件则进入可写层。按照 Docker 存储驱动文档 的说明,需要持久化或频繁写入的数据更适合放在 volume 中,而不是长期堆积在容器可写层。
首先查看整体占用:
docker system df
docker system df -v
详细模式可以分别展示镜像、容器和本地卷的空间信息,适合作为第一轮筛查。命令字段及输出含义可参考 docker system df 官方说明。随后检查宿主机文件系统,确认是否确实为 Docker 数据目录所在分区告警:
df -h
df -ih
docker info | grep -E "Docker Root Dir|Storage Driver|Backing Filesystem"
注意:磁盘容量正常但 inode 使用率达到上限时,同样无法创建新文件。大量细碎缓存、会话文件或临时文件,通常是 inode 异常增长的主要嫌疑。
二、快速锁定失控容器
使用以下命令查看所有容器的可写层大小:
docker ps -a --size
其中 SIZE 表示容器可写层占用,virtual size 还会计入镜像层,排查时不要把两者混为一谈。如果某个容器的 SIZE 持续增长,可进一步进入容器检查目录:
docker exec 容器名 sh -c 'du -x -h -d 1 / 2>/dev/null | sort -h'
再针对异常目录逐层执行 du,例如检查 /var、/tmp、/app 和应用日志目录。如果容器内查看的文件总量不大,但宿主机空间仍被占用,应检查“文件已删除、进程仍持有句柄”的情况:
lsof +L1 | grep /var/lib/docker
这类文件只有在相关进程关闭文件描述符后才会真正释放空间。优先让应用重新打开日志文件,必要时再滚动重启对应容器,避免直接重启整台主机扩大影响。
容器日志是最常见的隐形增长点
默认 json-file 日志可能随标准输出持续增长。可在宿主机检查日志文件:
find /var/lib/docker/containers -name '*-json.log' -printf '%s %p\n' | sort -n | tail
生产环境建议在 /etc/docker/daemon.json 中设置日志轮转,例如:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
修改后先用 dockerd --validate --config-file=/etc/docker/daemon.json 校验配置,再重启 Docker。已有容器通常需要重新创建才能应用新的日志选项,因此更稳妥的做法是在 Compose 或部署平台中同时声明日志策略。🔧
三、为单个容器设置磁盘配额
单容器空间限制依赖存储驱动和底层文件系统,不能认为所有环境都支持同一种参数。先执行 docker info 核实实际存储后端。对于经典 overlay2 环境,底层使用 XFS 时还要确认 d_type 支持情况;相关前提可查看 OverlayFS 官方文档。
在支持配额的环境中,可在启动容器时限制可写层:
docker run --storage-opt size=10G 镜像名
这里限制的是容器可写层,并不等于限制挂载的数据卷、绑定目录或外部存储。数据库文件如果写入 volume,仍需要在宿主机文件系统、存储系统或编排平台层面单独配置配额。
如需设置 overlay2 默认可写层大小,可以在 daemon.json 中配置 storage-opts,但该能力与 Docker 版本、存储后端和 XFS project quota 条件密切相关。实施前应在测试节点验证,并完成镜像、容器配置和业务数据备份。切换存储驱动可能导致原有镜像与容器暂时不可访问,不能直接在生产节点冒险操作。
四、按风险顺序处理磁盘告警
- 先止写:暂停异常任务、降低日志级别或临时切走流量,防止磁盘继续被写满。
- 再定位:结合 docker system df -v、docker ps -a --size、du、find 和 lsof 判断是可写层、日志、volume 还是已删除文件。
- 谨慎释放:优先删除业务确认无用的临时文件和缓存,不要直接手工删除 /var/lib/docker 下的未知目录。
- 清理闲置资源:使用 docker container prune、docker image prune、docker builder prune 前先查看待删除对象;docker system prune --volumes 风险更高,不应作为默认急救命令。
- 验证恢复:重新执行 df -h、df -ih 和 docker system df -v,并观察一段时间内空间是否继续增长。
五、建立长期防失控机制
- 为容器日志统一设置 max-size 和 max-file,并监控日志增长速率。
- 将数据库、上传文件等持久化数据放入受控 volume,避免写入容器根目录。
- 同时监控容量、inode、容器可写层和 volume,不只关注宿主机总磁盘。
- 为 Docker 数据目录预留独立分区,减少其占满系统根分区的风险。
- 对缓存目录设置过期策略,对异常增长设置分级告警。📊
- 在镜像构建阶段清理包管理器缓存,并减少无意义的大文件复制。
总结
Docker 单容器空间失控的处理原则是:先确认存储后端,再区分镜像、可写层、日志和数据卷,最后根据真实写入位置配置限制。磁盘配额只能控制特定存储层,不能替代日志轮转、业务数据治理和容量监控。把配额、轮转、告警和定期巡检组合起来,才能从根本上避免某个容器拖垮整台宿主机。✅