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

Вопрос или проблема

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

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

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

## ПРЕДУПРЕЖДЕНИЕ: ЭТО АВТОСОЗДАННЫЙ ФАЙЛ. ИЗМЕНЕНИЯ В НЕГО СКОРЕЕ ВСЕГО БУДУТ 
## ПЕРЕЗАПИСАНЫ И ПОТЕРЯНЫ. Изменения в этой конфигурации должны быть сделаны с использованием:
## virsh net-edit default
## или другим приложением, использующим API libvirt.
##
## Файл конфигурации dnsmasq, созданный 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
...вырезано...
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 имеет адрес 192.168.122.193
;; время запроса истекло; сервера не достигнуты
;; время запроса истекло; сервера не достигнуты

Но создается огромное количество запросов 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
...вырезано...
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: прослушивание на любом, тип ссылки LINUX_SLL (Linux cooked), размер захвата 65535 байт
11:04:49.453864 IP (tos 0x0, ttl 64, id 56217, offset 0, флаги [none], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [none], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 55)
    192.168.122.1.19631 > 192.168.122.1.53: 20542+ AAAA? mysql.kvm. (27)
...вырезано...
11:05:09.510237 IP (tos 0x0, ttl 64, id 20515, offset 0, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 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, флаги [DF], proto UDP (17), длина 55)
    192.168.122.1.19631 > 192.168.122.1.53: 63294+ MX? mysql.kvm. (27)
^C
934 пакетов захвачено
1857 пакетов получено фильтром
0 пакетов отброшено ядром

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

precedence ::ffff:0:0/96  100

Даже пытался полностью отключить IPv6 в /etc/sysctl.conf:

# Отключить 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), насколько мне известно.

локальный домен в 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, поэтому нужно применить ту же процедуру для настройки моста, как описано выше.

Я думаю, что есть две позитивные цели для DNS-настройки, такой как эта:

  • Разрешение name.vm на хосте (и в гостевой системе) должно возвращать IP-адрес для ВМ с именем name
  • Разрешение example.com в гостевой системе (и на хосте) должно возвращать IP-адрес для example.com

Прямое указание настроить резолвер хоста на экземпляр dnsmasq для гостевой сети как форвардер, и dnsmasq для гостевой сети на резолвер хоста, приведет к неизвестным хостам, отскакивающим взад и вперед и задержке.

Это предлагает две проблемы, которых нужно избегать:

  • Разрешение несуществующей ВМ (или записи AAAA для существующей, только IPv4 ВМ) должно сразу возвращать NXDOMAIN/без данных
  • Разрешение несуществующего имени хоста (nonexistent.example.com) также должно сразу возвращать NXDOMAIN/без данных

Разрешение name.vm вообще достигается путем помещения <domain name="vm" localOnly='yes'/> в конфигурацию сети libvirtd (virsh net-edit default или что-то еще). Я считаю, что name="vm" является как (a) поисковым доменом, выдаваемым по DHCP, так и (b) добавляется к именам хостов DHCP для создания полного доменного имени, которое dnsmasq использует для помещения ВМ в DNS. Установка localOnly означает, что если имя не появляется в локальной зоне, dnsmasq не будет запрашивать вышестоящий сервер — это ключевая настройка, чтобы предотвратить зацикливание dig name.vm AAAA.

Чтобы name.vm разрешилось с хоста, это зависит от конфигурации резолвера хоста. Если используется systemd-resolved, попробуйте resolvectl dns virbr0 192.168.122.1; resolvectl domain virbr0 vm; resolvectl default-route virbr0 no'. Первая часть говорит systemd-resolved использовать сервер DNS гостевой сети. Вторая часть говорит, что поисковый домен, связанный с этим интерфейсом, — это vm. С этими частями, хост может успешно разрешить name.vm и example.com. Тем не менее, третья часть говорит systemd-resolved использовать DNS-сервер гостевой сети только для настроенных доменов – без этого, запросы для nonexistent.example.com будут зацикливаться между DNS-серверами резолвера хоста и гостевой сети. (Обновление: судя по прочтению https://libvirt.org/formatnetwork.html#connectivity domain, я думаю, что настройка register на yes может заменить вышеуказанный фрагмент resolvectl — я еще не успел проверить это, так как это требует libvirt 10.1.0, выпущенного в марте 2024.)

(К слову, другой способ сделать так, чтобы name.vm ~разрешилось, это модуль NSS для libvirt https://libvirt.org/nss.html, хотя он не использует DNS как таковой, и я его не пробовал.)

.

Ответ или решение

Для решения задачи доступа к виртуальным машинам, управляемым с помощью libvirt и KVM, через DNS, необходимо учесть несколько ключевых моментов, учитывая, что на вашем Ubuntu Trusty используется NetworkManager и виртуальная сеть с NAT (192.168.122.0/24). Ваша цель — обеспечить резолвинг DNS-имен для виртуальных машин с хоста максимально эффективно и без задержек.

Проблемы и их решение

1. Перегрузка DNS-запросами AAAA

Одной из основных проблем является избыточное количество DNS-запросов на AAAA-записи, что приводит к значительным задержкам в резолвинге. Возможное решение — конфигурация dnsmasq для отказа в обслуживании или игнорирования таких запросов.

Способы оптимизации DNS-конфигурации:

Изменение конфигурации dnsmasq:

  • Уберите конфигурацию форвардера в файле конфигурации сети libvirt, если ваша виртуальная сеть не нуждается в доступе к внешним DNS-серверам. Это минимизирует количество DNS-запросов, передаваемых внешним серверам.

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

  • Добавьте параметр domain-needed и local=/kvm/, чтобы отклонять запросы на несуществующие домены и уменьшить количество лишних запросов.

Использование параметра auth-zone:

  • Параметр auth-zone имеет схожую функциональность с local, но более сложный в настройке. Используйте его, если необходимо разрешать обращения из внешних сетей. Это может потребовать ручной настройки мостов.

2. Настройка системного резолвера

Во избежание кольцевых запросов между хостом и сетью гостевых машин, настройте системный резолвер таким образом, чтобы он корректно обрабатывал DNS-запросы:

  • Используйте команду resolvectl для привязки DNS-сервера гостевой сети к интерфейсу virbr0 и установите домен kvm для поиска.
  • Убедитесь, что resolvectl default-route для virbr0 установлен в no, чтобы определять, к каким доменам применять данные настройки.

Рекомендации и дополнительные шаги:

  1. Обновление систем и компонентов: Убедитесь, что используемые версии libvirt и dnsmasq актуальны. Некоторые улучшения и параметры, такие как register=yes в libvirt версии 10.1.0, могут автоматически интегрировать эти настройки.

  2. Использование NSS модуля libvirt: Это сторонний метод, не использующий DNS напрямую, но может помочь в резолвинге имен в системе.

Таким образом, следуя данным рекомендациям, вы сможете обеспечить эффективный и быстрый доступ к виртуальным машинам через DNS. Настройка должна быть выполнена осторожно, чтобы избежать влияния на другие сетевые сервисы и добиться стабильности в работе системы.

Это решение удовлетворяет профессиональным требованиям и позволяет улучшить производительность сети ваших виртуальных машин.

Оцените материал
Добавить комментарий

Капча загружается...