- PVSM.RU - https://www.pvsm.ru -

DNS-поиск в Kubernetes

Прим. перев.: Проблема DNS в Kubernetes, а точнее — настройки параметра ndots, — на удивление популярна, причём уже не первый [1] год [2]. В очередной заметке по этой теме её автор — DevOps-инженер из крупной брокерской компании в Индии — в весьма простой и лаконичной манере рассказывает, о чём полезно знать коллегам, эксплуатирующим Kubernetes.

DNS-поиск в Kubernetes - 1

Одно из главных преимуществ развёртывания приложений в Kubernetes — беспроблемное обнаружение приложений. Внутрикластерное взаимодействие сильно упрощается благодаря концепции сервиса (Service [3]), которая представляет собой виртуальный IP, поддерживающий набор IP-адресов pod'ов. Например, если сервис vanilla желает связаться с сервисом chocolate, он может обратиться напрямую к виртуальному IP для chocolate. Возникает вопрос: кто в данном случае разрешит DNS-запрос к chocolate и как?

Разрешение имен DNS настраивается в кластере Kubernetes с помощью CoreDNS [4]. Kubelet прописывает pod с CoreDNS в качестве сервера имен в файлах /etc/resolv.conf всех pod'ов. Если посмотреть на содержимое /etc/resolv.conf любого pod'а, оно будет выглядеть примерно следующим образом:

search hello.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.152.183.10
options ndots:5

Эта конфигурация используется DNS-клиентами для перенаправления запросов на DNS-сервер. В файле resolv.conf содержится следующая информация:

  • nameserver: cервер, на который будут направляться DNS-запросы. В нашем случае это адрес сервиса CoreDNS;
  • search: определяет путь поиска определенного домена. Любопытно, что google.com или mrkaran.dev не являются FQDN (полными доменными именами [5]). Согласно стандартному соглашению, которому следуют большинство resolver'ов DNS, полными (FDQN) доменами считаются только те, которые заканчиваются точкой «.», представляющей корневую зону. Некоторые resolver'ы умеют добавлять точку самостоятельно. Таким образом, mrkaran.dev. — полное доменное имя (FQDN), а mrkaran.dev — нет;
  • ndots: Самый интересный параметр (эта статья именно о нем). ndots задает пороговое число точек в имени запроса, при достижении которого оно рассматривается как «полное» доменное имя. Подробнее об этом мы поговорим позже, когда будем анализировать последовательность DNS-поиска.

DNS-поиск в Kubernetes - 2

Давайте посмотрим, что происходит, когда мы запрашиваем mrkaran.dev в pod'е:

$ nslookup mrkaran.dev
Server: 10.152.183.10
Address: 10.152.183.10#53

Non-authoritative answer:
Name: mrkaran.dev
Address: 157.230.35.153
Name: mrkaran.dev
Address: 2400:6180:0:d1::519:6001

Для данного эксперимента я установил уровень логирования CoreDNS на all (что делает его весьма многословным). Посмотрим на логи pod'а coredns:

[INFO] 10.1.28.1:35998 - 11131 "A IN mrkaran.dev.hello.svc.cluster.local. udp 53 false 512" NXDOMAIN qr,aa,rd 146 0.000263728s
[INFO] 10.1.28.1:34040 - 36853 "A IN mrkaran.dev.svc.cluster.local. udp 47 false 512" NXDOMAIN qr,aa,rd 140 0.000214201s
[INFO] 10.1.28.1:33468 - 29482 "A IN mrkaran.dev.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.000156107s
[INFO] 10.1.28.1:58471 - 45814 "A IN mrkaran.dev. udp 29 false 512" NOERROR qr,rd,ra 56 0.110263459s
[INFO] 10.1.28.1:54800 - 2463 "AAAA IN mrkaran.dev. udp 29 false 512" NOERROR qr,rd,ra 68 0.145091744s

Фух. Две вещи здесь привлекают внимание:

  • Запрос проходит по всем этапам поиска до тех пор, пока ответ не будет содержать код NOERROR (DNS-клиенты его понимают и хранят как результат). NXDOMAIN означает, что для данного доменного имени запись не найдена. Поскольку mrkaran.dev не является FQDN-именем (в соответствии с ndots=5), resolver смотрит на поисковый путь и определяет порядок запросов;
  • Записи А и АААА поступают параллельно. Дело в том, что разовые запросы в /etc/resolv.conf по умолчанию настроены таким образом, что производится параллельный поиск по протоколам IPv4 и IPv6. Отменить подобное поведение можно, добавив опцию single-request в resolv.conf.

Примечание: glibc можно настроить на последовательную отправку этих запросов, а musl — нет, так что пользователям Alpine следует принять это к сведению.

Экспериментируем с ndots

Давайте еще немного поэкспериментируем с ndots и посмотрим, как себя ведет этот параметр. Идея проста: ndots определяет, будет ли DNS-клиент считать домен абсолютным или относительным. Например, как в случае простого google DNS-клиент узнает, является ли этот домен абсолютным? Если задать ndots равным 1, клиент скажет: «О, в google нет ни одной точки; пожалуй, пробегусь по всему списку поиска». Однако если запросить google.com, список суффиксов будет целиком проигнорирован, поскольку запрошенное имя удовлетворяет порогу ndots (имеется хотя бы одна точка).

Давайте убедимся в этом:

$ cat /etc/resolv.conf
options ndots:1
$ nslookup mrkaran
Server: 10.152.183.10
Address: 10.152.183.10#53

** server can't find mrkaran: NXDOMAIN

Логи CoreDNS:

[INFO] 10.1.28.1:52495 - 2606 "A IN mrkaran.hello.svc.cluster.local. udp 49 false 512" NXDOMAIN qr,aa,rd 142 0.000524939s
[INFO] 10.1.28.1:59287 - 57522 "A IN mrkaran.svc.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.000368277s
[INFO] 10.1.28.1:53086 - 4863 "A IN mrkaran.cluster.local. udp 39 false 512" NXDOMAIN qr,aa,rd 132 0.000355344s
[INFO] 10.1.28.1:56863 - 41678 "A IN mrkaran. udp 25 false 512" NXDOMAIN qr,rd,ra 100 0.034629206s

Поскольку в mrkaran нет ни одной точки, поиск проводился по всему списку суффиксов.

Примечание: на практике максимальное значение ndots ограничено 15; по умолчанию в Kubernetes оно равно 5.

Применение в production

Если приложение выполняет множество внешних сетевых вызовов, DNS может стать узким местом в случае активного трафика, поскольку при разрешении имени выполняется множество лишних запросов (прежде чем система доберется до нужного). Приложения обычно не добавляют корневую зону к доменным именам, однако это вполне тянет на хак. То есть вместо того, чтобы запрашивать api.twitter.com, вы можете за'hardcode'ить api.twitter.com. (с точкой) в приложении, что побудит DNS-клиентов выполнять авторитетный поиск сразу в абсолютном домене.

Кроме того, начиная с версии Kubernetes 1.14, расширения dnsConfig и dnsPolicy получили статус стабильных. Таким образом, при развертывании pod'а можно уменьшить значение ndots, скажем, до 3 (и даже до 1!). Из-за этого каждое сообщение внутри узла должно будет включать полный домен. Это один из классических компромиссов, когда приходится выбирать между производительностью и переносимостью. Мне кажется, что переживать об этом стоит только в случае, если сверхнизкие задержки жизненно важны для вашего приложения, поскольку результаты DNS также кэшируются внутри.

Ссылки

Впервые об этой особенности я узнал на K8s-meetup'е [6], прошедшем 25 января. Там шла речь, в том числе, и об этой проблеме.

Вот несколько ссылок для дальнейшего изучения:

Примечание: Я предпочел не использовать dig в этой статье. dig автоматически добавляет точку (идентификатор корневой зоны), делая домен «полным» (FQDN), не прогоняя его предварительно через список поиска. Писал об этом в одной из предыдущих публикаций [9]. Тем не менее, довольно удивителен тот факт, что, в общем-то, для стандартного поведения приходится задавать отдельный флаг.

Хорошего DNS'инга! До скорого!

P.S. от переводчика

Читайте также в нашем блоге:

Автор: Юлия Шарафитдинова

Источник [14]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/dns-2/348023

Ссылки в тексте:

[1] не первый: https://pracucci.com/kubernetes-dns-resolution-ndots-options-and-why-it-may-affect-application-performances.html

[2] год: https://medium.com/blocket-engineering/embracing-high-request-loads-on-kubernetes-1c9d4e84c508

[3] Service: https://kubernetes.io/docs/concepts/services-networking/service/

[4] CoreDNS: https://coredns.io/

[5] полными доменными именами: https://ru.wikipedia.org/wiki/FQDN

[6] K8s-meetup'е: https://failuremodes.dev/

[7] Объяснение: https://github.com/kubernetes/kubernetes/issues/33554#issuecomment-266251056

[8] Расхождения: https://www.openwall.com/lists/musl/2017/03/15/3

[9] одной из предыдущих публикаций: https://mrkaran.dev/posts/dig-overview/

[10] Calico для сети в Kubernetes: знакомство и немного из опыта: https://habr.com/ru/company/flant/blog/485716/

[11] CoreDNS — DNS-сервер для мира cloud native и Service Discovery для Kubernetes: https://habr.com/ru/company/flant/blog/331872/

[12] части 1 и 2 (сетевая модель, оверлейные сети): https://habr.com/ru/company/flant/blog/346304/

[13] часть 3 (сервисы и обработка трафика): https://habr.com/ru/company/flant/blog/433382/

[14] Источник: https://habr.com/ru/post/490174/?utm_source=habrahabr&utm_medium=rss&utm_campaign=490174