インフラ

CDK「Export <アウトプット> cannot be deleted as it is in use by <スタック名>」

cdk

こんにちは、ちゃりおです。

CDKの自動で追加されるクロススタック参照で以下のエラーがでました。

Export <アウトプット> cannot be deleted as it is in use by <スタック名>

Outputしている側は特に変更せず、Importしている側で取得する値を変えました。
Import側を変えた影響で、CDKが自動生成しているOutputを消してしまってスタックを変更できず困りました。

結論から書くと、exportValueで自動生成されるOutputを保持することで解決しました。

CDKのクロススタック参照がロックされてしまう

事象

ロググループとECSのタスク定義を別スタックにして、クロススタックする場合を例にします。

#!/usr/bin/env node
import "source-map-support/register"
import * as cdk from "@aws-cdk/core"
import * as logs from "@aws-cdk/aws-logs"
import * as ecs from "@aws-cdk/aws-ecs"

export class LogsStack extends cdk.Stack {
  logGroup: {
    sample: logs.LogGroup,
    sample2: logs.LogGroup
  }
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const sampleLog = new logs.LogGroup(this, "sample-logGroup", {
      removalPolicy: cdk.RemovalPolicy.DESTROY
    })
    const sample2Log = new logs.LogGroup(this, "sample2-logGroup", {
      removalPolicy: cdk.RemovalPolicy.DESTROY
    })
    this.logGroup = {
      sample: sampleLog,
      sample2: sample2Log
    }
  }
}

interface ecsProps extends cdk.StackProps { 
  log: LogsStack
}

export class EcsStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: ecsProps ) {
    super(scope, id)
    
    const taskDef = new ecs.FargateTaskDefinition(this, "app-task")
    
    taskDef.addContainer("nginx", {
      image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
      logging: new ecs.AwsLogDriver({
        streamPrefix: "fargate",
        logGroup: props.log.logGroup.sample
      })
    })
  }
}

const app = new cdk.App();
const logsStack = new LogsStack(app, "logs-stack")
new EcsStack(app, "ecs-stack", { log: logsStack })

上記がデプロイ済みの状態で、タスク定義のロググループを変更しようとするとエラーがでます。


// sample2に変更
//        logGroup: props.log.logGroup.sample
        logGroup: props.log.logGroup.sample2
% cdk deploy "*"                                                                                                                                                                    (git)-[master]
logs-stack
logs-stack: deploying...
logs-stack: creating CloudFormation changeset...
17:17:12 | UPDATE_ROLLBACK_IN_P | AWS::CloudFormation::Stack | logs-stack
Export logs-stack:ExportsOutputRefsamplelogGroupA6FE7BF7B332FB07 cannot be deleted as it is in use by ecs-stack
17:17:12 | UPDATE_ROLLBACK_IN_P | AWS::CloudFormation::Stack | logs-stack
Export logs-stack:ExportsOutputRefsamplelogGroupA6FE7BF7B332FB07 cannot be deleted as it is in use by ecs-stack

スタック作り直せば、ロググループ変更できますが作り直すのは面倒です。
どうやら「logs-stack」側のOutputを消そうとしているが、他のスタックで使っていて消せない旨のエラーがでます。

diffを見ると「logs-stack」は変更していないにも関わらず、Outputの変更がでてきます。

% cdk diff logs-stack                                                                                                                                                               (git)-[master]
Stack logs-stack
Outputs
[-] Output ExportsOutputRefsamplelogGroupA6FE7BF7B332FB07: {"Value":{"Ref":"samplelogGroupA6FE7BF7"},"Export":{"Name":"logs-stack:ExportsOutputRefsamplelogGroupA6FE7BF7B332FB07"}}
[-] Output ExportsOutputFnGetAttsamplelogGroupA6FE7BF7Arn1ECF63B5: {"Value":{"Fn::GetAtt":["samplelogGroupA6FE7BF7","Arn"]},"Export":{"Name":"logs-stack:ExportsOutputFnGetAttsamplelogGroupA6FE7BF7Arn1ECF63B5"}}
[+] Output Exports/Output{"Ref":"sample2logGroup2B304774"} ExportsOutputRefsample2logGroup2B3047744874A5FB: {"Value":{"Ref":"sample2logGroup2B304774"},"Export":{"Name":"logs-stack:ExportsOutputRefsample2logGroup2B3047744874A5FB"}}
[+] Output Exports/Output{"Fn::GetAtt":["sample2logGroup2B304774","Arn"]} ExportsOutputFnGetAttsample2logGroup2B304774Arn2624143A: {"Value":{"Fn::GetAtt":["sample2logGroup2B304774","Arn"]},"Export":{"Name":"logs-stack:ExportsOutputFnGetAttsample2logGroup2B304774Arn2624143A"}}

対策

自動で生成されるOutputを削除しようとするのが原因です。
保持するようにすれば解決します。

exportValueを使って明示的に定義すれば、変更時にOutputが自動で削除されなくなります。

    this.logGroup = {
      sample: sampleLog,
      sample2: sample2Log
    }
  // 追加
    this.exportValue(sampleLog.logGroupArn)
    this.exportValue(sampleLog.logGroupName)
    this.exportValue(sample2Log.logGroupArn)
    this.exportValue(sample2Log.logGroupName)

上記追加してデプロイしたところ、logGroupを変更できました。

参考 CDK tips, part 3 – how to unblock cross-stack references

Amzonで「AWS」の本を見てみる

楽天で「AWS」の本をみてみる!!

cdk
AWS CDKのADVANCED WORKSHOPやってみたこんにちは、ちゃりおです。 CDK Pipelineをざっくり試したいと思っていて、なにかいいチュートリアルないかと探していたら。「A...
Github Actionsを使ってCDKを自動デプロイするこんにちは、ちゃりおです。 CDK手動反映だと反映漏れが発生することもあり、今回はGithub Actionsを使ってCDKを自動デプ...
itエンジニア論理
【書評】ITエンジニア的論理思考テクニック!こんにちは、ちゃりおです。 今回紹介する本は、ITエンジニア向けの論理的思考の本です。 論理的思考について書かれた本は山のようにある...