You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建指向Beanstalk的Route53别名记录报错,求CDK资源创建后执行代码方法

解决方案

核心思路

CDK无法直接通过令牌获取Beanstalk环境的端点URL并用于Route53别名记录,需要借助**CloudFormation自定义资源(Custom Resource)**实现:在Beanstalk环境创建完成后,触发Lambda函数调用AWS API获取真实端点,再自动创建/更新Route53别名记录。

具体实现步骤

1. 编写Lambda处理函数

该函数负责接收CloudFormation事件,获取Beanstalk端点并操作Route53记录:

import { CloudFormationCustomResourceEvent, CloudFormationCustomResourceResponse } from 'aws-lambda';
import { ElasticBeanstalkClient, DescribeEnvironmentsCommand } from '@aws-sdk/client-elastic-beanstalk';
import { Route53Client, ChangeResourceRecordSetsCommand } from '@aws-sdk/client-route-53';

const ebClient = new ElasticBeanstalkClient({});
const route53Client = new Route53Client({});

export const handler = async (event: CloudFormationCustomResourceEvent): Promise<CloudFormationCustomResourceResponse> => {
  try {
    const { environmentName, hostedZoneId, recordName } = event.ResourceProperties;

    // 查询Beanstalk环境端点CNAME
    const ebCmd = new DescribeEnvironmentsCommand({ EnvironmentNames: [environmentName] });
    const ebResp = await ebClient.send(ebCmd);
    const endpointUrl = ebResp.Environments?.[0]?.CNAME;
    if (!endpointUrl) throw new Error('无法获取Beanstalk环境端点');

    // 执行Route53记录操作(创建/更新/删除)
    const route53Cmd = new ChangeResourceRecordSetsCommand({
      HostedZoneId: hostedZoneId,
      ChangeBatch: {
        Changes: [{
          Action: event.RequestType === 'Delete' ? 'DELETE' : 'UPSERT',
          ResourceRecordSet: {
            Name: recordName,
            Type: 'A',
            AliasTarget: {
              HostedZoneId: 'Z117KPS5GTRQ2G', // Beanstalk全局固定Hosted Zone ID
              DNSName: endpointUrl,
              EvaluateTargetHealth: false,
            },
          },
        }],
      },
    });
    await route53Client.send(route53Cmd);

    return {
      Status: 'SUCCESS',
      PhysicalResourceId: recordName,
      StackId: event.StackId,
      RequestId: event.RequestId,
      LogicalResourceId: event.LogicalResourceId,
    };
  } catch (err) {
    console.error('处理失败:', err);
    return {
      Status: 'FAILED',
      Reason: (err as Error).message,
      StackId: event.StackId,
      RequestId: event.RequestId,
      LogicalResourceId: event.LogicalResourceId,
    };
  }
};

2. 在CDK栈中集成自定义资源

将上述Lambda函数和自定义资源加入CDK代码,确保依赖顺序:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as cr from 'aws-cdk-lib/custom-resources';
import * as route53 from 'aws-cdk-lib/aws-route53';
import * as elasticbeanstalk from 'aws-cdk-lib/aws-elasticbeanstalk';

export class EBStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // 引用已有的Hosted Zone
    const hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'MyHostedZone', {
      hostedZoneId: '你的Hosted Zone ID',
      zoneName: 'example.com',
    });

    // 创建Beanstalk环境
    const ebEnv = new elasticbeanstalk.CfnEnvironment(this, 'MyEBEnv', {
      applicationName: '你的EB应用名称',
      solutionStackName: '64bit Amazon Linux 2 v5.8.0 running Node.js 18',
      // 其他Beanstalk配置...
    });

    // 创建处理Lambda
    const updateRoute53Lambda = new lambda.Function(this, 'UpdateRoute53Fn', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromInline(`/* 把上面的Lambda代码粘贴到这里 */`),
      initialPolicy: [
        // 赋予Lambda访问Beanstalk和Route53的权限
        new cdk.aws_iam.PolicyStatement({
          actions: ['elasticbeanstalk:DescribeEnvironments'],
          resources: ['*'],
        }),
        new cdk.aws_iam.PolicyStatement({
          actions: ['route53:ChangeResourceRecordSets'],
          resources: [hostedZone.hostedZoneArn],
        }),
      ],
    });

    // 创建自定义资源,依赖Beanstalk环境
    new cr.CustomResource(this, 'EBRoute53Alias', {
      serviceToken: updateRoute53Lambda.functionArn,
      properties: {
        environmentName: ebEnv.ref,
        hostedZoneId: hostedZone.hostedZoneId,
        recordName: `${config.companyName}-alias.${hostedZone.zoneName}`,
      },
      resourceType: 'Custom::EBRoute53Alias',
    });

    // 确保自定义资源在Beanstalk环境后执行
    this.node.addDependency(ebEnv);
  }
}

关键注意事项

  • Beanstalk别名记录必须使用AWS全局固定的Hosted Zone ID Z117KPS5GTRQ2G,无需根据区域修改。
  • Lambda权限需最小化,可将Beanstalk的资源限定为目标环境的ARN,而非*。
  • 自定义资源会自动处理栈的创建、更新、删除事件,删除栈时会同步删除Route53记录。

内容的提问来源于stack exchange,提问作者Davita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:55:14