
众所周知,我们给一些pod创建好Service之后,就可以通过service访问pod了。

从Kubernetes集群内通过service访问pod有两种办法:
肯定得有个DNS server来干这个活儿,在你的k8s上执行以下这个命令:
gaoyang@IT-C02XQ1HFJG5H standalone % kubectl get pod -A | grep dns
kube-system coredns-6b9cfd868c-fjmz5 1/1 Running 0 16d
kube-system coredns-6b9cfd868c-x7wrx 1/1 Running 0 16d
这个位于kube-system namespace内的叫做coredns的pod就是kubernetes内置的DNS server。
所有关于service和dns的事情都是他做的。
CoreDNS的工作原理示意图如下:

kubectl -n lemming exec -it standalone-0 -- cat /etc/resolv.conf
search lemming.svc.cluster.local svc.cluster.local cluster.local
nameserver 22.10.0.10
options ndots:5
这个22.10.0.10其实就是CoreDNS对应的service的地址
kubectl get svc -A | grep dns
kube-system kube-dns ClusterIP 22.10.0.10
现在让我们来来考虑一下StetefulSet的问题。
我们都知道,statefulset会为每一个pod创建一个固定的DNS记录(DNS解析后的IP是pod的IP,而不是service的ip)。但是StatefulSet的文档中明确要求我们先得自己创建一个headless类型的service,才能保证每个pod拥有一个dns记录。pod的dns域名长这样:my_pod.my_service.default.svc.cluster.local
这个结果其实是statefulset和headless service共同作用的结果:statefulset指定了pod的名字,headless service(其实真正干活的是coredns)给这个被指定了名字的pod创建了一个DNS记录。
当然,如果只有headless service,没有statefulset的情况下,pod也是会被创建一个DNS记录的,只不过记录的最前面pod名字的部分是一个随机的字符串。
所以关于上面的第6和第7步,其实是:
CoreDNS监听到service创建的事件后,会判断这是不是一个headless service,如果是的话,就从etcd中找到headless service对应的endpoint的ip,给每一个endpoint都创建一条记录。
因为headless service是没有ClusterIP的,所以直接请求headless service时,返回的其实是一个endpoint ip的列表。
更进一步,对于headless pod的DNS记录,CoreDNS并不是一监听到service创建的事件就会给每个endpoint创建一条DNS记录,如果我们的pod还没启动完,此时通过dns就能访问的话,就会出错了。
所以,CoreDNS真正给Endpoint创建DNS记录的时机是CoreDNS监听到Endpoint(pod)的状态变成ready时,才会创建。
而Pod的ready状态又是由Kubernetes的readiness probe 探针决定的。