ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

virt-manager虚拟机文件共享全攻略:virtiofs、9p与SMB/NFS详解

2026/9/13 15:39:32 拓冰建站 浏览量
virt-manager虚拟机文件共享全攻略:virtiofs、9p与SMB/NFS详解 如果你是从 VirtualBox 跳到 virt-manager 这边的第一件事八成是去虚拟机设置的某个标签页里找“共享文件夹”按钮。我当年也一样把图形界面翻了个遍也没找到那个熟悉的选项。这不是 virt-manager 故意藏功能而是它和 VirtualBox 的设计思路根本不一样——virt-manager 是 libvirt 的图形前端它管理的不是某个“共享文件夹”概念而是把目录当作一类硬件设备filesystem device挂给虚拟机。所以“宿主与虚拟机之间共享文件”这件事在 virt-manager 里确实能做只是入口和方式跟你想的不太一样。这篇文章就围绕在 virt-manager 环境里设置宿主机和虚拟机文件共享来写。适合这些情况Linux 开发机上跑了一台 Linux 虚拟机想把代码目录直接丢进 VM 里编译执行Windows 虚拟机需要定期从宿主机拿文件或者你已经尝试折腾过共享但总是报权限错误、找不到设备。下面我会把 virtiofs、9p、SMB/NFS、虚拟磁盘这几条主要路径全部过一遍讲清楚各自的适用场景和坑最后附上我踩坑之后沉淀下来的排查思路。1. 先承认一个事实virt-manager 没有“共享文件夹”按钮1.1 为什么图形界面里找不到很多人第一次用 virt-manager第一反应是去“硬件详情”里找类似 VirtualBox 的“共享文件夹”选项结果找不到。这不是 virt-manager 的缺陷而是底层模型的差异。VirtualBox 把“共享文件夹”作为产品功能单独封装了用户点个按钮就能配置。但 virt-manager 直接暴露的是 QEMU/KVM 的硬件抽象文件的共享被你理解成了“给虚拟机加一个设备”这个设备就是 libvirt 里的filesystem设备。所以在 virt-manager 里共享目录的正确说法是往虚拟机里添加一个filesystem类型的设备设备里指定宿主机目录和挂载标签然后虚拟机内部去挂载这个标签。整个流程更像“加了一块虚拟硬盘”而不是“设置一个共享路径”。另外要注意filesystem设备在 virt-manager 里的入口藏得比较深而且不同版本显示位置不一样。我在 Fedora、Ubuntu 不同版本上试过有的版本“添加硬件”面板里能直接看到 Filesystem 选项有的版本死活不显示。遇到这种情况不需要怀疑自己直接往下看用 XML 方式处理效果一样。1.2 梳理一下可用的四条主要路径文件共享不是只有一种实现方式我习惯把它们分成几类这样选型的时候不会乱共享方式运行平台性能上手难度典型场景virtiofs宿主机和 guest 内核较新接近本地盘中等Linux guest 日常代码目录、编译目录virtio-9p老内核也能用一般中等旧系统、临时共享SMB / NFS跨 Windows / Linux受网络和协议影响低Windows guest、异构终端SSH / HTTP 等轻共享所有看网络很低偶尔拷一个小文件虚拟数据盘所有最好中大文件一次性导入、数据库迁移我第一次配置共享时就吃了“只认一种方案”的亏非要在老内核的 guest 上搞 virtiofs折腾一天没结果。后来想通了这类需求本来就该根据 guest 和宿主机的系统环境、数据量、性能要求来选。后续的章节就是围绕这几种方式逐个展开。2. 首选实践用 virtiofs 挂载宿主机目录2.1 动手前确认三项版本条件virtiofs 是这几条共享路径里我个人最推荐的一种性能接近本地磁盘guest 里跑编译、跑 Node、跑数据库都比 9p 靠谱。但它的前提条件是版本不能太老。我在配置之前一般会按顺序确认三件事。# 1. 确认 libvirt、QEMU、virt-manager 版本 virsh version qemu-system-x86_64 --version virt-manager --version # 2. 确认 virtiofsd 是否存在 ls -l /usr/libexec/virtiofsd /usr/lib/kvm/virtiofsd 2/dev/null # 3. 确认 guest 和宿主机内核是否支持 virtiofs # 在 guest 里执行 grep virtiofs /proc/filesystems版本方面的建议是QEMU 5.0 以上、libvirt 6.0 以上、virt-manager 2.2 以上guest 内核建议 5.4 以上。如果virsh version看到的版本比较旧先升级再继续不然后面很容易遇到莫名其妙的问题。如果第二步里两个路径都没有输出说明系统里没装virtiofsd包。Fedora/RHEL 系列安装命令是sudo dnf install virtiofsdUbuntu/Debian 系列是sudo apt install virtiofsd装完之后再找一下二进制路径不同发行版路径有差异后面配置 XML 时有可能会用到对这个路径的判断。2.2 图形界面添加 Filesystem 设备确认版本没问题就可以在 virt-manager 里添加设备。我建议先彻底关机再配置因为 virtiofs 不支持热插拔虚拟机运行状态下改了配置不会生效。操作路径是这样在 virt-manager 里双击虚拟机打开详情窗口。点击左上角的“显示虚拟硬件详细信息”图标一般是i形状的按钮。窗口左下角找到“添加硬件”按钮点击后选择Filesystem。驱动类型选择virtiofs。源路径填宿主机要共享的目录比如/home/user/share。目标路径填挂载标签我习惯起一个简短的名字比如shared注意这里填的不是 guest 里的真实路径而是一个 tag。点击“完成”然后启动虚拟机。如果你在“添加硬件”列表里找不到Filesystem选项别急着怀疑人生。有的 virt-manager 发行版打包时没把 Filesystem 设备的入口放出来或者版本比较老这种情况下直接走下面的 XML 方案效果完全一样。2.3 图形界面没有入口时直接改 XML我实际使用中大部分情况反而是直接在 XML 里加配置因为这样能精确控制参数不受 virt-manager 版本限制。操作步骤确保虚拟机处于关机状态。在 virt-manager 中右键虚拟机 → “编辑” → “虚拟机的 XML 配置”不同版本叫法略有差异。找到devices段在disk设备附近追加一个filesystem节点。配置内容如下filesystem typemount accessmodepassthrough driver typevirtiofs/ source dir/home/user/share/ target dirshared/ /filesystem这里重点解释两个字段。source.dir就是宿主机上要共享出来的真实目录路径。target.dir则是给 guest 用的挂载标签它不是一个路径只是一个标识。guest 里执行挂载时要拿这个标签去挂下面马上会说。把这段 XML 保存后启动虚拟机就可以在 guest 里挂载了。我遇到过有人把target dir当成 guest 里的挂载点来填比如填/mnt/share然后 guest 里怎么挂都挂不上。这个字段是标签不是路径习惯上写短一点比较稳。2.4 guest 端的挂载与开机自动挂载进入 guest 系统创建一个挂载点然后挂载sudo mkdir -p /mnt/share sudo mount -t virtiofs shared /mnt/share执行完用df -h应该能看到 virtiofs 类型的挂载记录。如果提示unknown filesystem type virtiofs说明 guest 内核太老或模块没加载具体排查放到第 6 章讲。如果希望开机自动挂载编辑 guest 的/etc/fstab加一行shared /mnt/share virtiofs defaults,noatime 0 0这里的第一列shared必须和 XML 里的target dir完全一致不能写错。我在配置自动挂载时还踩过一个小坑有的发行版virtiofs挂载需要systemd版本不能太老如果 fstab 开机挂载失败先手动执行一次mount -a看报错再查系统日志不要一上来就怀疑 fstab 语法。2.5 为什么我把 virtiofs 放在首选virtiofs 相比 9p 最大的优势是性能和语义。它使用 FUSE 协议但做了大量优化guest 里的进程可以直接共享宿主机 page cache做代码编译、大规模小文件读写时体验接近本地盘。更重要的是virtiofs 支持mmap这意味着很多需要内存映射的程序不会出问题。9p 对 mmap 的支持一直有缺陷跑 Node、跑数据库可能会直接报错或性能骤降。如果条件允许我强烈建议直接上 virtiofs。版本不够就升级升级能解决 80% 的兼容问题。3. 旧内核环境的兜底方案virtio-9p 共享目录3.1 virtio-9p 和 virtiofs 的差别虽然 virtiofs 好用但总有一些环境升不了级。我手头有台老服务器的宿主机内核停在 4.xguest 里跑的还是 CentOS 7这种组合根本没法用 virtiofs。这时候 virtio-9p 就是最适合的兜底方案。9p 协议非常老从 Linux 2.6.30 开始就进内核了兼容性是它最大的优点。只要不是特别冷门的系统基本都能用。它的缺点也明显性能比 virtiofs 差不少大量小文件场景尤其明显而且对 mmap 支持不好。所以它更适合临时共享、轻量传输不适合在共享目录里跑数据库或者重型应用。3.2 XML 配置和 guest 挂载9p 的 XML 配置和 virtiofs 很像区别在于不写driver typevirtiofs/不加这行时 libvirt 默认走 9p。filesystem typemount accessmodemapped source dir/home/user/share/ target dirshared9p/ /filesystem这里有一个关键参数accessmode我实际测试过三种模式差别很大passthroughguest 里的 uid/gid 直接对应宿主机的 uid/gid。好处是权限语义清晰坏处是 guest 里 root 不一定能访问宿主机上权限受限的目录而且 qemu 进程本身权限不足时容易报错。mappedguest 里的 root 会被映射成宿主机的普通用户权限管理更安全适合大多数场景。squash所有 guest 用户都映射成同一个宿主机用户适合只读共享或者临时传文件。我自己最常用的是mapped安全性和易用性平衡得比较好。配置保存后启动虚拟机guest 里先加载内核模块再挂载sudo modprobe 9p sudo modprobe 9pnet_virtio sudo mount -t 9p -o transvirtio,version9p2000.L shared9p /mnt/share如果不想每次开机手动modprobe可以在 guest 的/etc/modules-load.d/9p.conf里写两行9p 9pnet_virtio自动挂载对应的 fstab 写法是shared9p /mnt/share 9p transvirtio,version9p2000.L 0 03.3 什么情况下别用 9p9p 能用的场景很多但有两个雷区我建议避开。第一不要在 9p 共享目录里跑数据库或者大量调用 mmap 的程序。数据库的写入模式对文件系统语义要求很高9p 在某些情况下会有兼容性问题表现可能是启动报错也可能是数据文件损坏风险很大。第二不要在同一台虚拟机上挂太多 9p 目录。每一个 filesystem 设备都会对应 QEMU 启动参数挂载点越多启动越慢出问题的概率也越大。如果确实有多个目录要共享优先考虑把父目录共享出去guest 里自己访问子目录。4. Windows guest 和跨系统终端SMB / NFS 共享4.1 宿主机开 Samba 给 Windows guest 用如果你的虚拟机装的是 Windows前面说的 virtiofs 基本不太适用——Windows 对 virtiofs 的支持现在还不成熟需要额外装驱动体验一般。最省心的路径就是宿主机开 Samba 服务Windows guest 通过网络邻居访问。先在宿主机安装 Samba。Fedora/RHELsudo dnf install samba samba-clientUbuntu/Debiansudo apt install samba然后编辑/etc/samba/smb.conf在文件末尾加一个共享段[share] path /home/user/win-share browseable yes read only no guest ok no valid users sambauser这里建议创建一个独立用户专门给 Samba 用不要直接拿系统 root 做认证sudo useradd sambauser sudo smbpasswd -a sambauser sudo systemctl enable --now smbWindows guest 在资源管理器地址栏输入\\192.168.122.1\share就能访问。为什么是192.168.122.1因为默认 NAT 网络下宿主机在虚拟网络里就是网关地址也就是 virbr0 的 IP。如果你的网络改了可以先在 guest 里查默认网关用网关地址访问宿主机。4.2 Linux guest 挂宿主机 NFSLinux guest 之间共享文件我个人更推荐 NFS配置比 Samba 简单性能也更好一些。宿主机上安装 NFS 服务端sudo dnf install nfs-utils编辑/etc/exports/home/user/share 192.168.122.0/24(rw,sync,no_root_squash,no_subtree_check)保存后执行sudo exportfs -ra sudo systemctl enable --now nfs-serverguest 里挂载sudo mount -t nfs 192.168.122.1:/home/user/share /mnt/share注意 NFS 导出目录如果被 SELinux 拦截需要开启对应的布尔值这个在第 6 章一起讲。4.3 临时传文件SFTP 和 HTTP 这种“轻共享”有些场景真的只是“把宿主机上一个安装包丢进虚拟机”没必要专门配置共享服务。我常用的两个轻量办法如果 guest 是 Linux且运行了 SSH 服务宿主机直接scp ./somefile.tar.gz userguest-ip:/tmp/guest 的 IP 可以通过ip addr查看NAT 网络下通常是192.168.122.x。如果 guest 是 Windows最简单的方式反而不是开额外服务而是宿主机上起一个临时 HTTP 文件服务cd /path/to/files python3 -m http.server 8000然后 Windows guest 的浏览器访问http://192.168.122.1:8000可以直接下载文件。这个办法零配置、用完就关适合临时传一两个文件没必要为了一个安装包专门搭 Samba。5. 大文件交换的进阶姿势虚拟磁盘 libguestfs5.1 为什么大文件不走共享文件共享不是万能的。遇到几十 GB 的数据库备份、几万个文件的静态资源包时virtiofs 和 9p 的表现不一定好SMB/NFS 还要受到网络协议损耗的影响。如果数据量特别大或者要反复拷贝多次我通常会放弃“共享目录”这个思路改用虚拟数据盘。虚拟数据盘的本质是给虚拟机加一块独立的虚拟硬盘数据传输时不再经过共享协议而是直接读写块设备性能最接近物理磁盘。而且它适合一个非常常见的场景把宿主机上已有的大数据文件“一次性”搬进虚拟机或者反过来把虚拟机里的数据“完整”导出来。5.2 创建数据盘并挂给虚拟机先创建虚拟硬盘镜像qemu-img create -f qcow2 /var/lib/libvirt/images/data.qcow2 50G然后在 virt-manager 里给虚拟机添加硬件 → Storage选择这块盘总线建议选 VirtIO。启动虚拟机guest 里对这块盘做格式化并挂载sudo mkfs.ext4 /dev/vdb sudo mkdir /mnt/data sudo mount /dev/vdb /mnt/data之后要把宿主机上的文件传进这个数据盘最直接的方法启动 guest 后通过 scp、Samba、HTTP 等方式传进去好处是传输目标是一个独立的块设备不受共享目录协议的限制。如果这一步传输量大建议用千兆或更快的虚拟网络KVM 默认的 virtio-net 性能足够。5.3 不启动虚拟机也能往里塞文件有时候你不想启动虚拟机比如虚拟机是迁移过过来的因为某些原因起不来但你只是想从里面把几个数据文件拷出来。这时候 libguestfs 工具非常有用。先在宿主机安装sudo dnf install libguestfs-tools然后可以通过virt-copy-in和virt-copy-out直接操作 qcow2 镜像里的文件不需要启动虚拟机# 把宿主机当前目录的 backup 文件夹复制进镜像的 /mnt/data 目录 sudo virt-copy-in -a /var/lib/libvirt/images/data.qcow2 ./backup /mnt/data/ # 把镜像里的 /var/log 导出到当前目录 sudo virt-copy-out -a /var/lib/libvirt/images/data.qcow2 /var/log ./这个方法要求虚拟机处于关机状态不能在运行中操作否则会破坏镜像文件系统这是最重要的注意事项。另外如果是加密的虚拟机或者镜像里的文件系统比较特殊virt-copy-in可能无法识别那种时候还是得启动虚拟机用常规方式传。6. 实战中容易卡住的坑与排查链路6.1 挂载报 unknown filesystem type virtiofs这个报错最直接的原因是 guest 内核不认识 virtiofs。可能 guest 内核版本太老也可能内核模块没加载。排查顺序grep virtiofs /proc/filesystems没有任何输出就说明内核不支持。先尝试sudo modprobe virtiofs如果 modprobe 报错说明内核模块不存在那就只能升级 guest 内核或者切换回 9p 方案。我遇到过一些精简版系统镜像内核根本没带 virtiofs 模块这种时候纠结 virtiofs 没有意义直接用 9p 反而省时间。6.2 Permission denied 与 virtiofsd 启动失败配置好 virtiofs 后进入 guest 挂载时发现权限不足或者宿主机日志里 virtiofsd 直接启动失败这是比较常见的问题。排查方向有两个。第一看共享目录本身的权限。virtiofsd 进程在宿主机上是以特定用户身份运行的不同发行版配置不一样如果共享目录该用户完全没有访问权限guest 里自然访问不了。先看宿主机目录权限ls -ld /home/user/share id qemu 2/dev/null || id libvirt-qemu 2/dev/null如果目录权限明显不够调整 owner 或组权限但没必要粗暴chmod -R 777把目录设置成对运行 virtiofsd 的用户可读可执行就够了。第二看 SELinux 和 AppArmor 是否拦截。日志在宿主机里查journalctl -xeu libvirtd | tail -50 journalctl -k | grep -i virtiofsd如果确实有 SELinux 拦截的记录给共享目录打svirt_image_t标签sudo chcon -R -t svirt_image_t /home/user/share需要永久生效的话再加一条 fcontext 规则sudo semanage fcontext -a -t svirt_image_t /home/user/share(/.*)? sudo restorecon -Rv /home/user/shareUbuntu 等使用 AppArmor 的系统拦截日志在/var/log/syslog里搜apparmor就能看到。解决方法是在 AppArmor 的 libvirt profile 里放行共享目录编辑/etc/apparmor.d/local/usr.sbin.libvirtd添加/home/user/share r, /home/user/share/** rw,然后重载 AppArmorsudo systemctl reload apparmor6.3 SELinux 对 SMB / NFS 的额外限制如果你在宿主机上开了 Samba 或 NFS 导出共享目录给虚拟机用SELinux 可能不让你导。Samba 的常见处理sudo setsebool -P samba_export_all_rw 1NFS 的对应参数是sudo setsebool -P nfs_export_all_rw 1设置完再exportfs -ra重新导出。还有一个容易被忽略的点如果你是在宿主机上跑 libvirt 虚拟机同时又希望通过 NFS/Samba 让虚拟机访问宿主机目录排查链路会和普通共享不同。遇到权限问题时优先看 SELinux 审计日志而不是在那里瞎猜。6.4 改动配置后必须彻底关机重启virtiofs 和 9p 设备都不支持热插拔这一点我在前面反复强调因为真的很容易踩。在 virt-manager 里点了“重启”有时候不是真正的关机再启动而是 guest 内部重启QEMU 命令行不会重新加载新设备。所以每次修改完 filesystem 类型的配置都要确保虚拟机先执行关机shutdown确认状态变成“关闭”再启动。如果改完 XML 启动后设备不生效回 virt-manager 查看虚拟硬件详情看 Filesystem 设备是不是已经出现在列表里。如果设备在但 guest 挂载失败检查 XML 里target dir和 guest 挂载时用的标签是否一致。这两个不一致的坑我见过太多次了。6.5 只读和权限问题的快速定位共享目录在 guest 里总是只读这个问题我最后单独说。排查链路一般是这样先看 guest 挂载时是不是指定了只读选项fstab 里有没有误写ro。然后回到宿主机看共享目录的宿主机侧权限用共享进程的身份去测试sudo -u qemu ls /home/user/share如果这条命令都看不到内容问题就在宿主机权限guest 里怎么调都是白搭。如果mapped模式下 guest root 写入失败往往是宿主共享目录本身对 mapped 后的用户没有写权限。把目录属主调整好问题立刻消失。最后再分享一个实际操作中的经验。我现在自己的主力开发机里跑两台 Linux 虚拟机日常代码共享直接用 virtiofs挂载/home/user/code到 guest 的/mnt/code编译速度几乎感觉不到是远程文件系统。Windows 虚拟机只有偶尔跑 Windows 软件才开里面文件交换就用宿主机 Samba设置一次后基本不用再动。大文件临时导入不折腾共享服务直接创建一块虚拟数据盘传完就完事。这几条路组合下来几年没为“宿主机和虚拟机之间传文件”这件事烦过。如果你正卡在共享配置上希望这篇文章能帮你少走点弯路。