然后我们使用 GODEBUG="netdns=go+2" 环境变量执行程序,带上这个环境变量之后程序运行时就会输出是先执行 dns 查询还是先从 /etc/hosts 文件进行查询
1 2 3 4
GODEBUG="netdns=go+2" go run main.go go package net: GODEBUG setting forcing use of Go's resolver go package net: hostLookupOrder(localhost) = files,dns Get "http://localhost:8080": dial tcp [::1]:8080: connect: connection refused
上面显示的 files,dns 的意思就是先从 /etc/hosts 文件中查询,再去查询 dns 结果,但是我们当时服务的运行结果是 dns,files 这个问题出现在哪里呢?和 Go 的版本以及本地环境有关系
go package net: built with netgo build tag; using Go's DNS resolver go package net: hostLookupOrder(localhost) = dns,files Get "http://localhost:8080": dial tcp 127.0.0.1:8080: connect: connection refused
Go 中定义了下面几种 DNS 解析顺序,其中 files 表示查询 /etc/hosts 文件,dns 表示执行 dns 查询
1 2 3 4 5 6 7 8 9 10 11 12 13
// hostLookupOrder specifies the order of LookupHost lookup strategies. // It is basically a simplified representation of nsswitch.conf. // "files" means /etc/hosts. type hostLookupOrder int
const ( // hostLookupCgo means defer to cgo. hostLookupCgo hostLookupOrder = iota hostLookupFilesDNS // files first hostLookupDNSFiles // dns first hostLookupFiles // only files hostLookupDNS // only DNS )
nss := c.nss srcs := nss.sources["hosts"] // If /etc/nsswitch.conf doesn't exist or doesn't specify any // sources for "hosts", assume Go's DNS will work fine. if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) { if c.goos == "solaris" { // illumos defaults to "nis [NOTFOUND=return] files" return fallbackOrder } if c.goos == "linux" { // glibc says the default is "dns [!UNAVAIL=return] files" // https://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html. return hostLookupDNSFiles } return hostLookupFilesDNS } if nss.err != nil { // We failed to parse or open nsswitch.conf, so // conservatively assume we should use cgo if it's // available. return fallbackOrder } }
通过上面的代码我们可以发现,当前系统如果是 linux 并且不存在 /etc/nsswitch.conf 文件的时候,会直接返回 dns,files 的顺序,这个是参考了 glibc 的实现[2]
这个问题其实一般在虚拟机上没有问题,因为一般操作系统都会默认有这个配置文件,但是容器化之后我们一般喜欢使用 alpine linux 这种比较小的基础镜像,alpine 中就不存在的 /etc/nsswitch.conf 这个文件,所以就有可能会出现问题
上面这段逻辑不能再 1.16 中进行复现,是因为 1.16 已经修改了这个逻辑,主要就是把 linux 的这个判断分支删除掉了,感兴趣可以看这个修改记录[3] 和这个 issue[4]