coredns 是用 go 语言写的高性能,高扩展性的 DNS 服务,是Kubernetes集群内负责域名解析的组件,集群内主要有两种资源拥有域名(FQDN域名)
Service资源
访问FQDN域名,coredns会把该域名解析成service的Cluster IP
1 | <Service Name>.<namespace>.svc.cluster.local. |
拥有固定名字的Pod + Headless Service
访问FQDN域名,coredns会把该域名解析成Pod IP
1 | # statefulset创建的Pod拥有固定的名字,手动定义的裸Pod也拥有固定的名字 |
DNS 策略可以单独对 Pod 进行设定,目前 Kubernetes 支持以下特定 Pod 的 DNS 策略。这些策略可以 在 Pod 规范中的 dnsPolicy 字段设置:
Default
Pod中的/etc/resolv.conf
的内容与自己所在的宿主机上的/etc/resolv.conf
内容一致,coredns组件的Pod一般会采用这种配置。
1 | 注意:说 Default 策略是使用宿主机的配置,这种说法并不准确。其实决定 Defalut 策略使用哪个文件的是宿主机的 kubelet 组件,而 kubelet 默认的方式,就是使用宿主机的 /etc/resolv.conf 文件。 |
ClusterFirst
优先使用集群内的dns,就是用coredns来解析,这是默认的方式
1 | 这种方式表示 Pod 内的 DNS 使用集群中配置的 DNS 服务,简单来说,就是使用 coredns 服务进行域名解析。coredns如果解析不成功,coredns会使用宿主机的 DNS 配置进行解析。 |
ClusterFirstWithHostNet
对于使用HostNet网络的Pod,依然采用clusterfirst策略
1 | 在某些场景下,我们的 Pod 是用 HostNetwork 模式启动的,一旦用 HostNetwork 模式,表示这个 Pod 中的所有容器,都要使用宿主机的 `/etc/resolv.conf` 配置进行 DNS 查询,但如果还想继续使用 Kubernetes 的 DNS 服务,那就将 dnsPolicy 设置为 ClusterFirstWithHostNet |
None
不需要k8s自动生成/etc/resolv.conf
文件,我会自己在Pod的yaml中定义
1 | 这种方式一般用于想要自定义 DNS 配置的场景,往往需要和 dnsConfig 配合一起使用达到自定义 DNS 的目的。dnsConfig详见下一小节 |
Pod的资源清单中,dnsConfig
字段是可选的,它可以与任何 dnsPolicy
设置一起使用。 但是,当 Pod 的 dnsPolicy
设 置为 “None” 时,则必须指定 dnsConfig
字段。
以下是具有自定义 DNS 设置的 Pod 示例:
1 | apiVersion: v1 |
创建上面的 Pod 后,容器 test 会在其 /etc/resolv.conf 文件中生成以下内容:
1 | nameserver 1.2.3.4 |
1 | # 编辑coredns的configmap,然后重启coredns |
集群规模大的情况,codedns 可能会出现超时5s的情况(dns请求超时,客户端默认策略时等待5s自动重试,如果重试成功,我们看到的现象就是dns请求有5s的延时),这对我们影响很大。
超时的原因是因为:无论你用的是iptables模式还是ipvs模式,它们的底层都会用到 conntrack内核模块 来组织dns的udp查询包,高并发场景,会出现conntrack冲突问题,导致一些dns请求包被丢掉,从而导致超时。
一个解决办法是在每个物理节点上缓存 DNS 解析记录,这可以缩短 DNS 查找的延迟时间,使 DNS 查找时间更加一致,以及减少发送到 coredns 的 DNS 查询次数。这就是 NodeLocal DNSCache 服务的作用,它采用的是DaemonSet控制器,确保每个节点都有一个NodeLocal DNSCache实例,使用HostNetwork网络模式,每个物理节点上启动起来的pod都监听在 169.254.20.10,当 Pod 尝试解析一个域名时,它将按照 /etc/resolv.conf 中的配置发送 DNS 查询到 169.254.20.10, Daemonset 会在每个节点创建一个网卡来绑这个 IP,Pod 向本节点这个 IP 发 DNS 请求, 由于 NodeLocal DNSCache 已经在该地址上监听,它会接收到查询并相应地处理。 如果 NodeLocal DNSCache 有缓存的响应或者知道答案,它将直接响应; 如果没有,它会将请求转发到集群的上游 DNS 服务器,例如 CoreDNS,然后再将响应返回给请求者。 这种方法可以减少 DNS 查询的延迟,并提高集群的整体性能。
部署NodeLocal DNSCache
1 | # 下载官方提供的资源清单文件 |
部署成功后,会占用宿主机的8080端口,需要提前保证该端口未被占用。
在IPVS模式下,此时还需要修改 kubelet 的 --cluster-dns
参数,将其指向 169.254.20.10
,然后重启kubelet 即可。
如果是iptables模式, Pod 还是向原来的集群 DNS 请求,节点上有这个 IP 监听,会被本机拦截,再请求集群 上游 DNS,所以不需要更改 --cluster-dns
参数。