本篇文章內有:
cdk.out
中的 tree.json
說好的 X 光機來了,我們先從最外面的 cdk.json
看起,畢竟他是 AWS CDK CLI 的設定檔,但他也太長了,我們就挑其中的 6 個常用的來說。
app
:這個項目可以填入兩種資訊,CDK App 的進入點,或是 cdk.out
的路徑。profile
:如果有指定 AWS Profile 的名稱,可以從這邊設定。progress
:指示 AWS CDK CLI 要如何呈現部署進度, bar
代表進度條, events
則會列出所有事件。requireApproval
:在部署時,若有安全性的變更,是否要暫停並等候確認,有三種模式, broadening
是預設值,只在增加時詢問; never
為永不確認, any-change
則是永遠都會問。rollback
:在部署失敗時,要不要自動復原,在除錯時,設為 false
很有幫助。watch
:在啟用監視模式時,用來決定要監視哪些檔案,可以利用 include
跟 exclude
做調整。再來,焦點轉到現在 app
所指定的檔案: bin/app.ts
,好的, 5 行程式碼跟一堆註解。
先從第一行開始,雖然他不是程式碼:
#!/usr/bin/env node
這是俗稱 Hashtag Shebang ,由井號 (hash or sharp) 跟驚嘆號 (bang) 所組成,用於載入器 (Loader) 知道說要使用哪個直譯器 (interpreter) 來執行以下的程式。
以這邊的例子來說,會利用 /usr/bin/env
去查找當前環境中 node
位於哪裡,並且執行他。
再來是引入套件的部分:
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { AppStack } from '../lib/app-stack';
source-map-support
:讓轉譯過後的 JavaScript 可以對照原始的 TypeScript 位置,方便除錯。aws-cdk-lib
: AWS CDK 的套件。../lib/app-stack
:我們所編寫的資源。接著建立了一個 CDK App :
const app = new cdk.App();
在 CDK 中, App 相當於一個專案,也是所有資源依附的對象,稍後會解釋這句話的意思。
最後是將我們的資源建立出來,以及很多註解:
new AppStack(app, 'AppStack', {});
發現我們把剛才建立的 CDK App 往這個地方傳進去,讓我們看一下是為什麼。
所以來到了 lib/app-stack.ts
:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
恩……怎麼多了 constructs
?先忽略好了。
找到 AppStack
了:
export class AppStack extends cdk.Stack {
原來他是從 Stack 擴充,或是繼承,而來的,又是個新名詞。
在建立這個 AppStack 的時候需要有 2~3 個參數:
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
做為 scope
的 Construct ,好,我知道不能再忽視這東西了,所以是時候進入下個章節。
不可避免的,要來看一下在每個 Stack 都會看到的東西, Construct 。
他可以說說建立起 CDK 的根本,在 AWS CDK 的官方網站上面是這樣描述的:
Constructs are the basic building blocks of AWS CDK apps. ...
...
Constructs are part of the Construct Programming Model (CPM). ...
...
A construct can represent a single AWS resource, ... . A construct can also be a higher-level abstraction consisting of multiple related AWS resources.
翻譯成人話就是, Construct 是無所不在的。
好,我認真說,在 CDK 中, Construct 可以代表任何一個資源。
換句話說,我們先前建立的 Amazon S3 儲存貯體是個 Construct , AWS EC2 執行個體是個 Construct ,拿來放置所有資源的 AppStack 也是個 Construct ,甚至最上層的 App 也都是 Construct 。
當這些 Construct 們組合在一起,便建構出一個完整的 CDK App 。
我們來用比喻好了,把整個 CDK App 當作一片果園, cdk.App
是這片果園本身,我們在上面中了一顆 cdk.Stack
的果樹,這棵樹又分枝長出了 Amazon S3 儲存貯體與 AWS EC2 執行個體的果實。
當我們在做 diff
與 deploy
時,這片果園會貼心地產生出現在他上面的植栽狀態,我覺得現代化農場很需要他,而這狀態,如果沒有變更過參數的話,可以在 cdk.out/tree.json
這邊看到。
cdk.out
中的 tree.json
不要被這上千行嚇到,我們看前 20 行就好。
{
"version": "tree-0.1",
"tree": {
"id": "App",
"path": "",
"children": {
"AppStack": {
"id": "AppStack",
"path": "AppStack",
"children": {
"bucket": {
"id": "bucket",
"path": "AppStack/bucket",
"children": {
"Resource": {
"id": "Resource",
"path": "AppStack/bucket/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::S3::Bucket",
"aws:cdk:cloudformation:props": {
這邊大致上可以有這樣的階級,我們先看 id
就好, App > AppStack > bucket Resource
,翻譯過來就是: App
中有個 AppStack
,裡面的 bucket
建立了 Resource
。
再來看 path
,會發現這些 id
都好好的放在這邊,形成了唯一路徑。
所以,其實一開始的話不是亂說的, Construct 的確無所不在,各式各樣對於 Construct 的擴充與實作,完成了這整個 CDK 。
而說到 Construct 最主要的功能,便是利用簡單的元件,不斷地拼接,逐漸組合出我們所期待的果園,也就是想要部署的基礎架構。
這時讓我們回到程式碼中,讓我擷取其中一些片段:
const app = new cdk.App();
new AppStack(app, 'AppStack', {});
export class AppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
}
}
一開始新增了 app
(cdk.App
) ,並將他作為 scope
(Construct
) 傳入 AppStack
(cdk.Stack
) ,就是這個地方,讓兩個 Construct 有了連結。
透過指定 scope
(Construct
) , CDK 才知道這棵樹,或是果實,應該在哪個地方。
至於說 App 跟 Stack 的命名嘛,我只能說,他沿襲了許多在 AWS 上面既有的名稱,App 是 Stack 的集合體,而 Stack 除了跟 AWS CloudFormation 的 Stack 重名,也是我們真正建立資源的地方,巧合嗎?我認為不是。
這篇基本上沒有需要寫程式碼的地方,所以篇幅少了點,更多的是理論與架構,但也就是這些知識才足以使我們可以更靈活的使用 CDK 這工具,後續的實作中,我們會參照部分 cdk.out/tree.json
的內容,讓各位更熟悉 CDK 的架構。