跳到主要内容

【4】K8S中的服务发现机制

参考 k8s-tutorial-cn

k8s支持下面两种服务发现方式:

  • kube-dns(推荐)
  • 环境变量

kube-dns

kube-dns service位于kube-system空间下,它是k8s内置的DNS组件,用来为集群中所有Pod提供服务发现功能。这个service通过selectork8s-app=kube-dns关联了名为coredns的Pod组。

> kubectl get pod,deployment,svc -n kube-system | grep dns
# pod
pod/coredns-6799fbcd5-9zn94 1/1 Running 0 6d19h
# deployment
deployment.apps/coredns 1/1 1 1 8d
# service
service/kube-dns ClusterIP 10.43.0.10 <none> 53/UDP,53/TCP,9153/TCP 8d

k8s通过每个节点部署的kubelet组件向每个新启动的Pod注入DNS配置(通过/etc/resolv.conf),从而实现服务发现。这里随意选择一个Pod,查看DNS配置。

> kubectl get pods -o wide
...略
> kubectl exec -it hellok8s-go-http-7c57cd6487-tp522 -- cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.43.0.10
options ndots:5

resolv.conf解析:

  1. search default.svc.cluster.local svc.cluster.local cluster.local 这一行定义了DNS搜索域。它告诉DNS解析器,如果在域名中没有明确指定的主机名,那么应该依次尝试附加这些搜索域来查找主机名。 在这种情况下,如果你尝试解析一个名为example的主机名,DNS解析器会首先尝试example.default.svc.cluster.local, 然后是example.svc.cluster.local,最后是example.cluster.local。这对于Kubernetes集群中的服务发现非常有用, 因为它允许你使用短名称来引用服务,而不必指定完整的域名。
  2. nameserver 10.43.0.10 这一行指定了要使用的DNS服务器的IP地址(对应kube-dns的ClusterIP)。在这种情况下,DNS解析器将查询由IP地址10.43.0.10指定的DNS服务器(即pod/coredns)来解析域名。
  3. options ndots:5 这一行定义了DNS解析选项。ndots是一个数字,表示DNS解析器应该在域名中查找多少次点(.)以确定绝对域名。在这种情况下, ndots:5表示如果一个域名中包含至少5个点,则DNS解析器会将它视为绝对域名,否则会依次附加搜索域来查找主机名。

测试:

> kubectl get pod,svc 
NAME READY STATUS RESTARTS AGE
pod/hellok8s-go-http-7c57cd6487-6rd7q 1/1 Running 0 8d
pod/hellok8s-go-http-7c57cd6487-tp522 1/1 Running 0 8d
pod/hellok8s-go-http-7c57cd6487-znnvc 1/1 Running 0 6d19h
pod/curl 1/1 Running 185 (22m ago) 7d19h

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 8d
service/service-hellok8s-nodeport NodePort 10.43.12.63 <none> 3000:30000/TCP 6d19h

由上文可知service-hellok8s-clusterip就是一个集群内有效的虚拟主机名(指向三个hellok8s-go-http pod),我们可以使用curl容器来测试:

> kubectl exec -it curl --  curl service-hellok8s-nodeport:3000      
[v3] Hello, Kubernetes!, From host: hellok8s-go-http-7c57cd6487-tp522

环境变量

在每个新启动的Pod中,kubelet也会向其注入当前namespace中已存在的Service信息(以环境变量形式),Pod可以通过这些环境变量来发现其他Service的IP地址。 这里依旧使用上文环境做测试,在curl shell中查看service/service-hellok8s-nodeport的环境变量。

> kubectl exec -it curl --  printenv |grep HELLOK8S
SERVICE_HELLOK8S_NODEPORT_PORT_3000_TCP_PROTO=tcp
SERVICE_HELLOK8S_NODEPORT_PORT_3000_TCP_PORT=3000
SERVICE_HELLOK8S_NODEPORT_PORT_3000_TCP=tcp://10.43.12.63:3000
SERVICE_HELLOK8S_NODEPORT_SERVICE_PORT=3000
SERVICE_HELLOK8S_NODEPORT_SERVICE_HOST=10.43.12.63
SERVICE_HELLOK8S_NODEPORT_PORT=tcp://10.43.12.63:3000
SERVICE_HELLOK8S_NODEPORT_PORT_3000_TCP_ADDR=10.43.12.63

所以此时我们也可以通过env的方式访问service/service-hellok8s-nodeport

# 先进入容器里面
> kubectl exec -it curl -- sh
# 下面的语句是在容器里面执行的
> curl $SERVICE_HELLOK8S_NODEPORT_SERVICE_HOST:$SERVICE_HELLOK8S_NODEPORT_SERVICE_PORT
[v3] Hello, Kubernetes!, From host: hellok8s-go-http-7c57cd6487-6rd7q
不推荐使用环境变量方式实现服务发现

环境变量方式对资源的创建顺序有要求。比如pod/curl先启动,某个service后创建,那么启动后的pod/curl 中就不会有这个Service相关的环境变量。 所以这里不推荐使用环境变量的方式访问Service,而是推荐使用内置DNS的方式。