Hatena::ブログ(Diary)

(ひ)メモ このページをアンテナに追加 RSSフィード

2013-11-12 (Tue)

Nginxでproxy_passにホスト名を書いた時の名前解決のタイミング

Nginx 1.4.2で試しました。

ネームサーバーは、ローカルのunboundをlocal-zone, local-dataを使って簡易コンテンツサーバーにして試しました。

  local-zone: "oreno." static
  local-data: "api.oreno.   30 IN A 192.0.2.11"
#  local-data: "api.oreno.   30 IN A 192.0.2.12"

proxy_passにホスト名を書くと→名前解決は一度だけ

このように Nginx の設定を書いた場合、

location /api {
  proxy_pass http://api.oreno:9999;
}
  • api.oreno」の名前解決は、nginxの起動時に行われます
    • 名前解決できない場合は、nginxは起動しません
    • 名前解決できた場合は、ずっとそのIPアドレスにreverse proxyします
      • DNS応答のTTLは一切影響しません
      • 再度名前解決させるには、SIGHUPを送ればよいです
      • もちろん、SIGTERMで再起動してもよいです

という挙動になります。

つまり、ホスト名に紐づくIPアドレスDNS的に変更されても、nginxは(HUPを受けるまでは)古いIPアドレスにreverse proxyし続けます。

定期的に名前解決させるにはどうすればよいか?

このように、setディレクティブで変数にホスト名をセットし、proxy_passではその変数を参照すれば、定期的に名前を引き直してくれるようになります。バッドな感じがしますが、公式ドキュメントにもこの挙動はちゃんと記されています。

location /api {
  resolver 127.0.0.1;
  set $api_backend "api.oreno";
  proxy_pass http://$api_backend:9999;
}

この時、resolverディレクティブもあわせて指定しないと、「no resolver defined to resolve api.oreno」とエラーログに記され、クライアントには 502 Bad Gateway が返されるので注意してください。

デフォルトではDNS応答のTTLが切れたら再度問い合わせに行きますが、

location /api {
  resolver 127.0.0.1 valid=2s;
  set $api_backend "api.oreno";
  proxy_pass http://$api_backend:9999;
}

と、resolverディレクティブにvalidオプションを指定することによって、TTLの値に関わらず、2秒経過したらまた再度DNS問い合わせするようにもできます。

upstreamディレクティブでserverを羅列してい場合に、定期的に名前解決させるには?

upstream api_upstream {
  resolver 127.0.0.1;

  set $api1 "api1.oreno";
  server $api1;
  set $api2 "api2.oreno";
  server $api2;
}

location /api {
  proxy_pass http://api_upstream:9999;
}

と書けばできそうに思えますがダメです。なぜなら、setディレクティブはupstreamコンテキストでは指定できないからです。

upstreamディレクティブでserverを羅列してい場合に、定期的に名前解決させる方法はないように思えるのですが、なにかよい方法があったら教えてもらえるとうれしいです><

追記

1.5.12以降なら、serverディレクティブにresolveパラメータをつければhttpブロックのresolverの設定の通りに名前を引き直してくれるようです。

http {
    resolver 127.0.0.1;

    upstream api_upstream {
        server api.oreno resolve;
    }
}

やったー!!!!と思って試してみたのですが「nginx: [emerg] invalid parameter "resolve" in ...」と怒られる。。と、よくドキュメント読んだら、

Additionally, the following parameters are available as part of our commercial subscription:

と書いてありました><

追記2

を使えばできました。nginx 1.8.0で確認。nginx 1.4.1ではビルドができませんでした。

これでTTL後に引き直し、

http {
    resolver 127.0.0.1;

    upstream api_upstream {
        dynamic_server api.oreno;
    }
}

これでTTLに関係なく2秒後に引き直してくれました!

http {
    resolver 127.0.0.1 valid=2s;

    upstream api_upstream {
        dynamic_server api.oreno;
    }
}

https://www.nginx.com/resources/wiki/modules/domain_resolve/ でもできるかもしれません。

なぞの「DNS error (32: Unknown error), query id:XXXXX

まだ再現方法がわからないのですが、proxy_passで変数参照している場合にこのエラーが出て数秒〜十数秒間reverse proxyできなくなる現象が起きています。

こちら何か情報お持ちの方は教えていただけるとうれしいです><

おまけ: nginxのdebug log

configureするときに --with-debug した上で、

error_log /path/to/file debug;

とすると、nginxがdebug logを吐くようになります。resolverの挙動もこれで確認できます。ただ、かなりの量を吐くので注意してください。

あと、コンテキストによって吐かれるログが違うので、serverやhttpコンテキストだけでなく、一番外側のmainコンテキストにもerror_logディレクティブを書いた方がよいです。

tokuhiromtokuhirom 2018/06/27 15:55 現在のドキュメントだと

>>
A server name, its port and the passed URI can also be specified using variables:
<<

は以下の表現にかわっているようです

>>
If a domain name resolves to several addresses, all of them will be used in a round-robin fashion. In addition, an address can be specified as a server group.

Parameter value can contain variables. In this case, if an address is specified as a domain name, the name is searched among the described server groups, and, if not found, is determined using a resolver.
<<

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

2003 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 05 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 12 |
2012 | 01 | 02 | 03 | 06 | 08 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 |
2015 | 01 | 02 | 07 | 10 |
2016 | 01 | 05 | 10 | 12 |
2017 | 07 |
2018 | 05 |