Como forçar o nginx a resolver o DNS (de um nome de host dinâmico) toda vez que faz proxy_pass?

52

Estou usando o nginx / 0.7.68, executando no CentOS, com a seguinte configuração:

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

O proxy_passé para um registro DNS cujo IP muda frequentemente. O Nginx armazena em cache o endereço IP desatualizado, resultando em uma solicitação para o endereço IP incorreto.

Como posso parar o nginx de armazenar em cache o endereço IP, quando está desatualizado?

xiamx
fonte
olhando através da fonte nginx, parece que o nginx está codificado para resolver em cache o seu TTL - qual é o TTL no seu DNS dinâmico?
26711 lunixbochs
TTL em meus DDNS é 60, o valor padrão de dyndns.com
xiamx
relacionado: serverfault.com/questions/560632/…
nick fox

Respostas:

8

É uma pergunta intrigante e AFAIK que não vai funcionar bem. Você pode tentar usar o módulo upstream e usar as diretivas de failover para ver se ele funciona como um hack.

Edição de 2018: muitas coisas mudaram. Verifique a resposta de @ohaal para obter informações reais sobre isso.

coredump
fonte
11
surpreendentemente, quando mudei para montante, tudo funcionou como esperado. Vou então marcar este como resposta correta
xiamx
11
De acordo com a documentação, há um montante especial serverbandeira resolveque só está disponível na versão comercial (ver nginx.org/en/docs/http/ngx_http_upstream_module.html#server )
omribahumi
11
@gansbrest esse site parece ser algum tipo de site com spam? eu pediria para você remover sua resposta.
28918 majikman
90

A resposta aceita não funcionou para mim no nginx / 1.4.2.

O uso de uma variável proxy_passforça a resolução dos nomes DNS, porque o NGINX trata as variáveis ​​de maneira diferente da configuração estática. Na documentação do NGINXproxy_pass :

O valor do parâmetro pode conter variáveis. Nesse caso, se um endereço for especificado como um nome de domínio, o nome será pesquisado entre os grupos de servidores descritos e, se não encontrado, será determinado usando um resolvedor.

Por exemplo:

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

Nota: Um resolvedor (ou seja, o servidor de nomes a ser usado) DEVE estar disponível e configurado para que isso funcione (e as entradas dentro de um /etc/hostsarquivo não serão usadas em uma pesquisa).

Por padrão, a versão 1.1.9 ou posterior do NGINX armazena respostas usando o valor TTL de uma resposta e um validparâmetro opcional permite que o tempo do cache seja substituído:

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

Antes da versão 1.1.9, o ajuste do tempo de armazenamento em cache não era possível e o nginx sempre armazenava em cache as respostas por 5 minutos. .

ohaal
fonte
isso não forçaria uma consulta DNS em cada solicitação? Isso soa como o desempenho horrível ...
lucascaro
Não, leia a fonte. In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.Adicionei à resposta para maior clareza.
ohaal
13
Depois de passar a maior parte do meu dia nisso - no Ubuntu 12.04 com nginx 1.1.19, o setinterior locationnão funciona corretamente. Cuidado
omribahumi
Esta solução funcionou comigo, no entanto, não consegui encontrar uma referência para o TTL de 5 minutos. 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;
Montaro
4
Nota: para o docker, seu resolvedor de DNS reside em 127.0.0.11; portanto, para desenvolvimento, eu uso o seguinte:resolver 127.0.0.11 [::1]:5353 valid=15s;
Dalibor Filus
9

Há informações valiosas no comentário de gansbrest e na resposta ohaal.

Mas acho importante mencionar este artigo oficial do nginx, publicado em 2016, que explica claramente o comportamento do nginx sobre esse assunto e as possíveis soluções: https://www.nginx.com/blog/dns-service-discovery-nginx-plus /

De fato, precisamos "Definir o nome do domínio em uma variável" e usar a diretiva resolvedor .

no entanto, o uso de uma variável altera o comportamento de reescrita. Talvez você precise usar a diretiva de reescrita, isso depende da sua localização e da configuração do proxy_pass.

PS: teria postado um comentário, mas ainda não há pontos suficientes ...

Jack B.
fonte
1

A resposta de ohaal leva a maioria de nós até lá, mas há um caso em que o resolvedor de DNS não vive em 127.0.0.1 (por exemplo, quando você está em um ambiente em contêiner especial)

Nesse caso, convém alterar o conf nginx para resolver ${DNS_SERVER};. Antes de iniciar o nginx, execute

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
Wonton
fonte
0

Eu hackeei um script para assistir a um fluxo de pastas conf.d para alterações no DNS e recarregar o nginx após a detecção. É uma primeira passagem e certamente pode ser melhorada (na próxima passagem, usarei o nginx -T para analisar os fluxos de dados especificamente. A mesma idéia pode ser usada para as diretivas 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
fonte