Dynamodb テーブルセットアップ (IAC)
Infrastructure as Code (IaC) を使用して Amazon DynamoDB テーブルを作成、デプロイ、管理するための包括的なリファレンス。TypeScript (AWS CDK)、CloudFormation、スキーマ検出用の AWS Glue に対応しています。
目次
-
DynamoDB コア概念
-
キースキーマ設計の基礎
-
キャパシティモード & 課金
-
セカンダリインデックス (GSI & LSI)
-
AWS CDK (TypeScript) を使用した DynamoDB テーブル作成
-
CloudFormation (YAML) を使用した DynamoDB テーブル作成
-
コンソールからコードへ: 手動設定の IaC への変換
-
エンドツーエンドデプロイメントワークフロー
-
AWS Glue: DynamoDB のスキーマ検出
-
本番環境ベストプラクティス
-
リファレンスリンク
DynamoDB コア概念
Amazon DynamoDB は、あらゆるスケールで一桁のミリ秒パフォーマンスを実現するよう設計された、フルマネージドの NoSQL キーバリューおよびドキュメントデータベースです。リレーショナルデータベースと異なり、DynamoDB はスキーマレスです。テーブル作成時に定義が必要なのはプライマリキー属性のみです。その他のすべての属性はアイテムごとに異なる可能性があります。
データモデル階層
| 概念 | 説明 |
| テーブル | アイテムの集合です。リレーショナルデータベースの「テーブル」に類似しています。 |
| アイテム | テーブル内の単一データレコードです。「行」に類似しています。各アイテムはプライマリキーによって一意に識別されます。 |
| 属性 | アイテム内の基本的なデータ要素です。「列」に類似しています。属性はスカラー (文字列、数値、バイナリ)、ドキュメント (リスト、マップ)、またはセット型です。 |
サポートされる属性型
| 型コード | 型 | 例 |
S | 文字列 | "Hello" |
N | 数値 | "42" または "3.14" |
B | バイナリ | Base64 エンコード済みバイナリデータ |
BOOL | ブール値 | true / false |
NULL | Null | true |
L | リスト | ["a", 1, true] |
M | マップ | {"name": "John", "age": 30} |
SS | 文字列セット | ["a", "b", "c"] |
NS | 数値セット | ["1", "2", "3"] |
BS | バイナリセット | バイナリ値のセット |
注:
S、N、およびB型のみプライマリキー属性およびインデックスキー属性に使用できます。
キースキーマ設計の基礎
すべての DynamoDB テーブルは、作成時に定義されるプライマリキーが必要です。2 つのタイプがあります:
シンプルプライマリキー (パーティションキーのみ)
各アイテムを一意に識別する単一の属性です。DynamoDB はパーティションキーの値をした内部ハッシュ関数への入力として使用して、アイテムが保存される物理パーティションを決定します。
┌─────────────────────────────────┐
│ テーブル: Users │
│ パーティションキー: user_id (S) │
├─────────────────────────────────┤
│ user_id = "u-001" → パーティション A │
│ user_id = "u-002" → パーティション B │
│ user_id = "u-003" → パーティション A │
└─────────────────────────────────┘
コンポジットプライマリキー (パーティションキー + ソートキー)
2 つの属性が一緒にプライマリキーを構成します。複数のアイテムは同じパーティションキーを共有できますが、パーティション内の各アイテムは一意のソートキーを持つ必要があります。同じパーティションキーを持つアイテムは一緒に保存され、ソートキーの値でソートされます。
┌───────────────────────────────────────────────────┐
│ テーブル: Orders │
│ パーティションキー: customer_id (S) │
│ ソートキー: 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 回の強い一貫性のあるリード/秒。
-
1 WCU = 最大 1 KB のアイテムに対して 1 回のライト/秒。
-
通常、利用状況に基づいて容量を調整するオートスケーリングとペアになります。
-
予測可能で安定したワークロードにはより費用効果的です。
| 要因 | オンデマンド | プロビジョニング |
| コストモデル | リクエストごとの課金 | 予約容量の時間単位の課金 |
| スケーリング | 自動、即座 | 手動または Auto Scaling 経由 |
| 最適な用途 | 予測不可能なトラフィック | 安定した予測可能なトラフィック |
| 容量計画 | 不要 | 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 コンソール内での手動アクション を再利用可能なインフラストラクチャコードに変換します。
仕組み
-
コンソールでプロトタイプを作成します — DynamoDB コンソールを使用してテーブルを作成および構成し、目的の設定 (パーティションキー、ソートキー、スループット、インデックスなど) を行います。
-
アクションを記録します — コンソール から コード は、実行するとこれらの構成アクションを記録します。
-
コードを生成します — このツールは生成 AI を使用して、コンソールアクションを希望の形式のコードに変換します。
-
カスタマイズしてデプロイします — 生成されたコードをコピーまたはダウンロードし、本番環境向けに適応させます。
サポートされている出力形式
-
TypeScript、Python、Java の AWS CDK
-
YAML または JSON の CloudFormation
コンソールからコードの使用を開始します
-
AWS Management Console にサインインします。
-
DynamoDB コンソール
https://console.aws.amazon.com/dynamodbv2/を開きます。 -
コンソール経由で DynamoDB リソースの作成または変更を開始します。
-
コンソール からコード パネルを使用してアクション用のコードを生成します。
-
生成されたコードをコピーまたはダウンロードします。 この機能は、すべてのコマーシャル AWS リージョンで利用可能です。詳細な手順については、Amazon Q Developer ユーザーガイドの「コンソール からコード」を参照してください。
リファレンス
-
AWS ドキュメンテーション: コンソール からコード を使用して DynamoDB のインフラストラクチャコードを生成
-
Amazon Q Developer: コンソール からコード を使用して AWS サービスを自動化
エンドツーエンドデプロイメントワークフロー
このセクションでは、TypeScript を使用した AWS CDK で DynamoDB テーブルをゼロからデプロイする手順を説明します。
ステップ 1: AWS 環境をブートストラップします
CDK では、アカウント/リージョンごとに 1 回のブートストラップが必要です。CDK がデプロイに必要なリソース (資産用 S3 バケット、IAM ロールなど) をプロビジョニングします:
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 を stdout に出力し、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 コード │────▶│ テンプレート │────▶│ リソース │
│ (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: 'DynamoDB テーブルスキーマ用の Glue カタログ',
},
});
// ── 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 AM に実行します
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_id | string | パーティションキー |
category | string | ソートキー |
name | string | データから推測 |
price | double | データから推測 |
in_stock | boolean | データから推測 |
tags | array<string> | データから推測 |
metadata | struct<...> | ネストされたマップから推測 |
Glue クローラー設定オプション
| 設定 | オプション | 説明 |
UpdateBehavior | UPDATE_IN_DATABASE, LOG | スキーマ変更が検出されたときに実行します |
DeleteBehavior | DELETE_FROM_DATABASE, LOG, DEPRECATE_IN_DATABASE | テーブルが検出されなくなったときに実行します |
RecrawlPolicy | CRAWL_EVERYTHING, CRAWL_NEW_FOLDERS_ONLY | 各実行時に再検査するデータを制御します |
本番環境ベストプラクティス
テーブル設計
-
本番テーブルには
RETAIN削除ポリシーを使用してください。実データを含むテーブルに対してDESTROYを使用しないでください。 -
Point-in-Time Recovery (PITR) を有効にして継続的なバックアップを取得してください。
-
削除保護を有効にして、テーブルの誤削除を防止してください。
-
TTL を使用して期限切れデータを自動的にクリーンアップし、ストレージコストを削減します。
-
変更データキャプチャがイベント駆動アーキテクチャに必要な場合は、DynamoDB ストリームを有効にしてください。
キャパシティ & パフォーマンス
-
トラフィックパターンを理解するまで、新しいテーブルにはオンデマンド課金で開始してください。
-
トラフィックが予測可能になったら、コストを削減するためにプロビジョニング容量とオートスケーリングに切り替えてください。
-
ConsumedReadCapacityUnits および ConsumedWriteCapacityUnits CloudWatch メトリクスを監視してください。
-
ホットパーティションキーを識別するために、貢献度インサイトを有効にしてください。
セキュリティ
-
機密テーブルにはカスタマー管理 KMS キーを使用して暗号化してください。
-
IAM で最小権限の原則に従ってください。広いポリシーではなく、
grantReadData()などの CDK 付与メソッドを使用してください。 -
DynamoDB API 呼び出しのCloudTrail ロギングを有効にしてください。
IaC ベストプラクティス
-
アプリケーションコードにテーブル名をハードコーディングしないでください。CloudFormation 出力または SSM パラメータを使用してください。
-
スタック出力とエクスポートを使用してスタック間でテーブル名/ARN を共有してください。
-
すべてのリソースにタグを付けて、コスト割り当てとガバナンスを行ってください。
-
ステートレスリソース (Lambda、API Gateway) とは独立して更新できるように、ステートフルリソース (DynamoDB、S3) には別のスタックを使用してください。
-
同じスタックで複数のインデックスを持つ複数のテーブルを作成する場合は、
LimitExceededExceptionを回避するためにDependsOnを宣言してください。
CDK 固有のヒント
-
グローバルテーブル機能またはマルチアカウントレプリケーションが必要な新しいテーブルには、
TableV2コンストラクトを使用してください。 -
Tableのデフォルト削除ポリシーはRETAINです。これはデータを保護するためです。dev/test テーブルにのみ明示的にDESTROYを設定してください。 -
ローカルセカンダリインデックスは 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::Table | https://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 コンストラクト API | https://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 ドキュメンテーションで確認してください。