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, происходит вот что:
- resolver добавляет суффикс:
webapp.default.svc.cluster.local; - шлёт UDP-запрос на
10.43.0.10:53; - kube-proxy перенаправляет запрос на Pod coredns;
- 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 timeout | coredns не отвечает (нет Pod, упал, NetworkPolicy) |
;; connection timed out; no servers could be reached | то же самое |
резолвится cluster.local, но не example.com | Corefile с битым 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 |
| битый Corefile | kubectl edit cm coredns -n kube-system, починить, подождать ~30 сек на reload |
| Pod в CrashLoopBackOff | kubectl logs -n kube-system -l k8s-app=kube-dns, смотреть причину |
После фикса резолв проверяют тем же nslookup из тестового Pod. Ждать перезапуска приложений не нужно: resolver ходит в DNS на каждый запрос.
Как не наступать снова
CoreDNS держат минимум в двух репликах с антиаффинити по нодам. На
kube-dns вешают алерт по пустым endpoints, а не по «доступности
кластера»: пустые endpoints у DNS ловятся за секунды, а деградация
приложений расползается минутами. Правки Corefile катят через
GitOps-репозиторий, чтобы битый конфиг было чем откатить.
Порядок проверки одним списком
# Есть ли вообще 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. На каком шаге ломается, там и причина.
Коротко
- Массовый отказ «всё сломалось» при живых Pod - подозревай DNS.
nslookup kubernetes.defaultиз временного Pod отделяет отказ инфраструктуры от опечатки в имени Service.- Пустые endpoints у
kube-dnsозначают, что реплик CoreDNS нет. - Corefile проверяют, когда реплики подняты, а резолв всё равно молчит.
- Две реплики и алерт на endpoints
kube-dnsзакрывают большую часть таких инцидентов.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс