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

如何在CDK中使用S3动态JSON构建CloudWatch仪表板?

解决CDK中基于S3动态JSON构建CloudWatch仪表板的$TOKEN问题

问题核心是CDK的声明式特性:自定义资源返回的是运行时令牌($TOKEN),而CloudWatch仪表板的定义需要在CDK合成(synth)阶段确定静态结构,直接用自定义资源的输出无法解析为具体值。下面提供两种可行方案:

方案一:合成阶段读取S3文件(静态生成仪表板)

在CDK执行synth时直接读取S3中的JSON文件,解析后生成仪表板的静态定义。这种方式能避免$TOKEN问题,因为所有值在构建时就已确定。

代码示例(TypeScript)

import * as cdk from 'aws-cdk-lib';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';

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

    // 初始化S3客户端(确保CDK运行环境有S3读取权限)
    const s3Client = new S3Client({ region: props?.env?.region });
    const getObjectCmd = new GetObjectCommand({
      Bucket: 'your-target-bucket',
      Key: 'path/to/app-pages.json',
    });

    // 同步读取并解析JSON(synth阶段需同步执行)
    const objectData = await s3Client.send(getObjectCmd);
    const jsonStr = await objectData.Body?.transformToString();
    const appPages = JSON.parse(jsonStr || '{"applications": []}');

    // 创建CloudWatch仪表板
    const dashboard = new cloudwatch.Dashboard(this, 'AppPagesDashboard', {
      dashboardName: 'App-Pages-Metrics',
    });

    // 遍历应用和页面生成指标组件
    for (const app of appPages.applications) {
      dashboard.addWidgets(new cloudwatch.TextWidget({
        markdown: `## ${app.name}`,
        width: 24,
      }));

      for (const page of app.pages) {
        dashboard.addWidgets(new cloudwatch.GraphWidget({
          title: `${page.name} - Average Latency`,
          left: [
            new cloudwatch.Metric({
              namespace: 'Your-App-Namespace',
              metricName: 'Latency',
              dimensionsMap: { App: app.name, Page: page.name },
              statistic: 'Average',
            }),
          ],
          width: 12,
        }));
      }
    }
  }
}

注意事项

  • 确保CDK运行环境(本地或CI/CD管道)有目标S3桶的s3:GetObject权限;
  • JSON文件更新后,必须重新执行cdk synth && cdk deploy才能更新仪表板;
  • 若文件过大,会增加synth阶段的耗时,需权衡文件大小与构建效率。

方案二:自定义资源+Lambda动态生成仪表板(运行时创建)

通过Lambda函数在堆栈部署时读取S3 JSON,调用CloudWatch API动态创建/更新仪表板。这种方式绕开了CDK合成阶段的静态要求,适合JSON频繁更新的场景。

步骤1:编写Lambda处理函数

import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { CloudWatchClient, PutDashboardCommand } from '@aws-sdk/client-cloudwatch';
import axios from 'axios';

const s3Client = new S3Client({ region: process.env.AWS_REGION });
const cwClient = new CloudWatchClient({ region: process.env.AWS_REGION });

export const handler = async (event: any) => {
  const sendResponse = async (status: string, physicalId?: string) => {
    await axios.put(event.ResponseURL, {
      Status: status,
      PhysicalResourceId: physicalId || `dashboard-${Date.now()}`,
      StackId: event.StackId,
      RequestId: event.RequestId,
      LogicalResourceId: event.LogicalResourceId,
    });
  };

  try {
    if (event.RequestType === 'Create' || event.RequestType === 'Update') {
      // 读取S3中的JSON文件
      const objectData = await s3Client.send(new GetObjectCommand({
        Bucket: process.env.S3_BUCKET!,
        Key: process.env.S3_KEY!,
      }));
      const jsonStr = await objectData.Body?.transformToString();
      const appPages = JSON.parse(jsonStr || '{"applications": []}');

      // 构建CloudWatch仪表板配置
      const widgets = [];
      for (const app of appPages.applications) {
        widgets.push({
          type: 'text',
          width: 24,
          properties: { markdown: `## ${app.name}` }
        });
        for (const page of app.pages) {
          widgets.push({
            type: 'metric',
            width: 12,
            properties: {
              title: `${page.name} Latency`,
              metrics: [['Your-App-Namespace', 'Latency', 'App', app.name, 'Page', page.name, { stat: 'Average' }]],
              view: 'timeSeries'
            }
          });
        }
      }

      // 调用CloudWatch API创建/更新仪表板
      await cwClient.send(new PutDashboardCommand({
        DashboardName: process.env.DASHBOARD_NAME!,
        DashboardBody: JSON.stringify({ widgets })
      }));
    }
    await sendResponse('SUCCESS');
  } catch (err) {
    console.error('Error generating dashboard:', err);
    await sendResponse('FAILED');
  }
};

步骤2:CDK中配置自定义资源

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import { CustomResource, Provider } from 'aws-cdk-lib/custom-resources';

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

    const config = {
      dashboardName: 'Dynamic-App-Pages-Dashboard',
      s3Bucket: 'your-target-bucket',
      s3Key: 'path/to/app-pages.json'
    };

    // 创建Lambda函数
    const dashboardLambda = new lambda.Function(this, 'DashboardGenerator', {
      runtime: lambda.Runtime.NODEJS_18_X,
      code: lambda.Code.fromAsset('path/to/lambda/code'),
      handler: 'index.handler',
      environment: {
        S3_BUCKET: config.s3Bucket,
        S3_KEY: config.s3Key,
        DASHBOARD_NAME: config.dashboardName
      }
    });

    // 授予Lambda必要权限
    dashboardLambda.addToRolePolicy(new iam.PolicyStatement({
      actions: ['s3:GetObject'],
      resources: [`arn:aws:s3:::${config.s3Bucket}/${config.s3Key}`]
    }));

    dashboardLambda.addToRolePolicy(new iam.PolicyStatement({
      actions: ['cloudwatch:PutDashboard'],
      resources: [`arn:aws:cloudwatch::${this.account}:dashboard/${config.dashboardName}`]
    }));

    // 创建自定义资源提供商
    const provider = new Provider(this, 'DashboardProvider', {
      onEventHandler: dashboardLambda
    });

    // 触发自定义资源执行
    new CustomResource(this, 'DynamicDashboardResource', {
      serviceToken: provider.serviceToken
    });
  }
}

注意事项

  • 仪表板定义不会出现在CDK的synth输出中,因为是运行时动态生成;
  • 若需JSON更新时自动同步仪表板,可给Lambda添加S3对象更新事件触发器;
  • 自定义资源支持Create/Update/Delete事件,可在Lambda中处理删除逻辑(比如删除仪表板)。

方案选择建议

  • 方案一:适合JSON更新频率低、需版本控制仪表板定义的场景;
  • 方案二:适合JSON频繁更新、CDK运行环境无法访问S3的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:33:15