根分区用到 92% 那天,我把 LVM 扩容的流程走了一遍
上个月收到监控告警,说根分区使用率 92%。 登录上去 df -h 一看,四十个 G 的盘只剩三个多 G。du -sh /* 挨个看,/var/lib/docker 占了大头,还有一堆构建缓存。 清了一轮,回到 60%。但我知道这只是暂时的,服务还在长,早晚得扩。 还好当初装系统的时候选了 LVM。要是普通分区,扩容就得停机、进救援模式、用 fdisk 调分区,风险大得多。 先理清楚 LVM 的三层 很多人被 LVM 绕晕,是因为它的名字太多。其实就三层。 物理层是 PV,Physical Volume,一块硬盘或者一个分区,初始化之后交给 LVM 管。 中间层是 VG,Volume Group,一个池子,把多个 PV 合成一个大的存储空间。 上层是 LV,Logical Volume,从池子里划出来的一块,格式化之后挂载使用。 扩容的时候,顺序是从下往上。先让 PV 变大,VG 才会跟着变大,然后才能扩 LV,最后扩文件系统。 搞反了就白做。 看现在的状态 1 lsblk 输出大概是这样: 1 2 3 4 5 6 7 8 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT vda 254:0 0 40G 0 disk ├─vda1 254:1 0 1M 0 part ├─vda2 254:2 0 512M 0 part /boot/efi └─vda3 254:3 0 39.5G 0 part ├─vg0-root 253:0 0 20G 0 lvm / ├─vg0-swap 253:1 0 2G 0 lvm [SWAP] └─vg0-data 253:2 0 17.5G 0 lvm /data 这块盘 40G,vda3 是 LVM 的物理分区,占了 39.5G。里面划了三个 LV。 问题是我这块盘本来就只有 40G,没有剩余空间。所以要扩,得先给虚拟机加盘。 加盘 在云控制台或者虚拟化平台里,把磁盘从 40G 调到 80G。这一步在云厂商那边点一下就行,不用停机。 加完之后,虚拟机里 lsblk 还是显示 40G,因为内核还没重新读分区表。 1 2 lsblk # vda 显示 80G,但 vda3 还是 39.5G 这就是关键的一步。vda 本身变大了,但 vda3 这个分区没变。 扩分区 有两种情况。 如果你用的是 GPT 分区表,而且分区后面没有别的分区,用 growpart 最省事: 1 sudo growpart /dev/vda 3 growpart 是 cloud-utils-growpart 包里的工具,大部分云镜像都预装了。 如果没装,apt install cloud-utils-growpart 或者 yum install cloud-utils-growpart。 跑完再看: 1 lsblk vda3 应该变成 79.5G 了。 如果是 MBR 分区表,growpart 也能处理,但有个限制,主分区最多四个,而且扩展分区后面的空间不好扩。这种情况下得用 fdisk 删了重建分区,fdisk 的 d 删分区只删分区表项,不动数据,只要起始扇区没变就是安全的。不过操作的时候手要稳。 让 PV 认识新的大小 分区变大了,但 LVM 还不知道。因为 PV 里记录了自己的大小。 1 sudo pvresize /dev/vda3 这个命令会让 PV 重新读取分区的大小,然后更新自己的元数据。 验证: 1 sudo pvs 输出里的 PSize 应该变成 79.5G,PFree 是新增的空间。 如果 PFree 没变,说明 pvresize 没生效,回头检查分区是不是真的扩了。 扩 LV 1 sudo lvs 看当前的 LV 大小。 扩的时候有两种写法。 按绝对值扩到某个大小: 1 sudo lvextend -L 40G /dev/vg0/root 注意 -L 是最终大小,不是增量。如果你写 -L 40G 而当前已经是 40G,它什么都不会做。 按增量扩: 1 sudo lvextend -L +20G /dev/vg0/root 这个更直观,加二十个 G。 或者干脆把池子里的空间全用掉: 1 sudo lvextend -l +100%FREE /dev/vg0/root 注意这里是小写的 -l,后面跟百分比。大写的 -L 后面跟具体数值。这个大小写很容易看错。 扩文件系统 这一步最容易被忘。LV 变大了,但上面的文件系统还是原来的大小,df -h 看不出变化。 ext4 用: 1 sudo resize2fs /dev/vg0/root 不用给大小,它会自动扩到 LV 的边界。 xfs 用: 1 sudo xfs_growfs / 注意 xfs 的 xfs_growfs 参数是挂载点,不是设备名。写 /dev/vg0/root 会报错。 这是两个文件系统最明显的区别。ext4 可以缩,xfs 只能扩。所以如果你的盘用 xfs,规划的时候要留点余量,缩不回去。 在线扩容 好消息是,上面这些操作除了 growpart 之外,全都可以在线做,不用卸载不用停机。 ext4 从内核 3.6 开始支持在线扩容,resize2fs 会自动检测并走在线模式。xfs 一直是在线的。 我用的是 ext4,整个流程在跑着服务的机器上做完,中间没有中断。nginx 和数据库都没感觉。 不过还是建议在业务低峰做。虽然理论上是安全的,但万一 growpart 把分区表写坏了,那就是大事故。 一次完整的操作 把上面的命令串起来,加上 df 前后的对比: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 扩容前 df -h / # 分区扩容 sudo growpart /dev/vda 3 # PV 重新读取 sudo pvresize /dev/vda3 # LV 扩容 sudo lvextend -l +100%FREE /dev/vg0/root # 文件系统扩容 sudo resize2fs /dev/vg0/root # 验证 df -h / 我实际跑的时候,每一步之间都 lsblk 或 pvs 确认一下。多敲几条命令,比出问题再回头找强。 几个坑 growpart 之后忘了 pvresize,这是最常见的。pvs 里 PFree 是 0,你就会以为是分区没扩成功,其实只是 LVM 不知道。 lvextend 用了 -L 但写的是增量值,比如 -L 20G 而当前已经是 20G,它什么都不做,也不报错。 xfs 用 resize2fs 会直接报错说不支持,别慌,换 xfs_growfs。 还有一个,如果你的 /boot 在 LVM 上,扩它是可以的,但 grub 那边可能需要重新生成配置。我这个机器的 /boot 是独立分区,没在 LVM 里,所以没遇到。 缩容的注意事项 扩容易,缩难。 ext4 缩容要三步。先 umount,然后 e2fsck -f 检查,再 resize2fs <设备> <目标大小>,最后 lvreduce。 顺序不能反。先缩文件系统再缩 LV。如果先缩 LV,文件系统就损坏了,数据基本找不回来。 xfs 根本不支持缩容。要用 xfs 又想缩,只能备份、重建、恢复。 所以我的建议是,宁可一开始规划得保守一点,也不要给自己留缩容的活。 磁盘规划的一点经验 装系统的时候我习惯这么分: /boot 给 512M,独立分区,不在 LVM 里。这是为了让 grub 和系统救援都能正常工作。 swap 给内存的一到两倍,但不超过 4G。现在很多云厂商建议不给 swap,我的看法是留一点,防止突发的内存尖峰直接把进程打死。 / 给剩下的全部。不用单独分 /var 和 /home,因为 LVM 的好处就是可以动态调,一开始分太细反而失去了灵活性。 这样分下来,如果哪天 /var/lib/docker 涨得太快,我直接扩根分区就行,不用去动别的。 现在的状态 扩到 80G 之后,根分区用了 38%,/data 那边还有空间。跑了一个多月,稳定。 顺手做了两件事。一是给 docker 加了 data-root 的迁移,把镜像目录挪到了 /data 下面,这样系统盘的压力小很多。二是加了个监控,磁盘到 85% 就推消息,不用等到 92% 才被叫醒。 LVM 这个东西,平时感觉不到它的存在,真正需要的时候才发现它的好。当初装系统多勾了一个选项,省了今天一晚上的事。
以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

登录后,加入这场讨论。
登录参与