Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
DynamoDBの"Replacement"時にデータが消されないようにCustom Reso...
Search
morimorikochan
October 31, 2024
Technology
1.4k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
DynamoDBの"Replacement"時にデータが消されないようにCustom Resource Provider Frameworkでカスタムリソース作ってみた件
"クラスメソッドのCDK事情大公開スペシャル#1" の際に登壇した内容です
https://classmethod.connpass.com/event/332020/
morimorikochan
October 31, 2024
More Decks by morimorikochan
See All by morimorikochan
実装だけじゃない! CCA-F取得エンジニアが教えるClaude Code開発プロセス活用術
diggymo
2
1.3k
Claude in Chromeで始める自律的フロントエンド開発
diggymo
1
1.1k
HonoとJSXを使って管理画面をサクッと型安全に作ろう
diggymo
0
530
バッチ処理で悩むバックエンドエンジニアに捧げるAWS Glue入門
diggymo
3
760
LIFF CLIとngrokを使ったLIFF/LINEミニアプリのお手軽実機確認
diggymo
0
1.1k
TypeScriptでモジュラーモノリスやってみた
diggymo
0
710
過去のインプットとアウトプットを振り返る
diggymo
0
480
Amazon BedrockとPR-Agentでコードレビュー自動化に挑戦・実際に運用してみた
diggymo
0
3.2k
個人開発でLIFFとMessagingAPIを使ってわかった5つのこと
diggymo
0
1.7k
Other Decks in Technology
See All in Technology
AIで仕事のやり方を変える
matsu7874
1
930
JAWS-UG初心者支部#88わいわい初心塾(夏休みの宿題やったかGit編)
otsuki
0
150
こんなアーキテクチャ図は嫌だ BEYOND THE TIME: 半年後の自分へ贈る15のメッセージ / 15 of Anti-pattern in AWS Architecture Diagrams
naospon
3
260
【視聴者参加型!】AWSセキュリティアンチパターンクイズ
syoshie
0
450
多摩川(.dev)ランニング入門 / Tamagawa.dev#3
fujiwara3
3
390
いま、生成AIにKaggleをどこまで 任せられるか — ROGIIコンペでの進め方とTips
k951286
3
1.4k
Sony-DroidKaigi2026
sony
1
320
module Synths; end
asonas
1
120
Nav2、Nav3 ... はたまた自作?〜 作って理解する Nav3 の設計意図 〜 / Nav2, Nav3 ... or Build Your Own? — Understanding Nav3's design intent by building it from scratch
yanzm
0
250
【Oracle AI Spotlight ウェビナー】AWSか、Azureか、Google Cloudか。その議論にオラクルを含める意義。
oracle4engineer
PRO
2
240
PdMをやめて、 "プロダクトビルダー"という 働き方に変えました / PdM to Product Builder
shikichee
2
730
DGX Sparkを2台使って いろいろ動かす話
sonoda_mj
1
130
Featured
See All Featured
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
510
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
310
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
810
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.6k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Building Flexible Design Systems
yeseniaperezcruz
330
41k
How to make the Groovebox
asonas
2
2.4k
It's Worth the Effort
3n
188
29k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
320
Un-Boring Meetings
codingconduct
0
410
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Transcript
DynamoDBの"Replacement"時にデータ が消されないように Custom Resource Provider Frameworkで カスタムリソース作ってみた件 クラスメソッド株式会社 リテールアプリ共創部 マッハチーム
morimorikochan
名前 morimorikochan 所属 クラスメソッド株式会社 リテールアプリ共創部 マッハチーム🚀 趣味 Switchのゲーム X @marooon88 ⼀⾔
中古7万の椅⼦でQoL爆上 ⾃⼰紹介
1. 結論 2. 問題提起 3. Custom Resources 4. Custom Resource
Provider Framework 5. 実装した 6. まとめ 内容
• CDKでDynamoDBのテーブル置換時、テーブルのデータが全件削除され て困っていた • CDKのcustomresources.Provider(通称Custom Resource Provider Framework)を使って新テーブルへのコピーを⾃動で⾏えるようにした • 処理時間も早く、CIへの影響も少ない
• 課題 ◦ Lambda関数のIAMロールがちょっとガバってしまう ◦ レースコンディション発⽣する 📚結論
DynamoDBのPrimaryKey/SortKeyこんな感じやろか とりあえず cdk deploy して開発開始や! ⸻⸻数⽇後⸻⸻ PrimaryKey/SortKey間違ってたわ、直して
cdk deploy っと... ほなさいなら...(データ全削除) うわあぁぁぁぁぁぁ動作確認⽤のデータが消えたあぁぁぁぁぁぁ 🤨こんなことないですか
🤨こんなことないですか
🤨こんなことないですか
📚こんなことないですか 🤔 CDKの⼒でなんとかならん?
📚こんなことないですか 💡 Custom Resource Provider Framework
カスタムリソースを使⽤すると、CloudFormation テンプレートにカスタムプロビジョニン グロジックを記述し、スタックを作成、更新 (カスタムリソースを変更した場合)、または削 除するたびに CloudFormation にそのロジックを実⾏させることができます。これは、プロ ビジョニング要件に、CloudFormation の組み込みリソースタイプでは表現できない複雑な ロジックやワークフローが含まれる場合に役⽴ちます。
カスタムリソースプロバイダーの定義⽅法 • SNS ◦ 1. メッセージが送られる ◦ 2. SNSのバックエンド側で受信し処理 ◦ 3. バックエンド側がS3にファイルをPUTし応答する • Lambda ◦ 1. Lambda関数が実⾏される ◦ 2. Lambda関数内で処理 ◦ 3. Lambda関数内でS3にファイルをPUTし応答する 🤔Custom Resourcesとは?
CDKでの定義⽅法は4種類 1. sns.Topic ◦ 前ページの処理を⾏うSNSを定義 2. lambda.Function ◦ 前ページの処理を⾏うLambdaを定義 3.
core.CustomResourceProvider ◦ 2を使いやすくした便利ラッパー(?) ◦ エラーハンドリングや応答をLambda関数の結果から⾃動で⾏ってくれる ◦ 15分のタイムアウト制限がある ◦ アプリケーション実装者には推奨されていない 4. customresources.Provider(Custom Resource Provider Framework) ◦ 3をさらに使いやすくした便利ラッパー(?) ◦ 別途“処理が終わったかどうかを判定する”ためのLambda関数 (isCompleteHandler)を定義可能なので、実質15分のタイムアウトがない >aws-cdk-lib module · AWS CDK 🤔CDKでどうやってCustom Resourcesを定義する?
🤔カスタムリソースプロバイダーにCRPFを使った場合 1. CloudFormation実⾏中にLambda関数が呼び出され、 同時にカスタムリソースが作成中/更新中/削除中になる 2. Lambda関数が応答する 3. カスタムリソースが完了状態になる ※isCompleteHandlerを利⽤しない場合
• DynamoDBがリソース置換されたことをカスタムリソースが検知し • Lambda関数を実⾏させる • Lambda関数内では以下の処理を⾏う ◦ 1. 旧テーブルからScanして全アイテムを取得 ◦
2. 新テーブルに全アイテムをBatchWriteItem この⽅法の他にも、AWSのAPI経由で旧テーブルからS3へコピーしそれを新 テーブルへコピーする⽅法もあったが⾒送り • 処理時間がかかる • DMSがややこしそう(DMSエアプ) 💡今回の課題へ適⽤すると...
const lambdaFunction = new nodejsLambda.NodejsFunction(/*略*/) lambdaFunction.addToRolePolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW,
actions: ["dynamodb:Scan"], resources: ["*"], }) ); props.ddbTable.grantWriteData(lambdaFunction); const provider = new cr.Provider(this, "CustomResourceProvider", { onEventHandler: lambdaFunction, }); new cdk.CustomResource(this, "CustomResource", { serviceToken: provider.serviceToken, properties: { tableName: props.ddbTable.tableName, } as ResourceProperties, }); 利⽤イメージ(CDK側)
const lambdaFunction = new nodejsLambda.NodejsFunction(/*略*/) lambdaFunction.addToRolePolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW,
actions: ["dynamodb:Scan"], resources: ["*"], }) ); props.ddbTable.grantWriteData(lambdaFunction); const provider = new cr.Provider(this, "CustomResourceProvider", { onEventHandler: lambdaFunction, }); new cdk.CustomResource(this, "CustomResource", { serviceToken: provider.serviceToken, properties: { tableName: props.ddbTable.tableName, } as ResourceProperties, }); 利⽤イメージ(CDK側) const originalTable = new dynamodb.Table(/* 略 */) new DynamoDbTableItemsRestorer(this,'OriginalTableItemsRestorer',{ ddbTable: originalTable }) 利⽤例
テーブルが置き換わる場合(=物理IDが変化した場合)のみ Lambdaを実⾏したい 🤔Lambda関数どう実装する? テーブルの変化 旧テーブルから新テーブルへ コピーさせるか テーブル作成時 ❌ テーブル更新時 (置換なし)
❌ テーブル更新時 (置換あり) テーブル削除時 ❌
/** Lambdaのエントリーポイント */ export const handler: CdkCustomResourceHandler<ResourceProperties> = async (event)
=> { logger.info("リソースが変化しました ", {event}); switch (event.RequestType) { case "Update": await copyAllItems({ fromTableName: event.OldResourceProperties.tableName, newTableName: event.ResourceProperties.tableName, }); return { PhysicalResourceId: event.ResourceProperties.tableName }; case "Create": case "Delete": return {}; } }; 利⽤イメージ(Lambda側)
/** Lambdaのエントリーポイント */ export const handler: CdkCustomResourceHandler<ResourceProperties> = async (event)
=> { logger.info("リソースが変化しました ", {event}); switch (event.RequestType) { case "Update": await copyAllItems({ fromTableName: event.OldResourceProperties.tableName, newTableName: event.ResourceProperties.tableName, }); return { PhysicalResourceId: event.ResourceProperties.tableName }; case "Create": case "Delete": return {}; } }; 利⽤イメージ(Lambda側) new cdk.CustomResource(this, "CustomResource", { serviceToken: provider.serviceToken, properties: { tableName: props.ddbTable.tableName, } as ResourceProperties, });
前回からPhysicalResourceId(物理ID)変化させた場合 • CloudFormationが”カスタムリソースが置換された”と認識する ◦ もしロールバックが発⽣した場合はCloudFormationがDeleteを実⾏する 前回から変化させなかった場合 • CloudFormationが”カスタムリソースが更新された”と認識する ◦ もしロールバックが発⽣した場合はCloudFormationが
パラメータを逆にしてUpdateを実⾏し、元の状態に戻そうとする 今回の要件では、ロールバック時に処理をさせる必要はないのでコードがシ ンプルになるよう”PhysicalResourceIdを変化させる” Update時に返却する物理IDについて
const copyAllItems = async (props: { fromTableName: string, newTableName: string,
} ) => { logger.info("データをコピーします ", {fromTableName: props.fromTableName, newTableName: props.newTableName}); const oldTableReadableStream = new DynamoDBReadableStream(ddbClient, props.fromTableName); const newTableWritableStream = new DynamoDBWritableStream(ddbClient, props.newTableName); await pipeline(oldTableReadableStream, newTableWritableStream) if (newTableWritableStream.errorChunks.length > 0) { logger.error("コピーに失敗したアイテムがあります ", {errorChunks: newTableWritableStream.errorChunks}) throw new Error(`${newTableWritableStream.errorChunks.length}件のデータをコピーでき ませんでした `) } } 利⽤イメージ(Lambda側)
💪実⾏してみた テーブルの置換
💪実⾏してみた カスタムリソース(Lambda) のポリシー変更
💪実⾏してみた カスタムリソースが実⾏されてる 物理IDが変化しているので、 カスタムリソースが置換されたと 認識されてる
💪実⾏してみた Lambda関数の処理時間 • Item数が少ない場合はだいたい10秒とか • これぐらいならCIへの影響が少ない Lambda関数のIAMロールがちょっとガバってしまう • CDK上で旧テーブル名を保持していないため •
SSM使えばできそうですけど 複雑にしたくない レースコンディション発⽣する(当然) • コピーの途中に旧テーブルにPutItemされると、そのデータは新テーブルにコピーされ ない可能性がある • 本番環境で利⽤する際は、メンテナンスモードなど検討必要 lambdaFunction.addToRolePolicy( new iam.PolicyStatement({ resources: ["*"], }) );
📚まとめ • CDKでDynamoDBのテーブル置換時、テーブルのデータが全件削除され て困っていた • CDKのcustomresources.Provider(通称Custom Resource Provider Framework)を使って新テーブルへのコピーを⾃動で⾏えるようにした •
処理時間も早く、CIへの影響も少ない • 課題 ◦ Lambda関数のIAMロールがちょっとガバってしまう ◦ レースコンディション発⽣する
📚資料 作成したコード • https://github.com/diggymo/ddb-table-item-restorer 参考資料 • aws-cdk-lib module · AWS
CDK ◦ https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib-readme.htm l#custom-resources • CDK で Custom resources を作成する|伊藤忠テクノソリューションズ ◦ https://www.ctc-g.co.jp/solutions/cloud/column/article/84.html
ありがとうございました 🫠おわり