0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GenUのバックエンド (CDK) 詳細解説 ④GenU CDKスタックの概要

Last updated at Posted at 2025-03-16

はじめに

皆さん、こんにちは。

私は業務でデータ利活用基盤を取り扱っているため、dbtIceberg、そしてAWS GenUに取り組む必要があると考えています。特に AWS Japan Top Engineer として、GenUを扱い、その活用を広めることが責務だと感じています。

しかし、私はこれまで CloudFormation を好んで使っており、(逆張り思考も重なって)Cfn テンプレートをシンプルかつ汎用性・拡張性の高い形で作ることに注力してきました。そのため、改めてGenU の CDK コードを読もうとしても、なかなか理解が進みませんでした。

そこで、CDK を学びながら、その過程を記事としてまとめることにしました。

前回までのおさらい

前回までで、以下が完了しました。

今回は GenU 内の CDK スタックを確認していきたいと思います。

GenU アーキテクチャについて

2025/3/16 現在、クイックスタートに記載されているアーキテクチャは以下の通りです。

image.png

このアーキテクチャを 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

この実行コマンドは前回確認した通り、以下の通りです。

package.json
{
  "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 を確認します。

packages/cdk/package.json
{
  "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

image.png

スタックはGenerativeAiUseCasesStackの 1 つのみで、依存関係はないようです。

GenU の CDK スタックの確認

それでは、CDK ソースコードを読んでいきます。
なお、この記事に記載のコードは、あくまでもこの記事の執筆時点(2025/3/17)のもの であることにご留意ください。
まずは packages/cdk/cdk.json を確認します。

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 を確認します。

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 に以下を設定します。

packages/cdk/parameter.ts
  dev: {
    allowedIpV4AddressRanges: ["192.168.0.0/24"],
    allowedIpV6AddressRanges: ["2001:0db8::/32"],
    allowedCountryCodes: ["JP"]
  }
packages/cdk/parameter.ts
  dev: {
    hostName: 'genai',
    domainName: 'example.com',
    hostedZoneId: 'Z0123456789ABCDEFGHIJ',
  }

RagKnowledgeBaseStack の作成条件

RagKnowledgeBaseStack は、RAG チャット (Knowledge Base) ユースケースの有効化 を行うと作成されます。

パラメータ例として、packages/cdk/parameter.ts に以下を設定します。

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 に以下を設定します。

packages/cdk/parameter.ts
  dev: {
    agentEnabled: true,
  }

GuardrailStack の作成条件

GuardrailStack は、ガードレール を適用すると作成されます。

パラメータ例として、packages/cdk/parameter.ts に以下を設定します。

packages/cdk/parameter.ts
  dev: {
    guardrailEnabled: true,
  }

GenerativeAiUseCasesStack の作成条件

GenerativeAiUseCasesStack は唯一、無条件で作成されるスタックです。

DashboardStack の作成条件

DashboardStack は、モニタリング用のダッシュボードの有効化 を行うと作成されます。

パラメータ例として、packages/cdk/parameter.ts に以下を設定します。

packages/cdk/parameter.ts
  dev: {
    dashboard: true,
  }

次回はこの 6 つのスタックをもう少し深堀りしていきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?