1. 动手之前的必修课:虚拟机里的“硬盘”到底是什么
如果你在公司里负责几台Linux虚拟机,早晚会遇到同一个场景:磁盘空间不够了,得给虚拟机加一块新硬盘。Windows桌面上装个新硬盘,插上SATA线、开机、磁盘管理里初始化一下就行;虚拟机里加硬盘则要过好几道关卡——先在虚拟化平台上加虚拟磁盘,再进系统里识别、分区、格式化、挂载。这套流程本身不难,但坑不少。
这篇文章里所有的操作,我都按最常见的环境来讲:宿主机用VMware Workstation或者KVM/QEMU,虚拟机内系统以CentOS/Rocky Linux和Ubuntu为主。整个思路是通用的,哪怕你用的是Proxmox VE、ESXi,或者Windows Server上的Hyper-V,原理也一致:虚拟化平台负责“造一块盘”,操作系统负责“认出它、格式化它、用起来”。
写这篇文章的初衷,是因为我见过太多人卡在中间环节:在管理界面加了磁盘,进系统后lsblk却看不到;看得到盘但mount报wrong fs type;或者重启之后挂载目录空空如也。这些问题单独看都不难,但凑在一起,特别容易让人怀疑是不是虚拟机平台坏了。所以这篇不只是给命令,我会把每一步为什么这么做讲清楚。
1.1 虚拟机里的“硬件”其实是一个文件
先说一个很多人忽略的事实:你在虚拟机管理界面里“添加硬盘”,本质上不是真的插了一块硬盘进去,而是创建了一个大文件(或者一个存储卷)。VMware里是.vmdk文件,KVM/QEMU里是.qcow2文件,Hyper-V里是.vhdx文件。虚拟机的磁盘控制器是软件模拟的(或者走半虚拟化驱动),它把对这个文件的读写请求包装成对“硬盘”的读写。
这个认知有多重要?它决定了三件事:
- 新加的虚拟硬盘,在虚拟机内部看起来就是一个块设备,和物理机里看到的
/dev/sdb、/dev/nvme0n1没有本质区别。 - 虚拟硬盘是“按需增长”还是“一次性占满空间”,取决于你创建它时选择的磁盘类型。厚置备(Thick Provision)会立刻占用宿主机空间,精简置备(Thin Provision)用多少占多少,但磁盘内部的文件系统必须在创建后自己格式化。
- 如果你做的是“直接使用物理硬盘”(比如把整个物理磁盘直通给虚拟机),操作流程完全一样,只是不经过虚拟化层的文件封装。
我见过有同事在虚拟机里加了一块20G的虚拟磁盘,格式化之后挂载上去,然后跑到宿主机上看,发现磁盘文件还是很小,以为加错了——实际上Thin Provision就是这样,文件系统刚建好时基本没数据,空间是“分期付”的。
1.2 设备命名:为什么有人看到sdb,有人看到vdb
虚拟机里的磁盘设备名,取决于你挂磁盘时选择的控制器类型。这块知识虽然不难,但搞错了容易导致后面操作时找错设备。
- SATA/SAS控制器(VMware默认对此类兼容性较好):在Linux里显示为
/dev/sdX,比如/dev/sda、/dev/sdb。 - IDE控制器(老虚拟机常见):同样显示为
/dev/sdX,但性能很受限制,新项目基本不选它。 - VirtIO(KVM/QEMU里最常见):设备名是
/dev/vdX,比如/dev/vda、/dev/vdb。VirtIO是半虚拟化设备,性能远好于纯模拟的SATA/IDE。 - NVMe(现代平台支持):设备名是
/dev/nvme0n1这样的格式,nvme0表示控制器编号,n1表示命名空间。
所以你在Linux虚拟机里新加磁盘后,先别急着格式化,第一件事是用命令看清设备名。
1.3 挂载不是格式化,两者千万别混
很多人把“挂载”和“格式化”混在一起,这是很容易出问题的开始。打个比方:格式化相当于在一块空地上打好地基、建好仓库;挂载相当于把你的货放进仓库,然后在大门上挂一个牌子“3号库”,以后所有往“3号库”这个地址送的货,都会被存进这个仓库里。
Linux的挂载就是:把你的文件系统挂到一个目录(挂载点)上,此后你读写这个目录,实际就是读写那块磁盘。用命令表达就是:
mount /dev/sdb1 /data这里的/data就是一个“3号库”的牌子,它本身不需要提前格式化,只需要目录存在。如果/data不存在,mount会报错,你得先mkdir。
搞清楚了这些基础概念,下面的操作部分才不容易跑偏。
2. 在虚拟机管理界面加硬盘:VMware和KVM完整操作
这个阶段最容易犯的错,不是点错按钮,而是磁盘模式选择了“独立持久化”或“独立非持久化”。如果你选了独立非持久化,那么虚拟机重启后对这块盘的所有写入都会丢掉,很多人挂载后重启发现数据没了,就是栽在这里。默认的“持久化”模式是普通使用的最佳选择。
2.1 VMware Workstation:从编辑设置到SCSI控制器
打开VMware Workstation(版本差异不大,以VMware Workstation Pro 17为例),选中目标虚拟机,执行以下步骤:
- 点击“编辑虚拟机设置”(Edit virtual machine settings)。
- 在“硬件”选项卡里,点击“添加”(Add),选择“硬盘”(Hard Disk),“下一步”。
- 磁盘类型选择,这步很关键:
- 如果你在虚拟机里看到的是
/dev/sda这种SATA设备名,新加的盘建议同样选SATA,避免设备名混杂。 - 如果你的虚拟机已经用了NVMe控制器,而且系统是Windows 10/ Server 2016之后的版本,可以直接选NVMe。
- “SCSI”通常用于Linux老设备或特定兼容场景,一般选默认即可。
- 如果你在虚拟机里看到的是
- 指定磁盘容量。这时候要注意**“立即分配所有磁盘空间”**这个选项。你想达到“宿主机不占多余空间”的效果,就不勾选“立即分配”;想要性能稳定、避免运行中报错“磁盘空间不足”,就勾选它。建议生产环境、物理机空间充裕时勾选“立即分配”,测试环境则不勾选。
- 关键一步:在“指定磁盘文件”名称之后,回到“硬件”列表,选中刚才添加的硬盘,展开下方的“高级”选项,虚拟设备节点(Virtual Device Node)选哪个控制器通道,通常默认即可,不用折腾。
- 点击“确定”,然后启动虚拟机,进入系统内操作。
如果你是想给ESXi里的虚拟机加磁盘,其实是两条路线:要么在vCenter的“编辑设置”里给虚拟机新增一块虚拟磁盘,要么在主机上先建一个数据存储(Datastore),再把存储映射给虚拟机用。这两条路线思路相通,但网上教程大多只讲Workstation,导致ESXi用户在/dev下怎么等都等不到新设备。ESXi加完磁盘后,虚拟机内需要执行echo "- - -" > /sys/class/scsi_host/host0/scan这类命令扫描新设备,这个我们后面章节单独讲。
2.2 KVM/QEMU:virt-manager添加流程与总线选择
KVM环境下最常用的是图形管理工具virt-manager,操作如下:
- 打开virt-manager,双击目标虚拟机,打开“详情”(Detail)视图。
- 左侧选择“添加硬件”(Add Hardware),右侧类型选“存储”(Storage)。
- 在“创建存储”(Create storage)里选择“文件(镜像文件)”或“块设备(物理磁盘/LVM卷)”。创建qcow2镜像时,需要注意选址:不要把镜像文件放在根分区,否则根分区满了虚拟机会直接卡死。应放在独立的存储池,比如
/var/lib/libvirt/images或其他数据盘。 - 分配大小,勾选“立即分配”等于厚置备,不勾选则是精简置备。
- 总线类型选“VirtIO磁盘”还是“SATA”/“IDE”,决定了系统内的显示名:
- VirtIO →
/dev/vdb - SATA →
/dev/sdb - IDE → 同样是
/dev/sdb但性能最差
- VirtIO →
- 完成添加,启动虚拟机。
需要注意,KVM里如果选VirtIO磁盘,但虚拟机内部没有安装virtio驱动(很老的Linux发行版会这样),系统会根本看不到这块盘,这是“加了盘但系统里找不到设备”的一种典型原因。
3. Linux虚拟机内部分区、格式化、挂载:一套命令走完
这部分我直接给你一套能照抄的命令序列,但每一条都会解释它到底在做什么,遇到异常时你才好排查。
3.1 先识盘:怎么确认新磁盘已经到系统了
进入虚拟机终端,第一步永远是这个:
lsblk fdisk -llsblk输出类似这样:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 40G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 39G 0 part / sdb 8:16 0 20G 0 disk看到sdb、vdb这种没有任何分区的新设备,MODE列显示disk而不是part,说明系统已经识别到这块盘,但没有被分区。如果你在虚拟机管理界面里加完盘,开机后lsblk里看不到,有几个常见原因:
- 需要重启虚拟机(热添加未配置好时,重启必定能认出来)。
- 控制器类型不匹配(如KVM里选了VirtIO但系统没有virtio驱动)。
- 虚拟机平台里磁盘处于“未连接”(Disconnected)状态,检查一下硬件列表里有没有勾选“连接”。
3.2 分区:fdisk还是parted,GPT还是MBR
现代环境优先选GPT分区表,因为MBR上限是2T,且对分区数量有限制。虚拟机磁盘如果大于2T,必须GPT。小于2T用GPT也没问题,无非是老工具不兼容。
使用fdisk对/dev/sdb分区,一个完整流程如下:
fdisk /dev/sdb交互界面里依次输入:
n (新建分区) p (主分区,如果默认类型是p就直接回车) 1 (分区号1,默认回车也可) 回车 (分区起始扇区用默认) 回车 (分区结束扇区用默认,就是把整块盘都用掉) w (写入分区表)然后执行:
partprobe /dev/sdb这个命令是让内核重新读取分区表。有些人分完区后lsblk看不到/dev/sdb1,就是漏了这一步,直接重启倒也行,但没必要。
如果你习惯用parted,对应命令是:
parted /dev/sdb mklabel gpt parted /dev/sdb mkpart primary 0% 100% parted /dev/sdb name 1 data # 给分区打个标签,方便识别我个人建议新环境直接parted走GPT,因为它同时负责磁盘标签和分区创建,一步到位,不容易犯“分区表类型选错”的错。
3.3 格式化:文件系统类型怎么选
分区创建好后,格式化这一步是分水岭。文件系统选错了,后面挂载融错率低,性能不明显,但对某些场景不兼容。
常用的几类:
- ext4:最稳的选择,绝大多数Linux默认都支持,不需要额外工具,适合大部分业务数据盘。
- xfs:CentOS/RHEL 7及以后版本的默认文件系统,适合大文件、高吞吐,但不能缩减大小。
- btrfs:功能强(快照、压缩、子卷),但生产环境折腾成本高,个人不建议在虚拟机的普通数据盘上冒险。
- ntfs/fat:如果这块盘以后要拔下来插到Windows上读取,才需要这些,虚拟机里一般不搞这种跨界盘。
我的建议:没有特殊需求,就在ext4或xfs里选。Ubuntu和Debian用户默认ext4即可;CentOS/Rocky用户习惯xfs也没错。
格式化命令:
mkfs.ext4 /dev/sdb1如果你选了xfs:
mkfs.xfs /dev/sdb1格式化的时候可以顺手给卷标,方便识别盘的身份:
mkfs.ext4 -L data /dev/sdb13.4 手动挂载与测试读写
创建一个挂载目录,然后挂载:
mkdir -p /data mount /dev/sdb1 /data验证一下:
df -h /data终端输出显示/dev/sdb1 20G挂在/data下就成功了。接着写入测试文件,确认读写正常:
dd if=/dev/zero of=/data/test.bin bs=1M count=1024 oflag=directoflag=direct强制绕过缓存直接写盘,避免数据先写在内存里给你造成“成功了”的错觉。命令跑完后查看/data/test.bin的大小是否为1G左右,然后删掉它。
这里还有一个细节:如果挂载时报错mount: /data: wrong fs type, bad option, bad superblock on /dev/sdb1,通常有三种情况:
/dev/sdb1其实还没格式化。- 文件系统类型跟挂载时指定/自动匹配的不一致,比如实际是xfs但系统稀里糊涂当ext4挂载。
- 分区文件系统损坏(常见于强行关机后)。
排查时先用blkid /dev/sdb1看文件系统类型对不对,再用fsck检查。
4. 开机自动挂载:UUID和fstab的正确用法
手动挂载有个明显的缺点:虚拟机一重启,挂载关系就丢了。要想每次开机都自动把新盘挂在指定目录,就要在/etc/fstab里写一条记录。
4.1 为什么推荐UUID而不是设备名
/dev/sdb1这种设备名看着直观,但它是根据检测顺序分配的名字。虚拟机一旦新增或移除磁盘、或者调整了SCSI通道,设备名会改,比如原来的/dev/sdb1可能变成/dev/sdc1,然后你的fstab就失效了,系统还可能因此直接卡在开机挂载失败的错误里。
而UUID是文件系统格式化时生成的唯一标识,只要不重新格式化,它就不会变。无论设备在系统里叫什么名字,fstab里写UUID永远能找到正确的分区。获取UUID的方式:
blkid输出里能看到类似/dev/sdb1: UUID="a1b2c3d4-..." TYPE="ext4"的信息,把UUID复制出来。
4.2 fstab的六个字段,逐行拆解
/etc/fstab每行格式如下:
<设备> <挂载点> <文件系统类型> <挂载选项> <dump> <fsck>对应我们的场景,写这样一行:
UUID=a1b2c3d4-... /data ext4 defaults 0 2字段含义:
- UUID=...:锁死设备身份。
- /data:挂载点,必须事先存在。
- ext4:文件系统类型。
- defaults:常用挂载选项。想启用读写权限就写
rw,想禁止执行文件就加noexec,需要每天自动清理垃圾可以加noatime。生产数据盘我一般写defaults,noatime。 - 0:dump备份标记,现在基本用不上。
- 2:fsck检查顺序。根分区一般写1,其他数据分区写2,不检查写0。
有一个反直觉的坑我得单独提醒:挂载点目录不要建在根分区根目录下面一个没有权限的路径里,更不要挂在像/home、/var这类已经被其他分区占用的路径上。如果/home已经是一个独立分区,你又把新盘挂到/home上,原来的数据会被“遮住”——不是删了,而是在这个挂载点下看不见了。等你卸载新盘,原数据又回来了。初学者容易在这里被吓到。
改完/etc/fstab,一定要执行一次:
mount -a这条命令会按fstab里的配置重新挂载所有未挂载的项。如果语法有错,它会当场报错,而不是等你重启后才出问题。看到没有任何输出,或者只是提示“已挂载”,就说明配置没问题。
重启前强烈建议再验证一次:
findmnt --verify --verbose这个命令会模拟检查fstab的正确性,输出没有异常再重启。我在这一步救过不少次级事故。
4.3 更现代的systemd挂载单元
RHEL/CentOS 7+、Ubuntu 16.04+这些系统上,systemd会读取/etc/fstab并自动生成对应的挂载单元,所以你其实不需要手写.mount文件。凡是fstab里的配置,systemd都会接管。
但如果你追求更清晰的管理方式(比如让挂载关系和某个服务绑定),可以手写挂载单元。假设挂载点是/data,对应的unit文件是/etc/systemd/system/data.mount:
[Unit] Description=Mount data disk After=local-fs.target [Mount] What=UUID=a1b2c3d4-... Where=/data Type=ext4 Options=defaults,noatime [Install] WantedBy=multi-user.target然后启用:
systemctl daemon-reload systemctl enable --now data.mount这种方式的好处是:如果挂载失败,你可以直接看systemctl status data.mount的错误信息,比fstab报错好诊断得多。不过绝大多数场景,fstab已经够用,不必引入额外的维护成本。
5. 不想重启虚拟机?热插拔识别新磁盘的完整链路
生产环境最忌讳无计划重启,所以我得单独开一节讲“不重启怎么认出新磁盘”。这里的完整链路分成两步:宿主机层面确认磁盘已经“接入”;虚拟机内部触发SCSI设备重扫。
如果你用的是VMware Workstation,在“编辑虚拟机设置”里加完磁盘,大多数情况下Linux虚拟机立刻就能在lsblk里看到新设备,因为VMware tools会主动通知客户机重新扫描。如果没看到,试试:
echo "- - -" > /sys/class/scsi_host/host0/scan echo "- - -" > /sys/class/scsi_host/host1/scan echo "- - -" > /sys/class/scsi_host/host2/scan这个命令是让每个SCSI主机控制器扫描一遍自己通道上未识别的设备。- - -分别是host、channel、target的占位符,全写减号就是“无论哪个通道都扫一遍”。执行后运行lsblk,大概率能看到新盘。
如果还是在看不到,换一条更暴力的方法:
for host in /sys/class/scsi_host/host*; do echo "- - -" > $host/scan; done这条命令自动遍历所有SCSI主机控制器,效果一样,只是省得手动敲好几遍。
热添加场景下,分区操作跟前面完全一样,但需要注意fstab的UUID获取时机。如果是热插拔,设备名可能不是刚才lsblk显示的那个(因为内核扫描顺序有延迟),所以更要坚定不移地用UUID写fstab,别想当然拿/dev/vdb1写进去。
5.1 在线扩容的一个额外小技巧
如果新添加的磁盘容量比你预先规划的大,而且你不想重新分区,可以只用parted调整分区边界,然后扩展文件系统。但虚拟机内如果加了盘,最安全的做法是“加一块新盘,而不是改原盘”,因为改原盘大小需要关闭分区使用或很小心地操作。这里甩出一个经验结论:单一数据盘不够用了,再加一块新盘挂到新目录/替换扩容,永远比在原盘上蹩脚地用LVM或growpart省心和安全。
如果你已经把根分区用LVM管理起来(CentOS/RHEL默认就是),扩容流程反而是加新盘最容易的路线。先把新盘分区、格式化后加入PV/VG/LV,然后扩展文件系统。不过LVM这块内容量太大,如果读者感兴趣,我后面可以单独再写一篇,本文先聚焦挂载操作本身。
6. 五类高频故障排查:从wrong fs type到设备消失
挂载出错不奇怪,每个人都会遇到。下面是我在实操中遇到最多、且网上说法又比较零散的五类问题,按发生频率排序,附排查链路。
6.1 mount时报wrong fs type, bad option
报错全貌类似:
mount: /data: wrong fs type, bad option, bad superblock on /dev/sdb1, missing codepage or helper program, or other error.这个报错看起来吓人,实际最常见的原因就是“分区没格式化”。你新加的盘从头到尾就没跑过mkfs,内核读写时找不到文件系统的超级块,自然报错。排查顺序:
blkid /dev/sdb1看有没有TYPE字段。如果有TYPE=ext4这类信息,说明是挂载命令或选项的问题;如果没有TYPE,基本确认没格式化,跑一遍mkfs.ext4 -f /dev/sdb1解决。- 如果TYPE是
xfs而系统是老内核/老发行版,可能内核里缺xfs驱动,那就modprobe xfs加载,或者在系统安装阶段确认要包含xfs支持。 - 如果之前格式化过,但中途崩溃过,可以
fsck.ext4 -y /dev/sdb1修复超级块。
6.2 重启后挂载目录是空的
这种情况基本可以断定是fstab没写对,或设备名变了。排查链路:
blkid看UUID是否跟fstab里一致。cat /etc/fstab,检查字段数量是不是6个,类型跟实际文件系统是否匹配。df -h确认是不是压根没挂载。如果根本没挂载,但fstab写了,看systemctl status里对应挂载单元的错误。- 如果系统启动时报错卡住,进入紧急模式(emergency mode)时执行
mount -a看具体报错信息。
注意:在紧急模式下修复fstab时,千万别直接删行完事,要先用
mount -a确认原因,再决定是改UUID还是改挂载点。
6.3 磁盘已存在但lsblk看不到
这是我在KVM和ESXi里都遇到过的问题。磁盘在管理界面已经添加,但客户机看不到。常见原因和对应解法:
| 可能原因 | 排查手段 | 解法 |
|---|---|---|
| SCSI控制器没触发重扫 | lsscsi看有没有设备 | 执行echo "- - -" > /sys/class/scsi_host/hostX/scan |
| VirtIO驱动缺失 | `lsmod | grep virtio` |
| 磁盘处于未连接状态 | 查看虚机硬件列表,确认磁盘勾选“连接” | 勾选后保存,重启虚拟机 |
| 平台是ESXi,且磁盘没有映射到虚拟机的控制器 | vCenter里看“添加新设备”是否正确选择“现有硬盘” | 重新编辑虚拟机配置,确认磁盘类型为“新标准硬盘”或“RDM” |
6.4 卸载时报target is busy
常见于你挂载了目录,但进程里还有文件正被占用:
umount /data # umount: /data: target is busy.解法是用fuser和lsof找到占用进程:
fuser -mv /data lsof +D /data然后根据业务情况杀掉相关进程,再卸载。生产环境千万别无脑fuser -km /data,会误杀数据库进程,造成数据损坏风险。正常情况下,提前通知业务停应用,再安全卸载。
还有一种target is busy是因为你在挂载目录内(比如当前工作目录就在/data里),shell占住了它。cd回到/再umount即可解决。
6.5 新加磁盘后虚拟机直接无法启动
这个比较冷门但很致命:虚拟机开着时在管理界面直接删除了磁盘文件,或者对磁盘做了“移除”操作,但系统里的分区表和fstab还认识它,启动时因找不到设备而进入紧急模式。这种情况下不要慌,进紧急模式,注释掉/etc/fstab里对应的那行,然后重启。等系统恢复后,再考虑是否需要把新盘加回来并重新配置挂载。
7. 挂载后的日常工作:卸载、扩展与习惯养成
挂载不是一次性动作,它涉及到长期的系统维护。这里分享一些我在实际运维中养成的习惯,以及卸载数据盘的正确姿势。
7.1 安全卸载的完整过程
当你需要把这块盘摘掉(比如迁移到别的虚拟机),正确顺序是:
- 停止写入该目录的所有业务进程。
- 执行
sync,把内存里的脏数据刷到磁盘。 umount /data卸载。rm掉/etc/fstab里的对应行,防止重启后找不到设备卡住。- 在虚拟化管理界面把磁盘从虚拟机分离或删除。
特别提醒:umount之前别依赖“看起来没有进程”就动手,生产环境务必先在业务层面确认没有活动事务。如果是数据库的数据盘,直接umount可能把数据文件搞坏,这种场景最好走数据库自身的备份/停机流程。
7.2 给后来人的几条习惯建议
- 每次操作完都要验证:加盘后先
lsblk再看df -h,写fstab后mount -a+findmnt --verify,这套验证成本只要几秒钟,但能避免很多经典事故。 - 数据盘目录单独规划:建议把业务数据放在
/data这类统一目录下,别把数据盘挂到/root、/tmp下面,否则权限和清理策略会让你很痛苦。 - 及时记录盘的身份:在物理机上给硬盘贴标签很常见,虚拟机里也可以做:格式化时加
-L卷标,或者把计划写在/etc/fstab注释里。半年后你再回去看这个系统,会感谢自己当时写了这几行注释。 - 监控磁盘空间:加盘解决的是空间不足问题,但如果业务增长快,应该考虑周期性监控分区使用率,在到达阈值前提前扩容或添加新盘,而不是每次等“满了再救火”。
提示:如果虚拟机用的是精简置备磁盘,可以在宿主机上看到磁盘文件实际占用远小于标称容量,但大量删除文件后,宿主机的空间不会自动回收,需要执行fstrim(Linux)或Defragment and Compact(VMware)来释放空间,这是另一类常见坑。
我个人在给虚拟机加盘这件事上,最大的体会是:步骤简单,但每个环节都有关键参数。你只要记住四个关键词——“设备名、UUID、挂载点、fstab”,这套操作就串起来了。先在测试虚拟机里练几遍,再上生产,基本上不会再出问题。