在容器中碰到一個怪的現象,一個域名配置了host解析,但是程式調用中,tcp連接配接成了其它IP
看如下操作: 通過nslookup解析域名
test.datakit.com
傳回的IP不是hosts檔案中配置的IP # nslookup test.datakit.com
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
test.datakit.com canonical name = server.datakit.com
Non-authoritative answer:
test.datakit.com canonical name = server.datakit.com
Name: server.datakit.com
Address: 46.105.51.17
# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.16.5.9 test.datakit.com
172.26.0.14 7707e6a4e86f
通過docker logs 擷取容器中應用的日志,發現請求該域名,最後連接配接的IP也不是hosts檔案中的IP,而是DNS解析的IP
Datadog Tracer v1.29.0 ERROR: lost 1 traces: Post "http://test.datakit.com:9529/v0.4/traces": dial tcp 46.105.51.17:9529: i/o timeout (occurred: 29 Mar 21 02:32 UTC)
Datadog Tracer v1.29.0 ERROR: lost 1 traces: Post "http://test.datakit.com:9529/v0.4/traces": dial tcp 46.105.51.17:9529: i/o timeout (occurred: 29 Mar 21 02:33 UTC)
遇到的問題:
問題1: 為什麼host配置了解析,不使用,這個不是優先使用嗎
是因為這個容器鏡像bash:4.4,沒有/etc/nsswitch.conf 解析順序檔案,導緻沒有優先使用host解析,而使用了dns
問題2: 解析test.datakit.com,為什麼傳回個server.datakit.com的IP
dnslookup傳回了非權威的應答,是一個緩存中的結果,是以自己随便定義域名,也不能和其它能解析的域名相關聯,例如: datakit.com 頂級域名,你随便檢視其它的a.datakit.com,b.datakit.com 也是這樣的結果
解決此問題:
方法一:增加/etc/nsswitch.conf解析順序檔案,從其它系統拷貝到容器中/etc/目錄下面
docker cp /etc/nsswitch.conf b753da9b566e:/etc/
方法二:更換域名綁定,如果dns解析失敗,那麼就會走host解析
# nslookup test.jiangyd.com
Server: 127.0.0.11
Address: 127.0.0.11:53
** server can't find test.jiangyd.com: NXDOMAIN
** server can't find test.jiangyd.com: NXDOMAIN
# cat /etc/hosts |grep test
172.16.5.9 test.jiangyd.com
問題到這裡就結束了嗎,以上的問題雖然是解決,但其實還有2個疑惑不能答疑?
在使用ping指令過程中,是正确的,能比對到/etc/hosts的配置
# ping test.datakit.com
PING test.datakit.com (172.16.5.9): 56 data bytes
64 bytes from 172.16.5.9: seq=0 ttl=64 time=0.095 ms
64 bytes from 172.16.5.9: seq=1 ttl=64 time=0.076 ms
在使用curl調用過程中,是正确的,能比對到/etc/hosts的配置
# curl http://test.datakit.com:9529/stats
{
"inputs_status": [
{
"name": "aliyunobject",
"category": "/v1/write/object",
"frequency": "20.23/min",
...
難道我還是沒了解?,不同的程式使用解析還不一樣,ping ,curl,自己寫的程式(go二進制)
怎麼辦,這就要放棄?,好吧,再嘗試下使用tcpdump抓包看看吧
ping指令抓的包,直接就是IP了,IP是在/etc/hosts中配置的
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iZ2kDZwMzY4QzMmV2Y4ATOxADZ0ITN5MWZ0ETYzAjZl9CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
curl 抓的包,直接就是IP了,IP是在/etc/hosts中配置的
程式(程式部署在容器中,映射出端口18090,容器内部端口18080,在主控端上通路程式
http://ip:18090,然後程式調用test.datakit.com)
看抓包該IP不是hosts解析配置的,而是通過DNS解析的(非權威應答)
我懷疑程式是不是有問題,因為程式使用了第三方的包,我來個最簡單的demo看看
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
c:=http.Client{}
req,err:=http.NewRequest("GET","http://test.datakit.com:9529/stats",nil)
if err!=nil{
fmt.Println(err)
}
resp,err:=c.Do(req)
if err!=nil{
fmt.Println(err)
}
data,_:=ioutil.ReadAll(resp.Body)
fmt.Println(string(data))
}
編譯後執行,同樣的是,tcp連接配接的IP不是我hosts配置檔案中的,那麼顯然問題與這個程式有關系了
抓包中顯示,query 查了A記錄,顯示經過了DNS,這下搞懂了原因了,隻是不明白為啥go程式會先查詢下DNS
最後在網上找到了答案,go預設使用純go的域名解析,還有一種cgo的方式
可以臨時設定下環境變量嘗試一下執行
bash-4.4# export GODEBUG=netdns=cgo
bash-4.4# ./demo
{
"inputs_status": [
{
...
為什麼go程式預設使用純go的域名解析呢,因為當DNS解析阻塞時,内置Go解析器隻是阻塞了一個goroutine,而cgo的解析器則是阻塞了一個作業系統級别的線程.
這也是巧合,把程式運作在容器鏡像bash4.4(沒有/etc/nsswitch.conf),如果運作在其它地方還不一定能知道此問題,是以說失敗乃是成功之母,隻要踩過坑,并認真找原因,解決問題,我相信你一定能有收貨