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/