DNS в контейнерных средах представляет собой принципиально иную
парадигму по сравнению с традиционными виртуальными машинами или
физическими серверами. Технология контейнеризации формирует
специфические задачи разрешения имён, обусловленные тремя ключевыми
аспектами: изоляцией, динамической природой среды и требованиями
масштабируемости.
Изоляция означает, что каждый контейнер существует в собственном сетевом пространстве имён с индивидуальной DNS-конфигурацией, что требует специальных механизмов для обеспечения связности. Динамичность подразумевает, что сервисы постоянно создаются и уничтожаются, IP-адреса меняются, а традиционные статические DNS-записи становятся неэффективными. Масштабирование - необходимость обработки
тысяч DNS-запросов в секунду без единых точек отказа, что требует
распределённых и отказоустойчивых архитектур.
В отличие от традиционных сред, где DNS-конфигурация наследуется от хоста,
контейнерные платформы создают собственные DNS-экосистемы с
автоматическим обнаружением сервисов, динамическим обновлением записей и сложными политиками разрешения имен. Эта сложность усугубляется необходимостью поддержки как “внутрикластерного”, так и внешнего разрешения имён, обеспечения производительности при высоких нагрузках и интеграции с существующими корпоративными DNS-инфраструктурами
Каждая контейнерная платформа — Docker, Podman, Kubernetes — реализует
собственную DNS-архитектуру со специфическими особенностями,
преимуществами и подводными камнями. Понимание этих различий критически важно для построения надежных и производительных контейнерных инфраструктур. С чем мы и попробуем разобраться в этой статье.
Это четвертая статья в цикле разбора механизмов разрешения имен и работы DNS. Предыдущие три можно найти по этим ссылкам:
Часть 1
Часть 2
Часть 3
А теперь перейдем к контейнерам, где последовательно рассмотрим платформы Docker, Podman и Kubernetes.
Docker: эволюция DNS от простоты к сложности
Docker
использует встроенный DNS-прокси для каждой пользовательской сети, что
обеспечивает автоматическое разрешение имен контейнеров. Этот прокси
работает по адресу 127.0.0.11 и выполняет две основные функции:
разрешает имена контейнеров в рамках одной сети и пересылает внешние
запросы на DNS-серверы, настроенные в daemon.json или resolv.conf хоста.
Архитектура DNS в rootful режиме
В классическом rootful режиме Docker создает стандартную конфигурацию DNS для контейнеров:
# Типичный /etc/resolv.conf в контейнере
nameserver 127.0.0.11
options ndots:0
DNS-прокси Docker принимает запросы от контейнеров и обрабатывает их следующим образом:
- внутренние имена: разрешает имена контейнеров и сервисов в рамках пользовательских сетей Docker
- внешние имена: пересылает запросы на DNS-серверы, указанные в конфигурации демона или хостовом resolv.conf
- область действия: работает во всех типах сетей Docker, включая bridge-сеть по умолчанию, но с разной функциональностью:
- В пользовательских сетях предоставляет встроенное разрешение имен контейнеров
- В default bridge-сети автоматическое разрешение имен контейнеров НЕ работает; доступен только устаревший механизм --link, который добавляет записи в /etc/hosts
Глобальные настройки Docker можно задать в /etc/docker/daemon.json:
{
"dns": ["<dns1>", "<dns2>"],
"dns-opts": ["use-vc", "rotate"],
"dns-search": ["example.com"]
}
Особенности rootless режима
Rootless
Docker кардинально меняет сетевую архитектуру. Вместо прямого доступа к
сетевому стеку хоста используется user namespace с изолированной
сетевой средой. Основные отличия включают:
Сетевой стек: используется slirp4netns или RootlessKit для эмуляции сетевого стека в пользовательском пространстве.
DNS-конфигурация: контейнеры получают DNS-сервер 10.0.2.3 вместо традиционного 127.0.0.11.
```bash
# В rootless контейнере
nameserver 10.0.2.3
```
Проблемы
производительности: rootless режим показывает значительно худшую
сетевую производительность из-за накладных расходов на трансляцию
пакетов.
Проброс source IP: по умолчанию source
IP адреса не передаются корректно, что критично для сетевых сервисов
вроде DNS или прокси. Для решения требуется специальная конфигурация:
```bash
# В ~/.config/systemd/user/docker.service.d/override.conf
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
```
Известные проблемы Docker DNS
Конфликт с systemd-resolved: автоматическая подстановка 127.0.0.53 может нарушить работу DNS в контейнерах.
Решение: Настройка /etc/docker/daemon.json с явными DNS-серверами:
{
"dns": ["<dns1>", "<dns2>"],
"dns-opts": [],
"dns-search": []
}
Проблемы с VPN: DNS-запросы могут не проходить через VPN-туннель, что приводит к утечкам DNS.
Решение: Принудительная маршрутизация DNS через VPN:
# Использование VPN DNS-серверов
docker run --dns 10.8.0.1 --dns-search vpn.local myimage
# Или также глобально в daemon.json для всех контейнеров
{
"dns": ["10.8.0.1"] # IP DNS-сервера в VPN сети
}
Устаревшие копии resolv.conf: изменения хостового файла не влияют на запущенные контейнеры до их перезапуска.
https://github.com/moby/moby/issues/23910
# Вариант 1: Перезапуск контейнеров после изменения хостового DNS
docker restart $(docker ps -q)
# Вариант 2: Монтирование resolv.conf как volume (обновления в реальном времени)
docker run -v /etc/resolv.conf:/etc/resolv.conf:ro myimage
# Вариант 3: Использование --dns флага с явными серверами, или также указанием в daemon.json
Podman: от CNI к современному Netavark
Podman
представляет наиболее динамичную эволюцию DNS-архитектур в контейнерном
мире, совершив переход от устаревшего CNI к современному решению
Netavark/aardvark-dns. Эта трансформация отражает общую тенденцию
индустрии к более производительным и функциональным DNS-решениям.
Архитектура CNI (Legacy режим)
До
версии 4.0 Podman использовал CNI (Container Network Interface) с
плагином dnsname для разрешения имен контейнеров. Эта архитектура
включала:
- dnsmasq как DNS-сервер: для каждой CNI-сети создавался отдельный экземпляр dnsmasq
- файловое хранилище записей: DNS-записи хранились в файлах в директории /run/containers/cni/dnsname или $XDG_RUNTIME_DIR/containers/cni/dnsname
- ограниченную функциональность: поддерживалось только базовое разрешение A-записей без PTR и других типов записей
Конфигурация CNI сети с dnsname выглядела следующим образом:
{
"cniVersion": "0.4.0",
"name": "cni-bridge-network",
"plugins": [
{
"type": "bridge",
"bridge": "cni0"
},
{
"type": "dnsname",
"domainName": "foobar.com",
"capabilities": {
"aliases": true
}
}
]
}
Максимально подробно про работу Podman с бэкендом CNI описано в этой статье на Хабре.
Основными
недостатками CNI подхода были низкая производительность dnsmasq при
высоких нагрузках, отсутствие поддержки современных DNS-функций,
сложность конфигурации и обслуживания и ограниченная интеграция с
современными контейнерными оркестраторами.
Переход к Netavark и aardvark-dns
Начиная
с Podman 4.0 по умолчанию используется новый сетевой стек Netavark с
DNS-сервером aardvark-dns. Это революционное изменение принесло
множество улучшений:
- Aardvark-dns как авторитетный сервер: написанный на Rust авторитетный DNS-сервер для A/AAAA записей контейнеров
- поддержка PTR-записей: автоматическое создание обратных DNS-записей для упрощения диагностики
- улучшенная производительность: значительно более высокая производительность по сравнению с dnsmasq
- лучшая поддержка IPv6: особенно в области NAT и port forwarding
Типичная конфигурация Netavark сети:
{
"name": "mynetwork",
"id": "3977b0c90383b8460b75547576dba6ebcf67e815f0ed0c4b614af5cb329ebb83",
"driver": "bridge",
"network_interface": "podman1",
"created": "2022-09-06T12:08:12.853219229Z",
"subnets": [{
"subnet": "10.89.0.0/24",
"gateway": "10.89.0.1"
}],
"ipv6_enabled": false,
"internal": false,
"dns_enabled": true,
"ipam_options": {
"driver": "host-local"
}
}
В
отличие от CNI, Netavark предоставляет нативную интеграцию с container
runtime, автоматическое управление DNS-записями при создании и удалении
контейнеров и современные возможности мониторинга и отладки.
# Проверить используемый сетевой бэкенд
podman info --format '{{.Host.NetworkBackend}}'
DNS в rootless Podman
Rootless
режим Podman формирует особые требования для DNS-архитектуры, поскольку
отсутствуют привилегии для создания полноценных bridge-сетей.
slirp4netns: традиционный rootless networking
В классическом rootless режиме с slirp4netns Podman создаёт изолированную сетевую среду:
# DNS в rootless контейнере (slirp4netns)
nameserver 10.0.2.3
options edns0 trust-ad
search
Архитектура DNS в slirp4netns:
• DNS-сервер 10.0.2.3 — встроенный DNS-прокси slirp4netns
• Автоматическая трансляция DNS-запросов через user-mode NAT
• Изолированное пространство имён с собственным routing table
• Предсказуемая, но ограниченная сетевая конфигурация
Ключевые ограничения slirp4netns:
• Невозможность использования Netavark в полном объёме из-за отсутствия привилегий
• Дополнительный overhead на трансляцию пакетов в user-space
• Проблемы с разрешением локальных имён хоста
• Ограниченная поддержка IPv6 DNS-запросов
• Производительность значительно хуже native networking
Революция с pasta/passt: новый стандарт rootless DNS
Начиная
с Podman 5.3, pasta/passt становится стандартным сетевым бэкендом для
новых установок во многих дистрибутивах, вытесняя slirp4netns,
кардинально изменяя подход к DNS.
# DNS в rootless контейнере (pasta/passt)
nameserver 192.168.1.1 # Реальный DNS хоста
nameserver <dns1> # Upstream DNS с хоста
search home.local # Search domains с хоста
options edns0 trust-ad
Pasta
(Pack A Subtle Tap Abstraction) работает на основе passt (Plug A Simple
Socket Transport) — современного сетевого драйвера, который
обеспечивает “quasi-native” сетевую связность для виртуальных машин и
контейнеров в пользовательском режиме без требования привилегий.
Ключевое
отличие от slirp4netns — pasta не использует Network Address
Translation (NAT) по умолчанию и копирует IP-адреса с основного
интерфейса хоста в namespace контейнера.
Translation layer
architecture: pasta реализует слой трансляции между виртуальным Layer-2
сетевым интерфейсом и нативными Layer-4 сокетами (TCP, UDP, ICMP) на
хосте. Это создаёт иллюзию, что процессы приложений в контейнере
выполняются на локальном хосте с сетевой точки зрения.
Встроенные
сетевые сервисы: pasta включает собственные реализации ARP, DHCP, NDP, и
DHCPv6, предоставляющие контейнеру сетевую конфигурацию, максимально
близкую к нативной конфигурации хоста.
Архитектурные улучшения:
- Использует IP-адрес хоста вместо предопределённого container IP (10.0.2.x)
- Использует имя сетевого интерфейса с хоста вместо стандартного tap0
- Использует gateway адрес с хоста вместо собственного gateway с NAT
Ключевые преимущества pasta для DNS:
Прямое наследование DNS-конфигурации: pasta копирует /etc/resolv.conf
хоста в контейнер, обеспечивая идентичную DNS-конфигурацию. Это
кардинально отличается от slirp4netns, который использует собственный
DNS-прокси.
Встроенные DNS-сервисы: pasta включает собственные реализации:
- DHCP-сервер для автоматической настройки DNS
- DNS forwarder для эффективной пересылки запросов
- ARP resolver для разрешения локальных имён
- NDP (IPv6) для modern dual-stack environments
Quasi-native DNS resolution: pasta имитирует выполнение DNS-запросов напрямую на хосте, устраняя промежуточные proxy layers.
Управление DNS в Netavark
Netavark предоставляет современные возможности управления DNS, которые по-разному взаимодействуют с rootless сетевыми бэкендами.
В rootful режиме (полная функциональность Netavark)
# Создание сети с кастомными DNS-настройками
podman network create --driver bridge \
--dns <dns2> \
--dns <dns1> \
--dns-search company.local \
custom-dns-net
# Динамическое обновление DNS для существующей сети
podman network update custom-dns-net --dns-add 9.9.9.9
podman network update custom-dns-net --dns-search-add internal.local
# Доступ к aardvark-dns с хоста
nslookup webapp.dns.podman 10.89.0.1
В rootless режиме с slirp4netns
slirp4netns не поддерживает полную функциональность Netavark. DNS-настройки ограничены:
• Невозможность создания кастомных bridge-сетей с DNS-настройками
• Aardvark-dns недоступен из-за изоляции user namespace
• DNS-конфигурация определяется исключительно slirp4netns
# Ограниченные возможности в slirp4netns режиме
podman run --dns <dns1> --dns-search company.local alpine
# DNS настройки применяются к /etc/resolv.conf, но без aardvark-dns
В rootless режиме с pasta/passt
Pasta обеспечивает расширенную совместимость с Netavark:
• Поддержка кастомных DNS-настроек через pasta options
• Частичная поддержка network management команд
• Автоматическая интеграция с хостовой DNS-конфигурацией
# Эмуляция slirp4netns поведения в pasta
podman run --network pasta:-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3 alpine
# Кастомизация DNS в pasta режиме
podman run --dns <dns2> --dns-search internal.local \
--network pasta:--map-guest-addr=172.16.1.100 alpine
Известные проблемы Podman DNS
Aardvark-DNS не может разрешить имена
Сбои разрешения имен в Podman 4.x с Netavark/aardvark-dns.
https://access.redhat.com/solutions/7094253
Решается обновлением до последней версии и перенастройкой сетей.
Долгие задержки при разрешении DNS между контейнерами
DNS-запросы между peer pods зависали на длительное время в версиях aardvark-dns 1.1.x-1.5.x.
https://github.com/containers/podman/issues/15972
Исправлено в версиях 1.6+
DNS resolution по умолчанию использует 8.8.8.8 в rootful режиме
Podman rootful CNI DNS resolution неправильно настраивал DNS-серверы по умолчанию.
https://github.com/containers/podman/issues/10570
Решено в GitHub Issue containers/podman#10570
DNS настройки игнорируются в podman run
DNS параметры, заданные в podman run, не применялись к /etc/resolv.conf в ранних версиях Netavark.
https://github.com/containers/netavark/issues/855
Исправлено в версиях aardvark-dns 1.6.0+ и netavark 1.6.0+
Podman
демонстрирует наиболее активную эволюцию DNS-архитектур среди
контейнерных платформ, с успешным переходом от CNI к Netavark в rootful
режиме и революционным внедрением pasta/passt для rootless containers.
Большинство критических DNS-проблем решены в последних версиях, что
делает Podman привлекательной альтернативой Docker для production
deployment с хорошей производительностью DNS и расширенными
возможностями управления.
Kubernetes: сложность корпоративного DNS
Kubernetes представляет наиболее сложную и функциональную DNS-архитектуру среди контейнерных платформ. Центральным компонентом является CoreDNS — модульный DNS-сервер, обслуживающий домены *.cluster.local и пересылающий остальные запросы на внешние DNS-серверы.
Базовая архитектура CoreDNS
CoreDNS развертывается как Deployment в namespace kube-system и доступен через Service с именем kube-dns:
# Типичная DNS-конфигурация в поде
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
IP-адрес 10.96.0.10 соответствует ClusterIP сервиса kube-dns:
$ kubectl get svc -n kube-system -l k8s-app=kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP
CoreDNS настраивается через ConfigMap с Corefile — конфигурационным файлом, определяющим поведение DNS:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . <dns1> <dns2> {
except cluster.local in-addr.arpa ip6.arpa
}
cache 30
loop
reload
loadbalance
}
Основные плагины CoreDNS:
- kubernetes: обрабатывает запросы для cluster.local
- forward: пересылает внешние запросы на upstream DNS
- cache: кэширует ответы на 30 секунд
- health: предоставляет health checks на порту 8080
- prometheus: экспортирует метрики на порту 9153
Kubernetes
поддерживает несколько DNS Policy для управления разрешением имен в
подах. Политики - это параметр конфигурации, который определяет, откуда и
как поды получают настройки DNS для разрешения имен. Это критически
важная настройка, влияющая на способность подов обращаться как к
кластерным сервисам, так и к внешним ресурсам.
- ClusterFirst (по умолчанию): использует кластерный DNS (CoreDNS).
- ClusterFirstWithHostNet: комбинирует кластерный DNS с hostNetwork.
- Default: наследует DNS-конфигурацию хоста.
- None: требует ручной настройки DNS.
Пример пода с ручной настройкой DNS для dnsPolicy: None:
spec:
dnsPolicy: "None"
dnsConfig:
nameservers:
- <dns1>
- <dns2>
searches:
- ns1.svc.cluster.local
- my.dns.search.suffix
options:
- name: ndots
value: "2"
- name: edns0
Диагностика DNS проблем в Kubernetes
Kubernetes предоставляет специальные инструменты для диагностики DNS:
# Развертывание диагностического пода
kubectl apply -f https://k8s.io/examples/admin/dns/dnsutils.yaml
# Создаёт pod 'dnsutils' с nslookup, dig, host и другими DNS-утилитами
# Тестирование разрешения кластерных имен
kubectl exec -i -t dnsutils -- nslookup kubernetes.default
# Должен вернуть ClusterIP сервиса kubernetes (обычно 10.96.0.1)
# Если не работает — проблема с CoreDNS или kube-dns Service
# Проверка внешних имен
kubectl exec -i -t dnsutils -- nslookup google.com
# Проверяет способность CoreDNS пересылать запросы на внешние DNS
# Если не работает — проблема с upstream DNS или network policies
Типичные ошибки, известные проблемы и решения
SERVFAIL: CoreDNS недоступен или перегружен — проверить статус подов CoreDNS.
# определить DNS-компоненты
kubectl get pods -n kube-system -l k8s-app=coredns
kubectl get pods -n kube-system -l k8s-app=kube-dns
# проверить статус сервиса DNS
kubectl get svc -n kube-system -l k8s-app=kube-dns
kubectl get svc -n kube-system -l k8s-app=coredns
# Проверка логов
kubectl logs -n kube-system -l k8s-app=coredns
NXDOMAIN: неполные или устаревшие DNS-записи — проверить конфигурацию сервисов.
kubectl get endpoints <service-name> -n <namespace>
kubectl describe service <service-name> -n <namespace>
kubectl get pods -n <namespace> -l <selector-from-service>
Медленные ответы: возможно это проблемы с ndots или перегрузка CoreDNS.
# Измерить время DNS-запроса
kubectl exec dnsutils -- sh -c "time nslookup google.com" 2>&1
# Проверить настройки resolv.conf (ndots)
kubectl exec dnsutils -- cat /etc/resolv.conf
Поды с hostNetwork: true используют сетевое пространство имен хоста, что приводит к проблемам с DNS.
Суть проблемы: под не может разрешать кластерные сервисы, так как использует хостовую DNS-конфигурацию.
Решение: использование dnsPolicy: ClusterFirstWithHostNet:
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
Альтернативное решение - iptables правила для перенаправления трафика:
# Перенаправление DNS-трафика на ClusterIP
iptables -t nat -A OUTPUT -p tcp --dport 53 -d external-ip \
-j DNAT --to-destination cluster-ip:53
Одна
из ключевых проблем Kubernetes DNS — параметр ndots:5, который
заставляет резолвер проверять неполные имена (содержащие меньше чем 5
точек) сначала среди внутренних доменов кластера, и только потом делать
запрос на внешний DNS:
# При запросе www.google.com с ndots:5 происходят попытки:
www.google.com.default.svc.cluster.local
www.google.com.svc.cluster.local
www.google.com.cluster.local
www.google.com. # только потом прямой запрос
Это приводит к множественным DNS-запросам и значительным задержкам.
Решения включают:
Использование FQDN с точкой: www.google.com. для пропуска поисковых доменов.
Настройка ndots для отдельных подов:
spec:
dnsConfig:
options:
- name: ndots
value: "1"
Оптимизация CoreDNS для улучшения производительности и отказоустойчивости
CoreDNS
в Kubernetes часто становится узким местом при большом количестве
сервисов и внешних DNS-запросов. Понимание тонкостей настройки CoreDNS
становится критически важным для поддержания стабильности production
кластеров.
Кэширование
По умолчанию плагин cache установлен на 30 секунд. Для крупных кластеров можно увеличить TTL и размеры кэша:
cache {
success 10000 60 # до 10k успешных ответов, TTL 60s
denial 10000 15 # NXDOMAIN до 10k, TTL 15s
}
Success cache: увеличение до 60-120 секунд снижает нагрузку на upstream на 70-80%
Denial cache: NXDOMAIN должны кэшироваться меньше (10-15 секунд)
Prefetch mechanism: автоматическое обновление записей за 10% до истечения TTL.
Политика форвардинга
В плагине forward можно выбирать стратегию обращения к upstream DNS:
random — распределяет запросы равномерно по серверам (улучшает балансировку);
sequential — всегда опрашивает сервера в порядке списка (по умолчанию).
Для кластеров с несколькими внешними DNS рекомендуется использовать random:
forward . <dns1> <dns2> {
policy random
}
Протокольная оптимизация
Директива prefer_udp снижает overhead при большом числе коротких запросов.
forward . <dns1> <dns2> {
prefer_udp
max_concurrent 1000
}
Указание force_tcp может быть полезно, если есть проблемы с фрагментацией UDP пакетов (часто в облаках и VPN).
Масштабирование
Горизонтальное
масштабирование CoreDNS — не опция, а необходимость для production
кластеров. Типичная конфигурация с 1-2 репликами совершенно неадекватна
при нагрузке в десятки тысяч DNS-запросов в секунду. Каждая реплика
CoreDNS способна обрабатывать 5000-10000 QPS до деградации
производительности, а в кластере на 100+ нод и 1000+ подов пиковая
нагрузка легко достигает 50000-100000 QPS, особенно во время:
- Массовых deployments, когда сотни новых подов одновременно начинают разрешать DNS-имена сервисов
- Rolling updates приложений, создающих временные пики DNS-активности
- Автомасштабирования приложений на основе HPA
- Startup burst — когда приложения делают множество DNS-запросов при инициализации
Недостаточное количество CoreDNS реплик приводит к:
- Высокой латентности DNS (>100ms вместо <10ms)
- Timeouts и SERVFAIL ответам
- Перегрузке CPU и memory на CoreDNS подах
- Каскадным отказам приложений, которые не могут обнаружить зависимые сервисы
Ручное масштабирование CoreDNS
Простейший
способ увеличить количество реплик CoreDNS:Критически важно
распределить CoreDNS реплики по разным нодам для обеспечения
отказоустойчивости. Если все реплики CoreDNS находятся на одной ноде, ее
отказ приведет к полному DNS outage.
# Anti-affinity для распределения по нодам
kubectl patch deployment coredns -n kube-system -p '
{
"spec": {
"template": {
"spec": {
"affinity": {
"podAntiAffinity": {
"preferredDuringSchedulingIgnoredDuringExecution": [{
"weight": 100,
"podAffinityTerm": {
"labelSelector": {
"matchLabels": {"k8s-app": "kube-dns"}
},
"topologyKey": "kubernetes.io/hostname"
}
}]
}
}
}
}
}
}'
При
масштабировании критически важно настроить PodDisruptionBudget для
предотвращения одновременного удаления слишком многих CoreDNS реплик.
NodeLocal DNSCache: современное решение
NodeLocal
DNSCache представляет современный подход к оптимизации DNS в
Kubernetes. Это DaemonSet, который запускает DNS-кэш на каждой ноде
кластера.
Преимущества NodeLocal DNSCache:
- Снижение
среднего времени DNS-разрешения (Поды обращаются к локальному кэшу на
той же ноде вместо прохождения через kube-dns Service) - Устранение
conntrack записей для DNS-соединений (Прямое обращение к локальному
кэшу избегает iptables DNAT правил и connection tracking) - Прямое
обращение к Cloud DNS, минуя kube-dns для внешних запросов (Это снижает
нагрузку на центральный CoreDNS и улучшает латентность.) - Автоматическое наследование stub domains и upstream nameservers
Архитектура: поды обращаются к DNS-кэшу на той же ноде, избегая iptables DNAT правил и connection tracking.
Конфигурация NodeLocal DNSCache:
apiVersion: v1
kind: ConfigMap
metadata:
name: node-local-dns
namespace: kube-system
data:
Corefile: |
cluster.local:53 {
errors
cache {
success 9984 30
denial 9984 5
}
reload
loop
bind 169.254.20.25 10.96.0.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
health 169.254.20.25:8080
}
NodeLocal
DNSCache работает на специальном link-local IP-адресе 169.254.20.25 на
каждой ноде. Поды автоматически настраиваются для использования этого
адреса как primary nameserver.
Кастомизация для корпоративных сред
Корпоративные
окружения предъявляют особые требования к DNS-инфраструктуре:
интеграция с существующими системами разрешения имён, разделение
внутренних и внешних зон, соблюдение политик безопасности и compliance
требований. CoreDNS предоставляет гибкие механизмы для реализации этих
требований через stub domains, split-horizon DNS, network policies и
encrypted DNS.
CoreDNS поддерживает гибкую настройку upstream серверов и stub domains для интеграции с корпоративными DNS-инфраструктурами:
# Конфигурация для корпоративного DNS
consul.local:53 {
errors
cache 30
forward . 10.150.0.1
}
# Принудительное использование конкретного upstream
forward . 172.16.0.1 # вместо /etc/resolv.conf
Split-horizon DNS: различные ответы для внутренних и внешних запросов:
# Пример split-brain конфигурации в CoreDNS
internal.company.com:53 {
hosts {
192.168.1.10 api.internal.company.com
fallthrough
}
forward . 192.168.1.1 # внутренний DNS
}
external.company.com:53 {
hosts {
203.0.113.10 api.external.company.com
fallthrough
}
forward . <dns1> # внешний DNS
}
Ограничение доступа к DNS-серверам: использование network policies.
Kubernetes
Network Policies позволяют реализовать fine-grained контроль доступа к
CoreDNS, ограничивая, какие поды могут выполнять DNS-запросы и откуда
CoreDNS может получать запросы.
Пример базовой NetworkPolicy для защиты CoreDNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
meta
name: coredns-network-policy
namespace: kube-system
spec:
podSelector:
matchLabels:
k8s-app: kube-dns
policyTypes:
- Ingress
ingress:
# Разрешить DNS-запросы от всех подов в кластере
- from:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# Разрешить health-checks (для liveness/readiness проб)
- from:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 8080 # health
- protocol: TCP
port: 8181 # ready
# Разрешить Prometheus метрики от мониторинга
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 9153
Мониторинг и логирование DNS
Эффективный
мониторинг CoreDNS критически важен для обеспечения стабильности всего
Kubernetes кластера. Проблемы с DNS могут привести к каскадным отказам,
когда сервисы не могут обнаруживать друг друга, что делает систему
мониторинга первой линией защиты от серьезных инцидентов.
CoreDNS предоставляет богатые возможности мониторинга:
Prometheus метрики: доступны на порту 9153 для каждого пода CoreDNS.
Ключевые метрики включают:
- Время ответа DNS
- Процент успешных запросов
- Cache hit ratio
- Количество upstream запросов
Логирование запросов:
добавление плагина log в Corefile для детального логирования:
Corefile: |
.:53 {
log # добавить для логирования всех запросов
errors
# остальная конфигурация
}
Health checks и автоматическое восстановление
CoreDNS предоставляет два endpoint для health checking:
Health endpoint (/health:8080)
# пример liveness probe
livenessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
Ready endpoint (/ready:8181)
# пример readiness probe
readinessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
Интеграция с облачными платформами
Kubernetes
DNS-архитектура в production среде редко существует изолированно.
Интеграция с облачными DNS-сервисами, системами автоматического
управления записями и service mesh решениями создаёт комплексную
экосистему, обеспечивающую высокую доступность, безопасность и
автоматизацию DNS-управления.
Cloud DNS интеграция
Использование
управляемых DNS-сервисов облачных провайдеров. Google Cloud DNS, Amazon
Route 53 и Azure DNS предоставляют высокодоступные и масштабируемые
решения для внешних запросов.
External DNS
External
DNS выводит управление DNS в Kubernetes на новый уровень, автоматически
создавая и обновляя DNS-записи на основе Kubernetes ресурсов. Это
устраняет необходимость ручного управления DNS и обеспечивает полную
синхронизацию состояния кластера с внешними DNS-провайдерами.
Архитектура и принцип работы
External DNS работает как controller, который:
- Мониторит Kubernetes ресурсы (Service, Ingress)
- Извлекает DNS-аннотации из ресурсов
- Синхронизирует записи с внешним DNS-провайдером через API
- Поддерживает актуальность записей при изменениях
Service mesh интеграция
Istio
использует Envoy proxies для перехвата всего трафика, включая
DNS-запросы. В такой архитектуре DNS становится частью service mesh
control plane.
Архитектура Istio DNS:
- Sidecar Envoy перехватывает DNS-запросы от приложений
- Pilot предоставляет service registry через xDS API
- DNS proxy в Envoy разрешает имена на основе Istio service registry
- Внешние домены по-прежнему разрешаются через CoreDNS
Практические рекомендации и выводы
Рекомендации по платформам
Если вы используете Docker — обратите внимание на различия между rootful и rootless режимами.
В rootful режиме
- мониторьте стабильность DNS-прокси 127.0.0.11
- настройте альтернативные DNS-серверы в daemon.json
- при использовании systemd-resolved создайте симлинк на /run/systemd/resolve/resolv.conf вместо stub-resolver
В rootless режиме
- учитывайте ограничения производительности из-за slirp4netns
- учитывайте, что DNS-сервер 10.0.2.3 является частью изолированного сетевого стека
Если переходите на современный Podman
- мигрируйте с CNI на Netavark/aardvark-dns для улучшения производительности.
- Используйте возможности динамического управления DNS через podman network update.
В rootless режиме
- учитывайте ограничения slirp4netns
- держите в голове, что Podman 5.3+ использует pasta по умолчанию, но при проблемах с pasta можно вернуться к slirp4netns через containers.conf
Если используете Kubernetes
- обязательно рассмотрите внедрение NodeLocal DNSCache для снижения задержек.
- оптимизируйте ndots для приложений, делающих много внешних запросов.
- настройте правильную dnsPolicy для подов с hostNetwork.
- мониторьте производительность CoreDNS и планируйте масштабирование
Заключение
DNS в контейнерных средах представляет собой многослойную архитектуру со значительными различиями между платформами. Docker обеспечивает простоту использования с встроенным DNS-прокси, но требует особого внимания в rootless режиме. Podman демонстрирует активную эволюцию от устаревшего CNI к современному Netavark с aardvark-dns, обеспечивая лучшую
производительность и функциональность. Kubernetes предлагает наиболее
сложную и мощную DNS-систему с CoreDNS, но требует глубокого понимания
особенностей конфигурации и оптимизации.
Контейнерные DNS-архитектуры представляют собой быстро развивающуюся область с постоянными улучшениями производительности, безопасности и
функциональности. Понимание особенностей каждой платформы и применение современных практик обеспечивает надежную и масштабируемую DNS-инфраструктуру для контейнерных приложений. Инвестиции в правильную архитектуру DNS окупаются через улучшение производительности приложений, снижение операционных затрат и повышение общей надежности системы.