TWBMT

技術的な記事や覚書について書いていきます。その内、自作サイトとかに技術記事をまとめたい。

【DynamoDB】 CloudFormation cannot update a stack when a custom-named resource requires replacing. の対策

CloudFormationを基にDynamoDB の Table などカスタム名付きのリソースを更新する際にタイトルの様なエラーが発生することがあります。
結論的にはCloudFormationを使用する上では避けられないエラーですので、このエラーの原因と上手い対応方法についてのメモをまとめていきます。

エラーの原因

以下のドキュメントにCloudFormationがリソースを更新する時の振る舞いが記載してあります。

Update behaviors of stack resources - AWS CloudFormation

このドキュメントの Replacement の項目に、「AWS CloudFormationは、アップデートの際にリソースを再作成し、新しい物理IDも生成します」と記載があります。

調べていく限りはこれが原因の模様でして、カスタム名付きのリソースの場合はリプレイスを伴う更新の際に「 カスタム名 = 物理ID」であるが為に、物理IDが衝突してエラーが発生するという事の様です。

「置換せずに更新してくれ!」っても思いますが「KeySchemaを変更して保持しているインデックス情報を書き換える事とDynamoDBの使用状況を基に課金料金を決めることとは訳が違うんだよ!」と言われたら「確かに。」と思ってしまいます。

という訳で、つらつらと対策をまとめていきます。

対策

公式のドキュメントではタイトルのエラーの対応として以下の2パターンが紹介されています。

  1. カスタム名を使用せずにリソースを作成する
  2. カスタム名を変更してデプロイ後、元々のカスタム名で再デプロイする

aws.amazon.com

「1. 」の場合は、カスタム名を使用しない事によって毎回一意な物理IDを払い出す為にエラーを避けることが出来るという事ですね。
もしかしたら、IAMやAutoScalingGroup なんかの永続性のある情報を持たないリソースなら有用かもしれない。

カスタム名を使わなければ行けない場合は自然と「2. 」の方法になります。
ただ、これをやるとDynamoDBのストレージの内容が全て吹き飛びます。 困ったもんですね。

とはいえ、DBの置換自体は避けられない事ですので大人しく対応策を調べていったところ、リソースの更新時の振る舞いの一つに Retain というプロパティを見つけました。

UpdateReplacePolicy 属性 - AWS CloudFormation

CloudFormation上からはリソースを削除するが実リソースとしては残す、というものの様です。

これを使えば、かなり面倒ですが、
「新DB作成 -> 旧DBから新DBへデータ移動 -> 真DB作成(旧DBと同一名で作成) -> 新DBから真DBへデータ移動」
という手順でカスタム名を維持したままDBを保つことが出来そうです。

ただ、データ移行が面倒くさいので、
カスタム名に version名 を付随させて更新の度にverisonを上げるというやり方でも良さそうな気もしますね。

まとめ

ざっくりとですが、

  • エラーの原因はリソースの置換の際の物理IDの衝突が原因。
  • 置換が必須の更新(DynamoDBのLSIなど)の場合、カスタム名の改名が必要になる。
  • その場合の移行方法として、UpdateReplacePolicyRetein などを利用し、旧リソースからデータを移動させる方針が良さそう。

といった次第ですね。

ひとしきりエラーの原因と対応方針は見つけられたのですが、 置換更新する際のベストプラクティスやデータ移行の方法まだ見つけられていないのでそちらも見つけ次第更新したいですね。

追記

~ この辺りも参考になりそう。(アカウント間でのデータ移行の方法なのでオーバースペックかも。) ~ aws.amazon.com

~ DynamoDBインポート / エクスポート機能を利用すると楽なことを確認。~ dev.classmethod.jp

色々調べた結果、scan + batchWrite を実行するスクリプトを書く事が一番の様子。 また追って更新する。