Linux 磁盘挂载、分区与 LVM 分卷实战

欢迎你来读这篇博客,这篇博客主要是关于 Linux 磁盘挂载、分区、分卷和 LVM 管理。

在服务器运维、Docker 数据目录迁移、数据库磁盘扩容、日志盘挂载、云服务器数据盘初始化这些场景里,磁盘管理都是绕不开的基础能力。

这块知识看起来命令很多:mountfdiskpartedmkfsblkidlsblkfstabpvcreatevgcreatelvcreate
lvextend……
但只要把它们放到一条主线里,其实很清晰:

磁盘来了,先识别;
要用它,先分区;
要存文件,建文件系统;
要访问它,挂载到目录;
要开机还在,写入 fstab;
要灵活扩容,交给 LVM。

序言

Linux 里有一句非常经典的话:

Everything is a file.

磁盘也不例外。

我们平时看到的 /dev/sda/dev/vda/dev/nvme0n1/dev/sdb1,本质上都是块设备文件。

但是,磁盘并不是插上去就能直接优雅使用。一个完整的磁盘使用链路通常是这样的:

flowchart LR
    A[物理磁盘 /dev/sdb] --> B[分区表 GPT/MBR]
    B --> C[分区 /dev/sdb1]
    C --> D[文件系统 ext4/xfs]
    D --> E[挂载点 /data]
    E --> F[业务读写文件]

如果使用 LVM,链路会变成这样:

flowchart LR
    A[物理磁盘 /dev/sdb] --> B[分区 /dev/sdb1]
    B --> C[PV 物理卷]
    C --> D[VG 卷组]
    D --> E[LV 逻辑卷]
    E --> F[文件系统 ext4/xfs]
    F --> G[挂载点 /data]

这篇文章会围绕以下几个核心工具展开:

工具 作用
lsblk 查看块设备结构
blkid 查看文件系统 UUID、类型
df 查看已挂载文件系统空间
findmnt 查看挂载关系
fdisk 交互式分区工具,常用于普通磁盘分区
parted 分区工具,适合 GPT、大磁盘、脚本化、调整分区
mkfs 创建文件系统
mount 临时挂载文件系统
umount 卸载文件系统
/etc/fstab 配置开机自动挂载
pvcreate 创建 LVM 物理卷
vgcreate 创建 LVM 卷组
lvcreate 创建 LVM 逻辑卷
lvextend 扩容 LVM 逻辑卷
pvresize 调整 LVM 物理卷大小

正文

一、先理解 Linux 磁盘命名

Linux 中常见磁盘命名如下:

设备名 常见场景
/dev/sda SATA、SCSI、传统虚拟磁盘
/dev/sdb 第二块 SATA/SCSI 磁盘
/dev/vda KVM、VirtIO 虚拟磁盘
/dev/xvda Xen 虚拟化环境
/dev/nvme0n1 NVMe SSD
/dev/sda1 /dev/sda 的第一个分区
/dev/nvme0n1p1 NVMe 磁盘的第一个分区

普通磁盘分区命名一般是:

1
2
3
/dev/sdb
/dev/sdb1
/dev/sdb2

NVMe 磁盘命名一般是:

1
2
3
/dev/nvme0n1
/dev/nvme0n1p1
/dev/nvme0n1p2

这里要注意一个细节:

/dev/sdb 是整块磁盘,/dev/sdb1 是这块磁盘上的第一个分区。

千万不要看到一个设备名就直接 mkfs,不然你可能一键把生产环境打成“考古现场”。命令不背锅,手才背锅。

二、磁盘管理的基本流程

一般新增一块磁盘后,标准流程如下:

flowchart TD
    A[新增磁盘] --> B[lsblk 查看磁盘]
    B --> C[fdisk/parted 创建分区]
    C --> D[partprobe 重新读取分区表]
    D --> E[mkfs 创建文件系统]
    E --> F[mkdir 创建挂载点]
    F --> G[mount 临时挂载]
    G --> H[blkid 获取 UUID]
    H --> I[写入 /etc/fstab]
    I --> J[mount -a 测试开机挂载配置]

对应命令大致如下:

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
# 1. 查看磁盘
lsblk

# 2. 创建分区
fdisk /dev/sdb

# 3. 通知内核重新读取分区表
partprobe /dev/sdb

# 4. 创建文件系统
mkfs.xfs /dev/sdb1

# 5. 创建挂载目录
mkdir -p /data

# 6. 临时挂载
mount /dev/sdb1 /data

# 7. 查看 UUID
blkid /dev/sdb1

# 8. 写入 /etc/fstab
vim /etc/fstab

# 9. 验证 fstab
mount -a

三、查看磁盘信息

1. lsblk:查看块设备结构

lsblk 是最常用的磁盘查看命令。

1
lsblk

输出示例:

1
2
3
4
5
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda 8:0 0 80G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 79G 0 part /
sdb 8:16 0 200G 0 disk

更推荐使用详细格式:

1
lsblk -f

或者:

1
lsblk -o NAME,SIZE,TYPE,FSTYPE,LABEL,UUID,MOUNTPOINT

示例:

1
2
3
4
5
NAME   SIZE TYPE FSTYPE LABEL UUID                                 MOUNTPOINT
sda 80G disk
├─sda1 1G part xfs 4e1b2c3d-xxxx-xxxx-xxxx-xxxxxxxxxxxx /boot
└─sda2 79G part xfs 6a7b8c9d-xxxx-xxxx-xxxx-xxxxxxxxxxxx /
sdb 200G disk

如果看到 sdb 没有分区、没有文件系统、没有挂载点,就说明它大概率是一块新盘。

2. fdisk -l:查看分区表

1
fdisk -l

查看指定磁盘:

1
fdisk -l /dev/sdb

示例:

1
2
3
4
5
Disk /dev/sdb: 200 GiB
Disk model: Virtual Disk
Disklabel type: gpt
Device Start End Sectors Size Type
/dev/sdb1 2048 419430366 419428319 200G Linux filesystem

重点看:

字段 含义
Disk 磁盘名称和大小
Disklabel type 分区表类型,如 dosgpt
Device 分区名称
Size 分区大小
Type 分区类型

3. blkid:查看 UUID 和文件系统类型

1
blkid

查看指定分区:

1
blkid /dev/sdb1

输出示例:

1
/dev/sdb1: UUID="a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="xfs"

UUID 非常重要,因为后面写 /etc/fstab 时,推荐使用 UUID,而不是 /dev/sdb1

原因是:

/dev/sdb1 这种设备名可能会因为磁盘识别顺序变化而改变,但 UUID 基本稳定。

4. df:查看文件系统空间

1
df -h

带文件系统类型:

1
df -hT

输出示例:

1
2
3
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda2 xfs 79G 20G 59G 26% /
/dev/sdb1 xfs 200G 10G 190G 5% /data

df 看的是“已经挂载的文件系统”,不是所有磁盘。
所以新磁盘如果还没挂载,df -h 里是看不到的。

5. findmnt:查看挂载关系

1
findmnt

查看指定目录:

1
findmnt /data

输出示例:

1
2
TARGET SOURCE    FSTYPE OPTIONS
/data /dev/sdb1 xfs rw,relatime

findmntmount 命令输出更清晰,非常适合排查挂载问题。

四、分区表:MBR 与 GPT

在给磁盘分区之前,先要理解分区表。

常见分区表有两种:

分区表 说明
MBR / DOS 老式分区表,兼容性好,但限制较多
GPT 新式分区表,适合大磁盘和现代系统

1. MBR

MBR 也叫 DOS 分区表。

特点:

特点 说明
兼容性 很好
最大磁盘支持 通常不适合超过 2TB 的磁盘
主分区数量 最多 4 个主分区
扩展分区 可以通过扩展分区绕过主分区数量限制

2. GPT

GPT 是现代 Linux 服务器更推荐的分区表。

特点:

特点 说明
支持大磁盘 适合 TB 级、PB 级磁盘
分区数量多 不再受 MBR 4 个主分区的传统限制
可靠性更好 分区表有主备结构
现代系统推荐 云服务器、NVMe、大容量数据盘更适合 GPT

一般建议:

场景 推荐
新数据盘 GPT
大于 2TB 的磁盘 GPT
老系统兼容 MBR
生产服务器 GPT
自动化脚本 parted + GPT

五、fdisk 分区实战

fdisk 是一个交互式分区工具,适合手动创建和修改分区。

假设现在新增一块磁盘 /dev/sdb,我们要把它分成一个完整的数据分区并挂载到 /data

1. 查看磁盘

1
lsblk

确认 /dev/sdb 是新磁盘:

1
2
3
4
5
NAME   SIZE TYPE MOUNTPOINT
sda 80G disk
├─sda1 1G part /boot
└─sda2 79G part /
sdb 200G disk

2. 进入 fdisk

1
sudo fdisk /dev/sdb

进入后输入 m 可以查看帮助:

1
Command (m for help): m

常用命令:

命令 作用
m 查看帮助
p 打印当前分区表
g 创建 GPT 分区表
o 创建 MBR/DOS 分区表
n 新建分区
d 删除分区
t 修改分区类型
w 保存并退出
q 不保存退出

3. 创建 GPT 分区表

1
Command (m for help): g

提示:

1
Created a new GPT disklabel.

4. 新建分区

1
Command (m for help): n

一路回车,使用默认值,表示创建一个占满整块磁盘的分区。

如果只想创建 100G 分区,可以在 Last sector 的地方输入:

1
+100G

5. 查看分区

1
Command (m for help): p

示例:

1
2
Device       Start       End   Sectors  Size Type
/dev/sdb1 2048 419430366 419428319 200G Linux filesystem

6. 保存分区表

1
Command (m for help): w

注意:

fdisk 在输入 w 之前通常不会真正写入分区表。
但一旦 w 写入,就不是“试试看”了,而是“真动刀”了。

7. 重新读取分区表

1
sudo partprobe /dev/sdb

或者:

1
sudo partx -a /dev/sdb

再查看:

1
lsblk

应该能看到:

1
2
sdb    200G disk
└─sdb1 200G part

六、parted 分区实战

parted 也是分区工具,相比 fdisk,它更适合:

场景 是否推荐 parted
大于 2TB 的磁盘 推荐
GPT 分区 推荐
脚本化创建分区 推荐
调整分区大小 推荐
临时手动分一个小盘 fdisk 也可以

1. 交互式使用 parted

1
sudo parted /dev/sdb

查看当前信息:

1
(parted) print

创建 GPT 分区表:

1
(parted) mklabel gpt

创建分区:

1
(parted) mkpart primary xfs 1MiB 100%

退出:

1
(parted) quit

注意:

parted 的很多操作是立即生效的,不像 fdisk 那样最后输入 w 才统一写入。
所以使用 parted 前一定要确认磁盘名,别拿生产盘练手。

2. parted 脚本化分区

创建一整块数据盘分区:

1
2
3
sudo parted -s /dev/sdb mklabel gpt
sudo parted -a optimal -s /dev/sdb mkpart primary xfs 1MiB 100%
sudo partprobe /dev/sdb

解释一下:

参数 含义
-s script 模式,不进入交互
mklabel gpt 创建 GPT 分区表
-a optimal 使用最优对齐
mkpart primary xfs 1MiB 100% 创建从 1MiB 到磁盘末尾的分区

3. parted 查看分区

1
sudo parted /dev/sdb print

输出示例:

1
2
3
4
5
6
7
Model: Virtio Block Device
Disk /dev/sdb: 215GB
Sector size: 512B/512B
Partition Table: gpt

Number Start End Size File system Name Flags
1 1049kB 215GB 215GB primary

这里有个细节:

parted mkpart 只是创建分区,不会创建文件系统。
文件系统需要用 mkfs.ext4mkfs.xfs 单独创建。

七、创建文件系统:mkfs

分区完成之后,磁盘还不能直接存文件。
还需要创建文件系统。

常见文件系统:

文件系统 特点
ext4 通用、稳定、兼容性好、支持缩容
xfs 高性能,适合大文件、大容量场景,但不支持缩容
btrfs 支持快照、压缩等高级特性
swap 交换分区,不是普通文件系统

1. 创建 XFS 文件系统

1
sudo mkfs.xfs /dev/sdb1

如果磁盘上已有文件系统,需要强制格式化:

1
sudo mkfs.xfs -f /dev/sdb1

慎用 -f
它的意思不是“放心”,而是“我知道我在毁灭什么”。

2. 创建 ext4 文件系统

1
sudo mkfs.ext4 /dev/sdb1

指定 Label:

1
sudo mkfs.ext4 -L data /dev/sdb1

3. 查看文件系统

1
blkid /dev/sdb1

输出示例:

1
/dev/sdb1: UUID="a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="xfs"

八、mount 挂载实战

Linux 不是像 Windows 那样通过 C 盘、D 盘访问磁盘。
Linux 是把文件系统挂载到某个目录上。

例如:

1
/dev/sdb1  -->  /data

访问 /data,实际就是访问 /dev/sdb1 这个分区里的文件系统。

1. 创建挂载点

1
sudo mkdir -p /data

2. 临时挂载

1
sudo mount /dev/sdb1 /data

查看:

1
df -hT /data

或者:

1
findmnt /data

3. 指定文件系统类型挂载

1
sudo mount -t xfs /dev/sdb1 /data

一般情况下,系统可以自动识别文件系统类型,不写 -t 也可以。

4. 只读挂载

1
sudo mount -o ro /dev/sdb1 /data

适合数据恢复、排查问题时避免误写。

5. 重新挂载

1
sudo mount -o remount,rw /data

或者:

1
sudo mount -o remount,ro /data

6. bind mount

bind mount 可以把一个目录挂载到另一个目录。

1
2
sudo mkdir -p /mnt/app-logs
sudo mount --bind /var/log/app /mnt/app-logs

查看:

1
findmnt /mnt/app-logs

这种方式在容器、chroot、目录隔离、日志目录映射中很常见。

7. tmpfs 挂载

tmpfs 是内存文件系统,适合临时缓存。

1
2
sudo mkdir -p /mnt/cache
sudo mount -t tmpfs -o size=1G tmpfs /mnt/cache

查看:

1
df -hT /mnt/cache

注意:

tmpfs 数据在重启后会消失,不要把数据库放进去。
除非你想体验一次“缓存即人生,重启即空”。

九、umount 卸载文件系统

卸载命令是 umount,不是 unmount

1
sudo umount /data

或者:

1
sudo umount /dev/sdb1

1. device is busy 问题

如果提示:

1
umount: /data: target is busy.

说明有进程正在使用这个目录。

查看占用进程:

1
sudo lsof +f -- /data

或者:

1
sudo fuser -vm /data

示例:

1
2
                     USER        PID ACCESS COMMAND
/data: root 1234 ..c.. bash

如果是自己 shell 当前就在 /data 目录下,也会导致卸载失败。

解决:

1
2
cd /
sudo umount /data

强制杀进程要非常谨慎:

1
sudo fuser -km /data

生产环境不要随手用这个命令。
它很有效,也很“缺德”。

2. 懒卸载

1
sudo umount -l /data

-l 表示 lazy unmount。
它会先从目录树中解除挂载关系,等设备不再忙时再清理。

这个命令适合某些卡住的场景,但不要把它当常规手段。

十、/etc/fstab:开机自动挂载

mount 命令只是临时挂载。
重启之后,挂载关系会消失。

如果想开机自动挂载,需要写入:

1
/etc/fstab

1. fstab 格式

/etc/fstab 每一行格式如下:

1
<设备>  <挂载点>  <文件系统类型>  <挂载参数>  <dump>  <fsck>

示例:

1
UUID=a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data xfs defaults,nofail 0 0

字段解释:

字段 说明
UUID=... 要挂载的设备
/data 挂载点
xfs 文件系统类型
defaults,nofail 挂载参数
0 dump 备份标记,通常为 0
0 fsck 检查顺序,根分区通常为 1,普通分区可为 2 或 0

2. 为什么推荐 UUID

不推荐这样写:

1
/dev/sdb1 /data xfs defaults 0 0

更推荐这样写:

1
UUID=a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data xfs defaults,nofail 0 0

原因是:

/dev/sdb1 可能因为磁盘识别顺序变化变成 /dev/sdc1,但 UUID 不会轻易变化。

获取 UUID:

1
sudo blkid /dev/sdb1

3. 常用挂载参数

参数 作用
defaults 默认参数
rw 可读写
ro 只读
nofail 挂载失败不阻塞启动
noatime 不更新访问时间,减少写入
relatime 相对访问时间,常见默认值
nodev 不解析设备文件
nosuid 禁用 suid
noexec 禁止执行二进制文件
x-systemd.automount systemd 自动挂载
x-systemd.device-timeout=10s 设备等待超时时间

普通数据盘示例:

1
UUID=a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data xfs defaults,nofail 0 0

日志盘示例:

1
UUID=b4c5d6e7-xxxx-xxxx-xxxx-xxxxxxxxxxxx /var/log/app xfs defaults,nofail,noatime 0 0

更安全的临时上传目录:

1
UUID=c5d6e7f8-xxxx-xxxx-xxxx-xxxxxxxxxxxx /upload ext4 defaults,nofail,nodev,nosuid,noexec 0 2

4. 修改 fstab 后一定要测试

修改 /etc/fstab 后,千万不要直接重启。

先执行:

1
sudo mount -a

如果没有报错,再检查:

1
2
df -hT
findmnt /data

也可以使用:

1
findmnt --verify

如果 fstab 写错,服务器可能启动时卡住。
所以改 fstab 的原则是:

写完不测试,重启两行泪。

十一、fdisk + mount 完整案例:挂载一块普通数据盘

目标:

项目
新磁盘 /dev/sdb
分区 /dev/sdb1
文件系统 xfs
挂载点 /data
开机自动挂载

1. 查看磁盘

1
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT

确认 /dev/sdb 是新盘。

2. 分区

1
sudo fdisk /dev/sdb

交互流程:

1
2
3
4
5
6
7
g      # 创建 GPT 分区表
n # 新建分区
回车 # 默认分区号
回车 # 默认起始扇区
回车 # 默认使用全部空间
p # 查看分区
w # 保存

3. 重新读取分区

1
sudo partprobe /dev/sdb

4. 创建文件系统

1
sudo mkfs.xfs /dev/sdb1

5. 创建挂载点

1
sudo mkdir -p /data

6. 临时挂载

1
sudo mount /dev/sdb1 /data

7. 查看结果

1
2
df -hT /data
findmnt /data

8. 获取 UUID

1
sudo blkid /dev/sdb1

示例:

1
/dev/sdb1: UUID="a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="xfs"

9. 写入 fstab

1
sudo vim /etc/fstab

追加:

1
UUID=a3f4e5d6-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data xfs defaults,nofail 0 0

10. 测试

1
2
sudo mount -a
df -hT /data

完成。

十二、parted 完整案例:脚本化初始化数据盘

目标:

项目
新磁盘 /dev/sdb
分区表 GPT
分区大小 使用整块磁盘
文件系统 ext4
挂载点 /data

脚本如下:

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
#!/usr/bin/env bash
set -euo pipefail

DISK="/dev/sdb"
PART="${DISK}1"
MOUNT_POINT="/data"

echo "当前磁盘信息:"
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT

echo "即将初始化磁盘:${DISK}"
read -r -p "确认继续?这会清空目标磁盘分区表!输入 yes 继续: " CONFIRM

if [ "${CONFIRM}" != "yes" ]; then
echo "已取消"
exit 1
fi

sudo parted -s "${DISK}" mklabel gpt
sudo parted -a optimal -s "${DISK}" mkpart primary ext4 1MiB 100%
sudo partprobe "${DISK}"

sudo mkfs.ext4 -F "${PART}"

sudo mkdir -p "${MOUNT_POINT}"
sudo mount "${PART}" "${MOUNT_POINT}"

UUID=$(sudo blkid -s UUID -o value "${PART}")

echo "UUID=${UUID} ${MOUNT_POINT} ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab

sudo mount -a

echo "挂载完成:"
df -hT "${MOUNT_POINT}"

保存为:

1
init-disk.sh

执行:

1
2
chmod +x init-disk.sh
./init-disk.sh

注意:

这个脚本会清空目标磁盘分区表,只适合新盘初始化。
不要对已有数据盘直接执行。

十三、LVM 是什么?

LVM 全称是 Logical Volume Manager,逻辑卷管理器。

普通分区模式是:

flowchart LR
    A[磁盘] --> B[分区]
    B --> C[文件系统]
    C --> D[挂载点]

LVM 模式是:

flowchart LR
    A[磁盘1] --> C[PV]
    B[磁盘2] --> D[PV]
    C --> E[VG 卷组]
    D --> E
    E --> F[LV 逻辑卷1]
    E --> G[LV 逻辑卷2]
    F --> H[文件系统]
    H --> I[挂载点 /data]

LVM 的核心价值是:

把底层物理磁盘抽象成资源池,然后从资源池里切逻辑卷使用。

这就像你不再直接拿一块块砖头盖房子,而是先把砖头、钢筋、水泥都放进一个材料仓库,然后按需要建卧室、厨房、车库。
当然,前提是你别把厨房建在数据库日志盘上,生活已经够难了。

十四、LVM 三层模型:PV、VG、LV

LVM 主要有三层:

层级 全称 作用
PV Physical Volume 物理卷,由磁盘或分区初始化而来
VG Volume Group 卷组,把多个 PV 聚合成一个存储池
LV Logical Volume 逻辑卷,从 VG 中划分出来给文件系统使用

关系如下:

flowchart TD
    A['/dev/sdb1'] --> B[PV]
    C['/dev/sdc1'] --> D[PV]
    B --> E[VG: vg_data]
    D --> E
    E --> F[LV: lv_app]
    E --> G[LV: lv_log]
    F --> H['/app']
    G --> I['/log']

简单理解:

概念 类比
PV 一块原材料
VG 一个资源池
LV 从资源池切出来的虚拟磁盘
文件系统 给虚拟磁盘铺格式
挂载点 对外使用入口

十五、LVM 常用命令

1. 查看命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看 PV
pvs
pvdisplay

# 查看 VG
vgs
vgdisplay

# 查看 LV
lvs
lvdisplay

# 查看块设备关系
lsblk

2. 创建命令

1
2
3
4
5
6
7
8
# 创建 PV
pvcreate /dev/sdb1

# 创建 VG
vgcreate vg_data /dev/sdb1

# 创建 LV
lvcreate -n lv_app -L 100G vg_data

3. 扩容命令

1
2
3
4
5
6
7
8
# 扩展 VG
vgextend vg_data /dev/sdc1

# 扩展 LV
lvextend -L +50G /dev/vg_data/lv_app

# 使用 VG 剩余所有空间扩展 LV
lvextend -l +100%FREE /dev/vg_data/lv_app

4. 文件系统扩容

XFS:

1
xfs_growfs /data

ext4:

1
resize2fs /dev/vg_data/lv_app

也可以使用:

1
lvextend -r -L +50G /dev/vg_data/lv_app

-r 表示扩容 LV 后同时尝试扩容文件系统。

十六、LVM 完整案例:创建逻辑卷并挂载

目标:

项目
磁盘 /dev/sdb
分区 /dev/sdb1
PV /dev/sdb1
VG vg_data
LV lv_app
文件系统 xfs
挂载点 /data

1. 创建分区

1
2
3
sudo parted -s /dev/sdb mklabel gpt
sudo parted -a optimal -s /dev/sdb mkpart primary 1MiB 100%
sudo partprobe /dev/sdb

2. 创建 PV

1
sudo pvcreate /dev/sdb1

查看:

1
sudo pvs

输出示例:

1
2
PV         VG       Fmt  Attr PSize    PFree
/dev/sdb1 lvm2 --- 200.00g 200.00g

3. 创建 VG

1
sudo vgcreate vg_data /dev/sdb1

查看:

1
sudo vgs

输出示例:

1
2
VG      #PV #LV #SN Attr   VSize   VFree
vg_data 1 0 0 wz--n- 200.00g 200.00g

4. 创建 LV

创建 100G 逻辑卷:

1
sudo lvcreate -n lv_app -L 100G vg_data

如果要使用全部空间:

1
sudo lvcreate -n lv_app -l 100%FREE vg_data

查看:

1
sudo lvs

输出示例:

1
2
LV     VG      Attr       LSize
lv_app vg_data -wi-a----- 100.00g

逻辑卷路径通常是:

1
/dev/vg_data/lv_app

或者:

1
/dev/mapper/vg_data-lv_app

5. 创建文件系统

1
sudo mkfs.xfs /dev/vg_data/lv_app

6. 创建挂载点并挂载

1
2
sudo mkdir -p /data
sudo mount /dev/vg_data/lv_app /data

7. 写入 fstab

获取 UUID:

1
sudo blkid /dev/vg_data/lv_app

追加到 /etc/fstab

1
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data xfs defaults,nofail 0 0

测试:

1
2
sudo mount -a
df -hT /data

十七、LVM 扩容场景一:新增一块磁盘扩容

这是生产环境非常常见的场景。

当前:

1
/data 100G

新增一块 /dev/sdc,想扩容到 /data

1. 给新磁盘分区

1
2
3
sudo parted -s /dev/sdc mklabel gpt
sudo parted -a optimal -s /dev/sdc mkpart primary 1MiB 100%
sudo partprobe /dev/sdc

2. 创建 PV

1
sudo pvcreate /dev/sdc1

3. 加入已有 VG

1
sudo vgextend vg_data /dev/sdc1

查看 VG 空间:

1
sudo vgs

4. 扩展 LV

把所有空闲空间都给 /data

1
sudo lvextend -l +100%FREE /dev/vg_data/lv_app

也可以只增加 100G:

1
sudo lvextend -L +100G /dev/vg_data/lv_app

5. 扩展文件系统

如果是 XFS:

1
sudo xfs_growfs /data

如果是 ext4:

1
sudo resize2fs /dev/vg_data/lv_app

6. 查看结果

1
2
3
df -hT /data
lvs
vgs

完整流程:

flowchart TD
    A[新增磁盘 /dev/sdc] --> B[创建分区 /dev/sdc1]
    B --> C[pvcreate /dev/sdc1]
    C --> D[vgextend vg_data /dev/sdc1]
    D --> E[lvextend lv_app]
    E --> F[xfs_growfs 或 resize2fs]
    F --> G[/data 容量变大]

十八、LVM 扩容场景二:云盘本身扩容

云服务器里还有一种常见情况:

不是新增一块磁盘,而是在云控制台把原来的磁盘从 100G 扩到了 200G。

比如:

1
/dev/sdb 100G -> 200G

这时系统里可能看到磁盘变大了,但分区、PV、LV、文件系统还没变大。

整体流程:

flowchart TD
    A[云控制台扩容磁盘] --> B[系统识别磁盘变大]
    B --> C[扩展分区]
    C --> D[pvresize 扩展 PV]
    D --> E[lvextend 扩展 LV]
    E --> F[扩展文件系统]

1. 查看磁盘

1
lsblk

假设看到:

1
2
sdb     200G disk
└─sdb1 100G part

说明磁盘已经是 200G,但分区还是 100G。

2. 扩展分区

使用 parted:

1
sudo parted /dev/sdb

进入后:

1
2
3
(parted) print
(parted) resizepart 1 100%
(parted) quit

重新读取分区表:

1
sudo partprobe /dev/sdb

再次查看:

1
lsblk

应该变成:

1
2
sdb     200G disk
└─sdb1 200G part

3. 扩展 PV

1
sudo pvresize /dev/sdb1

查看:

1
2
sudo pvs
sudo vgs

4. 扩展 LV

1
sudo lvextend -l +100%FREE /dev/vg_data/lv_app

5. 扩展文件系统

XFS:

1
sudo xfs_growfs /data

ext4:

1
sudo resize2fs /dev/vg_data/lv_app

6. 验证

1
df -hT /data

十九、LVM 缩容要非常谨慎

扩容一般比较安全,缩容就危险得多。

尤其是 XFS:

XFS 不支持缩容。

ext4 支持缩容,但流程也比较危险,通常需要:

  1. 备份数据
  2. 卸载文件系统
  3. 检查文件系统
  4. 先缩文件系统
  5. 再缩 LV
  6. 重新挂载

大致流程:

1
2
3
4
5
sudo umount /data
sudo e2fsck -f /dev/vg_data/lv_app
sudo resize2fs /dev/vg_data/lv_app 80G
sudo lvreduce -L 80G /dev/vg_data/lv_app
sudo mount /data

更稳妥的方式是:

1
sudo lvreduce --resizefs -L 80G /dev/vg_data/lv_app

但是,即使用 --resizefs,也不代表可以不备份。

缩容原则:

先缩文件系统,再缩块设备。
顺序反了,数据就没了。
数据没了,人也安静了。

生产环境里,如果不是非常必要,尽量不要缩容。
更推荐新建小卷、迁移数据、验证后切换。

二十、普通分区和 LVM 怎么选?

场景 推荐方案
临时测试机 普通分区
简单数据盘 普通分区
Docker 数据目录 LVM 或独立数据盘
数据库数据盘 LVM,或者云盘直接管理
日志盘 LVM
经常扩容 LVM
多块盘合并管理 LVM
要做快照 LVM 或云盘快照
对运维能力要求低 普通分区
追求长期灵活性 LVM

我的建议:

单机简单业务,普通分区够用。
生产环境长期跑服务,尤其是数据目录、日志目录、数据库目录,优先考虑 LVM 或云厂商块存储方案。

二十一、文件系统选择:ext4 还是 xfs?

1. ext4

优点:

优点 说明
稳定成熟 使用广泛
兼容性好 各类发行版支持好
支持缩容 相比 XFS 更灵活
适合普通场景 中小型数据盘非常合适

2. xfs

优点:

优点 说明
大文件性能好 适合大容量、大文件
扩容方便 在线扩容体验好
适合日志/数据盘 生产环境常见
元数据性能好 大目录、大文件场景表现不错

缺点:

缺点 说明
不支持缩容 一旦建大了,不能直接缩小

选择建议:

场景 推荐
普通 Web 服务数据盘 ext4 / xfs 都可以
大日志目录 xfs
数据库数据盘 xfs 常见
需要可能缩容 ext4
RHEL/CentOS 系 xfs 很常见
Debian/Ubuntu 普通场景 ext4 很常见

二十二、挂载 Docker 数据目录案例

Docker 默认数据目录通常是:

1
/var/lib/docker

如果根分区空间不大,Docker 镜像、容器、日志很容易把 / 撑爆。

可以把新盘挂载到 /var/lib/docker

1. 停止 Docker

1
sudo systemctl stop docker

2. 准备新磁盘并挂载到临时目录

假设新盘已经格式化为 /dev/sdb1

1
2
sudo mkdir -p /mnt/docker-data
sudo mount /dev/sdb1 /mnt/docker-data

3. 迁移原数据

1
sudo rsync -aHAX --numeric-ids /var/lib/docker/ /mnt/docker-data/

4. 备份旧目录

1
2
sudo mv /var/lib/docker /var/lib/docker.bak
sudo mkdir -p /var/lib/docker

5. 卸载临时目录并挂载到正式目录

1
2
sudo umount /mnt/docker-data
sudo mount /dev/sdb1 /var/lib/docker

6. 写入 fstab

获取 UUID:

1
sudo blkid /dev/sdb1

写入:

1
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /var/lib/docker xfs defaults,nofail 0 0

7. 测试并启动 Docker

1
2
3
sudo mount -a
sudo systemctl start docker
sudo docker info | grep "Docker Root Dir"

确认:

1
Docker Root Dir: /var/lib/docker

8. 验证没有问题后删除备份

1
sudo rm -rf /var/lib/docker.bak

注意:

删除备份前一定要确认容器、镜像、数据卷都正常。
不要为了省几 GB,省出一个通宵事故。

二十三、挂载数据库数据盘案例

以 MySQL 为例,假设要把数据目录放到 /data/mysql

1. 创建挂载点

1
sudo mkdir -p /data

2. 挂载数据盘

1
sudo mount /dev/vg_data/lv_mysql /data

3. 创建 MySQL 数据目录

1
2
sudo mkdir -p /data/mysql
sudo chown -R mysql:mysql /data/mysql

4. 修改 MySQL 配置

1
2
3
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock

5. fstab 示例

1
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data xfs defaults,nofail,noatime 0 0

数据库目录建议:

项目 建议
独立磁盘 推荐
独立挂载点 推荐
使用 UUID 推荐
noatime 可以考虑
随便迁移 不推荐
没备份就操作 强烈不推荐

二十四、swap 分区和 swap 文件

除了普通数据盘,Linux 还可以配置 swap。

1. 创建 swap 分区

假设 /dev/sdb2 是 swap 分区:

1
2
sudo mkswap /dev/sdb2
sudo swapon /dev/sdb2

查看:

1
2
swapon --show
free -h

写入 /etc/fstab

1
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none swap defaults 0 0

2. 创建 swap 文件

1
2
3
4
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

写入 /etc/fstab

1
/swapfile none swap sw 0 0

查看:

1
2
free -h
swapon --show

注意:

swap 不是内存平替。
它是兜底,不是性能加速器。
真缺内存,最终还是要加内存或者优化程序。

二十五、常见故障排查

1. df 看不到新磁盘

原因:

df 只显示已挂载文件系统。

排查:

1
2
3
lsblk
blkid
findmnt

如果 lsblk 能看到新盘,但 df 看不到,说明还没挂载。

2. mount 报错 unknown filesystem type

示例:

1
mount: unknown filesystem type 'xfs'

可能原因:

  1. 系统缺少对应文件系统工具包
  2. 文件系统类型写错
  3. 分区还没格式化
  4. 分区损坏

排查:

1
2
blkid /dev/sdb1
file -s /dev/sdb1

安装工具:

1
2
3
4
5
# RHEL/CentOS
sudo yum install -y xfsprogs e2fsprogs

# Ubuntu/Debian
sudo apt install -y xfsprogs e2fsprogs

3. mount 报错 already mounted

查看挂载关系:

1
2
findmnt /data
findmnt /dev/sdb1

如果已经挂载,不要重复挂载。

4. umount 报错 target is busy

查看占用:

1
2
sudo lsof +f -- /data
sudo fuser -vm /data

常见原因:

  1. 当前 shell 在 /data 目录下
  2. 应用进程正在读写
  3. Docker 容器占用
  4. NFS 或其他服务占用

5. fstab 写错导致启动失败

解决思路:

  1. 进入救援模式
  2. 重新挂载根分区为读写
  3. 修改 /etc/fstab
  4. 注释错误挂载项
  5. 重启

所以修改后一定要测试:

1
2
sudo mount -a
findmnt --verify

6. 挂载到非空目录后文件“不见了”

比如 /data 里原来有文件:

1
/data/a.txt

然后你执行:

1
mount /dev/sdb1 /data

这时 /data/a.txt 看起来“不见了”。

其实不是删除了,而是被新挂载的文件系统遮住了。

卸载后又会出现:

1
2
umount /data
ls /data

所以挂载点最好使用空目录。

7. 删除分区后空间没变化

你可能只是删了分区表,文件系统和挂载关系还在内核中。
排查:

1
2
3
lsblk
findmnt
mount

必要时:

1
partprobe

或者重启。

8. LVM 扩容后 df 没变

可能你只扩了 LV,没有扩文件系统。

查看:

1
2
lvs
df -hT

如果 lvs 变大了,但 df 没变,说明文件系统还没扩。

XFS:

1
xfs_growfs /data

ext4:

1
resize2fs /dev/vg_data/lv_app

二十六、生产环境操作建议

1. 操作前先确认磁盘

至少执行:

1
2
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
sudo fdisk -l

确认:

  1. 哪块是系统盘
  2. 哪块是新盘
  3. 有没有文件系统
  4. 有没有挂载点
  5. 有没有业务数据

2. 危险命令前先停一下

危险命令包括:

1
2
3
4
5
6
7
8
9
10
mkfs
fdisk
parted mklabel
parted rm
pvcreate
wipefs
dd
lvremove
vgremove
pvremove

这些命令执行前都要确认:

1
2
3
4
lsblk
blkid
df -hT
findmnt

3. 生产环境优先使用 UUID

/etc/fstab 推荐:

1
UUID=xxxx /data xfs defaults,nofail 0 0

不推荐:

1
/dev/sdb1 /data xfs defaults 0 0

4. 修改 fstab 后必须测试

1
2
sudo mount -a
findmnt --verify

5. 数据盘建议独立挂载

常见目录:

目录 说明
/data 通用数据目录
/var/lib/docker Docker 数据目录
/var/lib/mysql MySQL 数据目录
/data/mysql 自定义 MySQL 数据目录
/data/postgresql PostgreSQL 数据目录
/data/redis Redis 持久化目录
/var/log 日志目录
/backup 备份目录

6. 数据库和日志尽量不要挤在根分区

根分区爆了,系统会出现很多奇怪问题:

  1. SSH 登录异常
  2. 日志写不进去
  3. 服务无法启动
  4. 数据库无法写入
  5. Docker 无法创建容器
  6. 包管理器无法安装软件

根分区爆满不是“小问题”,它是很多事故的“起手式”。

二十七、常用命令速查表

1. 查看类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
lsblk
lsblk -f
lsblk -o NAME,SIZE,TYPE,FSTYPE,LABEL,UUID,MOUNTPOINT

blkid
blkid /dev/sdb1

df -h
df -hT

findmnt
findmnt /data

fdisk -l
parted -l

pvs
vgs
lvs

2. 分区类

1
2
3
4
5
6
7
8
9
fdisk /dev/sdb

parted /dev/sdb print
parted -s /dev/sdb mklabel gpt
parted -a optimal -s /dev/sdb mkpart primary xfs 1MiB 100%
parted /dev/sdb resizepart 1 100%

partprobe /dev/sdb
partx -a /dev/sdb

3. 文件系统类

1
2
3
4
5
6
7
8
mkfs.xfs /dev/sdb1
mkfs.xfs -f /dev/sdb1

mkfs.ext4 /dev/sdb1
mkfs.ext4 -L data /dev/sdb1

xfs_info /data
tune2fs -l /dev/sdb1

4. 挂载类

1
2
3
4
5
6
7
8
9
10
11
12
mkdir -p /data
mount /dev/sdb1 /data
mount -t xfs /dev/sdb1 /data
mount -o ro /dev/sdb1 /data
mount -o remount,rw /data
mount --bind /src /target

umount /data
umount -l /data

mount -a
findmnt --verify

5. LVM 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pvcreate /dev/sdb1
pvs
pvdisplay

vgcreate vg_data /dev/sdb1
vgextend vg_data /dev/sdc1
vgs
vgdisplay

lvcreate -n lv_app -L 100G vg_data
lvcreate -n lv_app -l 100%FREE vg_data
lvextend -L +50G /dev/vg_data/lv_app
lvextend -l +100%FREE /dev/vg_data/lv_app
lvextend -r -L +50G /dev/vg_data/lv_app
lvs
lvdisplay

xfs_growfs /data
resize2fs /dev/vg_data/lv_app

pvresize /dev/sdb1

二十八、完整推荐流程

场景一:普通数据盘

1
2
3
4
5
6
7
8
9
10
lsblk
fdisk /dev/sdb
partprobe /dev/sdb
mkfs.xfs /dev/sdb1
mkdir -p /data
mount /dev/sdb1 /data
blkid /dev/sdb1
vim /etc/fstab
mount -a
df -hT

场景二:大磁盘或脚本化

1
2
3
4
5
6
7
8
9
10
11
lsblk
parted -s /dev/sdb mklabel gpt
parted -a optimal -s /dev/sdb mkpart primary xfs 1MiB 100%
partprobe /dev/sdb
mkfs.xfs /dev/sdb1
mkdir -p /data
mount /dev/sdb1 /data
blkid /dev/sdb1
vim /etc/fstab
mount -a
df -hT

场景三:LVM 数据盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
lsblk
parted -s /dev/sdb mklabel gpt
parted -a optimal -s /dev/sdb mkpart primary 1MiB 100%
partprobe /dev/sdb

pvcreate /dev/sdb1
vgcreate vg_data /dev/sdb1
lvcreate -n lv_app -l 100%FREE vg_data

mkfs.xfs /dev/vg_data/lv_app
mkdir -p /data
mount /dev/vg_data/lv_app /data

blkid /dev/vg_data/lv_app
vim /etc/fstab
mount -a
df -hT

场景四:LVM 新增磁盘扩容

1
2
3
4
5
6
7
8
9
10
11
12
lsblk

parted -s /dev/sdc mklabel gpt
parted -a optimal -s /dev/sdc mkpart primary 1MiB 100%
partprobe /dev/sdc

pvcreate /dev/sdc1
vgextend vg_data /dev/sdc1
lvextend -l +100%FREE /dev/vg_data/lv_app

xfs_growfs /data
df -hT /data

场景五:云盘原盘扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
lsblk

parted /dev/sdb
# print
# resizepart 1 100%
# quit

partprobe /dev/sdb

pvresize /dev/sdb1
lvextend -l +100%FREE /dev/vg_data/lv_app
xfs_growfs /data

df -hT /data

二十九、启示录

Linux 磁盘管理看起来命令很多,但真正核心的就两条线。

第一条是普通分区线:

1
磁盘 -> 分区 -> 文件系统 -> 挂载点 -> fstab

第二条是 LVM 线:

1
磁盘 -> 分区 -> PV -> VG -> LV -> 文件系统 -> 挂载点 -> fstab

如果只是临时挂一块小数据盘,fdisk + mkfs + mount + fstab 就够了。
如果是生产服务器,尤其是数据库、Docker、日志、备份目录,建议认真考虑 LVM,因为后续扩容会舒服很多。

最后记住几个原则:

  1. 操作前先 lsblk
  2. 格式化前先 blkid
  3. 挂载后用 df -hTfindmnt 验证
  4. 开机挂载用 UUID
  5. 改完 /etc/fstab 必须 mount -a
  6. XFS 可以在线扩容,但不能缩容
  7. LVM 扩容容易,缩容危险
  8. 生产环境动磁盘前必须备份

磁盘管理不是炫技,它是服务器稳定性的地基。
地基打好了,上层服务才不会一边跑业务,一边表演“根分区爆满行为艺术”。

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。


Linux 磁盘挂载、分区与 LVM 分卷实战
https://allendericdalexander.github.io/2026/06/08/devops/linux/linux_disk/
作者
AtLuoFu
发布于
2026年6月8日
许可协议