在 Kubernetes 集群中,服务发现是一个非常重要的环节。Kubernetes 提供了多种方式来实现服务发现,如 NodePort、LoadBalancer、Ingress 等。本文将以 NodePort 为例,讲解在 Kubernetes 集群上如何解决服务发现问题。
问题描述
假设我们在 Kubernetes 集群上部署了一个简单的应用,其中包含两个 Deployment,分别是 web 和 api。web 服务需要调用 api 服务提供的接口,那么在 Kubernetes 中,我们应该如何实现这种服务发现?
通常,我们可以通过在 Pod 内部使用 Kubernetes 环境变量来实现服务发现。例如,我们可以在 web Pod 中使用以下代码来调用 api:
axios.get(`http://${process.env.API_SERVICE_HOST}:${process.env.API_SERVICE_PORT}/api/user`)
其中,process.env.API_SERVICE_HOST
和 process.env.API_SERVICE_PORT
是 Kubernetes 自动创建的环境变量,分别代表了 api 服务的 IP 和端口。
但是,在部署较大规模的应用时,手动在代码中添加环境变量显然是不现实的,因此需要一种更加自动化的方式来实现服务发现。
解决方案
Kubernetes Service
在 Kubernetes 中,Service 是一种可以封装一个或多个 Pod 的访问逻辑的抽象。通过 Service,我们可以在 Kubernetes 内部创建一个虚拟的服务,而无需关心服务的具体实现。
在上述示例中,我们可以创建一个 Service 来代表 api 服务。首先,我们需要创建一个 api-deployment.yaml 文件,用于定义 api 服务的 Deployment:
-- -------------------- ---- ------- ----------- ------- ----- ---------- --------- ----- --- ----- --------- ------------ ---- --- --------- --------- ------- ---- --- ----- ----------- - ----- --- ------ --- ------ - -------------- ----
然后,我们可以创建一个 api-service.yaml 文件,用于定义 api 服务的 Service:
-- -------------------- ---- ------- ----------- -- ----- ------- --------- ----- --- ----- --------- ---- --- ------ - ----- ---- ----------- ---- ----- -- ----- --------
其中,targetPort
字段代表了 Pod 中实际的端口号,port
字段代表了 Service 对外暴露的端口号,type
字段代表了 Service 的类型,可以是 ClusterIP、NodePort、LoadBalancer 或 ExternalName。在本示例中,我们使用了 NodePort 类型,表示 Service 会暴露一个随机端口给集群的任意节点,可以通过该节点的 IP 地址和端口号来访问 Service。
最后,我们可以创建一个 web-deployment.yaml 文件,用于定义 web 服务的 Deployment:
-- -------------------- ---- ------- ----------- ------- ----- ---------- --------- ----- --- ----- --------- ------------ ---- --- --------- --------- ------- ---- --- ----- ----------- - ----- --- ------ ---
可以看到,与 api 服务相比,web 服务没有暴露任何端口,也没有定义任何环境变量。
Kubernetes Endpoint
为了实现从 web 服务到 api 服务的服务发现,我们还需要创建一个 Endpoint(即 endpoints),用于将 Service 和其对应的 Pod 的 IP 地址和端口号对应起来。
在 Kubernetes 中,Endpoint 是 Service 的一部分,可以通过在 Service 中设置 selector
字段来自动关联 Pod 和 Endpoint。例如,在上述示例中,我们定义了一个 api Service,并通过 selector.app=api
来关联 api Service 和 api Deployment 中的 Pod。Kubernetes 会自动将 api Deployment 中所有标签为 app=api
的 Pod 的 IP 地址和端口号添加到 api Service 的 Endpoint 中,从而实现服务发现。
当 web Pod 需要调用 api 服务时,只需要使用 http://api
即可,Kubernetes 会自动将其转换为 http://api.default.svc.cluster.local
,并通过 Service 和 Endpoint 实现从 web Pod 到 api Pod 的请求转发。
示例代码
上述示例的完整代码可以在 GitHub 上查看:
注意事项
- 在使用 NodePort 类型的 Service 时,一定要注意集群中 NodePort 的使用情况,避免端口冲突;
- 在使用 Ingress 类型的 Service 时,一定要注意 Ingress Controller 的配置,以及 Service 和 Endpoint 的关联;
- 在使用 Service 和 Endpoint 时,一定要注意 Pod 的标签和 Service 的
selector
字段是否匹配。
总结
本文介绍了在 Kubernetes 集群中使用 Service 和 Endpoint 实现服务发现的方法。通过定义 Service 和 Endpoint,我们可以将应用的访问逻辑抽象出来,从而实现更加自动化和智能化的服务发现。在实际应用中,一定要注意端口和标签的使用,以及 Service 和 Endpoint 的关联。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6522159295b1f8cacd973f4d