作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,这就需要一个集群范围内的DNS服务来完成从服务名到ClusterIP地址的解析。DNS服务在Kubernetes的发展过程中经历了3个阶段,接下来进行讲解。
在Kubernetes 1.2版本时,DNS服务是由SkyDNS提供的,它由4个容器组成:kube2sky、skydns、etcd和healthz。kube2sky容器监控Kubernetes中Service资源的变化,根据Service的名称和IP地址信息生成DNS记录,并将其保存到etcd中;skydns容器从etcd中读取DNS记录,并为客户端容器应用提供DNS查询服务;healthz容器提供对skydns服务的健康检查功能。
图4.3展现了SkyDNS的总体架构。

图4.3 SkyDNS的总体架构
从Kubernetes 1.4版本开始,SkyDNS组件便被KubeDNS替换,主要考虑的是SkyDNS组件之间通信较多,整体性能不高。KubeDNS由3个容器组成:kubedns、dnsmasq和sidecar,去掉了SkyDNS中的etcd存储,将DNS记录直接保存在内存中,以提高查询性能。kubedns容器监控Kubernetes中Service资源的变化,根据Service的名称和IP地址生成DNS记录,并将DNS记录保存在内存中;dnsmasq容器从kubedns中获取DNS记录,提供DNS缓存,为客户端容器应用提供DNS查询服务;sidecar提供对kubedns和dnsmasq服务的健康检查功能。图4.4展现了KubeDNS的总体架构。

图4.4 KubeDNS的总体架构
从Kubernetes 1.11版本开始,Kubernetes集群的DNS服务便由CoreDNS提供。CoreDNS是CNCF基金会孵化的一个项目,是用Go语言实现的高性能、插件式、易扩展的DNS服务端,目前已毕业。CoreDNS解决了KubeDNS的一些问题,例如dnsmasq的安全漏洞、externalName不能使用stubDomains进行设置,等等。CoreDNS支持自定义DNS记录及配置upstream DNS Server,可以统一管理Kubernetes基于服务的内部DNS和数据中心的物理DNS。它没有使用多个容器的架构,只用一个容器便实现了KubeDNS内3个容器的全部功能。图4.5展现了CoreDNS的总体架构。

图4.5 CoreDNS的总体架构
接下来以CoreDNS为例,说明Kubernetes集群DNS服务的搭建过程。
修改每个Node上kubelet的启动参数,在其中加上以下两个参数。
◎ --cluster-dns=169.169.0.100:为DNS服务的ClusterIP地址。
◎ --cluster-domain=cluster.local:为在DNS服务中设置的域名。
然后重启kubelet服务。
部署CoreDNS服务时需要创建3个资源对象:1个ConfigMap、1个Deployment和1个Service。在启用了RBAC的集群中,还可以设置ServiceAccount、ClusterRole、ClusterRoleBinding对CoreDNS容器进行权限设置。
ConfigMap“coredns”主要设置CoreDNS的主配置文件Corefile的内容,其中可以定义各种域名的解析方式和使用的插件,示例如下(Corefile的详细配置说明参见4.3.4节):


Deployment“coredns”主要设置CoreDNS容器应用的内容,其中,replicas副本的数量通常应该根据集群的规模和服务数量确定,如果单个CoreDNS进程不足以支撑整个集群的DNS查询,则可以通过水平扩展提高查询能力。由于DNS服务是Kubernetes集群的关键核心服务,所以建议为其Deployment设置自动扩缩容控制器,自动管理其副本数量。
另外,对资源限制部分(CPU限制和内存限制)的设置也应根据实际环境进行调整:



Service“kube-dns”是DNS服务的配置,这个服务需要设置固定的ClusterIP地址,也需要将所有Node上的kubelet启动参数--cluster-dns都设置为这个ClusterIP地址:


通过kubectl create命令完成CoreDNS服务的创建:

查看Deployment、Pod和Service,确保容器成功启动:

接下来使用一个带有nslookup工具的Pod来验证DNS服务能否正常工作:


运行kubectl create-f busybox.yaml即可完成创建。
在该容器成功启动后,通过kubectl exec <container_id>--nslookup进行测试:

可以看到,通过DNS服务器169.169.0.100成功解析了redis-master服务的IP地址169.169.8.10。
如果某个Service属于不同的命名空间,那么在进行Service查找时,需要补充Namespace的名称,将其组合成完整的域名。下面以查找kube-dns服务为例,将其所在Namespace“kube-system”补充在服务名之后,用“.”连接为“kube-dns.kube-system”,即可查询成功:

如果仅使用“kube-dns”进行查找,则会失败:

CoreDNS的主要功能是通过插件系统实现的。CoreDNS实现了一种链式插件结构,将DNS的逻辑抽象成了一个个插件,能够灵活组合使用。
常用的插件如下。
◎ loadbalance:提供基于DNS的负载均衡功能。
◎ loop:检测在DNS解析过程中出现的简单循环问题。
◎ cache:提供前端缓存功能。
◎ health:对Endpoint进行健康检查。
◎ kubernetes:从Kubernetes中读取zone数据。
◎ etcd:从etcd中读取zone数据,可用于自定义域名记录。
◎ file:从RFC1035格式文件中读取zone数据。
◎ hosts:使用/etc/hosts文件或者其他文件读取zone数据,可用于自定义域名记录。
◎ auto:从磁盘中自动加载区域文件。
◎ reload:定时自动重新加载Corefile配置文件的内容。
◎ forward:转发域名查询到上游DNS服务器上。
◎ prometheus:为Prometheus系统提供采集性能指标数据的URL。
◎ pprof:在URL路径/debug/pprof下提供运行时的性能数据。
◎ log:对DNS查询进行日志记录。
◎ errors:对错误信息进行日志记录。
在下面的示例中为域名“cluster.local”设置了一系列插件,包括errors、health、ready、kubernetes、prometheus、forward、cache、loop、reload和loadbalance,在进行域名解析时,这些插件将以从上到下的顺序依次执行:


另外,etcd和hosts插件都可以用于用户自定义域名记录。
下面是使用etcd插件的配置示例,将以“.com”结尾的域名记录配置为从etcd中获取,并将域名记录保存在/skydns路径下:

如果用户在etcd中插入一条“10.1.1.1 mycompany.com”DNS记录:

客户端应用就能访问域名“mycompany.com”了:

forward插件用于配置上游DNS服务器或其他DNS服务器,当在CoreDNS中查询不到域名时,会到其他DNS服务器上进行查询。在实际环境中,可以将Kubernetes集群外部的DNS纳入CoreDNS,进行统一的DNS管理。