【4】K8S中的服务发现机制
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
解析:
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集群中的服务发现非常有用, 因为它允许你使用短名称来引用服务,而不必指定完整的域名。nameserver 10.43.0.10
这一行指定了要使用的DNS服务器的IP地址(对应kube-dns的ClusterIP)。在这种情况下,DNS解析器将查询由IP地址10.43.0.10
指定的DNS服务器(即pod/coredns)来解析域名。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的方式。