背景介绍
CoreDNS 是一个灵活的、可扩展的 DNS 服务器,可以用作 Kubernetes 集群 DNS。当您启动至少有一个节点的 Amazon EKS 集群时,默认情况下会部署 CoreDNS image 的两个副本,而不管集群中部署了多少节点。CoreDNS pod 为 Amazon EKS 集群中的所有pod提供名称解析。Amazon EKS 集群中默认部署的 CoreDNS 在DNS QPS 较高场景下可能会出现 DNS 解析时延高、解析超时、解析失败等问题。本文介绍如何优化 Amazon EKS 集群中 DNS 性能。
???? 想要了解更多亚马逊云科技最新技术发布和实践创新,敬请关注在上海、北京、深圳三地举办的2021亚马逊云科技中国峰会!点击图片报名吧~上海站峰会已经圆满落幕,更多精彩内容,敬请期待北京、深圳分会吧!
前提条件
在具有 Kubernetes 1.16 或更高版本的 Amazon EKS 集群上支持 CoreDNS
有关如何在 Amazon EKS 上安装和升级CoreDNS,请参考下方链接:
https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/coredns.html
优化方案
增加CoreDNS副本数
默认部署的 Amazon EKS 集群,CoreDNS 的副本数是2,当集群规模较大和 DNS 查询并发较高时,可能会出现2个 Pods 的 CoreDNS 不足以及时处理 DNS 查询请求从而影响 DNS 查询效率,我们可以通过直接增加 CoreDNS 副本数量的方式提升 DNS 查询性能。
执行以下命令调整 CoreDNS 的副本数到合理值,N时目标副本数
1kubectl scale --replicas=N deployment/coredns -n kube-system
增加 CoreDNS 的 Cache 时间
在有大量外部域名解析请求的场景中,适当增加 CoreDNS 对条目的缓存时间可以有效的提高 CoreDNS 的性能,CoreDNS 默认配置的缓存时间是 30s,增大 cache 时间对域名解析 TTL 敏感型的应用会有一定的影响,会延缓应用感知域名解析配置变更的时间。
1kubectl edit configmap coredns -n kube-system
2
3apiVersion: v1
4
5data:
6
7 Corefile: |
8
9 .:53 {
10
11 errors
12
13 log
14
15 health
16
17 kubernetes cluster.local in-addr.arpa ip6.arpa {
18
19 pods insecure
20
21 fallthrough in-addr.arpa ip6.arpa
22
23 }
24
25 prometheus :9153
26
27 forward . /etc/resolv.conf
28
29 cache 60
30
31 loop
32
33 reload
34
35 loadbalance
36
37 }
例如配置文件中 cache 30 调整为 60。
调整 ndots 数值
Pod 在使用 DNS 的时候有四种策略,默认是 ClusterFirst 策略,在 ClusterFirst 模式下, Pod 内/etc/resolv.conf配置的 DNS 服务地址是集群 DNS 服务的地址kube-dns
1nameserver 10.100.0.10
2
3search default.svc.cluster.local svc.cluster.local cluster.local ap-southeast-1.compute.internal
4
5options ndots:5
在 Amazon EKS 中 CoreDNS 的 service 对应的 cluster ip 地址默认是 10.100.0.10,在 ClusterFirst 模式下存在一个问题,当集群内部查询外部域名的时候,2 次(1次IPv4,1次IPv6)集群外部域名DNS查询会产生 10 次(5次IPv4,5次IPv6)查询请求。例如解析www.amazon.com域名,会先分别携带四个/etc/resolv.conf 中search对应的搜索域后缀,产生八次无效查询请求,这样会导致集群 DNS QPS 放大四倍(例如如下日志中显示为 NXDOMAIN 的请求全部为无效请求)
1[INFO] 192.168.91.232:38354 - 53881 "AAAA IN www.amazon.com.default.svc.cluster.local. udp 58 false 512" NXDOMAIN qr,aa,rd 151 0.000166861s
2
3[INFO] 192.168.91.232:38354 - 44145 "A IN www.amazon.com.default.svc.cluster.local. udp 58 false 512" NXDOMAIN qr,aa,rd 151 0.000228392s
4
5[INFO] 192.168.91.232:41643 - 16970 "AAAA IN www.amazon.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.000084297s
6
7[INFO] 192.168.91.232:41643 - 65092 "A IN www.amazon.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.000074557s
8
9[INFO] 192.168.91.232:36820 - 54794 "AAAA IN www.amazon.com.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000100624s
10
11[INFO] 192.168.91.232:36820 - 11271 "A IN www.amazon.com.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000098021s
12
13[INFO] 192.168.91.232:33623 - 47179 "AAAA IN www.amazon.com.ap-southeast-1.compute.internal. udp 64 false 512" NXDOMAIN qr,rd,ra 187 0.009907116s
14
15[INFO] 192.168.91.232:33623 - 58950 "A IN www.amazon.com.ap-southeast-1.compute.internal. udp 64 false 512" NXDOMAIN qr,rd,ra 187 0.010631084s
16
17[INFO] 192.168.91.232:48515 - 56834 "A IN www.amazon.com. udp 32 false 512" NOERROR qr,rd,ra 212 0.001209964s
18
19[INFO] 192.168.91.232:48515 - 16391 "AAAA IN www.amazon.com. udp 32 false 512" NOERROR qr,rd,ra 318 0.001528659s
在进行域名解析时,操作系统先判断其是否是一个 FQDN(Fully qualified domain name,即完整域名,指以.结尾的),如果是则会直接查询 DNS 服务器;如果不是则就要根据 search 和 ndots 的设置进行 FQDN 的拼接再将其发到 DNS 服务器进行解析。
ndots 表示的是完整域名中必须出现的.的个数,如果域名中的.的个数不小于 ndots,则该域名会被认为是一个 FQDN,操作系统会直接将其发给 DNS 服务器进行查询;否则,操作系统会在 search 搜索域中依次查询。
默认情况下 ndots 为 5,查询的域名 www.amazon.com 不以.结尾,且.的个数少于 5,因此操作系统会依次在 default.svc.cluster.local svc.cluster.local cluster.localap-southeast-1.compute.internal 四个域中进行搜索。如果集群内只会用到同 namespace 下的 Service 和跨 namespace 下 Service 的访问, 将 ndots 的默认值设为 2 便可满足业务需求并避免大量无效的解析请求。
修改 pod 的 ndots 值的方法如下
1apiVersion: apps/v1
2
3kind: Deployment
4
5metadata:
6
7 name: "centos"
8
9spec:
10
11 selector:
12
13 matchLabels:
14
15 app: "centos"
16
17 replicas: 1
18
19 template:
20
21 metadata:
22
23 labels:
24
25 app: "centos"
26
27 spec:
28
29 containers:
30
31 - image: centos
32
33 imagePullPolicy: Always
34
35 name: "centos"
36
37 args:
38
39 - /bin/sh
40
41 - -c
42
43 - sleep 10; touch /tmp/healthy; sleep 30000
44
45 readinessProbe:
46
47 exec:
48
49 command:
50
51 - cat
52
53 - /tmp/healthy
54
55 initialDelaySeconds: 10
56
57 periodSeconds: 5
58
59 dnsConfig:
60
61 options:
62
63 - name: ndots
64
65 value: "2"
修改后测试解析 DNS 域名,CoreDNS 日志如下:
1[INFO] 192.168.67.216:39187 - 41028 "A IN www.amazon.com. udp 32 false 512" NOERROR qr,rd,ra 212 0.001406832s
2
3[INFO] 192.168.67.216:39187 - 22603 "AAAA IN www.amazon.com. udp 32 false 512" NOERROR qr,rd,ra 280 0.002514496s
可以看到只有两次解析,无效解析已经消失。
使用 autopath 插件
autopath 是一个可选的优化插件,可以提高集群外部名称查询的性能(例如 amazon.com )。启用 autopath 插件需要 CoreDNS 使用更多的内存来存储有关 Pod 的信息。Autopath 的原理是在第一次域名查询失败尝试找到正确的域名,这样共需要 2 次(1次IPv4,1次IPv6)查询就可以获取到正确的结果, 减少客户端在查找外部名称时进行的 DNS 查询次数。
启用 autopath 的方式如下
1kubectl edit configmap coredns -n kube-system
2
3apiVersion: v1
4
5data:
6
7 Corefile: |
8
9 .:53 {
10
11 errors
12
13 log
14
15 health
16
17 kubernetes cluster.local in-addr.arpa ip6.arpa {
18
19 pods verified
20
21 fallthrough in-addr.arpa ip6.arpa
22
23 }
24
25 autopath @kubernetes
26
27 prometheus :9153
28
29 forward . /etc/resolv.conf
30
31 cache 30
32
33 loop
34
35 reload
36
37 loadbalance
38
39 }
使用 NodeLocal DNSCache
NodeLocal DNSCache 通过在集群节点上作为 DaemonSet 运行 DNS 缓存代理来提高集群 DNS 性能,通过这种架构,可以让 pod 直接查询运行在同一节点上的 DNS 缓存代理,避免 DNS 查询请求报文经过 iptables NAT 和 conntrack 从而可能触发瓶颈。
关于在集群上部署 NodeLocal DNSCache,可以参考下方链接:
https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/
使用 Amazon Route53 resolver 作为外部 DNS 服务器
默认情况下,Amazon EKS 的 CoreDNS 部署后使用节点中 /etc/resolv.conf 中配置的 nameserver 作为外部 DNS 解析服务器。在 VPC 中单个 EC2 的网卡的域名解析并发为 1024 个数据包,并且无法提高此限制,这样就导致单个 CoreDNS 的 pod 最大的外部 DNS 解析能力是 1024 QPS,除了前文提到的增加更多的 CoreDNS pod 的方法外,我们还可以利用 Amazon Route53 resolver 提供的 Inbound endpoints 作为 CoreDNS 外部解析地址,突破1024 QPS 的限制(每个 Amazon Route53 resolver 终端节点中单个 IP 地址的每秒查询数为 10000,可以增加更多的 IP 提高 QPS )
1apiVersion: v1
2
3data:
4
5 Corefile: |
6
7 .:53 {
8
9 errors
10
11 log
12
13 health
14
15 kubernetes cluster.local in-addr.arpa ip6.arpa {
16
17 pods insecure
18
19 fallthrough in-addr.arpa ip6.arpa
20
21 }
22
23 prometheus :9153
24
25 forward . 192.168.56.21 192.168.1.68
26
27 cache 30
28
29 loop
30
31 reload
32
33 loadbalance
34
35 }
其中192.168.56.21和192.168.1.68是 Amazon Route53 resolver 的入栈终端节点
(备注:此方案会额外产生 Amazon Route53 resolver 费用)
性能测试
我们可以使用 dnsperf 工具对 CoreDNS 进行测试,我们先创建一个 Pod,在 Pod 中安装 dnsperf,模拟 DNS 查询客户端。安装命令如下
(备注:根据操作系统下载对应的版本):
1rpm -ivh https://download-ib01.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/e/epel-release-8-11.el8.noarch.rpm
2
3yum install dnsperf
准备好压测的 DNS 列表,dns.txt 格式如下:
1www.test.com A
执行压测命令:
1dnsperf -l 30 -s 10.100.0.10 -d dns.txt
(备注:其中-l代表压测时长,-s代表域名服务器地址,-d指向压测域名的配置文件)
压测环境:
使用 3 台 c5.xlarge,压测的 dnsperf Pod 和 CoreDNS Pod 分布在不同的 Node 上, CoreDNS 使用默认资源配置
压测结果:
(备注:因为测试域名只有一个,未必能反应实际业务场景,实际数据会随着节点性能、CoreDNS 的资源分配而有差异,其中 Cache 设置为 0 是为了测试缓存未命中的情况下 CoreDNS 的实际性能)
结果分析:
CoreDNS cache 对外部域名查询性能影响很大
增加 CoreDNS pod 个数基本可以线性增加 QPS
使用 Route53 resolver 可以提升单个 CoreDNS Pod 对外查询的 QPS
总结
通过以上方法,在大规模 Amazon EKS 集群中在遇到 DNS 查询性能问题的时候,我们根据不同的场景可以采取不同的解决办法,能够有效的提升 Amazon EKS 集群处理大并发域名解析的能力。对应的场景和方案选取如下(几种优化措施可以同时启用)。
增加 CoreDNS pod 个数和使用 Route 53 resolver 的方式可以突破 EC2 单网卡查询请求 DNS 最大 1024 QPS 的限制,在单个 CoreDNS 达到 QPS 上限的时候可以使用。
使用 NodeLocal DNSCache 和增加 CoreDNS cache 的方式对可以命中缓存的查询可以有效的提升 DNS 查询 QPS 和性能。需要注意的是增加 cache 都会增加 DNS 的缓存时间,如果对 DNS TTL 敏感的应用需要平衡考量。
修改 Ndots 和启用 autopath 都是为了降低外部域名查询的时候的无效请求,Ndots 的方式操作简单但可能会影响跨集群的应用调用, autopath 会增加 CoreDNS 的内存占用,一般情况下选择一种配置即可。
参考链接
https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/coredns.html
https://github.com/kubernetes/kubernetes/issues/33554#issuecomment-266251056
https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/resolver-getting-started.html
https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/vpc-dns.html#vpc-dns-limits
https://github.com/kubernetes/perf-tests/tree/master/dns
本篇作者
柳向全
亚马逊云科技解决方案架构师
负责基于亚马逊云科技的云计算方案架构的咨询和设计,目前主要专注于容器和大数据技术领域研究和亚马逊云科技云服务在国内和全球的应用和推广。
听说,点完下面4个按钮
就不会碰到bug了!