搭建Kubernetes集群时DNS没法解析问题的处理过程

问题描述

在搭建Kubernetes集群过程当中,安装了kube-dns插件后,运行一个ubuntu容器,发现容器内没法解析集群外域名,一开始能够解析集群内域名,一段时间后也没法解析集群内域名。html

$ nslookup kubernetes.default
Server:    10.99.0.2
Address 1: 10.99.0.2 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'kubernetes.default' 复制代码

排查过程

在排查问题前,先思考一下Kubernetes集群中的DNS解析过程,在安装好kube-dns的集群中,普通Pod的dnsPolicy属性是默认值ClusterFirst,也就是会指向集群内部的DNS服务器,kube-dns负责解析集群内部的域名,kube-dns Pod的dnsPolicy值是Default,意思是从所在Node继承DNS服务器,对于没法解析的外部域名,kube-dns会继续向集群外部的dns进行查询,过程如图。node

Ubuntu容器是一个普通的Pod,在Linux系统中,/etc/resolv.conf是存储DNS服务器的文件,普通Pod的/etc/resolv.conf文件应该存储的是kube-dns的Service IP。git

nameserver 10.99.0.2  # 这里存储的是kube-dns的Service IP
search default.svc.cluster.local. svc.cluster.local. cluster.local.
options ndots:5
复制代码

查看后发现/etc/resolv.conf文件中存储的是kube-dns的Service IP,证实这一步没有问题,接下来查看一下kube-dns的Pod,先进入kube-dns的Pod中检查一下/etc/resolv.conf文件,这里存储的应该是集群外部的DNS服务器地址,查看后发现,这里存储的地址是127.0.0.53,进一步查看kube-dns Pod的log,发现出现了很是多的i/o timeout错误。github

2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:38019->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:57567->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:52599->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:42539->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:46885->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:44189->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:56505->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:47320->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:42464->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:49203->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:58103->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:47148->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:36883->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:40968->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:55672->127.0.0.53:53: i/o timeout
复制代码

如今基本上能够发现问题的缘由了,kube-dns只能解析集群内部地址,而集群外部地址应该发给外部DNS服务器进行解析,因为kube-dns Pod中的/etc/resolv.conf文件存储的DNS服务器地址是127.0.0.53,127...*都是回环地址,也就是集群外域名的DNS解析请求会再次发送回kube-dns,致使造成一个循环,这也是一秒钟会出现几十次i/o timeout日志的缘由,请求会不断的在kube-dns中循环,kube-dns就像一个黑洞同样,吃掉了全部dns解析请求,不断累积的请求最终会致使整个集群的网络出现卡顿。ubuntu

为何

虽然问题的缘由找到了,可是为何kube-dns Pod中/etc/resolv.conf文件存储的DNS服务器是127.0.0.53?bash

kube-dns Pod的dnsPolicy值是Default,查看一下Kubernetes文档。服务器

"Default": The Pod inherits the name resolution configuration from the node that the pods run on. See related discussion for more details.网络

因此kube-dns的/etc/resolv.conf文件是从Node中继承来的,查看Node中的/etc/resolv.conf文件,存储的DNS服务器地址确实是127.0.0.53,那么下一个问题出现了,在Node中发送DNS解析请求为何不会产生回环的问题呢?架构

Node使用的是Ubuntu 18.04 Server,在这个版本的系统中,DNS解析请求并非直接发给所在网络的DNS服务器的,Ubuntu 18.04中有一个systemd-resolved服务,为本地应用程序提供了DNS解析服务,例如nslookup localhost,解析程序从/etc/resolv.conf文件中找到DNS服务器127.0.0.53,发送解析请求,systemd-resolved会监听在53端口上,捕获到解析请求后,若是是本身能够解析的,例如localhost,会直接返回127.0.0.1,若是不能解析,才会发送给外部服务器,而外部服务器的地址存储在/run/systemd/resolve/resolv.conf文件中,这个文件是systemd-resolved服务器的配置文件,过程如图。ui

怎么破

理解了问题的前因后果,解决问题的办法也就应运而生。在Kubernetes集群中,kubelet是worker组建,负责管理Pod,根据kubernetes文档,kubelet默认会从Node的/etc/resolv.conf文件读取DNS服务器地址,使得dnsPolicy是Default的Pod得以继承,kubelet中的--resolv-conf参数能够指定这个配置文件的地址。在Ubuntu 18.04中,将这个参数设置为systemd-resolved的DNS服务器配置文件/run/systemd/resolve/resolv.conf,Pod就会继承真正的外部DNS服务器。

总结

经过对问题的探究,也理解了Kubernetes集群中DNS解析的完整过程,如图。

* 在Ubuntu 16.04中也是相似的逻辑,只不过systemd-resolved换成了dnsmasq,监听地址是127.0.1.1 * 在具体实践过程当中,也顺便探究了CoreDNS和KubeDNS架构和解析逻辑上的区别,不过不在此问题的讨论范围,有兴趣的朋友能够本身看一下。 * 若是Kubernetes集群是安装在NAT网络下的虚拟机上,虚拟机(也就是Kubernetes集群中的Node)中/etc/resolv.conf文件可能被修改成NAT的地址,也就不会出现上面这个问题。

参考内容

kubernetes.io/docs/refere…

kubernetes.io/docs/concep…

kubernetes.io/docs/tasks/…

www.freedesktop.org/software/sy…

github.com/kubernetes/…

github.com/kubernetes/…

相关文章
相关标签/搜索