AWS Cloud Map 允许您为 VPC 设置一些命名空间,然后将该命名空间中的名称分配给各个服务。名称可以是 A) 只能通过 API 调用私下发现,B) 可通过 API 调用或通过 DNS 在 VPC 内私下发现,或者 C) 可通过公有 DNS 和 API 调用发现。弹性云服务器可以与云地图交互,自动注册服务。所有这些都在 AWS ECS 中称为服务发现。
AWS ECS还有一个相对较新的东西,称为Service Connect。它利用云映射,但也为您的 ECS 服务添加了一个挎斗"代理"容器,从而有效地创建自动服务网格。
我让 Service Connect 使用 CloudFormation 与 ECS 一起工作。在我的 CloudFormationAWS::ECS::Cluster
中,我配置了ServiceConnectDefaults
到我要使用的 Cloud Map 命名空间,例如example.internal
。然后我在ServiceConnectConfiguration
下为AWS::ECS::Service
定义设置了enabled: true
,以及一些额外的细节,例如为服务/端口提供名称。假设我已经将我的服务/端口命名为my-service
,我相信现在在同一 VPC 中使用服务连接的其他一些服务可以连接到my-service.example.internal
并且 sidecar-proxy 会找出要连接的my-service
实例,甚至不使用 DNS!(我还没有测试过;我首先想对当前的问题进行一些澄清。
但是我也想要私有DNS访问,如果没有别的,那就是能够转到Cloud9并发布例如curl my-service.example.internal/api/test
,而无需查找my-service
实例之一的IP地址。我发现我可以定义一个AWS::ServiceDiscovery::PrivateDnsNamespace
和一个AWS::ServiceDiscovery::Service
(使用相同的名称my-service
),甚至可以使用ServiceRegistries
将后者与我的 ECS 服务相关联。但是当我尝试部署我的CloudFormation堆栈时,我收到一个错误:
提供的请求无效:创建服务错误:服务已存在。
我猜在内部为了让服务连接工作,ECS 创建了自己的AWS::ServiceDiscovery::Service
,此时它看到我的 CloudFormation 堆栈已经创建了一个同名AWS::ServiceDiscovery::Service
。但是,如果我不自己创建AWS::ServiceDiscovery::Service
,则 ECS 创建的那个将不会提供my-service
的 DNS 条目。
我是否可以推断 AWS ECS 可以使用 Service Connect(在这种情况下,不会有服务 DNS 条目,但挎斗代理将使用 API 调用来查找已注册的服务)或服务发现(其中我手动创建云映射 DNS 条目,ECS 将根据我与 ECS 服务关联的AWS::ServiceDiscovery::Service
自动注册它们), 但不能同时两者?还是我配置不正确?
我想如果我使用服务发现并获取 DNS 条目,我可以简单地指示其他服务中的(在我的情况下是私有的)DNS 条目,它们将通过 Cloud Map 找到它们,为我提供与 Service Connect 相同的功能,而无需挎斗代理。但是,也许服务连接具有一些额外的监视功能,我将失去?
有人可以确认这是否是一种正确的理解,并详细说明将服务连接或服务发现与 ECS 一起使用之间的实际差异和含义吗?
Service Connect 使用普通云映射带来的服务发现的好处是,当服务实例出现故障时,故障转移速度更快。将基于 DNS 的查找与云映射结合使用意味着当服务出现故障时,客户端可能需要一段时间(基于 TTL 设置)才能意识到它应该获取新的 IP 地址。更糟糕的是,客户端库可能会将相同的 IP 地址缓存更长时间,并且/或客户端的重试逻辑可能会在失败时继续尝试相同的 IP 地址。
另一方面,服务连接引入了一个挎斗"代理"容器,该容器拦截传出连接并将其路由到正确的目标。挎斗使用对 Cloud Map 的 API 调用来实时查找服务正常实例的 IP 地址,而不是依赖于可能过时的 DNS 条目。这带来了 Envoy 等服务网格的标准优势,但在本例中,Service Connect 为您管理挎斗。有关这些优势的更多讨论,请参阅将现有 Amazon ECS 服务从服务发现迁移到 Amazon ECS Service Connect。
由于服务连接不依赖于 DNS,因此它甚至不会费心注册私有 DNS 条目,而是向 Cloud Map 注册只能通过 API 调用私下发现的终结点。似乎没有办法告诉服务连接在DNS中注册服务名称。
您不能同时对同一服务名称同时使用服务连接和服务发现,因为如问题中所述,服务连接和服务发现都将尝试向 Cloud Map 注册相同的服务名称。但是,您可以使用两个不同的服务名称将它们一起使用!如果您使用服务/端口发现名称(如my-service-connect
)定义任务定义端口映射和服务ServiceConnectConfiguration
,并使用命名空间example.internal
指定 ECS 集群ServiceConnectDefaults
,则即使没有该名称的 DNS 条目,您的其他 ECS 服务也可以连接到my-service-connect.example.internal
,如上所述。
但是,您还可以定义AWS::ServiceDiscovery::PrivateDnsNamespace
example.internal
(服务连接将使用该服务连接,而不是创建新服务),以及使用不同服务名称(如my-service
)的AWS::ServiceDiscovery::Service
。将此服务发现与使用ServiceRegistries
的 ECS 服务相关联,您将两全其美!ECS 服务可以使用my-service-connect.example.internal
进行通信,但您仍然可以转到 Cloud9 并通过 DNS 连接到my-service.example.internal
(注意不同的名称),因为 ECS 将确保两者都已注册。不能保证这两种方法在任何特定时间都会引用同一个服务实例,如果服务实例出现故障,则 DNS 方法my-service.example.internal
可能会过时,直到传播新的 DNS 值,但对于 Cloud9 中的临时测试(首先是这样做的动机)这几乎无关紧要。
我发表了一篇博客文章《结合使用 AWS ECS Service Connect and Service Discovery Together》,其中更深入地介绍了如何使其工作,并附有 CloudFormation 模板代码段。