kube-dns的前世今生

Tenxcloud · · 1315 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

上一期我们以1.2版本为背景,介绍了K8S的服务发现和kube-dns插件的相关内容。有了上一期内容作为基础,这期了解最新版本的kube-dns就会容易很多。 本文主要对比1.2和1.4版本中kube-dns 的主要变化,以及最新版本中kube-dns的内部实现。满满的干货来了,你准备好了吗? ## 大纲 ● kube-dns的主要变化 ● kube-dns的实现原理 ● kubedns容器详解 ● dnsmasq容器简介 ● exechealthz容器简介 ## 主要变化 **● 服务发现机制未变化** 也就是说kube-dns对外的接口是基本没变的。变化主要在于kube-dns插件的内部组成,由原来的四个容器变为了三个。 现在回顾一下上一期所讲的1.2版本kube-dns的组成。 Kube2sky通过K8S API监视K8S Service资源的变化,并根据Service的信息生成DNS记录写入到etcd中。Skydns为集群中的Pod提供DNS查询服务,DNS记录从etcd中读取。Exechealthz提供健康检查功能。 [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F1.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F1.png) 接下来我们再看一下1.4版本kube-dns的组成。对比两张图,可以很直观的看到kube-dns对外接口没有发生变化。Exechealthz是唯一保留的容器,依然提供健康检查。 **不同点:** 1.会检查两个容器的健康状态。 2.为集群提供DNS查询服务的容器由skydns变为了dnsmasq。 3.Kubedns容器替代了kube2sky来监视Service资源。 4.Etcd容器不见了。 [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F2.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F2.png) 相信有些人会好奇DNS记录现在保存在哪了呢?那为了回答这个问题以及了解新版kube-dns的工作原理,我们就进入下一章内容来了解其实现原理。 ## 实现原理 **● kubedns容器的实现** 本着“Talk is cheap, show me the code”原则,我们将会以源码分析的方式介绍其原理。对另外两个容器会进行简要介绍。 先来看一下源码位置,这里列出的是kube-dns插件相关的源码,不仅仅是kubedns容器的。之前的源码是集中在cluster/addons/dns下面的,那么1.4版本中分成了三个目录: ● 第一个目录会有K8S DNS相关的README以及kubedns容器的Dockerfile。 ● 第二个目录存放kube-dns插件的编排文件。 ● 第三个是kubedns源码目录,kubedns容器使用的命令行就是从这构建出来的。 ● kubedns容器的功能: ● 接入SkyDNS,为dnsmasq提供查询服务 ● 替换etcd容器,使用树形结构在内存中保存DNS记录 ● 通过K8S API监视Service资源变化并更新DNS记录 ● 服务10053端口 对功能有了大概了解之后,我们下面就结合源码来看看各个功能是如何实现的。 **● kubedns实现——SkyDNS接入** 下面是kubedns启动的部分代码,这部分显示的是kubedns在启动的时候会初始化一个SkyDNS Server,初始化的时候传入了一个KubeDNSServer.kd。 [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F3.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F3.png) 下面是KubeDNSServer.kd的初始化代码,使用的是K8S提供的包。使用K8S提供的包可以初始化一个SkyDNS Server?相信很多人能够想到,这个KubeDNSServer.kd应该实现了一个接口。 [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F4.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F4.png) SkyDNS Server在初始化的时候需要传入一个Backend接口,其定义如下。SkyDNS基于Etcd实现了该接口,也会使用它初始化Server。得益于SkyDNS的良好设计,K8S只要实现该接口便可以接入SkyDNS来提供DNS查询服务,并定制存储功能。 skydns/server/server.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F5.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F5.png) skydns/server/backend.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F6.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F6.png) **● kubedns实现——etcd替换** 在服务发现的流程中,主要用到了Records这个方法,下面我们就来看看K8S是如何实现这个方法。 主要步骤是先将域名按“.”拆分,并将各部分颠倒顺序生成一个path数组。调用getRecordsForPath方法获取DNS记录并返回。 kubernetes/pkg/dns/dns.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F7.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F7.png) getRecordsForPath会调用cache的相关方法。这个cache会被初始化为一个TreeCache结构,定义如下: kubernetes/pkg/dns/dns.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F8.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F8.png) kubernetes/pkg/dns/treecache.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F9.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F9.png) 如下图所示,TreeCache的结构类似于目录树。从根节点到叶子节点的每个路径与一个域名是相对应的,顺序是颠倒的。它的叶子节点只包含Entries,非叶子节点只包含ChildNodes。叶子节点中保存的就是SkyDNS定义的msg.Service结构,可以理解为DNS记录。 在Records接口方法实现中,只需根据域名查找到对应的叶子节点,并返回叶子节点中保存的所有msg.Service数据。K8S就是通过这样的一个数据结构来保存DNS记录的,并替换了Etcd。 [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F10.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F10.png) **● kubedns实现——监视Service** 最后我们来看一下监视Service资源的相关代码。如下图所示,这里使用了k8s.io/kubernetes/pkg/client/cache包的NewInformer方法,这个方法在K8S源码里会经常看到。其参数为: ● 第一个参数需要传入ListWatch结构,它定义了List和Watch操作步骤。kd.kubeClient结构可以用来访问K8S API,从代码中可以看出分别访问了List和Watch API ● 第二个参数为监视的资源类型,代码中指定了Service资源 ● 第三个参数为List操作的执行间隔。Watch操作是通知机制,只要监视的资源发送变化 就会调用对应的回调函数。List操作会获取最新的全量资源与本地状态进行比较来产生通知,可以避免网络原因导致的Watch丢失通知的情况。List操作代价较高,因此需要通过第三个参数来设置其执行间隔。 ● 最后一个参数用来设置处理事件的回调。 kubernetes/pkg/dns/dns.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F11.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F11.png) 下面我们以新增Service事件的处理流程为例来简单了解一下事件处理的代码。 在创建一个K8S Service资源后,newService方法最终会调用newPortalService方法,其代码如下。getSkyMsg函数会将Service的ClusterIP保存到msg.Service结构中并返回,对应recordValue。recordLabel可以理解为一个摘要值,与ClusterIP是一一对应的,它将作为TreeCache叶子节点的key。 最后根据Service信息找到对应的树枝(如不存在会构建),并设置叶子节点。这样一个新建的Service对应的DNS记录就保存到kubedns中了。 kubernetes/pkg/dns/dns.go [![](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F12.png)](http://blog.tenxcloud.com/wp-content/uploads/2016/10/%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F12.png) Kubedns容器的主要原理已经讲解完了,下面我们简要介绍一下其他两个容器。 ● dnsmasq简介 ● Dnsmasq是一款小巧的DNS配置工具 ● 在kube-dns插件中的作用: ● 通过kubedns容器获取DNS规则,在集群中提供DNS查询服务 ● 提供DNS缓存,提高查询性能 ● 降低kubedns容器的压力、提高稳定性 ● Dockerfile在GitHub上Kubernetes组织的contrib仓库中,位于dnsmasq目录下。 ● 在kube-dns插件的编排文件中可以看到,dnsmasq通过参数--server=127.0.0.1#10053指定upstream为kubedns。 **● exechealthz简介** ● 在kube-dns插件中提供健康检查功能 ● 源码同样在contrib仓库中,位于exec-healthz目录下。 ● 新版中会对两个容器都进行健康检查,更加完善。 ## 总结 1.4版本kube-dns插件的三个容器的功能如下: **● kubedns容器** ● 监视k8s Service资源并更新DNS记录 ● 替换etcd,使用TreeCache数据结构保存DNS记录并实现SkyDNS的Backend接口 ● 接入SkyDNS,对dnsmasq提供DNS查询服务 **● dnsmasq容器** ● 对集群提供DNS查询服务 ● 设置kubedns为upstream ● 提供DNS缓存,降低kubedns负载,提高性能 **● exechealthz容器** ● 定期检查kubedns和dnsmasq的健康状态 ● 为k8s活性检测提供HTTP API 相比于1.2版本,个人认为有了如下改进: ● 无状态服务。1.2版本中,需要将Etcd的数据Volume出来才能保证Etcd容器重启之后数据不会丢失,服务可以快速恢复。新版本中作为无状态服务出现,通过增加冗余来提高可靠性。即使kubedns容器重启,dnsmasq缓存机制也可以保证服务的可用性。 ● 优化查询效率。SkyDNS直接从内存中获取DNS记录。 ● 完善健康检查。1.2版本中只对kube2sky设置了健康检查。 除了改进之外,还有一点不足,也是大家比较担心的 「 内存占用 」。目前在kube-dns编排文件中默认设置了内存限制为170M,在注释中可以看出这一数字并未在大规模集群中验证。不过相信不久的将来我们就能看到这一验证结果。 Tips :直播在哪里?嘘,悄悄告诉你,点击http://t.cn/RVRITb3 即可查看直播回放! ![](http://77fkk5.com1.z0.glb.clouddn.com/upload/image/f0e324569f5311e68333525400020562.jpg) 扫描上方二维码。阅读更多优质文章。

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1315 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传