Как заставить nginx разрешать DNS (динамического имени хоста) каждый раз при выполнении proxy_pass?


52

Я использую nginx / 0.7.68, работающий на CentOS, со следующей конфигурацией:

server {
    listen       80;
    server_name ***;
    index index.html index.htm index.php default.html default.htm default.php;

    location / {
            root   /***;
            proxy_pass   http://***:8888;
            index  index.html index.htm;
    }
    # where *** is my variables

Это proxy_passDNS-запись, IP-адрес которой часто меняется. Nginx кэширует устаревший IP-адрес, что приводит к запросу на неправильный IP-адрес.

Как я могу остановить nginx от кеширования IP-адреса, если он устарел?


просматривая исходный код nginx, кажется, что nginx жестко запрограммирован для кэширования разрешений для их TTL - что такое TTL на вашем динамическом днс?
— lunixbochs

TTL на моем ddns - 60 с, значение по умолчанию для dyndns.com
— xiamx


Ответы:


8

Это интригующий вопрос и AFAIK, который не будет работать хорошо. Вы можете попробовать использовать вышестоящий модуль и использовать директивы для аварийного переключения, чтобы увидеть, работает ли он как хак.

Редактирование 2018 года: многое изменилось. Проверьте ответ @ohaal, чтобы получить реальную информацию об этом.


1
удивительно, когда я перешел на апстрим, все заработало как положено. Затем я
— отмечу

1
Согласно документации, есть специальный serverфлаг resolveдля апстрима, который доступен только в коммерческой версии (см. Nginx.org/en/docs/http/ngx_http_upstream_module.html#server )
— omribahumi

1
@gansbrest этот сайт, кажется, какой-то спам-сайт? Я бы попросил, чтобы вы удалили свой ответ.
— Маджикман

90

Принятый ответ не работал для меня на nginx / 1.4.2.

Использование переменной приводит к proxy_passповторному разрешению имен DNS, потому что NGINX обрабатывает переменные иначе, чем в статической конфигурации. Из документации NGINXproxy_pass :

Значение параметра может содержать переменные. В этом случае, если в качестве имени домена указан адрес, имя ищется среди описанных групп серверов и, если не найдено, определяется с помощью распознавателя.

Например:

server {
    ...
    resolver 127.0.0.1;
    set $backend "http://dynamic.example.com:80";
    proxy_pass $backend;
    ...
}

Примечание: распознаватель (т. Е. Используемый сервер имен) ДОЛЖЕН быть доступен и настроен для его работы (и записи в /etc/hostsфайле не будут использоваться при поиске).

По умолчанию версия 1.1.9 или более поздние версии кэша NGINX отвечают, используя значение ответа TTL и необязательный validпараметр, позволяющий переопределить время кэширования:

resolver 127.0.0.1 [::1]:5353 valid=30s;

До версии 1.1.9 настройка времени кэширования была невозможна, и nginx всегда кэшировал ответы продолжительностью 5 минут. ,


не вызовет ли это запрос DNS на каждый запрос? это звучит как ужасное представление ...
— lucascaro

Нет, читайте источник. In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.Я добавил это к ответу для ясности.
— ohaal

13
Проведя большую часть моего дня на этом - на Ubuntu 12.04 с nginx 1.1.19, setвнутренняя часть locationне работает должным образом. Осторожно
— омрибахуми

Это решение работало со мной, однако я не мог найти ссылку на 5 минут TTL. nginx.org/en/docs/http/ngx_http_core_module.html#resolver By default, nginx caches answers using the TTL value of a response. An optional valid parameter allows overriding it: resolver 127.0.0.1 [::1]:5353 valid=30s;
— Монтаро

4
Примечание: для докера это DNS-распознаватель, расположенный на 127.0.0.11, поэтому для разработки я использую это:resolver 127.0.0.11 [::1]:5353 valid=15s;
— Dalibor Filus

9

В комментариях гансбреста и устных ответах содержится ценная информация.

Но я думаю, что важно упомянуть об этой официальной статье nginx, опубликованной в 2016 году, в которой четко объясняется поведение nginx по этому вопросу и возможные решения: https://www.nginx.com/blog/dns-service-discovery-nginx-plus /

Нам действительно нужно «установить имя домена в переменной» и использовать директиву resolver .

однако использование переменной изменяет поведение при перезаписи. Возможно, вам придется использовать директиву rewrite, это зависит от вашего местоположения и настройки proxy_pass.

PS: хотел бы оставить комментарий, но пока недостаточно очков ...


1

Ответ ohaal переносит большинство из нас туда, но есть случай, когда DNS-распознаватель не живет по адресу 127.0.0.1 (например, когда вы находитесь в специальной контейнерной среде)

В этом случае вы можете изменить nginx conf на resolver ${DNS_SERVER};. Затем, прежде чем запустить nginx, запустите

export DNS_SERVER=$(cat /etc/resolv.conf |grep -i '^nameserver'|head -n1|cut -d ' ' -f2)
envsubst '${DNS_SERVER} < your_nginx.conf.template > your_nginx.conf

0

Я взломал скрипт, который следит за тем, как папка conf.d направляет изменения dns, и перезагружает nginx при обнаружении. Это первый проход, и, безусловно, его можно улучшить (на следующем проходе я буду использовать nginx -T для конкретного анализа исходящих потоков. Та же идея может быть использована для директив proxy_pass):

#!/bin/bash

get_upstreams() {
  local files=$@
  grep -hEo '(server\s+)[^:;]+' $files | cut -d' ' -f 2
}

resolve_hosts() {
  local hosts=$@
  for h in $hosts; do dig +short $h; done | sort -u
}

watch_dir=$1

[ -d $watch_dir ] || exit 2

upstreams=$(get_upstreams $watch_dir/*)
ips=$(resolve_hosts $upstreams)
if [ ! "$ips" ]; then
  echo "Found no resolvable hosts in $watch_dir files."
fi

host_hash=$(echo $ips | /usr/bin/sha512sum)

echo $host_hash
echo $ips

while [ -d $watch_dir ]; do
  sleep 30
  upstreams=$(get_upstreams $watch_dir/*)
  ips=$(resolve_hosts $upstreams)
  new_hash=$(echo $ips | /usr/bin/sha512sum)
  if [ "$host_hash" != "$new_hash" ]; then
    echo Detected an upstream address change.  $ips
    echo Reloading nginx
    echo $new_hash
    echo $ips
    /sbin/service nginx reload
    host_hash=$new_hash
  fi
done
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.