虚拟机网络的四种模式
一句话总结
VM 网络模式的选择取决于由谁处理数据包:用户空间(SLIRP)、内核(TAP)、内核网桥,以及内核中的 virtio 处理(vhost-net)。
为什么需要了解这些
“VM 能访问互联网,但外部无法连接 VM。”这类问题几乎总是由 user(SLIRP)模式引起。它常被用作开发环境的默认值,如果不了解其特性,就可能原样带入生产环境。
工作原理
user(SLIRP)
QEMU 在用户空间完整实现 TCP/IP 协议栈。QEMU 解析客户机发出的数据包,再将其转换为宿主机上的普通套接字流量发送出去。
- 完全不需要特权。 这是它在本实验环境中成为唯一可用方式的原因。
- 客户机位于
10.0.2.0/24网段,网关为10.0.2.2,DNS 为10.0.2.3。 - 外部无法直接连接客户机。 必须通过
hostfwd单独开放端口。 - ICMP 支持有限。客户机内经常无法使用
ping,这是正常现象。 - 性能较低。所有数据包都要额外经过一次用户空间。
tap
在内核中创建虚拟以太网设备,由 QEMU 持有其中一端。由于数据包会直接进入内核网络栈,从宿主机看,它就像一个真实接口。但创建 TAP 设备需要特权,或者需要对预先创建的设备拥有权限。
bridge
将 TAP 接入 Linux 网桥。如果物理 NIC 也接入该网桥,VM 就会像直接连接物理网络一样工作。VM 可以通过 DHCP 获取企业内网地址,其他服务器也能直接通过该地址连接它。这是生产环境的基本配置。
ip link add br0 type bridge
ip link set eth0 master br0
ip link set br0 up
qemu-system-x86_64 -netdev tap,id=n0,ifname=tap0,script=no -device virtio-net-pci,netdev=n0
vhost-net
在内核中处理 virtio 环形缓冲区。无需往返 QEMU 用户空间,因此可以显著降低延迟和 CPU 使用率。配置方式为 -netdev tap,...,vhost=on。
| 模式 | 特权 | 外部→内部连接 | 性能 | 用途 |
|---|---|---|---|---|
| user | 不需要 | 仅限 hostfwd | 低 | 开发/测试 |
| tap | 需要 | 可以 | 中 | 隔离的 VM 网络 |
| bridge | 需要 | 可以(直连物理网络) | 中~高 | 生产环境 |
| vhost-net | 需要 | 可以 | 高 | 高性能工作负载 |
生产现场中的常见情况
开发环境中正常的功能到了预发布环境却无法工作。 开发环境使用 user 模式,只通过 hostfwd 开放了 22 端口,而预发布环境使用 bridge,所有端口都可以访问。反过来,从只能依靠 hostfwd 访问的环境迁移到网桥后,必须重新设计防火墙——此前 QEMU 实际上承担了防火墙的作用。
MTU 问题。 在网桥上叠加 VXLAN 等覆盖网络后,有效 MTU 会减小。VM 内仍然使用 1500,导致大数据包悄无声息地丢失。此时需要降低客户机 MTU,或进行 MSS 钳制。
与容器网络有何异同
前面介绍的四种模式,在容器网络中几乎都会原样出现。名称不同,作用却相同;理解其中一侧,另一侧也就很容易掌握。
- VM 的 user 模式 ≈ 容器端口转发。内部可以访问外部,而外部只能通过明确开放的端口进入内部。
- VM 的 tap ≈ 容器的 veth 对。在内核中创建虚拟接口,一端放在内部,另一端留在外部。
- VM 的 bridge ≈ Docker 默认网桥网络。将多个实例接入同一网桥,使它们能够相互通信。
- VM 的 vhost-net ≈ 将数据平面下沉到内核或 eBPF。避免往返用户空间,从而提高速度。
两者的差异也很明确。容器共享宿主机内核,只隔离网络命名空间;VM 则拥有自己的内核。 因此,在 VM 内修改内核参数不会影响宿主机;而容器内的许多内核设置要么与宿主机共享,要么根本无法修改。另一方面,VM 启动时间更长,也会完整占用所分配的内存。
转化为实际决策就是:如果必须操作内核本身(加载模块、使用不同内核版本)、确实需要极高隔离级别,或需要运行非 Linux 系统,就选择 VM。除此之外,容器几乎总是更轻、更快。而且二者混合使用十分常见——典型结构是 Kubernetes 节点本身运行在 VM 中,容器再运行于其上。此时网络层叠加两层,前面提到的 MTU 问题尤其容易出现。
下一步要做什么
本模块只讲解概念。现在应当能够解释为何前面的 vm-boot 实验使用 -netdev user,hostfwd=...——因为在无特权环境中,这是唯一可行的选择。