转:原文:http://hambut.com/2016/09/09/how-to-resolve-the-domain-name-in-openresty/?utm_source=tuicool&utm_medium=referral
为什么我们的域名不能被解析
最近经常有朋友在使用一个域名地址时发现无法被正确解析
比如在使用Mysql
实例时某些云会给一个私有的域名搭配自有的nameserver
使用
1 2 3 4 5 6 7 8
|
local client = mysql:new() client:connect({ host = "rdsmxxxxxx.mysql.rds.xxxx.com", port = 3306, database = "test", user = "test", password = "123456" })
|
以上代码在直接使用时往往会报一个无法解析的错误。那么怎么在openresty
中使用域名呢
搭配 resolver 指令
我们可以直接在 nginx
的配置文件中使用 resolver
指令直接设置使用的 nameserver
地址。
官方文档中是这么描述的
1
|
Syntax: resolver address ... [valid=time] [ipv6=on|off];
Default: —
Context: http, server, location
|
一个简单的例子
1
|
resolver 8.8.8.8 114.114.114.114 valid=3600s;
|
不过这样的问题在于nameserver
被写死在配置文件中,如果使用场景比较复杂或有内部dns
服务时维护比较麻烦。
进阶玩法
我们的代码常常运行在各种云上,为了减少维护成本,我采用了动态读取本机/etc/resolv.conf
的方法来做。
废话不说,让我们一睹为快。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
local pcall = pcall local io_open = io.open local ngx_re_gmatch = ngx.re.gmatch
local ok, new_tab = pcall(require, "table.new")
if not ok then new_tab = function (narr, nrec) return {} end end
local _dns_servers = new_tab(5, 0)
local _read_file_data = function(path) local f, err = io_open(path, 'r')
if not f or err then return nil, err end
local data = f:read('*all') f:close() return data, nil end
local _read_dns_servers_from_resolv_file = function() local text = _read_file_data('/etc/resolv.conf')
local captures, it, err it, err = ngx_re_gmatch(text, [[^nameserver\s+(\d+?\.\d+?\.\d+?\.\d+$)]], "jomi")
for captures, err in it do if not err then _dns_servers[#_dns_servers + 1] = captures[1] end end end
_read_dns_servers_from_resolv_file()
|
通过上述代码我们成功动态拿到了一组nameserver
的地址,下面就可以通过resty.dns.resolver
大杀四方了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
local require = require local ngx_re_find = ngx.re.find local lrucache = require "resty.lrucache" local resolver = require "resty.dns.resolver" local cache_storage = lrucache.new(200)
local _is_addr = function(hostname) return ngx_re_find(hostname, [[\d+?\.\d+?\.\d+?\.\d+$]], "jo") end
local _get_addr = function(hostname) if _is_addr(hostname) then return hostname, hostname end
local addr = cache_storage:get(hostname)
if addr then return addr, hostname end
local r, err = resolver:new({ nameservers = _dns_servers, retrans = 5,
|
我这边把解析的结果放入了lrucache
缓存了5分钟,你们同样可以把结果放入shared
中来减少worker
查询次数。
高阶玩法
现在我们已经实现了自缓存体系的dns
查询,如果搭配resty.http就会达到更好的效果。
一个简单的例子是,通过解析uri
得到hostname
、port
、path
,把hostname
扔给自缓存dns
获取结果
发起request
请求,addr
+ port
connect 之,设置header
的host
为hostname
, path
等值来实现ip
直接访问等高阶用法。
这里就不过多的阐述了。
最终的演示例子如下
1 2 3 4 5 6 7 8
|
local client = mysql:new() client:connect({ host = _get_addr(conf.mysql_hostname), port = 3306, database = "test", user = "test", password = "123456" })
|
如何使用 /etc/hosts 自定义域名
还有些同学可能会在hosts
文件中自定义域名和ip
,这时候resolve
是无法正常解析的。
这个时候可以借助dnsmasq
这个服务来缓存我们的dns
结果,而且hosts
文件中的定义可以被该服务识别。
需要在nginx
的配置文件中,设置resolver
为dnsmasq
服务的监听地址即可。