DNS解析及缓存策略说明

本文介绍Kubernetes集群中容器Pod在域名解析过程中的解析策略和缓存策略。

DNS解析链路全景图

以下介绍三种应用部署形式下应用解析域名的链路:

说明

关于图中的timeout、attempts等术语的含义,请参考下文解析策略和缓存策略。

  • 非容器化应用直接运行于ECS之上。

    示例:App运行于ECS上。

    DNS解析链路1.png

  • 容器化应用运行于Kubernetes中,DNSPolicy注入ClusterFirst的Pod里。

    示例:App运行于Kubernetes容器Pod中。

    DNS解析链路2.png

  • 容器化应用运行于Kubernetes中,DNSPolicy注入了NodeLocal DNSCache的Pod里。

    示例:App运行于Kubernetes容器Pod中,同时部署了NodeLocal DNSCache。

    DNS解析链路3.png

解析策略

客户端侧

一般情况下,应用解析域名是通过Glibc提供的接口完成的,下表参数为/etc/resolv.conf中暴露的域名解析参数,即Glibc解析域名时的可配置参数。

参数

说明

Glibc中默认值

ECS

DNSPolicy为ClusterFirst的Pod

DNSPolicy为Default的Pod

注入了NodeLocal DNSCache的Pod

DNSPolicy为Default且采用主机网络的Pod

nameserver

解析域名时使用的DNS服务器

VPC DNS服务器

CoreDNS ClusterIP

VPC DNS服务器

  • NodeLocal DNSCache IP

  • CoreDNS ClusterIP

VPC DNS服务器

search

请求非完整域名(非FQDN)时,域名会被拼接上search组成FQDN再进行请求

<ns>.svc.cluster.cloal svc.cluster.local cluster.local

<ns>.svc.cluster.cloal svc.cluster.local cluster.local

ndots:n

访问的域名字符串内的点字符数量超过ndots值,则认为是完整域名(FQDN),并被直接解析;如果不足ndots值,则追加search段后缀再进行查询。

1

1

5

1

3

1

timeout:n

对于单个域名解析请求的超时时间,单位为秒

5

2

5

5

1

2

attempts:n

解析域名失败时重试的次数

2

3

2

2

2

3

rotate

以Round Robin的形式轮询DNS服务器

关闭

开启

关闭

关闭

关闭

开启

single-request-reopen

开启该配置后,一旦需要处理同一Socket发送的两次请求时,解析端会在发送第一次请求后关闭Socket,并在发送第二次请求前打开新的socket。

关闭

开启

关闭

关闭

关闭

开启

attempts参数仅在部分场景下起到重试的效果,例如服务端返回SERVFAIL、NOTIMP、REFUSED时,或服务端返回NOERROR,但没有解析结果时。更多信息,请参见attempts参数解析请求说明

VPC DNS服务器是指ECS上默认配置的DNS服务器,IP为100.100.2.136和100.100.2.138,负责PrivateZone和权威域名的解析。

CoreDNS ClusterIP是指Kubernetes集群内默认部署的CoreDNS在kube-system命名空间下提供的kube-dns服务的IP地址,负责集群内部服务域名的解析,以及PrivateZone、权威域名的解析转发。

NodeLocal DNSCache IP是指部署了NodeLocal DNSCache组件后,组件在每个节点上监听的169.254.20.10的IP地址。

说明

关于resolv.conf配置的更多信息,请参见resolv.conf

部分情况下,客户端侧的域名解析策略可能与上述配置不同:

  • 当采用Alpine作为容器镜像时,其内置了Musl库代替Glibc实现,解析行为会有较大不同,例如:

    • Alpine不遵循/etc/resolv.conf里面的single-request和single-request-reopen。

    • 3.3及更早版本Alpine不支持search参数,不支持搜索域,无法完成服务发现。

    • 并发请求/etc/resolv.conf中配置的多个DNS服务器,导致NodeLocal DNSCache优化失效。

    • 并发使用同一Socket请求A和AAAA记录,在旧版本内核上触发Conntrack源端口冲突导致丢包问题。

    说明

    关于解析行为的更多信息,请参见musl libc

  • 当使用Golang、NodeJS等编程语言时,应用可能会采用语言内置的域名解析器,其行为也存在较大区别。

集群内DNS服务器

CoreDNS的/etc/resolv.conf默认沿用ECS的配置,但在实际转发DNS请求时,会使用内置的Forward插件完成。

NodeLocal DNSCache内置了CoreDNS实现DNS服务转发,与CoreDNS配置方式一致。

Forward插件的解析策略控制的参数如下表所示。关于CoreDNS Forward插件的更多配置,请参见Forward

参数

说明

CoreDNS默认值

NodeLocal DNSCache默认值

prefer_udp

优先使用UDP协议与上游通信

开启

关闭

force_tcp

强制使用TCP协议与上游通信

关闭

开启

max_fails

连续多少次健康检查失败就认为upstream不健康

2

2

expire

与upstream的链接保持10秒

10s

10s

policy

选择upstream的策略

random

random

health_check

健康检查时间间隔

0.5s

0.5s

max_concurrent

最大请求upstream的链接并发数

dial timeout

连接upstream的超时

30s,根据实际耗时动态减小

30s,根据实际耗时动态减小

read timeout

从upstream等待数据的超时

2s

2s

缓存策略

客户端侧

客户端侧的缓存策略是因容器和应用而异的,实际的缓存策略取决于您的配置。

集群内DNS服务器

参数

说明

CoreDNS社区默认配置

NodeLocal DNSCache ACK默认配置

CoreDNS ACK默认配置

success Max TTL

成功的域名解析结果缓存最大TTL

3600s

30s

30s

success Min TTL

成功的域名解析结果缓存最小TTL

5s

5s

5s

success Capacity

成功的域名解析结果缓存数目

9984

9984

9984

denial Max TTL

失败的域名解析结果缓存最大TTL

1800s

5s

30s

denial Min TTL

失败的域名解析结果缓存最小TTL

5s

5s

5s

denial Capacity

失败的域名解析结果缓存数目

9984

9984

9984

ServerError TTL

上游DNS服务器异常时解析结果TTL

5s

0s(NodeLocal DNSCache Helm Chart版本低于1.5.0时,默认为5s)

0s(CoreDNS低于1.8.4.2版本时默认为5s)

serve_stale

允许无法连接上游DNS服务器时使用已过期的本地缓存

关闭

开启(NodeLocal DNSCache Helm Chart版本低于1.5.0时,默认关闭)

关闭

说明

实际生效的缓存时间TTL由域名解析结果自身TTL、最大TTL、最小TTL共同决定,规则如下:

  • 解析结果TTL>Max TTL时,实际生效的TTL为Max TTL。

  • 解析结果TTL<Min TTL时,实际生效的TTL为Min TTL。

  • Min TTL<解析结果TTL<Max TTL时,实际生效的TTL为解析结果TTL。

优化建议

本文介绍了Kubernetes集群的解析路径及各环节参数配置,您可以通过修改Pod Yaml、CoreDNS ConfigMap、NodeLocal DNSCache ConfigMap等方式来修改参数,示例如下。

当客户端Pod配置dnsPolicy:Default时,ECS上VPC DNS服务器会被拷贝至容器内/etc/resolv.conf配置文件中。

apiVersion: v1
kind: Pod
metadata:
  name: example
  namespace: default
spec:
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/example-ns/example:v1
    name: example
  #Pod YAML中dnsPolicy值为Default。
  dnsPolicy: Default

# 此时容器内/etc/resolv.conf。
# cat /etc/resolv.conf
nameserver 100.100.2.136
nameserver 100.100.2.138

容器内对比ECS上,缺少了rotate single-request-reopen timeout:2 attempts:3的options参数,可能会使一个偶发的网络链路抖动导致业务侧域名解析异常,需要补充这些参数以提升容错能力。调整Pod YAML如下:

apiVersion: v1
kind: Pod
metadata:
  name: example
  namespace: default
spec:
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/example-ns/example:v1
    name: example
  # Pod YAML中dnsPolicy值为Default。
  dnsPolicy: Default
  # 增加以下容错配置。
  dnsConfig:
    options:
    - name: timeout
      value: "2"
    - name: attempts
      value: "3"
    - name: rotate
    - name: single-request-reopen

# 修改后重新部署Pod,容器内/etc/resolv.conf新增了options参数。
# cat /etc/resolv.conf
nameserver 100.100.2.136
nameserver 100.100.2.138
options rotate single-request-reopen timeout:2 attempts:3