CentOS 7服务器磁盘爆满:从紧急清理到长效预防的实战指南
1. 当服务器磁盘告警响起时我的第一反应是什么那天下午监控平台的告警邮件和钉钉消息几乎同时弹了出来“服务器/根目录使用率超过 90%”。心里咯噔一下这可不是小事。对于一台跑着线上服务的 CentOS 7 服务器来说磁盘爆满意味着服务随时可能因为无法写入日志或临时文件而崩溃数据库也可能因此停止工作直接影响业务。很多新手运维或者开发者第一次遇到这个问题时往往会手忙脚乱地直接去删文件但这是最危险的做法。因为你根本不知道哪些文件能动哪些动了系统就起不来了。我处理过太多类似的 case从单纯的日志堆积到 Docker 这个“磁盘吞噬兽”作祟再到一些隐蔽的未清理的软件包缓存。每一次清理都是一次对服务器状态的深度体检。今天我就结合这些年的实战经验系统性地梳理一下当你的 CentOS 7 服务器磁盘爆满时应该如何一步步地、安全高效地进行清理。无论你是运维工程师、后端开发者还是自己折腾服务器的爱好者这套方法都能帮你稳住阵脚快速定位问题根源并解决它。我们的目标不仅仅是清理出空间更是要建立预防机制避免问题反复发生。2. 紧急处置快速定位“元凶”与安全释放空间当磁盘使用率超过 85% 时系统性能就会开始下降超过 90%很多应用就会报错。所以第一步不是盲删而是精准定位。我们需要一把“手术刀”而不是“斧头”。2.1 使用df和du命令进行宏观定位首先我们需要看清全局。使用df -h命令可以快速查看所有磁盘分区的使用情况。-h参数表示以人类可读的格式GB MB显示。df -h输出可能类似这样文件系统 容量 已用 可用 已用% 挂载点 /dev/vda1 50G 47G 1.0G 98% / devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 8.5M 3.9G 1% /run tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup /dev/vdb1 200G 45G 155G 23% /data这里一眼就能看到根分区/dev/vda1已经用了 98%只剩 1G 空间问题就出在这里。而/data分区还很充裕。这告诉我们清理的重点是根目录/下的内容。接下来我们需要进入根目录找出到底是哪个子目录占用了最多的空间。这里要用到dudisk usage命令。一个非常实用的组合命令是cd / sudo du -sh * | sort -rh | head -20这个命令分解开来sudo因为有些目录需要 root 权限才能查看。du -sh *计算当前目录下每个文件和目录的磁盘使用情况-s表示汇总总计-h表示人类可读格式。sort -rh对结果进行排序-r是反向从大到小-h是能识别人类可读的数字单位如 10G, 100M。head -20只显示前 20 行结果。执行后你可能会看到类似这样的输出45G /var 1.5G /usr 800M /home 200M /opt ...如果/var独占鳌头占了 45G那么问题几乎可以肯定出在它身上。/var是系统可变数据的家园包括日志、缓存、邮件、Docker 容器数据等是磁盘爆满的重灾区。2.2 逐层深入揪出具体的“大文件”或“大目录”假设我们锁定/var就进入该目录继续分析cd /var sudo du -sh * | sort -rh | head -20可能发现是/var/lib或/var/log巨大。再继续深入。除了看目录大小直接寻找服务器上体积最大的单个文件也很有用sudo find / -type f -size 500M -exec ls -lh {} \; 2/dev/null | sort -k5 -rh | head -10这个命令的意思是在根目录/下查找类型为文件 (-type f)大小超过 500M (-size 500M) 的文件然后以详细列表形式显示 (ls -lh)将所有错误信息如权限不足重定向到黑洞 (2/dev/null)最后按第五列文件大小反向排序取前10个。 注意在根目录下执行find命令可能较慢且会产生一些权限错误这是正常的。更高效的做法是先通过du定位到大目录再在该目录下执行find。2.3 安全清理“第一滴血”日志文件如果发现/var/log目录异常庞大那么清理日志是最常见且相对安全的第一步。CentOS 7 使用journald系统日志和传统的rsyslog。清理journald日志journald的日志是二进制的存放在/run/log/journal或/var/log/journal。查看其占用空间journalctl --disk-usage如果占用过大比如超过 1G可以限制其保留时间或大小。一种紧急清理方法是只保留最近 2 天的日志sudo journalctl --vacuum-time2d或者限制总大小例如 500Msudo journalctl --vacuum-size500M这比直接删除/var/log/journal目录下的文件要安全得多。清理应用日志进入/var/log目录查看哪些日志文件巨大。常见的“嫌疑犯”有/var/log/messages系统主日志。/var/log/secure安全认证日志。/var/log/audit/audit.log审计日志如果开启 SELinux。/var/log/httpd/或/var/log/nginx/Web 服务器日志。/var/log/mysqld.log或/var/log/mariadb/数据库日志。对于这些文本日志切忌直接使用rm删除正在被进程写入的日志文件这可能导致进程无法继续写入甚至崩溃。正确的做法是清空文件内容sudo truncate -s 0 /var/log/mysqld.log或sudo /var/log/mysqld.log。这会将文件大小置为零但文件描述符还在进程可以继续写入。使用logrotate这是管理日志轮转的标准工具。检查/etc/logrotate.conf和/etc/logrotate.d/下的配置确保日志能按计划如每天、每周进行压缩、归档和删除旧文件。紧急情况下可以手动强制执行所有日志轮转sudo logrotate -f /etc/logrotate.conf。3. 深度清理针对常见“磁盘黑洞”的专项手术快速释放一些日志空间后我们可能获得了喘息之机。但要彻底解决问题必须对几个著名的“磁盘黑洞”进行深度清理。3.1 包管理缓存YUM/DNF 的“旧货仓库”CentOS 7 默认使用 YUM新版本是 DNF管理软件包。每次安装、更新软件时下载的.rpm包都会缓存起来以便回滚或重复安装。时间一长这个缓存目录 (/var/cache/yum) 会变得非常庞大。检查缓存大小sudo du -sh /var/cache/yum安全清理所有已安装软件包的缓存不会删除当前已安装软件sudo yum clean all或者更精确地只清理过时的缓存包sudo yum clean packages 实操心得yum clean all非常安全可以定期执行例如放入 crontab 每月执行一次。但请注意清理后如果你要降级某个软件包可能需要重新下载旧版本的 rpm 包。3.2 未使用的内核与旧头文件CentOS 在更新内核后旧内核并不会自动删除。这会导致/boot分区被占满如果/boot是独立分区或者占用根分区空间。查看当前已安装的所有内核rpm -qa | grep kernel或sudo awk -F\ $1menuentry {print i : $2} /etc/grub2.cfg通常系统只会保留最新的 2-3 个内核。使用yum或package-cleanup工具来自yum-utils包来移除旧内核# 安装 yum-utils sudo yum install yum-utils -y # 移除所有旧内核只保留当前正在运行的内核 sudo package-cleanup --oldkernels --count1--count1表示只保留 1 个旧内核加上当前运行的内核共保留2个。建议至少保留一个旧内核作为备份以防新内核启动失败。同时也可以清理旧的内核头文件kernel-headers和开发包sudo package-cleanup --orphans3.3 Docker容器世界的“空间吞噬者”如果你的服务器上运行着 Docker那么它极有可能是磁盘空间的第一杀手。Docker 占用的空间主要分几块镜像Images下载的镜像文件。容器Containers运行中的容器产生的可写层。数据卷Volumes容器挂载的持久化数据。构建缓存Build Cache构建镜像时产生的中间层。首先查看 Docker 的整体磁盘使用情况docker system df这个命令会清晰地列出镜像、容器、本地卷和构建缓存各自占用的空间。针对性清理策略清理所有悬空dangling镜像这些是构建过程中产生的、没有标签的中间镜像通常可以安全删除。docker image prune -f清理所有未被使用的镜像、容器、卷和网络这是一个“大扫除”命令请谨慎使用确保没有重要数据。docker system prune -a -f --volumes-a会删除所有未被容器引用的镜像不仅仅是悬空镜像--volumes会删除未被任何容器使用的数据卷。执行此命令前务必确认没有需要保留的停止状态的容器或独立的数据卷清理容器日志单个容器日志过大也是常见问题。Docker 默认的日志驱动是json-file日志存放在/var/lib/docker/containers/容器ID/容器ID-json.log。可以通过配置 Docker Daemon 的日志轮转策略log-opts来限制日志大小和数量这是治本之策。紧急清理可以找到大日志文件并清空注意容器需在运行状态用truncate命令。 踩坑实录我曾遇到一个开发测试服务器因为频繁构建镜像且从未清理docker system df显示有 80G 的构建缓存Build Cache。仅用docker builder prune -a -f就一次性释放了 70G 的空间。对于 CI/CD 环境定期清理构建缓存至关重要。3.4 临时文件与缓存目录系统还有一些标准的临时目录长期不清理也会堆积文件。/tmp所有用户都可写的临时目录。系统重启可能会清空取决于配置但长期运行的服务器不会。可以安全删除其中很久未访问的文件如超过 10 天sudo find /tmp -type f -atime 10 -delete注意-delete操作很危险建议先只用-atime 10列出文件确认。/var/tmp比/tmp更持久的临时文件目录。清理策略同上但时间阈值可以设得更长如 30 天。用户家目录下的缓存例如~/.cache特别是浏览器缓存、pip/npm 缓存等。对于服务器来说这部分通常不大但如果是桌面环境或开发机也可能很可观。4. 进阶排查与长效预防从治标到治本经过上述清理大部分磁盘爆满问题都能得到解决。但如果空间很快又满了或者发现占用最大的并非上述常见目录就需要进行更进阶的排查并建立预防机制。4.1 查找被删除文件但未释放空间的“幽灵”文件这是一个经典问题一个大文件被某个进程打开并写入然后你或某个脚本删除了这个文件。在 Linux 上只要打开文件的进程不退出该文件所占用的磁盘空间就不会释放尽管你在文件系统里已经看不到它了。使用lsof命令可以查看这些被删除但仍被进程占用的文件sudo lsof L1或者更精确地查找已删除的大文件sudo lsof | grep deleted输出会显示进程 PID、命令名和文件描述符。找到占用空间大的那个文件对应的进程重启该进程如 nginx, mysql, java 应用等空间就会立即释放。这是解决“明明删了文件df显示空间没变”问题的关键。4.2 分析目录内文件数量与分布有时候不是单个文件大而是文件数量极其庞大例如成千上万个小图片、日志碎片导致 inode 耗尽。虽然df -h显示磁盘空间还有但系统会报“No space left on device”错误。此时需要检查 inode 使用情况df -i如果某个分区IUse%接近 100%就需要清理海量小文件。可以用find命令统计某个目录下的文件数量sudo find /path/to/dir -type f | wc -l然后结合du -sh和文件数量判断是否是海量小文件问题。4.3 建立长效监控与自动清理机制亡羊补牢不如未雨绸缪。清理之后必须建立监控和自动维护流程。配置监控告警使用 Zabbix, PrometheusGrafana, 或简单的crontab脚本监控关键分区的磁盘使用率和 inode 使用率在达到阈值如 80%时就发出告警而不是等到 95% 才处理。配置自动化清理任务将安全的清理操作写入crontab定期执行。# 示例每周日凌晨3点执行清理 # 清理 yum 缓存 0 3 * * 0 yum clean all /dev/null 21 # 清理 docker 悬空资源 0 4 * * 0 docker system prune -f /dev/null 21 # 清理 /tmp 下超过30天的文件 0 5 * * 0 find /tmp -type f -mtime 30 -delete /dev/null 21 # 轮转系统日志 (logrotate 通常已配置) 0 6 * * 0 /usr/sbin/logrotate -f /etc/logrotate.conf /dev/null 21规范应用日志行为为所有自研应用配置合理的日志级别、输出格式并务必对接logrotate设置日志文件大小上限和保留数量。禁止将日志无限制地打印到标准输出如果不被捕获可能会填满磁盘。合理规划存储在服务器初始化时就应根据用途规划分区。将/home、/var、/opt甚至/var/log、/var/lib/docker等容易增长的目录放在独立的大容量分区或逻辑卷上避免根分区被挤爆导致系统无法启动。使用 LVM逻辑卷管理可以在后期灵活调整分区大小。5. 特殊场景与疑难杂症处理在实际运维中你可能会遇到一些不那么常规的“磁盘杀手”。5.1 邮件队列堆积 (/var/spool/postfix或/var/spool/mail)如果服务器配置了邮件发送服务如 Postfix, Sendmail但邮件发送失败邮件可能会堆积在队列里。检查邮件队列mailq如果队列很长可以尝试清空队列谨慎操作确认邮件非重要sudo postsuper -d ALL或者删除某个用户的邮件文件如/var/spool/mail/username过大。5.2 软件安装或编译产生的临时文件手动编译安装软件如./configure make make install时如果中途失败或在源码目录内进行可能会留下巨大的中间文件如.o对象文件。检查/usr/local/src、/opt或用户家目录下的源码目录。5.3 容器或虚拟机的镜像存储除了 Docker如果你使用了其他容器技术如 LXC或虚拟机如 KVM它们的镜像和实例文件通常也存放在/var/lib目录下如/var/lib/libvirt/images。需要根据具体技术进行管理。5.4 数据库的临时表或二进制日志对于 MySQL/MariaDB如果执行了大型复杂查询可能会在磁盘上创建巨大的临时表文件通常位于/tmp或 MySQL 的tmpdir指定目录。此外如果开启了二进制日志binlog用于主从复制且没有设置自动清理expire_logs_days/var/lib/mysql目录也会快速增长。需要登录数据库进行管理和清理。处理磁盘爆满问题本质上是一个“定位-分析-清理-预防”的标准化流程。核心心法就是永远先查后删知其所以然。盲目执行网上搜来的rm -rf命令是运维大忌。通过今天的梳理希望你不仅能解决眼前的紧急告警更能建立起一套应对此类问题的系统性方法让你的服务器运行得更加稳健、清爽。记住干净的磁盘空间是服务器稳定运行的宝贵氧气。