1 问题现象
我们的程序属于客户端程序,该程序运行在容器中,进程启动后会调用服务端接口获取配置信息,在测试环境一直都没有问题,但是更新到线上环境后就出现问题,调用服务端接口报错,错误信息是执行HTTP请求失败,错误码为7。
2 定位过程
- 确定是必现问题还是偶现:进程调用配置接口失败,会自动重启,重启后依然出现该报错信息,说明是必现的。
- 确定是程序问题还是环境问题:同一个服务端,其他集群上都没有问题,只有这一个OpenShift集群出现问题,初步怀疑是环境问题
- 根据错误信息判断大致的问题:程序使用的是libcurl库连接服务端,在libcurl的帮助文档上查看到错误码为7的含义为:Failed to connect() to host or proxy,说明无法连接到目标机器
- 在内部用该OpenShift集群安装其他环境的客户端程序自测:运行正常,与出现问题的场景的区别是内部自测时没有配置域名,客户端是直接通过IP连接,而线上环境配置了域名
- 复现:内部找了个服务端配置了域名的环境测试,在该OpenShift集群确实可以复现,然后安装了debug版本的程序,查看到详细的HTTP调用日志,发现IP解析的不对,确认是域名解析的问题
- 进入到容器中,使用curl和ping可以解析到正确的IP地址
3 域名解析中的/etc/resolv.conf
程序解析域名时会读取/etc/resolv.conf,其中主要有两个字段:
- ndots:域名中点的个数限制
- search:主域名
- nameserver:域名服务器的地址
如果要访问的域名不以点号结尾,且点号的个数小于ndots,则将要访问的域名依次跟search中的主域名拼接,然后再向nameserver配置的域名服务器查询,否则,直接向nameserver发起域名查询请求。
执行strace ping
发现,域名查询时会尝试search中的多个域名,但是都失败了,最后会尝试不带域名的形式,从而找到正确的IP地址,而对我们的程序执行strace时,发现在尝试search中的最后一个域名时成功了,返回了OpenShift集群的引导节点的IP。
在宿主机上用任何字符串后面接search中的最后一个主域名进行ping,发现都会返回引导节点的IP地址,这个跟我们的现象很像,而且宿主机的nameserver配置的也是引导节点。
登录OpenShift的引导节点,发现上面有CoreDNS,且其中有个配置:
template IN A hello.cn {
match .*hello\.cn # 匹配请求 DNS 名称的正则表达式
answer "{{ .Name }} 60 IN A 127.0.0.1" # DNS 应答
fallthrough
}
虽然不太看得懂该配置文件,但是大概可以猜出来,该配置会导致任何以hello.cn结尾的域名都返回下面的127.0.0.1。
4 遗留问题
基本确定就是上述配置导致我们的程序无法解析到正确的服务端IP,从而导致无法连接,唯一遗留的问题是:
为什么ping活着curl命令可以解析到正确的IP,而调用libcurl得到的IP却是不对的?
后面有时间再看下。