Kubernetes服务之间的调用, 同一个namespace之间可以通过服务名来调用, 不同namespace可以通过服务域名来调用, 默认格式是 <serviceName>.<namespace>.svc.cluster.local
CoreDNS Pod数量最好和节点数是1:8的关系
基本规则
在k8s中,CoreDNS会监听3类k8s资源的事件,分别是Service、StatefulSet和Pod这3类资源,并会为这三类资源自动创建(更新/删除)相应的域名记录,k8s中各服务间可以直接通过服务域名的方式进行通信。
Service
CoreDNS会为Service创建3种域名记录:A或Cname、SRV、PTR
A/Cname的域名规则:
<svc-name>.<namespace-name>.svc.<cluster-domain>
SRV记录的域名命名规则:
<port-name>.<port-protocol>.<svc-name>.<namespace-name>.svc.<cluster-domain>
PTR记录的域名记录规则:
<reverse-ip>.in-addr.arpa. ttl IN PTR <svc-FQDN>
Statefulset
对于StatefulSet,CoreDNS会为其包含的每一个Pod创建A记录,域名命名规则如下:
<pod-name>.<svc-name>.<namespace-name>.svc.<cluster-domain>
Pod
CoreDNS只会为一种Pod创建域名记录,记录类型为A:Pod配置了hostName和subdomain,并且该Pod的subdomain与该Pod关联的Service名称相同时,域名命名规则与StatefulSet的Pod类似。
<host-name>.<svc-name>.<namespace-name>.svc.<cluster-domain>
CoreDNS
kube-proxy是运行在每个节点上面的,每个节点上面的kube-proxy其实都是按照同样的规则配置了负载均衡的,比如iptables和ipvs规则,也即是集群上面所有节点它的负载均衡是完全一致的,那么同样集群里面的A服务访问B服务这样的场景,在任何节点上面行为都是一样的。
这样就相当于在每个节点上面都配置了负载均衡的规则,来达到集群层面的分布式负载均衡。
任何的一个客户端要去访问一个服务,它的负载均衡策略在客户端这一层就做掉了,不需要去额外的负载均衡器里面再去做网络地址转换,因为数据包再出去的时候就已经实现了整个的负载均衡。
针对不同类型的service,ClusterIP类型,NodePort,LoadBalance类型。
它本身是基于内存的DNS,不落盘,早期kube-dns是落盘的,那么效率不太好,在集群启动的时候就启动了这样一个dns服务,但是dns服务里面没有任何的记录,这些记录从哪来?
在core dns里面还有控制器,控制器在启动的时候就会去读取集群所有的service的信息,endpoint信息,pod信息,它会将这些dns的映射关系转化为dns配置,service_name+name_space+svc+clusterdomin就是真正服务的域名。
任何的服务都会以这种模式,名称规则去创建域名。
coredns通过控制器来扫描当前集群的endpoint信息和service信息,来决定域名配置,哪个域名指向哪个虚拟IP。
pod这边怎么去解析呢?在pod里面有一个属性叫做DNS Policy,这个DNS Policy的默认值叫做ClusterFirst,也就是当我们去定义pod的时候这个属性你可以不去定义,如果属性不定义那么默认就是ClusterFirst,如果不去定义的话,它默认就是ClusterFirst,那么在你的pod启动之后,它就会帮你创建/etc/resolv.conf这个文件。
在这个文件里面就会去指定说我的nameserver是哪个coredns的地址,然后它会去做一些相应的配置,以便支持你这个域名服务发现。
不同类型服务的DNS记录
Headless是一个无头服务,你显示的声明了clusterIP为none,针对headless servcie那么kube-proxy不会做任何的路由转发和数据包的地址转换,因为它没有一个虚拟IP,所以kube-proxy和headless service没有任何的关系,那么headless service是怎么使用的呢?
dns会去辅助headless servcie,为服务创建地址记录,和普通的service不同的是,它这个地址记录会指向pod IP,是直接访问到pod IP的。
external name:我一个外部的服务域名,在内部通过别名去访问,所谓的别名就是在DNS里面称为Cname,她在本地的DNS里面为外部的服务创建一个cname,你访问这个cname,事实上最终这个dns就会转到外部的这个dns查询,最终请求到这个真实域名所对应的IP地址里面。
来看看具体的clusterfirst的dnsploicy做了什么事情,最终的作用体现在resolve.conf里面。
第一个就是nameserver(域名去哪个DNS查询),当pod发生域名查询的时候,这个域名去哪解析,这个是coreDns的clusterIP。coredns pod里面运行了内存状态的域名服务器和控制器,这个控制器负责往域名服务器里面刷记录。
Kubernetes当中的域名解析
你会看到有很多关于和service相关的一些环境变量,也就是说当我pod启动的时候,这个pod在启动的时候,kubernetes会去读取当前namespace里面所有已存在的service的信息,service对里面地址和端口信息都会以环境变量的方式存放到这个pod里面,做域名服务发现的时候,一方面可以基于dns去查询。
pod里面enableservicelinks这个属性,它默认是true,那么这个属性默认为true的结果就是所有的这种service的信息都会以环境变量的形式export到这个pod里面去
同一个namespace里面建立了几千的service,最后发现namespace里面的pod创建不出来,是因为kubernetes在启动容器的时候,它最终还是通过cri的接口,通过runc的命令去启动这些容器进程,所有的环境变量其实是在这套启动命令里面的一些参数,它通过enviorment参数传递进去的,当一个namespace里面有数千个个service的时候,它的命令行就变的超长了,linux对应用进程启动时候,参数的长度是有限制的,超长之后就要将后面的截取掉了,这样就使得启动命令不完整,这样的话容器就启动不起来了。
很多场景其实就是一个namespace里面很多service,在早期版本里面无法解决,后面支持了enableservicelinks这个属性,如果不希望通过环境变量来获取这些服务的信息,我们只需要将其置为false,里面的环境变量就看不到这些服务的信息了。
这样一个namspace建立多少service都不影响pod的启动。
自定义DNSPolicy
有些场景下,某些用户它的应用需要自定义DNSPolicy,比如它有自己的nameserver,它有自己的searchdomain,你可以在你的pod里面定义dnspolicy为none,然后加上自己的dnsconfig。