HackToTech

Hack To Technology

AWS CDKでdiffが出るのにdeployでnochangesになる

最近CDK使ってて出会した
端的に言えばCFnが悪いやつ(下はGithubのIssue)

github.com

ただまあ公式にも書いてあるこれをどうにかしてデプロイしたい

CreationPolicy、DeletionPolicy または UpdatePolicy 属性単独では更新できません。
更新できるのは、リソースを追加、変更、または削除する変更を含める場合だけです。
たとえば、リソースのメタデータ属性を追加または変更することはできます。

docs.aws.amazon.com

しかしながら一部変更を適用するのに、
いちいちリソースを変更まではしたくないなあと思って適当に回避策を思いついて試したらうまく動いたので残しとく

まずは適当にCDKのアプリケーションを作る(今回はTypeScriptだけど他の言語でも出来るはず)

cdk init app --language typescript
# 作ると勝手にディレクトリ移動されるので今回はS3を使う
npm install @aws-cdk/aws-s3

作ったらまずは適当にBucketを作る

import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';

export class CdkTestStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    new s3.Bucket(this, 'TestBucket', {
      bucketName: 'ex-test-bucket-000000'
    });
  }
}

デプロイする

npm run cdk -- deploy

で、作ったあとにやっぱRemovalPolicyにDESTROYをつけたくなったとする

new s3.Bucket(this, 'TestBucket', {
  bucketName: 'ex-test-bucket-000000',
  removalPolicy: cdk.RemovalPolicy.DESTROY,
});

diffが出る(元々デフォルトでRetainがついてるので)

npm run cdk -- diff

> cdk-test@0.1.0 cdk
> cdk "diff"

Stack CdkTestStack
Resources
[~] AWS::S3::Bucket TestBucket TestBucket560B80BC 
 ├─ [~] DeletionPolicy
 │   ├─ [-] Retain
 │   └─ [+] Delete
 └─ [~] UpdateReplacePolicy
     ├─ [-] Retain
     └─ [+] Delete

デプロイするとNo changes!!!!😇

npm run cdk -- deploy

> cdk-test@0.1.0 cdk
> cdk "deploy"

CdkTestStack: deploying...
CdkTestStack: creating CloudFormation changeset...

 ✅  CdkTestStack (no changes)

というわけで↓を新たに入れておく

new cdk.CfnOutput(this, 'UpdateTime', {
  description: 'UpdateTime',
  value: new Date().toLocaleString(),
})

diffが増える

npm run cdk -- diff

> cdk-test@0.1.0 cdk
> cdk "diff"

Stack CdkTestStack
Resources
[~] AWS::S3::Bucket TestBucket TestBucket560B80BC 
 ├─ [~] DeletionPolicy
 │   ├─ [-] Retain
 │   └─ [+] Delete
 └─ [~] UpdateReplacePolicy
     ├─ [-] Retain
     └─ [+] Delete

Outputs
[+] Output UpdateTime UpdateTime: {"Description":"UpdateTime","Value":"2021/7/22 16:51:32"}

デプロイをする
今回はリソースを追加したので当たり前だが成功する

npm run cdk -- deploy

> cdk-test@0.1.0 cdk
> cdk "deploy"

CdkTestStack: deploying...
CdkTestStack: creating CloudFormation changeset...

 ✅  CdkTestStack

Outputs:
CdkTestStack.UpdateTime = 2021/7/22 16:52:02

今度はRemovalPolicyをRETAINに戻したくなったとする

new s3.Bucket(this, 'TestBucket', {
  bucketName: 'ex-test-bucket-000000',
  // removalPolicy: cdk.RemovalPolicy.DESTROY, これを削除する
});

diffを見る
(ぱっと見、上で失敗したときのパターンに見える)

npm run cdk -- diff

> cdk-test@0.1.0 cdk
> cdk "diff"

Stack CdkTestStack
Resources
[~] AWS::S3::Bucket TestBucket TestBucket560B80BC 
 ├─ [~] DeletionPolicy
 │   ├─ [-] Delete
 │   └─ [+] Retain
 └─ [~] UpdateReplacePolicy
     ├─ [-] Delete
     └─ [+] Retain

これをdeployするとOutputsのUpdateTimeが変わる為、CDK(CFn)はちゃんとデプロイしてくれる

npm run cdk -- deploy

> cdk-test@0.1.0 cdk
> cdk "deploy"

CdkTestStack: deploying...
CdkTestStack: creating CloudFormation changeset...


 ✅  CdkTestStack

Outputs:
CdkTestStack.UpdateTime = 2021/7/22 16:56:21

再度diffを叩くと何も変更なしになる
(リソースへの変更は適用された為)

npm run cdk -- diff

> cdk-test@0.1.0 cdk
> cdk "diff"

Stack CdkTestStack
There were no differences

この状態でdeployするとUpdateTimeに対しての変更がかかる

npm run cdk -- deploy

> cdk-test@0.1.0 cdk
> cdk "deploy"

CdkTestStack: deploying...
CdkTestStack: creating CloudFormation changeset...


 ✅  CdkTestStack

Outputs:
CdkTestStack.UpdateTime = 2021/7/22 16:58:23

とまあこんな感じでOutputsにUpdateTimeとかを設定しておけば、
管理したいリソースに対して変更を加えずともOutputsに変更を加えて半強制的にデプロイをすることが出来て便利という小技