All Articles

/etc/hostsから名前解決するluaライブラリ書いた

これは何

READMEにも書いたけど、openrestyを使っているとちょくちょくhostnameからIPを引けないケースがある。

resty.redis

content_by_lua_blockなどのディレクティブではnginx側のresolver指定を引き継ぐ(のかな?)で例えばresolver 8.8.8.8とかしてるとローカルのアドレスが引けなかったりする。localhostもダメで、127.0.0.1を指定しないといけない。

参考: Resolv hostname problem

対策として、 REDISHOSTみたいな環境変数を作り、nginx.confの先頭でenv REDISHOSTでロードして、luaからos.getenv(“REDIS_HOST”)しろみたいな方法がある。

ngx.balancer.set_current_peer(host, port)

dynamic upstreamをやるときに使うディレクティブだけど、接続するピアを指定するのにhostnameは許可されていない。

参考: Problems when the hostname is not an ip but a name defined in /etc/hosts (Docker)

docker

上にも関連しているけどこれが一番困った問題で、openrestyのコンテナとアプリケーションのコンテナをlinkしてapp01, app02, app03,...とロードバランシングする時、app01とかでIPを引けないのはキツイ。

ということで、/etc/hostsに書かれているホスト設定を読み込んでhostname -> IPを解決するライブラリを書いた。

ysugimoto/lua-local-resolver

使い方

読み込んで、ホストファイル指定でインスタンス化してresolve(hostname)を呼ぶだけ。ipv6もサポートしている(はず)。

local Resolver = require "local-resolver"
local resolver = Resolver.new("/etc/hosts")

-- resolve local host
local ip = resolver:resolve("localhost") -- 127.0.0.1
local app = resolver:resolve("app01") -- docker linkしたコンテナのIP

-- resolve ipv6 local host
local ipv6 = resolver:resolve_v6("localhost") -- ::1

lua-resty-coreのissueにも簡単だぜ!って書かれてるけど特に誰もやって無さそうだったのでやってみた。実際実装は簡単だった。

hostsファイルはそう頻繁に変更されないと思うので、使う時はinitbylua_blockとかでグローバルに初期化しておいて、各ディレクティブで参照するのが効率が良さそう。openrestyを使う時は入れておくと良いと思います。

ちなみにこれはあくまでローカルの名前解決なので、外向きの時はlua-resty-dnsを使いましょう。

現場からは以上です。