kubernetes网路 – 服务与DNS

欢迎加入本站的kubernetes技术交流群,QQ群号:450203387,微信群:加Blue_L。


kubernetes会为每个service对象创建dns记录,这个操作是由dns插件完成的,基本上所有集群都会使用coredns作为dns插件。

kubernetes中的服务是区分命名空间的,nginx这个域名在默认情况下是使用本pod所在namespace解析的,如pod所在的namespace为default,则默认解析为nginx.default。下列是一个示例pod的resolv文件配置

[root@master1 ~]# kubectl exec -it nginx-deployment-66b6c48dd5-95c7f -- cat /etc/resolv.conf
nameserver 172.17.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

服务对象分为普通服务和无头服务,无头服务是指spec.clusterIP=None的,其他服务则为普通服务。

如果service是一个普通服务对象,则会为其创建一个dns A记录(ipv6则为AAAA记录),该记录的ip地址是在kube-controller-manager的--service-cluster-ip-range参数指定的网段内,该网段和pod网段以及节点网段都不在一个网段内。

如果service是一个无头服务,则会创建一些列dns A记录,记录的ip地址是pod的ip。

k8s还会为服务对象的每个命名端口创建srv记录。如_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster-domain.example。对于普通服务,解析到my-svc.my-namespace.svc.cluster-domain.exampl加端口号。对于无头服务会为每个pod创建一个类似的记录。auto-generated-name.my-svc.my-namespace.svc.cluster-domain.example加端口号。

通常情况下,会为所有pod创建如下类型的dns解析:

pod-ip-address.my-namespace.pod.cluster-domain.example -> pod-ip
kubectl run aaaa --image=nginx
[root@master1 ~]# nslookup 10-248-5-2.default.pod.cluster.local 172.17.0.10
Server:         172.17.0.10
Address:        172.17.0.10#53
​
Name:   10-248-5-2.default.pod.cluster.local
Address: 10.248.5.2

通常情况下,会为deployment和daemonset的pod,且通过service进行暴露的话,则会创建下列dns解析:

pod-ip-address.deployment.my-namespace.svc.cluster.local -> pod-ip

针对deployment进行测试

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx  --port 80
[root@master3 ~]# nslookup nginx.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: nginx.default.svc.cluster.local
Address: 172.17.184.200
​
# 基于deployment(或daemonset)的解析规则
[root@master3 ~]# nslookup 10-248-213-77.nginx.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: 10-248-213-77.nginx.default.svc.cluster.local
Address: 10.248.213.77
​
# 来看pod是否也同样有解析
[root@master3 ~]# kubectl get pod -owide | grep nginx
nginx-6799fc88d8-gfpkp   1/1     Running   0          5m34s   10.255.136.159   worker3   <none>           <none>
[root@master3 ~]# nslookup 10-255-136-159.default.pod.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: 10-255-136-159.default.pod.cluster.local
Address: 10.255.136.159
​
[root@master3 ~]#

但是针对statefulset规则不同,statefulset可以直接通过pod名(主机名)解析

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
​
[root@master3 ~]# kubectl apply -f statefulset.yaml
[root@master3 ~]# kubectl get pod -owide | grep web-0
web-0                    0/1     ImagePullBackOff   0          57s   10.248.213.77    worker1   <none>           <none>
[root@master3 ~]# nslookup nginx.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: nginx.default.svc.cluster.local
Address: 10.255.136.159
​
# 使用主机名解析,普通服务和无头服务都可以
[root@master3 ~]# nslookup web-0.nginx.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: web-0.nginx.default.svc.cluster.local
Address: 10.248.213.77

使pod的域名可解析。

kubernetes设计中,满足该条件则可以通过dns解析到pod的ip地址:被service选中的pod有hostname和subdomain配置。如果被service选中的pod没有hostname配置,但是有subdomain配置时,pod的ip仅可以作为无头服务的A纪录返回,如果hostname和subdomain都有配置,则应创建pod的dns记录(因为这时候endpoint才会有hostname字段)。

下面是测试pod配置或不配置subdomain时,分别创建普通服务和无头服务的测试(基于kubernetes 1.22和coredns 1.8.4):

# pod对象
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  hostname: busybox
  subdomain: default-subdomain
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: busybox
  restartPolicy: Always
​
# service对象
apiVersion: v1
kind: Service
metadata:
  name: default-subdomain
spec:
  selector:
    app: busybox
  type: ClusterIP
  ports:
  - port: 80
# 有subdomain,没有创建服务时pod解析
[root@master3 ~]# nslookup busybox.default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
** server can't find busybox.default-subdomain.default.svc.cluster.local: NXDOMAIN
​
​
# 有subdomain,创建普通服务,service解析到clusterIP,pod可以解析,endpoint有hostname
[root@master3 ~]# nslookup default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: default-subdomain.default.svc.cluster.local
Address: 172.17.33.97
​
[root@master3 ~]# nslookup busybox.default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: busybox.default-subdomain.default.svc.cluster.local
Address: 10.248.213.79
​
[root@master3 ~]#
[root@master3 ~]# kubectl get ep default-subdomain -oyaml | grep -C 1 hostname
- addresses:
  - hostname: busybox
    ip: 10.248.213.79
​
​
​
# 有subdomain,创建无头服务,service解析的pod地址列表,pod可解析,endpoint有hostname
[root@master3 ~]# nslookup default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: default-subdomain.default.svc.cluster.local
Address: 10.248.213.79
​
[root@master3 ~]# nslookup busybox.default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: busybox.default-subdomain.default.svc.cluster.local
Address: 10.248.213.79
​
[root@master3 ~]# kubectl get ep default-subdomain -oyaml | grep -C 1 hostname
- addresses:
  - hostname: busybox
    ip: 10.248.213.79
[root@master3 ~]#
​
​
​
​
# 无subdomain,创建普通服务,service解析到clusterIP,pod不可解析,endpoint无hostname
[root@master3 ~]# nslookup default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: default-subdomain.default.svc.cluster.local
Address: 172.17.74.211
​
[root@master3 ~]# nslookup busybox.default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
** server can't find busybox.default-subdomain.default.svc.cluster.local: NXDOMAIN
​
[root@master3 ~]# kubectl get ep default-subdomain -oyaml | grep -C 1 hostname
[root@master3 ~]#
​
​
​
​
# 无subdomain,创建无头服务,service解析到pod地址列表,pod不可解析,endpoint无hostname
[root@master3 ~]# nslookup default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: default-subdomain.default.svc.cluster.local
Address: 10.248.213.79
​
[root@master3 ~]# nslookup busybox.default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
** server can't find busybox.default-subdomain.default.svc.cluster.local: NXDOMAIN
​
[root@master3 ~]# kubectl get ep default-subdomain -oyaml | grep -C 1 hostname
[root@master3 ~]#

kubernetes中,对于statefulset的pod,kubernetes在创建的时候会自动设置相关字段

func initIdentity(set *apps.StatefulSet, pod *v1.Pod) {
  updateIdentity(set, pod)
  // Set these immutable fields only on initial Pod creation, not updates.
  pod.Spec.Hostname = pod.Name
  pod.Spec.Subdomain = set.Spec.ServiceName
}

对于deployment的pod是不会自动设置hostname和subdomain的,因此我们无法通过dns解析到pod。但是我们可以通过修改coredns配置,加上endpoint_pod_names参数使deployment的pod name(同hostname)可解析为pod ip。开启此参数之后,coredns判断如果endpoint没有hostname字段,则会使用pod的name(不开启的话,则返回“-”分割的ip地址的记录),所以针对上面busybox中无subdomain情况,pod也可解析。

func endpointHostname(addr object.EndpointAddress, endpointNameMode bool) string {
  if addr.Hostname != "" {
    return addr.Hostname
  }
  if endpointNameMode && addr.TargetRefName != "" {
    return addr.TargetRefName
  }
  if strings.Contains(addr.IP, ".") {
    return strings.Replace(addr.IP, ".", "-", -1)
  }
  if strings.Contains(addr.IP, ":") {
    return strings.Replace(addr.IP, ":", "-", -1)
  }
  return ""
}

kubernetes代码中下面的判读决定是否要创建endpoint的hostname

func ShouldSetHostname(pod *v1.Pod, svc *v1.Service) bool {
   return len(pod.Spec.Hostname) > 0 && pod.Spec.Subdomain == svc.Name && svc.Namespace == pod.Namespace
}

开启endpoint_pod_names后测试

[root@master3 ~]# kubectl create deployment web --image=nginx
[root@master3 ~]# kubectl expose deployment web --port=80
[root@master3 ~]# nslookup web.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: web.default.svc.cluster.local
Address: 172.17.138.248
​
[root@master3 ~]# nslookup web-96d5df5c8-29ps6.web.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: web-96d5df5c8-29ps6.web.default.svc.cluster.local
Address: 10.255.136.160
​
[root@master3 ~]# kubectl get pod -owide | grep web
web-96d5df5c8-29ps6              1/1     Running            0             3m16s   10.255.136.160   worker3   <none>           <none>
[root@master3 ~]# kubectl get pod web-96d5df5c8-29ps6 -oyaml | grep -i subdomain
[root@master3 ~]# kubectl get pod web-96d5df5c8-29ps6 -oyaml | grep -i hostname
[root@master3 ~]# kubectl get ep web -oyaml | grep -i hostname
​
# 无hostname和subdomain配置的裸pod
[root@master3 ~]# kubectl get pod busybox -oyaml | grep -i hostname
[root@master3 ~]# kubectl get pod busybox -oyaml | grep -i subdomain
[root@master3 ~]# nslookup default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: default-subdomain.default.svc.cluster.local
Address: 10.255.136.155
​
[root@master3 ~]# nslookup busybox.default-subdomain.default.svc.cluster.local 172.17.0.10
Server:   172.17.0.10
Address:  172.17.0.10#53
​
Name: busybox.default-subdomain.default.svc.cluster.local
Address: 10.255.136.155

针对deployment的pod设置hostname和subdomain讨论还在开放中:

https://github.com/kubernetes/kubernetes/issues/60789

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注