部署coredns
部署CoreDNS服务时需要创建3个资源对象:1个ConfigMap、1个Deployment和1个Service。在启用了RBAC的集群中,还可以设置ServiceAccount、ClusterRole、ClusterRoleBinding对CoreDNS容器进行权限设置。
ConfigMap”coredns”主要设置CoreDNS的主配置文件Corefile的内容,其中可以定义各种域名的解析方式和使用的插件。
在下面的示例中为域名“cluster.local”设置了一系列插件,包括errors、health、ready、kubernetes、prometheus、forward、cache、loop、reload和loadbalance,在进行域名解析时,这些插件将以从上到下的顺序依次执行:
forward插件用于配置上游DNS服务器或其他DNS服务器,当在CoreDNS中查询不到域名时,会到其他DNS服务器上进行查询。在实际环境中,可以将Kubernetes集群外部的DNS纳入CoreDNS,进行统一的DNS管理。
pod dns 文件
/etc/resolv.conf
1 |
|
DNS 服务器 – nameserver
为什么请求这个地址可以进行 DNS 解析. 这个答案就是 iptables
, 我仅截取 UDP 的 53 端口, 以下内容可以通过iptables-save
获得.
1 |
|
我们再看下这条链KUBE-SVC-TCOU7JCQXEZGVUNU
:
1 |
|
Kubernetes 的 Deployment
再看下我们的 Kubernetes 中 Pod 的 IP 地址, 也就是说, DNS 请求实际上会到我们的 Coredns 容器中被处理.
1 |
|
Kubernetes 中 Service 的具体实现
再查看下对应的 Service, 可以看到, 上述机器中的 Iptables 其实就是 Service 的具体实现方式.
1 |
|
可能有人会有疑问, 现在是 2 个 Pod 可以均分流量, 如果是 3 个, 4 个 Pod, Iptables 是如何做转发的呢, 正好我有这个疑问, 因此我就再加了 2 个 Pod, 看看iptables
是怎么实现对于 4 个 Pod 均分流量的.
这是最后的实现方式:
1 |
|
这些语句的意思应该是:
- 前 1/4 的流量到一条链中, 剩 3/4
- 剩下 3/4 的流量, 1/3到一条链, 剩 2/4
- 剩下 2/4 的浏览, 1/2到一条链, 剩 1/4
- 最后 1/4 到一条链
通过这样的方式对流量进行了均分, 还是挺巧妙的, 这样, 5个,10个也是可以依次去分的。
search
假如没有这个search
参数, 我们查找时:
1 |
|
如果增加了search
参数后, 再去查找:
1 |
|
可以看到, 解析域名时, 如果给定的域名无法查找, 会添加search
后面的后缀进行查找(假如以.
结尾, 类似kube-dns.
, 这样的域名不会再去尝试, FQDN域名).
search
的工作就是帮我们去尝试, 用在 Kubenetes 中, 配置kube-system.svc.cluster.local svc.cluster.local cluster.local
就会帮我们尝试, 我们ping abc
, 就会这样进行查询
1 |
|
ndots
search
配置需要与ndots
一起使用, 默认的ndots
是 1,
它的作用是: 如果检查到被查询的域名中dot
的数量小于该值时, 就会优先尝试添加search
域中的后缀。
1 |
|
实际举例
假如我们的 DNS 配置如下:
1 |
|
当我们ping abc.123
(此域名只有一个 dot ), DNS 服务器的日志如下, 可以注意到日志中最先尝试的是abc.123.kube-system.svc.cluster.local.
, 最后才会尝试我们的域名.
1 |
|
那我们ping abc.123.def
(此域名有两个 dot), DNS 服务器的日志像下面这样, 注意到日志中最优先尝试的是abc.123.def.
1 |
|
希望借这个例子让大家明白两点:
-
无论 ndots 是多少, search 参数中的后缀都会被以此查找(我们测试时使用了一个不存在的域名, 解析工具尝试了全部的可能)
-
ndots 的不妥当设置, 可能会给 DNS 服务器造成压力(假如域名是存在的, dns查询会尽快返回, 不会继续查找了, 会减少服务器压力)
优化讨论
假如现在 ndots 是 2, 我们想要查询baidu.com
, 由于 dot 数目为 1 小于配置中的 2, 会首先添加后缀进行查找:
1 |
|
那么, 我们会产生 3 个无用的 DNS 查询记录. 对于DNS服务器来说, 仅仅是baidu.com
这个域名, 流量就变成了4倍. 假如 n继续增大呢, 就像是Kubernetes
中默认给定的5, 那我们会产生更多的无效请求, 因为不只是baidu.com
, 就连map.baidu.com
, m.map.baidu.com
, 这些域名也要从search域中开始尝试, 会对 DNS 服务器造成比较大的压力.
Node本地DNS缓存
由千在Kubernetes集群中配置的DNS服务是一个名为“kube-dns”的Service,所以容器应用都通过其ClusterIP地址(例如169.169.0.100)去执行服务名的DNS域名解析。
这对于大规模集群可能引起以下两个问题。
-
集群DNS服务压力增大(这可以通过自动扩容缓解)。
-
由于DKS服务的IP地址是Service的ClusterIP地址,所以会通过kube-proxy设置的iptables规则进行转发,可能导致域名解析性能很差,原因是Netfilter在做DNAT转换时可能会引起conntrack冲突,从而导致DNS查询产生5s的延时。
为了解决这两个问题,Kubemetes引人了Node本地DNS缓存(NodeLocalDNSCache)来提高整个集群的DNS域名解析的性能,这在1.18版本时达到Stable阶段。使用Node本地DNS缓存的好处如下。
- 在没有本地 DNS 缓存时,集群 DNS 服务的 Pod 很可能在其他节点上,跨主机访 问会增加网络延时,使用 Node 本地 DNS 缓存可显著减少跨主机查询的网络延时
- 跳过 iptables DNAT 和连接跟踪将有助于减少 conntrack 竞争, 并避免 UDP DNS记录坟满 conntrack表。
- 本地缓存到集群 DNS 服务的连接协议可以升级为 TCP。 TCP conntrack 条目将在连接关闭时被删除;默认使用 UDP时, conntrack条目只能等到超时时间过后才被删除,操作系统的默认超时时间 (nf_conntrack_udp_timeout) 为 30s。
- 将 DNS 查询从 UDP 升级为 TCP, 将减少由千丢弃的 UDP 数据包和 DNS 超时而 引起的尾部延迟 (tail latency ), UDP 超时时间可能会长 达 30s (3 次重试 , 每次10s )。
- 提供Node级别DNS解析请求的度量(Metrics)和可见性。
- 可以重新启用负缓存 (Negative caching) 功能,减少对集群 DNS 服务的查询地址。
客户端 Pod 首先会通过本地 DNS 缓存进行域名解析,当缓存中不存在域名时, 会将请求转发到集群 DNS 服务进行 解析。