Come forzare nginx a risolvere DNS (di un nome host dinamico) ogni volta che si esegue proxy_pass?


52

Sto usando nginx / 0.7.68, in esecuzione su CentOS, con la seguente configurazione:

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_passun record DNS il cui IP cambia frequentemente. Nginx memorizza nella cache l'indirizzo IP obsoleto, generando una richiesta all'indirizzo IP errato.

Come posso impedire a nginx di memorizzare nella cache l'indirizzo IP, quando è obsoleto?


guardando attraverso la sorgente di nginx, sembra che nginx sia hardcoded per memorizzare nella cache il loro TTL - qual è il TTL sul tuo dns dinamico?
— lunixboch,

TTL sul mio ddns è 60s, il valore predefinito di dyndns.com
— xiamx,


Risposte:


8

È una domanda intrigante e AFAIK che non funzionerà bene. Puoi provare a utilizzare il modulo upstream e utilizzare le direttive per il failover per vedere se funziona come un hack.

Modifica del 2018: molte cose sono cambiate. Controlla la risposta di @ohaal per ottenere informazioni reali su questo.


1
sorprendentemente quando sono passato a monte, tutto ha funzionato come previsto.
— Segnerò

1
Secondo la documentazione, c'è un serverflag upstream speciale resolvedisponibile solo nella versione commerciale (vedi nginx.org/en/docs/http/ngx_http_upstream_module.html#server )
— omribahumi

1
@gansbrest quel sito sembra essere una specie di sito di spam? ti chiederei di rimuovere la tua risposta.
— Majikman,

90

La risposta accettata non ha funzionato per me su nginx / 1.4.2.

L'uso di una variabileproxy_pass per forzare la nuova risoluzione dei nomi DNS perché NGINX tratta le variabili in modo diverso alla configurazione statica. Dalla documentazione NGINXproxy_pass :

Il valore del parametro può contenere variabili. In questo caso, se un indirizzo viene specificato come nome di dominio, il nome viene cercato tra i gruppi di server descritti e, se non trovato, viene determinato utilizzando un resolver.

Per esempio:

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

Nota: un resolver (ovvero il server dei nomi da utilizzare) DEVE essere disponibile e configurato per funzionare (e le voci all'interno di un /etc/hostsfile non verranno utilizzate in una ricerca).

Per impostazione predefinita, la versione 1.1.9 o successive della cache NGINX risponde utilizzando il valore TTL di una risposta e un validparametro facoltativo consente di sovrascrivere il tempo della cache:

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

Prima della versione 1.1.9, l'ottimizzazione del tempo di memorizzazione nella cache non era possibile e nginx memorizzava sempre nella cache le risposte per la durata di 5 minuti. .


questo non imporrebbe una query DNS su ogni singola richiesta? sembra una performance terribile ...
— Lucascaro

No, leggi la fonte. In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.L'ho aggiunto alla risposta per chiarezza.
— ohaal,

13
Dopo aver trascorso gran parte della mia giornata su questo - su Ubuntu 12.04 con nginx 1.1.19, setdentro locationnon funziona correttamente. Attenzione
— omribahumi,

Questa soluzione ha funzionato con me, tuttavia non sono riuscito a trovare un riferimento per il 5 minuti TTL. nginx.org/it/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: per docker, il suo resolver DNS risiede al 127.0.0.11, quindi per lo sviluppo, io uso questo:resolver 127.0.0.11 [::1]:5353 valid=15s;
— Dalibor Filus

9

Ci sono informazioni preziose nel commento gansbrest e nella risposta ohaal.

Ma penso che sia importante menzionare questo articolo ufficiale di nginx, pubblicato nel 2016, che spiega chiaramente il comportamento di nginx su questo argomento e le possibili soluzioni: https://www.nginx.com/blog/dns-service-discovery-nginx-plus /

Dobbiamo davvero "Impostare il nome di dominio in una variabile" e utilizzare la direttiva del resolver .

tuttavia, l'utilizzo di una variabile modifica il comportamento di riscrittura. Potrebbe essere necessario utilizzare la direttiva di riscrittura, dipende dalla posizione e dall'impostazione proxy_pass.

PS: avrebbe pubblicato un commento ma non abbastanza punti ancora ...


1

La risposta di ohaal ci porta la maggior parte di noi lì, ma c'è un caso in cui il resolver DNS non vive a 127.0.0.1 (ad esempio quando ci si trova in un ambiente containerizzato speciale)

In tal caso, potresti voler modificare la configurazione di nginx resolver ${DNS_SERVER};. Quindi, prima di avviare nginx, esegui

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

Ho hackerato insieme uno script per guardare una cartella conf.d upstream per le modifiche DNS e ricaricare nginx al momento del rilevamento. È un primo passaggio e sicuramente può essere migliorato (passaggio successivo, userò nginx -T per analizzare in particolare i flussi up. La stessa idea potrebbe essere usata per le direttive 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.