AWS CDK:如何从Route53定位API Gateway API

13
我已经在AWS Route53注册了一个现有的域名,并在API Gateway中设置了自定义域名。在控制台中,我可以配置xxxxxx.zenxxxxxxfoundry.com从外部实际到达API Gateway API,然后通过我的Lambda函数。
现在,我想使用AWS CDK实现这一点。
我尝试了以下操作:
    const zone = route53.HostedZone.fromHostedZoneId(this, 'ZenithWebFoundryZone', 'ZXXXXXX04V8134');
    new route53.AliasRecord(this, 'BlogAPIRecord', {
      zone: zone,
      recordName: 'xxxxxx.zenxxxxxxfoundry.com',
      target: {
        bind: (): route53.AliasRecordTargetProps => ({
          dnsName: 'd-xxxxxxy00g.execute-api.ap-southeast-2.amazonaws.com',
          hostedZoneId: 'ZXXXXXX04V8134'
        })
      }
    });

在执行命令npm run build时一切正常,但是当我运行cdk synth命令时,出现了一个相当晦涩的错误:

$ cdk synth
HostedZone.fromHostedZoneId doesn't support "zoneName"
Subprocess exited with error 1

打开--trace并没有起到太大的帮助作用:附加信息如下:

Error: Subprocess exited with error 1
    at ChildProcess.proc.on.code (/Users/mikecoxon/.npm-packages/lib/node_modules/aws-cdk/lib/api/cxapp/exec.ts:108:23)
    at ChildProcess.emit (events.js:189:13)
    at ChildProcess.EventEmitter.emit (domain.js:441:20)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)

我已经查看了整个堆栈脚本,没有任何关于zoneName的引用。有人知道这个错误是从哪里来的吗?


1
“ZenithWebFoundryZone”是您在“fromHostedZoneId”方法中传递的区域名称吗?文档说明“fromHostedZoneId”的第二个参数是“id”,但没有解释“id”是什么。 - Chetan
不,实际上是第三个参数。对于这些工厂方法,“id”似乎总是第二个参数,并且大多数示例似乎将其表示为正在创建的构造体的某种句柄。但是,大多数示例实际上并没有使用该句柄,因此我假设它在生成的 Cloud Formation 模板中具有某些应用程序。 - Michael Coxon
我参考了这个文档 https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-route53.HostedZone.html ,它来自于 AWS... 根据文档,第三个参数是 hostedZoneId.... 但是没有关于 id 参数的解释。 - Chetan
6个回答

11

我在使用cdk 1.36.1时遇到了同样的问题,通过在ApiGateway中使用新的自定义域名,并结合BasePath Mapping解决了该问题,然后在现有托管区域的route53中添加了一个CName记录,将其指向新的自定义域名:

import {BasePathMapping, DomainName, EndpointType, LambdaRestApi} from '@aws-cdk/aws-apigateway';
import {Certificate} from '@aws-cdk/aws-certificatemanager';
import {HostedZone, CnameRecord} from '@aws-cdk/aws-route53'

// First create a custom domain:
const customDomain = new DomainName(this, 'customDomain', {
      domainName: 'api.xxxxxxx.com',
      certificate: Certificate.fromCertificateArn(this, 'ACM_Certificate', ACM_CERTIFICATE_ARN),
      endpointType: EndpointType.EDGE
});

// create a new ApiGateway instance and associate a lambda function with it:
const api = new LambdaRestApi(this, 'MainGatewayEndpoint', {
      handler: toyFunction,
});

// Associate the Custom domain that we created with new APIGateway using BasePathMapping:
new BasePathMapping(this, 'CustomBasePathMapping', {
      domainName: custom,
      restApi: api
});

// Get a reference to AN EXISTING hosted zone using the HOSTED_ZONE_ID. You can get this from route53
const hostedZone = HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
      hostedZoneId: PROD_HOSTED_ZONE_ID,
      zoneName: 'xxxxxxx.com'
});

// Finally, add a CName record in the hosted zone with a value of the new custom domain that was created above:
new CnameRecord(this, 'ApiGatewayRecordSet', {
      zone: hostedZone,
      recordName: 'api',
      domainName: customDomain.domainNameAliasDomainName
});


8

使用 aws-cdk v1 应该能够完成以下操作:

const zone = route53.HostedZone.fromHostedZoneAttributes(this, 'ZenithWebFoundryZone', {
  hostedZoneId: 'ZXXXXXX04V8134',
  zoneName: 'zenxxxxxxfoundry.com' // your zone name here
});

new route53.ARecord(this, 'BlogAPIRecord', {
  zone,
  recordName: 'xxxxxx.zenxxxxxxfoundry.com',
  target: route53.RecordTarget.fromAlias({
    bind() {
      return {
        dnsName: 'd-xxxxxxy00g.execute-api.ap-southeast-2.amazonaws.com', // Specify the applicable domain name for your API.,
        hostedZoneId: 'XXXX', // Specify the hosted zone ID for your API.
      };
    },
  }),
});

如果你的API和DNS在同一个stack/code base中,你可以从中获取dnsNamehostedZoneId(它是CF属性)。
否则,请参考DNSNameHostedZoneIdAWS::Route53::RecordSet AliasTarget documentation中的相关信息。
注意:你的别名记录的hostedZoneId和你自己区域的托管区域ID不同。

我正要确认你的建议,但是我现在好像遇到了这个问题(https://github.com/awslabs/aws-cdk/issues/2713),暂时无法执行`cdk synth`。 - Michael Coxon
确认这个有效 - 非常感谢。我在通过npm干净地更新到0.34.0时遇到了很多问题。 - Michael Coxon
我在我的编辑器中看到AddressRecordTarget已被弃用。我还不知道要用什么来替换它 - 如果我找到了,我会在这里更新。 - halfer
@halfer 使用 RecordTarget,已更新答案。 - jogold
谢谢你的编辑。在那之前,我可能有另一个问题 - 我想在CDK中创建一个HostedZone,需要将DNS委派给另一个AWS账户。你不知道如何假定远程账户中设置的角色吗?我找到的所有示例都是使用角色来执行已部署对象中的操作,而不是使用角色来执行部署本身。 - halfer

5
在 AWS CDK 0.36.1 版本中,您可以使用 @aws-cdk/aws-route53-targets 包创建别名。
import { HostedZone, RecordSet, RecordType, RecordTarget } from '@aws-cdk/aws-route53'
import { ApiGatewayDomain } from '@aws-cdk/aws-route53-targets'
import { Certificate } from '@aws-cdk/aws-certificatemanager'

// ...

  const customDomain = new apigateway.DomainName(this, 'CustomDomain', {
    domainName: props.apiDomain,
    certificate: Certificate.fromCertificateArn(this, 'Certificate', props.certificateArn),
    endpointType: apigateway.EndpointType.EDGE,
  })

  const hostedZone = HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
    hostedZoneId: props.hostedZoneId,
    zoneName: props.hostedZoneName,
  })

  new RecordSet(this, 'ApiRecordSetA', {
    zone: hostedZone,
    recordType: RecordType.A,
    recordName: 'api',
    target: RecordTarget.fromAlias(new ApiGatewayDomain(customDomain))
  })

  new RecordSet(this, 'ApiRecordSetAAAA', {
    zone: hostedZone,
    recordType: RecordType.AAAA,
    recordName: 'api',
    target: RecordTarget.fromAlias(new ApiGatewayDomain(customDomain))
  })

2

我成功地让它工作了,但是在 Hosted Zone 名称末尾需要 '.',这一点让我有些意外。

这是针对已经手动创建的现有托管区域,需要通过 CDK 查找并添加别名记录。

const hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
  hostedZoneId: config.apiHostedZoneId,
  name: `${config.apiDomainName}.`,
});

new route53.RecordSet(this, 'ApiRecordSetA', {
  zone: hostedZone,
  recordType: route53.RecordType.A,
  recordName: config.apiDomainName,
  target: route53.RecordTarget.fromAlias(new route53Targets.ApiGatewayDomain(apiDomain))
});

new route53.RecordSet(this, 'ApiRecordSetAAAA', {
  zone: hostedZone,
  recordType: route53.RecordType.AAAA,
  recordName: config.apiDomainName,
  target: route53.RecordTarget.fromAlias(new route53Targets.ApiGatewayDomain(apiDomain))
});

0

在托管区域文档中 - 具体来说是从fromHostedZoneID和fromHostedZoneAttributes方法:

https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-route53.HostedZone.html#static-fromwbrhostedwbrzonewbrattributesscope-id-attrs

它明确提到“通过此查询,托管区域名称变得不可用”

由fromHostedZoneID返回的HostedZone对象没有zoneName属性,因此无法与route53.AliasRecord一起使用-必须使用fromHostedZoneAttributes。为了检索cdk所需的A记录设置信息。

值得注意的是:如果您在API声明中分配域名,则使用(在Python中,因为我手头有)

route53.ARecord(
        self, "DomainAliasLogicalID",
        zone=route53_host_zone,
        target=route53.RecordTarget.from_alias(route53_targets.ApiGateway(your_api_object)),
        record_name=your_domain_name
    )

如果您正在设置自己的域名对象(而不是API网关的一部分),请使用route53_targets.ApiGatewayDomain(your_domain_object)。

0

我使用以下代码时得到了相同的错误:

const zone = route53.HostedZone.fromHostedZoneId(this, 'MyZone', 'ZXXXXXXXXXXXXX');

我在Route53中有一个类似于以下的区域:

Domain Name:    example.com.
Type:           Public Hosted Zone
Hosted Zone ID: ZXXXXXXXXXXXXX

我改成下面这样就可以了(CDK 0.34.0):

const zone = new route53.HostedZoneProvider(this,  {
  domainName: 'example.com',
}).findAndImport(this, 'MyZone');

我一直在思考这件事,只是因为担心它会破坏我当前已经设置并运作良好的托管区域,所以一直没有尝试。也许我应该闭上眼睛试试? - Michael Coxon

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