无负载均衡时VPC内ECS结合AWS ServiceDiscovery通信问题
AWS ECS EC2服务通过CloudMap VPC DNS实现VPC内通信问题排查与解决方案
问题背景
已通过AWS CDK完成以下部署:
- 创建VPC
self.vpc = ec2.Vpc( self, "rcs-vpc", vpc_name="rcs-vpc", max_azs=2, ip_addresses=ec2.IpAddresses.cidr("10.180.0.0/16"), subnet_configuration=[ ec2.SubnetConfiguration( subnet_type=ec2.SubnetType.PUBLIC, name="public", cidr_mask=24 ), ec2.SubnetConfiguration( subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS, name="private", cidr_mask=24 ) ], nat_gateway_provider=ec2.NatProvider.gateway(), nat_gateways=1 )
- 在VPC内创建PrivateDNSNamespace
self.rcs_sd_namespace = servicediscovery.PrivateDnsNamespace( self, "rcs-sd-private-namespace", name="rcs.internal", vpc=vpc_stack.vpc )
- 创建ECS EC2集群
self.ecs_cluster = ecs.Cluster( self, "rcs-ecs-cluster", cluster_name="rcs-cluster", vpc=vpc_stack.vpc )
- 部署EC2类型的ECS容器服务并配置CloudMap(A记录关联PrivateDNSNamespace)
from aws_cdk import CfnOutput, Stack, Duration, Lazy import aws_cdk.aws_ec2 as ec2 import aws_cdk.aws_elasticloadbalancingv2 as elbv2 import aws_cdk.aws_ecs as ecs import aws_cdk.aws_ecr as ecr import aws_cdk.aws_ssm as ssm import aws_cdk.aws_servicediscovery as servicediscovery from constructs import Construct class DSERootStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) self.rcs_sd_namespace = servicediscovery.PrivateDnsNamespace.from_private_dns_namespace_attributes( self, "rcs-sd-namespace", namespace_arn=ssm.StringParameter.value_from_lookup(self, parameter_name="rcs-sd-namespace-arn"), namespace_id=ssm.StringParameter.value_from_lookup(self, parameter_name="rcs-sd-namespace-id"), namespace_name=ssm.StringParameter.value_from_lookup(self, parameter_name="rcs-sd-namespace-name") ) self.dse_vpc = ec2.Vpc.from_lookup( self, "dse_vpc", vpc_id=ssm.StringParameter.value_from_lookup(self, parameter_name="rcs-vpc-id") ) self.dse_security_group = ec2.SecurityGroup( self, "dse-security-group", security_group_name="dse-security-group", vpc=self.dse_vpc, description="Allow access to DSE", allow_all_outbound=True, disable_inline_rules=False ) self.dse_security_group.add_ingress_rule( peer=ec2.Peer.any_ipv4(), connection=ec2.Port.all_traffic() ) self.dse_security_group.add_egress_rule( peer=ec2.Peer.any_ipv4(), connection=ec2.Port.all_traffic() ) self.dse_task_definition = ecs.TaskDefinition( self, "dse-task-definition", compatibility=ecs.Compatibility.EC2, network_mode=ecs.NetworkMode.AWS_VPC ) self.dse_container = self.dse_task_definition.add_container( "dse-container", image=ecs.ContainerImage.from_ecr_repository( ecr.Repository.from_repository_name( self, "enter", repository_name="test" ) ), memory_limit_mib=512, port_mappings=[ ecs.PortMapping( name="http_port_mapping", container_port=8000 ) ], logging=ecs.AwsLogDriver.aws_logs( mode=ecs.AwsLogDriverMode.NON_BLOCKING, stream_prefix="TEST" ) ) self.dse_service = ecs.Ec2Service( self, "dse-service", service_name="dse-service", assign_public_ip=False, cluster=ecs.Cluster.from_cluster_attributes( self, "dse-cluster", cluster_name=ssm.StringParameter.from_string_parameter_name(self, "rcs-cluster-name", string_parameter_name="rcs-cluster-name").string_value, vpc=self.dse_vpc ), cloud_map_options=ecs.CloudMapOptions( cloud_map_namespace=self.rcs_sd_namespace, name="dse", container=self.dse_container, container_port=8000, dns_record_type=servicediscovery.DnsRecordType.A, dns_ttl=Duration.seconds(10) ), security_groups=[ self.dse_security_group ], task_definition=self.dse_task_definition )
当前问题
ECS Agent API和CloudMap返回的容器IP一致,但从其他容器执行wget dse.rcs.internal:8000提示连接拒绝,堡垒主机也无法ping通该服务。
需求
希望该容器服务能与VPC内的其他实例、其他容器服务以及Lambda函数通信,询问是否可以不使用负载均衡,仅通过ServiceDiscovery的VPC内部DNS实现。
核心问题解答
完全可以。CloudMap的Private DNS Namespace就是为VPC内部服务发现设计的,无需负载均衡,就能让VPC内的EC2实例、ECS服务、VPC专属Lambda通过服务域名(如dse.rcs.internal)直接访问目标ECS服务。
连接失败的原因排查与修复步骤
1. 安全组规则的隐性限制
虽然你为任务配置的dse-security-group允许所有IPv4流量,但需注意以下几点:
- ECS集群EC2实例的安全组:需要允许与任务ENI的通信(VPC CIDR
10.180.0.0/16的TCP 8000端口、ICMP协议),因为任务运行在EC2实例上,实例安全组会过滤进出实例的流量。 - 堡垒主机的安全组:确认其出站规则允许访问目标端口(TCP 8000)和ICMP协议,即使任务安全组允许所有入站,堡垒主机自身的出站限制也会导致连接失败。
2. 容器应用的监听地址问题
检查容器内的应用是否监听在0.0.0.0而非127.0.0.1:
- 进入容器执行命令:
netstat -tulpn - 如果应用仅绑定localhost,外部(包括VPC内其他节点)无法访问容器端口,需修改应用配置为监听所有网卡。
3. VPC DNS解析配置
确保VPC的DHCP选项集使用默认的AmazonProvidedDNS:
- 进入VPC控制台,查看目标VPC的DHCP选项集,确认域名服务器配置为
AmazonProvidedDNS,否则VPC内的节点无法解析CloudMap私有域名。
4. ECS任务网络模式的细节验证
使用AWS_VPC网络模式时,任务拥有独立ENI,需确认:
- 任务所在私有子网有足够的可用IP地址分配给ENI
- 子网路由表允许VPC内流量互通(私有子网默认路由到NAT网关,但VPC内的区域间流量无需经过NAT,只要安全组允许即可正常通信)
验证步骤
- 从堡垒主机执行
nslookup dse.rcs.internal,确认返回的IP与ECS Agent API返回的任务IP一致 - 执行
telnet dse.rcs.internal 8000,若能连通说明端口访问正常 - 从同VPC内的其他ECS容器或EC2实例重复上述验证操作
内容的提问来源于stack exchange,提问作者Zu Jiry
相关产品推荐
相关产品推荐

