DNS概念
DNS协议的作用是将域名解析成ip地址, 域名只是ip地址的代号
为了将域名解析成ip地址,需要建立一个域名到ip地址之间的映射关系,提供将域名动态解析成ip地址的服务器就叫做DNS服务器, 由于当前故障的原因,DNS无法设计成集中式,因此出现了分层解析架构,分为根服务器,二级域名服务器,三级域名服务器等。
根域名服务器(Root Domain):用 · (句点)表示,根域名服务器全球的数量是固定的,为 13 个(当然这里的“个”是“组”的意思)
顶级域名服务器(Top-Level Domain, TLD):指代某个国家/地区或组织使用的类型名称,如 com、cn、edu 等。
次级域名服务器(Second-Level Domain, SLD):个人或组织在 Internet 上注册的名称,如 qq.com、gitHub.com 等
三次域名服务器或权威域名服务器(如果有):这层严格来说是次级域名的子域,是二层域名派生的域名,通俗说就是网站名,如 index.baidu.com
- linux网络中,
/etc/hosts用于记录主机hostname跟ip之间的映射关系,/etc/resolve.conf用于记录外网DNS服务器地址
DNS查询过程
以查询www.baidu.com为例子:
- 本地终端发出域名解析请求,到本地DNS服务器
- 本地DNS服务器查询DNS缓存是否有对应的Ip, 检查hosts文件中是否与对应的ip地址, 不存在就想外部DNS服务器发送请求(Dnsmasq提供DNS缓存和DHCP服务、Tftp服务功能。当接受到一个DNS请求时,Dnsmasq首先会查找/etc/hosts这个文件,然后查找/etc/resolv.conf中定义的外部DNS)
- 外部DNS服务器同样先查看缓存,不存在再向众所周知的全球 13 台根服务器发出请求
- 根 DNS 服务器收到请求后会判断该域名由谁授权管理,返回管理这个域名的顶级 DNS 服务器的 IP,给到DNS服务器
- DNS 服务器根据返回的 IP 继续请求顶级 DNS 服务器
- 顶级 DNS 服务器收到请求后,如果自己无法解析,也会判断对应域名由下一级的哪个 DNS 服务器授权管理,并将该次级 DNS 服务器的 IP 返回
- DNS 服务器继续根据返回的 IP 请求次级 DNS 服务器
- 次级 DNS 服务器如果解析出对应的域名,就将该域名对应的 IP 返回给 DNS 服务器
- DNS 服务器缓存一份域名与 IP 的映射关系
DNS 域名记录设置
在使用云厂商的域名后进行DNS域名配置时,首先需要选择对应的记录类型,DNS有多种记录类型,包括:
- A 地址记录, 将域名指向一个 IP 地址(例如:120.55.23.197);
- AAAA 地址记录, 将域名指向一个 IPv6 地址;
- CNAME 别名记录,将域名指向另一个域名,再由另一个域名提供 IP 地址;
- TXT 域名对应的文本信息, 对域名进行标识和说明,绝大多数的 TXT 记录是用来做 SPF 记录(反垃圾邮件);
- NS 名字服务器记录, 将子域名交给其他 DNS 服务商解析;
- SRV TCP服务器信息记录, 用来标识某台服务器使用了某个服务,常见于微软系统的目录管理;
- MX 邮件服务器记录, 设置邮箱,让邮箱能收到邮件;
- AFSDB Andrew文件系统数据库服务器记录;
- ATMA ATM地址记录;
- HINFO 硬件配置记录,包括CPU、操作系统信息;
- ISDN 域名对应的ISDN号码;
- MB 存放指定邮箱的服务器;
- MG 邮件组记录;
- MINFO 邮件组和邮箱的信息记录;
- MR 改名的邮箱记录;
- PTR 反向记录;
- RP 负责人记录;
- RT 路由穿透记录;
- X25 域名对应的X.25地址记录;
注: 主机记录就是域名前缀,例如
www.baidu.com中的www就是域名前缀,比较特殊的主机记录有:
- @:直接解析主域名,例如@.baidu.com == https://baidu.com
- ***** : 泛解析,匹配其他所有域名, 例如 *.baidu.com == https://xxxx.baidu.com
DNS 查询相关的命令
1、nslookup 命令
nslookup 是域名查询命令, 用户查询域名对应的ip地址, 命令格式如下:
nslookup damain [dns-server]
如果未指定dns服务器时, 采用系统默认的dns服务器
1 | dawn@node-2:~$ nslookup baidu.com |
nslookup 默认查询的A类型的记录, 可以设置查询指定类型的记录,通过qt=类型查询指定类型的记录,例如:nslookup -qt=mx baidu.com
2、whois 命令
whois用于查询域名的注册情况。
1 | [root@whois~]# whois baidu.com |
3、 dig 命令
Linux下解析域名除了使用nslookup之外,还可以使用dig(全称 domain information groper)命令来解析域名,相对于nslookup, dig命令的输出更为丰富,它会打印出>DNS name server的回应。dig命令的格式如下:
1 | dig [@server] [-b address] [-c class] [-f filename] [-k filename] [ -n ][-p port#] [-t type] [-x addr] [-y name:key] [name] [type] [class] [queryopt...] |
选项:
1 | @server:指定进行域名解析的域名服务器; |
查询选项:
1 | +[no]tcp: 查询域名服务器时使用 [不使用] TCP。缺省行为是使用 UDP,除非是 AXFR 或 IXFR 请求,才使用 TCP 连接。 |
查询例子:
1 | [root@localhost ~]# dig www.baidu.com |
DNS In Kubernetes
在 k8s 中,一个 Pod 如果要访问同 Namespace 下的 Service(比如 user-svc),那么只需要curl user-svc。如果 Pod 和 Service 不在同一域名下,那么就需要在 Service Name 之后添加上 Service 所在的 Namespace(比如 beta),curl user-svc.beta。那么 k8s 是如何知道这些域名是内部域名并为他们做解析的呢?答案是dns
resolv.conf
resolv.conf 是 DNS 域名解析的配置文件。每行都会以一个关键字开头,然后跟配置参数。这里主要使用到的关键词有3个。
- nameserver #定义 DNS 服务器的 IP 地址
- search #定义域名的搜索列表,当查询的域名中包含的 . 的数量少于 options.ndots 的值时,会依次匹配列表中的每个值
- options #定义域名查找时的配置信息
那么我们进入一个 Pod 查看它的 resolv.conf
1 | 1. nameserver 100.64.0.10 |
上述配置文件 resolv.conf 是 dnsPolicy: ClusterFirst 情况下,k8s 为 Pod 自动生成的,这里的 nameserver 所对应的地址正是 DNS Service 的Cluster IP(该值在启动 kubelet 的时候,通过 clusterDNS 指定)。所以,从集群内请求的所有的域名解析都需要经过 DNS Service 进行解析,不管是 k8s 内部域名还是外部域名。
可以看到这里的 search 域默认包含了 namespace.svc.cluster.local、svc.cluster.local 和 cluster.local 三种。当我们在 Pod 中访问 a Service时( curl a ),会选择nameserver 100.64.0.10 进行解析,然后依次带入 search 域进行 DNS 查找,直到找到为止。
1 | # curl a |
显然因为 Pod 和 a Service 在同一 Namespace 下,所以第一次 lookup 就能找到。
如果 Pod 要访问不同 Namespace(例如: beta )下的 Service b ( curl b.beta ),会经过两次 DNS 查找,分别是
1 | # curl b.beta |
正是因为 search 的顺序性,所以访问同一 Namespace 下的 Service, curl a 是要比 curl a.default 的效率更高的,因为后者多经过了一次 DNS 解析。
那么当Pod中访问外部域名时仍然需要走search域吗
这个答案,不能说肯定也不能说否定,看情况,可以说,大部分情况要走 search 域。
在 /etc/resolv.conf 文件中,我们可以看到 options 中有个配置项 ndots:5 。
ndots:5,表示:如果需要 lookup 的 Domain 中包含少于5个 . ,那么将使用非绝对域名,如果需要查询的 DNS 中包含大于或等于5个 . ,那么就会使用绝对域名。如果是绝对域名则不会走 search 域,如果是非绝对域名,就会按照 search 域中进行逐一匹配查询,如果 search 走完了都没有找到,那么就会使用 原域名.(domgoer.com.) 的方式作为绝对域名进行查找。
在 /etc/resolv.conf 文件中,我们可以看到 options 中有个配置项 ndots:5 。
因此,可以找到两种优化的方法
- 直接使用绝对域名
这是最简单直接的优化方式,可以直接在要访问的域名后面加上 . 如:domgoer.com. ,这样就会避免走 search 域进行匹配。
- 配置ndots
还记得之前说过 /etc/resolv.conf 中的参数都可以通过k8s中的 dnsConfig 字段进行配置。这就允许你根据你自己的需求配置域名解析的规则。
例如 当域名中包含两个 . 或以上时,就能使用绝对域名直接进行域名解析。
1 | apiVersion: v1 |
Kubernetes DNS配置
Pod中dns配置主要有dnsConfig跟dnsPolicy, 其中dnsPolicy主要dns网络策略, dnsConfig主要配置dns的resolv.conf配置,详情可以参考官方api
dnsConfig
dnsConfig通过配置nameserver、search 和 options来修改容器的pod的resolv.conf配置
1 | dnsConfig: |
dnsPolicy
在k8s中,有4中DNS策略,分别是 ClusterFirstWithHostNet、ClusterFirst、Default、和 None,这些策略可以通过dnsPolicy这个字段来定义
如果在初始化 Pod、Deployment 或者 RC 等资源时没有定义,则会默认使用 ClusterFirst 策略
ClusterFirstWithHostNet
当一个 Pod 以 HOST 模式(和宿主机共享网络)启动时,这个 POD 中的所有容器都会使用宿主机的/etc/resolv.conf 配置进行 DNS 查询,但是如果你还想继续使用 Kubernetes 的 DNS 服务,就需要将 dnsPolicy 设置为 ClusterFirstWithHostNet。
ClusterFirst
使用这是方式表示 Pod 内的 DNS 优先会使用 k8s 集群内的DNS服务,也就是会使用 kubedns 或者 coredns 进行域名解析。如果解析不成功,才会使用宿主机的 DNS 配置进行解析。Default
这种方式,会让 kubelet 来绝定 Pod 内的 DNS 使用哪种 DNS 策略。kubelet 的默认方式,其实就是使用宿主机的 /etc/resolv.conf 来进行解析。你可以通过设置 kubelet 的启动参数,–resolv-conf=/etc/resolv.conf 来决定 DNS 解析文件的地址None
这种方式顾名思义,不会使用集群和宿主机的 DNS 策略。而是和 dnsConfig 配合一起使用,来自定义 DNS 配置,否则在提交修改时报错。
参考文档
- https://blog.domgoer.io/2019/08/07/kube-dns-and-core-dns
- https://cizixs.com/2017/04/11/kubernetes-intro-kube-dns/
- https://juejin.im/entry/5b84a90f51882542e60663cc
- https://kubernetes.io/zh/docs/concepts/services-networking/dns-pod-service/
- https://mp.weixin.qq.com/s/V5qOl5Ure3Pj5aZmTFp-Fg
- https://sanyuesha.com/2017/11/08/how-dns-resolve-in-linux/