Nginx resolver в Docker: обновить IP сервиса
По умолчанию Nginx разрешает имя из proxy_pass один раз при старте и запоминает IP. В Docker контейнер сервиса может пересоздаться с другим адресом, и старый Nginx начнёт отдавать 502 до перезагрузки. Решение — встроенный DNS Docker и proxy_pass через переменную: тогда имя разрешается во время запроса.
Разрешать имя сервиса при каждом запросе
server {
listen 80;
resolver 127.0.0.11 valid=10s ipv6=off;
resolver_timeout 2s;
set $api http://api:8000;
location / {
proxy_pass $api;
proxy_set_header Host $host;
}
}127.0.0.11 — адрес встроенного DNS-сервера Docker; он работает для контейнеров в пользовательской сети, где доступно имя сервиса api. Параметр valid=10s ограничивает время кеширования ответа, ipv6=off убирает лишние AAAA-запросы, если IPv6 в сети не настроен. resolver_timeout не даёт запросу висеть при недоступном DNS.
Без переменной proxy_pass http://api:8000; Nginx пытается разрешить имя при загрузке конфигурации и завершается с ошибкой host not found in upstream, если сервис ещё не запущен. С переменной $api проверка откладывается до запроса, поэтому порядок запуска контейнеров перестаёт быть критичным.
Учтите, что resolver не читает /etc/hosts и не использует системный resolver автоматически: адрес DNS нужно указать явно. В Docker Compose это 127.0.0.11, в Kubernetes — DNS кластера, на хосте — локальный или публичный resolver. Слишком маленький valid увеличивает число DNS-запросов; 10–30 секунд обычно достаточно.
При proxy_pass с переменной Nginx передаёт исходный URI без отдельного rewrite. Если нужно изменить путь, соберите адрес явно, например proxy_pass $api$request_uri;, и проверьте, что схема и порт входят в переменную. Для keepalive к бэкенду переменная не даёт использовать статический upstream; в таком случае применяйте динамическое разрешение через поддерживаемый вашей версией механизм или перезагружайте Nginx после изменения адресов.
Документация: ngx_http_core_module: resolver, Docker DNS.