kubernetes网络之DNS
默认DNS策略
Pod默认的dns策略是 ClusterFirst
,意思是先通过kubernetes的权威DNS服务器(如CoreDNS)直接解析出A记录或CNAME记录;如果解析失败,再根据配置,将其转发给上游DNS服务器。以CoreDNS为例,它的配置文件Corefile如下所示:
1➜ ~ kubectl get cm -n kube-system coredns -o yaml
2apiVersion: v1
3data:
4 Corefile: |
5 .:53 {
6 errors
7 health {
8 lameduck 5s
9 }
10 ready
11 kubernetes cluster.local in-addr.arpa ip6.arpa {
12 pods insecure
13 fallthrough in-addr.arpa ip6.arpa
14 ttl 30
15 }
16 prometheus :9153
17 forward . /etc/resolv.conf
18 cache 30
19 loop
20 reload
21 loadbalance
22 }
23kind: ConfigMap
24...
第17行使用forward插件配置了上游域名服务器为主机的/etc/resolv.conf
中指定的nameserver
。
Service和DNS
尽管kubelet在启动容器时,会将同namespace下的Service信息注入到容器的环境变量中:
1➜ ~ kubectl get svc | grep kubernetes
2kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 347d
3
4➜ ~ kubectl exec -it debug-pod -n default -- env | grep KUBERNETES
5KUBERNETES_SERVICE_PORT=443
6KUBERNETES_PORT=tcp://192.168.0.1:443
7KUBERNETES_PORT_443_TCP_ADDR=192.168.0.1
8KUBERNETES_PORT_443_TCP_PORT=443
9KUBERNETES_PORT_443_TCP_PROTO=tcp
10KUBERNETES_PORT_443_TCP=tcp://192.168.0.1:443
11KUBERNETES_SERVICE_PORT_HTTPS=443
12KUBERNETES_SERVICE_HOST=192.168.0.1
但是通常情况下我们使用DNS域名解析的方式进行服务注册和发现。
Kubernetes中的DNS应用部署好以后,会对外暴露一个服务,集群内的容器可以通过访问该服务的Cluster IP进行域名解析。DNS服务的Cluster IP由Kubelet的cluster-dns
参数指定。并且在创建Pod时,由Kubelet将DNS Server的信息写入容器的/etc/resolv.conf
文件中。
查看resolv.conf
文件的配置:
1➜ ~ k exec -it debug-pod -n default -- cat /etc/resolv.conf
2nameserver 192.168.0.2
3search default.svc.cluster.local svc.cluster.local cluster.local
4options ndots:5
-
nameserver 192.168.0.2
这一行即表示DNS服务的地址(Cluster IP)为192.168.0.2
。 -
search
这一行表示,如果无法直接解析域名,则会尝试加上default.svc.cluster.local
,svc.cluster.local
,cluster.local
后缀进行域名解析。其中
default
是namespace,cluster.local
是默认的集群域名后缀,kubelet也可以通过--cluster-domain
参数进行配置。
也就是说:
- 同namespace下,可以通过
nslookup
+kubernetes
解析域名 - 不同namespace下,可以通过
nslookup
+kubernetes.default
、kubernetes.default.svc
、kubernetes.default.svc.cluster.local
解析域名
因为dns服务器会帮你补齐全域名:kubernetes.default.svc.cluster.local
{svc name}.{svc namespace}.svc.{cluster domain}
就是kubernetes的FQDN格式。
Headless Service的域名解析
无论是kube-dns还是CoreDNS,基本原理都是通过watch Service和Pod,生成DNS记录。常规的ClusterIP类型的Service的域名解析如上所述,DNS服务会返回一个A记录
,即域名和ClusterIP的对应关系:
1➜ ~ k exec -it debug-pod -n default -- nslookup kubernetes.default
2Server: 192.168.0.2
3Address: 192.168.0.2#53
4
5Name: kubernetes.default.svc.cluster.local
6Address: 192.168.0.1
Headless Service的域名解析稍微复杂一点。
ClusterIP可以看作是Service的头,而Headless Service,顾名思义也就是指定他的ClusterIP为None的Service。
直接解析
当你直接解析它的域名时,返回的是EndPoints中的Pod IP列表:
这个EndPoints后端的Pod,不仅可以通过在service中指定selector来选择,也可以自己定义,只要名字和service同名即可。
1➜ ~ k exec -it debug-pod -n default -- nslookup headless
2Defaulting container name to debug.
3Use 'kubectl describe pod/debug-pod -n default' to see all of the containers in this pod.
4Server: 192.168.0.2
5Address: 192.168.0.2#53
6
7Name: headless.default.svc.cluster.local
8Address: 1.1.1.1
9Name: headless.default.svc.cluster.local
10Address: 2.2.2.2
11Name: headless.default.svc.cluster.local
12Address: 3.3.3.3
给Pod生成A记录
如果在Pod.spec
中指定了hostname
和subdomain
,并且subdomain
和headleass service的名字相同,那么kubernetes DNS会额外给这个Pod的FQDN生成A记录:
1➜ ~ k exec -it debug-pod -n default -- nslookup mywebsite.headless.default.svc.cluster.local
2Server: 192.168.0.2
3Address: 192.168.0.2#53
4
5Name: mywebsite.headless.default.svc.cluster.local
6Address: 10.189.97.217
Pod的FQDN是:
{hostname}.{subdomain}.{pod namespace}.svc.{cluster domain}
ExternalName Service
ExternalName 类型的Service,kubernetes DNS会根据ExternalName
字段,为其生成CNAME记录,在DNS层进行重定向。
1apiVersion: v1
2kind: Service
3metadata:
4 name: external
5 namespace: default
6spec:
7 type: ExternalName
8 externalName: my.example.domain.com
1➜ ~ k exec -it debug-pod -n default -- nslookup external
2Server: 192.168.0.2
3Address: 192.168.0.2#53
4
5external.default.svc.cluster.local canonical name = my.example.domain.com.
6Name: my.example.domain.com
7Address: 66.96.162.92