使用PublicDnsNamespace配置Fargate服务CloudMap遇问题求助
问题背景
我正尝试搭建一组需互相通信的Fargate服务,其中一个通过负载均衡器对外开放。当前使用PublicDnsNamespace,通过FargateService的cloudMapOptions关联到服务。使用的是另一个账号的VPC(无法修改但拥有子网权限),域名是另一个账号HostedZone的子域,且具备该域的委托角色。
PublicDnsNamespace和FargateServices均已正常启动,但服务无法解析任何主机名,推测原因是PublicDnsNamespace创建的HostedZone的域名服务器未配置到父账号的HostedZone中。
尝试使用CrossAccountZoneDelegationRecord创建NS记录时,出现如下错误:
(internalzonedelegationCrossAccountZoneDelegationCustomResource3DD11448) Received response status [FAILED] from custom resource. Message returned: TypeError: Cannot read properties of undefined (reading 'map') at r (/var/task/index.js:1:1466) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Runtime.handler (/var/task/__entrypoint__.js:1:952) (RequestId: 570780ca-f06e-459b-bcd1-b1df2928ff9b)
经排查,错误由传入CrossAccountZoneDelegation lambda函数的HostedZone域名服务器为null导致。基础栈代码如下:
export class Stack extends cdk.Stack { constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); /* Create a PublicDnsNamespace and delegate its created HostedZone * to the parent internal domain name using the delegation role*/ const dnsNamespace = new serviceDiscovery.PublicDnsNamespace(this, 'namespace', { name: props.internalDomainName, }); if (props.internalDelegationRoleArn) { const internalDelegationRole = iam.Role.fromRoleArn(this, 'internal-zone-delegationRole', props.internalDelegationRoleArn); new r53.CrossAccountZoneDelegationRecord(this, 'internal-zone-delegation', { delegatedZone: r53.HostedZone.fromHostedZoneAttributes(this, 'internal-zone', { hostedZoneId: dnsNamespace.namespaceHostedZoneId, zoneName: props.internalDomainName }), parentHostedZoneName: props.internalParentDomainName, delegationRole: internalDelegationRole, }); } const vpc = ec2.Vpc.fromLookup(this, 'apps-vpc', { vpcName: 'apps-vpc', }); const cluster = new ecs.Cluster(this, 'cluster', { vpc: vpc, }); // Test service const testTask = new ecs.FargateTaskDefinition(this, 'test-task', { memoryLimitMiB: 512, cpu: 256, }); testTask.addContainer('test-container', { image: ecs.ContainerImage.fromRegistry('alpine'), command: ['sh', '-c', `while true; do wget -O - http://service.${dnsNamespace.namespaceName}/healthCheck; sleep 60; done`], logging: new ecs.AwsLogDriver({ logGroup: loggingGroup, streamPrefix: 'test-container', }), }); new ecs.FargateService(this, 'test-service', { cluster: cluster, taskDefinition: testTask, assignPublicIp: true, desiredCount: 1, vpcSubnets: props.subnetFilter, cloudMapOptions: { name: 'test-service', cloudMapNamespace: dnsNamespace, dnsRecordType: serviceDiscovery.DnsRecordType.A, }, }); } }
问题解答
1. 如何解决上述错误?
错误根源在于使用r53.HostedZone.fromHostedZoneAttributes导入托管区时,仅传入了hostedZoneId和zoneName,未提供nameServers参数,导致CrossAccountZoneDelegationRecord的自定义资源无法获取域名服务器列表,触发map操作的未定义错误。
修复方法很简单:直接使用PublicDnsNamespace实例自带的hostedZone属性作为delegatedZone参数。因为该属性是CDK自动关联的托管区对象,包含了完整的域名服务器信息,无需手动导入。
修改后的代码片段:
if (props.internalDelegationRoleArn) { const internalDelegationRole = iam.Role.fromRoleArn(this, 'internal-zone-delegationRole', props.internalDelegationRoleArn); new r53.CrossAccountZoneDelegationRecord(this, 'internal-zone-delegation', { delegatedZone: dnsNamespace.hostedZone, // 直接使用namespace创建的HostedZone对象 parentHostedZoneName: props.internalParentDomainName, delegationRole: internalDelegationRole, }); }
2. 这种实现Fargate服务间发现与通信的方式是否为最优方案?
当前方案并非最优,需根据服务的访问范围调整:
当前方案的优缺点
- 优点:利用Cloud Map自动注册Fargate实例,简化服务发现配置;跨账号DNS委托实现子域的独立管理,适合需要公网可访问的服务。
- 缺点:
PublicDnsNamespace会将服务DNS记录暴露到公网,若服务仅需VPC内部通信,存在不必要的安全风险;跨账号DNS委托需要额外的权限配置,且依赖Route53的跨账号操作逻辑。
更优方案建议
- 内部服务优先用PrivateDnsNamespace:如果服务仅需在VPC内部通信,改用
PrivateDnsNamespace并关联目标VPC,这样DNS记录仅在指定VPC内可解析,安全性更高。示例代码:
跨账号访问可通过RAM共享Private HostedZone,或配置VPC peering并关联托管区实现。const dnsNamespace = new serviceDiscovery.PrivateDnsNamespace(this, 'namespace', { name: props.internalDomainName, vpc: vpc, // 关联到目标VPC }); - 公网服务需强化安全:若必须使用
PublicDnsNamespace,需确保父域NS记录委托配置正确,同时通过Fargate安全组限制仅允许必要的IP或服务访问,避免公网暴露带来的风险。 - 服务间通信优化:无需对外暴露的服务,尽量使用VPC内部的服务发现机制,减少公网DNS解析的开销和安全隐患。
内容的提问来源于stack exchange,提问作者bytesnz

