众所周知,Pod 是Kubernetes的最小管理单元,它里面包含一组相关的容器,用来提供某种服务。用户的最终请求流量到达的是Pod。但是Pod是有生命周期的。这也意味着Pod随时会挂掉。新生成的Pod的IP地址,所在节点等都有可能变化。那如何才能保证Pod提供的服务是稳定的呢?
Kubernetes使用了Service来解决这个问题。用户的流量请求并不是直接指向Pod, 而是先指向Service. Service再转发到Pod. 这里我们就来看下Service 是如何转发流量,如何做到负载均衡的呢。
如下图,假设用户使用某个Node的port(当然,最普遍的是使用云运营商的LoadBalance服务,这里不赘述,本文只介绍Service的LB角色) 来访问集群,当流量到达集群内部后,会首先到达Service的IP和端口,然后Service会去查询EndPoint 中的Pod IP地址和端口,最后把该请求转发到符合条件的某个Pod的IP和端口上,然后Pod开始处理用户请求, 完成✅。
Pod 是由副本控制器(ReplicaSet)所管理的。Pod重启之后它的IP已经发生了变化,那么Servie是如何知道这个新Pod的IP的呢?答案是Kube-Proxy. Kube-Proxy会一直监听主机上的Pod, 当Pod发生变化时,它会把Pod的新生成的IP 写入到EndPoint. 这样Service就知道新Pod的IP和端口号是多少了, 从而转发用户请求到对应的Pod.
我们以marketplace-operator为例来试下,该operator会向Prometheus 组件上报自身的指标. 它运行了两个Pod副本,IP 地址分别是:10.129.0.28 10.130.0.41
# oc get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
marketplace-operator-6948c8d548-jvfwc 1/1 Running 0 21h 10.129.0.28 ip-10-0-204-63.us-east-2.compute.internal <none> <none>
marketplace-operator-6948c8d548-jz9k7 1/1 Running 0 18m 10.130.0.41 ip-10-0-144-204.us-east-2.compute.internal <none> <none>
我们查看下它的Service. 它的IP 地址(ClusterIP,即虚拟IP)是172.30.23.219
# oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
marketplace-operator-metrics ClusterIP 172.30.23.219 <none> 8383/TCP,8081/TCP 22h
我们再来看下它的EndPoint, 包含了10.129.0.28 10.130.0.41地址。
# oc get ep
NAME ENDPOINTS AGE
marketplace-operator-metrics 10.129.0.28:8383,10.130.0.41:8383,10.129.0.28:8081 + 1 more... 22h
现在我们删除其中一个Pod.
# oc delete pods marketplace-operator-6948c8d548-jvfwc
pod "marketplace-operator-6948c8d548-jvfwc" deleted
再来查看下新Pod的IP, 可以看到新Pod 的IP地址为10.128.0.21
# oc get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
marketplace-operator-6948c8d548-84vrr 1/1 Running 0 45s 10.128.0.21 ip-10-0-161-62.us-east-2.compute.internal <none> <none>
marketplace-operator-6948c8d548-jz9k7 1/1 Running 0 26m 10.130.0.41 ip-10-0-144-204.us-east-2.compute.internal <none> <none>
我们再来看下EndPoints,可以看到10.129.0.28已经被更新为10.128.0.21了。
# oc get ep
NAME ENDPOINTS AGE
marketplace-operator-metrics 10.128.0.21:8383,10.130.0.41:8383,10.128.0.21:8081 + 1 more... 22h
在此Pod重建期间,Service的IP(172.30.23.219) 始终保持不变, 对外提供稳定的服务。它也可以被看作是Pod的网关。
# oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
marketplace-operator-metrics ClusterIP 172.30.23.219 <none> 8383/TCP,8081/TCP 22h
思考:
1,Service和EndPoint是如何对应的呢?名称!
从上面可以看到Service和Endpoint的name是相同的都是marketplace-operator-metrics.
2, Service背后有很多Pod,它是采用什么算法来如何选择某个具体Pod的?轮询吗?
3,既然Service可以通过EndPoint来找到对应的Pod, 那为什么还要使用标签选择器(Selector)来选择Pod呢?
# oc get svc marketplace-operator-metrics -o=jsonpath='{.spec.selector}'
map[name:marketplace-operator]
# oc get pods -l name=marketplace-operator
NAME READY STATUS RESTARTS AGE
marketplace-operator-6948c8d548-84vrr 1/1 Running 0 19m
marketplace-operator-6948c8d548-jz9k7 1/1 Running 0 45m