ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

Nginx DNS в Docker/Kubernetes: resolver, valid и ipv6=off без сюрпризов

Когда backend в Docker или Kubernetes меняет IP, Nginx может продолжать подключаться к «старому» адресу. Разбираем, как работает DNS в upstream, директива resolver, параметр valid, зачем бывает нужен ipv6=off и как диагностировать stale DNS без рестартов.
Nginx DNS в Docker/Kubernetes: resolver, valid и ipv6=off без сюрпризов

Почему DNS в upstream внезапно становится проблемой

Если вы проксируете на сервисы по имени (например, api, backend, svc.namespace) и живёте в мире контейнеров, рано или поздно ловите симптом: Nginx «залип» на старом IP и упорно шлёт трафик не туда. В логах это часто выглядит как всплеск connect() failed, no live upstreams, 502/504, а потом «само проходит» после reload или рестарта.

Снаружи это похоже на сетевую нестабильность, но корень часто в том, как Nginx резолвит DNS для upstream и как он кэширует результат. В Docker и особенно в Kubernetes IP-адреса подов/контейнеров меняются регулярно, и если Nginx не обновляет DNS в рантайме, вы получаете stale DNS — устаревший адрес в памяти воркеров.

Дальше разберём: когда Nginx резолвит имя «один раз», когда умеет пере-резолвить, что реально делает resolver, как работает resolver valid, зачем часто ставят ipv6=off, и как собрать всё в рабочую конфигурацию для Docker и Kubernetes.

Как Nginx резолвит имена: «один раз при старте» против «в рантайме»

В статической инфраструктуре Nginx обычно достаточно модели: резолвим имя при чтении конфигурации (на старте или при reload) и дальше работаем с IP. В динамике контейнеров это становится ловушкой.

Ключевой момент: если вы указываете имя хоста в proxy_pass или в блоке upstream, Nginx не обязан автоматически обновлять его по DNS на каждое соединение. Часто без специальных приёмов он фиксирует результат на момент загрузки конфигурации.

Практически это выглядит так:

  • Имя в upstream как server backend:8080; — обычно резолвится при загрузке конфигурации. Дальше IP живёт в памяти. Если IP сменился — получите stale DNS до reload.

  • Имя в proxy_pass через переменную (например, proxy_pass http://$backend;) — Nginx вынужден резолвить в рантайме, но только если настроен внутренний резолвер директивой resolver.

Отсюда правило: если адреса реально меняются (Docker/Kubernetes, autoscaling, rolling updates), вам почти всегда нужен resolver и такая схема конфигурации, где Nginx делает DNS-запросы в рантайме.

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

Если вы поднимаете Nginx как отдельный шлюз, в большинстве кейсов удобнее держать его на отдельной VDS: проще контролировать DNS, логи, метрики и не завязываться на жизненный цикл приложений в кластере.

Фрагмент конфигурации Nginx с resolver, valid и ipv6=off

Что делает директива resolver и почему без неё «динамики» не будет

resolver задаёт DNS-сервер(а), к которым Nginx будет обращаться, когда ему нужно резолвить имена в рантайме. Без resolver многие сценарии либо не будут работать (ошибки резолвинга), либо будут вести себя не так, как ожидается (не будет пере-резолва).

Базовый пример для Docker:

resolver 127.0.0.11 valid=10s ipv6=off;
resolver_timeout 2s;

Расшифровка:

  • 127.0.0.11 — встроенный DNS Docker (типично для пользовательских bridge-сетей).

  • valid=10s — срок «годности» записи в кэше Nginx (не равен DNS TTL, см. ниже).

  • ipv6=off — отключает AAAA/IPv6, чтобы не ловить задержки/таймауты при «полуживом» IPv6.

  • resolver_timeout — сколько ждать ответ DNS, прежде чем считать запрос неуспешным.

Важно: resolver сам по себе не превращает обычный upstream в сервис-дискавери. Он нужен именно там, где Nginx в принципе выполняет DNS-запросы во время обработки запроса (например, когда proxy_pass использует переменную).

Про resolver valid: это не TTL, но часто важнее TTL

Ожидание «Nginx уважает DNS TTL» — частый источник сюрпризов. У Nginx свой кэш, и параметр valid задаёт, как долго он считает результат резолвинга актуальным в своей памяти. Это может отличаться от TTL у записи.

Ментальная модель такая: valid — это «как часто Nginx будет готов перепроверять DNS». Слишком большое значение увеличивает окно stale DNS (дольше верим старому IP). Слишком маленькое может привести к лишней нагрузке на DNS и сделать DNS скрытой точкой отказа.

Типовые стартовые значения для контейнерной среды:

  • 2–10 секунд — если сервисы пересоздаются часто и важно быстрое восстановление без reload.

  • 10–30 секунд — если инфраструктура стабильнее или вы экономите QPS к CoreDNS/Docker DNS.

Ещё нюанс: отрицательное кэширование. В отдельных ситуациях Nginx может кэшировать неуспешный резолв (NXDOMAIN/timeout) на время valid. Если сервис на мгновение пропал из DNS, большое valid может искусственно растянуть простой.

Почему в Docker/Kubernetes часто нужен ipv6=off

Смысл в предсказуемости. Если IPv6 фактически не настроен end-to-end (маршрутизация отсутствует, AAAA есть, но нерабочие, или попытки подключения дают таймаут), то резолв AAAA и соединения по IPv6 могут вносить задержки и «плавающие» 502/504.

Симптомы, которые часто исчезают после ipv6=off:

  • периодические 502/504 при живом IPv4;

  • длинные паузы перед connect() failed;

  • нестабильная латентность на первых запросах после смены адресов.

Если у вас корректный dual-stack и IPv6 действительно используется, отключать его не нужно. Но для типовых контейнерных сетей это практичная «страховка» от класса проблем «IPv6 объявлен, но не работает».

Рабочий паттерн: динамический DNS для proxy_pass через переменную

Самый простой и предсказуемый способ заставить Nginx пере-резолвить имя — использовать переменную в proxy_pass. Это заставляет Nginx делать DNS-запросы в рантайме и применять кэш по valid.

Пример (в Docker или в Kubernetes, когда вы идёте по DNS-имени сервиса):

server {
    listen 80;

    resolver 127.0.0.11 valid=10s ipv6=off;
    resolver_timeout 2s;

    location / {
        set $upstream_host backend;
        proxy_pass http://$upstream_host:8080;

        proxy_connect_timeout 2s;
        proxy_read_timeout 60s;
    }
}

Компромисс: часть оптимизаций теряется, а если вам нужна сложная балансировка, keepalive-пулы и тонкая политика ретраев, иногда удобнее идти другим путём (см. следующий раздел).

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Если Nginx живёт рядом с сайтом/приложением и вы не хотите управлять ОС и обновлениями, часто удобнее вынести фронт на виртуальный хостинг и держать конфиги в понятной схеме деплоя через reload по изменениям.

Если нужен upstream с балансировкой: что можно и что нельзя

Ожидание «достаточно написать в upstream имя, и Nginx сам будет следить за DNS» обычно не оправдывается. Пример, который чаще всего даёт stale DNS:

upstream app {
    server backend:8080;
}

При смене IP у backend Nginx продолжит использовать старый адрес до перечитывания конфигурации.

Что делать на практике:

  • Стараться проксировать на стабильный endpoint. В Kubernetes это обычно Service (ClusterIP) или балансировщик, где IP стабилен, а смена endpoint-ов происходит ниже уровня Nginx.

  • Не ходить напрямую на IP подов без необходимости: IP меняются, и вы постоянно будете ловить отвал на уровне L4.

  • Если список адресов должен меняться, выбирайте управляемую схему: шаблонизация конфига + безопасный reload, либо внешний сервис-дискавери, который генерирует актуальный список бекендов.

В «чистом Nginx» наиболее универсально: опираться на стабильные endpoints и корректно настроить таймауты/ретраи, вместо попыток сделать из Nginx полноценный discovery-движок.

Docker: какой DNS указывать в resolver

В Docker для пользовательских bridge-сетей встроенный DNS обычно слушает 127.0.0.11. Это хороший кандидат для resolver, потому что он знает имена контейнеров/сервисов в рамках сети.

Минимальный практичный набор:

resolver 127.0.0.11 valid=10s ipv6=off;
resolver_timeout 2s;

Если внутри контейнера используется кастомный /etc/resolv.conf (например, корпоративный DNS), указывать нужно те DNS-серверы, которые реально доступны из того же network namespace, где работает Nginx.

Kubernetes: DNS для Nginx и типовые ловушки

В Kubernetes резолвинг обычно обслуживает CoreDNS. При этом директива resolver не «подхватывает» системный резолвер автоматически: вы жёстко задаёте адрес(а), по которым Nginx будет слать DNS-запросы.

Типовая ловушка: вручную прописали IP CoreDNS, затем сменили кластер или диапазон — и Nginx перестал резолвить. Поэтому на практике часто делают так:

  • не задают resolver статическим IP без необходимости;

  • или параметризуют конфиг (ConfigMap/шаблоны), чтобы IP DNS был управляемым;

  • или проектируют маршрутизацию через стабильные сервисные имена, чтобы частый пере-резолв не требовался.

Кейс «Nginx в поде ходит по DNS на сервис, у которого меняются endpoints» — нормальный. Тогда как раз помогают адекватный valid и короткий resolver_timeout.

Если параллельно вы автоматизируете выпуск сертификатов и завязаны на DNS, полезно держать под рукой материал про автоматизацию wildcard SSL через DNS-01: там часто всплывают схожие вопросы про доступность резолвера и задержки обновления записей.

Диагностика stale DNS: сравнение DNS-ответов и подключений Nginx к upstream

Диагностика: как понять, что это stale DNS и виноват резолвинг

Задача диагностики — ответить на два вопроса: какой IP сейчас отдаёт DNS и какой IP использует Nginx.

Проверяем DNS из окружения Nginx

В контейнере/поде (именно там, где работает Nginx) выполните:

getent hosts backend
nslookup backend

Если утилит нет (часто в минимальных образах), используйте отладочный контейнер/ephemeral container или отдельный диагностический pod.

Проверяем, куда реально пытается подключиться Nginx

Начните с вывода активной конфигурации:

nginx -T

И проверьте, нет ли у вас схемы, фиксирующей адреса на старте (типичный upstream со статическим server name:port без рантайм-резолвинга).

Дальше — активные соединения и попытки:

ss -tnp | grep nginx

Вы увидите реальные IP, к которым Nginx устанавливает TCP-сессии. Сверьте с тем, что показывает DNS. Если не совпадает — у вас stale DNS/кэш на стороне Nginx или промежуточного слоя.

Если видите, что DNS уже отдаёт новый IP, а Nginx продолжает стучаться в старый, почти всегда дело в том, что резолв был сделан «один раз», либо кэш живёт дольше, чем вы думаете (через valid или через схему использования имени).

Тюнинг: как выбрать valid, таймауты и не устроить DNS-шторм

valid — это компромисс: чем меньше значение, тем быстрее реакция на смену IP, но тем выше QPS к DNS и тем сильнее вы зависите от здоровья резолвера.

Для старта в контейнерной среде обычно достаточно:

  • valid=10s как базовое значение;

  • resolver_timeout 2s (иногда 1s), чтобы деградация DNS не «съедала» бюджет таймаутов;

  • короткий proxy_connect_timeout (1–3s), чтобы быстрее отваливаться от мёртвого IP.

Если у вас много воркеров и высокий RPS, слишком агрессивный valid в сочетании с большим числом разных имён upstream может создать заметную нагрузку на CoreDNS/Docker DNS. Следите за метриками резолвера и при необходимости увеличивайте valid или сокращайте число уникальных имён, которые приходится резолвить.

Чек-лист: стабильная схема для Docker/Kubernetes

  • По возможности проксируйте на стабильный endpoint (в Kubernetes чаще всего Service), а не на IP подов.

  • Если нужны динамические адреса — используйте resolver и переменную в proxy_pass, чтобы Nginx резолвил в рантайме.

  • Подберите resolver valid под частоту изменений и допустимое окно «залипания».

  • Если IPv6 не настроен end-to-end — включайте ipv6=off, чтобы убрать задержки на AAAA/IPv6 connect.

  • При инциденте сравнивайте: что отдаёт DNS из этого окружения и куда реально соединяется Nginx (логи, ss).

Итог

Проблемы DNS в Nginx чаще всего всплывают в динамической инфраструктуре: Docker, Kubernetes, автоскейлинг и частые пересоздания. Чтобы не лечить отвалившиеся бэкенды рестартом, осознанно настройте resolver, подберите resolver valid как управляемый кэш, и используйте ipv6=off там, где IPv6 фактически отсутствует. Тогда окно stale DNS становится контролируемым, а поведение прокси — предсказуемым.

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

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

DNSSEC на практике: KSK/ZSK, DS record и безопасный rollover без SERVFAIL OpenAI Статья написана AI (GPT 5)

DNSSEC на практике: KSK/ZSK, DS record и безопасный rollover без SERVFAIL

Разбираем DNSSEC на практике: как устроены KSK/ZSK и DS record, как читать DNSKEY/RRSIG, почему при ошибках появляется SERVFAIL и ...
Linux passthrough (VFIO): включение IOMMU (VT-d/AMD-Vi), проверка и типовые проблемы OpenAI Статья написана AI (GPT 5)

Linux passthrough (VFIO): включение IOMMU (VT-d/AMD-Vi), проверка и типовые проблемы

Практический разбор IOMMU в Linux для PCI passthrough: включаем VT-d/AMD-Vi в BIOS и через grub, проверяем /proc/cmdline и dmesg, ...
HTTP caching headers: Cache-Control, ETag и Last-Modified без боли OpenAI Статья написана AI (GPT 5)

HTTP caching headers: Cache-Control, ETag и Last-Modified без боли

Разбираем, как браузер и CDN кэшируют ответы: Cache-Control, ETag, Last-Modified, revalidation и 304 Not Modified. Даю рабочие про ...