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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
morimorikochan
October 31, 2024
Technology
1.3k
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
900
Claude in Chromeで始める自律的フロントエンド開発
diggymo
1
1k
HonoとJSXを使って管理画面をサクッと型安全に作ろう
diggymo
0
500
バッチ処理で悩むバックエンドエンジニアに捧げるAWS Glue入門
diggymo
3
730
LIFF CLIとngrokを使ったLIFF/LINEミニアプリのお手軽実機確認
diggymo
0
1k
TypeScriptでモジュラーモノリスやってみた
diggymo
0
640
過去のインプットとアウトプットを振り返る
diggymo
0
420
Amazon BedrockとPR-Agentでコードレビュー自動化に挑戦・実際に運用してみた
diggymo
0
3k
個人開発でLIFFとMessagingAPIを使ってわかった5つのこと
diggymo
0
1.6k
Other Decks in Technology
See All in Technology
なぜ、あなたのエージェントは言うことを聞かないのか
segavvy
1
170
AI、CDK と協働する Full TypeScript アプリケーション開発 / Full TypeScript Application with AI and CDK
geekplus_tech
2
460
CDKで書くECSのベストプラクティス、 改めて考え直す2026 #cdkconf2026
makies
3
920
Aurora MySQL 8.4リリース! Rubyistが備えること / what-rubyist-should-prepare-for-aurora-mysql-8-4
fkmy
0
240
AI時代におけるテストの基礎の再定義 / Rethinking the Fundamentals of Testing in the AI Era
mineo_matsuya
5
2.1k
ダッシュボード"開発"について 〜使われるダッシュボードのつくりかた〜
kimichan
0
160
『モデル + ハーネス』で読み解く AIエージェント入門
oracle4engineer
PRO
2
150
2年前に削除したPHPクラスが、 ある日突然決済をエラーにした
ykagano
1
710
【公開用】AI_Dev_Ex2026_AI_登壇資料
matsuritechnologies
PRO
1
440
「守りたい体験」を渡すだけで E2E を生成させられるようになった話
hinac0
2
980
AI Coding Agent時代のcdk-nagガードレール 〜組織ルールを強制CIで守り抜く設計の挑戦〜
mhrtech
3
480
ここは地獄!つらい朝会を体験することで、チームとしてのより良い振る舞いに気づくワークショップ / The stand-up meeting from hell in the game industry
scrummasudar
0
210
Featured
See All Featured
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
470
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
210
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
350
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
190
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
Claude Code のすすめ
schroneko
67
230k
The Spectacular Lies of Maps
axbom
PRO
1
870
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
180
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
320
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
ありがとうございました 🫠おわり