首先,我的问题类似于如何使用 KVM (Virt-Manager) 设置虚拟机和主机的桥接网络?但标记的答案对我不起作用,并且由于问题被标记为已解决,我认为最好发布一个新问题。
我会尝试简化我的设置。
- 我有一个
host
witheno1
(运行 Debian + KDE) - 我已经删除了所有
eno1
接口 - 我创建了一个桥接接口
br0
并添加eno1
为从属接口 - 我安装了 virt-manager
host
现在:
host
已连接br0
并获得IP- virt-manager
VM
配置为使用br0
,但它没有获取 IP
无论我如何尝试,我都无法获得VM
IP。我怎样才能解决这个问题?
这是一些屏幕截图。忽略 br1,因为那只是我在玩/测试。
连接br0
...
...带有以太网从站...
... 链接到eno1
.
VM
配置为桥接设备br0
Docker 使用iptables来管理其容器,就像libvirt也使用它一样。但通常 Docker 不能与同一系统上运行的其他网络相关工具很好地配合,原因有二:
Docker 加载
br_netfilter
内核模块,使桥接帧遍历iptables(而不仅仅是ebtables)。Docker 还将iptables的默认过滤器/FORWARD 策略设置为 DROP
br_netfilter
这些的组合,以及将此作为默认行为的事实,系统上存在的任何桥,无论是否与 Docker 相关,都会通过iptables继承默认的 DROP 转发策略,此外还有ebtables可能执行的任何操作(如果也存在) :任何转发的帧都会被丢弃。因此, libvirt处理的所有桥都会受到影响:虚拟机因 Docker 运行而被隔离。如上所述,可以将例外添加(但实际上应该插入而不是添加)到
DOCKER-USER
Docker 创建的链式规则(但如果需要,可以首先由管理员创建)。仅仅向链添加规则FORWARD
可能还不够,因为 Docker 总是在之前插入其规则(但DOCKER-USER
首先调用)。要允许任何非 Docker 桥不被iptables过滤,可以使用以下选择之一:
通过 IP 地址匹配允许转发的内容。使用 0.0.0.0 和 255.255.255.255 等地址很难与 DHCP 区分开来,还必须添加它们。对于 IP LAN 192.0.2.0/24 来说:
或者通过非 Docker 接口进行匹配
除非自定义命名,否则 Docker 接口始终命名为
docker0
或br-...
。不要使用相同的命名约定并为它们添加例外。从iptables 的角度来看,从桥接端口eno1转发的桥接帧,例如vnet0(虚拟机的 Tap 接口)被显示为来自br0接口:桥接端口不会被看到,因此数据包来自br0并转发到br0。
顺序很重要。声明插入索引可以保持下面规则的自然顺序,就像添加了(但由于 Docker 添加了最后的)
-A
而必须插入它们。-j RETURN
允许
br0
并且br1
:让我们继续讨论 libvirt 和 LXC(也是常见的受害者)的其他常见名称:
或者让iptables获取一些桥接信息来做出决定
即使它看起来更通用,也应该避免,因为使用
physdev
match 模块确实会加载br_netfilter
内核模块来工作(如果尚未加载),所以即使不使用 Docker 也会得到这个,而其目标是保护自己免受 Docker 加载br_netfilter
。它更强大一点,因为它允许区分桥接的帧和路由的数据包(使用单臂路由,恰好使用网桥作为路由接口)。Docker 仍然需要例外,因为 Docker 在自己的链中进行自己的 LAN 过滤。任何非 Docker 和桥接(而不是路由)的东西都是允许的。
考虑到libvirt本身在 FORWARD 链中的规则可能无法正常工作或者可能被 Docker 的规则短路,以前的选择可能不适用于所有可能的情况。尽管nat规则也受到影响,但在这种情况下,libvirt(和 LXC)通常可以完全正确地处理这些规则。
虚拟机中的 Docker
不要将 Docker 与任何其他网络工具混合使用,它会在存在网桥的情况下扰乱它们的行为。相反,在正确隔离的虚拟机中运行 Docker 本身,不会影响主机或主机上的其他虚拟机和容器(例如:LXC)。然后,如果该虚拟机本身与主网络桥接,正如当前主机的设置已经允许的那样,这不会对到达其容器的外部设置进行太大改变:Docker 将在物理 LAN 上拥有自己独立的 IP 地址,而不是主人的。
其他可能性(需要内核 >= 5.3)
预加载
br_netfilter
以确保sysctl设置可用,并使用以下命令禁用iptables的系统范围设置:并在选定的 Docker 桥上重新启用它(可能使用运行 Docker 命令的脚本来检索其名称):
这将需要对创建的每个新桥进行操作。
另一种方法可能是Docker-in-Docker在容器中运行自身,仅禁用全局设置(默认情况下,在新的网络命名空间上仍启用此设置...)。这看起来越来越困难,因为与在虚拟机中运行 Docker 相比,需要额外的管理负担。
我会选择 4。(虚拟机:避免所有可能的 Docker 干扰)或者 2。(保持简单但足够好)
iptables
注意:通过替换ip6tables
上面的内容(包括) ,所有内容都适用于 IPv6sysctl
。对于nftables集成,请参阅此nftables具体答案。