《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路

书籍来源:《Kubernetes网络权威指南:基础、原理与实践》

一边学习一边整理读书笔记,并与大家分享,侵权即删,谢谢支持!

附上汇总贴:《Kubernetes网络权威指南》读书笔记 | 汇总_COCOgsta的博客-CSDN博客


Kubernetes DNS服务目前有两个实现,分别是Kube-dns和CoreDNS。

4.3.1 Kube-dns的工作原理

Kube-dns架构历经两个较大的变化。Kubernetes 1.3之前使用etcd+kube2sky+SkyDNS的架构,Kubernetes 1.3之后使用kubedns+dnsmasq+exechealthz的架构,这两种架构都利用了SkyDNS的能力。下面将分别详解Kube-dns的这两种架构。

  1. etcd+kube2sky+SkyDNS

etcd+kube2sky+SkyDNS属于第一个版本的Kube-dns架构,包含三个重要的组件,分别是:

  • etcd:存储所有DNS查询所需的数据;
  • kube2sky:观察Kubernetes API Server处Service和Endpoints的变化,然后同步状态到Kube-dns自己的etcd;
  • SkyDNS:监听在53端口。根据etcd中的数据对外提供DNS查询服务。etcd+kube2sky+SkyDNS版本的Kube-dns架构如图4-13所示。

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第1张图片

图4-13 etcd+kube2sky+SkyDNS版本的Kube-dns架构

SkyDNS配置etcd作为后端数据储存,当Kubernetes cluster中的DNS请求被SkyDNS接受时,SkyDNS从etcd中读取数据,然后封装数据并返回,完成DNS请求响应。Kube2Sky通过watch Service和Endpoints更新etcd中的数据。

假设etcd容器ID为0fb60dcfb8b4,下面让我们一窥Service的Cluster IP在etcd中的数据存储:

如上所示,位于default namespace的服务mysql-service的Cluster IP为10.254.162.44。SkyDNS的基本配置信息也存在etcd中,例如Kube-dns IP地址、域名后缀等。如下所示:

不难看出,SkyDNS是真正对外提供DNS查询服务的组件,kube2sky是Kubernetes到SkyDNS之间的“桥梁”,而etcd则存储Kubernetes只涉及域名解析部分的API对象。这个版本的Kube-dns选择直接部署SkyDNS进程来提供域名解析服务。

  1. kubedns+dnsmasq+exechealthz

新演进的Kube-dns架构如图4-14所示。

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第2张图片

图4-14 新演进的Kube-dns架构

Kube-dns包含以下三个核心组件:

  • kubedns:从Kubernetes API Server处观察Service和Endpoints的变化并调用SkyDNS的 golang库,在内存中维护DNS记录。kubedns作为dnsmasq的上游在dnsmasq cache未命中时提供DNS数据;
  • dnsmasq:DNS配置工具,监听53端口,为集群提供DNS查询服务。dnsmasq提供DNS缓存,降低了kubedns的查询压力,提升了DNS域名解析的整体性能;
  • exechealthz:健康检查,检查Kube-dns和dnsmasq的健康,对外提供/healthz HTTP接口以查询Kube-dns的健康状况。

这个版本的Kube-dns和之前版本的区别在于:

  • 从Kubernetes API Server那边观察(watch)到的Service和Endpoints对象没有存在etcd,而是缓放在内存中,既提高了查询性能,也省去了维护etcd存储的工作量;
  • 引入了dnsmasq容器,由它接受Kubernetes集群中的DNS请求,目的就是利用dnsmasq的cache模块,提高解析性能;
  • 没有直接部署SkyDNS,而是调用了SkyDNS的golang库,相当于之前的SkyDNS和Kube2Sky整合到了一个进程中;
  • 增加了健康检查功能。

运行过程中,dnsmasq在内存中预留一个缓冲区(默认是1GB),保存最近使用到的DNS查询记录。如果缓存中没有要查找的记录,dnsmasq会去kubeDNS中查询,同时把结果缓存起来。

需要注意的是,dnsmasq是一个C++写的小程序,有内存泄漏的“小毛病”。

综上所述,无论是哪个版本的架构,Kube-dns的本质就是一个Kubernetes API对象的监视器+SkyDNS。

4.3.2 上位的CoreDNS

CoreDNS作为CNCF中托管的一个域名发现的项目,原生集成Kubernetes,它的目标是成为云原生的DNS服务器和服务发现的参考解决方案。所以,CoreDNS走的也是Traefik的路子,降维打击SkyDNS。

从Kubernetes 1.12开始,CoreDNS就成了Kubernetes的默认DNS服务器,但kubeadm默认安装CoreDNS的时间要更早。在Kuberentes 1.9版本中,使用kubeadm方式安装的集群可以通过以下命令直接安装CoreDNS。

下面,我们将详细解释CoreDNS的架构设计和基本用法。

从功能角度看,CoreDNS更像是一个通用的DNS方案,通过插件模式极大地扩展自身功能,从而适用于不同的场景。正如CoreDNS官方博客描述的那样:

CoreDNS is powered by plugins.

CoreDNS有以下3个特点。

(1)插件化(Plugins)。基于Caddy服务器框架,CoreDNS实现了一个插件链的架

构,将大量应用端的逻辑抽象成插件的形式(例如,Kubernetes 的DNS服务发现、Prometheus监控等)暴露给使用者。CoreDNS以预配置的方式将不同的插件串成一条链,按序执行插件链上的逻辑。在编译层面,用户选择需要的插件编译到最终的可执行文件中,使得运行效率更高。CoreDNS采用Go语音编写,所以从代码层面来看,每个插件其实都只实现了CoreDNS定义的接口的组件而已。第三方开发者只要按照CoreDNS Plugin API编写自定义插件,就可以很方便地集成到CoreDNS中。

(2)配置简单化。引入表达力更强的DSL,即Corefile形式的配置文件(也是基于Caddy框架开发的)。

(3)一体化的解决方案。区别于Kube-dns“三合一”的架构,CoreDNS编译出来就是一个单独的可执行文件,内置了缓存、后端存储管理和健康检查等功能,无须第三方组件辅助实现其他功能,从而使部署更方便,内存管理更安全。

  1. Corefile知多少

Corefile是CoreDNS的配置文件(源于Caddy框架的配置文件Caddyfile),它定义了:

  • DNS server以什么协议监听在哪个端口(可以同时定义多个server监听不同端口);
  • DNS负责哪个zone的权威(authoritative)DNS解析;
  • DNS server将加载哪些插件。

通常,一个典型的Corefile格式如下:

  • ZONE:定义DNS server负责的zone,PORT是可选项,默认为53;
  • PLUGIN:定义DNS server要加载的插件,每个插件可以有多个参数。例如:

上述配置文件表达的是:DNS server负责根域.的解析,其中插件是chaos且没有参数。

1)定义DNS server

一个最简单的DNS server配置文件如下:

即DNS server监听53端口并且不使用任何插件。如果此时定义其他DNS server,需要保证监听端口不冲突。如果是在原来DNS server的基础上增加zone,则要保证zone之间不冲突。例如:

如上所示,另一个DNS server监听在54端口并负责根域.的解析。

又如:

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第3张图片

这是同一个DNS server但是负责不同zone的解析,而且有不同的插件链。

2)定义Reverse Zone

跟其他DNS服务器类似,Corefile也可以定义Reverse Zone:

或者简化版本:

3)使用不同的通信协议

CoreDNS除了支持DNS协议,也支持TLS和gRPC,即DNS-over-TLS和DNS-overgRPC模式。例如:

  1. 插件工作模式

当CoreDNS启动后,它将根据配置文件启动不同的DNS server,每个DNS server都拥有自己的插件链。当新来一个DNS请求时,它将依次经历以下3步逻辑:

(1)如果当前请求的DNS server有多个zone,则将采用贪心原则选择最匹配的zone。

(2)一旦找到匹配的DNS server,按照plugin.cfg定义的顺序遍历执行插件链上的插件。

(3)每个插件将判断当前请求是否应该处理,将有以下几种可能的情况:

  • 请求被当前插件处理。插件将生成对应的响应并返回客户端,此时请求结束,下一个插件将不会被调用,如whoami插件;
  • 请求不被当前插件处理。直接调用下一个插件。如果最后一个插件执行错误,服务器返回SERVFAIL响应;
  • 请求被当前插件以Fallthrough的形式处理。如果请求在该插件处理过程中有可能跳转至下一个插件,该过程称为fallthrough,并以关键字fallthrough决定是否允许此项操作。例如,host插件尝试用/etc/hosts查询域名,如果没有查询到则会调用下一个插件;
  • 请求在处理过程携带hint。请求被插件处理,并在其响应中添加了某些提示信息(hint),继续交由下一个插件处理。这些额外的信息将组成对客户端的最终响应,例如metric插件。
  1. CoreDNS请求处理工作流

下面将以一个实际的Corefile为例,详解CoreDNS处理DNS请求的工作流。Corefile如下所示:

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第4张图片

通过配置文件不难看出,我们定义了两个DNS server(尽管有4个配置块),分别监听5300和53端口。将以上Corefile翻译成处理逻辑图,如图4-15所示。

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第5张图片

图4-15 CoreDNS请求处理流程

每个进入某个DNS server的请求将按照plugin.cfg的定义顺序执行其已经加载的插件。

需要注意的是,尽管在.:53配置了health插件,但是它并未在上面的逻辑图中出现,原因是该插件并未参与请求相关的逻辑(即并没有在插件链上),只是修改了DNS server的配置。通常,我们可以将插件分为两种:

  • Normal插件:参与请求相关的逻辑,且插入插件链中;
  • 其他插件:不参与请求相关的逻辑,也不出现在插件链中,只是用于修改DNS server的配置,例如health、tls等插件。
  1. 性能测试下面介绍CoreDNS的域名解析性能和资源消耗情况,如表4-4所示。

表4-4 CoreDNS的域名解析性能和资源消耗情况

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第6张图片

值得一提的是,以上性能测试数据是在不带cache的情况下取得的,一般情况下要高于Kube-dns,具体的CoreDNS与Kube-dns的性能对比数据请看下文。

4.3.3 Kube-dns VS.CoreDNS

虽然Kube-dns血统纯正,而且早早地进入Kubernetes的“后宫”,也早有“名分”,但近来CoreDNS却独得Kubernetes Network工作小组核心成员“圣宠”,它不仅早早地进入CNCF,就连其中一位创始人也被挖到谷歌的Kubernetes核心团队担任资深工程师(senior staff engineer)。

与Kube-dns的三进程架构不同,CoreDNS就一个进程,运维起来更加简单。而且采用Go语言编写,内存安全,高性能。值得称道的是,CoreDNS采用的是“插件链”架构,每个插件挂载一个DNS功能,保证了功能的灵活、易扩展。尽管资历不深,却“集万千宠爱于一身”,自然是有绝技的。

下面我们从性能和功能两个维度全面对比Kube-dns和CoreDNS。

  1. 性能对比

下面从内存、CPU、QPS和时延这4个维度对比Kube-dns和CoreDNS的性能和资源消耗。内存和CPU消耗

CoreDNS和Kube-dns都维护集群中所有服务和端点的本地缓存。因此,随着服务和端点数量的增加,每个DNS Pod的内存要求也会增加。在默认设置下,CoreDNS应该比Kube-dns使用更少的内存,这是由于部署Kube-dns需要使用三个容器,而CoreDNS只要一个容器便足够。

图4-16对比了随着集群内服务和Pod数量的增加,CoreDNS和Kube-dns消耗的内存。

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第7张图片

图4-16 CoreDNS和Kube-dns内存消耗对比

当Kube-dns 和CoreDNS分别达到最大QPS负载时,观测CPU的使用量分别是58Mi(Kube-dns)和5Mi(CoreDNS)。

注:Mi是CPU核心数的度量单位,代表千分之一核,因此58Mi即0.058核,5Mi即0.005核。

QPS和时延

从表4-5所示的数据中可以看出:

  • Kube-dns对外部域名解析(例如kubernetes.default.svc.cluster.local)的表现比CoreDNS要好10%左右。这可能是因为dnsmasq比CoreDNS的内置缓存做了更多的性能优化;
  • CoreDNS对外部域名解析的性能提高了约3倍。部分原因可能是Kube-dns没有在缓存中存储DNS查询的负面响应(例如访问一个不存在的域名)。然而,即使Kube-dns在缓存中存储了负面响应也没有明显的区别,数据如表4-6所示。

表4-5 Kube-dns和CoreDNS的QPS和时延对比

《Kubernetes网络权威指南》读书笔记 | 沧海桑田:Kubernetes DNS架构演进之路_第8张图片

表4-6 Kube-dns在缓存中存储了负面响应时响应内/外部域名请求的QPS与时延

  1. 功能对比

为什么建议使用CoreDNS呢?Kubernetes官方已经将CoreDNS“扶正”,成为了默认模式,除了性能好,还有什么其他优势吗?Core DNS修复了Kube-dns的一些“令人讨厌”的的问题:

  • dns#55-Allow custom DNS entries for Kube-dns(允许Kube-dns自定义DNS记录);
  • dns#116-Missing‘A’records for headless service with pods sharing hostname(当后端Pod共享主机名时,headless Service丢失A记录);
  • dns#131-ExternalName not using stubDomains settings(stubDomains配置对External-Name Service不生效);
  • dns#167-Enable round robin A/AAAA records(启用Kube-dns A/AAAA记录的轮询);
  • dns#190-Kube-dns cannot run as non-root user(只有root用户才能运行Kube-dns);
  • dns#232-Use pod’s name instead of pod’s hostname in DNS SRV records(在DNS SRV记录中使用Pod名而不是Pod主机名)。

同时,还有一些吸引人的特性:

  • Zone transfers-list all records,or copy records to another server(CoreDNS允许将全部或部分的DNS记录复制到另一个CoreDNS服务器);
  • Namespace and label filtering-expose a limited set of services(基于namespace和labels过滤一部分Service记录);
  • Adjustable TTL-adjust up/down default service record TTL(动态调整DNS记录的TTL);
  • Negative Caching-By default caches negative responses(默认存储DNS查询的负面响应);

其中,原生支持基于namespace和labels隔离及过滤Service和Pod的DNS记录这一特性,在多租户场景下格外有用。

4.3.4 小结

无论是Kube-dns还是CoreDNS,基本原理都是利用watch Kubernetes的Service和Pod,生成DNS记录,然后通过重新配置Kubelet的DNS选项让新启动的Pod使用Kube-dns或CoreDNS提供的Kubernetes集群内域名解析服务。

你可能感兴趣的:(kubernetes,网络,架构)