
先交代一下背景这不是我第一次在 openEuler 上处理根分区写满的问题但这次麻烦的地方不只是磁盘满了而是我在扩容过程中连续踩了三个报错走了两小时弯路。如果你现在也遇到“根分区使用率100%”加“扩容报错”的组合别慌这篇文章把整个排查和操作链条都拆开讲清楚照着做基本能解决。先说现象。openEuler 20.03 这台虚拟机跑着 Nginx 和 MySQL某天开始 SSH 登录特别慢journalctl提示 No space left on device应用日志疯狂刷错误df -h一看根分区/那行 Use% 已经到了 100%。我赶紧去看磁盘确认有 LVM 卷然后按常规流程lvextendresize2fs结果直接报错Couldnt find valid filesystem superblock。这时候才反应过来openEuler 20.03 默认根文件系统是 XFS不是 ext4。后面又陆续遇到分区表报错、扩容后df不更新等问题索性一步步把所有坑都趟明白了。1. 问题复盘根分区 100% 是怎么发生的扩容又卡在哪1.1 根分区写满后的典型症状根分区写满不像 CPU 飙高那样立刻引起注意它是慢慢卡死整个系统的。常见表现有这几个应用日志报No space left on device但看磁盘又没存什么大文件。journalctl无法写入系统服务状态异常重启后部分服务起不来。su或sudo切换用户时提示无法创建临时文件因为/tmp或者用户家目录落在根分区上。SSH 能连上但执行命令特别慢tab补全可能直接报错。数据库这类依赖临时文件、socket 文件的程序会频繁崩溃。我这次的直接原因是 Nginx 访问日志和 MySQL binlog 把/var目录撑爆了。用du -x -h --max-depth1 /逐层排查发现/var/log下面有几个 GB 的旧日志加上 MySQL 的 binlog 一直没清理根分区 50G 很快就满了。1.2 扩容报错的第一步先搞清楚磁盘有没有被看见很多人一上来就执行df -h和lvextend这其实是错的。扩容报错第一步应该先确认底层虚拟磁盘是否已经变大、系统内核是否识别到了新容量。用lsblk看磁盘和分区大小用pvs看物理卷大小用df -hT看文件系统类型。如果lsblk里/dev/sda已经显示 100G但pvs里的 PV 还是 50G说明只是磁盘扩容了分区和 PV 还没跟进。如果lsblk里 sda 还是 50G说明虚拟机管理平台的磁盘扩容根本没生效或者需要重启让内核重新扫描。一个容易忽略的点如果底层磁盘从 50G 扩到 100G但内核没重新读取分区表lsblk可能仍然显示旧容量。可以用partprobe /dev/sda或者partx -u /dev/sda让内核重新读取实在不行就重启一次。这一步没做对后面pvresize根本不会识别新空间vgextend或者lvextend自然会报错。2. 扩容链路拆解从磁盘扇区到文件系统到底要打通几层2.1 openEuler 20.03 默认分区方案决定了你的扩容路线openEuler 20.03 安装时默认采用 LVM 逻辑卷管理根分区通常挂在/dev/mapper/openeuler-root这类逻辑卷上文件系统默认 XFS。XFS 和 ext4 的扩容命令完全不同这是整个扩容过程中最大的分水岭。扩容本质上是一条链虚拟机/物理机磁盘 - /dev/sda 块设备 - /dev/sdaX 分区 - PV 物理卷 - VG 卷组 - LV 逻辑卷 - 文件系统每一步都有对应的命令层级查看命令扩容命令说明磁盘lsblk管理平台/关机加盘在虚拟化管理界面完成分区parted -l/lsblkgrowpart/parted resizepart让分区占满磁盘新空间PV 物理卷pvs/pvdisplaypvresize /dev/sdaX让 PV 感知分区新容量VG 卷组vgs/vgdisplayvgextend或直接扩 PVPV 变大后 VG 自动变大LV 逻辑卷lvs/lvdisplaylvextend把 VG 空余空间划给 LV文件系统df -hT/blkidxfs_growfs或resize2fs把文件系统扩展到 LV 新容量报错往往就发生在中间某一环断裂。比如分区没扩展就pvresize报 No space left on device比如 XFS 文件系统用resize2fs报 Bad magic number in super-block比如分区表是 GPT 但备份头没更新报 The backup GPT table is not at the end of the disk。2.2 扩容前后的四层操作与对应的命令扩容报错绝大多数是下面四个原因第一分区层没有扩。底层磁盘已经变大但分区表还停在原来的大小。这时候直接pvresize是无效的因为 PV 建在分区之上分区边界没动。必须先扩分区例如growpart /dev/sda 2或者用parted /dev/sda resizepart 2 100%。第二文件系统类型搞混。openEuler 20.03 如果默认安装根分区大概率是 XFS必须用xfs_growfs而且 XFS 扩容时不需要指定大小直接xfs_growfs /或xfs_growfs /dev/mapper/openeuler-root即可。如果分区是 ext4才用resize2fs。用反了直接报 superblock 相关错误。第三内核分区表没有刷新。扩完分区之后lsblk可能显示分区还是旧大小原因是内核还在用旧的 in-memory 分区表。此时需要partprobe或partx -u有时必须重启。第四LV 没有真正扩大或没有自动扩文件系统。lvextend只是扩逻辑卷文件系统还没跟上df自然还是 100%。最省事的做法是用lvextend -r这个-r参数会在扩容 LV 后自动调用xfs_growfs或resize2fs避免漏掉最后一步。3. 手把手实操openEuler 20.03 根分区扩容完整流程3.1 操作前准备先救急再扩容根分区 100% 时直接扩容有风险因为过程里可能因为临时文件写不进去导致工具崩溃。我的习惯是先腾出一点空间至少让系统有几百 MB 空闲再做正式扩容。我这次是清掉/var/log下旧日志和 MySQL binlog# 查看根分区下最占空间的目录 du -x -h --max-depth1 / 2/dev/null | sort -hr | head # 清理 journal 日志保留最近 100M 日志 journalctl --vacuum-size100M # 查找 /var/log 下的大文件 find /var/log -type f -size 100M -exec ls -lh {} \;清理完再看df -h一般能腾出几 GB。腾出空间后做快照或备份这是对自己的保护。生产环境建议先打快照至少也要tar备份关键配置和数据目录。然后确认扩容目标。这次虚拟磁盘原大小 50G我计划扩到 100G。虚拟机管理界面直接改磁盘大小这一步不影响运行中的系统具体平台有差异VMware/KVM 基本都支持在线扩展磁盘但不支持热扩容的话需要停机操作。3.2 场景ALVM XFS 虚拟磁盘扩容这是 openEuler 20.03 最常见的布局也是网上咨询最多的情况。第一步确认磁盘、分区、PV、LV 和文件系统类型lsblk df -hT pvs vgs lvs blkid /dev/sda2我这里输出大致是sda 50G ├─sda1 1G /boot ├─sda2 49G └─openeuler 49G ├─root 47G / └─swap 2G [SWAP]确认根文件系统是 XFSdf -hT / # 输出/dev/mapper/openeuler-root xfs 47G ...第二步扩容分区。用growpart如果没有安装用yum install -y cloud-utils-growpart安装growpart /dev/sda 2如果系统没有 growpart也可以用 partedparted /dev/sda (parted) resizepart 2 100% (parted) quit注意这里容易报Error: The backup GPT table is not at the end of the disk属于 GPT 备份头问题解决办法在下一节排查里讲。第三步让内核重新读取分区表partprobe /dev/sda # 或者 partx -u /dev/sda再运行lsblk确认 sda2 已经是 99G 左右。第四步扩展 PVpvresize /dev/sda2执行后pvsPV 大小应该变成约 99GVFree 列会显示新增加的可用空间。第五步扩展 LV 和文件系统。最推荐带-r参数一条命令搞定lvextend -r -l 100%FREE /dev/mapper/openeuler-root-r表示同时调整文件系统大小。对 XFS 会自动调用xfs_growfs对 ext4 会自动调用resize2fs非常省心。执行成功后直接df -hT /就能看到根分区变成 97G 左右。如果不想用-r也可以手动lvextend -l 100%FREE /dev/mapper/openeuler-root xfs_growfs /手动执行的时候千万记住 XFS 用xfs_growfs不要用resize2fs。3.3 场景B非 LVM裸分区扩容如果你当时安装系统时直接给了/一个独立分区没有用 LVM扩容链路更短磁盘扩容 - 分区扩容 - 文件系统扩容。没有中间 PV/VG/LV 三层。这种场景下操作如下# 1. 查看根分区对应的块设备 lsblk # 假设根分区是 /dev/vda1 # 2. 扩分区 growpart /dev/vda 1 # 3. 刷新内核分区表 partprobe /dev/vda # 4. 扩展文件系统 # XFS xfs_growfs / # ext4 resize2fs /dev/vda1这里有个细节裸分区扩容时执行growpart会报错 unexpected output in sfdisk --version 之类的小概率问题通常是因为工具版本和内核版本不匹配建议先yum update -y,再装cloud-utils-growpart。另外如果根分区是 ext4 且挂载在/resize2fs可能提示 Filesystem is already X blocks long或者提示需要先卸载。ext4 支持在线扩容但必须确保文件系统没有错误最好先e2fsck -f /dev/vda1检查一遍再扩。不过生产环境直接e2fsck有一定风险建议在系统负载低时操作或者在快照基础上做。4. 扩容报错排查速查表这些错误我全踩过4.1 报错案例与解决方案对照报错信息原因解决办法Couldnt find valid filesystem superblockXFS 文件系统用了resize2fs改用xfs_growfs /如果是 ext4 用resize2fsBad magic number in super-block while trying to open同上多半是命令选错确认文件系统类型df -hT或blkidDevice or resource busy while trying to open /dev/sda2分区正在使用无法离线 resize如果是裸分区考虑在线扩容命令不行则需维护模式LVM 场景直接扩 LV 即可不用动分区设备The backup GPT table is not at the end of the diskGPT 备份头没有跟随磁盘扩容更新用gdisk进入后w重写 GPT或先备份再重建分区表Cant have overlapping partitions扩容分区时没有先删除旧分区定义用parted时谨慎rm旧分区再mkpart或用 growpart 避免手动重叠Partition(s) X on /dev/sda have been written, but we have been unable to inform the kernel内核没有重新读取分区表partprobe /dev/sda或partx -u /dev/sda必要时重启Insufficient free spaceVG 里没有可分配空间PV 还没扩先pvresize /dev/sdaX再vgs确认 VFree 有空间df还是显示 100%文件系统没有扩容或df缓存执行xfs_growfs /或resize2fs如果提示 already说明已经扩容No space left on device但df显示有空间inode 耗尽df -i查看删除垃圾小文件或用 find 批量清理4.2 两个最容易忽视的细节第一个细节是lvextend -r对 XFS 并不是在所有版本都自动生效。openEuler 20.03 的 lvm2 版本较新-r参数能够正确识别 XFS 并执行xfs_growfs但如果你在别的发行版遇到lvextend报 Filesystem not mounted 之类的提示多半是因为根分区挂载方式判断问题。此时不要慌手动执行xfs_growfs /即可不影响前面已经扩大的 LV。第二个细节是分区扩容后一定要确认内核使用的是新分区表。我曾经在云平台上扩容 sdagrowpart执行成功后lsblk仍然显示旧分区大小关键原因是这台机器上开着旧的设备映射或分区被占用。遇到这种情况我建议优先partx -u /dev/sda如果还不行就重启。在生产环境重启前务必确认系统能正常启动否则宁可先计划维护窗口。还有一个小坑parted的resizepart在某些旧版本上会报 Error: Partition(s) X on /dev/sda have been written, but we have been unable to inform the kernel of the change虽然分区可能已经成功写入但内核不知道。解决办法还是partprobe或partx -u如果提示 device busy可以考虑partx -u /dev/sda指定分区号有时候比全局 partprobe 管用。5. 扩容之后如何不让根分区再一次 100%5.1 先做一次根分区大排查扩容成功后我习惯再花十分钟做一次清理因为满了这件事基本不会只出现一次。用这几个命令快速定位占空间的大户# 查看当前根分区文件系统类型和空间 df -hT / # 查看根分区下所有一级目录的大小 du -x -h --max-depth1 / 2/dev/null | sort -hr | head -20 # 查看 /var 下的目录大小 du -x -h --max-depth1 /var 2/dev/null | sort -hr | head -20 # 查看所有大于 100M 的文件 find / -xdev -type f -size 100M -exec ls -lh {} \;常见的大户是/var/log/journal、/var/lib/docker、/var/lib/mysql、/home下的用户文件、/tmp目录残留等。如果服务是容器化的/var/lib/docker下 overlay2 的历史镜像和悬空镜像经常能占几十 GB用docker system prune可以定期清理。5.2 给根分区扩容留好余地这次教训之后我的建议是分区规划时千万别把根分区卡得太死。openEuler 20.03 默认 LVM 布局其实很友好只要当初分配时给 VG 留了空间后续扩容只需要lvextend -r一条命令。但如果你把所有物理空间都划给了 root LVVG 没有空余就得走一遍磁盘扩容-分区扩容-pvresize-lvextend的完整流程。另外建议对关键目录做监控。部署node_exporter或者写个简单的 cron 脚本每天检查根分区使用率超过 80% 就告警。脚本不复杂核心逻辑就几行#!/bin/bash USAGE$(df / | awk NR2 {print $5} | sed s/%//) if [ $USAGE -gt 85 ]; then echo $(date): root partition usage ${USAGE}% /var/log/disk_alert.log fi配合 crontab 每天跑一次至少能在根分区撞墙之前给自己留出处理时间。这次扩容踩坑最终处理完我的体会是openEuler 20.03 扩容报错90% 的根因是对文件系统类型判断失误剩下 10% 是分区表刷新和 GPT 备份头问题。只要记住 XFS 用xfs_growfs、ext4 用resize2fs扩容前先lsblk和df -hT确认现状然后按分区、PV、VG、LV、文件系统逐层推进基本不会有大问题。最后再提醒一句生产环境扩容前一定做快照尤其是根分区接近写满的状态下任何一步操作失败都可能让系统彻底无法启动。实在不行该安排维护窗口就安排别在业务高峰期硬来。