はじめに
皆さん、こんにちは。
私は業務でデータ利活用基盤を取り扱っていること、2024 AWS Japan Top Engineer に選出されたということから、AWS GenU およびそれに必要なデータ基盤の探求 (Snowflake, dbt, Iceberg, etc) に取り組む必要があると考えています。
本投稿では、GenU のバックエンドである CDK コードを詳細に解説します。
自身そして閲覧して頂いた皆様の GenU への理解が少しでも深まり、生成 AI の民主化につながっていければと考えています。
前回までのおさらい
前回までで、以下が完了しました。
今回は GenU 内の CDK スタックを解説していきたいと思います。
GenU アーキテクチャについて
2025/3/10 現在、クイックスタートに記載されているアーキテクチャは以下の通りです。
このアーキテクチャを CDK のソースコードと照らし合わせながら見ていくと、このような構造になっています。
※それぞれのスタック、リソースは、この後の記事の中で詳細に解説していきます。
デプロイコマンドの解説
まずは CDK のデプロイコマンドを解説します。
最初にnpm ci
コマンドを実行します。
npm ci
コマンドについて、npm Docs の説明文を訳すと以下の通りです。
このコマンドは npm install と似ているが、テストプラットフォーム、継続的インテグレーション、デプロイなどの自動化された環境で使うことを意図している。
npm install と npm ci の主な違いは以下の通り:
- プロジェクトに既存の package-lock.json か npm-shrinkwrap.json があること。
- package-lock.json 内の依存関係が package.json 内の依存関係と一致しない場合、 npm ci はパッケージロックを更新する代わりにエラーで終了します。
- npm ci は、一度にプロジェクト全体をインストールすることしかできません: 個々の依存関係をこのコマンドで追加することはできません。
- 既に node_modules が存在する場合は、npm ci がインストールを始める前に自動的に削除されます。
- package.json や package-lock に書き込むことはありません: インストールは基本的に凍結されます。
つまり、package-lock.json のみを利用してクリーンインストールするコマンドになります。
こちらは大人しく実行しておきましょう。
npm ci
次に、以下のデプロイコマンドを実行せよと記載されています。
# 通常デプロイ
npm run cdk:deploy
# 高速デプロイ (作成されるリソースを事前確認せずに素早くデプロイ)
npm run cdk:deploy:quick
この実行コマンドは前回解説した通り、以下の通りです。
{
"name": "generative-ai-use-cases-jp",
"private": true,
"version": "3.0.0",
"scripts": {
"lint": "run-s root:lint web:lint cdk:lint",
"test": "run-s web:test",
"root:lint": "npx prettier --write .",
"web:devw": "source ./setup-env.sh ${npm_config_env} && VITE_APP_VERSION=${npm_package_version} npm -w packages/web run dev",
"web:devww": "powershell ./web_devw_win.ps1",
"web:dev": "VITE_APP_VERSION=${npm_package_version} npm -w packages/web run dev",
"web:build": "VITE_APP_VERSION=${npm_package_version} npm -w packages/web run build --",
"web:build:analyze": "VITE_APP_VERSION=${npm_package_version} npm -w packages/web run build -- --mode analyze",
"web:lint": "npm -w packages/web run lint",
"web:test": "npm -w packages/web run test",
+ "cdk:deploy": "npm -w packages/cdk run cdk deploy -- --all",
+ "cdk:deploy:quick": "npm -w packages/cdk run cdk deploy -- --all --asset-parallelism --asset-prebuild=false --concurrency 3 --method=direct --require-approval never --force",
"cdk:deploy:quick:hotswap": "npm -w packages/cdk run cdk deploy -- --all --asset-parallelism --asset-prebuild=false --concurrency 3 --method=direct --require-approval never --force --hotswap",
"cdk:destroy": "npm -w packages/cdk run cdk destroy --",
"cdk:lint": "npm -w packages/cdk run lint",
"cdk:test": "npm -w packages/cdk run test",
"cdk:test:update-snapshot": "npm -w packages/cdk run test -- --update-snapshot",
"extension:ci": "cd browser-extension && npm ci",
"extension:dev": "cd browser-extension && npm run dev",
"extension:devw": "source ./setup-env.sh && cd browser-extension && npm run dev",
"extension:build": "cd browser-extension && npm run build",
"extension:buildw": "source ./setup-env.sh && cd browser-extension && npm run build",
"extension:lint": "npx prettier --write browser-extension/. && cd browser-extension && npm run lint",
"docs:dev": "mkdocs serve",
"docs:build": "mkdocs build",
"docs:gh-deploy": "mkdocs gh-deploy --"
},
"devDependencies": {
"npm-run-all": "^4.1.5",
"prettier": "^3.2.5"
},
"workspaces": [
"packages/*"
]
}
つまり、以下のコマンドを実行しています。
# npm run cdk:deploy
npm -w packages/cdk run cdk deploy -- --all
# npm run cdk:deploy:quick
npm -w packages/cdk run cdk deploy -- --all --asset-parallelism --asset-prebuild=false --concurrency 3 --method=direct --require-approval never --force
デプロイコマンド(2 層目)の解説
上記のデプロイコマンドは packages/cdk を Workspace としてrun cdk deploy --all # +オプション
を実行しています。
ここで--
は最上階の npm コマンドではなく、run cdk deploy
に--all
オプションをつけるという記法です。
packages/cdk/package.json の npm-scripts を確認します。
{
"name": "cdk",
"private": true,
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
+ "cdk": "cdk",
"lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0",
"postinstall": "npm ci --prefix custom-resources"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.137",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.5",
"@typescript-eslint/eslint-plugin": "^7.6.0",
"@typescript-eslint/parser": "^7.6.0",
"aws-cdk": "^2.154.1",
"eslint": "^8.56.0",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "~5.4.5"
},
"dependencies": {
"@aws-cdk/aws-cognito-identitypool-alpha": "^2.154.1-alpha.0",
"@aws-cdk/aws-lambda-python-alpha": "^2.154.1-alpha.0",
"@aws-sdk/client-bedrock-agent": "^3.755.0",
"@aws-sdk/client-bedrock-agent-runtime": "^3.755.0",
"@aws-sdk/client-bedrock-runtime": "^3.755.0",
"@aws-sdk/client-dynamodb": "^3.755.0",
"@aws-sdk/client-kendra": "^3.755.0",
"@aws-sdk/client-s3": "^3.755.0",
"@aws-sdk/client-sagemaker-runtime": "^3.755.0",
"@aws-sdk/client-transcribe": "^3.755.0",
"@aws-sdk/client-transcribe-streaming": "^3.755.0",
"@aws-sdk/lib-dynamodb": "^3.755.0",
"@aws-sdk/s3-request-presigner": "^3.755.0",
"@aws-solutions-constructs/aws-cloudfront-s3": "^2.68.0",
"aws-cdk-lib": "^2.154.1",
"aws-jwt-verify": "^4.0.0",
"constructs": "^10.3.0",
"deploy-time-build": "^0.3.17",
"node-html-parser": "^6.1.13",
"sanitize-html": "^2.13.0",
"source-map-support": "^0.5.21",
"upsert-slr": "^1.0.4",
"zod": "^3.24.1"
}
}
Workspace の package/cdk でcdk deploy --all
を実行しています。
cdk deploy
コマンドに以下のオプションをつけて実行しています。
-
--all
BOOLEAN: CDK アプリにすべてのスタックをデプロイします。
ここまでで、クイックスタートのコマンドは、すべての CDK スタックをデプロイするコマンドであることが確認できました。
GenU に含まれている CDK スタックについて
次に GenU に含まれている CDK スタックを解説します。
CDK のcdk list
コマンドを使います。
--show-dependencies
オプションをつけて依存関係情報も確認します。
cd packages/cdk
cdk list --show-dependencies
スタックはGenerativeAiUseCasesStack
の 1 つのみで、依存関係はないようです。
GenU の CDK スタックの解説
それでは、CDK ソースコードを読んでいきます。
なお、この記事に記載のコードは、あくまでもこの記事の執筆時点(2025/3/10)のもの であることにご留意ください。
まずは packages/cdk/cdk.json
を確認します。
{
"app": "npx ts-node --prefer-ts-exts bin/generative-ai-use-cases.ts",
~~ 省略 ~~
}
bin/generative-ai-use-cases.ts
を実行しています。
次に、 packages/cdk/bin/generative-ai-use-cases.ts
を確認します。
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { getParams } from '../parameter';
import { createStacks } from '../lib/create-stacks';
const app = new cdk.App();
const params = getParams(app);
createStacks(app, params);
createStacks 関数でスタックを作成しているため、packages/cdk/lib/create-stacks.ts
を確認します。
import * as cdk from 'aws-cdk-lib';
import { IConstruct } from 'constructs';
import { GenerativeAiUseCasesStack } from './generative-ai-use-cases-stack';
import { CloudFrontWafStack } from './cloud-front-waf-stack';
import { DashboardStack } from './dashboard-stack';
import { AgentStack } from './agent-stack';
import { RagKnowledgeBaseStack } from './rag-knowledge-base-stack';
import { GuardrailStack } from './guardrail-stack';
import { StackInput } from './stack-input';
class DeletionPolicySetter implements cdk.IAspect {
constructor(private readonly policy: cdk.RemovalPolicy) {}
visit(node: IConstruct): void {
if (node instanceof cdk.CfnResource) {
node.applyRemovalPolicy(this.policy);
}
}
}
export const createStacks = (app: cdk.App, params: StackInput) => {
// CloudFront WAF
// IP アドレス範囲(v4もしくはv6のいずれか)か地理的制限が定義されている場合のみ、CloudFrontWafStack をデプロイする
// WAF v2 は us-east-1 でのみデプロイ可能なため、Stack を分けている
const cloudFrontWafStack =
params.allowedIpV4AddressRanges ||
params.allowedIpV6AddressRanges ||
params.allowedCountryCodes ||
params.hostName
? new CloudFrontWafStack(app, `CloudFrontWafStack${params.env}`, {
env: {
account: params.account,
region: 'us-east-1',
},
params: params,
crossRegionReferences: true,
})
: null;
// RAG Knowledge Base
const ragKnowledgeBaseStack =
params.ragKnowledgeBaseEnabled && !params.ragKnowledgeBaseId
? new RagKnowledgeBaseStack(app, `RagKnowledgeBaseStack${params.env}`, {
env: {
account: params.account,
region: params.modelRegion,
},
params: params,
crossRegionReferences: true,
})
: null;
// Agent
const agentStack = params.agentEnabled
? new AgentStack(app, `WebSearchAgentStack${params.env}`, {
env: {
account: params.account,
region: params.modelRegion,
},
params: params,
crossRegionReferences: true,
})
: null;
// Guardrail
const guardrail = params.guardrailEnabled
? new GuardrailStack(app, `GuardrailStack${params.env}`, {
env: {
account: params.account,
region: params.modelRegion,
},
crossRegionReferences: true,
})
: null;
// GenU Stack
const generativeAiUseCasesStack = new GenerativeAiUseCasesStack(
app,
`GenerativeAiUseCasesStack${params.env}`,
{
env: {
account: params.account,
region: params.region,
},
description: params.anonymousUsageTracking
? 'Generative AI Use Cases JP (uksb-1tupboc48)'
: undefined,
params: params,
crossRegionReferences: true,
// RAG Knowledge Base
knowledgeBaseId: ragKnowledgeBaseStack?.knowledgeBaseId,
knowledgeBaseDataSourceBucketName:
ragKnowledgeBaseStack?.dataSourceBucketName,
// Agent
agents: agentStack?.agents,
// Guardrail
guardrailIdentifier: guardrail?.guardrailIdentifier,
guardrailVersion: 'DRAFT',
// WAF
webAclId: cloudFrontWafStack?.webAclArn,
// Custom Domain
cert: cloudFrontWafStack?.cert,
}
);
cdk.Aspects.of(generativeAiUseCasesStack).add(
new DeletionPolicySetter(cdk.RemovalPolicy.DESTROY)
);
const dashboardStack = params.dashboard
? new DashboardStack(
app,
`GenerativeAiUseCasesDashboardStack${params.env}`,
{
env: {
account: params.account,
region: params.modelRegion,
},
params: params,
userPool: generativeAiUseCasesStack.userPool,
userPoolClient: generativeAiUseCasesStack.userPoolClient,
appRegion: params.region,
crossRegionReferences: true,
}
)
: null;
return {
cloudFrontWafStack,
ragKnowledgeBaseStack,
agentStack,
guardrail,
generativeAiUseCasesStack,
dashboardStack,
};
};
GenU の CDK は最大で以下の 6 つの子スタックを作成します。
CloudFrontWafStack
RagKnowledgeBaseStack
AgentStack
GuardrailStack
GenerativeAiUseCasesStack
DashboardStack
デプロイオプションを設定しない場合、デフォルトでは GenerativeAiUseCasesStack
スタックのみ作成する作りになっています。
そのため、cdk list
コマンドでは GenerativeAiUseCasesStack
スタックしか出力されませんでした。
他の 5 つのスタックについては、前回の記事で少し触れたデプロイオプションを指定することで作成されます。
それぞれのスタックの作成条件について見ていきましょう。
CloudFrontWafStack の作成条件
CloudFrontWafStack は、AWS WAF による制限を有効化するか、カスタムドメインの使用 を行うと作成されます。
パラメータ例として、packages/cdk/parameter.ts
に以下を設定します。
dev: {
allowedIpV4AddressRanges: ["192.168.0.0/24"],
allowedIpV6AddressRanges: ["2001:0db8::/32"],
allowedCountryCodes: ["JP"]
}
dev: {
hostName: 'genai',
domainName: 'example.com',
hostedZoneId: 'Z0123456789ABCDEFGHIJ',
}
RagKnowledgeBaseStack の作成条件
RagKnowledgeBaseStack は、RAG チャット (Knowledge Base) ユースケースの有効化 を行うと作成されます。
パラメータ例として、packages/cdk/parameter.ts
に以下を設定します。
dev: {
ragKnowledgeBaseEnabled: true,
ragKnowledgeBaseId: 'XXXXXXXXXX',
ragKnowledgeBaseStandbyReplicas: false,
ragKnowledgeBaseAdvancedParsing: false,
ragKnowledgeBaseAdvancedParsingModelId: 'anthropic.claude-3-sonnet-20240229-v1:0',
embeddingModelId: 'amazon.titan-embed-text-v2:0',
}
AgentStack の作成条件
AgentStack は、Agent チャットユースケースの有効化 を行うと作成されます。
パラメータ例として、packages/cdk/parameter.ts
に以下を設定します。
dev: {
agentEnabled: true,
}
GuardrailStack の作成条件
GuardrailStack は、ガードレール を適用すると作成されます。
パラメータ例として、packages/cdk/parameter.ts
に以下を設定します。
dev: {
guardrailEnabled: true,
}
GenerativeAiUseCasesStack の作成条件
GenerativeAiUseCasesStack は唯一、無条件で作成されるスタックです。
DashboardStack の作成条件
DashboardStack は、モニタリング用のダッシュボードの有効化 を行うと作成されます。
パラメータ例として、packages/cdk/parameter.ts
に以下を設定します。
dev: {
dashboard: true,
}
次回はこの 6 つのスタックをもう少し深堀りしていきます。
(参考) GenU のバックエンド (CDK) 詳細解説投稿一覧
- ①AWS CDK のセットアップ
- ②AWS CDK の動作確認
- ③GenU の概要
- ④GenU CDK スタックの概要
- ⑤CloudFrontWafStack スタックの解説
- ⑥RagKnowledgeBaseStack スタックの解説
- ⑦WebSearchAgentStack スタックの解説
- ⑧GuardrailStack スタックの解説
- ⑨GenerativeAiUseCasesStack > Auth スタックの解説
- ⑩GenerativeAiUseCasesStack > Database, Api スタックの解説
- ⑪GenerativeAiUseCasesStack > CommonWebAcl, Web, Rag スタックの解説
- ⑫GenerativeAiUseCasesStack > RagKnowledgeBase, UseCaseBuilder, Transcribe スタックの解説
- ⑬DashBoard スタックの解説
- ⑭GenU の Outputs の解説