Как заставить 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-адреса, если он устарел?

xiamx
источник
просматривая исходный код nginx, кажется, что nginx жестко запрограммирован для кэширования разрешений для их TTL - что такое TTL на вашем динамическом днс?
lunixbochs
TTL на моем ddns - 60 с, значение по умолчанию для dyndns.com
xiamx
См. Также stackoverflow.com/questions/26956979/…
Cheekysoft
связанные: serverfault.com/questions/560632/…
Ник Фокс

Ответы:

8

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

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

CoreDump
источник
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 минут. ,

ohaal
источник
не вызовет ли это запрос 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
mushuweasel
источник