5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CDKデプロイ時に「S3バケットが既に存在する」エラーが出たときの対処法

5
Posted at

はじめに

AWS CDKでインフラをコード管理(IaC)していると、手動やCLIで先に作成したリソースとCDKの管理対象が衝突するケースがあります。

本記事では、CDKデプロイ時にS3バケットの重複エラーが発生した場合の原因と、データを保持したまま解決する方法を紹介します。

問題

CDKでS3バケットを含むスタックをデプロイしたところ、以下のエラーが発生しました。

❌ my-project-cdk-stack-s3 failed: ToolkitError: ChangeSet 'cdk-deploy-change-set' on stack 'my-project-cdk-stack-s3' failed early validation:
- Resource of type 'AWS::S3::Bucket' with identifier 'my-project-bucket-data' already exists.

同名のS3バケットがすでにAWSアカウント上に存在しているため、CDK(CloudFormation)が新規作成しようとして失敗しています。

さらに、既存バケットにはデータが格納されているため、単純に削除して作り直すわけにもいきません。

原因

CDK(CloudFormation)は、スタック内で定義されたリソースを「新規作成」しようとします。しかし、以下のようなケースでは同名のリソースがすでに存在するため衝突が起きます。

  • 過去にAWSコンソールやCLIで手動作成したバケットと同じ名前をCDKで定義した
  • 以前のCDKスタックを削除した際に RemovalPolicy.RETAIN によりバケットだけが残った
  • 別のCloudFormationスタックで同名バケットが管理されている

CloudFormationは「自分が管理していないリソース」を認識できないため、作成時に重複エラーとなります。

解決案

方法A: データを一時退避してバケットを再作成する

最もシンプルな方法です。一時バケットにデータを退避し、既存バケットを削除してからCDKで再作成します。

# 1. 一時バケット作成
aws s3 mb s3://my-project-bucket-data-tmp --region ap-northeast-1

# 2. データ退避
aws s3 sync s3://my-project-bucket-data \
            s3://my-project-bucket-data-tmp

# 3. 既存バケットを空にして削除
aws s3 rm s3://my-project-bucket-data --recursive
aws s3 rb s3://my-project-bucket-data

# 4. CDKデプロイ(同名バケットがCDK管理で再作成される)
cdk deploy my-project-cdk-stack-s3

# 5. データ復元
aws s3 sync s3://my-project-bucket-data-tmp \
            s3://my-project-bucket-data

# 6. 一時バケット削除
aws s3 rm s3://my-project-bucket-data-tmp --recursive
aws s3 rb s3://my-project-bucket-data-tmp

メリット

  • 手順がわかりやすい

デメリット

  • データ量が多いと時間がかかる
  • sync中に新たなデータが書き込まれると不整合が起きる可能性がある
  • 一時的にバケットが存在しない期間が発生する

方法B: CloudFormationのリソースインポートで既存バケットを取り込む

CloudFormationの リソースインポート 機能を使うと、既存のバケットをデータごとそのままCDKスタックの管理下に入れることができます。

リソースインポートは2019年からリリースされている機能です。
https://aws.amazon.com/jp/blogs/news/new-import-existing-resources-into-a-cloudformation-stack/

# 1. CDKテンプレートを生成
cdk synth my-project-cdk-stack-s3 > template.yaml
# 2. インポート用チェンジセットを作成
aws cloudformation create-change-set \
  --stack-name my-project-cdk-stack-s3 \
  --change-set-name import-s3-bucket \
  --change-set-type IMPORT \
  --template-body file://template.yaml \
  --resources-to-import "[{
    \"ResourceType\": \"AWS::S3::Bucket\",
    \"LogicalResourceId\": \"s3BucketDataXXXXXXXX\",
    \"ResourceIdentifier\": {
      \"BucketName\": \"my-project-bucket-data\"
    }
  }]"

LogicalResourceIdcdk synth で出力されるテンプレート内の論理IDを確認して置き換えてください。

# 3. チェンジセットを実行
aws cloudformation execute-change-set \
  --stack-name my-project-cdk-stack-s3 \
  --change-set-name import-s3-bucket
# 4. インポート完了を確認
aws cloudformation describe-stacks \
  --stack-name my-project-cdk-stack-s3 \
  --query "Stacks[0].StackStatus"

メリット

  • データ移動が不要
  • ダウンタイムなし
  • 事故のリスクが低い

デメリット

  • CDKテンプレート内のバケット設定(暗号化、バージョニングなど)が既存バケットの実際の設定と一致している必要がある
  • 論理IDの特定が必要(cdk synth の出力から確認する)

CDKでもcdk importにより、他メソッドで作成した既存リソースをCDKを利用して管理できます。
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/ref-cli-cmd-import.html

方法Bの注意点

インポート時にテンプレートの設定と既存リソースの設定に差異があると、次回の cdk deploy でドリフト修正が走り意図しない変更が入る可能性があります。事前に以下を確認しておくと安全です。

# 既存バケットの設定を確認
aws s3api get-bucket-versioning --bucket my-project-bucket-data
aws s3api get-bucket-encryption --bucket my-project-bucket-data

CDK側のS3定義を既存バケットの設定に合わせてからインポートすると、差分なくスムーズに管理下に入れられます。

まとめ

観点 方法A(データ退避) 方法B(リソースインポート)
データ移動 必要 不要
ダウンタイム あり なし
手順の複雑さ シンプル やや複雑
安全性 △(sync中の不整合リスク)

既存リソースにデータが入っている場合は、方法B(リソースインポート) を使うのが安全です。データ移動もダウンタイムも発生せず、既存バケットをそのままCDKの管理下に入れることができます。

CDKで既存リソースとの衝突に遭遇した際は、削除・再作成の前にまずインポートを検討してみてください。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?