返回星港

虚拟机共享宿主机文件夹,仅限Linux

OBSERVER又菜又爱玩的小朱 LAUNCH RESYNC JUMPS456 次跃迁
星域 NAS 信标 # NAS# 虚拟化
虚拟机共享宿主机文件夹,仅限Linux · 封面
# 概述 本教程介绍如何在 FnOS(飞牛NAS)上使用 [**virtio-9p**(Plan 9)协议](https://www.kernel.org/doc/html/latest/filesystems/9p.html)将宿主机目录共享到 KVM 虚拟机中。9p 是一种轻量级的文件共享协议,无需网络配置,通过 virtio 总线直接在宿主机和虚拟机之间传输文件,性能优于 NFS/Samba 等网络共享方案。 ### 适用场景 - 宿主机与虚拟机之间共享文件/模板 - 虚拟机访问宿主机上的大容量存储 - 多台虚拟机共享同一目录(如模板库、ISO 仓库等) ### 环境要求 | 项目 | 要求 | | ------ | --------------------------------------------------------- | | 宿主机 | FnOS(基于 Debian 12)或其他支持 KVM/QEMU 的 Linux | | 虚拟机 | 需要内核支持 9p(Linux 内核 2.6.14+,主流发行版默认支持) | | QEMU | 支持 virtio-9p-pci 设备 | --- ## 操作步骤 ### 第一步:确认宿主机共享目录存在 确保要共享的目录已创建,以 `/vol1/1000/templates` 为例: ```bash ls -ld /vol1/1000/templates ``` 如果目录不存在,先创建: ```bash sudo mkdir -p /vol1/1000/templates ``` ### 第二步:修复目录权限 QEMU 进程以 `libvirt-qemu` 用户运行,需要确保从根目录到共享目录的**整条路径链**都有可访问权限: ```bash sudo chmod 755 /vol1 /vol1/1000 /vol1/1000/templates ``` > ⚠️ **关键**:即使共享目录本身权限正确,如果上级目录(如 `/vol1` 或 `/vol1/1000`)缺少 `o+x` 权限,QEMU 仍然无法访问,会报 `Permission denied` 错误。 ### 第三步:关闭虚拟机 9p 设备需要在虚拟机配置中添加,修改配置前必须先关闭虚拟机: ```bash sudo virsh shutdown <虚拟机名称> ``` 如果虚拟机未响应 shutdown,可以强制关闭: ```bash sudo virsh destroy <虚拟机名称> ``` 确认已关闭: ```bash sudo virsh list --all | grep <虚拟机名称> ``` ### 第四步:添加 9p 共享设备(一键命令) 使用以下一键命令将 9p 文件系统设备注入到虚拟机 XML 配置中: ```bash VM_NAME="ubuntu24-clone-01" SHARE_DIR="/vol1/1000/templates" SHARE_TAG="templates_share" virsh dumpxml $VM_NAME > /tmp/${VM_NAME}.xml && \ sed -i "/<\/devices>/i \ \n \n \n \n <\/filesystem>" /tmp/${VM_NAME}.xml && \ virsh define /tmp/${VM_NAME}.xml && \ rm -f /tmp/${VM_NAME}.xml ``` 输出: ``` Domain 'ubuntu24-clone-01' defined from /tmp/ubuntu24-clone-01.xml ``` **参数说明:** | 变量 | 说明 | 示例 | | ------------- | -------------------------------- | ------------------------ | | `VM_NAME` | 虚拟机名称 | `ubuntu24-clone-01` | | `SHARE_DIR` | 宿主机要共享的目录路径 | `/vol1/1000/templates` | | `SHARE_TAG` | 共享标签名(虚拟机内挂载时引用) | `templates_share` | **XML 配置解读:** 添加到 `` 内的配置如下: ```xml ``` | 属性 | 说明 | | ---------------------------- | -------------------------------------------- | | `type="mount"` | [挂载类型,将宿主机本地目录共享](https://libvirt.org/formatdomain.html) | | `accessmode="passthrough"` | 直接使用宿主机文件权限,性能最佳 | | `` | 使用路径驱动 | | `` | 宿主机上的共享目录路径 | | `` | 共享标签名,**不是虚拟机内的挂载路径** | ### 第五步:启动虚拟机 ```bash sudo virsh start <虚拟机名称> ``` ### 第六步:虚拟机内挂载共享目录 通过 SSH 或 VNC 进入虚拟机,执行以下操作: **1. 加载 9p 内核模块(通常已自动加载):** ```bash sudo modprobe 9p sudo modprobe 9pnet sudo modprobe 9pnet_virtio ``` **2. 创建挂载点:** ```bash sudo mkdir -p /mnt/templates ``` **3. 挂载共享目录:** ```bash sudo mount -t 9p -o trans=virtio,version=9p2000.L templates_share /mnt/templates ``` > ⚠️ **注意**:`templates_share` 是第四步中设置的 `SHARE_TAG` 标签名,**必须与配置中的 `` 完全一致**,否则会报 `no channels available` 错误。 **4. 验证挂载:** ```bash ls /mnt/templates df -h /mnt/templates mount | grep 9p ``` 正常输出示例: ``` templates_share on /mnt/templates type 9p (rw,relatime,sync,dirsync,access=client,trans=virtio) ``` ### 第七步:设置开机自动挂载(可选) 将挂载配置写入 `/etc/fstab`,实现开机自动挂载: ```bash echo 'templates_share /mnt/templates 9p trans=virtio,version=9p2000.L,_netdev 0 0' | sudo tee -a /etc/fstab ``` 验证 fstab 配置是否正确(不会实际挂载,只检查语法): ```bash sudo mount -a ``` **fstab 参数说明:** | 参数 | 说明 | | -------------------- | -------------------------------------- | | `templates_share` | 设备名(即共享标签) | | `/mnt/templates` | 虚拟机内的挂载点 | | `9p` | 文件系统类型 | | `trans=virtio` | 使用 virtio 传输层 | | `version=9p2000.L` | 使用 Linux 扩展的 9p 协议 | | `_netdev` | 延迟挂载,确保 virtio 设备就绪后再挂载 | --- ## accessmode 模式对比 | 模式 | 权限映射 | 性能 | 适用场景 | | ---------------- | ---------------------- | ----------- | ------------------------------------------- | | `passthrough` | 直接使用宿主机 UID/GID | ⭐⭐⭐ 最优 | QEMU 以 root 运行,或路径链权限已正确配置 | | `mapped-xattr` | 通过扩展属性映射权限 | ⭐⭐ 良好 | QEMU 以非 root 用户运行,文件系统支持 xattr | | `mapped-file` | 通过隐藏文件映射权限 | ⭐ 一般 | 文件系统不支持 xattr 时的备选方案 | 如果使用 `passthrough` 模式遇到权限问题,可以切换为 `mapped-xattr`: ```bash VM_NAME="ubuntu24-clone-01" virsh dumpxml $VM_NAME > /tmp/${VM_NAME}.xml && \ sed -i 's/accessmode="passthrough"/accessmode="mapped-xattr"/' /tmp/${VM_NAME}.xml && \ virsh define /tmp/${VM_NAME}.xml && \ rm -f /tmp/${VM_NAME}.xml ``` --- ## 共享多个目录 可以同时共享多个目录,每个目录使用**不同的标签名**。重复第四步,修改变量即可: ```bash # 共享第二个目录 VM_NAME="ubuntu24-clone-01" SHARE_DIR="/vol1/1000/isos" SHARE_TAG="isos_share" virsh dumpxml $VM_NAME > /tmp/${VM_NAME}.xml && \ sed -i "/<\/devices>/i \ \n \n \n \n <\/filesystem>" /tmp/${VM_NAME}.xml && \ virsh define /tmp/${VM_NAME}.xml && \ rm -f /tmp/${VM_NAME}.xml ``` 虚拟机内挂载: ```bash sudo mkdir -p /mnt/isos sudo mount -t 9p -o trans=virtio,version=9p2000.L isos_share /mnt/isos ``` --- ## 删除 9p 共享 如果不再需要共享,执行以下步骤: **1. 虚拟机内卸载:** ```bash sudo umount /mnt/templates ``` 如果设置了自动挂载,还需删除 fstab 中对应行: ```bash sudo sed -i '/templates_share/d' /etc/fstab ``` **2. 宿主机上移除 9p 设备:** ```bash VM_NAME="ubuntu24-clone-01" virsh dumpxml $VM_NAME > /tmp/${VM_NAME}.xml && \ sed -i '//d' /tmp/${VM_NAME}.xml && \ virsh define /tmp/${VM_NAME}.xml && \ rm -f /tmp/${VM_NAME}.xml ``` > ⚠️ **注意**:上面的命令会删除**所有** 9p 共享。如果只想删除特定的共享,建议使用 `virsh edit` 手动编辑。 --- ## 常见问题 ### Q1: 挂载时报 `no channels available for device xxx` **原因**:标签名不匹配或拼写错误。 **解决**:确认虚拟机 XML 中 `` 的值与 `mount` 命令中的设备名完全一致: ```bash # 查看配置中的标签名 virsh dumpxml <虚拟机名称> | grep "target dir" ``` ### Q2: 启动虚拟机报 `Permission denied` **原因**:QEMU 进程无权访问共享目录或其上级目录。 **解决**:确保整条路径链都有可执行权限: ```bash sudo chmod 755 /vol1 /vol1/1000 /vol1/1000/templates ``` 或者改用 `mapped-xattr` 模式(参见上方 accessmode 模式对比章节)。 ### Q3: 虚拟机内无法写入共享目录 **原因**:`passthrough` 模式下,虚拟机内用户的 UID/GID 需与宿主机上文件的权限匹配。 **解决方案**: - 方案一:在宿主机上对共享目录设置宽松权限 `chmod 777` - 方案二:确保虚拟机内用户 UID 与宿主机目录 owner 一致 - 方案三:改用 `mapped-xattr` 模式 ### Q4: 9p 性能不如预期 **优化建议**: - 挂载时添加 `cache=loose` 选项提升读取性能(适合只读场景): ```bash sudo mount -t 9p -o trans=virtio,version=9p2000.L,cache=loose templates_share /mnt/templates ``` - 挂载时添加 `msize=262144` 增大传输块大小: ```bash sudo mount -t 9p -o trans=virtio,version=9p2000.L,msize=262144 templates_share /mnt/templates ``` ``` ```