Задача 15. Медленный DNS и загадка ndots

Обращение к внешнему API из пода отрабатывает заметно дольше, чем с ноды. Разбираем search-домены, параметр ndots:5 и почему один внешний запрос превращается в пять DNS-запросов.
Опубликовано:

Задача

Приложение в поде обращается к внешнему API — api.example.com. Запросы стабильно медленнее, чем те же запросы с самой ноды: разница в десятки миллисекунд на каждом обращении.

Внутрикластерные обращения при этом быстрые.

Вопрос: откуда берётся задержка именно на внешних именах?

Что кажется очевидным

«CoreDNS перегружен» или «сеть до внешнего резолвера медленная». Но метрики CoreDNS в норме, а нагрузка невысокая.

Как это работает на самом деле

Загляните в /etc/resolv.conf внутри любого пода:

BASH
kubectl exec -it my-pod -- cat /etc/resolv.conf
Нажмите, чтобы развернуть и увидеть больше
PLAINTEXT
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Нажмите, чтобы развернуть и увидеть больше

Здесь два интересных элемента.

search — список суффиксов, которые резолвер по очереди приписывает к неполному имени. Это то, что позволяет обращаться к сервису просто по имени backend, а не по полному backend.default.svc.cluster.local.

ndots:5 — правило, определяющее, считать ли имя «полным». Смысл такой: если в имени меньше 5 точек, сначала пробуем его с каждым суффиксом из search, и только потом — как есть.

Посчитаем точки в api.example.com — их две. Два меньше пяти, значит имя считается неполным, и резолвер начинает перебор:

  1. api.example.com.default.svc.cluster.local → NXDOMAIN
  2. api.example.com.svc.cluster.local → NXDOMAIN
  3. api.example.com.cluster.local → NXDOMAIN
  4. api.example.comуспех

Четыре запроса вместо одного. А поскольку резолвер обычно спрашивает и A, и AAAA-записи, реальное число обращений удваивается — до восьми.

Отсюда и задержка: три бесполезных цикла «запрос → NXDOMAIN» перед полезным ответом. Внутрикластерные имена при этом быстрые, потому что для них первый же суффикс даёт попадание.

Ответ

Виноват ndots:5 вместе со списком search-доменов: внешнее имя с двумя точками считается неполным, поэтому резолвер сначала безуспешно перебирает все внутрикластерные суффиксы и только потом спрашивает настоящее имя.

Что с этим делать

Способ 1: точка в конце (самый простой)

Полностью квалифицированное имя — с точкой на конце — перебор отключает:

PLAINTEXT
api.example.com.        ← обратите внимание на завершающую точку
Нажмите, чтобы развернуть и увидеть больше

Резолвер считает такое имя абсолютным и спрашивает ровно один раз. Работает, если приложение корректно передаёт имя с точкой (некоторые библиотеки её обрезают).

Способ 2: настроить ndots для конкретного пода

YAML
spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2"
Нажмите, чтобы развернуть и увидеть больше

При ndots:2 имя api.example.com (две точки) уже считается полным — перебор не запускается. Внутрикластерные короткие имена (backend, 0 точек) продолжают работать через search.

Осторожно: если приложение использует имена вида backend.other-namespace (одна точка) — при ndots:2 они тоже перестанут дополняться суффиксами. Проверьте свои паттерны обращений.

Способ 3: полные имена внутри кластера

Если приложение всё равно ходит по полным именам, можно уменьшить и search-перебор:

PLAINTEXT
backend.default.svc.cluster.local.
Нажмите, чтобы развернуть и увидеть больше

Четыре точки + завершающая — резолвится сразу.

Дополнительно: кэш DNS на ноде

Для кластеров с интенсивным DNS-трафиком существует NodeLocal DNSCache — кэширующий агент на каждой ноде. Он снимает нагрузку с CoreDNS, убирает лишние сетевые прыжки и сглаживает всплески задержек. Для больших кластеров это стандартная практика.

Известная историческая проблема

Стоит знать про давнюю проблему с гонкой в conntrack при параллельных DNS-запросах (A и AAAA через один UDP-сокет), которая проявлялась как редкие пятисекундные задержки резолвинга. Симптом характерный: ровно 5 секунд (таймаут резолвера) на случайных запросах. Лечится настройкой single-request-reopen в dnsConfig, NodeLocal DNSCache или современным CNI. Если видите такие ровные пятисекундные всплески — это почти наверняка оно.

Диагностика

BASH
# Сколько запросов реально уходит
kubectl exec -it my-pod -- nslookup -debug api.example.com

# Замер: сравните время
kubectl exec -it my-pod -- time nslookup api.example.com
kubectl exec -it my-pod -- time nslookup api.example.com.

# Метрики и логи CoreDNS
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50
Нажмите, чтобы развернуть и увидеть больше

Если второй замер (с точкой) заметно быстрее первого — диагноз подтверждён.


Дальше: Задача 16. Почему под висит в Pending.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша