Выберите продукт

Kubernetes DNS: как Pod резолвит имена через CoreDNS и upstream

Разбираем DNS в Kubernetes по шагам: что kubelet пишет в /etc/resolv.conf внутри Pod, как search и ndots создают лишние попытки резолвинга и задержки, как CoreDNS отвечает за зоны кластера и форвардит во внешний upstream, и чем проверять dig/nslookup при инциденте.
Kubernetes DNS: как Pod резолвит имена через CoreDNS и upstream

Зачем вообще разбираться в Kubernetes DNS

Проблемы с резолвингом в Kubernetes часто выглядят одинаково: Service «вроде есть», Pod «вроде живой», но приложение периодически не может найти имя, запросы внезапно уходят во внешний DNS, а время ответа скачет. Почти всегда корень — комбинация настроек DNS внутри Pod (в первую очередь /etc/resolv.conf), логики ndots/search и того, как CoreDNS выбирает upstream (куда он форвардит запросы, которые не относятся к кластеру).

Ниже разложу Kubernetes DNS «по проводам»: что kubelet создаёт в Pod, как CoreDNS строит ответы, где обычно ломается форвардинг во внешний резолвер, и какие команды dig/nslookup реально помогают при инциденте.

Как выглядит DNS-путь запроса из Pod

Типовой путь запроса такой:

  • Приложение в Pod вызывает резолвер (glibc/musl/библиотека языка), который читает правила из /etc/resolv.conf.
  • Запрос уходит на nameserver, которым обычно является ClusterIP сервиса kube-dns/CoreDNS (например, 10.96.0.10).
  • CoreDNS решает: имя относится к зоне кластера (Service/Pod) или это внешняя зона.
  • Если зона кластера — отвечает через плагин kubernetes; если внешняя — пересылает в upstream через forward (или proxy в старых Corefile).

Для администратора здесь две зоны ответственности:

  • DNS внутри Pod: ndots, search, лимиты резолвера, нюансы glibc/musl, поведение приложения.
  • DNS в CoreDNS: Corefile, плагины, кеш, политика форвардинга, отдельные зоны (split-DNS).

Если вы держите несколько окружений (dev/stage/prod) или вам нужен изолированный стенд под CoreDNS-эксперименты и нагрузочные тесты DNS, удобнее всего делать это на отдельном VDS и воспроизводить проблему без влияния на боевой кластер.

Что находится в /etc/resolv.conf внутри Pod

Начните с самого простого: зайдите в Pod и посмотрите resolv.conf (в том же Pod, где проявляется проблема).

kubectl exec -it deploy/app -- cat /etc/resolv.conf

Чаще всего будет что-то вроде:

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Здесь важно всё:

  • nameserver — куда именно Pod отправляет DNS-запросы (обычно сервис CoreDNS).
  • search — суффиксы, которые резолвер будет автоматически подставлять к «коротким» именам.
  • options ndots:5 — порог: начиная с какого количества точек имя считается «достаточно полным», чтобы сначала пробовать резолвить «как есть» (без подстановки search).

Схема пути DNS-запроса: Pod обращается к CoreDNS и далее в upstream

Почему ndots так сильно влияет на задержки

ndots — это количество точек в имени, начиная с которого резолвер сначала пытается резолвить имя «как есть», и только затем (если не получилось) перебирает варианты с search. В Kubernetes по умолчанию часто стоит ndots:5.

Практический эффект: имя вроде api.example.com содержит две точки. При ndots:5 резолвер будет считать его «коротким» и сначала попробует (в порядке из search):

  • api.example.com.default.svc.cluster.local
  • api.example.com.svc.cluster.local
  • api.example.com.cluster.local
  • и только потом — api.example.com как внешнее имя

Узнаваемый симптом: внешние домены резолвятся медленно, а в логах CoreDNS много запросов к несуществующим именам, где хвост заканчивается на .svc.cluster.local.

Откуда берутся эти значения

Содержимое /etc/resolv.conf в Pod формируется kubelet на ноде на основе:

  • настроек Pod (spec.dnsPolicy, spec.dnsConfig);
  • параметров kubelet (например, --cluster-dns, --cluster-domain);
  • /etc/resolv.conf самой ноды (в зависимости от выбранной политики).

dnsPolicy: ClusterFirst, Default, None — что реально меняется

dnsPolicy определяет, как Pod использует кластерный DNS:

  • ClusterFirst (обычно по умолчанию): nameserver указывает на CoreDNS, а search включает ...svc.cluster.local.
  • Default: Pod берёт DNS-настройки ноды (часто полезно для диагностики или для hostNetwork).
  • None: DNS задаётся вручную через dnsConfig (и здесь легко сломать резолвинг кластерных имён, если забыть нужные search-домены).

Если в Pod внезапно не ClusterIP CoreDNS, первым делом проверьте манифест и мутации (admission): нет ли dnsPolicy: Default/None или подмены dnsConfig.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

CoreDNS, kube-dns и Service kube-dns: почему названия путают

Исторически в Kubernetes был аддон kube-dns. Сейчас чаще всего работает CoreDNS, но Service в кластере по привычке может называться kube-dns, а не coredns. Это нормально: важен не label, а фактическая конфигурация и pod’ы за сервисом.

Быстрая проверка:

kubectl -n kube-system get svc kube-dns
kubectl -n kube-system get deploy -l k8s-app=kube-dns
kubectl -n kube-system get cm coredns -o yaml

Если конфиг хранится в ConfigMap coredns, «движок» — CoreDNS, даже если сервис называется kube-dns.

Как CoreDNS решает: отвечать самому или идти в upstream

В CoreDNS это определяется Corefile. Типовой фрагмент выглядит так (пример для понимания, не копируйте слепо):

.:
    errors
    health
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance

Ключевые моменты:

  • Плагин kubernetes отвечает за зоны кластера (обычно cluster.local и reverse-зоны).
  • Плагин forward определяет upstream — куда отправлять всё остальное (в примере — резолверы из /etc/resolv.conf внутри Pod’а CoreDNS, то есть DNS ноды).
  • cache уменьшает частоту обращений к upstream; loadbalance может менять порядок A/AAAA в ответах (иногда важно при отладке).

Если вам нужно закрыть вопросы «доверия» и шифрования при обращении к внутренним сервисам (в том числе тем, что обнаруживаются через DNS), посмотрите SSL-сертификаты: с корректным TLS меньше шансов спутать «не тот» сервис при похожих именах и окружениях.

Что такое upstream на практике

Upstream — это внешние (относительно CoreDNS) DNS-резолверы, которые умеют резолвить «не кластерные» имена: публичные домены, корпоративные зоны, партнёрские зоны и т.д.

Частые варианты upstream:

  • DNS ноды через forward . /etc/resolv.conf (удобно, но вы наследуете все особенности ноды).
  • Явно заданные IP корпоративных DNS-серверов (часто надёжнее и предсказуемее).
  • Отдельный кэширующий резолвер в инфраструктуре (например, Unbound) — полезно для стабильности и контроля.

Типовая проблема: CoreDNS форвардит в systemd-resolved stub и ловит ошибки

На многих дистрибутивах нода использует systemd-resolved со stub’ом 127.0.0.53. Если CoreDNS настроен на /etc/resolv.conf, а там указан 127.0.0.53, CoreDNS внутри Pod’а не сможет обратиться к loopback ноды и начнёт получать таймауты или SERVFAIL (конкретное поведение зависит от сети и окружения).

Проверка:

kubectl -n kube-system exec -it deploy/coredns -- cat /etc/resolv.conf

Если видите nameserver 127.0.0.53 — это красный флаг. Обычно решение одно из двух: прописать CoreDNS явные upstream-адреса или обеспечить, чтобы CoreDNS читал «правильный» resolv.conf ноды (не stub).

Split-DNS (stub zones): как направлять отдельные зоны в отдельные DNS

Термин stubDomains исторически связан с kube-dns, но идея актуальна и для CoreDNS: часть доменных зон нужно резолвить через корпоративные DNS, а всё остальное — через общий upstream.

В CoreDNS это обычно делают отдельными server block’ами или отдельными правилами forward на конкретную зону. Принцип:

  • для зоны corp.local форвардим запросы на корпоративные DNS (upstream только для этой зоны);
  • для остальных зон используем общий upstream.

Практика: split-DNS почти всегда проще поддерживать на уровне CoreDNS, чем разносить по десяткам манифестов Pod’ов.

Если вы параллельно наводите порядок с корпоративными зонами и их делегированием, может быть полезно посмотреть материал: делегирование поддомена через NS: как избежать сюрпризов с DNS.

Диагностика: dig из Pod и чтение результатов

Для отладки удобнее всего работать прямо из проблемного Pod или из временного debug Pod (в зависимости от ваших политик образов). Ниже — проверки, которые чаще всего дают ответ «где именно сломалось».

1) Проверяем, что Pod видит CoreDNS

kubectl exec -it deploy/app -- nslookup kubernetes.default.svc.cluster.local 10.96.0.10

Если ответа нет, проблема обычно не в upstream, а в доступности CoreDNS: Service/Endpoints, NetworkPolicy, CNI, kube-proxy/IPVS, conntrack на ноде.

2) Смотрим search и ndots в Pod

kubectl exec -it deploy/app -- cat /etc/resolv.conf

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

3) Сравниваем короткое имя и FQDN

Допустим, у вас есть сервис redis в namespace default.

kubectl exec -it deploy/app -- dig +time=1 +tries=1 redis
kubectl exec -it deploy/app -- dig +time=1 +tries=1 redis.default.svc.cluster.local

Если FQDN резолвится стабильно и быстро, а короткое имя — долго, время уходит на перебор вариантов по search и ожидание таймаутов на промежуточных запросах.

4) Проверяем внешний домен и видим «паразитные» попытки

kubectl exec -it deploy/app -- dig +search +time=1 +tries=1 api.example.com

Опция +search помогает увидеть поведение с учётом search-суффиксов. Если в выводе проскакивают варианты с .svc.cluster.local, это ожидаемо при высоком ndots, но иногда нежелательно по задержкам.

5) Смотрим, куда CoreDNS форвардит (upstream), и жив ли он

Сначала проверьте Corefile, затем — резолвинг из самого Pod’а CoreDNS:

kubectl -n kube-system get cm coredns -o yaml
kubectl -n kube-system exec -it deploy/coredns -- cat /etc/resolv.conf
kubectl -n kube-system exec -it deploy/coredns -- nslookup example.com

Если из CoreDNS не резолвится внешнее имя, проблема почти точно в upstream (сетевой доступ, firewall, недоступен корпоративный DNS, или CoreDNS смотрит в stub).

Пример диагностики DNS из Pod с помощью dig и nslookup

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Частые причины проблем и быстрые фиксы

Слишком высокий ndots и лишние запросы

Если приложение постоянно ходит во внешние домены, а вы видите задержки и много NXDOMAIN в CoreDNS, можно рассмотреть снижение ndots точечно для конкретных Pod’ов через dnsConfig. Делайте это осознанно: низкий ndots меняет порядок попыток резолвинга и иногда может повлиять на «короткие» имена, если они пересекаются с внешними зонами.

Если есть возможность — используйте FQDN для внешних имён в конфигурации приложений. Это самый простой способ уменьшить зависимость от search/ndots.

CoreDNS смотрит в неправильный upstream

Если CoreDNS форвардит в /etc/resolv.conf, а там systemd-resolved stub или DNS, недоступные из Pod-сети, вы получите таймауты, SERVFAIL и «плавающий» резолвинг.

Диагностический критерий: кластерные имена резолвятся стабильно, а внешние — с задержками или периодическими ошибками. Тогда смотрим именно forward и достижимость upstream.

Split-DNS реализован «в Pod’ах», а не централизованно

Когда часть Pod’ов резолвит корпоративные зоны через один DNS, часть — через другой, а часть — через публичный, вы ловите не только задержки, но и разные ответы на одно и то же имя. Централизация на CoreDNS обычно проще: один конфиг, одна точка диагностики.

AAAA/IPv6-запросы и неожиданные таймауты

Если сеть или upstream не готовы к IPv6, но клиенты и CoreDNS активно спрашивают AAAA, возможны задержки на таймаутах. Для проверки сравнивайте отдельно:

kubectl exec -it deploy/app -- dig +time=1 +tries=1 A example.com
kubectl exec -it deploy/app -- dig +time=1 +tries=1 AAAA example.com

Практический чек-лист при инциденте Kubernetes DNS

  1. Проверить /etc/resolv.conf в проблемном Pod: nameserver, search, ndots.
  2. Проверить резолвинг FQDN сервисов кластера: kubernetes.default.svc.cluster.local.
  3. Сравнить резолвинг коротких имён и FQDN внутри кластера.
  4. Проверить внешний домен из проблемного Pod и отдельно из Pod’а CoreDNS.
  5. Посмотреть CoreDNS Corefile: наличие kubernetes, forward, настройки зон для split-DNS.
  6. Проверить, что upstream доступен из namespace kube-system и что это не loopback stub.

Итоги: как держать DNS в Kubernetes предсказуемым

Резолвинг в Kubernetes складывается из двух логик: клиентской (в Pod, через resolv.conf, ndots и search) и серверной (CoreDNS: плагины, кеш и upstream). Большинство «странностей» появляется на стыке.

Если у вас много внешнего трафика и чувствительность к латентности, уделите внимание ndots, используйте FQDN там, где это возможно, и обеспечьте стабильный upstream (лучше контролируемый кэширующий резолвер, чем случайные настройки ноды). А если нужен split-DNS, делайте его на уровне CoreDNS, а не «по месту» в отдельных Pod.

В связке с DNS часто всплывают вопросы доменов и управления зонами; по смежной теме может пригодиться материал: перенос домена и EPP-код: что проверить заранее в DNS.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...