1. 关于 DNS
1.1 DNS 服务的用途
DNS 提供的是域名到 IP 的映射服务。例如,在浏览器输入 https://www.chenshaowen.com 访问页面,但数据链路是基于 IP 的通信,无法识别 www.chenshaowen.com 。这时就需要进行 DNS 查询,输入参数是 www.chenshaowen.com ,返回结果是 IP 地址。
可以看到 DNS 提供了一种助记方法,我们不必关注 IP 地址以及其变动,而只需记住一段英文字符串,就能够找到服务。
一种常见的服务发现机制是配置管理中心,存储 Key/Value 值,例如 Consul、ZooKeeper、Etcd 等。而 DNS 提供的功能,也可以满足微服务架构中服务发现的需求,Kubernetes 就是采用的这种方式。
Kubernetes 从 1.11 版本开始,使用 CoreDNS 替代 KubeDNS 成为了内置的 DNS 服务。
1.2 resolv.conf
/etc/resolv.conf
是 DNS 客户端的配置文件,主要有四部分组成:
- nameserver ,DNS 服务器的 IP 地址
- domain ,本地域名的后缀
- search ,搜索的域名后缀
- sortlist ,对查询结果进行特定排序
当遇到无法解析的域名时,解析器才会用到 domain 、search 。例如,访问 http://abc/index.html, 解析器无法解析 abc ,就会拼接 domain 或 search 的配置作为后缀继续解析。当配置了 search 时,domain 失效。
2. CoreDNS
2.1 简介
CoreDNS 是 CNCF 正式毕业的项目。它是一个基于 Caddy 实现,模块化且可插拔的 DNS 服务器。
每个插件都遵循一个特定的接口协议。在 Corefile 文件中采用 DSL 定义 DNS 服务,可以很方便地开启各种插件,定制 DNS 服务。下面是一个示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
| example.org:8000 {
file example.org
prometheus
errors
log
}
.:8000 {
kubernetes
proxy . 8.8.8.8
log
errors
cache
}
|
这个配置暴露了一个 DNS Server ,监听在 8000 端口,根据不同的域名匹配不同的处理逻辑。每个逻辑,加载指定的插件处理。
2.2 相关插件
常用的插件包括:
- hosts,配置集群全局可解析的 hosts ,需要注意的是域名后缀需要与 search 保持一致,例如,cluster.local ,否则 nodelocaldns 无法上报 coredns 解析
- errors, 错误记录到 stdout
- health,提供健康报告接口
- kubernetes,解析为 Kubernetes 集群服务的 IP 地址
- prometheus,提供 Prometheus 的 Metrics 接口
- proxy,不在集群域内的查询转到指定解析器
- cache,启用缓存
- loop,检测死循环,并中断
- reload,自动加载 Corefile,热更新
- loadbalance,DNS 负载均衡器
2.3 集群 ConfigMap 配置
1
2
3
| kubectl -n kube-system get svc coredns
coredns ClusterIP 10.233.0.3 <none> 53/UDP,53/TCP,9153/TCP 5h
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| kubectl -n kube-system get cm coredns -o yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream /etc/resolv.conf
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
...
|
DNS 的默认端口是 53 。cluster.local 、 in-addr.arpa 、 ip6.arpa 格式的域名将被解析为 Kubernetes 的内部 IP 地址。
3. NodelocalDNS
3.1 简介
为了避免 Pod 进行 DNS 解析时,频繁查询 CoreDNS ,NodelocalDNS 在每个节点上都以 DaemonSet 运行 DNS 缓存以提高集群性能。
NodelocalDNS 的原理是,运行一个 hostNetwork 网络模式的 Pod,创建一个网卡绑定本地 DNS 的 IP 地址。节点上的 Pod 请求 DNS 解析时,将被拦截到 NodelocaDNS 。NodelocalDNS 通过取缓存或向上游请求 DNS ,完成解析过程。
3.2 集群 ConfigMap 配置
1
2
3
| kubectl -n kube-system get ds nodelocaldns
nodelocaldns 1 1 1 1 1 <none> 5h
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| kubectl -n kube-system get cm nodelocaldns -o yaml
apiVersion: v1
data:
Corefile: |
cluster.local:53 {
errors
cache {
success 9984 30
denial 9984 5
}
reload
loop
bind 169.254.25.10
forward . 10.233.0.3 {
force_tcp
}
prometheus :9253
health 169.254.25.10:9254
}
in-addr.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.25.10
forward . 10.233.0.3 {
force_tcp
}
prometheus :9253
}
ip6.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.25.10
forward . 10.233.0.3 {
force_tcp
}
prometheus :9253
}
.:53 {
errors
cache 30
reload
loop
bind 169.254.25.10
forward . /etc/resolv.conf
prometheus :9253
}
...
|
同样使用 53 端口提供 DNS 服务,但是根据不同的域名,NodelocalDNS 提供了不同的解析策略。 cluster.local、in-addr.arpa、ip6.arpa 格式的域名从 CoreDNS 解析后缓存到本地,其他则使用节点的 DNS 解析后缓存。
4. Kubernetes Pod 中的 DNS 解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| cat > busybox.yaml <<-EOF
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.4
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
|
1
| kubectl apply -f busybox.yaml
|
1
2
3
4
5
| kubectl exec busybox cat /etc/resolv.conf
nameserver 169.254.25.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
|
1
2
3
4
5
6
7
| kubectl exec -ti busybox -- nslookup kubernetes.default
Server: 169.254.25.10
Address 1: 169.254.25.10
Name: kubernetes.default
Address 1: 10.233.0.1 kubernetes.default.svc.cluster.local
|
解析链路:nodelocaldns -> 缓存 -> coredns -> 返回 IP
其中涉及 search 添加域名后缀的逻辑,在此不再表述。
1
2
3
4
5
6
| kubectl exec -ti busybox -- nslookup a.b
Server: 169.254.25.10
Address 1: 169.254.25.10
nslookup: can't resolve 'a.b'
|
解析链路:nodelocaldns -> 节点配置的 DNS -> 未找到
1
2
3
4
5
6
7
| kubectl exec -ti busybox -- nslookup www.chenshaowen.com
Server: 169.254.25.10
Address 1: 169.254.25.10
Name: www.chenshaowen.com
Address 1: 163.181.33.208
|
解析逻辑:nodelocaldns -> 节点配置的 DNS -> 返回 IP
5. ExternalName - CNAME 解析
ExternalName Service 是 Service 的一个特例,没有选择器,可以用于给外部服务取一个内部别名。
1
2
3
4
5
6
7
8
9
10
| cat > externalname.yaml <<-EOF
apiVersion: v1
kind: Service
metadata:
name: chenshaowen
namespace: default
spec:
type: ExternalName
externalName: www.chenshaowen.com
EOF
|
1
| kubectl apply -f externalname.yaml
|
1
2
3
4
5
6
7
| kubectl exec -ti busybox -- nslookup chenshaowen.default
Server: 169.254.25.10
Address 1: 169.254.25.10
Name: chenshaowen.default
Address 1: 58.215.145.110
|
chenshaowen.default 将会被映射到 www.chenshaowen.com ,这是通过 DNS 的 CNAME 记录实现的。
6. 参考