本篇文章內有:
在之前的文章中,我們都是用 sample-app
這個模板所生成的程式碼,在這篇文章中,我們終於要來親手寫 AWS CDK 了。
先建立一個新資料夾,透過下面的指令,在裡面生成一個空的 AWS CDK 專案。
npm exec --package=aws-cdk -- cdk init app --language=typescript
一樣用 Visual Studio Code 開啟專案後,我們要來編輯 lib
資料夾下的 app-stack.ts
,檔案名字可能會不同,但在 lib
之下也只有一個檔案,不會迷路,他應該會長得像這個樣子。
這邊建議大家可以開啟 Format On Save ,點選左下角的齒輪開啟設定 (Settings) ,或是按快捷鍵 macOS: cmd (⌘) + ,
, Windows: ctrl + ,
。
在上方搜尋欄輸入 editor.formatOnSave
,並勾選下方出現的 Format On Save ,這樣在儲存的時候, Visual Studio Code 就會試著幫你把程式碼變整齊。
回歸正題,先將空的 AWS CDK App 部署上去,如此一來我們比較好知道接下來新增的程式碼有甚麼效果。
npm run cdk -- deploy
接下來要做的是,在中間的部分, 建構子 (constructor
) 裡面, super
下面,貼上以下的程式碼。
new cdk.aws_s3.Bucket(this, 'bucket');
是的,就一行,如此一來我們就已經告訴了 AWS CDK 去建立一個 Amazon S3 。
馬上來看一下跟 AWS 上面的資源差異。
npm run cdk -- diff
出現了我們想要的 Amazon S3 儲存貯體。
Resources
[+] AWS::S3::Bucket bucket bucket43879C71
現在剩餘的事情就是將這個變更更新到 AWS 上面,更新的指令跟部署的指令是一樣的。
npm run cdk -- deploy
如果就這樣結束這篇文章也太便宜作者了,所以我們要來客製化這個Amazon S3 儲存貯體。
針對剛才貼上的程式碼,我們改成下面的內容。
new cdk.aws_s3.Bucket(this, 'bucket', {
encryption: cdk.aws_s3.BucketEncryption.KMS_MANAGED,
bucketKeyEnabled: true,
});
這邊是更改了加密行為,這將使用 Bucket Key 做加密,這是個可以節省 KMS API 呼叫次數,是個省錢的方式,來看一下差異變更。
Resources
[~] AWS::S3::Bucket bucket bucket43879C71
└─ [+] BucketEncryption
└─ {"ServerSideEncryptionConfiguration":[{"BucketKeyEnabled":true,"ServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}
發現這次的資源變更,從 [+]
變成了 [~]
,這是因為資源已經存在,只是針對其中的參數進行更新。
還有 [-]
這個符號,這是代表該資源將被刪除。
除了直接在物件建立時給予屬性,也有些參數是支援用物件方法進行設定或更新,我們將程式碼改成以下的內容。
const bucket = new cdk.aws_s3.Bucket(this, 'bucket', {
encryption: cdk.aws_s3.BucketEncryption.KMS_MANAGED,
bucketKeyEnabled: true,
});
bucket.addLifecycleRule({
expiration: cdk.Duration.days(7),
});
這次的差異也很清楚地列表出來,這個變更會讓 Amazon S3 自動刪除存放了 7 天以上的物件 (Object) 。
Resources
[~] AWS::S3::Bucket bucket bucket43879C71
└─ [+] LifecycleConfiguration
└─ {"Rules":[{"ExpirationInDays":7,"Status":"Enabled"}]}
我們可以進到 AWS Console 上面看剛才所有的變更,一樣在上方搜尋欄輸入 S3 進入服務頁面。
會發現這個 Amazon S3 儲存貯體的名稱實在是不和藹,甚至可以說很醜,這是因為 AWS CDK 在沒有特別指示的情況下,會自動為資源產生名字,而 AWS CloudFormation 會在資源後再加上亂數後綴,確保資源不會衝突。
其實,可以在建立物件時,加上這個屬性,讓 Amazon S3 儲存貯體的名字清楚明瞭。
bucketName: 'app-bucket'
這時如果看差異變更,會發現有點不一樣,後面多出了 Replace
。
Resources
[~] AWS::S3::Bucket bucket bucket43879C71 replace
└─ [+] BucketName (requires replacement)
└─ app-bucket
看了一下,原來更改名稱這個屬性會需要做資源替換 (requires replacement
) , AWS CDK CLI 也在差異變更中指出這件事情。
但這回在部署的時候,好像不妙,出現了 UPDATE_FAILED
,我們的變更沒有被成功的執行,但同時,既有的 Amazon S3 儲存貯體也沒有受到影響。
AppStack: deploying... [1/1]
AppStack: creating CloudFormation changeset...
AppStack | 0/3 | 12:00:04 AM | UPDATE_IN_PROGRESS | AWS::CloudFormation::Stack | AppStack User Initiated
AppStack | 0/3 | 12:00:07 AM | UPDATE_IN_PROGRESS | AWS::S3::Bucket | bucket (bucket43879C71) Requested update requires the creation of a new physical resource; hence creating one.
AppStack | 0/3 | 12:00:08 AM | UPDATE_FAILED | AWS::S3::Bucket | bucket (bucket43879C71) app-bucket already exists
AppStack | 0/3 | 12:00:08 AM | UPDATE_ROLLBACK_IN_P | AWS::CloudFormation::Stack | AppStack The following resource(s) failed to update: [bucket43879C71].
AppStack | 1/3 | 12:00:11 AM | UPDATE_COMPLETE | AWS::S3::Bucket | bucket (bucket43879C71)
AppStack | 2/3 | 12:00:11 AM | UPDATE_ROLLBACK_COMP | AWS::CloudFormation::Stack | AppStack
AppStack | 2/3 | 12:00:12 AM | DELETE_SKIPPED | AWS::S3::Bucket | bucket (bucket43879C71)
AppStack | 3/3 | 12:00:12 AM | UPDATE_ROLLBACK_COMP | AWS::CloudFormation::Stack | AppStack
熟悉的綠色勾勾不見了,變成兩個紅色的叉叉。
Failed resources:
AppStack | 12:00:08 AM | UPDATE_FAILED | AWS::S3::Bucket | bucket (bucket43879C71) app-bucket already exists
❌ AppStack failed: Error: The stack named AppStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: app-bucket already exists
at FullCloudFormationDeployment.monitorDeployment (/tmp/app/node_modules/aws-cdk/lib/index.js:443:10232)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Object.deployStack2 [as deployStack] (/tmp/app/node_modules/aws-cdk/lib/index.js:446:153546)
at async /tmp/app/node_modules/aws-cdk/lib/index.js:446:136809
❌ Deployment failed: Error: The stack named AppStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: app-bucket already exists
at FullCloudFormationDeployment.monitorDeployment (/tmp/app/node_modules/aws-cdk/lib/index.js:443:10232)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Object.deployStack2 [as deployStack] (/tmp/app/node_modules/aws-cdk/lib/index.js:446:153546)
at async /tmp/app/node_modules/aws-cdk/lib/index.js:446:136809
The stack named AppStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: app-bucket already exists
AWS CDK CLI 把錯誤訊息也列了出來,原來是已經有人佔用了 app-bucket
這個沒創意的名稱,果然亂數產生名字還是有一定的道理在的。
寫完這 8 行程式碼之後,如果有進去 AWS CloudFormation 看一下,會發現產生出來的模板超過 250行呢。
透過親自寫程式碼,雖然可能都是複製貼上,但應該有更了解如何透過 AWS CDK 建立 AWS 資源,也體驗到部署失敗的滋味,緊接著要來嘗試資源之間的互相參照。