Preface
在日常使用 Linux 系统的过程中,尤其是磁盘空间有限的云主机用户,很多人都会遇到磁盘空间逐渐被占满的情况。
导致磁盘空间紧张的原因有很多,比如系统生成的大量日志文件、Docker 镜像占用空间、包管理器的缓存未清理等。面对这些不同的原因,清理方法也各不相同。为了帮助大家更高效地管理系统空间,我在这篇教程中总结了几种常见的空间占用问题及其对应的清理方法,希望能让你在遇到空间不足时能够快速排查到具体的原因并高效的解决问题。
清理步骤
1、查看文件系统磁盘使用率
在开始清理之前,我们需要对磁盘的总体占用情况有个谱,这一步通过使用df -h
命令来实现的,其中,”-h”参数是使用人类可读格式,在显示空间使用情况时会使用 KB、MB、GB 等单位。以下是通常的一个df -h
命令输出:
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 20G 28G 42% /
tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs 7.8G 1.5G 6.3G 20% /run
/dev/sdb1 200G 50G 150G 25% /mnt/data
输出字段解释:
2、确认磁盘空间占用高的原因及针对性清理
按照常规经验,磁盘空间的高占用一般和以下几方面原因有关。
日志文件造成的磁盘空间占用
系统日志
搜寻目标
通常,系统日志文件的路径是/var/log
,所以如果是日志文件引起的磁盘空间紧张,那么/var
会有异常,此时df -h
命令的显示可能如下:
从上面这张图可以看出,/var
目录直接占用了45G空间,当然,这是将/var
路径单独挂载到路径/dev/sda2
时的显示,而对于一般硬盘空间不大的云主机,更可能是所有内容都在一个分区,所以更可能是如下的显示:
由于此时
/var
目录是在主分区的一部分,需要进一步判断是否是/var/log
目录占用了空间,可以使用du命令:
du -ah /var/log | sort -n -r | head -n 10
此命令将列出/var/log
目录下占用空间最多的前10个文件和目录,可能的输出如下:
在这个例子中,/var/log/syslog
and /var/log/auth.log
占据了最多的空间,所以应该是最优先处理的。
清空系统日志
使用如下命令清空系统日志文件内容又保留日志文件本身:
truncate -s 0 /var/log/messages
详细解释:
• truncate:这是一个用于调整文件大小的命令。它可以用来扩展或缩小文件。
• -s 0:这个参数将文件的大小设置为 0 字节。也就是说,它把文件内容清空,但保留文件的元信息(如权限、所有者等)。
这条命令的效果是清空 /var/log/messages 文件的内容,而不删除文件本身。它是管理日志文件时常用的操作,特别是在日志文件过大时,清空文件以释放空间,但保持日志文件结构和权限不变。
应用日志
搜寻目标
除了系统日志文件以外,不同的应用可能会在其他位置存放日志,以docker为例说明,默认情况下,docker 在 Linux 系统下使用 JSON 文件格式记录日志,并将日志存储在 /var/lib/docker/containers/[container-id]/[container-id]-json.log
路径中,仍旧可以用du
命令查看:
du -h /var/lib/docker/containers/*/*-json.log | sort -hr
该命令解释如下:
• du -h
: 递归地显示每个日志文件的大小,并使用人类可读的格式(如 KB、MB)。
• /var/lib/docker/containers/*/*-json.log
: 这是 Docker 默认的日志文件路径,匹配所有容器的日志文件。
• sort -hr
: 按大小递减排序。
• -h
: 按人类可读格式进行排序。
• -r
: 递减顺序排序。
该命令可能会显示如下结果:
按照前面的逻辑,也应该按优先级从上到下的方式处理。
清空应用日志
然后可以按照前面的方式,使用truncate 命令来清空该日志文件:
truncate -s 0 /var/lib/docker/containers//-json.log
这会将日志文件的大小设置为 0 字节,但文件本身仍然存在,Docker 也会继续往该文件中写入新的日志。
需要注意的事项:
• 不会影响容器运行:清空日志文件不会影响正在运行的容器,它们会继续记录新的日志。
• 定期清理日志:Docker 默认不会自动清理日志,因此日志文件可能会变得很大。你可以定期使用这种方法清理日志,也可以配置 Docker 限制日志文件的大小。
要限制docker日志,有2种方式:
1、日志轮转机制:可以配置 Docker 的日志轮转机制,限制日志文件的大小和保留的日志数量。
为了防止日志文件过大,可以在 Docker 启动容器时配置日志轮转,示例如下:
docker run --log-opt max-size=10m --log-opt max-file=3 ...
这表示每个日志文件最大 10MB,最多保留 3 个日志文件。
2、修改docker配置:可以通过修改 Docker 配置文件来限制容器日志大小
- 找到或创建 Docker 的配置文件:
Docker 的配置文件通常是 /etc/docker/daemon.json,如果该文件不存在,你可以手动创建。
- 编辑daemon.json文件:
打开 /etc/docker/daemon.json 文件,添加或修改日志限制配置。具体的日志选项如下:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m", // 每个日志文件最大为10MB
"max-file": "3" // 最多保留3个日志文件
}
}
这段配置的含义是:
• log-driver:设置日志驱动为 json-file(Docker 默认使用的日志驱动)。
• max-size:限制每个日志文件的最大大小为 10MB。当日志文件达到这个大小时,会自动开始写新的日志文件。
• max-file:最多保留 3 个日志文件。超过这个数量后,最旧的日志文件将被删除。
- 重启 Docker 服务:
修改完配置文件后,需要重启 Docker 服务使其生效:
sudo systemctl restart docker
- 验证配置是否生效:
你可以通过以下命令查看 Docker 当前的日志选项,确认设置是否生效:
docker info | grep 'Logging Driver'
如果一切正常,所有新启动的容器将按照设置的日志限制来管理日志文件。
注:该配置将适用于所有新启动的容器,已经在运行的容器不会自动受到影响。如果需要现有容器应用日志限制,可以先停止并删除这些容器,然后根据新配置重新启动这些容器。
应用造成的磁盘空间占用
这种场景就要根据不同的应用分别来看了,无法一概而论,所以我以最容易遇见的docker镜像文件所造成的空间占用情况来分析。
搜寻未使用的镜像
docker本身最常见的占用是image文件引起的,比如安装wordpress的时候,当使用了命令docker pull wordpress
,默认是拉取最新版本的镜像,也就是加了:latest
标签,如果这个时候使用docker run
命令创建容器,就是使用的最新版本,那么老版本的镜像就没用了;如果容器多偏偏又喜欢升级,那么遗留下的未使用的镜像就会占用很大的空间。
使用以下命令查看未使用的docker镜像(悬空镜像):
docker images -f "dangling=true"
所谓悬空镜像,即那些没有标签的镜像,通常悬空镜像是由于重新构建或更新镜像时留下的旧镜像,但是,这个命令不能显示那些有标签却未被容器使用的镜像。
如果要想要查看”所有未被任何容器使用的镜像”,而不仅仅是悬空镜像,就有点麻烦,因为docker没有直接的命令来列出”所有未被容器使用的镜像”,因此一般有如下2种方式来实现:
- 脚本大法
要实现上述功能,需要直接运行以下脚本:
docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" | while read line; do
img=(echoline | awk '{print 2}');
if ! docker ps -a --filter "ancestor=img" --format "{{.Image}}" | grep -q img; then
echoline;
fi;
done
这个脚本的原理是:
- 列出所有镜像
- 检查这些镜像是否被任何容器使用
- 如果没有被使用,则输出该镜像
- 人眼观测大法
使用以下命令:
• docker images -a:列出所有镜像,包括被使用和未被使用的。
• docker ps -a:列出所有容器,包括运行中的和停止的容器。
然后使用高阶技能”人眼观测大法”:人工对比这两个命令的输出,自己找到所有未被任何容器使用的镜像。
附加知识:overlay和overlay2
我们在使用dh -f
命令时,可能会遇到如下类似的输出:
那么,这个红框中的overlay是什么呢?
在使用 Docker 时,overlay 和 overlay2 是两种常见的存储驱动,它们决定了 Docker 如何在文件系统中管理容器的文件和镜像层。Docker 使用这些存储驱动来提供 联合文件系统(Union Filesystem) 的功能,以高效地管理容器镜像和层。
- Overlay(OverlayFS)
overlay 是一种早期的存储驱动,使用 Linux 内核中的 OverlayFS 实现。它通过将多个文件系统层“叠加”在一起,使容器能够共享相同的基础镜像层,而不需要为每个容器复制整个文件系统。这种机制允许容器更轻量化并节省磁盘空间。
特点:
• 镜像层叠加:每个 Docker 镜像由多个只读层构成,当启动容器时,Docker 会在这些只读层的顶部叠加一个可写层。任何写入操作都会发生在这个可写层中,避免修改基础层。
• 较低的性能:相对于 overlay2,overlay 的性能稍差,尤其是在管理大量层时。
不足:
• 支持的层数较少:overlay 支持的镜像层数较少,当层数超过一定数量时会导致性能问题。
• 逐渐被淘汰:由于 overlay 的局限性,Docker 后来引入了 overlay2,并逐渐推荐使用后者。
- Overlay2
overlay2 是 overlay 的改进版,也基于 Linux 的 OverlayFS,但解决了 overlay 的一些性能瓶颈和限制。自 Docker 1.13 版本起,overlay2 成为推荐的默认存储驱动,适用于更广泛的场景,尤其是需要处理更多镜像层的情况下。
特点:
• 支持多层叠加:overlay2 允许 Docker 使用单个文件系统层来表示镜像的多个层,从而提高了性能和效率。即使 Docker 镜像有很多层,它也能更好地处理,不会像 overlay 那样因层数多导致性能下降。
• 性能更优:相比 overlay,overlay2 具有更好的写入和读取性能,尤其是在处理大量层或文件时。
改进:
• 减少空间浪费:在多个容器共享相同镜像层的场景下,overlay2 能够更高效地使用存储空间,避免不必要的文件复制。
• 减少系统调用:通过简化文件操作,overlay2 提高了文件系统操作的性能。
虽然overlay2看起来更好,但是我们通常也不会手动去指定使用,在安装 Docker 时,存储驱动的选择通常是由 Docker 根据操作系统的内核自动决定的,用户通常不需要手动指定存储驱动。例如,当你使用 apt 安装 Docker 时,Docker 会检测你的系统环境并选择最合适的存储驱动,通常应该是 overlay2,因为它是目前的推荐默认驱动。
所以大家看到这个输出也不要意外,关注右边对应的具体路径即可。
清理镜像
确定要清理未使用的镜像,可以直接使用以下命令:
docker image prune -a
这会删除所有未被任何容器使用的镜像,包括带标签的镜像。需要谨慎使用,因为删除后需要重新拉取或重新构建这些镜像。
另外,如果部署了Portainer之类的docker图形管理UI,其实也方便操作,只要在Images里的Filter中勾选”Unused”,即可直接看到所有未使用的镜像,如下图所示:
然后只需要选中所有未使用的镜像,然后点击”Remove”即可,如下图:
注:其他还有一些应用,比如mysql(mariadb)造成的空间占用,清理需要一定的专业知识来支撑,我这里就不多提了。
包管理器缓存文件造成的磁盘空间占用
包管理器缓存(如debian系统中的apt)的未清理,通常是因为系统安装和升级过程中下载的软件包缓存长期堆积,导致占用大量磁盘空间,以下是几种常见的原因和解决方法:
APT 缓存堆积
当使用 apt 或 apt-get 安装和更新软件时,系统会将下载的 .deb 安装包保存在缓存目录中(通常是 /var/cache/apt/archives)。如果没有定期清理,这些缓存文件会长期占用空间。
清理方案:
• 手动清理 APT 缓存
使用以下命令来清理缓存:
sudo apt clean
该命令会删除所有已下载的 .deb 包文件。
• 自动清理未使用的软件包
使用以下命令清理系统上不再需要的包文件,包括依赖和旧版本:
sudo apt autoremove
• 仅清理过时的缓存:
apt-get autoclean 会删除过时的软件包缓存文件(即不再可用或被替换的缓存):
sudo apt-get autoclean
未自动清理缓存
系统默认不会自动清理下载的缓存文件,尤其是当系统经常进行更新和安装操作时,缓存文件容易积累。
清理方案:
• 启用定期自动清理:
可以通过设置系统定期清理缓存文件来避免长时间不清理的问题。可以创建定期清理任务:
- 使用 cron 定期运行 apt clean 命令。
- 通过 /etc/cron.daily/apt 或自定义 cron 作业,确保定期自动执行清理。
配置 cron 任务(例如每月清理一次)
- 打开 cron 编辑器:
sudo crontab -e
- 添加以下内容来每月清理一次:
@monthly apt clean
未使用的软件包和旧版本累积
系统升级后,某些软件包的旧版本和不再需要的依赖项会留在系统中,这些未清理的包会占用磁盘空间。
清理方案:
• use apt autoremove 清理不再需要的软件包:
sudo apt autoremove
命令会清理所有不再使用的依赖项和软件包,释放磁盘空间。
其他情况造成的磁盘空间占用
这种方式主要是因为用户自行下载的文件或系统中的临时文件(如 /tmp 目录)如果长期未清理,可能会占用大量磁盘空间,这时一般按前面排查的思路,使用df -h
anddu -h --max-depth=1
命令交替着一级一级排查,找出临时文件或目录占用过大的情况,然后使用rm
命令进行删除即可,我就不重复讲了。
Afterword
虽然我在本文中总结了几种常见的磁盘空间占用问题及其对应的清理方法,但难免会有疏漏之处,特别是某些应用本身所导致的空间占用问题(例如 Docker 镜像等)。只不过,即便本文未详细涉及某些特定情境,但是通过文中提到的排查思路,使用df -h
查看整体磁盘使用情况,再结合du -h --max-depth=1
一步步深入目录排查占用源,最终也能够帮助你找到造成空间紧张的“罪魁祸首”,并采取相应的清理措施。
希望这篇教程能为大家提供思路,帮助大家更好地管理linux系统的磁盘空间。