6.K8S-Coredns
一、概述
为了解决pod地址变化的问题,需要部署service资源,用service资源代理后端pod,通过暴露service资源的固定地址(集群IP),来解决以上POD资源变化产生的IP变动问题
那service资源的服务发现呢?
service资源提供了一个不变的集群IP供外部访问,但
- IP地址毕竟难以记忆
- service资源可能也会被销毁和创建
- 将service资源名称和service暴露的集群网络IP对映
早期使用skydns、kubedns;1.11之后使用coredns。

NodeLocalDNS
节点本地域名解析。如果k8s集群pod数增加后,pod之间的相互访问,都需先通过域名解析,那么CoreDNS将不堪重负,所以通过Daemonset在每个节点都启动了一个NodeLocalDNS,缓解全局CoreDNS的域名解析压力,其本身k8s-dns镜像,但功能没有全局的CoreDNS镜像丰富。

k8s的pod域名解析配置和解析流程:
- 配置了NodeLocal DNS本地缓存的Pod,pod首先检查自己的/etc/resolv.conf配置文件默认会通过NodeLocal DNSCache监听于节点上的IP (169.254.20.10)解析域名。
- NodeLocal DNSCache本地若无缓存应答解析请求,则会通过全局DNS服务器kube-dns服务请求CoreDNS进行解析
- CoreDNS对于非集群内域名,会通过外部 DNS服务器进行解析
- 已注入DNS本地缓存的Pod,当无法连通NodeLocal DNSCache时,会继而直接通过kube-dns服务连接到CoreDNS进行解析,此链路为备用链路
- 未注入DNS本地缓存的Pod,会通过标准的kube-dns服务链路连接到CoreDNS进行解析
查看已安装的coredns
kubectl get pods -n kube-system |grep dns
kubectl get svc -o wide -n kube-system|grep coredns

查看coreDNS的clusterIP
kubectl get svc -n kube-system kubectl describe svc coredns -n kube-system
查看coredns的configmap yaml文件
kubectl -n kube-system get configmaps coredns
kubectl -n kube-system get configmaps coredns -o yaml
验证
dig测试coredns的解析
dig -t A www.baidu.com @172.16.89.1 +short
注意coredns已经能解析外网域名了,因为coredns的配置中,写了他的上级DNS为node节点的DNS,如果它自己解析不出来域名,会通过递归查询一级级查找
但coredns我们不是用来做外网解析的,而是用来做service名和serviceIP的解析
验证解析svc的IP
创建一个service
kubectl create deployment nginx-dp --image=nginx ##default名称空间
kubectl get deployments kubectl get pod kubectl expose deployment nginx-dp --port=80 ,##给这个pod创建一个svc,在default名称空间。
用dig验证
dig -t A nginx-dp @172.16.89.1 +short # 发现无返回数据;需要完整域名:服务名.名称空间.svc.cluster.local. dig -t A nginx-dp.default.svc.cluster.local. @172.16.89.1 +short 172.16.30.219
进入容器内部
kubectl exec -it nginx-dp-5fcfbd685-cxm76 /bin/bash
不需要用完整域名,因为容器的/etc/resolv.conf中配置了搜索域


169.254.25.10这个IP是NodeLocalDNS侦听DNS请求的IP,pod会先将dns请求发给本地的NodeLocalDNS进行域名解析。
查看nodelocaldns的安装
kubectl get pod -n kube-system|grep nodelocaldns
查看nodelocaldns的yaml文件
二、Pod的DNS配置策略
每个Pod所使用的DNS策略,是通过pod.spec.dnsPolicy字段设置的,共有4种DNS策略:
ClusterFirst:默认策略,用CoreDNS来做域名解析,Pod内/etc/resolv.conf文件中配置的nameserver是集群的DNS服务器,即kube-dns的地址。
Default:Pod用集群node节点的域名解析配置,也就是,Pod会直接使用宿主机上的/etc/resolv.conf文件内容。不能访问集群内的服务。
None:忽略k8s集群环境中的DNS设置,Pod用dnsConfig字段所提供的DNS配置,dnsConfig字段的内容要在创建Pod时手动设置好。
ClusterFirstWithHostNet:如果Pod的hostNetwork字段设置为true,则表示Pod与宿主机共用同一个网络命名空间,此时Pod的DNS策略默认使用的是Default,不能访问集群内的服务。若希望Pod在host网络模式下还能访问集群内的服务,可以将dnsPolicy设置成ClusterFirstWithHostNet。
场景1:使用k8s集群提供的CoreDNS来做域名解析
将dnsPolicy字段设置为ClusterFirst,或者省略dnsPolicy字段,默认也是ClusterFirst。
apiVersion: v1 kind: Pod metadata: name: nginx-demo namespace: default spec: containers: - image: nginx name: nginx1 ports: - containerPort: 80 protocol: TCP dnsPolicy: ClusterFirst ## #该字段要设置为ClusterFirst(若省略该字段默认也是ClusterFirst)
kubectl create -f corednstest.yaml
创建好Pod后,查看Pod内/etc/resolv.conf文件内容,nameserver指向的是kube-dns service地址,也就是使用CoreDNS来做域名解析。
kubectl exec nginx-demo cat /etc/resolv.conf

场景2:Pod层面自定义DNS配置
将dnsPolicy设置为None,同时添加dnsConfig字段手动配置DNS解析内容。apiVersion: v1
kind: Pod
metadata:
name: nginx-demo-none
namespace: default
spec:
containers:
- image: nginx
name: nginxnone
ports:
- containerPort: 80
protocol: TCP
dnsPolicy: None
dnsConfig:
nameservers: ["192.168.1.1","10.146.15.193"] #最多可指定3个IP,当Pod的dnsPolicy设置为None时,列表必须至少包含一个IP地址
searches: #Pod中主机名查找的DNS搜索域列表
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "5"
kubectl create -f corednsnone.yaml
创建好Pod后,查看Pod内/etc/resolv.conf文件内容,nameserver是dnsConfig字段中配置的IP。
kubectl exec nginx-demo-none cat /etc/resolv.conf

如果dnsPolicy字段不是设置为None,而是ClusterFirst,则coredns的地址也会加入到Pod的/etc/resolv.conf文件中,该文件内容会变成如下:
nameserver 169.254.25.10
nameserver 192.168.1.1
nameserver 10.146.15.193
search mytest.svc.cluster.local svc.cluster.local cluster.local default.svc.cluster.local
options ndots:5
场景3:继承node节上的DNS配置
将dnsPolicy字段设置为Default。Pod会继承宿主机上的/etc/resolv.conf内容,如果宿主机上/etc/resolv.conf文件中没有定义指向coredns地址的nameserver,则Pod容器内是无法访问到service name的。
apiVersion: v1 kind: Pod metadata: name: nginx-demo namespace: default spec: containers: - image: nginx:1.7.9 name: nginx ports: - containerPort: 80 protocol: TCP dnsPolicy: Default
但注意,这个要先在宿主机上配置好/etc/resolv.conf的内容,如下:
$ cat /etc/resolv.conf
options timeout:2 attempts:3 rotate single-request-reopen
; generated by /usr/sbin/dhclient-script
nameserver 10.146.15.193
nameserver 10.0.2.1
创建好Pod后,查看Pod内/etc/resolv.conf文件内容,跟宿主机上的是一样的,说明从宿主机上继承过来了。
#kubectl exec nginx-demo cat /etc/resolv.conf
nameserver 10.146.15.193
nameserver 10.0.2.1
options timeout:2 attempts:3 rotate single-request-reopen
场景4:Pod在HostNetwork网络模式下访问集群内的服务
如果Pod的hostNetwork字段设置为true,也就是Pod与宿主机共享同一个网络命名空间,则此时Pod的dnsPolicy默认策略是Default,即Pod会继承宿主机上的resolv.conf文件内容。若宿主机上的resolv.conf文件中没有配置coredns地址作为域名解析服务器,则此时的Pod容器内是无法访问集群内部其他的service name的,所以要访问集群内的service name,就要将dnsPolicy字段设置为ClusterFirstWithHostNet。
apiVersion: v1 kind: Pod metadata: name: nginx-demo namespace: default spec: containers: - image: nginx:1.7.9 name: nginx ports: - containerPort: 80 protocol: TCP hostNetwork: true dnsPolicy: ClusterFirstWithHostNet
创建好Pod后,查看Pod内/etc/resolv.conf文件内容,nameserver指向的还是coredns的地址。
$ kubectl exec nginx-demo cat /etc/resolv.conf
nameserver 169.254.25.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
如果不设置dnsPolicy字段,默认使用的策略是Default,则resolv.conf里就是宿主机上的内容,这时Pod内无法解析service name的。
$ kubectl exec nginx-demo cat /etc/resolv.conf
nameserver 10.146.15.193
nameserver 10.0.2.1
options timeout:2 attempts:3 rotate single-request-reopen
三、集群CoreDNS配置:
coredns是k8s集群的一个DNS解析组件,不仅为集群内部的Pod应用提供域名解析服务,还支持集群内部的自定义服务域名、集群外部域名等。
常见的用法是,可以在coredns配置文件中,添加一些自定义DNS解析配置,它会对集群内部的所有Pod生效(前提是这个Pod的nameserver指向的是coredns)。
比如说,集群内部有很多个Pod应用,这个集群中的所有Pod应用都要能够访问到一个集群外部的域名a.test.com,如果此时逐个登录到Pod容器里修改/etc/hosts文件,添加一条a.test.com域名解析记录,要是真的这样做,估计会累死,另外如果后面还有源源不断的Pod要创建,每个Pod创建时又要配置好这个域名的解析,这样做实在太麻烦了。这时我们就可以通过coredns,修改它的corefile配置文件,添加一条a.test.com域名解析记录,这样只要Pod的nameserver指向的是coredns,这个Pod就不用做任何修改,就能访问到这个a.test.com域名。
比如说,现在集群中的Pod要访问的不只是a.test.com这一个域名,还有b.test.com、c.test.com 等很多外部域名要访问,而这些域名都在10.10.10.1这台外部的nameserver上做了解析绑定。那为了让集群内的Pod能访问到这些域名,就算在corefile里逐个添加这些域名的解析记录,也会很麻烦。这时可以在corefile里面,直接配置成10.10.10.1这个nameserver地址,供集群中的所有Pod使用,只要Pod的nameserver指向的是coredns,就能通过这个nameserver访问到集群外部的这些域名。
详细用法可参考官方手册:CoreDNS: DNS and Service Discovery
CoreDNS的默认配置:
如果k8s集群安装了coredns插件,在命名空间kube-system下,会有一个CoreDNS配置项。
$ kubectl -n kube-system get configmaps coredns
NAME DATA AGE
coredns 1 475d
这个配置项中,有一个data.Corefile字段,默认配置内容如下:
kubectl -n kube-system get configmaps coredns -o yaml
apiVersion: v1 data: Corefile: | .:53 { errors health ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure upstream fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance } kind: ConfigMap metadata: annotations: ...
配置字段说明:
error:错误信息到标准输出。
health:CoreDNS自身健康状态报告,默认监听端口8080,一般用来做健康检查。可通过http://localhost:8080/health获取健康状态。
ready:CoreDNS插件状态报告,默认监听端口8181,一般用来做可读性检查。可通过http://localhost:8181/ready读取状态。
kubernetes:CoreDNS kubernetes插件,提供集群内服务解析能力。
prometheus:CoreDNS自身metrics数据接口。可过http://localhost:9153/metrics获取prometheus格式的监控数据。
forward(或proxy):将域名查询请求转到预定义的DNS服务器。
cache:DNS缓存。
loop:环路检测,如果检测到环路,则停止CoreDNS。
reload:允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,最好等几分钟以使更改生效。
loadbalance:循环负载均衡器。
四、CoreDNS的扩展配置:
场景1:特定域名使用指定的自定义DNS服务器
比如a.test.com域名需要经过自建DNS服务器(IP为10.10.10.1)进行解析,可为域名配置一个单独的服务块,示例配置如下:
a.test.com:53 {
errors
cache 30
forward . 10.10.10.1
}
也可以匹配指定后缀为test.com的域名,都经过自建DNS服务器进行解析,如下:
test.com:53 {
errors
cache 30
forward . 10.10.10.1
}
完整配置如下:
Corefile: |-
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
proxy . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
test.com:53 {
errors
cache 30
forward . 10.101.1.3
}场景2:所有外部域名都使用自建DNS服务器
如果要访问的外部域名没有统一后缀,也可以直接指定自建的DNS服务器(IP为10.10.10.1、10.10.10.2).
Corefile: |-
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . 10.10.10.1 10.10.10.2 #直接指定DNS服务器IP,可以有多个
cache 30
loop
reload
loadbalance
}
场景3:自定义hosts
也可以在coredns上配置ip与域名的绑定关系,比如a.test.com指定IP为192.168.1.100。
Corefile: |-
.:53 {
errors
health
hosts { #设置hosts绑定
192.168.1.100 a.test.com
fallthrough
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
proxy . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
场景4:集群外部访问集群内服务
集群node节点上的进程,如果希望能够访问到集群内的服务,可以修改node节点上的/etc/resolv.conf文件中的nameserver配置,将nameserver指定为集群kube-dns的ClusterIP来达到目的。
五、pod DNS解析过程
kubectl get pod -n kube-system nodelocaldns-8zhcb -o yaml
1、pod首先检查自己的/etc/resolv.conf配置文件
是一个169.254.25.10,这个IP是NodeLocalDNS侦听DNS请求的IP
2、NodeLocalDNS如果能够解析则直接返回解析结果,如果不能解析则转发给全局DNS服务器。
NodeLocalDNS容器的Corefile,
kubectl get configmap -n kube-system nodelocaldns -o yaml
CoreDNS的Corefile
kubectl get configmap -n kube-system coredns -o yaml

浙公网安备 33010602011771号