Masteries

技術的なことや仕事に関することを書いていきます.

Nginxと名前解決の話

Nginxでは, serverコンテキストのlocationコンテキストにおいて, proxy_passディレクティブを利用することで任意のホストにアクセスを転送することができます. 例えば, serverコンテキストにおいて,

location / {
    proxy_pass http://127.0.0.1:5000;
}

みたいに書いてあげれば, localhostの5000番ポートにアクセスを転送することが出来ます. Webサービスでは, こういう感じでNginxが443番(HTTPS)や80番ポート(HTTP)で受けたアクセスを5000番ポートなどで動いているWebアプリケーションに転送している訳です.

で, このproxy_passディレクティブは, IPをそのまま書くのではなく, 次のようにドメインを書くこともできます.

location / {
    proxy_pass http://google.co.jp;
}

このようにすれば, アクセスを全てGoogleに転送(!?)することが出来ます. Nginxは内部でDNSを利用してgoogle.co.jpの名前解決(ドメインからIPアドレスを取得)して, そこに転送するわけです.

...で, この「名前解決」ですが, 実はデフォルトの設定ではNginxが起動した直後に1回しか実行されず, その結果はずっとキャッシュされるという仕様になっています.

これは, 例えばNginxから更にELBに転送するような場合に不具合を招きます. ELBに紐づくDNS名は変化しませんが, ELBに紐付いたIPは一定間隔で変化するので, Nginxで

location / {
    proxy_pass internal-hogehoge-service-12345676890.ap-northeast-1.elb.amazonaws.com;
}

...のようにアクセスをELBへ転送しようとした場合, ELBに紐づくIPが変化したタイミングで転送が出来なくなってしまいます.

解決策としては, httpコンテキストにおいて, resolverディレクティブを使い, 名前解決のために使うDNSを設定してやれば, TTL(Time to live, DNSから名前を引いてきた結果をキャッシュしておく時間)が切れたタイミングで名前解決をやり直す(名前を引き直す)ことが出来ます.

http {
    resolver 10.0.0.2;
    
    server {
        ...

        location / {
            proxy_pass internal-hogehoge-service-12345676890.ap-northeast-1.elb.amazonaws.com;
        }
    }
}

AWSのVPC内にインスタンスがある場合, IPアドレス範囲+2のアドレス(例えば, CIDRが10.0.0.0/24の場合, 10.0.0.2`)に内部向けのDNSサーバが設置されているので, 上記のようにこれを使えば良さそうです.

あわせてよみたい