使用 DNS 访问 libvirt+KVM 虚拟机

Tim*_*nes 6 domain-name-system internal-dns libvirt dnsmasq kvm-virtualization

我有一台运行 KVM + Libvirt 的 Ubuntu Trusty 机器来管理小型虚拟机,并使用标准 NetworkManager 连接到常规网络。

我希望能够从主机通过 DNS 访问虚拟机。

Libvirt 使用虚拟专用子网 (192.168.122.0/24),NAT 可通过我的 eth0 上的网桥 (virbr0) 访问世界其他地方。Dnamasq 将该虚拟网络的 DHCP+DNS 私有化。

这是虚拟网络的 libvirt 配置:

<network>
  <name>default</name>
  <uuid>400c59ff-c276-4154-ab73-9a8a8d1c6be3</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:f4:bd:37'/>
  <domain name='kvm'/>
  <dns forwardPlainNames='no'>
    <forwarder addr='127.0.1.1'/>
    <host ip='192.168.122.1'>
      <hostname>host</hostname>
      <hostname>host.kvm</hostname>
    </host>
  </dns>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>
Run Code Online (Sandbox Code Playgroud)

Libvirt 启动一个 dnsmasq 实例,侦听 192.168.122.1:53,它回答对 .knv 的所有请求并将任何其他请求转发到我的主机。这个 dnsmasq 配置是由 libvirt 自动生成的:

/var/lib/libvirt/dnsmasq/default.conf

##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
##    virsh net-edit default
## or other application using the libvirt API.
##
## dnsmasq conf file created by libvirt
strict-order
user=libvirt-dnsmasq
no-resolv
server=127.0.1.1
domain=kvm
expand-hosts
domain-needed
local=//
pid-file=/var/run/libvirt/network/default.pid
except-interface=lo
bind-dynamic
interface=virbr0
dhcp-range=192.168.122.2,192.168.122.254
dhcp-no-override
dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases
dhcp-lease-max=253
dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
Run Code Online (Sandbox Code Playgroud)

NetworkManager 有一个 dnsmasq 实例在 127.0.1.1:53 上侦听,它用于所有 DNS 查询,然后再传递给我的主机由外部 DHCP 系统分配的任何 DNS 服务器。

为了让我的主机Ubuntu系统使用libvirt的dnsmasq,我将NetworkManager的dnsmasq指向域kvm使用192.168.122.1:

/etc/NetworkManager/dnsmasq.d/libvirt.conf

server=/kvm/192.168.122.1
Run Code Online (Sandbox Code Playgroud)

这在大多数情况下有效......

me@host ~ $ ps aufx
...cut...
root     11010  0.2  0.0 342084  6348 ?        Ssl  10:59   0:00 NetworkManager
root     11018  0.0  0.0  10232  3732 ?        S    10:59   0:00  \_ /sbin/dhclient -d -sf /usr/lib/NetworkManager/nm-dhcp-client.action -pf /run/sendsigs.omit.d/network-manager.dhclient-eth0.pid -lf /var/lib/NetworkManager/dhclient-b8043 
nobody   11228  0.0  0.0  32252  1564 ?        S    10:59   0:00  \_ /usr/sbin/dnsmasq --no-resolv --keep-in-foreground --no-hosts --bind-interfaces --pid-file=/run/sendsigs.omit.d/network-manager.dnsmasq.pid --listen-address=127.0.1.1 --
root     11033  1.0  0.1 513356 15160 ?        Sl   10:59   0:01 /usr/sbin/libvirtd -d
libvirt+ 11085  0.0  0.0  28208   948 ?        S    10:59   0:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf

me@host ~ $ sudo netstat -nulpd | grep dnsmasq
udp  0  0  127.0.1.1:53      0.0.0.0:*  11228/dnsmasq   
udp  0  0  192.168.122.1:53  0.0.0.0:*  11085/dnsmasq   
udp  0  0  0.0.0.0:67        0.0.0.0:*  11085/dnsmasq  

me@host ~ $ host test.kvm
test.kvm has address 192.168.122.193
;; connection timed out; no servers could be reached
;; connection timed out; no servers could be reached
Run Code Online (Sandbox Code Playgroud)

但是会创建大量 dnsmasq AAAA 查询,所有查询都在等待响应。

me@host ~ $ sudo netstat -nulpd | grep dnsmasq
udp  0  0  0.0.0.0:39329  0.0.0.0:*  11228/dnsmasq   
udp  0  0  0.0.0.0:2469   0.0.0.0:*  11085/dnsmasq   
udp  0  0  0.0.0.0:14805  0.0.0.0:*  11228/dnsmasq
...cut...
udp  0  0  0.0.0.0:51569  0.0.0.0:*  11228/dnsmasq   
udp  0  0  0.0.0.0:31091  0.0.0.0:*  11085/dnsmasq   
udp  0  0  0.0.0.0:39305  0.0.0.0:*  11085/dnsmasq

me@host ~ $ sudo netstat -nulpd | grep dnsmasq | wc -l
131
Run Code Online (Sandbox Code Playgroud)

tcpdump 显示它们主要是 AAAA 请求:

me@host ~ $ sudo tcpdump -vni any udp port 53
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
11:04:49.453864 IP (tos 0x0, ttl 64, id 56217, offset 0, flags [none], proto UDP (17), length 55)
    127.0.0.1.58535 > 127.0.1.1.53: 31275+ A? mysql.kvm. (27)
11:04:49.453948 IP (tos 0x0, ttl 64, id 20062, offset 0, flags [DF], proto UDP (17), length 55)
    192.168.122.1.7098 > 192.168.122.1.53: 41491+ A? mysql.kvm. (27)
11:04:49.454013 IP (tos 0x0, ttl 64, id 20063, offset 0, flags [DF], proto UDP (17), length 71)
    192.168.122.1.53 > 192.168.122.1.7098: 41491* 1/0/0 mysql.kvm. A 192.168.122.193 (43)
11:04:49.454068 IP (tos 0x0, ttl 64, id 37088, offset 0, flags [DF], proto UDP (17), length 71)
    127.0.1.1.53 > 127.0.0.1.58535: 31275* 1/0/0 mysql.kvm. A 192.168.122.193 (43)
11:04:49.454321 IP (tos 0x0, ttl 64, id 56218, offset 0, flags [none], proto UDP (17), length 55)
    127.0.0.1.56040 > 127.0.1.1.53: 47999+ AAAA? mysql.kvm. (27)
11:04:49.454381 IP (tos 0x0, ttl 64, id 20064, offset 0, flags [DF], proto UDP (17), length 55)
    192.168.122.1.19631 > 192.168.122.1.53: 20542+ AAAA? mysql.kvm. (27)
...cut...
11:05:09.510237 IP (tos 0x0, ttl 64, id 20515, offset 0, flags [DF], proto UDP (17), length 55)
    192.168.122.1.19631 > 192.168.122.1.53: 35761+ MX? mysql.kvm. (27)
11:05:09.510237 IP (tos 0x0, ttl 64, id 56674, offset 0, flags [DF], proto UDP (17), length 55)
    127.0.0.1.46085 > 127.0.1.1.53: 53641+ AAAA? mysql.kvm. (27)
11:05:09.510315 IP (tos 0x0, ttl 64, id 56675, offset 0, flags [DF], proto UDP (17), length 55)
    127.0.0.1.46085 > 127.0.1.1.53: 26166+ MX? mysql.kvm. (27)
11:05:09.510334 IP (tos 0x0, ttl 64, id 20516, offset 0, flags [DF], proto UDP (17), length 55)
    192.168.122.1.19631 > 192.168.122.1.53: 4247+ AAAA? mysql.kvm. (27)
11:05:09.510407 IP (tos 0x0, ttl 64, id 56676, offset 0, flags [DF], proto UDP (17), length 55)
    127.0.0.1.46085 > 127.0.1.1.53: 49331+ AAAA? mysql.kvm. (27)
11:05:09.510433 IP (tos 0x0, ttl 64, id 20517, offset 0, flags [DF], proto UDP (17), length 55)
    192.168.122.1.19631 > 192.168.122.1.53: 63294+ MX? mysql.kvm. (27)
^C
934 packets captured
1857 packets received by filter
0 packets dropped by kernel
Run Code Online (Sandbox Code Playgroud)

我尝试降低/etc/gai.conf中 AAAA 记录的优先级

precedence ::ffff:0:0/96  100
Run Code Online (Sandbox Code Playgroud)

甚至尝试完全禁用 IPv6 /etc/sysctl.conf

# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
Run Code Online (Sandbox Code Playgroud)

但是 AAAA 请求仍在发送,名称解析变得慢得无法忍受。

有没有办法让 libvirt 或 NetworkManager 忽略或否定这些请求,这样我就不必在使用已经收到的 A 记录之前等待所有请求超时?

Mar*_*lck 3

如果配置了转发器,dnsmasq 将转发所有没有明确数据的 DNS 查询。这包括没有活动租约的已配置静态 DHCP 客户端的记录、AAAA 记录(除非明确定义 IPv6 地址)等。

有几种方法可以避免这种情况:

不配置转发器

只需省略网络定义中的转发器条目即可。可能并不理想,除非虚拟网络确实是隔离的。AFAIK,这是 libvirt 当前支持的唯一可能性(12/2014)。

dnsmasq.conf 中的本地域

在 dnsmasq 中将域配置为“本地”:

 domain=local.net,192.168.10.0/24
 local=/local.net/
 local=/10.168.192.in-addr.arpa/
Run Code Online (Sandbox Code Playgroud)

理论上,这可以缩写为domain=local.net,192.168.10.0/24,local,但最近才修复的 dnsmasq 错误导致此失败。

libvirt 不支持这个。为了使用此配置,您需要在操作系统中手动设置桥并配置 libvirt 网络,如下所示:

   <network>
     <name>local</name>
     <forward mode='bridge'/>
     <bridge name='br0'/>
   </network>
Run Code Online (Sandbox Code Playgroud)

您根本不必在此配置中创建 libvirt 虚拟网络,只需<interface 'type=bridge'>在 VM 定义文件中使用即可。

dnsmasq.conf 中的授权区域

auth-zone参数具有与 类似的效果local。然而,它还有其他一些我并不认为完全理解的含义。我想如果虚拟网络中的名称应该从外部解析,那么这种配置是理想的。

domain=local.net
auth-zone=local.net
Run Code Online (Sandbox Code Playgroud)

libvirt 也不支持此设置,因此必须应用与上面相同的设置桥接的过程。