golang在Linux下在nsswitch.conf允许的情况下,默认会使用自己的pure go resolver,parse了/etc/resolv.conf的内容。

但在部分安装了nscd的机器上,如果刚好resolv.conf中配置了无效的dns服务器,则ping和curl命令都可以通过nscd的缓存获取到解析结果,而golang的程序则会报错解析失败。

按照golang的官方文档,可以通过设置GODEBUG=netdns=cgo来强制使用libc的resolver,go代码中则可以通过以下代码开启

import "os"

func init() {
	os.Setenv("GODEBUG", "netdns=cgo")
}

Update:

上面其实不是最好的办法,最标准的姿势,应该是go build中指定-tags 'netcgo',按照src/net/conf_netcgo.go中的指定,就会在编译期就使用cgo resolver。

但这会带来另外一个问题,公司里用的是魔改RHEL5,内核上到2.6.32了,但默认的gcc还停留在4.1,按照golang/go#9520的描述,会导致编译错误,解决方法有两个:

  1. 修改golang的源代码,将src/cmd/go/build.godisableBuildID方法内容,按上面的注释,从"-Wl,--build-id=none"修改为"-r",然后重新编译出go可执行文件并替换,注意根据文档指示设定$GOROOT_FINAL变量并使用RHEL5平台进行编译,否则syscall可能无法对齐。
  2. 或者直接使用DevTools 2,里面针对RHEL5的平台提供了GCC 4.8.2,同样也可以解决这个问题,这也是我最终选择的方案,这样每次都能用官方的golang二进制。