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

如何使用AWS CDK定义API Gateway的Canary金丝雀发布阶段配置

可行实现方案

方案1:直接使用CDK原生API Gateway金丝雀配置

  • TypeScript CDK的aws-apigateway模块已经原生支持Canary配置,不需要完全拆成两套独立资源,直接在Stage配置项中指定canarySettings即可,示例代码如下:
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    // 正式版本和金丝雀版本的后端处理逻辑,仅差异部分单独定义
    const prodLambda = new lambda.Function(this, 'ProdHandler', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda/prod'),
      environment: { STAGE: 'prod' }
    });
    const canaryLambda = new lambda.Function(this, 'CanaryHandler', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda/canary'), // 仅代码逻辑有小差异,其他配置和正式一致
      environment: { STAGE: 'canary' }
    });

    // 禁用默认部署,自定义部署和阶段配置
    const api = new apigateway.RestApi(this, 'BizApi', { deploy: false });

    // 公共API结构定义,可批量复用
    const prodIntegration = new apigateway.LambdaIntegration(prodLambda);
    api.root.addMethod('GET', prodIntegration);
    // 其他API资源、方法定义统一写在这里即可

    const deployment = new apigateway.Deployment(this, 'ApiDeployment', { api });

    // 正式阶段
    new apigateway.Stage(this, 'ProdStage', {
      deployment,
      stageName: 'prod'
    });

    // 金丝雀阶段,绑定同一份部署,仅配置差异规则
    new apigateway.Stage(this, 'CanaryStage', {
      deployment,
      stageName: 'canary',
      canarySettings: {
        percentTraffic: 10, // 10%流量切到金丝雀版本
        stageVariables: {
          backendVersion: 'canary'
        }
      }
    });
  }
}
  • 优势:无需重复定义API结构,仅需声明差异配置项,维护成本最低。

方案2:封装自定义构造实现两套完全隔离的资源

  • 如果你需要完全独立的两套API资源(比如域名、权限、限流规则完全隔离),可以把公共的API定义逻辑封装成自定义CDK构造,传入阶段标识参数控制差异配置,示例如下:
import { Construct } from 'constructs';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as route53 from 'aws-cdk-lib/aws-route53';

// 自定义构造入参,仅声明差异配置项
interface BizApiProps {
  isCanary: boolean;
  domainName: string;
}

class BizApi extends Construct {
  constructor(scope: Construct, id: string, props: BizApiProps) {
    super(scope, id);
    // 公共配置逻辑统一写在这里
    const handler = new lambda.Function(this, 'Handler', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: props.isCanary ? lambda.Code.fromAsset('lambda/canary') : lambda.Code.fromAsset('lambda/prod'),
      // 差异环境变量配置
      environment: {
        STAGE: props.isCanary ? 'canary' : 'prod',
        DB_INSTANCE: props.isCanary ? 'canary-db' : 'prod-db'
      }
    });

    const api = new apigateway.RestApi(this, 'Api', {
      restApiName: props.isCanary ? 'BizApi-Canary' : 'BizApi-Prod',
      deployOptions: {
        stageName: props.isCanary ? 'canary' : 'prod',
        throttlingRateLimit: props.isCanary ? 100 : 1000 // 差异限流配置
      },
      domainName: {
        domainName: props.domainName,
        certificate: props.isCanary ? canaryCert : prodCert
      }
    });
    api.root.addMethod('GET', new apigateway.LambdaIntegration(handler));
    // 其他公共API结构定义
  }
}

// 实例化两套独立资源
const prodApi = new BizApi(this, 'ProdApi', { isCanary: false, domainName: 'api.xxx.com' });
const canaryApi = new BizApi(this, 'CanaryApi', { isCanary: true, domainName: 'canary.api.xxx.com' });
  • 优势:两套资源完全隔离,配置自由度最高,公共逻辑复用不会出现配置不一致问题。

方案3:基于Lambda别名的轻量化金丝雀方案

  • 如果两套资源的差异仅在后端处理逻辑,API结构完全一致,可以不用修改API Gateway的定义,直接给Lambda设置别名,通过API Gateway的阶段变量绑定不同的Lambda别名,流量切分直接在API Gateway的金丝雀配置中完成,不需要重复定义任何API资源。

内容的提问来源于stack exchange,提问作者y. bs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 00:36:02