☰
CentOS服务器磁盘爆满排查:Docker日志清理与存储管理实战
2026/9/28 2:09:13 网站建设 项目流程

1. 项目概述:当磁盘爆满成为运维的日常

“磁盘空间不足”这个报错,对于任何一个在服务器上跑过生产环境的人来说,都太熟悉了。它不像内存溢出那样瞬间致命,却像慢性病一样,悄无声息地侵蚀着系统的健康,直到某一天,你的应用无法写入日志,数据库无法创建临时表,甚至系统连SSH都登录不上,你才惊觉/dev/vda1这个根分区已经亮起了刺眼的100%红灯。尤其是在我们广泛使用Docker容器化部署的今天,这个问题变得尤为高频和隐蔽。很多人第一反应是“删点日志”或者“清理下缓存”,但往往治标不治本,过几天问题又卷土重来。今天,我就结合一次真实的线上故障处理,从头到尾拆解一下CentOS系统下,特别是由Docker引发的磁盘空间占满问题的系统性排查与根治思路。这不仅仅是一次清理操作,更是一次对服务器存储管理的深度体检。

我们面对的场景很典型:一台跑着多个Docker容器的CentOS 7.9服务器,df -h命令显示/dev/vda1挂载的根目录使用率100%,可用空间为0。业务开始出现写入失败的错误。盲目删除文件是危险的,因为你可能删掉关键数据或正在被进程打开的文件,导致服务异常。我们的目标,是像外科手术一样,精准定位“病因”(哪些文件/目录在疯狂增长),评估“病情”(是否可安全清理),并实施“治疗方案”(清理、转移或扩容),同时建立“预防机制”(避免问题复发)。这个过程,适用于任何Linux发行版,但我们会聚焦在CentOS和Docker这个经典组合上。

2. 核心思路:从宏观到微观的排查路径

处理磁盘满的问题,最忌讳的就是无头苍蝇似的乱删。一个清晰的排查路径至关重要。我的思路通常是自上而下,从文件系统整体视角逐步深入到具体的罪魁祸首文件。

2.1 第一步:确认整体磁盘使用情况

首先,我们需要一个全局视野。使用df -h命令。这个命令大家都会用,但关键要看懂输出里的细节。

df -h

你会看到类似下面的输出:

文件系统 容量 已用 可用 已用% 挂载点 /dev/vda1 50G 50G 0B 100% / devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 1.1M 3.9G 1% /run tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup

这里明确告诉我们,问题是出在根分区/dev/vda1上。可用为0B,已用100%。-h参数让数据以人类可读的G、M单位显示,更直观。

注意:有时候df显示的空间和实际文件大小之和对不上,这可能是因为文件系统保留了约5%的空间给root用户(使用tune2fs -l /dev/vda1 | grep ‘Reserved block count’查看),或者是存在已经被删除但仍有进程在占用的文件(这些文件不会释放空间,直到进程结束)。这是我们后续需要排查的一个点。

2.2 第二步:定位占用空间的大目录

知道了是根分区满了,接下来就要找是哪个“坏小子”目录吃掉了大部分空间。这里祭出神器du(disk usage)命令。但直接du -sh /*可能会因为权限问题有些目录报错,而且输出杂乱。我常用的组合命令是:

cd / sudo du -sh * 2>/dev/null | sort -rh | head -20

这个命令分解一下:

  • cd /:切换到根目录。
  • sudo:因为有些目录需要root权限才能查看。
  • du -sh *:以人类可读的格式(-h)汇总(-s)计算根目录下每个一级目录和文件的大小。
  • 2>/dev/null:将权限错误等标准错误输出重定向到“黑洞”,让屏幕只显示有效结果,界面更清爽。
  • sort -rh:逆序(-r)按人类可读的数字大小(-h)排序。-h参数能正确排序 10K, 1M, 2G 这样的单位。
  • head -20:只显示最大的前20个。

运行后,你可能会看到像/var(30G),/usr(10G),/home(5G) 这样的结果。通常,在Docker环境中,/var目录是头号嫌疑犯,因为Docker默认将镜像、容器、卷数据等都存放在/var/lib/docker。

2.3 第三步:深入嫌疑目录,揪出具体文件

假设我们发现/var最大,就进入/var目录,重复上面的操作:

cd /var sudo du -sh * 2>/dev/null | sort -rh | head -20

很可能你会看到lib目录独占鳌头。再进入/var/lib,最终定位到/var/lib/docker异常庞大。至此,我们初步锁定了“案发现场”。

但Docker目录下子目录很多,我们需要知道具体是overlay2(存储驱动目录)、containers(容器元数据)、volumes(数据卷)还是images(镜像层)占用了空间。继续使用du深入:

cd /var/lib/docker sudo du -sh * 2>/dev/null | sort -rh | head -10

2.4 第四步:针对Docker的专项检查

除了用du查看磁盘用量,Docker本身也提供了一些命令来查看其资源占用情况,这能给我们另一个维度的信息。

  1. 查看镜像、容器、数据卷的磁盘占用:

    docker system df -v

    这个命令非常有用。-v参数会显示详细信息,包括每个镜像、每个容器、每个卷的具体大小和可回收空间。它能清晰告诉你,哪些镜像是悬空的(dangling),哪些容器虽然停止了但还占着文件系统,哪些数据卷已经不再使用。

  2. 查看容器日志大小: Docker容器的标准输出(STDOUT/STDERR)日志默认会由json-file或journald驱动收集,存放在宿主机的特定位置。长时间运行的、日志输出频繁的容器,其日志文件可能巨大无比。日志位置通常在/var/lib/docker/containers/<容器ID>/<容器ID>-json.log。我们可以用命令快速找出日志最大的容器:

    find /var/lib/docker/containers/ -name “*.log” -exec ls -lh {} \; | awk ‘{ print $9 “: ” $5 }’ | sort -hr -k2 | head -10

通过以上四步,我们从“磁盘满了”这个现象,精准地定位到了可能是“Docker的某个特定容器日志”或“某个悬空镜像层”导致了问题。这个排查思路是通用的,即使不是Docker,是MySQL的binlog、是Nginx的access_log、是某个应用生成的临时文件,你都能用这套方法找到它。

3. 实战清理:安全高效地释放空间

定位到问题后,就要开始清理了。但清理不是简单的rm -rf,必须有策略,分优先级,确保业务不受影响。

3.1 清理优先级与安全操作

我的清理优先级通常是:日志文件 > 无用Docker资源 > 系统包缓存 > 其他临时文件。

第一优先级:容器日志清理这是最安全、见效最快的操作。如果发现某个容器的日志文件巨大(比如超过1G),处理方式如下:

  1. 动态清理(治标):直接清空日志文件。注意,不能直接删除文件,因为容器进程可能正打开它。正确做法是使用truncate命令或重定向清空。

    # 找到大日志文件,比如 /var/lib/docker/containers/abcd1234/abcd1234-json.log # 使用 truncate 命令将其大小截断为0,但保留文件句柄 sudo truncate -s 0 /var/lib/docker/containers/abcd1234/abcd1234-json.log

    或者,如果知道是哪个容器,可以进入容器内部重启日志服务(如果支持),但更通用的方法是配置Docker日志驱动,限制日志大小和数量,这是治本之策,我们后面讲。

  2. 查看容器日志(诊断用):清理前,如果想看最后一部分日志内容,可以用docker logs命令,但不要用-f(follow)或--tail所有内容,这可能会输出海量数据。建议:

    docker logs --tail 100 <容器名或ID> # 只看最后100行

第二优先级:清理Docker无用资源使用Docker自带的修剪命令,这是最安全的方式。

  1. 删除所有悬空镜像:悬空镜像是那些没有标签且没有被任何容器引用的中间层镜像,是磁盘空间的隐形杀手。

    docker image prune

    执行后会提示确认,输入y。如果想强制删除不提示,加-f参数。

  2. 删除所有未被使用的资源:这个命令更彻底,会删除悬空镜像、停止的容器、未被任何容器引用的网络和构建缓存。

    docker system prune

    注意:这个命令会删除所有停止的容器!请确保这些容器确实不再需要。如果想保留卷,加--volumes参数,但通常不推荐,因为未使用的卷也可能很大。更安全的做法是先docker system df -v查看确认。

  3. 针对性删除镜像:如果某个特定的大镜像不再需要,直接删除。

    docker rmi <镜像ID或镜像名:标签>

    如果镜像被容器引用,需要先删除容器。

第三优先级:清理系统包管理缓存CentOS的YUM/DNF会在/var/cache/yum或/var/cache/dnf目录下保留下载的软件包头文件(headers)和软件包文件(packages)。这些缓存可以安全清理。

# 清理缓存的软件包文件 sudo yum clean packages # 或者使用 dnf (CentOS 8+) sudo dnf clean packages # 更彻底的清理(包括元数据、插件缓存等) sudo yum clean all

清理缓存不会删除已安装的软件,非常安全。这通常能释放出几百MB到几GB的空间。

第四优先级:查找并清理其他大文件/目录使用find命令寻找特定大小或特定时间前的文件。

# 查找根目录下大于100M的文件 sudo find / -type f -size +100M 2>/dev/null | xargs ls -lh | sort -k5hr | head -20 # 查找 /var/log 目录下7天前的日志文件(.log结尾) sudo find /var/log -name “*.log” -type f -mtime +7 -exec ls -lh {} \; # 确认无误后,可以删除(谨慎!) # sudo find /var/log -name “*.log” -type f -mtime +7 -exec rm -f {} \;

重要警告:在根目录/下执行find并删除文件是极其危险的!务必先ls -lh列出文件,确认其路径和用途(特别是/proc,/sys,/dev下的文件绝对不能动),再决定是否删除。对于日志文件,更好的做法是使用logrotate服务进行轮转和压缩管理,而不是手动删除。

3.2 一个完整的实战清理案例

假设我们通过排查,发现问题是:1)一个Nginx容器日志达到5GB;2)积累了数十个悬空镜像;3)YUM缓存有2GB。

我的操作序列会是:

  1. 备份意识:虽然清理操作相对安全,但如果有极其重要的自定义镜像或数据卷,在操作前心里要有数。对于日志,可以先压缩备份再清理。

    # 例如,备份大日志文件(可选) sudo gzip -c /var/lib/docker/containers/nginx-container-id/nginx-container-id-json.log > /tmp/nginx-log-backup-$(date +%Y%m%d).gz
  2. 清理容器日志:

    # 找到Nginx容器的ID docker ps --filter “name=nginx” --format “{{.ID}}” # 假设ID是 abcd1234 sudo truncate -s 0 /var/lib/docker/containers/abcd1234/abcd1234-json.log
  3. 清理Docker资源:

    # 先查看,做到心中有数 docker system df -v # 删除悬空镜像 docker image prune # 删除停止的容器和未使用的网络(确认这些容器已不需要) docker system prune -f
  4. 清理系统缓存:

    sudo yum clean all
  5. 验证效果:

    df -h /

    此时,你应该能看到/dev/vda1的可用空间增加了。记录下释放的空间量,并与之前的估算对比。

4. 根治与预防:构建可持续的磁盘管理策略

一次清理解决不了根本问题。我们需要建立机制,防止磁盘再次被“吃光”。这包括配置调整、监控告警和良好的使用习惯。

4.1 配置Docker日志驱动,限制日志大小

这是预防容器日志膨胀的最有效手段。Docker支持多种日志驱动,默认的json-file没有大小限制。我们可以为Docker守护进程全局配置,或者为单个容器配置日志选项。

方法一:全局配置(修改/etc/docker/daemon.json)

{ “log-driver”: “json-file”, “log-opts”: { “max-size”: “10m”, “max-file”: “3” } }
  • max-size: 单个日志文件的最大大小,到达后会自动轮转。这里设置为10MB。
  • max-file: 保留的旧日志文件数量。这里设置为3,意味着最多会有当前日志文件+3个历史日志文件(如-json.log,-json.log.1,-json.log.2,-json.log.3)。更旧的文件会被自动删除。 修改后,需要重启Docker服务生效:
sudo systemctl daemon-reload sudo systemctl restart docker

注意:重启Docker服务会短暂影响所有正在运行的容器。请在业务低峰期操作。

方法二:单个容器配置(运行容器时指定)

docker run -d \ --name my-nginx \ --log-driver json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ nginx:latest

对于已经运行的容器,需要先删除再重新用新参数创建。所以,最佳实践是在编写docker-compose.yml或 Kubernetes Pod Spec 时就定义好日志策略。

4.2 使用日志轮转工具 logrotate

对于系统服务(如Nginx、MySQL、Syslog)和Docker容器日志(如果未用上述方法限制),可以使用系统自带的logrotate服务进行管理。我们可以为Docker容器日志创建专用的轮转配置。

创建文件/etc/logrotate.d/docker-containers:

/var/lib/docker/containers/*/*.log { rotate 7 daily compress delaycompress missingok copytruncate }
  • rotate 7: 保留7个备份文件。
  • daily: 每天轮转一次。
  • compress: 轮转后使用gzip压缩旧日志。
  • delaycompress: 延迟压缩,下一次轮转时才压缩上一次的日志文件(方便排查最近一天的问题)。
  • missingok: 如果日志文件不存在,也不报错。
  • copytruncate: 这是关键!先复制日志文件,然后清空原文件。这避免了需要重启Docker或容器进程来释放文件句柄。对于正在写入的日志文件,这种方式最安全。 配置好后,logrotate服务会每天自动执行。你也可以手动测试配置:sudo logrotate -vf /etc/logrotate.d/docker-containers。

4.3 建立磁盘空间监控与告警

“治未病”比“治已病”更重要。我们需要在磁盘空间使用率达到一个危险阈值(比如80%)时就收到告警,而不是等到100%。

  1. 简单脚本监控:可以写一个Shell脚本,结合df命令和邮件或钉钉/企业微信机器人API,定时(通过cron)检查磁盘使用率。

    #!/bin/bash THRESHOLD=80 USAGE=$(df / | tail -1 | awk ‘{print $5}’ | sed ‘s/%//’) if [ $USAGE -gt $THRESHOLD ]; then echo “警告:根分区磁盘使用率 ${USAGE}% 超过阈值 ${THRESHOLD}%!” | mail -s “磁盘空间告警” admin@example.com # 或者调用webhook发送到告警平台 fi

    将脚本加入crontab,每小时执行一次:0 * * * * /path/to/check_disk.sh

  2. 使用专业监控系统:在生产环境中,更推荐使用Prometheus + Grafana + Alertmanager,或者Zabbix,Nagios等成熟的监控方案。它们可以更直观地展示历史趋势,并配置多级、多通道的告警规则。

4.4 优化存储架构与使用习惯

  1. 为Docker配置独立的数据分区或目录:在初始化服务器时,最好将/var/lib/docker挂载到一块独立的大容量数据盘上,而不是和根分区挤在一起。这样即使Docker数据增长,也不会影响系统根分区。可以通过修改Docker的>sudo lsof +L1

    或者更精确地查找已删除的大文件:

    sudo lsof | grep deleted | awk ‘{print $2, $4, $7, $9}’ | sort -n -k3 -r | head -20

    这个命令会列出所有状态为“deleted”的已打开文件,并显示其进程ID(PID)、文件描述符(FD)、文件大小和路径。你会看到类似(deleted)的路径名。

    解决方法: 找到对应的进程后,你有两个选择:

    1. 重启该进程:这是最干净的方法。通知业务方或选择合适的时间窗口,重启持有该文件句柄的进程(比如某个Java应用、MySQL、或者一个Docker容器)。进程重启后,内核会回收所有其占用的资源,包括这些已删除文件的空间。
    2. 清空文件内容:如果进程非常重要不能重启,你可以通过文件描述符来清空文件内容(前提是你知道这个文件可以清空,比如日志文件)。首先找到进程PID和文件描述符FD(比如1234和3w,w表示写模式)。然后:
      # 方法:将空内容写入 /proc/[PID]/fd/[FD] # 警告:此操作不可逆,且可能影响进程行为,请务必确认文件类型! sudo echo “” > /proc/1234/fd/3 # 或者使用 truncate 命令(更安全) sudo : > /proc/1234/fd/3
      极度谨慎!确保你清空的是日志文件之类的可丢弃数据,而不是数据库文件或其他关键数据文件。

    5.2 文件系统inode耗尽

    df命令看的是数据块(block)的使用情况。文件系统还有另一个限制:inode数量。每个文件(包括目录、软硬链接)都会消耗一个inode。如果磁盘上存在海量小文件(比如Docker镜像的无数个小层,或者邮件系统的无数小邮件),即使数据块空间还有剩余,inode用完了,系统也无法创建新文件,同样会报“No space left on device”。

    检查inode使用情况:

    df -i

    或者

    df -ih /

    查看/dev/vda1的IUse%列。如果接近或达到100%,就是inode耗尽了。

    排查inode被谁用了:

    # 查找根目录下哪个目录包含的文件数量最多(消耗inode最多) sudo find / -xdev -type f | cut -d “/” -f 2 | sort | uniq -c | sort -rn | head -20

    -xdev参数防止find命令跨越到其他挂载点(比如/proc,/sys)。

    解决方法: 找到产生海量小文件的源头(通常是某个失控的程序或配置错误的日志记录)。清理该目录下的文件。对于Docker,可能是某个容器内的临时目录或缓存目录产生了大量小文件,需要进入容器内部或通过数据卷进行清理。预防措施同样是监控inode使用率,并在docker run时注意挂载卷的权限和容器内进程的文件创建行为。

    5.3 磁盘挂载点重叠或异常

    极少数情况下,可能是挂载点(mount point)出现了问题。例如,某个目录被单独挂载了一个设备,但这个设备满了,而df -h显示的是根分区的使用情况,没有显示这个子挂载点。或者,有文件系统被以只读(ro)方式重新挂载,导致无法写入。

    检查所有挂载点:

    mount | column -t

    或者

    findmnt

    查看是否有意料之外的挂载,或者/var,/home等目录是否被单独挂载了分区。如果/var/lib/docker被单独挂载了一个小分区,那么即使根分区空间充足,Docker也会因为自己的小分区满了而无法工作。

    检查文件系统读写状态:

    mount | grep “ / ”

    查看根分区的挂载选项,确认是rw(读写)而不是ro(只读)。

    处理这类问题需要根据实际的挂载情况调整,可能需要修改/etc/fstab文件并重新挂载。

    6. 总结与个人心得

    处理/dev/vda1磁盘100%的问题,尤其是Docker环境下的,已经成了运维的必修课。回顾整个过程,我的体会是,它更像是一场“侦查”与“排雷”的结合。侦查在于,你必须依靠df,du,docker system df,lsof,find这些命令,像拼图一样,从全局到局部,从表象到根源,一步步还原出磁盘空间被“谁”、以“何种方式”占用。排雷在于,每一个删除或清理操作都带有潜在风险,你必须清楚你在删除什么,是否会影响正在运行的服务,是否有更优雅的替代方案(如日志轮转替代直接删除)。

    我个人的几条血泪经验:

    1. truncate比rm更安全:对于正在被进程写入的日志文件,永远优先考虑用truncate -s 0或: > file来清空内容,而不是直接rm。后者可能导致进程报错甚至崩溃。
    2. docker system prune是双刃剑:它很方便,但一定要先docker ps -a确认那些停止的容器是否真的可以丢弃。我曾经不小心用它删除了一个包含未持久化重要配置的测试容器,不得不重新构建。
    3. 监控一定要做在平时:不要等到报警电话响起才去处理。将磁盘使用率(包括inode)纳入日常监控仪表盘,设置80%-85%的预警线和90%的告警线。这能给你预留充足的反应和操作时间。
    4. 理解存储驱动:Docker使用overlay2存储驱动时,镜像和容器的层管理非常高效,但也相对复杂。了解docker system df -v输出中RECLAIMABLE的含义,能帮你更好地判断哪些空间是可安全回收的。
    5. 文档化你的清理步骤:将有效的排查和清理命令写成脚本或记录在运维手册中。当下次凌晨三点再次被叫醒处理同样的问题时,这份文档能让你保持清醒,快速解决问题。

    最后,记住一个原则:释放空间是手段,优化管理才是目的。每一次磁盘满的告警,都应该推动你去思考:日志输出是否合理?缓存策略是否恰当?存储架构是否需要优化?只有这样,你的系统才会在一次次“治疗”中变得更强健。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询