前言
在 Linux 系统运维过程中,磁盘空间不足是一个常见且棘手的问题。特别是当系统分区使用率接近 100%时,如何快速、安全地扩容存储空间成为运维人员必须面对的挑战。
本文将详细介绍一个功能强大的 LVM 自动扩容脚本,帮助您快速解决存储空间不足的问题。
背景
传统的磁盘扩容操作通常需要执行多个复杂的命令步骤:
- 创建物理卷(pvcreate)
- 扩展卷组(vgextend)
- 扩展逻辑卷(lvextend)
- 扩展文件系统(resize2fs/xfs_growfs)
这些步骤不仅繁琐,而且容易出错。一旦操作失误,可能导致数据丢失或系统无法启动。因此,开发一个自动化的扩容脚本显得尤为重要。
脚本源码
为此特地写了个 lvm 一键扩容脚本,其实还是为了偷懒,脚本源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
| #!/bin/bash
set -e
show_help() { cat << EOF LVM扩容脚本 - 自动将新磁盘添加到现有卷组并扩容
使用方法: $0 -n <新磁盘设备> -d <挂载点> [选项]
参数: -n <device> 新磁盘设备 (必需) -d <mountpoint> 挂载点目录 (必需) -y 跳过确认提示,直接执行 -h 显示此帮助信息
示例: $0 -n /dev/sdc -d /data $0 -n /dev/sdd -d /opt -y
EOF }
NEW_DISK="" MOUNT_POINT="" AUTO_CONFIRM=0
if [ $# -eq 0 ]; then show_help exit 0 fi
while getopts "n:d:yh" opt; do case $opt in n) NEW_DISK="$OPTARG" ;; d) MOUNT_POINT="$OPTARG" ;; y) AUTO_CONFIRM=1 ;; h) show_help exit 0 ;; \?) echo "无效选项: -$OPTARG" >&2 show_help exit 1 ;; esac done
if [ -z "$NEW_DISK" ] || [ -z "$MOUNT_POINT" ]; then echo "错误: 缺少必需参数" echo "" show_help exit 1 fi
if [ ! -b "$NEW_DISK" ]; then echo "错误: 磁盘设备 $NEW_DISK 不存在" exit 1 fi
if [ ! -d "$MOUNT_POINT" ]; then echo "错误: 挂载点 $MOUNT_POINT 不存在" exit 1 fi
echo "正在获取挂载点 $MOUNT_POINT 的LVM信息..."
DEVICE_PATH=$(df "$MOUNT_POINT" | tail -1 | awk '{print $1}') if [ -z "$DEVICE_PATH" ]; then echo "错误: 无法获取挂载点 $MOUNT_POINT 对应的设备" exit 1 fi
if [[ "$DEVICE_PATH" =~ ^/dev/mapper/(.+)-(.+)$ ]]; then VG_NAME="${BASH_REMATCH[1]}" LV_NAME="${BASH_REMATCH[2]}" elif [[ "$DEVICE_PATH" =~ ^/dev/(.+)/(.+)$ ]]; then VG_NAME="${BASH_REMATCH[1]}" LV_NAME="${BASH_REMATCH[2]}" else echo "错误: 挂载点 $MOUNT_POINT 不是LVM逻辑卷" exit 1 fi
echo "检测到LVM信息:" echo " 设备路径: $DEVICE_PATH" echo " 卷组名称: $VG_NAME" echo " 逻辑卷名: $LV_NAME"
if ! vgdisplay "$VG_NAME" >/dev/null 2>&1; then echo "错误: 卷组 $VG_NAME 不存在" exit 1 fi
if ! lvdisplay "/dev/$VG_NAME/$LV_NAME" >/dev/null 2>&1; then echo "错误: 逻辑卷 $LV_NAME 在卷组 $VG_NAME 中不存在" exit 1 fi
echo "" echo "=========================================" echo "LVM扩容操作信息" echo "=========================================" echo "新磁盘设备: $NEW_DISK" echo "目标挂载点: $MOUNT_POINT" echo "目标卷组: $VG_NAME" echo "目标逻辑卷: $LV_NAME" echo "========================================="
echo "" echo "扩容前状态:" echo "物理卷信息:" pvs echo "" echo "卷组信息:" vgs echo "" echo "逻辑卷信息:" lvs echo "" echo "磁盘使用情况:" df -h "$MOUNT_POINT" echo ""
if [ $AUTO_CONFIRM -eq 0 ]; then read -p "确认要将 $NEW_DISK 添加到卷组 $VG_NAME 并扩容 $LV_NAME 吗?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "操作已取消" exit 0 fi else echo "自动确认模式,开始执行..." fi
echo "" echo "步骤1: 创建物理卷..." pvcreate "$NEW_DISK" echo "物理卷 $NEW_DISK 创建成功"
echo "" echo "步骤2: 扩展卷组..." vgextend "$VG_NAME" "$NEW_DISK" echo "卷组 $VG_NAME 扩展成功"
echo "" echo "步骤3: 扩展逻辑卷..." lvextend -l +100%FREE "/dev/$VG_NAME/$LV_NAME" echo "逻辑卷 $LV_NAME 扩展成功"
echo "" echo "步骤4: 检测文件系统类型并扩展..." FS_TYPE=$(df -T "$MOUNT_POINT" | tail -1 | awk '{print $2}') echo "检测到文件系统类型: $FS_TYPE"
case $FS_TYPE in ext4|ext3|ext2) echo "扩展ext文件系统..." resize2fs "/dev/$VG_NAME/$LV_NAME" ;; xfs) echo "扩展xfs文件系统..." xfs_growfs "$MOUNT_POINT" ;; *) echo "警告: 不支持的文件系统类型 $FS_TYPE,请手动扩展文件系统" ;; esac
echo "" echo "=========================================" echo "扩容完成! 最终状态:" echo "=========================================" echo "" echo "物理卷信息:" pvs echo "" echo "卷组信息:" vgs echo "" echo "逻辑卷信息:" lvs echo "" echo "磁盘使用情况:" df -h "$MOUNT_POINT" echo "" echo "磁盘布局:" lsblk echo "" echo "=========================================" echo "LVM扩容脚本执行完成" echo "========================================="
|
实战演示
有一台 RHEL 系统,根分区空间严重不足(使用率 97%),需要添加一块 50GB 的新磁盘来扩容根分区。
扩容前状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| [root@localhost ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/rhel-root 50G 49G 2.0G 97% / devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 34M 3.8G 1% /run tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup /dev/vda1 1014M 143M 872M 15% /boot /dev/mapper/rhel-home 42G 4.7G 37G 12% /home tmpfs 1.6G 0 1.6G 0% /run/user/0 [root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT fd0 2:0 1 4K 0 disk sr0 11:0 1 1024M 0 rom vda 252:0 0 100G 0 disk ├─vda1 252:1 0 1G 0 part /boot └─vda2 252:2 0 99G 0 part ├─rhel-root 253:0 0 50G 0 lvm / ├─rhel-swap 253:1 0 7.9G 0 lvm [SWAP] └─rhel-home 253:2 0 41.1G 0 lvm /home vdb 252:16 0 50G 0 disk [root@localhost ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 rhel lvm2 a-- <99.00g 4.00m [root@localhost ~]# vgs VG rhel 1 3 0 wz--n- <99.00g 4.00m [root@localhost ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert home rhel -wi-ao---- <41.12g root rhel -wi-ao---- 50.00g swap rhel -wi-ao---- <7.88g
|
执行扩容操作
执行脚本一键扩容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| [root@localhost ~]# vi led.sh [root@localhost ~]# chmod +x led.sh [root@localhost ~]# ./led.sh LVM扩容脚本 - 自动将新磁盘添加到现有卷组并扩容
使用方法: ./led.sh -n <新磁盘设备> -d <挂载点> [选项]
参数: -n <device> 新磁盘设备 (必需) -d <mountpoint> 挂载点目录 (必需) -y 跳过确认提示,直接执行 -h 显示此帮助信息
示例: ./led.sh -n /dev/sdc -d /data ./led.sh -n /dev/sdd -d /opt -y
[root@localhost ~]# ./led.sh -n /dev/vdb -d / 正在获取挂载点 / 的LVM信息... 检测到LVM信息: 设备路径: /dev/mapper/rhel-root 卷组名称: rhel 逻辑卷名: root
========================================= LVM扩容操作信息 ========================================= 新磁盘设备: /dev/vdb 目标挂载点: / 目标卷组: rhel 目标逻辑卷: root =========================================
扩容前状态: 物理卷信息: PV VG Fmt Attr PSize PFree /dev/vda2 rhel lvm2 a-- <99.00g 4.00m
卷组信息: VG rhel 1 3 0 wz--n- <99.00g 4.00m
逻辑卷信息: LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert home rhel -wi-ao---- <41.12g root rhel -wi-ao---- 50.00g swap rhel -wi-ao---- <7.88g
磁盘使用情况: Filesystem Size Used Avail Use% Mounted on /dev/mapper/rhel-root 50G 49G 2.0G 97% /
确认要将 /dev/vdb 添加到卷组 rhel 并扩容 root 吗?(y/N): y
步骤1: 创建物理卷... Physical volume "/dev/vdb" successfully created. 物理卷 /dev/vdb 创建成功
步骤2: 扩展卷组... Volume group "rhel" successfully extended 卷组 rhel 扩展成功
步骤3: 扩展逻辑卷... Size of logical volume rhel/root changed from 50.00 GiB (12800 extents) to 100.00 GiB (25600 extents). Logical volume rhel/root successfully resized. 逻辑卷 root 扩展成功
步骤4: 检测文件系统类型并扩展... 检测到文件系统类型: xfs 扩展xfs文件系统... meta-data=/dev/mapper/rhel-root isize=512 agcount=4, agsize=3276800 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=0 spinodes=0 data = bsize=4096 blocks=13107200, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal bsize=4096 blocks=6400, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 data blocks changed from 13107200 to 26214400
========================================= 扩容完成! 最终状态: =========================================
物理卷信息: PV VG Fmt Attr PSize PFree /dev/vda2 rhel lvm2 a-- <99.00g 0 /dev/vdb rhel lvm2 a-- <50.00g 0
卷组信息: VG rhel 2 3 0 wz--n- 148.99g 0
逻辑卷信息: LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert home rhel -wi-ao---- <41.12g root rhel -wi-ao---- 100.00g swap rhel -wi-ao---- <7.88g
磁盘使用情况: Filesystem Size Used Avail Use% Mounted on /dev/mapper/rhel-root 100G 49G 52G 49% /
磁盘布局: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT fd0 2:0 1 4K 0 disk sr0 11:0 1 1024M 0 rom vda 252:0 0 100G 0 disk ├─vda1 252:1 0 1G 0 part /boot └─vda2 252:2 0 99G 0 part ├─rhel-root 253:0 0 100G 0 lvm / ├─rhel-swap 253:1 0 7.9G 0 lvm [SWAP] └─rhel-home 253:2 0 41.1G 0 lvm /home vdb 252:16 0 50G 0 disk └─rhel-root 253:0 0 100G 0 lvm /
========================================= LVM扩容脚本执行完成 =========================================
|
扩容后检查
扩容后的根目录为 100G:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| [root@localhost ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/rhel-root 100G 49G 52G 49% / devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 34M 3.8G 1% /run tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup /dev/vda1 1014M 143M 872M 15% /boot /dev/mapper/rhel-home 42G 4.7G 37G 12% /home tmpfs 1.6G 0 1.6G 0% /run/user/0 [root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT fd0 2:0 1 4K 0 disk sr0 11:0 1 1024M 0 rom vda 252:0 0 100G 0 disk ├─vda1 252:1 0 1G 0 part /boot └─vda2 252:2 0 99G 0 part ├─rhel-root 253:0 0 100G 0 lvm / ├─rhel-swap 253:1 0 7.9G 0 lvm [SWAP] └─rhel-home 253:2 0 41.1G 0 lvm /home vdb 252:16 0 50G 0 disk └─rhel-root 253:0 0 100G 0 lvm /
|
写在最后
本文介绍的 LVM 自动扩容脚本具有智能化、安全性高、操作简便的特点,能够有效解决 Linux 系统中磁盘空间不足的问题。脚本通过自动识别 LVM 结构、多重安全检查、智能文件系统扩展等特性,大大简化了传统的手工扩容流程,降低了操作风险。
在实际应用中,建议根据具体环境需求对脚本进行适当定制,并建立完善的测试和备份机制。通过合理使用此脚本,可以显著提升系统运维效率,确保业务系统的稳定运行。