跳转到内容

CDK 基础设施

AWS CDK 是一个用于在代码中定义云基础设施并通过 AWS CloudFormation 进行配置的框架。

TypeScript 基础设施生成器创建一个用 TypeScript 编写的 AWS CDK 基础设施应用程序。生成的应用程序通过 Checkov 安全检查包含安全最佳实践。

您可以通过两种方式生成新的基础设施项目:

Terminal window
pnpm nx g @aws/nx-plugin:ts#infra
您还可以执行试运行以查看哪些文件会被更改
Terminal window
pnpm nx g @aws/nx-plugin:ts#infra --dry-run
参数类型默认值描述
name 必需string-应用程序的名称。
directory stringpackages新应用程序的目录。
subDirectory string-项目所在的子目录。默认为项目名称。
stageConfig boolean为多环境 CDK 部署启用集中式阶段配置(凭证、账户、区域)。
preferInstallDependencies booleantrue是否在生成器运行后优先安装依赖项。设置为 false 可在批量运行多个生成器时延迟安装(如果后续生成器需要计算 Nx 项目图,仍会运行安装);最后统一安装一次。

生成器将在 <directory>/<name> 目录中创建以下项目结构:

  • 文件夹src
    • main.ts Application entry point instantiating CDK stages to deploy
    • 文件夹stages CDK Stage definitions
      • application-stage.ts Defines a collection of stacks to deploy in a stage
    • 文件夹stacks CDK Stack definitions
      • application-stack.ts Main application stack
  • cdk.json CDK configuration
  • package.json Project manifest defining the project’s package name and dependencies
  • project.json Project configuration and build targets
  • checkov.yml Checkov configuration file

如果您设置了 stageConfig 选项,生成器还会创建两个用于集中凭证管理的共享包(如果它们尚不存在):

  • 文件夹packages/common
    • 文件夹infra-config Stage configuration types and credential mappings
      • 文件夹src
        • stages.types.ts Type definitions for stage credentials and config
        • stages.config.ts Your stage-to-credential mappings (edit this)
        • index.ts Re-exports for importing from other packages
    • 文件夹scripts Centralized deploy/destroy scripts
      • 文件夹src
        • infra-deploy.ts Deploy bin script
        • infra-destroy.ts Destroy bin script
        • 文件夹stage-credentials/ Shared logic (credential lookup, CDK command building)

您可以在 src/stacks/application-stack.ts 中开始编写您的 CDK 基础设施,例如:

src/stacks/application-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib';
import { Bucket } from 'aws-cdk-lib/aws-s3'
import { Construct } from 'constructs';
export class ApplicationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Declare your infrastructure here
new Bucket(this, 'MyBucket');
}
}

CDK 使用 Stages 来分组应该一起部署到特定环境的堆栈。生成的 src/main.ts 为您自己的开发和测试创建了一个沙箱阶段:

src/main.ts
new ApplicationStage(app, 'my-app-sandbox', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});
// Define other instances of stages, such as beta and prod, below

env 属性告诉 CDK 要部署到哪个 AWS 账户和区域。CDK_DEFAULT_ACCOUNTCDK_DEFAULT_REGION 由 CDK CLI 从您的活动 AWS 凭证自动解析。有关更多详细信息,请参阅 CDK 环境文档

沙箱阶段是 deploy-sandbox 目标 部署的阶段。

如果您使用 stageConfig 生成,main.ts 会从集中配置文件中读取账户和区域,当没有设置配置时回退到环境变量:

src/main.ts (with stageConfig)
import { resolveStage } from '@my-scope/common-infra-config';
// Looks up the stage under this project (packages/infra), falling back to
// shared stages. Returns undefined when no config exists for the stage.
const sandboxConfig = resolveStage('packages/infra', 'my-app-sandbox');
new ApplicationStage(app, 'my-app-sandbox', {
env: {
account: sandboxConfig?.account ?? process.env.CDK_DEFAULT_ACCOUNT,
region: sandboxConfig?.region ?? process.env.CDK_DEFAULT_REGION,
},
});

您可以添加更多阶段以部署到不同的环境。例如,针对不同 AWS 账户的 betaprod 阶段:

src/main.ts
new ApplicationStage(app, 'project-beta', {
env: {
account: '123456789012',
region: 'us-west-2',
},
});
new ApplicationStage(app, 'project-prod', {
env: {
account: '098765432109',
region: 'us-west-2',
},
});

一个阶段可以分组一个或多个堆栈。您可以在阶段内添加任意数量的堆栈:

src/stages/application-stage.ts
import { Stage, StageProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { BackendStack } from '../stacks/backend-stack.js';
import { FrontendStack } from '../stacks/frontend-stack.js';
export class ApplicationStage extends Stage {
constructor(scope: Construct, id: string, props?: StageProps) {
super(scope, id, props);
new BackendStack(this, 'Backend', {
crossRegionReferences: true,
})
new FrontendStack(this, 'Frontend', {
crossRegionReferences: true,
});
}
}

当您有多个针对不同 AWS 账户的阶段时,手动管理凭证可能容易出错,特别是随着阶段数量的增加。

stageConfig 选项通过生成两个共享包来解决这个问题:

  • packages/common/infra-config — 一个单一配置文件,您可以在其中将每个阶段映射到其 AWS 凭证、账户和区域。这可以从工作区中的任何包导入,因此您的 CDK main.ts 可以从同一真实来源读取账户和区域。
  • packages/common/scriptsinfra-deployinfra-destroy 命令,它们使用自动凭证解析包装 CDK。当您运行 deploy 时,脚本会读取配置,为 CDK 子进程设置正确的 AWS 环境变量,并运行 cdk deploy。您的 shell 环境永远不会被修改。

编辑 packages/common/infra-config/src/stages.config.ts 以将您的阶段映射到 AWS 凭证:

packages/common/infra-config/src/stages.config.ts
import type { StagesConfig } from './stages.types.js';
const config: StagesConfig = {
projects: {
// The key is the project path relative to the workspace root.
// This matches the path in project.json and in deploy commands.
'packages/infra': {
stages: {
// Stage names must match the CDK stage identifiers in main.ts
// (the first argument to `new ApplicationStage(app, 'my-app-dev', ...)`).
'my-app-dev': {
credentials: { type: 'profile', profile: 'dev-account' },
region: 'us-east-1',
},
'my-app-prod': {
credentials: {
type: 'assumeRole',
assumeRole: 'arn:aws:iam::123456789012:role/DeployRole',
},
region: 'us-west-2',
account: '123456789012',
},
},
},
},
shared: {
// Shared stages are available to all infra projects.
// Project-specific entries take priority over shared ones.
stages: {
sandbox: {
credentials: { type: 'profile', profile: 'personal-sandbox' },
region: 'us-east-1',
},
},
},
};
export default config;

当您部署时,例如:

Terminal window
pnpm nx deploy infra my-app-dev/*

部署脚本:

  1. 从命令参数中提取阶段名称 my-app-dev
  2. 在配置中查找凭证:首先在 projects['packages/infra'] 下,然后在 shared
  3. 如果找到,仅为 CDK 子进程设置 AWS_PROFILE(或假定 IAM 角色)
  4. 如果未找到,回退到您环境中的任何 AWS 凭证

这意味着没有任何配置的现有工作流程将继续工作 — 脚本仅在找到匹配条目时应用凭证。

支持两种凭证策略:

  • profile — 使用来自 ~/.aws/config 的命名 AWS CLI 配置文件。脚本为 CDK 进程设置 AWS_PROFILE
  • assumeRole — 使用指定的角色 ARN 调用 STS AssumeRole,并将临时凭证传递给 CDK。您可以选择指定一个 profile 作为 AssumeRole 调用的源凭证、用于跨账户信任策略的 externalId 以及以秒为单位的 sessionDuration

每个阶段配置包括一个必需的 region 和一个可选的 account

  • region(必需)— 要部署到的 AWS 区域(例如,us-east-1eu-west-2)。
  • account(可选)— AWS 账户 ID。如果省略,CDK 会在部署时从活动凭证推断它。有关 CDK 如何解析账户和区域,请参阅 CDK 环境文档

生成的 main.ts 从配置中读取这些值,以便 CDK 合成和部署使用相同的环境设置:

src/main.ts
const sandboxConfig = resolveStage('packages/infra', 'my-app-sandbox');
new ApplicationStage(app, 'my-app-sandbox', {
env: {
account: sandboxConfig?.account ?? process.env.CDK_DEFAULT_ACCOUNT,
region: sandboxConfig?.region ?? process.env.CDK_DEFAULT_REGION,
},
});

共享阶段(在 shared.stages 下)适用于工作区中的任何基础设施项目。当多个项目部署到同一个沙箱账户时,这很有用 — 您只需定义一次凭证,而不是为每个项目重复它们。

项目特定阶段(在 projects['packages/infra'].stages 下)仅适用于该项目。当同一阶段名称同时存在时,项目特定条目优先。

如果您使用了 tRPC APIFastAPI 生成器来创建 API,您会注意到在 packages/common/constructs 中已经有一些可用的构造来部署它们。

例如,如果您创建了一个名为 my-api 的 tRPC API,您可以简单地导入并实例化该构造以添加部署它所需的所有基础设施:

src/stacks/application-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { MyApi } from '@my-scope/common-constructs';
export class ApplicationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Add infrastructure for your API
new MyApi(this, 'MyApi', {
integrations: MyApi.defaultIntegrations(this).build(),
});
}
}

如果您使用了 React Website 生成器,您会注意到在 packages/common/constructs 中已经有一个构造来部署它。例如:

src/stacks/application-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { MyWebsite } from '@my-scope/common-constructs';
export class ApplicationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Add infrastructure for your website
new MyWebsite(this, 'MyWebsite');
}
}

作为 build 目标的一部分,除了运行 默认的编译、检查和测试目标 之外,您的基础设施项目还会被_合成_为 CloudFormation。这也可以通过运行 synth 目标以独立方式执行:

Terminal window
pnpm nx synth <my-infra>

您将在根 dist 文件夹中找到您合成的云程序集,位于 dist/packages/<my-infra-project>/cdk.out 下。

一个 checkov 目标被添加到您的项目中,它使用 Checkov 对您的基础设施运行安全检查。

Terminal window
pnpm nx checkov <my-infra>

您将在根 dist 文件夹中找到您的安全测试结果,位于 dist/packages/<my-infra-project>/checkov 下。

在某些情况下,您可能希望抑制资源上的某些规则。您可以通过两种方式执行此操作:

import { suppressRules } from '@my-scope/common-constructs';
// suppresses the CKV_AWS_XXX for the given construct.
suppressRules(construct, ['CKV_AWS_XXX'], 'Reason');
import { suppressRules } from '@my-scope/common-constructs';
// Supresses the CKV_AWS_XXX for the construct or any of its descendants if it is an instance of Bucket
suppressRules(construct, ['CKV_AWS_XXX'], 'Reason', (construct) => construct instanceof Bucket);

如果您是第一次将 CDK 应用程序部署到 AWS 账户,则需要对其进行引导。引导会创建 CDK 管理部署所需的资源(用于资产的 S3 存储桶、IAM 角色等)。

首先,确保您已为您的 AWS 账户配置了凭证

接下来,为您计划部署到的每个账户和区域运行引导命令:

Terminal window
npx cdk bootstrap aws://<account-id>/<region>

有关更多详细信息,请参阅 CDK 引导文档

您的项目有三个部署目标,每个都适合不同的情况:

目标用途
deploy-sandbox在开发期间部署您自己的沙箱阶段。不需要阶段参数。
deploy通过命名您想要的阶段或堆栈来部署任何阶段。
deploy-ci从 CI/CD 管道部署,使用预合成的云程序集。

首先,确保您已配置 AWS 凭证。如果您使用 stageConfig 生成并在 packages/common/infra-config/src/stages.config.ts 中配置了阶段凭证,部署命令将自动解析并应用目标阶段的正确凭证。否则,请确保在您的环境中设置了 AWS 凭证(例如,通过 AWS_PROFILE 或环境变量)。有关可用选项,请参阅 AWS 凭证文档

deploy-sandbox 目标部署 main.ts 声明的沙箱阶段,因此您不需要记住其阶段名称:

Terminal window
pnpm nx deploy-sandbox <my-infra>

这是在开发时让您自己的应用程序副本在 AWS 中运行的最快方法。

deploy 目标部署您命名的任何阶段或堆栈。将其用于沙箱以外的阶段,或部署单个堆栈:

Terminal window
pnpm nx deploy <my-infra> <my-infra>-sandbox/*

您可以指定任何阶段,只要它在 main.ts 中定义。要部署单个堆栈,请提供完整的堆栈名称:

Terminal window
pnpm nx deploy <my-infra> <my-infra>-sandbox/Application

如果您要作为 CI/CD 管道的一部分部署到 AWS,请使用 deploy-ci 目标。

Terminal window
pnpm nx deploy-ci <my-infra> my-stage/*

此目标与常规 deploy 目标略有不同,因为它部署预合成的云程序集,而不是即时合成。这避免了包版本更改带来的潜在非确定性,确保每个管道阶段使用相同的云程序集进行部署。

使用 destroy 目标来拆除您的资源:

Terminal window
pnpm nx destroy <my-infra> <my-infra>-sandbox/*

有关 CDK 的更多信息,请参阅 CDK 开发者指南API 参考