我有一个场景,我必须在 AWS ECS 上部署多个微服务。我想让服务能够通过在每个微服务中开发的 API 相互通信。我也想在 AWS ECS 上部署前端,可以公开访问,也可以与部署在 AWS ECS 上的其他微服务进行通信。我怎样才能做到这一点?我可以通过将所有服务放在私有子网中来启用它们之间的通信来使用 AWS ECS 服务发现吗?我是否可以使用 Elastic Load Balancer 使最终用户只能通过 HTTP/HTTPS 协议通过 Internet 访问前端微服务,同时将其保留在私有子网中?
3 回答
AWS 负载均衡器(用于公共访问)和 Amazon ECS 服务发现(用于内部通信)的组合是 Web 应用程序的完美选择。
ECS 中的内置服务发现是另一个功能,可以轻松开发动态容器环境,而无需在应用程序之外管理尽可能多的资源。ECS 和 Route 53 相结合,提供高度可用、完全托管和安全的服务发现
服务发现是一种使用容器直接 IP 地址从一个容器获取流量到另一个容器的技术,而不是像负载均衡器这样的中介。它适用于各种用例:
- 私有的内部服务发现
- 服务之间的低延迟通信
- 长期存在的双向连接,例如 gRPC。
是的,您可以使用AWS ECS 服务发现 将所有服务都放在一个私有子网中,以实现它们之间的通信。
这使得 ECS 服务可以在 Amazon Route 53 中使用可预测且友好的 DNS 名称自动注册自己。当您的服务根据负载或容器运行状况进行扩展或缩减时,Route 53 托管区域会保持最新,允许其他服务根据每个服务的状态查找它们需要建立连接的位置。
是的,您可以使用负载均衡器使最终用户可以通过 Internet 访问前端微服务。您可以查看此图,该图显示了 ECS 中 Web 应用程序的 AWS LB 和服务发现。
您可以看到位于私有子网中的后端容器,通过 ALB 服务公共请求,而容器的其余部分使用 AWS 服务发现。
Amazon ECS 服务发现
让我们启动一个带有服务发现的应用程序!首先,我将创建两个任务定义:“flask-backend”和“flask-worker”。两者都是简单的 AWS Fargate 任务,使用单个容器服务 HTTP 请求。我将让烧瓶后端要求 worker.corp 做一些工作,然后我将返回响应以及 Route 53 为工人返回的地址。类似于下面的代码:
@app.route("/")
namespace = os.getenv("namespace")
worker_host = "worker" + namespace
def backend():
r = requests.get("http://"+worker_host)
worker = socket.gethostbyname(worker_host)
return "Worker Message: {]\nFrom: {}".format(r.content, worker)
请注意,在这个私有架构中没有公共子网,只有一个私有子网。子网内的容器可以使用它们的内部 IP 地址相互通信。但是他们需要某种方式来发现彼此的 IP 地址。
AWS 服务发现提供两种方法:
- 基于 DNS(Route 53 创建并维护一个自定义 DNS 名称,该名称解析为其他容器的一个或多个 IP 地址,例如http://nginx.service.production然后其他容器只需打开连接即可将流量发送到目的地使用此 DNS 名称)
- 基于 API(容器可以查询 API 以获取可用的 IP 地址目标列表,然后直接打开与另一个容器之一的连接。)
您可以在此处阅读有关 AWS 服务发现和使用案例amazon-ecs-service-discovery 的 更多信息
我也想在 AWS ECS 上部署前端,可以公开访问,也可以与部署在 AWS ECS 上的其他微服务进行通信。
我将使用 Service Discovery 在内部连接服务,并使用 Elastic Load Balancer 集成使公众可以访问它们。
负载平衡器可以在一侧进行负载平衡,DNS SRV 记录可以在内部为您的 API 进行负载平衡。
Stack Overflow 上有一个类似的问题,其答案 [1] 概述了使用负载均衡器和 ECS 中的服务发现集成的可能解决方案。
我是否可以使用 Elastic Load Balancer 使最终用户只能通过 HTTP/HTTPS 协议通过 Internet 访问前端微服务,同时将其保留在私有子网中?
是的,负载均衡器可以在私有子网中注册目标。
参考
根据文档,“Amazon ECS 不支持将服务注册到公共 DNS 命名空间”
换句话说,当它注册 DNS 时,它只使用服务的私有IP 地址,这可能会出现问题。“公共”服务的 DNS 将注册到专用 IP 地址,例如,如果您在专用网络上的 VPN 上,则无论您的子网规则是什么,该地址都有效。
我认为更好的解决方案是将服务附加到两个负载均衡器之一……一个面向互联网,一个面向内部。我认为这更自然地用于扩展服务。服务发现很酷,但实际上更多的是用于服务相互通信,而不是用于外部客户端。