初めに
この記事はNginxのresolverにローカルホスト(127.0.0.1)のdnsmasqで構築したDNSを指定したことにより起きたインシデントについて書いていますので、resolverにローカルホスト以外を設定しようとしている方にはほぼ関係のない内容となっています。
NginxのIPアドレスキャッシュについて
他のブログなどで散々説明されているので簡単に説明すると、Nginxは起動したタイミングでproxy_passに記載されているURLの名前解決を行い、それをTTLに関係なく再起動もしくは設定更新までキャッシュするというものです。DNS側でIPアドレスが変わったとしても、古い情報で通信を行ってしまいます。
キャッシュしないようにする解決策としてはresolverを設定し、proxy_passに変数を使用するというものです。対策法方が悪かったわけではないのですが、今回の事件はこの対策を行ったために起こってしまいました。
対策前の環境
上記対策をとる前の環境として、Nginxは/etc/hostsを参照して他のサーバのドメイン名を解決し、そこに存在しないドメイン名は別サーバの上位DNSに問い合わせていました。
対策後の環境
対策をした結果、Nginxと同じサーバにdnsmasqを用いたDNSを構築し、新たに追加されたresolverの設定には、これまた新たに構築したDNSで名前解決を行うよう127.0.0.1を設定しました。そうすることで、Nginxはhostsファイルを直接参照せずにdnsmasqを通してhostsファイルを参照することになります。上位DNSのくだりは対策前と変わりません。
何がダメだったのか
対策前後で違う点はNginxがhostsファイルをdnsmasq経由で参照するようになったことです。お恥ずかしい話ですが、dnsmasqを用いてDNSを構築するのは初めてのことであったため、hostsファイルの内容が更新された際にdnsmasqの再起動が必要だということを知らなかったのです。
hostsファイルとは、自分の中では編集したら即時反映のイメージであったがためにdnsmasqを通した途端に再起動が必要になるとは思ってもいませんでした。
dnsmasq自体は今回の対応以前からサーバにインストールされており、しかし使用されてなかったため再起動したことなど一度もありません。そのため今日まで更新されてきたhostsファイルがdnsmasqに反映されておらず、対策反映後にdnsmasqを通したhostsファイルの参照で名前解決ができずに通信エラーとなってしまいました。
たとえ今回のデプロイのタイミングでdnsmasqのインストールから起動までを行ったとしても、結局後にhostsファイルに変更が加わることがあれば、その変更を参照することができずに通信エラーとなっていたでしょう。
まとめ
dnsmasqでhostsファイルを参照している場合は、編集した際の再起動を徹底しなければなりませんね。