作用
coreDNS的作用是在集群内提供Service和Pod的域名解析服务。coreDNS会监听集群中Service和Pod的创建销毁事件,当Service或Pod被创建时,记录对应的解析记录。当其他Pod需要通过域名访问集群中的Service或Pod时,会向coreDNS服务查询解析记录,然后访问解析到的IP地址。整个流程如下
K8S服务在部署好coreDNS服务后,会对外暴露一个Service,集群内就可以通过访问该Service的ClusterIP+53端口获取域名解析服务。ClusterIP一般是固定的,在安装kubelet时,会传递--cluster-dns=<cluster-ip> --cluster-domain=<default-local-domain>(默认为cluster.local)
参数给kubelet,kubelet在创建Pod时,就会把这两个配置写入到Pod的/etc/resolv.conf
文件中。
cat /etc/kubernetes/kubelet
可以看到kubelet的配置。
目前k8s支持正向查找(A记录),端口查找(SRV记录),反向IP地址查找(PTR记录)。
K8S中一般只有service和headless service后端的statefulset创建的Pod域名是固定的,其他Pod域名中都带有Pod IP,Pod重启后IP改变域名也会改变,不推荐通过域名访问。
coreDNS配置说明
Corefile配置
Corefile 是 CoreDNS 的配置文件,它定义了:
- server 以什么协议监听在哪个端口(可以同时定义多个 server 监听不同端口)
- server 负责哪个 zone 的权威(authoritative)DNS 解析
- server 将加载哪些插件
Corefile的配置格式如下
zone:port {
plugin1
plugin2
}
其中zone表示监听的域名,可以是根域名.
,顶级域名com
等(一般省略前面的.
);port表示server提供服务的端口,未配置使用默认的53端口。
server和端口是1对1的关系,server和zone是1对多的关系,即一个server只监听一个端口,一个server可以负责多个zone的DNS解析。
正向解析
.: {
log
errors
}
com: {
log
}
.:54 {
log
}
上面的coreDNS配置表示,起两个server,一个监听53端口,提供根域和com域的解析,另一个监听54端口,负责根域的解析。
域名解析使用贪心算法。当我们访问53端口,请求www.baidu.com
的解析时,会匹配到第二个,即com
域的解析。匹配成功后,开始执行里面配置的插件,此处记录一个log就结束了。
反向解析
in-addr.arpa (反向域名解析,从IP地址到域名的映射)
in-addr是inverse address, arpa 的标准名称对应为Address and Routing Parameter Area, 即“地址路由参数域”。
由于在域名系统中,一个IP地址可以对应多个域名,因此从IP出发去找域名,理论上应该遍历整个域名树,但这在 Internet上是不现实的。为了完成逆向域名解析,系统提供一个特别域,该特别域称为逆向解析域in-addr.arpa。这样欲解析的IP地址就会被表达成一种像域名一样的可显示串形式,后缀以逆向解析域域名“in-addr.arpa”结尾。例如一个IP地址:218.30.103.170,其逆向域名表达方式为:170.103.30.218.in-addr.arpa。两种表达方式中IP地址部分顺序恰好相反,因为域名结构是自底向上(从子域到域),而IP地址结构是自顶向下(从网络到主机)的。实质上逆向域名解析是将IP地址表达成一个域名,以地址做为索引的域名空间,这样逆向解析的很大部分可以纳入正向解析中。
coreDNS在K8S中的配置
apiVersion: v1
data:
Corefile: |
.:53 {
errors
log
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
hosts {
10.20.31.104 www.google.com
fallthrough
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
......
插件调用说明
匹配域名后,会按照域内的插件顺序,依次调用插件。插件处理逻辑有以下四种:
- 插件处理完成后,直接返回结果。如kubernetes,hosts,如果没有加fallthrough,则调用结束本插件后,就返回了。
- 不被该插件处理,流转到下一个插件,如果所有插件不处理,则返回错误。
- 插件内有fallthrough关键字,fallthrough到下一个插件。fallthrough关键字的含义是,继续调用下一个插件处理。
- 插件处理后,打上hint,流转到下一个插件。
参数 | 说明 |
---|---|
errors | 打印/存储错误日志 |
log | 将CoreDNS每次域名解析的日志打印出来 |
health | CoreDNS自身健康状态报告,默认监听端口8080,一般用来做健康检查。您可以通过http://localhost:8080/health获取健康状态(coredns Pod配置的存活探针使用此接口获取CoreDNS自身健康)。 |
ready | CoreDNS插件状态报告,默认监听端口8181,一般用来做可读性检查。可以通过http://localhost:8181/ready获取可读状态。当所有插件都运行后,ready状态为200(coredns Pod配置的就绪探针使用此接口获取CoreDNS插件的就绪状况)。 |
kubernetes | kubernetes: CoreDNS Kubernetes插件,提供集群内服务解析能力。该插件实现了基于Kubernetes DNS的服务发现。 其中cluster.local in-addr.arpa ip6.arpa表示kubernetes插件会处理域名后缀为cluster.local的所有域名以及处理所有的in-addr.arpa中的反向dns查找和ip6.arpa形式域名,其中kubernetes集群域名后缀是在kubelet参数中配置的,默认值为cluster.local。 pods参数用于设置基于pods ip的A记录,例如default namespace下存在一个pod,ip为10.233.64.2,此Pod的A记录为10-233-64-2.default.pod.cluster.local ->10.233.64.2,pods参数有三个值,其中disabled表示关闭pod ip的A记录;insecure总是从请求中返回一个带有IP的A记录(不检查k8s)(例如:1-2-3-4.ns.pod.cluster.local. in A 1.2.3.4);verified表示如果在同一命名空间中,则存在匹配IP的pod。 fallthrough:指定特定区域查询失败,如果in-addr.arpa和ip6.arpa形式的域名在kubernetes插件没有匹配成功的话则进入下一个 plugin 继续。 ttl参数为响应客户端请求设置的自定义 TTL。更多参数配置见:https://coredns.io/plugins/kubernetes/ |
hosts | 相当于主机/etc/hosts 文件里面的解析信息。如果一个域名在 hosts中存在,则优先使用这个信息返回,在本例中一定要注意hosts插件的位置,如果放在了forward插件之后,那么hosts插件即没有匹配的机会; |
prometeus | CoreDNS自身metrics数据接口。可以通过http://localhost:9153/metrics获取prometheus格式的监控数据。 |
forward | 将域名查询请求转到预定义的DNS服务器。默认配置中,当域名不在Kubernetes域时,将请求转发到预定义的解析器(/etc/resolv.conf)中。默认使用宿主机的/etc/resolv.conf配置。 forward . /etc/resolv.conf中的"."表示匹配所有域名。 |
cache | 溯源得到的结果,缓存指定时间。类似 TTL 的概念;TTL以秒为单位。如果未指定,将使用最大 TTL,对于 NOERROR 响应为 3600,对于拒绝存在响应为 1800。将 TTL 设置为 30表示缓存记录长达 30 秒。 |
loop | 环路检测,如果检测到环路,则停止CoreDNS。例如,forward . /etc/resolv.conf中配置的dns server地址和coredns地址一致,客户端请求解析in-addr.arpa类型域名,在kubernetes插件中解析in-addr.arpa类型域名失败,由于配置了fallthrough in-addr.arpa ip6.arpa,那么就会进入到forward插件继续解析,由于forward . /etc/resolv.conf中配置的dns server地址和coredns地址一致,那么又会传到dns server进行解析,这么就陷入了一个死循环,通过loop插件可以避免环路问题。 |
reload | 允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,请等待两分钟以使更改生效,无需重启coredns对应的Pod。 |
loadbalance | 循环DNS负载均衡器,可以在答案中随机A、AAAA、MX记录的顺序。 |
其他典型场景
- 特定域名使用自定义DNS服务器
example.com:53 {
errors
cache 30
forward . 10.10.0.10
}
- 外部域名完全使用自建DNS服务器
Corefile: |
.:53 {
...
forward . 10.10.0.10 10.10.0.20{
prefer_udp
}
...
}
- 禁止CoreDNS对IPv6类型的AAAA记录查询返回
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
#新增以下一行Template插件,其它数据请保持不变。
template IN AAAA .
}
- 统一域名访问服务或是在集群内对域名的做CNAME解析
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
ready
rewrite stop {
name regex foo.example.com foo.default.svc.cluster.local
answer name foo.default.svc.cluster.local foo.example.com
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
此处的含义是请求域名符合正则表达式foo.example.com
时,重定向到foo.default.svc.cluster.local
处理;处理完返回时,把response的foo.default.svc.cluster.local
改写为foo.example.com
,否则client端可能会认为返回结果无效,因为client请求的地址和接收到的answer的地址不是同一个,会认为存在中间人攻击。
rewrite的好处是,在公网(默认使用域名foo.example.com
)、内网(默认使用域名foo.example.com
)、集群内部(默认使用域名foo.default.svc.cluster.local
),都可以使用同一个域名foo.example.com
访问服务。(前提:该服务在公网和内网都通过LB暴露并绑定了域名。)
rewrite用法参考。
参考
https://www.cnblogs.com/zhangmingcheng/p/15680815.html
https://help.aliyun.com/document_detail/380963.html