如何使用服务名称访问Kubernetes集群中的服务。

19
我对 Kubernetes 还不太熟悉,但我已经在 Google 容器引擎上成功搭建了一个集群。在我的集群中,我有一个使用 Dropwizard 开发的后端 API,使用 Node.js 开发的前端以及一个 MySQL 数据库。所有内容都已部署到了集群上并且运行良好。但我的挑战是:在为我的节点容器和后端设置外部 IP 后,我可以通过远程访问它们,但我无法通过服务名称在前端访问后端,例如我的后端名称为 backendapi。当我将其部署到集群上时,我不能使用 http://backendapi:8080 来调用我的 REST 服务。 对我来说,关键在于当我部署到集群时,我不希望我的前端使用外部 IP 访问后端,而是希望它们在集群内部连接,而不需要经过外部 IP 地址。当我连接到一个 Pod 并 ping backendapi 就会返回结果,但当我部署我的前端并使用标签名称时,它就无法正常工作。我可能做错了什么?
2个回答

33
只要 kube-dns 在运行(我相信默认是一直在运行除非你禁用它),所有 Service 对象都有一个内部集群的 DNS 名称,格式为 service_name +"."+ service_namespace + ".svc.cluster.local"。因此,其他任何东西都可以通过这个名称来访问位于 default 命名空间下的 backendapi(以您端口编号的示例): http://backendapi.default.svc.cluster.local:8080。正因为此原因,Kubernetes 强制所有标识符都必须是“DNS 兼容”名称(没有下划线或其他怪异字符)。
即使您没有运行 kube-dns,所有 Service 的名称和端口也会像 Docker 一样注入到 Pod 的环境中,所以环境变量 ${BACKENDAPI_SERVICE_HOST}:${BACKENDAPI_SERVICE_PORT} 将包含 Service 的集群内 IP(即使 env-var 的名称为 “host”)和 "default" Service 端口(如果只有一个,则为 8080,就像您的示例一样)。
无论您选择使用 DNS 名称还是环境变量 IP,都取决于您是喜欢在日志输出或错误消息中拥有“可读性”的名称,还是喜欢跳过 DNS 查找并使用 Service IP 地址来提高速度但降低可读性。它们的行为相同。
完整的解释在 services-networking 概念文档中

感谢您的回复,我非常感激。但是当我更改为此http://backendapi.default.svc.cluster.local:8080时,问题仍然存在,我甚至尝试使用其内部映射到的其他端口,但我的前端网页仍然显示http://backendapi.default.svc.cluster.local:32208/api/v1/auth/login net :: ERR_NAME_NOT_RESOLVED。有趣的是,当我从我的前端Pod进行curl时,它可以工作。但是当我使用Web浏览器访问它时,它不起作用。 - I.Tyger
这可能是因为我也暴露了服务的外部IP。不过外部IP是可以工作的。 - I.Tyger
3
感谢您的帮助回复以及提供文档链接。我在文档中找到了DNS部分,其中提到即使使用更短的DNS名称http://service-name.namespace,服务也可以在集群内访问。因此,对于我们的示例,它将是http://backendapi.default - Jacek J

7
但是,当我改用这个backendapi.default.svc.cluster.local:8080时,问题仍然存在。 我甚至尝试使用其内部映射到的另一个端口,但我的前端网页仍然说backendapi.default.svc.cluster.local:32208/api/v1/auth/login net :: ERR_NAME_NOT_RESOLVED。有趣的是,当我从我的前端pod进行卷曲时,它可以工作。 但是,当我使用网络浏览器访问时,它就不行了。
因为它只能在集群内解析。 (因为只有带有kube-dns插件的K8s集群才能将域名backendapi.default.svc.cluster.local:8080转换为相应的IP地址)
这可能是因为我也为服务公开了外部IP吗? 不,这是因为域名backendapi.default.svc.cluster.local只能在集群内解析,而不是从随机机器上的随机浏览器中解析。
解决方案
你所做的是其中一种解决方案,即为服务公开外部IP。 如果您不想使用该IP,则可以创建入口(并在集群中使用入口控制器)并公开您的微服务。 由于您在GCP上,因此可以利用其API网关,而不是公开加密的IP地址。
注意:请记住添加身份验证/授权以锁定您的微服务,因为它正在向用户公开。
另一个解决方案
通过为Web应用程序提供服务的服务器(nginx / nodejs等)代理所有后端调用
这种方法的优点是,您将避免所有同源策略/ CORS头痛,您的微服务(express)身份验证详细信息将从用户浏览器中抽象出来。 (这不一定是优势)。
这种方法的缺点是,您的后端微服务将与前端紧密耦合(或反之亦然,具体取决于您的看法),这将使后端扩展取决于前端。 您的后端未公开。 因此,如果您有另一个消费者(假设是Android应用程序),它将无法访问您的服务。
混合解决方案
通过为 Web 应用程序提供服务的服务器(如 nginx / nodejs 等)代理所有后端调用,以便您的 API 将继承您的 Web 应用程序域。并在需要时仍然公开后端服务(以便其他消费者(如果有)可以使用它)。
类似问题:https://stackoverflow.com/a/47043871/6785908

谢谢,我会尝试其他选项。我一直以为前端可以使用集群IP地址看到后端在集群中的情况。 - I.Tyger
非常感谢。真的很感激。 - I.Tyger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接