服务发现

上一章中我们通过Deployment部署了一个Flask应用,并且通过登录到容器内部验证了服务是否能够正常访问。那我们该如何对外暴露应用供其他服务访问呢?以及我们该如何在集群外部访问集群内部的服务呢?本章带领大家一起去探索。

4.1 Service

为什么需要 Service

集群中的每一个 Pod 都可以通过 Pod IP 直接访问,但是正如我们所看到的,Kubernetes 中的 Pod 是有生命周期的,尤其是被 ReplicaSet、Deployment 等对象管理的 Pod,随时都有可能被销毁和重建。这就会出现一个问题,当 Kuberentes 集群中的一些 Pod 需要为另外的一些 Pod 提供服务时,我们如何为这组 Pod 建立一个抽象让另一组 Pod 找到它。这个抽象在 Kubernetes 中其实就是 Service,每一个 Service 都是一组 Pod 的逻辑集合和访问方式的抽象。即 Service 至少帮我们解决了如下问题:

  • 对外暴露部署的应用
  • 为一组 Pod 提供负载均衡功能
  • 监控 Pod 中启动容器的健康状况,不健康则踢除
  • 将服务名注册到 DNS 中去

Pods to Pods

如何暴露 Service

Kubernetes 中的 Service 对象将一组 Pod 以统一的形式对外暴露成一个服务,它利用运行在内核空间的 iptables 或 ipvs 高效地转发来自节点内部和外部的流量。

Pods to Service

对于每一个 Service,会在节点上添加 iptables 规则,通过 iptables 或 ipvs 将流量转发到后端的 Pod 进行处理。

Service

在集群的内部我们可以通过这个 ClusterIP 访问这组 Pod 提供的服务,那如何在集群外部访问这个服务呢?这里最常用的一种方式就是:NodePort。在这个 Service 的定义里,通过声明它的类型为 type=NodePort。当我们配置了 NodePort 这种服务类型后,Kubernetes 会在每个物理节点上生成 iptables 规则,将相应端口的流量导入到集群内部,这样我们就可以在集群外部访问到这个服务了。另外一种类型叫 LoadBalancer,这个适用于公有云上的 Kubernetes 对外暴露服务。

NodePort

服务发现

我们通过 Service 这个抽象对外暴露服务,但还有一个问题,在 Kubernetes 集群中,A 服务访问 B 服务,如果 B 服务是一个还未部署的服务,这时,我们是不知道 B 服务的 ClusterIP 是什么的?那我在编写 A 服务的代码时,如何描述 B 服务呢?其实,我们可以给这个服务定义一个名字,当 B 服务部署时自动解析这个名字就可以了。这就是 Kubernetes 内部的服务发现机制。Service 被分配了 ClusterIP 后,还会将自己的服务名注册到 DNS 中,这样其他服务就可以通过这个服务名访问到这个服务了。如果 A、B 两个服务在相同的命名空间,那么他们通过 svc_name 就可以相互访问了(如上例:hello),如果是在不同的命名空间还需要加上命名空间的名字,如 svc_name.namespace(如上例:hello.default),或者使用完整域名去访问,一般是 svc_name.namespace.svc.cluster.local(如上例:hello.default.svc.cluster.local)。

如何配置 Service

部署 Service

  1. kubectl apply -f services/nginx.yaml

获取 Service 的 Endpoint

  1. kubectl get endpoints hello

获取 Service

  1. kubectl get svc hello

访问 Service

  1. minikube ssh
  2. curl https://127.0.0.1:30080

4.2 小结

本章服务发现相关的知识,我向你讲解了为什么需要 Service 这个资源,以及如何将 Service 暴露出来。Service 为服务间的相互访问提供了一个固定的端点,也为多个 Pod 提供了负载均衡能力,并且他能够监控 Pod 内容器的健康状况,当容器出错时将其从负载均衡后面摘除。另外 Service 将服务名注册到 DNS 中,以便其他服务发现此服务。

下一章是一节实践课,我们利用前面学到的知识,将一个微服务部署到 Kubernetes 集群中。