kubernetes CoreDNS组件研究

发布时间 2023-04-12 16:11:03作者: 若-飞

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