Kube-dns 架构经历两个比较大的变化。kubernetes 1.3之前使用etcd+kube2sky+SkyDNS的架构。kubernetes 1.3 之后使用 kubedns+dnsmasq+exechealthz 架构,这两种架构都利用了SkyDNS的能力。SkyDNS支持正向查找(A记录)、服务查找(SRV记录)和反向IP地址查找(PTR记录)。
etcd+kube2sky+SkyDNS
etcd+kube2sky+SkyDNS 是属于第一个版本的kube-dns架构,包含三个重要的组件,分别是:
etcd:存储所有DNS查找所需的数据;
kube2sky:观察kubernetes API Server 和Endpoint 的变化,然后同步状态到kube-dns自己的etcd;
SkyDNS:监听在53 端口,根据etcd中的数据对外提供DNS查询服务;
结构图如下
(由于图片大小限制上传不了,敬请谅解)
SkyDNS 配置etcd作为后端数据的存储,当kubernetes cluster 中国的DNS请求被SkyDNS接收时,SkyDNS会从etcd中读取数据,然后封装数据并返回,完成DNS请求响应。kube2sky 通过watch Service 和Endpoint 更新etcd中的数据。
假设 etcd 容器ID为 0fb60dxxx,下面我们来看看Service的Cluster IP在etcd中的数据存储。
docker exec -it 0fb60d etcdctl get /skydns/local/kube/svc/default/mysql-service
{"host":"10.254.162.44", "priority":10, "weught":10."ttl":30,"targetstrip":0}
如上所示,位于default namespace 的服务mysql-service 的cluster IP为 10.254.162.44.
SkyDNS 的基本配置信息也存在了etcd中,例如kube-dns IP地址、域名后缀等。如下所示:
docker exec -it ofb6od etcdctl get /skydns/config
{"dns-addr":"10.254.10.2:53","ttl":30,"domain":"cluster.local"}
不难看出,SkyDNS是正式对外提供查询服务的组件,kube2sky是kubernetes到SkyDNS之间的桥梁,而etcd是存储kubernetes只涉及域名接卸部分的API对象。这个版本的kube-dns直接部署SkyDNS进程来提供域名解析服务。
kubedns+dnsmasq+exechealthz
新演进的kube-dns架构如图
(由于图片大小限制上传不了,敬请谅解)
kube-dns包含三个核心组件:
这个版本的kube-dns和之间的版本区别在于:
运行过程中,dnsmasq在内存中预留了一个缓冲区(默认是1G),保留最近使用的DNS查询记录,如果缓存中没有找到要查询的记录,dnsmasq会向kubedns中查询,同时把记录缓存起来。
注:dnsmasq是使用C++写的一个小程序,存在内存泄漏的“小毛病”
综上所述,不管是哪种架构,kube-dns的本质都是一个kubernetes API对象的监视器+SkyDNS;
CoreDNS作为CNCF中托管的一个域名发现项目,原生集成kubernetes,它的目标是成为云原生的DNS服务器和服务发现的参考解决方案。虽有,CoreDNS走的也是TraeFik的路子,姜维打击SkyDNS。
从kubernetes1.12开始,CoreDNS就成为kubernetes的默认DNS服务器,但是kubeadm默认安装CoreDNS的时间更早。在kubernetes 1.9版本中,使用kubeadm方式安装的集群可以通过以下明明直接安装CoreDNS。
kubeadm init --feature-getas=CoreDNS=true
下面我们将详细讲解CoreDNS的架构设计和基本用法。
从功能角度看,CoreDNS更像是一个通用的DNS方案,通过插件模式极大地扩展自身功能,从而适应不同的场景。
CoreDNS有以下三个特点:
Corefile是CoreDNS的配置文件(源于Caddy框架的配置文件Caddyfile),它定义了:
通常,一个典型的Corefile格式如下:
ZONR:{PORT} {
[PLUGIN] ...
}
. {
chaos CoreDNS-001
}
上诉配置文件表达的是:DNS server负责根域 . 的解析,其中插件就是 chaos 且没有参数。
1)定义 DNS server
一个简单的DNS server配置文件如下:
.{}
即DNS server监听53端口,并且不适用任何插件。如果此时定义其他DNS server,需要保证监听端口不冲突。如果在原来 DNS server的基础上增加zone,则保证zone之间不冲突。例如:
. {}
.:54 {}
如上所示,另一个 DNS server监听在54端口,负责根域 . 的解析。
又如:
example.org {
whomi
}
org {
whomi
}
这是同一个DNS server但是负责不同zone的解析,而且有不同的插件链。
2)定义Reverse Zone
根其他DNS 服务器类似,Corefile也可以定义Reverse Zone:
0.0.10.in-addr.arpa {
whoami
}
或者简化版本:
10.0.0.0/24 {
whomi
}
3) 使用不同的通信协议
CoreDNS 除了支持DNS 协议,也支持 TLS 和gRPC,即DNS-over-TLS和DNS-over-gRPC模式。例如:
tls://example.org:1443 {
#...
}
CoreDNS启动后,它将根据配置文件启动不同的DNS server,每个DNS server 都有自己的插件链。当新来一个DNS请求时,它将经历以下3步逻辑:
(1)如果当前请求的DNS server有多个zone,则将采用贪心原则选择最匹配的zone;
(2)一旦找到匹配的DNS server,按照plugin.cfg 定义的顺序,便利插件链上的插件;
(3)每个插件判断当前请求是否应该处理,将有以下几种可能的情况:
下面将以一个实际的Corefile为例,详解CoreDNS处理DNS请求的工作流。Corefile如下所示:
coredns.io:5300 {
file /etc/coredns/zones/coredns.io.db
}
example.io:53 {
errors
log
file /etc/coredns/zones/example.io.db
}
example.net:53 {
file /etc/coredns/zones/example.net.db
}
.:53 {
errors
log
health
rewrite name foo.example.com foo.default.svc.cluster.local
}
通过配置文件不难看出,我们定义了两个DNS server(尽管有4个配置块),分别监听5300和53端口。将以上Corefile 翻译成处理逻辑图,如图所示:
(由于图片大小限制上传不了,敬请谅解)
每个进入某个DNS server的请求将按照 plugin,cfg 的定义顺序执行其已经加载的差劲。
需要注意的是,尽管在.:53配置了health插件,但是它并未在上面的逻辑图中出现,原因是该插件并未参与请求相关的逻辑(即并没有在插件链上),只是修改了DNS server的配置。通常我们可以将插件分为两类: