本篇來聊聊當遇到已存在的 CloudFormation Stack 時該如何用 AWS CDK 管理?這是一個很常見的問題,尤其是一開始已經有用 CloudFormation 要過渡到 AWS CDK 最好是一個比較無痛的過程
照慣例先找到 AWS 官方文件放在前面:Import or migrate an existing AWS CloudFormation template,本篇所有的 sample code 都放在 shazi7804/cdk-samples
首先先準備一個既有的 CloudFormation template 作為範例:
Resources:
ExistBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Join ["-",['cfn-exist-bucket',!Ref "AWS::AccountId"]]
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
Tags:
- Key: version
Value: 'v1'
拿這個 CloudFormation template 建立一個名為 ImportExistCloudFormationStack 的 CloudFormation Stack,在這個 CloudFormation Stack 會產生一個 Bucket name 為 cfn-exist-bucket-{AccountId} 的 S3 Bucket。
CloudFormation Stack Name 相當重要,與待會 AWS CDK 產生的 Stack Name 必須相同
AWS CDK 有兩種方法 import CloudFormation Stack
- core.CfnInclude:單純就是 include CloudFormation 的基礎方法,要引用 Cfn 的值時要用
core.Fn.getAtt()
去拿,和 CloudFormation Fn::GetAtt 相同概念。 - cloudformation-include.CfnInclude:建議也是本篇實作的用法,要引用 Cfn 的值時可以直接從 return 拿到,比較貼近程式語言的開發方法。
cloudformation-include.CfnInclude 需要用到 @aws-cdk/cloudformation-include 這個 library
import cdk = require('@aws-cdk/core');
import s3 = require('@aws-cdk/aws-s3');
import cfn_inc = require('@aws-cdk/cloudformation-include');
建立一個 CfnInclude 的資訊,引用 CloudFormation YAML/JSON 檔案
# lib/import.ts
export class ImportCloudFormationStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StageProps) {
super(scope, id, props);
const cfnTemplate = new cfn_inc.CfnInclude(this, 'ExistCFN', {
templateFile: 'include/cloudformation.yaml',
});
}
}
New 一個 CDK App
# bin/cdk.ts
import * as cdk from '@aws-cdk/core';
import { MyStack } from '../lib/import';
const app = new cdk.App();
new MyStack(app, 'ImportExistCloudFormationStack');
必須注意 CDK Stack Name 要和 CloudFormation Stack Name 相同,否則 CDK 不曉得要管理哪一個 CloudFormation Stack。
測試一,cdk diff
應該要 There were no differences
沒有變更才算成功
$ cdk diff ImportExistCloudFormationStack
Stack ImportExistCloudFormationStack
There were no differences
測試二,修改 CloudFormation YAML 將 Tags 變更為 v2
Resources:
ExistBucket:
Type: AWS::S3::Bucket
Properties:
...
Tags:
- Key: version
Value: 'v2'
再 cdk diff
必須要 修改 而不是建立新的 Bucket
$ cdk diff
Resources
[~] AWS::S3::Bucket ExistCFN/ExistBucket ExistBucket
└─ [~] Tags
└─ @@ -1,6 +1,6 @@
[ ] [
[ ] {
[ ] "Key": "version",
[-] "Value": "v1"
[+] "Value": "v2"
[ ] }
[ ] ]