表现
在机器上,curl harbor 域名返回状态码 200,但执行 crictl pull rancher/rancher-agent:v2.6.8 时出现异常:dial tcp: lookup <domain>: try again。
# crictl pull rancher/rancher-agent:v2.6.8
FATA[2023-05-10T22:23:36.325976772+08:00]pulling image: rpc error: code = Unknown desc = failed to pull and unpack image "rancher/rancher-agent:v2.6.8": failed to copy: httpReaderSeeker: failed open: failed to do request: Get "..."
... : dial tcp: lookup <domain>: try again
排查
- 通过
PING或curl https://<domain>两者验证 OK。 - 通过配置
/etc/hosts后执行后重新pull成功。
怀疑是 crictl 命令执行时 dns 返回的解析参数问题。通过 tcpdump 抓取 DNS 包分析。从包中发现,镜像域名的 A 记录解析正常,但 AAAA 记录返回的状态是 Server Failure,而不是预期的 NOERROR 状态。
结合上面 curl 操作正常,我们将问题范围缩小到 golang net 库对于 DNS 解析的实现上(crictl 是 golang 实现的工具)。
查看 go net 的源码,在 src/net/dnsclient_unix 解析时,会同时进行 A 和 AAAA 记录的解析:
在对解析结果的处理上,在 dns response 处理 时,AAAA 解析返回 Server Failure 导致返回的 addr = nil:
从而导致后续在 crictl pull 时出现异常:dial tcp : lookup 异常。
补充:什么样的异常会中断 DNS 解析呢?哪些异常是 strictErrors() 呢?
StrictErrors 控制使用 Go 内置解析器时的临时错误(包括超时、套接字错误和 SERVFAIL)的行为。对于由多个子查询组成的查询(例如 A+AAAA 地址查找或遍历 DNS 搜索列表),此选项会导致此类错误中止整个查询而不是返回部分结果。默认情况下未启用,因为它可能会影响与错误处理 AAAA 查询的解析器的兼容性
按照 RFC 1035 中的定义了 DNS 返回异常的 RCODE,从而中断了 DNS 解析。
措施
- 检查运行环境对 AAAA 进行拦截,放行
- 配置 /etc/hosts (优先级更高)