S3 TablesがCloudFormation/CDKに完全対応 — テーブルバケットからAthenaクエリまで一気に試してみた
S3 TablesのCloudFormation/CDKサポートが強化され、テーブルバケットに加えてテーブルとネームスペースもIaCで管理できるようになりました(2025年8月28日 AWS What’s New)。
S3 Tablesは2024年12月のre:Inventで発表された、Apache Icebergネイティブのテーブルストレージです。構造化データ向けに最適化されたバケットタイプ(テーブルバケット)を提供し、コンパクションやスナップショット管理が自動化されています。自分も発表時から気になっていたサービスですが、IaCで管理できない部分が多く手を出しにくい状態でした。今回のアップデートでようやくCloudFormationのみでテーブルバケット・ネームスペース・テーブルの一式をデプロイできるようになったので、実際に試してみました。
S3 Tablesとは何か
通常のS3が「ファイル置き場」であるのに対し、S3 Tablesは構造化データ専用のストレージです。内部的にはApache Icebergフォーマットでデータを保持しており、Athena・Redshift・EMR・Sparkからクエリできます。
AWS公式には以下のように記載されています(S3 Tables ユーザーガイド)。
Amazon S3 Tables deliver up to 3x faster query throughput and up to 10x higher transactions per second compared to self-managed Apache Iceberg tables stored in Amazon S3 general purpose buckets.
セルフマネージドのIcebergテーブルと比較して、最大3倍のクエリスループットと10倍のTPSが得られるとのことです。
通常のS3との違い
| 通常のS3 | S3 Tables | |
|---|---|---|
| データモデル | 非構造化オブジェクト | 構造化テーブルデータ(Iceberg) |
| テーブルメンテナンス | 手動(Glueジョブ等) | 自動(コンパクション、スナップショット管理、孤立ファイル削除) |
| アクセス制御 | バケット/プレフィックス単位 | テーブル/ネームスペース/バケット単位 |
| パブリックアクセス | 設定可能 | 常にブロック(無効化不可) |
| ストレージ料金 | $0.023/GB | $0.0265/GB(約15%高い) |
リソースの階層構造はテーブルバケット > ネームスペース > テーブルの3層です。
自動メンテナンス
S3 Tablesの最大の特徴は、Icebergテーブルの運用で面倒だったメンテナンスタスクが自動化されている点です。
- コンパクション: 小さなファイルを統合して大きなファイルにまとめる。binpack、sort、z-orderの3戦略。デフォルトは
auto - スナップショット管理: 古いスナップショットの自動期限切れ。デフォルトは120時間保持、最低1スナップショット
- 孤立ファイル削除: 参照されなくなったファイルを自動削除。デフォルトは3日後に削除
自分の環境で作成したテーブルのメンテナンス設定を確認すると、以下のようにデフォルトで全て有効になっていました。
{
"configuration": {
"icebergCompaction": {
"status": "enabled",
"settings": {
"icebergCompaction": {
"targetFileSizeMB": 512,
"strategy": "auto"
}
}
},
"icebergSnapshotManagement": {
"status": "enabled",
"settings": {
"icebergSnapshotManagement": {
"minSnapshotsToKeep": 1,
"maxSnapshotAgeHours": 120
}
}
}
}
}
今回のアップデート — CloudFormation/CDK対応の拡充
S3 Tables発表時(2024年12月)はCloudFormationでテーブルバケットしか作れませんでした。今回、以下の5つのリソースタイプが利用可能になっています(CloudFormation ドキュメント)。
| リソースタイプ | 内容 |
|---|---|
AWS::S3Tables::TableBucket | テーブルバケット |
AWS::S3Tables::Namespace | ネームスペース |
AWS::S3Tables::Table | テーブル |
AWS::S3Tables::TableBucketPolicy | テーブルバケットポリシー |
AWS::S3Tables::TablePolicy | テーブルポリシー |
CDK側は@aws-cdk/aws-s3tables-alphaパッケージとして提供されています(CDK ドキュメント)。パッケージ名にalphaが付いている通り、まだ実験的な段階です。
IaCの対応タイムライン — Terraformが先行した珍しいケース
ここが個人的に面白いと思ったポイントです。通常、AWSの新サービスはCloudFormationが同日対応し、Terraformが後追いする流れですが、S3 TablesではTerraformの方が9ヶ月早かったです。
| 日付 | 出来事 |
|---|---|
| 2024年12月3日 | S3 Tables GA発表(re:Invent 2024) |
| 2024年12月4日 | Terraform対応(AWS Provider v5.80.0) |
| 2025年8月28日 | CloudFormation/CDK対応(テーブル・ネームスペース追加) |
HashiCorpは「launch-day support」とブログで発表しており(2024年12月 HashiCorp Blog)、re:Invent翌日にはPRがマージされていました(GitHub PR #40420)。
これはTerraformがAWS APIを直接利用して即座にリソースを実装できるのに対し、CloudFormationはサービスチーム内部でリソースプロバイダーを開発する必要があることが要因だと思います。
ただしTerraformにも課題が残っている
Terraform対応は早かったものの、実務で完結させるにはまだ課題があります。
| GitHub Issue | 内容 | 状態 |
|---|---|---|
| #40725 | GlueでS3 Tablesカタログを作成できない | Open(2024年12月〜) |
| #42556 | 作成したテーブルのmetadataLocationが空で、PyIceberg等から使えない | Open |
| #40724 | LakeFormationの権限設定がバリデーションエラー | Open |
特にGlueカタログの作成(#40725)は、AthenaやRedshiftからS3 Tablesにクエリするために必須の手順です。これがTerraformで完結しないのは実務上かなり痛いポイントです。実際にブログ記事でも「Terraformでやろうとしたがバグで断念し、コンソールで手動設定した」という報告があります(2025年6月頃 The Last Dev)。
実際に試してみた
自分の環境でCLIとCloudFormationの両方で試してみました。
- AWS CLI:
aws-cli/2.34.8 - リージョン:
ap-northeast-1
CLIでのテーブル作成
テーブルバケット → ネームスペース → テーブルの順に作成します。
# テーブルバケットの作成
aws s3tables create-table-bucket \
--profile your-profile \
--region ap-northeast-1 \
--name my-test-table-bucket
{
"arn": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/my-test-table-bucket"
}
# ネームスペースの作成
aws s3tables create-namespace \
--profile your-profile \
--region ap-northeast-1 \
--table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/my-test-table-bucket \
--namespace test_namespace
# スキーマ付きでテーブルを作成
aws s3tables create-table \
--profile your-profile \
--region ap-northeast-1 \
--table-bucket-arn arn:aws:s3tables:ap-northeast-1:123456789012:bucket/my-test-table-bucket \
--namespace test_namespace \
--name purchase_records \
--format ICEBERG \
--metadata '{
"iceberg": {
"schema": {
"fields": [
{"name": "order_id", "type": "int", "required": true},
{"name": "customer_name", "type": "string", "required": false},
{"name": "amount", "type": "int", "required": false},
{"name": "purchase_date", "type": "string", "required": false}
]
}
}
}'
{
"tableARN": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/my-test-table-bucket/table/2723cfda-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"versionToken": "13f7e0428ecc3b1239be"
}
ここで気づいたのですが、CLIのcreate-tableでは--format ICEBERGと指定するのに対し、CloudFormationではOpenTableFormat: ICEBERGというプロパティ名です。さらにスキーマの指定方法も異なります(後述)。CLI/CFn/CDKでプロパティ名が微妙に統一されていない点は注意が必要です。
Glueカタログとの連携
S3 Tablesにデータを投入・クエリするにはAthenaやSparkを使いますが、そのためにはまずGlue Data Catalogとの連携を設定する必要があります。自分が最初にハマったのがここで、テーブルバケットを作っただけではAthenaからは見えません。
手順は以下の通りです。
1. Lake Formation用IAMロールの作成
aws iam create-role \
--profile your-profile \
--role-name S3TablesRoleForLakeFormation \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lakeformation.amazonaws.com"},
"Action": ["sts:AssumeRole", "sts:SetContext", "sts:SetSourceIdentity"],
"Condition": {
"StringEquals": {"aws:SourceAccount": "123456789012"}
}
}]
}'
このロールにはs3tables:*系の権限を付与します(GetTableData、PutTableDataを含む)。
2. Lake Formationへのリソース登録
aws lakeformation register-resource \
--profile your-profile \
--region ap-northeast-1 \
--with-privileged-access \
--resource-arn "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/*" \
--with-federation \
--role-arn "arn:aws:iam::123456789012:role/S3TablesRoleForLakeFormation"
3. Glueカタログの作成
aws glue create-catalog \
--profile your-profile \
--region ap-northeast-1 \
--name s3tablescatalog \
--catalog-input '{
"FederatedCatalog": {
"Identifier": "arn:aws:s3tables:ap-northeast-1:123456789012:bucket/*",
"ConnectionName": "aws:s3tables"
},
"CreateDatabaseDefaultPermissions": [],
"CreateTableDefaultPermissions": [],
"AllowFullTableExternalDataAccess": "True"
}'
この3ステップを完了すると、AthenaからS3 Tablesにクエリできるようになります。テーブルバケットを作っただけでは自動的にカタログは作られないので、この設定は忘れずに行う必要があります。
Athenaでのデータ投入・クエリ
S3 TablesのCLI(aws s3tables)はコントロールプレーン専用です。データの読み書き(データプレーン)はAthena、Spark、Data Firehose等のクエリエンジン経由で行います。put-table-dataのようなCLIコマンドは存在しません。
Athena経由でINSERTとSELECTを試してみました。
-- データ投入
INSERT INTO "s3tablescatalog/my-test-table-bucket"."test_namespace"."purchase_records"
VALUES
(1, 'Alice', 1500, '2026-03-18'),
(2, 'Bob', 2300, '2026-03-18'),
(3, 'Charlie', 800, '2026-03-18');
INSERTは約3.2秒で完了しました。
-- クエリ
SELECT * FROM "s3tablescatalog/my-test-table-bucket"."test_namespace"."purchase_records";
| order_id | customer_name | amount | purchase_date |
|---|---|---|---|
| 1 | Alice | 1500 | 2026-03-18 |
| 2 | Bob | 2300 | 2026-03-18 |
| 3 | Charlie | 800 | 2026-03-18 |
SELECTは約1.1秒で完了しました。テーブル名の指定方法が"s3tablescatalog/バケット名"."ネームスペース"."テーブル名"のフォーマットになる点は慣れが必要です。
CloudFormationでのデプロイ
CloudFormationでテーブルバケット・ネームスペース・テーブルをまとめてデプロイしてみました。
AWSTemplateFormatVersion: '2010-09-09'
Description: S3 Tables CloudFormation test
Resources:
TestTableBucket:
Type: AWS::S3Tables::TableBucket
Properties:
TableBucketName: cfn-test-table-bucket-v2
TestNamespace:
Type: AWS::S3Tables::Namespace
Properties:
TableBucketARN: !GetAtt TestTableBucket.TableBucketARN
Namespace: cfn_test_namespace
TestTable:
Type: AWS::S3Tables::Table
Properties:
TableBucketARN: !GetAtt TestTableBucket.TableBucketARN
Namespace: cfn_test_namespace
TableName: events
OpenTableFormat: ICEBERG
IcebergMetadata:
IcebergSchema:
SchemaFieldList:
- Name: event_id
Type: int
Required: true
- Name: event_name
Type: string
- Name: created_at
Type: string
DependsOn: TestNamespace
デプロイは成功しましたが、いくつかのハマりポイントがありました。
-
FormatではなくOpenTableFormat— CLIでは--format ICEBERGですが、CloudFormationではOpenTableFormat: ICEBERGです。最初にFormatで書いたらバリデーションエラーになりました -
IcebergMetadataまたはWithoutMetadataが必須 — CLIではスキーマなしでもテーブルを作れますが、CloudFormationではIcebergMetadata(スキーマ付き)かWithoutMetadata: trueのどちらかを明示的に指定する必要があります。省略するとエラーになりますResource handler returned message: "Invalid request provided: Either IcebergMetadata or WithoutMetadata must be specified" -
スキーマのプロパティ名が独自 — CLIでは
schema.fields[].nameのようなシンプルな構造ですが、CloudFormationではIcebergMetadata.IcebergSchema.SchemaFieldList[].Nameと深くネストされます -
テーブルバケットの削除に時間がかかる — CloudFormationスタックを削除して再作成しようとすると、テーブルバケットが「transitional state」のエラーで作成に失敗することがありました。同名のバケットを再作成する場合は数分待つ必要があります
Resource handler returned message: "The bucket is in a transitional state because of a previous deletion attempt. Try again later."
料金と注意点
ストレージ料金
S3 Tablesのストレージは通常S3より約15%高い$0.0265/GB(us-west-2、最初の50TB)です(S3 料金ページ)。
コンパクション料金の変遷
S3 Tablesのコンパクション料金は発表当初、コミュニティから批判を受けていました。Onehouseの分析では、100GBのコンパクションでEMR自前運用の20〜30倍のコストになるケースが報告されていました(2025年3月頃 Onehouse Blog)。
これを受けてか、AWSは2025年7月にコンパクション料金を大幅に引き下げています(2025年7月1日 AWS What’s New)。
| 項目 | 引き下げ前 | 引き下げ後 | 削減率 |
|---|---|---|---|
| オブジェクトあたり(1,000件) | $0.004 | 約$0.002 | 50% |
| バイトあたり(binpack) | $0.05/GB | 約$0.005/GB | 90% |
| バイトあたり(sort/z-order) | $0.05/GB | 約$0.01/GB | 80% |
binpack戦略で90%の削減は大きいです。ただし、コンパクションは自動で実行されるため発生タイミングのコントロールが難しく、書き込みが多いワークロードではコストに注意が必要です。
コンパクションの可視性
コンパクションがいつ実行されるかの可視性が低い点は意識しておく必要があります。自分の環境ではテーブル作成後すぐにはコンパクションは実行されず、データ量やファイル数が閾値に達した段階で自動的にトリガーされるようです。CloudWatchでコンパクションの実行状況を監視するダッシュボードが公式に提供されていない点は改善を期待したいところです。
対応リージョン
S3 Tablesは段階的にリージョンを拡大しており、ap-northeast-1(東京)には2025年1月に対応しています(2025年1月17日 AWS What’s New)。2025年5月時点で30リージョンに対応済みです。
まとめ
S3 TablesのCloudFormation/CDK対応は、IaCでの管理が当たり前になった現在のAWS運用において必要なアップデートでした。テーブルバケット・ネームスペース・テーブルの3リソースをスタックとしてまとめて管理できるようになったことで、複数アカウントへの一貫したデプロイが可能になります。
ただし、実際に使ってみていくつかの課題も見えてきました。
- Glueカタログ連携はIaCの範囲外: テーブルを作っただけではAthenaから見えず、Lake FormationとGlueカタログの設定が別途必要です。この部分はCloudFormationでもTerraformでもスムーズに完結しません
- CLI/CFn/CDKでプロパティ名が統一されていない:
FormatvsOpenTableFormat、スキーマの構造など、ドキュメントをしっかり確認する必要があります - コンパクション料金は改善されたが要注意: 2025年7月の値下げで大幅に改善されましたが、自動実行のためコスト予測が難しい面があります
S3 Tablesは「Icebergテーブルの運用を楽にしたい」という明確なユースケースに対しては非常に有効なサービスだと思います。特に、これまでGlueジョブやEMRでコンパクションを自前で回していた環境では、運用負荷の大幅な削減が期待できます。一方で、Glueカタログ連携やIaCの成熟度を考えると、本番投入前に一度手を動かして検証しておくことを強くお勧めします。