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?


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


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.


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. .


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 ...


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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.