在Linux宿主机通过libvirt安装的kvm虚拟机,能看到IP,但是却不能联网。我碰到这种情况是因为有docker在运行。是 Docker 和 Libvirt (KVM) 在 iptables 规则上的冲突。

简单来说:Docker 启动时会重写防火墙规则,它通常会默认拦截所有非 Docker 管理的转发流量。因为你的虚拟机(通过 virbr0 网卡)发出的流量属于“非 Docker 流量”,所以被 Docker 的防火墙规则丢弃了,导致无法连网。

虽然 DHCP(分配 IP)工作正常(因为这是在虚拟机内部或 Libvirt 的 dnsmasq 层面处理的),但数据包一旦要跨出虚拟机访问外网,就会被拦截。

为了让规则在 Docker 重启后依然有效,最优雅的方法是利用 Libvirt Hook 脚本。每当 Libvirt 启动虚拟机或网络时,自动插入这些规则。

创建 Hook 脚本目录:

sudo mkdir -p /etc/libvirt/hooks

创建脚本文件:

sudo vim /etc/libvirt/hooks/qemu

(注:如果该文件已存在,请将内容追加进去)

写入以下内容:

#!/bin/bash
# Fix for Docker + Libvirt network conflict

if [ "${1}" = "prepare" ]; then
    # 允许 virbr0 的流量转发
    if ! iptables -C FORWARD -i virbr0 -j ACCEPT 2>/dev/null; then
        iptables -I FORWARD 1 -i virbr0 -j ACCEPT
    fi
    
    if ! iptables -C FORWARD -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then
        iptables -I FORWARD 1 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
    fi
    
    # 确保 NAT 规则存在
    if ! iptables -t nat -C POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE 2>/dev/null; then
        iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
    fi
fi

这是一个 Bash 脚本,它会检测虚拟机是否在准备启动,并修补 iptables 规则。

赋予执行权限:

sudo chmod +x /etc/libvirt/hooks/qemu

重启 Libvirt 守护进程:

sudo systemctl restart libvirtd

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐