1. 概述
本文介绍k8s集群中,默认的CoreDNS配置,域名解析过程分析,解释服务发现的机制。
从kubernetes 1.11版本开始,Kubernetes集群的DNS服务由CoreDNS提供。CoreDNS是CNCF基金会的一个项目,是用Go语言实现的高性能、插件式、易扩展的DNS服务端。CoreDNS解决了KubeDNS的一些问题,例如dnsmasq的安全漏洞、externalName不能使用stubDomains设置,等等。
CoreDNS:域名解析服务,DNS服务器软件,通用用于在容器化环境中支持服务发现功能
如果发现本人的理解有误,欢迎指正。
2. K8S域名上报和解析
2.1. K8S域名上报流程
K8S创建service的时候,会把service的域名,以及entpoint等信息存储到etcd中。
方便后续域名解析查看
当我们请求某个域名的时候,把请求发给coredns==》coredns把请求发给apiserver==》apiserver再去etcd中拿取数据返回给dns==》dns返回给客户端
上报域名的格式:"<service-name>.<namespace>.svc.cluster.local"
2.2. K8S域名解析流程
在 K8s 中,Pod 之间通过 svc 访问的时候,转化为域名: "<service-name>.<namespace>.svc.cluster.local",经过 DNS 域名解析,拿到 ip 通信。
这样就实现了只需将 svc name 当成域名就能访问到 pod
3. kube-dns服务查看
sudo kubectl get service -n kube-system
qiteck@server:~$ sudo kubectl get service -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 277d
metrics-server ClusterIP 10.96.119.138 <none> 443/TCP 62d
sudo kubectl describe service kube-dns -n kube-system
qiteck@server:~$ sudo kubectl describe service kube-dns -n kube-system
Name: kube-dns
Namespace: kube-system
Labels: k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=CoreDNS
Annotations: prometheus.io/port: 9153
prometheus.io/scrape: true
Selector: k8s-app=kube-dns
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.0.10
IPs: 10.96.0.10
Port: dns 53/UDP
TargetPort: 53/UDP
Endpoints: 10.244.0.169:53,10.244.0.171:53
Port: dns-tcp 53/TCP
TargetPort: 53/TCP
Endpoints: 10.244.0.169:53,10.244.0.171:53
Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 10.244.0.169:9153,10.244.0.171:9153
Session Affinity: None
Events: <none>
可以看到dns的ip地址是10.96.0.10,部署是采用ClusterIP方式,只对内开放。如果要对外开放可以修改成NodePort方式
3. 服务名的DNS解析举例
接下来使用一个带有nslookup工具的Pod来验证DNS服务能否正常工作
3.1. 查看当前可用的服务
后面nslookup的时候会用到
sudo kubectl get service
qiteck@server:~/program/k8s$ sudo kubectl get service --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default consul-client NodePort 10.96.15.198 <none> 8500:8500/TCP,8600:8600/UDP,8600:8600/TCP 237d
default consul-server NodePort 10.96.189.236 <none> 8500:10251/TCP,8443:44046/TCP,8400:41489/TCP,8301:7227/TCP,8301:7227/UDP,8302:9582/TCP,8302:9582/UDP,8300:62187/TCP,8600:12039/UDP,8600:12039/TCP 237d
default course NodePort 10.96.139.231 <none> 8804:8804/TCP 5d
default demo ClusterIP 10.96.154.203 <none> 80/TCP 22d
default dev ClusterIP 10.96.205.48 <none> 9704/TCP 8d
default file ClusterIP 10.96.45.189 <none> 8808/TCP 5d23h
default gateway NodePort 10.96.196.181 <none> 1080:1080/TCP,1663:1663/TCP,1773:1773/TCP,1783:1783/TCP 89d
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 277d
default omp NodePort 10.96.121.12 <none> 18800:18800/TCP 105d
default omp2 NodePort 10.96.29.29 <none> 18801:18801/TCP 25h
ingress-nginx ingress-nginx-controller NodePort 10.96.180.91 <none> 80:80/TCP,443:443/TCP 22d
ingress-nginx ingress-nginx-controller-admission ClusterIP 10.96.242.221 <none> 443/TCP 22d
kafka kafka NodePort 10.96.40.171 <none> 9092:9092/TCP 40d
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 277d
kube-system metrics-server ClusterIP 10.96.119.138 <none> 443/TCP 62d
rabbitmq rabbitmq NodePort 10.96.253.124 <none> 1883:1883/TCP,5672:5672/TCP,15672:15672/TCP 9d
rabbitmq rabbitmq-internal ClusterIP None <none> 1883/TCP,4369/TCP,5672/TCP,5671/TCP,15672/TCP,25672/TCP 9d
zookeeper zk-cs NodePort 10.96.106.4 <none> 2181:2181/TCP 41d
zookeeper zk-hs ClusterIP None <none> 2888/TCP,3888/TCP 41d
需要注意不同的NAMESPACE
3.2. 部署dnsutils
dnsutils.yaml
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
spec:
containers:
- name: dnsutils
image: registry.qiteck.net:10002/dnsutils:1.3
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
部署dnsutils pod
sudo kubectl deploy -f dnsutils.yaml
sudo kubectl get pods |grep dnsutils
qiteck@server:~/program/k8s$ sudo kubectl get pods |grep dnsutils
dnsutils 1/1 Running 1 (47m ago) 112m
3.3. nslookup查找NAMESPACE为default的服务:
sudo kubectl exec -it dnsutils -- nslookup course
qiteck@server:~/program/k8s$ sudo kubectl exec -it dnsutils -- nslookup course
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: course.default.svc.cluster.local
Address: 10.96.139.231
可以看到找到的域名是course.default.svc.cluster.local,地址是10.96.139.231
3.4. nslookup查找非default的NAMESPACE的服务:
nslookup查找kube-dns服务:
sudo kubectl exec -it dnsutils -- nslookup kube-dns
qiteck@server:~/program/k8s$ sudo kubectl exec -it dnsutils -- nslookup kube-dns
Server: 10.96.0.10
Address: 10.96.0.10#53
** server can't find kube-dns: SERVFAIL
command terminated with exit code 1
这样是无法找到kube-dns服务的,为啥呢?就是因为NAMESPACE不同,加上namespace就可以了
sudo kubectl exec -it dnsutils -- nslookup kube-dns.kube-system
qiteck@server:~/program/k8s$ sudo kubectl exec -it dnsutils -- nslookup kube-dns.kube-system
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kube-dns.kube-system.svc.cluster.local
Address: 10.96.0.10
后面一起分析原因
3.5. dnsutils域名解析过程分析
部署 pod 的时候,如果用的是 K8s 集群的 DNS,那么 kubelet 在起 pause 容器的时候,会将其 DNS 解析配置初始化成集群内的配置。
比如刚才创建了一个叫 dnsutils 的 pod,它的 resolv.conf 文件如下:
sudo kubectl exec -it dnsutils -- cat /etc/resolv.conf
qiteck@server:~/program/k8s$ sudo kubectl exec -it dnsutils -- cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local qiteck.net localdomain
nameserver 10.96.0.10
options ndots:5
在集群中 pod 之间互相用 svc name 访问的时候,会根据 resolv.conf 文件的 DNS 配置来解析域名,下面来分析具体的过程。
pod 的 resolv.conf 文件主要有三个部分,分别为 nameserver、search 和 option。而这三个部分可以由 K8s 指定,也可以通过 pod.spec.dnsConfig 字段自定义。
- nameserver
resolv.conf 文件的第一行 nameserver 指定的是 DNS 服务的 IP,这里就是 coreDNS 的 clusterIP:
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 277d
也就是说所有域名的解析,都要经过 coreDNS 的虚拟 IP 10.96.0.10 进行解析,不论是 Kubernetes 内部域名还是外部的域名。
- search 域
resolv.conf 文件的第二行指定的是 DNS search 域。解析域名的时候,将要访问的域名依次带入 search 域,进行 DNS 查询。
比如我要在刚才那个 pod 中访问一个域名为 dnsutils 的服务,其进行的 DNS 域名查询的顺序是:
dnsutils.default.svc.cluster.local -> dnsutils.svc.cluster.local -> dnsutils.cluster.local
直到查到为止。
- options
resolv.conf 文件的第三行指定的是其他项,最常见的是 dnots。dnots 指的是如果查询的域名包含的点 “.” 小于 5,则先走 search 域,再用绝对域名;如果查询的域名包含点数大于或等于 5,则先用绝对域名,再走 search 域。K8s 中默认的配置是 5。
也就是说,如果我访问的是 a.b.c.e.f.g ,那么域名查找的顺序如下:
a.b.c.e.f.g. -> a.b.c.e.f.g.default.svc.cluster.local -> a.b.c.e.f.g.svc.cluster.local -> a.b.c.e.f.g.cluster.local
如果我访问的是 a.b.c.e,那么域名查找的顺序如下:
a.b.c.e.default.svc.cluster.local -> a.b.c.e.svc.cluster.local -> a.b.c.e.cluster.local -> a.b.c.e