Назад | Перейти на главную страницу

Доступ к виртуальным машинам libvirt + KVM через DNS

У меня есть машина Ubuntu Trusty с KVM + Libvirt для управления небольшими виртуальными машинами и использование стандартного NetworkManager для подключения к обычным сетям.

Я хочу иметь доступ к виртуальным машинам через DNS с хоста.

Libvirt использует виртуальную частную подсеть (192.168.122.0/24), NAT'd для доступа к остальному миру через мост (virbr0) на моем eth0. 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>

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

NetworkManager имеет экземпляр dnsmasq, прослушивающий 127.0.1.1:53, который он использует для всех запросов DNS перед передачей на любые DNS-серверы, которые мой хост назначает внешней системой DHCP.

Чтобы моя хост-система Ubuntu могла использовать dnsmasq libvirt, я указываю dnsmasq NetworkManager использовать 192.168.122.1 для домена kvm:

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

server=/kvm/192.168.122.1

И это по большей части работает ...

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

Но создает огромное количество запросов 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

И 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

Я попытался снизить приоритет записей AAAA в /etc/gai.conf

precedence ::ffff:0:0/96  100

Даже пытался полностью отключить 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

Но запросы AAAA все еще отправляются, и разрешение имен становится невыносимо медленным.

Есть ли способ для libvirt или NetworkManager игнорировать эти запросы или отрицательно реагировать на них, чтобы мне не приходилось ждать, пока все запросы истекут, прежде чем использовать уже полученную запись A?

Если настроен сервер пересылки, dnsmasq будет пересылать все DNS-запросы, для которых нет явных данных. Сюда входят записи для настроенных статических DHCP-клиентов, у которых нет активной аренды, записи AAAA, если IPv6-адреса не определены явно, и многое другое.

Есть несколько способов избежать этого:

Не настраивать пересылку

Просто опустите дополнительные записи в определении сети. Наверное, нежелательно, если только виртуальная сеть не действительно изолированные. Это единственная возможность, которую libvirt в настоящее время поддерживает (12/2014), AFAIK.

локальный домен в dnsmasq.conf

Настройте домен как «локальный» в dnsmasq:

 domain=local.net,192.168.10.0/24
 local=/local.net/
 local=/10.168.192.in-addr.arpa/

Теоретически это можно было бы сократить как domain=local.net,192.168.10.0/24,local, но ошибка dnsmasq исправлена ​​совсем недавно приводит к сбою.

libvirt не поддерживает это. Чтобы использовать эту конфигурацию, вам необходимо вручную настроить мост в вашей ОС и настроить сеть libvirt следующим образом:

   <network>
     <name>local</name>
     <forward mode='bridge'/>
     <bridge name='br0'/>
   </network>

Вам совсем не нужно создавать виртуальную сеть libvirt в этой конфигурации, просто используйте <interface 'type=bridge'> в ваших файлах определения виртуальной машины.

зона авторизации в dnsmasq.conf

В auth-zone параметр имеет аналогичный эффект local. Однако это имеет и другие последствия, которые я не могу полностью понять. Я полагаю, что такая конфигурация была бы желательна, если предполагается, что имена в виртуальной сети разрешаются извне.

domain=local.net
auth-zone=local.net

Эта настройка также не поддерживается libvirt, поэтому необходимо применить ту же процедуру для настройки моста, что и выше.