在 VPC 中连接 Amazon ECS 服务的最佳实践 - Amazon Elastic Container Service

在 VPC 中连接 Amazon ECS 服务的最佳实践

在 VPC 中使用 Amazon ECS 任务,您可以将单体应用程序拆分为独立的部分,并在安全的环境中独立部署和扩展这些部分。这种架构称为服务导向型架构(SOA)或微服务。但是,要确保 VPC 内外的所有这些部分都能相互通信,可能具有挑战性。有几种有助于通信的方法,它们的优缺点各不相同。

使用 Service Connect

建议使用 Service Connect,它为服务发现、连接和流量监控提供 Amazon ECS 配置。借助 Service Connect,您的应用程序可以使用短名称和标准端口连接到同一集群中的服务,也可以连接到其他集群(包括同一区域的不同 VPC)中的服务。有关更多信息,请参阅 Amazon ECS Service Connect

当您使用 Service Connect 时,Amazon ECS 会管理服务发现的所有部分:创建可发现的名称,在任务开始和停止时动态管理每个任务的条目,在配置为发现名称的每个任务中运行代理。您的应用程序可以通过使用 DNS 名称的标准功能,并建立连接来查找这些名称。如果您的应用程序已执行此操作,则您无需修改应用程序即可使用 Service Connect。

图中显示了使用 Service Connect 的网络架构。
更改仅在部署期间发生

您在每项服务和任务定义中都提供完整的配置。Amazon ECS 在每个服务部署中管理对该配置的更改,以确保部署中的所有任务以相同的方式运行。例如,DNS 作为服务发现的一个常见问题是控制迁移。如果您将 DNS 名称更改为指向新的替换 IP 地址,则在所有客户端开始使用新服务之前,可能需要最大的 TTL 时间。使用 Service Connect,客户端部署将通过替换客户端任务来更新配置。您可以像配置任何其他部署一样配置部署断路器和其他部署配置,以对 Service Connect 更改造成影响。

使用服务发现

服务间通信的另一种方法是使用服务发现进行直接通信。在这种方法中,您可以使用与 Amazon ECS 的 AWS Cloud Map 服务发现集成。使用服务发现,Amazon ECS 将已启动的任务列表同步到 AWS Cloud Map,后者将维护一个 DNS 主机名,该主机名解析为来自该特定服务的一个或多个任务的内部 IP 地址。Amazon VPC 中的其他服务可以使用此 DNS 主机名,以通过其内部 IP 地址将流量直接发送到另一个容器。有关更多信息,请参阅服务发现

图中显示了使用服务发现的网络架构。

在上图中有三个服务。service-a-local 有一个容器并与 service-b-local 通信,后者有两个容器。service-b-local 还必须与 service-c-local 通信,后者只有一个容器。所有这三个服务中的每个容器都可以使用 AWS Cloud Map 中的内部 DNS 名称,从容器需要与之通信的下游服务中查找容器的内部 IP 地址。

这种服务间的通信方法可实现低延迟。乍一看,这也很简单,因为容器之间没有额外的组件。流量直接从一个容器传递到另一个容器。

这种方法适用于使用 awsvpc 网络模式时,在这种模式下,每项任务都有自己唯一的 IP 地址。大多数软件仅支持使用 DNS A 记录,这些记录可直接解析为 IP 地址。使用 awsvpc 网络模式时,每项任务的 IP 地址都是一个 A 记录。但是,如果您使用 bridge 网络模式,则多个容器可能会共享相同的 IP 地址。此外,动态端口映射会导致容器在该单个 IP 地址上被随机分配端口号。此时,A 记录已不足以进行服务发现。您还必须使用 SRV 记录。这种类型的记录可以同时跟踪 IP 地址和端口号,但需要您相应地配置应用程序。您使用的某些预建应用程序可能不支持 SRV 记录。

awsvpc 网络模式的另一个优点是,您的每项服务都有一个唯一的安全组。您可以将此安全组配置为只允许来自需要与该服务通信的特定上游服务的传入连接。

使用服务发现进行服务间直接通信的主要缺点是,您必须实现额外的逻辑才能进行重试和处理连接失败。DNS 记录具有生存时间(TTL),可控制其缓存时长。更新 DNS 记录和缓存过期需要一些时间,这样您的应用程序可以获取 DNS 记录的最新版本。因此,您的应用程序最终可能会将 DNS 记录解析为指向另一个不再存在的容器。您的应用程序需要处理重试,并具有忽略不良后端的逻辑。

使用内部负载均衡器

另一种服务到服务的通信方法是使用内部负载均衡器。内部负载均衡器完全存在于您的 VPC 内部,并且只能由位于您 VPC 内部的服务访问。

图中显示了使用内部负载均衡器的网络架构。

负载均衡器通过将冗余资源部署到每个子网来保持高可用性。当来自 serviceA 的容器需要与来自 serviceB 的容器通信时,它会打开与负载均衡器的连接。然后,负载均衡器会从 service B 打开与容器的连接。负载均衡器可作为集中位置来管理每个服务之间的所有连接。

如果来自 serviceB 的容器停止,则负载均衡器可以将该容器从池中移除。负载均衡器还会对其池中的每个下游目标进行运行状况检查,并可以自动将不良目标从池中移除,直到它们恢复正常运行。应用程序不再需要知道有多少下游容器。应用程序只向负载均衡器打开其连接。

这种方法对所有网络模式都有利。使用 awsvpc 网络模式时,负载均衡器可以跟踪任务 IP 地址,在使用 bridge 网络模式时还可以跟踪更高级的 IP 地址和端口组合。负载均衡器可以在所有 IP 地址和端口组合之间均匀分配流量,即使多个容器实际上托管在同一 Amazon EC2 实例上(只是在不同的端口上)也是如此。

这种方法的一个缺点是成本。为了实现高可用性,负载均衡器需要在每个可用区中都有资源。这就增加了额外成本,因为针对负载均衡器和流经负载均衡器的流量付费会导致出现开销。

但是,您可以通过让多个服务共享一个负载均衡器来降低开销成本。对于使用应用程序负载均衡器的 REST 服务而言,该方法尤其适用。您可以创建将流量路由到不同服务的基于路径的路由规则。例如,/api/user/* 可能路由到作为 user 服务一部分的容器,而 /api/order/* 可能路由到关联的 order 服务。使用这种方法,您只需为一个应用程序负载均衡器付费,而您的 API 将拥有一致的 URL。但是,您可以将流量拆分至后端的各项微服务。