如何在openresty里解析域名


轉:原文: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, -- 5 retransmissions on receive timeout
timeout = 2000, -- 2 sec
})

if not r then
return nil, hostname
end

local answers, err = r:query(hostname, {qtype = r.TYPE_A})

if not answers or answers.errcode then
return nil, hostname
end

for i, ans in ipairs(answers) do
if ans.address then
cache_storage:set(hostname, ans.address, 300)
return ans.address, hostname
end
end

return nil, hostname
end

ngx.say(_get_addr("www.baidu.com"))
ngx.say(_get_addr("192.168.0.1"))

我這邊把解析的結果放入了lrucache緩存了5分鍾,你們同樣可以把結果放入shared中來減少worker查詢次數。

高階玩法

現在我們已經實現了自緩存體系的dns查詢,如果搭配resty.http就會達到更好的效果。

一個簡單的例子是,通過解析uri得到hostnameportpath,把hostname扔給自緩存dns獲取結果

發起request請求,addr + port connect 之,設置headerhosthostname, 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的配置文件中,設置resolverdnsmasq服務的監聽地址即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM