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

如何使用AWS CDK-Typescript创建MySQL数据库及数据表

使用AWS CDK TypeScript创建MySQL数据库及数据表

1. 初始化项目与安装依赖

初始化CDK TypeScript项目,安装所需AWS服务依赖包:

cdk init app --language typescript
npm install @aws-cdk/aws-rds @aws-cdk/aws-ec2 @aws-cdk/aws-lambda @aws-cdk/aws-secretsmanager @aws-cdk/custom-resources

2. 创建RDS MySQL实例

在lib/<你的栈名称>.ts中编写代码,完成VPC、RDS实例及数据库凭证的创建:

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';

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

    // 创建VPC(RDS必须部署在VPC内)
    const vpc = new ec2.Vpc(this, 'MyVpc', {
      maxAzs: 2,
      subnetConfiguration: [
        {
          name: 'private-subnet',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
        {
          name: 'public-subnet',
          subnetType: ec2.SubnetType.PUBLIC,
        },
      ],
    });

    // 创建数据库凭证(存储在Secrets Manager)
    const dbSecret = new secretsmanager.Secret(this, 'DbSecret', {
      secretName: 'mysql-db-credentials',
      generateSecretString: {
        secretStringTemplate: JSON.stringify({ username: 'admin' }),
        generateStringKey: 'password',
        excludePunctuation: true,
        passwordLength: 16,
      },
    });

    // 创建RDS MySQL实例
    const dbInstance = new rds.DatabaseInstance(this, 'MySqlInstance', {
      engine: rds.DatabaseInstanceEngine.mysql({
        version: rds.MysqlEngineVersion.VER_8_0_33,
      }),
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
      vpc: vpc,
      vpcSubnets: {
        subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
      },
      credentials: rds.Credentials.fromSecret(dbSecret),
      databaseName: 'mydb',
      publiclyAccessible: false,
      enablePerformanceInsights: false,
      deletionProtection: false, // 测试环境可关闭,生产环境建议开启
    });
  }
}

3. 通过自定义资源创建数据表

CDK本身不直接支持建表操作,需通过自定义资源触发Lambda函数连接数据库执行SQL:

3.1 编写Lambda建表代码

  1. 创建lambda目录并初始化依赖:
mkdir lambda && cd lambda
npm init -y
npm install mysql2 @aws-sdk/client-secrets-manager
  1. 创建create-table.ts文件,写入以下代码:
import * as mysql from 'mysql2/promise';
import * as secretsmanager from '@aws-sdk/client-secrets-manager';

const secretsClient = new secretsmanager.SecretsManagerClient({});

export const handler = async (event: any) => {
  // 仅在资源创建/更新时执行
  if (event.RequestType !== 'Create' && event.RequestType !== 'Update') {
    return sendResponse(event, 'SUCCESS', 'No action needed');
  }

  try {
    // 从Secrets Manager获取数据库凭证
    const secretResponse = await secretsClient.send(
      new secretsmanager.GetSecretValueCommand({
        SecretId: event.ResourceProperties.SecretArn,
      })
    );
    const secret = JSON.parse(secretResponse.SecretString!);

    // 连接数据库
    const connection = await mysql.createConnection({
      host: event.ResourceProperties.DbEndpoint,
      user: secret.username,
      password: secret.password,
      database: event.ResourceProperties.DbName,
      connectTimeout: 10000,
    });

    // 执行建表SQL(示例创建users表)
    await connection.execute(`
      CREATE TABLE IF NOT EXISTS users (
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(50) NOT NULL,
        email VARCHAR(100) UNIQUE NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
      );
    `);

    await connection.end();
    return sendResponse(event, 'SUCCESS', 'Table created successfully');
  } catch (error) {
    console.error('Error creating table:', error);
    return sendResponse(event, 'FAILED', (error as Error).message);
  }
};

// 向CDK发送自定义资源响应
const sendResponse = async (event: any, status: string, message: string) => {
  const https = require('https');
  const url = require('url');

  const parsedUrl = url.parse(event.ResponseURL);
  const options = {
    hostname: parsedUrl.hostname,
    port: 443,
    path: parsedUrl.path,
    method: 'PUT',
    headers: {
      'Content-Type': '',
      'Content-Length': Buffer.byteLength(JSON.stringify({
        Status: status,
        Reason: message,
        PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,
        StackId: event.StackId,
        RequestId: event.RequestId,
        LogicalResourceId: event.LogicalResourceId,
        Data: { Message: message }
      })),
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res: any) => {
      resolve('Success');
    });

    req.on('error', (err: any) => {
      reject(err);
    });

    req.write(JSON.stringify({
      Status: status,
      Reason: message,
      PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,
      StackId: event.StackId,
      RequestId: event.RequestId,
      LogicalResourceId: event.LogicalResourceId,
      Data: { Message: message }
    }));
    req.end();
  });
};

3.2 在CDK栈中配置自定义资源

回到lib/<你的栈名称>.ts,添加Lambda和自定义资源的配置代码:

import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as cr from 'aws-cdk-lib/custom-resources';

// ... 保留之前的VPC、RDS实例代码 ...

// 创建Lambda函数,用于执行建表SQL
const createTableLambda = new lambda.Function(this, 'CreateTableLambda', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'create-table.handler',
  code: lambda.Code.fromAsset('lambda'),
  vpc: vpc,
  vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
  environment: {
    NODE_ENV: 'production',
  },
});

// 授予Lambda访问Secrets Manager的权限
dbSecret.grantRead(createTableLambda);

// 允许Lambda访问RDS实例的3306端口
dbInstance.connections.allowFrom(createTableLambda, ec2.Port.tcp(3306));

// 创建自定义资源,触发Lambda执行建表
new cr.AwsCustomResource(this, 'CreateTableResource', {
  onCreate: {
    service: 'Lambda',
    action: 'invoke',
    parameters: {
      FunctionName: createTableLambda.functionName,
      Payload: JSON.stringify({
        RequestType: 'Create',
        ResourceProperties: {
          SecretArn: dbSecret.secretArn,
          DbEndpoint: dbInstance.dbInstanceEndpointAddress,
          DbName: 'mydb',
        },
      }),
    },
    physicalResourceId: cr.PhysicalResourceId.of(`CreateTable-${Date.now()}`),
  },
  onUpdate: {
    service: 'Lambda',
    action: 'invoke',
    parameters: {
      FunctionName: createTableLambda.functionName,
      Payload: JSON.stringify({
        RequestType: 'Update',
        ResourceProperties: {
          SecretArn: dbSecret.secretArn,
          DbEndpoint: dbInstance.dbInstanceEndpointAddress,
          DbName: 'mydb',
        },
      }),
    },
  },
  policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
    resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
  }),
});

4. 部署与验证

执行部署命令:

cdk deploy

部署完成后,可通过Secrets Manager获取数据库凭证,使用MySQL客户端连接实例,验证users表是否存在。

注意事项

  • Lambda需部署在与RDS同VPC的私有子网中,确保网络连通性
  • 建表SQL中使用IF NOT EXISTS避免重复创建报错
  • 生产环境建议开启RDS删除保护,调整实例类型和VPC配置
  • 可扩展Lambda代码支持多表创建或数据初始化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:16:18