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.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
1
52
Claude in Chromeで始める自律的フロントエンド開発
diggymo
1
980
HonoとJSXを使って管理画面をサクッと型安全に作ろう
diggymo
0
490
バッチ処理で悩むバックエンドエンジニアに捧げるAWS Glue入門
diggymo
3
720
LIFF CLIとngrokを使ったLIFF/LINEミニアプリのお手軽実機確認
diggymo
0
1k
TypeScriptでモジュラーモノリスやってみた
diggymo
0
630
過去のインプットとアウトプットを振り返る
diggymo
0
410
Amazon BedrockとPR-Agentでコードレビュー自動化に挑戦・実際に運用してみた
diggymo
0
3k
個人開発でLIFFとMessagingAPIを使ってわかった5つのこと
diggymo
0
1.5k
Other Decks in Technology
See All in Technology
Fabricをフル活用する AI Agent Hub -製造業特化AIエージェントの設計
iotcomjpadmin
0
190
「ビジネスがわかるエンジニア」とは何か?
ryooob
0
490
LiDAR SLAMの実装とセンサ融合 ~Lie群からContinuous-Time LIOまで~
naokiakai
1
910
AI駆動開発におけるQAエンジニアの役割事例 〜AI駆動開発の現場から〜
kobayashiyorimitsu
0
290
打造你的 AI 工作流:Agent Skill + MCP 實戰工作坊
appleboy
0
480
5分でわかる Amazon Connect_20260608
hwangbyeonghun
0
170
MySQL & MySQL HeatWave Report - June 2026
freshdaz
0
300
AI時代における最適なQA組織の作り方
ymty
3
350
記録をかんたんに、提案をパーソナルに ── AIであすけんが目指すもの
oprstchn
0
130
SRE歴2ヶ月でも開発6年の知見を活かして、チームで止まっていた環境改善を前に進めた話
a_ono
0
180
「ちゃんとやっている」は独りよがりだった ― 不安に寄り添うインシデント対応へ / Towards incident response that addresses anxieties
chmikata
1
300
はてなのサービス基盤を支える Kubernetes《足腰》
masayoshimaezawa
0
430
Featured
See All Featured
Designing for Performance
lara
611
70k
Optimizing for Happiness
mojombo
378
71k
Music & Morning Musume
bryan
47
7.3k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.2k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
We Have a Design System, Now What?
morganepeng
55
8.2k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
430
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
310
Product Roadmaps are Hard
iamctodd
55
12k
Optimising Largest Contentful Paint
csswizardry
37
3.8k
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
ありがとうございました 🫠おわり