无法通过服务发现使AWS ECS服务进行通信

16
我正在尝试使两个服务通过AWS ECS服务中的服务发现端点进行通信。
例如: Service1:运行任务定义以运行nginx和phpfpm Service2:运行任务定义以运行redis
现在,我需要让service1容器与service2容器通信。 根据文档和互联网上找到的资源,这就是我所做的事情,但无法实现需求。
我们需要打开服务发现(完成), 设置适当的服务名称和命名空间作为服务发现端点(完成), 创建任务定义并使用上述属性创建服务(完成), 现在AWS将在Route53上生成SRV记录(OK)。
现在,当使用服务发现端点时,通常格式为“service_discovery_service_name.service_discovery_namespace”。 错误日志显示它无法解析名称。

enter image description here


你需要在Route53中创建DNS Type A记录,而不是SRV记录,以为每个服务任务分配IP地址。只有当你的通信支持SRV记录查找时,才需要使用SRV记录,即客户端需要知道它需要执行SRV查找,然后获取IP地址。 - Imran
@Imran 是的,但是 AWS ECS 已经内置了这个功能,并且 A 记录也会自动生成,指向实例的 IP 地址。 - Tara Prasad Gurung
2
你在任务定义中使用哪种Docker网络模式?如果你没有使用 awspvc,那么它只会创建 SRV 类型,然后指向 A 类型。当你执行 nslookup myapp.local 时,你将什么也得不到,因为它是 SRV 类型而不是 A类型。当你尝试 nslookup -type=srv myapp.local 时,你将得到SRV列表,然后你可以尝试 nslookup {taskid}.myapp.local 来获取容器的IP地址。除非你的客户端支持执行SRV查找和IP查找,否则最好只创建 A 记录。如果你需要示例,请让我知道,我会发布它作为答案。 - Imran
我的任务定义网络模式是桥接,它正在创建SRV,其中包含任务ID和指向容器IP的A记录。请检查编辑问题部分上传的图像@Imran。 - Tara Prasad Gurung
2
这正是我所说的!你的客户端(Service1)需要知道它需要执行Service2的SRV查找,然后使用SRV结果(端口和主机名)进行通信。例如- 如果您的Service1是nginx,则[premium](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#service)版本的nginx [支持](https://stackoverflow.com/a/42115019/5030709)此功能。如果您的Service1是`phpfpm`,我不确定它是否支持SRV查找通信。首先[了解](https://anders.com/cms/263/Tutorial/SIP/DNS/SRV/djbdns)“SRV”记录如何不同于“A”类型。 - Imran
@Imran,感谢您让我清楚地了解了我的问题所在。我只需要我的Web服务器(服务=nginx)来解析SRV。看起来在免费的NGINX中不可能实现。接下来您有什么建议或者如果您已经完成了一些工作或者任何我可以参考的东西,请告诉我。非常感谢。 - Tara Prasad Gurung
2个回答

18

更新 03/2022

AWS现在拥有ENI Trunking,可以增加在VPC中给定EC2实例类型可附加的ENIs数量。这使得使用awsvpc模式更加灵活,并使得为ECS服务配置服务发现更加容易。

结合AWS App MeshAWS Cloud Map,您可以使ECS服务发现更加容易。

有关ENI Trunking和App Mesh示例的更多信息,请参见: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/container-instance-eni.html https://github.com/aws/aws-app-mesh-examples/tree/main/walkthroughs/howto-ingress-gateway


原始答案

根据我们的交谈,这是正在发生的事情的简要概述。

  • 如果Service1(在您的情况下是nginx)需要使用AWS ServiceDiscovery选项与Service2redis)进行交互,并使用SRV记录,则Service1需要知道它需要执行DNS SRV查找而不是DNS A(地址)查找。

  • 您有多个选项。首先,如果您想继续使用SRV记录,则您的客户端nginx需要使用serviceresolve选项代理redis上游服务器,这些选项仅在premium版本的nginx中available。请检查我在答案底部测试过的示例nginx配置。

  • 还要确保使用前缀_http._tcp创建AWS服务发现名称,否则,我在没有前缀的情况下配置SRV resolve/service选项时遇到了问题。

aws ecs service

其他选择是,如果您不想依赖{{SRV}}记录而是转到标准的{{A}}记录查找,则必须对容器使用{{awsvpc}}模式并选择{{A}}选项。

enter image description here

  • 如果使用DNS A选项,那么您查询service_discovery_service_name.service_discovery_namespace将正常工作。
  • 使用DNS A选项时,有一些限制。由于每个EC2实例可以附加的ENI数量取决于EC2实例族系,因此您无法在给定的EC2实例上运行多个任务。更新检查03/2022修改如上所述。

示例nginx DNS SRV选项配置:

stream {
    resolver 172.31.0.2;
    upstream redis {
        zone tcp_servers 64k;
        server redisservice.local service=_http._tcp resolve;
    }
    server {
        listen 12345;
        status_zone tcp_server;
        proxy_pass redis;
    }
}

一些参考资料 -

https://aws.amazon.com/blogs/aws/amazon-ecs-service-discovery/ https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-service-discovery.html


如果不使用nginx-plus,我认为可以使用前端服务发现(弹性负载均衡器)来解决这个问题。@Imran - Tara Prasad Gurung
@TaraPrasadGurung 我之前提到的另一个选项也不使用nginx-plus,但它也有其缺点。是的,如果流量不是很高,那么ELB是比nginx-plus更好的选择。附言 - 当您接受答案时,点赞总是很好的。:) - Imran

8

我想更详细地阐述@Imran的答案,因为大部分答案都涉及SRV DNS记录类型,并且仅为Nginx的高级版本(以及SRV)提供示例。

如果您使用ECS Fargate并配置了A DNS记录,则最重要的是配置适当的resolver

从文档中可以了解到:

配置用于将上游服务器的名称解析为地址的名称服务器,例如:

resolver 127.0.0.1 [::1]:5353;

地址可以指定为域名或IP地址,带有可选端口。如果未指定端口,则使用端口53。名称服务器会以轮询方式查询。

在此情况下,解析器必须解析私有DNS。因此,我们需要使用NS DNS记录。 使用8.8.8.8作为解析程序行不通,因为这个DNS无法解析私有DNS。

NS代表'name server',该记录指示哪个DNS服务器对该域具有权威性(即哪个服务器包含实际的DNS记录)。一个域经常会有多个NS记录,可以表示该域的主要和备份名称服务器。

为了获取DNS解析器,请运行以下命令:

aws route53 list-resource-record-sets --hosted-zone-id %HOSTED_ZONE_ID% --query "ResourceRecordSets[?Type == 'NS']"

选择一个资源记录并将其放入Nginx的resolver中(包括尾随的.)。
Nginx基本模板:
events {
  worker_connections 768;
}

http {
  # DNS Resolver
  resolver ns-###.awsdns-####.com. valid=10s;
  gzip on;
  gzip_proxied any;
  gzip_types text/plain application/json;
  gzip_min_length 1000;
  fastcgi_buffers 16 16k; 
  fastcgi_buffer_size 32k;

  server {

    listen 80;
    
    location / {
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host $host;
          proxy_redirect   off;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          # This is the important part
          proxy_pass http://ecs-fargate-svc.local:8080;
    }

    location = /health-check {
      return 200 'all good';
    }

  }
}

需要考虑的几个要点:

  • 不要忘记添加映射端口(在我的示例中为8080)。
  • 确保安全组允许VPC内部的流量。
  • 由于使用Fargate并且我们的日志有限,请考虑在VPC中创建一个EC2实例,该实例位于ECS Fargate任务位置,并尝试使用curl\ping URL\DNS记录。

我的服务发现:

enter image description here

文档:

Nginx resolver

域名服务器(NS)记录


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