メインコンテンツまでスキップ
最新1mo ago

DynamoDBテーブルセットアップ(IaC)

Amazon DynamoDBテーブルの作成、デプロイ、管理に関する包括的なリファレンス。TypeScript(AWS CDK)、CloudFormation、およびスキーマ検出用のAWS Glueを使用したインフラストラクチャアズコード(IaC)について説明します。


目次

  1. DynamoDBコア概念

  2. キースキーマ設計の基礎

  3. キャパシティモードと請求

  4. セカンダリインデックス(GSIおよびLSI)

  5. AWS CDK(TypeScript)を使用したDynamoDBテーブルの作成

  6. CloudFormation(YAML)を使用したDynamoDBテーブルの作成

  7. コンソールからコードへ:手動設定をIaCに変換する

  8. エンドツーエンドデプロイメントワークフロー

  9. AWS Glue:DynamoDBのスキーマ検出

  10. 本番環境のベストプラクティス

  11. 参照リンク


DynamoDBコア概念

Amazon DynamoDBは、任意のスケールで一ケタミリ秒のパフォーマンスを実現するように設計された、完全マネージド型のNoSQL キー値およびドキュメントデータベースです。リレーショナルデータベースとは異なり、DynamoDBはスキーマレスです。テーブル作成時に定義する必要があるのはプライマリキー属性のみで、他のすべての属性はアイテムごとに異なる場合があります。

データモデルの階層構造

概念説明
テーブルアイテムのコレクション。リレーショナルデータベースの「テーブル」に相当します。
アイテムテーブル内の単一のデータレコード。「行」に相当します。各アイテムはプライマリキーによって一意に識別されます。
属性アイテム内の基本的なデータ要素。「列」に相当します。属性は、スカラー(文字列、数値、バイナリ)、ドキュメント(リスト、マップ)、またはセット型である場合があります。

サポートされている属性タイプ

タイプコードタイプ
S文字列"Hello"
N数値"42" または "3.14"
BバイナリBase64エンコードされたバイナリデータ
BOOLブール値true / false
NULLNulltrue
Lリスト["a", 1, true]
Mマップ{"name": "John", "age": 30}
SS文字列セット["a", "b", "c"]
NS数値セット["1", "2", "3"]
BSバイナリセットバイナリ値のセット

注: SN、および B タイプのみ、プライマリキー属性およびインデックスキー属性に使用できます。


キースキーマ設計の基礎

すべてのDynamoDBテーブルには、テーブル作成時に定義されるプライマリキーが必要です。2つのタイプがあります。

シンプルプライマリキー(パーティションキーのみ)

各アイテムを一意に識別する単一の属性。DynamoDBはパーティションキーの値を内部ハッシュ関数への入力として使用して、アイテムが保存される物理パーティションを決定します。

┌─────────────────────────────────┐
│ Table: Users │
│ Partition Key: user_id (S) │
├─────────────────────────────────┤
│ user_id = "u-001" → Partition A │
│ user_id = "u-002" → Partition B │
│ user_id = "u-003" → Partition A │
└─────────────────────────────────┘

複合プライマリキー(パーティションキー+ソートキー)

2つの属性がまとめてプライマリキーを構成します。複数のアイテムが同じパーティションキーを共有できますが、パーティション内の各アイテムは一意のソートキーを持つ必要があります。同じパーティションキーを持つアイテムはまとめて保存され、ソートキー値でソートされます。

┌───────────────────────────────────────────────────┐
│ Table: Orders │
│ Partition Key: customer_id (S) │
│ Sort Key: order_date (S) │
├───────────────────────────────────────────────────┤
│ customer_id = "c-100", order_date = "2025-01-15" │
│ customer_id = "c-100", order_date = "2025-03-22" │ ← 同じパーティション
│ customer_id = "c-200", order_date = "2025-02-10" │ ← 異なるパーティション
└───────────────────────────────────────────────────┘

キー設計のヒント

  • 高カーディナリティのパーティションキーはデータをパーティション全体にわたってより均等に分散し、ホットパーティションを回避します。

  • 複合ソートキー(例:STATUS#2025-01-15)を使用して、範囲クエリと階層的なデータモデルを実現します。

  • アクセスパターンに基づいて最初にキーを設計します。エンティティの関係ではなく。


キャパシティモードと請求

DynamoDBは2つのキャパシティモードを提供します。テーブル作成時にモードを選択し、後で(24時間ごとに1回)モード間を切り替えることができます。

オンデマンドモード(PAY_PER_REQUEST

  • キャパシティプランニングは不要です。DynamoDBは自動的にスケーリングします。

  • 読み取り/書き込みリクエストごとに支払います。

  • 予測不可能なワークロード、新しいテーブル、またはスパイクトラフィックに最適です。

  • トラフィックがアカウントレベルのスループットクォータを超えない限り、スロットリングはありません。

プロビジョニングモード(PROVISIONED

  • 読み取りキャパシティユニット(RCU)と書き込みキャパシティユニット(WCU)を指定します。

  • 1 RCU = 4 KBまでのアイテムに対する強力な一貫性のある読み取り/秒。

  • 1 WCU = 1 KBまでのアイテムに対する書き込み/秒。

  • 通常、オートスケーリングと組み合わせて、利用率に基づいてキャパシティを調整します。

  • 通常、予測可能で安定したワークロードの場合、コスト効率が優れています。

要因オンデマンドプロビジョニング
コストモデルリクエストごとの料金予約キャパシティの時間単価
スケーリング自動、即座手動またはオートスケーリング経由
最適な用途予測不可能なトラフィック安定した予測可能なトラフィック
キャパシティプランニング不要RCU/WCUを推定する必要があります

セカンダリインデックス(GSIおよびLSI)

セカンダリインデックスを使用すると、テーブルのプライマリキー以外の属性を使用してデータをクエリできます。

グローバルセカンダリインデックス(GSI)

  • ベーステーブルとは異なるパーティションキーとソートキーを持つことができます。

  • テーブル作成後に追加または削除できます。

  • 独自のプロビジョニングスループットを持ちます(プロビジョニングモード)。

  • 結果整合性のある読み取りのみ。

  • テーブルごとに最大20個のGSI。

ローカルセカンダリインデックス(LSI)

  • ベーステーブルと同じパーティションキーを共有しますが、異なるソートキーを持ちます。

  • テーブル作成時に作成する必要があります。後で追加することはできません。

  • 強力な一貫性と結果整合性のある読み取りの両方をサポートします。

  • テーブルごとに最大5個のLSI。

  • LSIを含むテーブルのパーティションキーあたりの上限は10 GB。

プロジェクションタイプ

インデックスを作成する場合、インデックスにプロジェクト(コピー)する属性を選択します。

プロジェクションタイプ説明
KEYS_ONLYテーブルキーとインデックスキーのみがプロジェクションされます。最も安いストレージ。
INCLUDEキーに加えて、指定した特定の非キー属性。
ALLすべての属性がプロジェクションされます。最も柔軟ですが、ストレージコストが最も高い。

AWS CDK(TypeScript)を使用したDynamoDBテーブルの作成

AWS CDK(Cloud Development Kit)を使用すると、使い慣れたプログラミング言語を使用してクラウドインフラストラクチャを定義できます。aws-cdk-lib/aws-dynamodb モジュールはDynamoDBの高レベルコンストラクトを提供します。

前提条件


# Node.jsがインストールされていることを確認します(v18以上推奨)
node -v

# AWS CDKをグローバルにインストールします
npm install -g aws-cdk

# CDKバージョンを確認します
cdk --version

# AWS認証情報が設定されていることを確認します
aws sts get-caller-identity

プロジェクトセットアップ


# 新しいCDKプロジェクトを作成します
mkdir dynamodb-cdk && cd dynamodb-cdk
cdk init app --language=typescript

# 依存関係をインストールします(aws-cdk-libにはDynamoDBコンストラクトが含まれています)
npm install aws-cdk-lib constructs

例1:オンデマンド課金を使用した基本的なテーブル

// lib/dynamodb-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';

export class DynamoDbStack extends cdk.Stack {
public readonly usersTable: dynamodb.Table;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

this.usersTable = new dynamodb.Table(this, 'UsersTable', {
tableName: 'Users',
partitionKey: {
name: 'user_id',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY, // 本番環境ではRETAINを使用
});

// テーブル名を出力
new cdk.CfnOutput(this, 'TableName', {
value: this.usersTable.tableName,
});
}
}

例2:ソートキー付きの複合キー

const ordersTable = new dynamodb.Table(this, 'OrdersTable', {
tableName: 'Orders',
partitionKey: {
name: 'customer_id',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'order_date',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.RETAIN,
pointInTimeRecovery: true, // PITRバックアップを有効化
});

例3:グローバルセカンダリインデックス付きテーブル

const productsTable = new dynamodb.Table(this, 'ProductsTable', {
tableName: 'Products',
partitionKey: {
name: 'product_id',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'created_at',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});

// GSI 1:カテゴリと価格で製品をクエリ
productsTable.addGlobalSecondaryIndex({
indexName: 'CategoryPriceIndex',
partitionKey: {
name: 'category',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'price',
type: dynamodb.AttributeType.NUMBER,
},
projectionType: dynamodb.ProjectionType.ALL,
});

// GSI 2:売り手で製品をクエリ(軽量検索のためキーのみ)
productsTable.addGlobalSecondaryIndex({
indexName: 'SellerIndex',
partitionKey: {
name: 'seller_id',
type: dynamodb.AttributeType.STRING,
},
projectionType: dynamodb.ProjectionType.KEYS_ONLY,
});

例4:ローカルセカンダリインデックス付きテーブル

const messagesTable = new dynamodb.Table(this, 'MessagesTable', {
tableName: 'Messages',
partitionKey: {
name: 'conversation_id',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'timestamp',
type: dynamodb.AttributeType.NUMBER,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});

// LSI:会話内の送信者でメッセージをクエリ
// 注:LSIはテーブル作成時に定義される必要があります
messagesTable.addLocalSecondaryIndex({
indexName: 'SenderIndex',
sortKey: {
name: 'sender_id',
type: dynamodb.AttributeType.STRING,
},
projectionType: dynamodb.ProjectionType.ALL,
});

例5:オートスケーリング付きプロビジョニング容量

const sessionsTable = new dynamodb.Table(this, 'SessionsTable', {
tableName: 'Sessions',
partitionKey: {
name: 'session_id',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PROVISIONED,
readCapacity: 100,
writeCapacity: 50,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});

// 読み取りキャパシティを100~5000 RCUの間でオートスケール
const readScaling = sessionsTable.autoScaleReadCapacity({
minCapacity: 100,
maxCapacity: 5000,
});
readScaling.scaleOnUtilization({
targetUtilizationPercent: 70,
scaleInCooldown: cdk.Duration.minutes(1),
scaleOutCooldown: cdk.Duration.minutes(1),
});

// 書き込みキャパシティを50~2000 WCUの間でオートスケール
const writeScaling = sessionsTable.autoScaleWriteCapacity({
minCapacity: 50,
maxCapacity: 2000,
});
writeScaling.scaleOnUtilization({
targetUtilizationPercent: 70,
});

例6:DynamoDBストリームとTTL

const eventsTable = new dynamodb.Table(this, 'EventsTable', {
tableName: 'Events',
partitionKey: {
name: 'event_id',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'timestamp',
type: dynamodb.AttributeType.NUMBER,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
timeToLiveAttribute: 'ttl', // TTLが期限切れのアイテムは自動削除
removalPolicy: cdk.RemovalPolicy.DESTROY,
});

例7:カスタマー管理KMSキーを使用した暗号化

import * as kms from 'aws-cdk-lib/aws-kms';

const encryptionKey = new kms.Key(this, 'DynamoDbKey', {
description: 'DynamoDB暗号化用のKMSキー',
enableKeyRotation: true,
});

const sensitiveTable = new dynamodb.Table(this, 'SensitiveDataTable', {
tableName: 'SensitiveData',
partitionKey: {
name: 'record_id',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED,
encryptionKey: encryptionKey,
pointInTimeRecovery: true,
removalPolicy: cdk.RemovalPolicy.RETAIN,
contributorInsightsEnabled: true, // CloudWatchコントリビューターインサイトを有効化
});

// コスト追跡用にタグを追加
cdk.Tags.of(sensitiveTable).add('Environment', 'production');
cdk.Tags.of(sensitiveTable).add('Team', 'backend');

例8:グローバルテーブル(マルチリージョンレプリケーション)

グローバルテーブルの場合は、新しいプロジェクトの推奨アプローチである TableV2 コンストラクトを使用します。

import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

// スタックはグローバルテーブルに対して定義されたリージョンを持つ必要があります
const stack = new cdk.Stack(app, 'GlobalTableStack', {
env: { region: 'us-west-2' },
});

const globalTable = new dynamodb.TableV2(stack, 'GlobalTable', {
tableName: 'GlobalUsers',
partitionKey: {
name: 'pk',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'sk',
type: dynamodb.AttributeType.STRING,
},
billing: dynamodb.Billing.onDemand(),
replicas: [
{ region: 'us-east-1' },
{ region: 'eu-west-1' },
],
});

IAM権限の付与

CDKは、テーブルへのアクセスを管理するための便利な付与メソッドを提供します。

import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';

declare const myFunction: lambda.Function;

// Lambda関数に読み取り/書き込みアクセス権限を付与
usersTable.grantReadWriteData(myFunction);

// またはより詳細な権限
usersTable.grantReadData(myFunction); // 読み取り専用
usersTable.grantWriteData(myFunction); // 書き込み専用
usersTable.grant(myFunction, 'dynamodb:Query'); // 特定のアクション

アプリエントリーポイント

// bin/app.ts
import * as cdk from 'aws-cdk-lib';
import { DynamoDbStack } from '../lib/dynamodb-stack';

const app = new cdk.App();

new DynamoDbStack(app, 'DynamoDbStack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});


CloudFormation(YAML)を使用したDynamoDBテーブルの作成

CDKよりも宣言的なYAML/JSONテンプレートを使用する場合は、AWS CloudFormationを直接使用できます。

例1:シンプルなテーブル

AWSTemplateFormatVersion: '2010-09-09'
Description: オンデマンド課金を使用したDynamoDBテーブル

Resources:
UsersTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
TableName: Users
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: user_id
AttributeType: S
KeySchema:
- AttributeName: user_id
KeyType: HASH
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true

Outputs:
TableName:
Value: !Ref UsersTable
TableArn:
Value: !GetAtt UsersTable.Arn

例2:GSIおよびプロビジョニングスループット付きテーブル

AWSTemplateFormatVersion: '2010-09-09'
Description: GSIおよびオートスケーリング付きDynamoDBテーブル

Resources:
OrdersTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
Properties:
TableName: Orders
AttributeDefinitions:
- AttributeName: customer_id
AttributeType: S
- AttributeName: order_date
AttributeType: S
- AttributeName: status
AttributeType: S
KeySchema:
- AttributeName: customer_id
KeyType: HASH
- AttributeName: order_date
KeyType: RANGE
GlobalSecondaryIndexes:
- IndexName: StatusDateIndex
KeySchema:
- AttributeName: status
KeyType: HASH
- AttributeName: order_date
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
TimeToLiveSpecification:
AttributeName: ttl
Enabled: true

CloudFormationスタックのデプロイ


# スタックを作成
aws cloudformation create-stack \
--stack-name my-dynamodb-stack \
--template-body file://template.yaml

# スタックを更新
aws cloudformation update-stack \
--stack-name my-dynamodb-stack \
--template-body file://template.yaml

# スタックを削除
aws cloudformation delete-stack \
--stack-name my-dynamodb-stack

重要: テンプレートに複数のセカンダリインデックスを持つDynamoDBテーブルが含まれている場合、それらが順序どおりに作成されるように、DependsOn 関係を宣言する必要があります。DynamoDBは、セカンダリインデックスを持つテーブルの数を CREATING 状態で同時に制限しています。


コンソールからコードへ:手動設定をIaCに変換する

AWSはコンソールからコードと呼ばれる機能(Amazon Q Developerを搭載)を提供し、DynamoDBコンソールの手動アクション(再利用可能なインフラストラクチャコードに変換)をキャプチャします。

仕組み

  1. コンソールでプロトタイプを作成 — DynamoDBコンソールを使用してテーブルを作成し、目的の設定(パーティションキー、ソートキー、スループット、インデックスなど)で設定します。

  2. アクションを記録 — コンソールからコードは、実行する構成アクションを記録します。

  3. コードを生成 — ツールは生成AIを使用して、コンソールアクションを優先形式のコードに変換します。

  4. カスタマイズしてデプロイ — 生成されたコードをコピーまたはダウンロードし、本番環境に合わせて調整します。

サポートされている出力形式

  • TypeScript、Python、JavaのAWS CDK

  • YAML または JSONのCloudFormation

コンソールからコードの開始方法

  1. AWS管理コンソールにサインインします。

  2. https://console.aws.amazon.com/dynamodbv2/ でDynamoDBコンソールを開きます。

  3. コンソール経由でDynamoDBリソースの作成または変更を開始します。

  4. コンソールからコードパネルを使用してアクションのコードを生成します。

  5. 生成されたコードをコピーまたはダウンロードします。 この機能はすべての商用AWSリージョンで利用可能です。詳細な手順については、Amazon Q Developer ユーザーガイドのコンソールからコードを参照してください。

参考資料


エンドツーエンドデプロイメントワークフロー

このセクションでは、TypeScriptを使用したAWS CDKからDynamoDBテーブルをデプロイする方法を説明しています。

ステップ1:AWSのブートストラップ

CDKは、CDKがデプロイするために必要なリソース(資産用S3バケット、IAMロールなど)をプロビジョニングするために、アカウント/リージョンごとに1回限りのブートストラップが必要です。

cdk bootstrap aws://ACCOUNT_ID/REGION

# 例:
cdk bootstrap aws://123456789012/us-east-1

ステップ2:CDKプロジェクトを初期化

mkdir my-dynamodb-app && cd my-dynamodb-app
cdk init app --language=typescript

ステップ3:スタックを定義

lib/my-dynamodb-app-stack.ts を編集してください。

import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';

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

// DynamoDBテーブルを作成
const table = new dynamodb.Table(this, 'MyAppTable', {
tableName: 'MyAppData',
partitionKey: {
name: 'pk',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'sk',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
pointInTimeRecovery: true,
timeToLiveAttribute: 'ttl',
});

// タイプと日付でクエリするためのGSIを追加
table.addGlobalSecondaryIndex({
indexName: 'GSI1',
partitionKey: {
name: 'GSI1PK',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'GSI1SK',
type: dynamodb.AttributeType.STRING,
},
projectionType: dynamodb.ProjectionType.ALL,
});

// 出力
new cdk.CfnOutput(this, 'TableNameOutput', {
value: table.tableName,
exportName: 'MyAppTableName',
});

new cdk.CfnOutput(this, 'TableArnOutput', {
value: table.tableArn,
exportName: 'MyAppTableArn',
});
}
}

ステップ4:CloudFormationテンプレートを合成


# 生成されたCloudFormationテンプレートをプレビュー
cdk synth

これは CloudFormation YAMLを標準出力に出力し、cdk.out/ に書き込みます。

ステップ5:既存インフラストラクチャとの差分


# 行われる変更を確認
cdk diff

ステップ6:デプロイ


# スタックをデプロイ
cdk deploy

# 特定のAWSプロファイルでデプロイ
cdk deploy --profile my-profile

# 確認プロンプトなしでデプロイ
cdk deploy --require-approval never

ステップ7:検証


# テーブルが存在することを確認
aws dynamodb describe-table --table-name MyAppData

# CloudFormationの出力からテーブル名を取得
aws cloudformation describe-stacks \
--stack-name MyDynamodbAppStack \
--query 'Stacks[0].Outputs'

ステップ8:クリーンアップ


# スタックを破棄(removalPolicyがDESTROYの場合のみ機能)
cdk destroy

デプロイメントフロー図

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│ TypeScript │ │ CloudFormation│ │ AWS │
│ CDK Code │────▶│ Template │────▶│ Resources │
│ (lib/*.ts) │ │ (cdk.out/) │ │ (DynamoDB) │
└──────────────┘ └──────────────┘ └──────────────┘
cdk synth cdk deploy ライブテーブル


AWS Glue:DynamoDBのスキーマ検出

AWS Glueは、DynamoDBテーブルのスキーマを自動的に検出してカタログ化できます。これは分析、Athenaを使用したDynamoDBデータのクエリ、またはテーブル構造のドキュメント化に便利です。

Glueクローラーとは

AWS Glueクローラーは、データストア(DynamoDBなど)に接続し、アイテムをスキャンして、スキーマ(列名、データ型)を推論し、メタデータをAWS Glueデータカタログに書き込みます。データカタログテーブルは、Amazon Athena、Redshift Spectrum、Glue ETLジョブなどのサービスで使用できます。

Glueがどのようにして DynamoDBをクロール

Glueクローラーが DynamoDBテーブルに対して実行されると、Scan 操作を実行し、最初の1 MBのデータ(データサンプリング)を読み取ってスキーマを推論します。テーブルが複数のアイテムにわたってスキーマが大きく異なる場合は、データサンプリングを無効にして、クローラーが正確な結果を得るためにテーブル全体をスキャンするようにします。

CDKを使用したDynamoDB用Glueクローラーの設定

次は、DynamoDBテーブルを作成し、カスタムリソースを使用してサンプルデータを入力し、スキーマ検出用のGlueクローラーを設定する完全な例です。

// lib/glue-dynamodb-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as glue from 'aws-cdk-lib/aws-glue';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

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

// ── 1. DynamoDBテーブルを作成 ──
const productTable = new dynamodb.Table(this, 'ProductCatalog', {
tableName: 'ProductCatalog',
partitionKey: {
name: 'product_id',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'category',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});

// ── 2. Glueデータベースを作成 ──
const glueDatabase = new glue.CfnDatabase(this, 'GlueDatabase', {
catalogId: this.account,
databaseInput: {
name: 'dynamodb_catalog',
description: 'Glueカタログ for DynamoDBテーブルスキーマ',
},
});

// ── 3. クローラー用IAMロールを作成 ──
const crawlerRole = new iam.Role(this, 'GlueCrawlerRole', {
assumedBy: new iam.ServicePrincipal('glue.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWSGlueServiceRole'
),
],
});

// クローラーにDynamoDBテーブルへの読み取りアクセス権限を付与
productTable.grantReadData(crawlerRole);

// ── 4. Glueクローラーを作成 ──
const crawler = new glue.CfnCrawler(this, 'DynamoDbCrawler', {
name: 'product-catalog-crawler',
role: crawlerRole.roleArn,
databaseName: 'dynamodb_catalog',
targets: {
dynamoDbTargets: [
{
path: productTable.tableName,
},
],
},
schemaChangePolicy: {
updateBehavior: 'UPDATE_IN_DATABASE',
deleteBehavior: 'LOG',
},
schedule: {
// 毎日UTC午前2時に実行
scheduleExpression: 'cron(0 2 * * ? *)',
},
});

crawler.addDependency(glueDatabase);

// ── 5. 出力 ──
new cdk.CfnOutput(this, 'CrawlerName', {
value: crawler.name!,
});

new cdk.CfnOutput(this, 'GlueDatabaseName', {
value: 'dynamodb_catalog',
});
}
}

クローラーを手動で実行

スタックをデプロイした後、クローラーを実行してスキーマを検出します。


# クローラーを起動
aws glue start-crawler --name product-catalog-crawler

# クローラーのステータスを確認
aws glue get-crawler --name product-catalog-crawler \
--query 'Crawler.State'

# 完了後、検出されたテーブルスキーマを表示
aws glue get-table \
--database-name dynamodb_catalog \
--name productcatalog

Athenaでスキーマを表示

クローラーがカタログテーブルを作成した後、スキーマメタデータをクエリできます。

-- Athenaで 'dynamodb_catalog' データベースを選択
-- クローラーはDynamoDBテーブル名に一致するテーブルを作成

-- テーブルメタデータを表示
SHOW CREATE TABLE productcatalog;

-- データをクエリ(AthenaのDynamoDBコネクタが必要)
SELECT * FROM productcatalog LIMIT 10;

Glueクローラースキーマ出力の例

クローラーが実行された後、Glueデータカタログテーブルには次のようなスキーマ情報が含まれます。

列名データ型コメント
product_idstringパーティションキー
categorystringソートキー
namestringデータから推測
pricedoubleデータから推測
in_stockbooleanデータから推測
tagsarray\\<string>データから推測
metadatastruct<...>ネストされたマップから推測

Glueクローラー設定オプション

設定オプション説明
UpdateBehaviorUPDATE_IN_DATABASELOGスキーマ変更が検出されたときの動作
DeleteBehaviorDELETE_FROM_DATABASELOGDEPRECATE_IN_DATABASEテーブルが検出されなくなったときの動作
RecrawlPolicyCRAWL_EVERYTHINGCRAWL_NEW_FOLDERS_ONLY各実行で再検査されるデータを制御

本番環境のベストプラクティス

テーブル設計

  • 本番環境のテーブルに RETAIN 削除ポリシーを使用 — 実データを含むテーブルで DESTROY を使用しないでください。

  • ポイントインタイムリカバリ(PITR)を有効化して継続的なバックアップを実現します。

  • 削除保護を有効化して、誤ったテーブル削除を防ぎます。

  • TTLを使用して、期限切れのデータを自動的にクリーンアップし、ストレージコストを削減します。

  • DynamoDBストリームを有効化して、イベント駆動型アーキテクチャの変更データキャプチャが必要な場合。

キャパシティとパフォーマンス

  • 新しいテーブルについてはオンデマンド課金で開始します。トラフィックパターンを理解するまで。

  • トラフィックが予測可能になったら、プロビジョニング容量とオートスケーリングに切り替えてコストを削減します。

  • ConsumedReadCapacityUnits および ConsumedWriteCapacityUnits CloudWatchメトリクスを監視します。

  • コントリビューターインサイトを有効化して、ホットパーティションキーを識別します。

セキュリティ

  • 機密テーブルにカスタマー管理KMSキーを使用して暗号化を行います。

  • IAMで最小権限の原則に従う — 広範なポリシーではなく、grantReadData() のようなCDK付与メソッドを使用します。

  • DynamoDB APIコールについて、CloudTrailロギングを有効化します。

IaCベストプラクティス

  • テーブル名をアプリケーションコードにハードコーディングしない — CloudFormationの出力またはSSMパラメータを使用します。

  • スタック出力とエクスポートを使用して、スタック間でテーブル名/ARNを共有します。

  • すべてのリソースにタグを付けるコスト配分とガバナンスのため。

  • ステートフルリソース(DynamoDB、S3)とステートレスリソース(Lambda、API Gateway)に対して別のスタックを使用して、独立して更新できます。

  • 同じスタック内に複数のテーブルとインデックスを作成する場合、LimitExceededException を回避するために DependsOn を宣言します。

CDK固有のヒント

  • グローバルテーブル機能またはマルチアカウントレプリケーションが必要な新しいテーブルには、TableV2 コンストラクトを使用します。

  • Table のデフォルト削除ポリシーは RETAIN です。これはデータを保護するためのものです。DESTROY を明示的に設定するのはdev/testテーブルのみです。

  • ローカルセカンダリインデックスはテーブル作成時にCDK経由でのみ追加でき、初期デプロイ後は追加できません。

  • オンデマンド課金からプロビジョニング課金モード(またはその逆)に切り替える場合、DynamoDBはこの切り替えを24時間ごとに1回のみ許可します。


参照リンク

AWSの公式ドキュメント

リソースURL
DynamoDB開発者ガイドhttps://docs.aws.amazon.com/amazondynamodb/latest/developerguide/
DynamoDB向けコンソールからコードhttps://docs.aws.amazon.com/amazondynamodb/latest/developerguide/console-to-code.html
CloudFormation — AWS::DynamoDB::Tablehttps://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html
CloudFormation DynamoDBスニペットhttps://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-dynamodb.html
CDK aws_dynamodb モジュールリファレンスhttps://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb-readme.html
CDK Table コンストラクトAPIhttps://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb.Table.html
AWS Glueクローラーhttps://docs.aws.amazon.com/glue/latest/dg/add-crawler.html
DynamoDBベストプラクティスhttps://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html

CDKの例とチュートリアル

リソースURL
AWS CDKの例(GitHub)https://github.com/aws-samples/aws-cdk-examples
CDKワークショップhttps://cdkworkshop.com

最終更新:2026年4月。最新のAPIの変更と機能追加について、常にAWSの最新ドキュメントを確認してください。

Related Articles