← Kubernetes: разбор поломок
6 мин · жёстко · Урок 8 из 12

DNS не резолвит: когда лежит CoreDNS

Как отличить общий отказ DNS от проблемы одного Service и по какой цепочке искать причину.

Инцидент приходит в виде «всё сломалось». Приложения не находят базу, очередь не находит брокер, health-check падает у половины сервисов. При этом Pod-ы живы, сеть между нодами работает, а kubectl отвечает нормально.

Когда список пострадавших сервисов слишком широкий, причина обычно одна: DNS-инфраструктура кластера.

Как DNS работает внутри кластера

CoreDNS это отдельный Deployment в namespace kube-system, обычно одна или две реплики. Перед ним стоит Service kube-dns (имя историческое, ещё с эпохи kube-dns) с фиксированным ClusterIP. Адрес этого Service kubelet прописывает каждому новому Pod в /etc/resolv.conf:

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

nameserver это ClusterIP Service kube-dns. search это суффиксы, которыми resolver дополняет неполные имена. ndots:5 означает: если в имени меньше 5 точек, сначала пробуем дополнить суффиксами, потом уже как FQDN.

Когда внутри Pod выполняется curl webapp, происходит вот что:

  1. resolver добавляет суффикс: webapp.default.svc.cluster.local;
  2. шлёт UDP-запрос на 10.43.0.10:53;
  3. kube-proxy перенаправляет запрос на Pod coredns;
  4. CoreDNS смотрит в API Kubernetes и отвечает ClusterIP Service.

Сломанное звено в этой цепочке валит резолв для всего кластера сразу.

Диагностика: nslookup из Pod

Команда номер один. Поднимают временный Pod и спрашивают у DNS то, что существует в любом кластере:

kubectl run dns-probe --image=busybox:1.36 --restart=Never -- \
  sleep 3600
kubectl exec dns-probe -- nslookup kubernetes.default

Здоровый ответ:

Server:    10.43.0.10
Address:   10.43.0.10:53

Name:      kubernetes.default.svc.cluster.local
Address:   10.43.0.1

Что бывает вместо него:

СимптомПричина
nslookup: read udp ... i/o timeoutcoredns не отвечает (нет Pod, упал, NetworkPolicy)
;; connection timed out; no servers could be reachedто же самое
резолвится cluster.local, но не example.comCorefile с битым forward: внешний DNS не работает
NXDOMAIN на существующий Serviceимя из другого namespace или selector mismatch

Первые две строки говорят про инфраструктуру, последняя про конкретный Service. Это разные инциденты.

Где живёт CoreDNS

kubectl get deploy -n kube-system
# coredns   1/1   1   1   30d   ← обычно 1 реплика, в больших кластерах 2

Состояние Pod:

kubectl get pods -n kube-system -l k8s-app=kube-dns
# coredns-...   1/1   Running   ...

READY 0/1 или полное отсутствие Pod означает, что DNS лежит. Масштабирование в ноль выглядит так же. Service kube-dns при этом остаётся на месте со своим ClusterIP, но за ним пусто:

kubectl get endpoints kube-dns -n kube-system
# kube-dns   <none>   ← endpoints пуст: coredns в нуле реплик или Pod не Ready

Объект v1 Endpoints deprecated с 1.33, и kubectl печатает про это предупреждение. Тот же список адресов через актуальный объект:

kubectl get endpointslice -n kube-system -l kubernetes.io/service-name=kube-dns

Пустые endpoints у kube-dns это готовый диагноз. Дальше остаётся понять, почему Pod нет.

Что внутри Corefile

Конфиг CoreDNS лежит в ConfigMap coredns в kube-system:

kubectl get cm coredns -n kube-system -o yaml

Главные строки: kubernetes cluster.local отвечает на *.cluster.local, forward . отправляет внешние домены дальше. Повреждённый блок роняет CoreDNS при старте, и Pod уходит в CrashLoopBackOff. Причина будет видна в логах:

kubectl logs -n kube-system -l k8s-app=kube-dns

Corefile стоит смотреть, когда реплики есть, а резолв всё равно не работает. Если реплик ноль, конфиг ни при чём.

Лечение

ПроблемаКоманда
ноль репликkubectl scale deploy coredns -n kube-system --replicas=1
битый Corefilekubectl edit cm coredns -n kube-system, починить, подождать ~30 сек на reload
Pod в CrashLoopBackOffkubectl logs -n kube-system -l k8s-app=kube-dns, смотреть причину

После фикса резолв проверяют тем же nslookup из тестового Pod. Ждать перезапуска приложений не нужно: resolver ходит в DNS на каждый запрос.

Как не наступать снова

CoreDNS держат минимум в двух репликах с антиаффинити по нодам. На kube-dns вешают алерт по пустым endpoints, а не по «доступности кластера»: пустые endpoints у DNS ловятся за секунды, а деградация приложений расползается минутами. Правки Corefile катят через GitOps-репозиторий, чтобы битый конфиг было чем откатить.

Порядок проверки одним списком

deploy coredns реплики есть pods k8s-app=kube-dns Pod Ready endpoints kube-dns IP в списке nslookup kubernetes.default
На каком шаге условие не выполнилось, там и причина.
# Есть ли вообще Pod coredns?
kubectl get pods -n kube-system -l k8s-app=kube-dns

# Сколько реплик хочет deploy?
kubectl get deploy coredns -n kube-system

# Endpoints у kube-dns
kubectl get endpoints kube-dns -n kube-system

# nslookup из Pod
kubectl exec dns-probe -- nslookup kubernetes.default

Цепочка: deploy → pods → endpoints → nslookup. На каком шаге ломается, там и причина.

Коротко

Прошли материал до конца? Отметьте урок пройденным.