Docker磁盘空间爆满?73GB构建缓存清理实战指南

291 阅读9分钟

前言

公司线上报警群又开始报警了,磁盘空间超过80%,作为兼职运维工作的测试人员,慌的一批, 赶紧下手排查回复。

报警信息

信息源

报警信息如下,

image.png

通过报警信息,可以看到是 Prometheus 告警显示某台机器的磁盘使用率超过 80% ,接下来看看 监控命令是怎么写的

监控命令

登录 Prometheus 监控网站,可以看到监控命令如下:

(max by(device, instance) (node_filesystem_size_bytes{device=~"/dev/.*",fstype!=""}) - max by(device, instance) (node_filesystem_avail_bytes{device=~"/dev/.*",fstype!=""})) / max by(device, instance) (node_filesystem_size_bytes{device=~"/dev/.*",fstype!=""}) * 100 >= 80

这个 PromQL 查询用于 监控文件系统磁盘使用率,它会找出 磁盘使用率超过 80% 的挂载点。我们来逐步解析:

查询分解

计算已用磁盘空间
(max by(device, instance) (node_filesystem_size_bytes{device=~"/dev/.*",fstype!=""})
-
max by(device, instance) (node_filesystem_avail_bytes{device=~"/dev/.*",fstype!=""})
  • node_filesystem_size_bytes :文件系统总大小(字节)
  • node_filesystem_avail_bytes :文件系统可用空间(字节)
  • max by(device, instance) :按 device (磁盘设备名)和 instance (主机实例)分组,取最大值(避免重复数据)
  • device=~"/dev/.*" :只匹配 /dev/ 开头的设备(物理磁盘、分区等)
  • fstype!="" :排除未定义文件系统类型的记录
  • 结果 :得到每个磁盘设备的 已用空间 (总大小 - 可用空间)。
计算使用率百分比
(已用空间) / max by(device, instance) (node_filesystem_size_bytes{...}) * 100
  • 用 已用空间 除以 总空间 ,再乘以 100,得到使用率百分比。

排查过程

了解了大背景后,我们正式进入排查。

1. 确认磁盘使用情况

登录目标机器,验证磁盘状态:

# 查看整体磁盘使用情况
df -h

执行后,输出结果如下:

Filesystem      Size  Used Avail Use% Mounted on
udev            3.8G     0  3.8G   0% /dev
tmpfs           768M  732K  767M   1% /run
/dev/vda1       148G   120G  28G  81% /
tmpfs           3.8G     0  3.8G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           3.8G     0  3.8G   0% /sys/fs/cgroup
tmpfs           768M     0  768M   0% /run/user/0

从输出结果可以看出,根目录 / 占用了 81% 的空间。

  • 这里 / 是挂载点,对应的设备是 /dev/vda1 ,它们会被上述 PromQL 查询覆盖。

额外知识点:如果只想监控特定挂载点(如 / 或 /var
需要在查询中显式指定 mountpoint 标签:

(
  max by(device, instance, mountpoint) (node_filesystem_size_bytes{device=~"/dev/.*", mountpoint="/", fstype!=""})
  -
  max by(device, instance, mountpoint) (node_filesystem_avail_bytes{device=~"/dev/.*", mountpoint="/", fstype!=""})
)
/
max by(device, instance, mountpoint) (node_filesystem_size_bytes{device=~"/dev/.*", mountpoint="/", fstype!=""})
* 100 >= 80

接下来,查看根目录下的文件大小(按大小排序),执行如下命令:

du -sh /* 2>/dev/null | sort -h

这条命令用于快速分析 Linux 根目录 / 下各子目录的磁盘占用情况,并按排序输出。

  • du -sh /*# 计算根目录下所有一级子目录的总大小
  • 2>/dev/null# 屏蔽无权限访问的目录报错(如 /proc/sys
  • sort -h# 按大小排序结果

执行后,输出结果如下:

0	/bin
0	/dev
0	/lib
0	/lib32
0	/lib64
0	/libx32
0	/proc
0	/sbin
0	/sys
4.0K	/mnt
4.0K	/srv
12K	/media
16K	/lost+found
80K	/home
92K	/tmp
732K	/run
5.4M	/etc
145M	/boot
2.7G	/opt
11G	/usr
21G	/root
79G	/var

从输出结果,可以看出/var 目录占用了 79G 空间,这是最大的目录。

额外知识点:
du 需要递归统计每个目录下所有文件大小,执行上面命令会有点慢,我们可以扫描可疑的大目录,命令如下

du -sh /var /usr /home /opt 2>/dev/null | sort -h

2. 定位大文件/目录

快速找出占用空间最多的目录:

第一步,我们已经确认 /var 是占用最多的目录,继续深入,查询 /var 目录下子目录大小

du -h --max-depth=1 /var 2>/dev/null | sort -h
  • --max-depth=1:仅统计 /var 下的一级子目录(不递归子目录的子目录)

执行后,输出结果如下,

4.0K	/var/local
4.0K	/var/mail
4.0K	/var/opt
12K	/var/www
28K	/var/spool
36K	/var/tmp
1.8M	/var/backups
98M	/var/log
114M	/var/cache
79G	/var
79G	/var/lib

从输出结果可以看出,/var/lib 目录占用了 79G 空间,这是最大的目录,继续深入查询 /var/lib 目录下子目录大小,执行命令

du -h --max-depth=1 /var/lib | sort -h

执行后,输出结果如下,

4.0K	/var/lib/dbus
4.0K	/var/lib/dhcp
4.0K	/var/lib/git
4.0K	/var/lib/lsb
4.0K	/var/lib/man-db
4.0K	/var/lib/misc
4.0K	/var/lib/os-prober
4.0K	/var/lib/plymouth
4.0K	/var/lib/private
4.0K	/var/lib/python
4.0K	/var/lib/resolvconf
4.0K	/var/lib/rpm
4.0K	/var/lib/update-notifier
8.0K	/var/lib/logrotate
8.0K	/var/lib/sudo
8.0K	/var/lib/ubuntu-release-upgrader
8.0K	/var/lib/vim
12K	/var/lib/AccountsService
12K	/var/lib/chrony
12K	/var/lib/initramfs-tools
12K	/var/lib/locales
12K	/var/lib/update-manager
16K	/var/lib/grub
16K	/var/lib/polkit-1
28K	/var/lib/pam
40K	/var/lib/php
132K	/var/lib/nginx
260K	/var/lib/ucf
296K	/var/lib/cloud
424K	/var/lib/systemd
444K	/var/lib/containerd
608K	/var/lib/usbutils
2.3M	/var/lib/ubuntu-advantage
3.2M	/var/lib/command-not-found
34M	/var/lib/dpkg
293M	/var/lib/apt
78G	/var/lib/docker
79G	/var/lib

好了,到这里可以确定/var/lib/docker 目录占用了 78G

3. 检查 Docker 磁盘占用

从上一步,我们知道/var/lib/docker 目录占用了比较多的空间,接下来就可以检查 Docker 磁盘占用,执行如下命令:

docker system df

执行后,输出结果如下:

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          3         2         1.431GB   397.6MB (27%)
Containers      9         0         19.89kB   19.89kB (100%)
Local Volumes   15        0         83.74MB   83.74MB (100%)
Build Cache     1319      0         73.76GB   73.76GB

真相大白 :Docker 构建缓存是罪魁祸首!
通过输出结果,发现 Build Cache(构建缓存)独占 73.76GB ,且完全可回收!

4. 清理构建缓存

一键清理所有缓存

docker builder prune --all
  • --all :强制清理所有构建缓存(包括未被引用的层)。
  • 效果 :73.76GB 空间立即释放!

深度清理

也可以删除所有未使用的镜像、容器、卷、网络和缓存

docker system prune -a --volumes

注意 :此操作会删除所有未被使用的资源(谨慎操作)。

我这里主要是构建缓存造成的占用率很高,清除缓存之后,再次执行df -h, 发现空间已经恢复正常,关键输出结果如下,

Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1       148G   36G  106G  26% /

可以看到已经从开始的 81% ,变为了现在的 26%。

预防措施

限制构建缓存大小

编辑 Docker 配置文件 /etc/docker/daemon.json

{
  "builder": {
    "gc": {
      "enabled": true,
      "defaultKeepStorage": "10GB"
    }
  }
}

重启 Docker:

sudo systemctl restart docker

设置定期清理任务

通过 Crontab 每周自动清理:

0 3 * * 0 docker builder prune --all -f && docker system prune -a -f --volumes

优化 Dockerfile

  • 使用 .dockerignore 排除非必要文件。
  • 将高频变化的指令(如 RUN apt-get update )放在文件后部。

最后

经过层层排查,发现是 Docker 构建缓存占用了比较多的空间,导致磁盘空间占用率较高,清理构建缓存后,恢复正常, 磁盘告警终于消失了,报警群又恢复了往日的安静。

附录:常用命令速查表

命令作用
docker system df查看 Docker 磁盘占用
docker build prune --all清除构建缓存
docker system prune -a --volumes清理所有未使用资源
du -h --max-depth=1 /var/lib | sort -h 分析目录大小