Comment forcer nginx à résoudre le DNS (d'un nom d'hôte dynamique) à chaque fois lors de l'exécution de proxy_pass?

52

J'utilise nginx / 0.7.68 sous CentOS avec la configuration suivante:

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

Le proxy_passest à un enregistrement DNS dont l'IP change fréquemment. Nginx met en cache l'adresse IP obsolète, ce qui entraîne une demande à la mauvaise adresse IP.

Comment puis-je empêcher nginx de mettre en cache l'adresse IP lorsqu'elle est obsolète?

xiamx
la source
En regardant à travers la source nginx, il apparaît que nginx est codé en dur pour que le cache résolve pour sa durée de vie - quelle est la durée de vie sur votre dns dynamique?
lunixbochs
TTL sur mes DDNS est de 60s, la valeur par défaut de Dyndns.com
xiamx

Réponses:

8

C'est une question intrigante et AFAIK qui ne va pas bien fonctionner. Vous pouvez essayer d'utiliser le module en amont et utiliser les directives de basculement pour voir s'il fonctionne comme un piratage.

Édition 2018: beaucoup de choses ont changé. Vérifiez la réponse de @ohaal pour obtenir de vraies informations à ce sujet.

coredump
la source
1
étonnamment quand je suis passé en amont, tout a fonctionné comme prévu. Je marquerai alors ceci comme étant la réponse correcte
xiamx
1
Selon la documentation, il existe un serverdrapeau spécial en amont resolvequi est uniquement disponible dans la version commerciale (voir nginx.org/en/docs/http/ngx_http_upstream_module.html#server )
omribahumi le
1
@ gansbrest ce site semble être une sorte de site de spam? Je vous demanderais de retirer votre réponse.
Majikman
90

La réponse acceptée n'a pas fonctionné pour moi sous nginx / 1.4.2.

L'utilisation d'une variable pour proxy_passforcer la resolution des noms DNS, car NGINX traite les variables différemment de la configuration statique. De la documentation NGINXproxy_pass :

La valeur du paramètre peut contenir des variables. Dans ce cas, si une adresse est spécifiée en tant que nom de domaine, le nom est recherché parmi les groupes de serveurs décrits et, s'il n'est pas trouvé, est déterminé à l'aide d'un résolveur.

Par exemple:

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

Remarque: Un résolveur (c.-à-d. Le serveur de noms à utiliser) DOIT être disponible et configuré pour que cela fonctionne (et les entrées d'un /etc/hostsfichier ne seront pas utilisées dans une recherche).

Par défaut, la version 1.1.9 ou ultérieure du cache NGINX répond en utilisant la valeur TTL d'une réponse et un validparamètre facultatif permet de remplacer la durée du cache:

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

Avant la version 1.1.9, il était impossible de régler la durée de la mise en cache, et nginx mettait toujours en mémoire cache les réponses pendant 5 minutes. .

ohaal
la source
Cela ne forcerait-il pas une requête DNS à chaque requête? cela ressemble à une performance épouvantable ...
lucascaro
Non, lisez la source. In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.Je l'ai ajouté à la réponse pour plus de clarté.
Ohaal
13
Après avoir passé la majeure partie de ma journée sur ce sujet - sur Ubuntu 12.04 avec nginx 1.1.19, l’ setintérieur locationne fonctionne pas correctement. Attention
omribahumi
Cette solution a fonctionné avec moi, mais je n'ai pas pu trouver de référence pour la durée de vie de 5 minutes. 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
Note: pour docker, son résolveur DNS est situé à 127.0.0.11, donc pour le développement, j'utilise ceci:resolver 127.0.0.11 [::1]:5353 valid=15s;
Dalibor Filus
9

Il y a des informations précieuses dans le commentaire de gansbrest et la réponse ohaal.

Mais je pense qu'il est important de mentionner cet article officiel de nginx, publié en 2016, qui explique clairement le comportement de nginx à ce sujet et les solutions possibles: https://www.nginx.com/blog/dns-service-discovery-nginx-plus /

Nous devons en effet "définir le nom de domaine dans une variable" et utiliser la directive resolver .

Cependant, l'utilisation d'une variable modifie le comportement de réécriture. Vous devrez peut-être utiliser la directive rewrite, cela dépend de votre emplacement et de la configuration de proxy_pass.

PS: aurait poster un commentaire mais pas assez de points encore ...

Jack B.
la source
1

La réponse de ohaal attire la plupart d'entre nous, mais il existe un cas où le résolveur DNS ne vit pas à 127.0.0.1 (par exemple, dans un environnement conteneurisé spécial)

Dans ce cas, vous voudrez peut-être changer la configuration de nginx en resolver ${DNS_SERVER};. Puis, avant de commencer nginx, lancez

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
la source
0

J'ai hacké ensemble un script pour regarder un dossier conf.d en amont pour les modifications du DNS et recharger nginx après détection. C'est une première passe, et peut sûrement être améliorée (la prochaine passe, j'utiliserai nginx -T pour analyser en amont spécifiquement. La même idée pourrait être utilisée pour les directives proxy_pass):

#!/bin/bash

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

resolve_hosts() {
  local [email protected]
  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
la source