AWS CDK 和 SAM 是 DOP-C02 中較高抽象層級的 IaC 選擇。CloudFormation 是宣告式的 YAML/JSON,強迫你詳盡列出每個資源,而 CDK 則讓你使用 TypeScript、Python、Java、C# 或 Go 編寫基礎架構並合成 (synthesize) 出 CloudFormation,而 SAM 則是專為無伺服器 (serverless) 優化的 CloudFormation 轉換 (transform)。考試會測試這兩者何時優於純 CloudFormation、L1/L2/L3 構造 (construct) 層級結構、用於自我突變 (self-mutating) CD 的 CDK Pipelines、用於組織級政策注入的 CDK Aspects、SAM 漸進式部署(透過 CodeDeploy)以及簡化無伺服器 IAM 的政策範本。
本指南假設你已了解什麼是 CloudFormation 堆疊以及 Lambda 函式。DOP-C02 的重點在於:L1 vs L2 vs L3 構造權衡、CDK 引導 (bootstrap) 與工具箱 (toolkit) 堆疊、CDK Pipelines 自我突變、用於全組織政策注入的 CDK Aspects、SAM 轉換 vs 原始 CloudFormation、用於離線測試的 sam local、sam deploy --guided、漸進式部署配置 (Canary10Percent5Minutes, Linear10PercentEvery1Minute, AllAtOnce) 以及 政策範本(如 DynamoDBCrudPolicy)。
為什麼 CDK 與 SAM 在 DOP-C02 中很重要
DOP-C02 在 2023 年取代 DOP-C01 時明確將 CDK 納入範疇。社群考試報告指出,IaC 選擇場景是排名前三的考試考點之一:「團隊有 50 個微服務,每個都包含 API Gateway + Lambda + DynamoDB,希望透過單個命令部署並內置畫線部署 (canary)」 —— 答案是 SAM。「平台團隊希望強制執行應用團隊建立的每個 S3 儲存桶都必須啟用版本控制和 KMS-CMK 加密,且規則要以程式碼形式表達」 —— 答案是 CDK Aspects。「團隊使用 Python 編寫基礎架構,並希望在 IDE 中對 AWS 資源進行類型檢查的自動完成」 —— 答案是 CDK。
考試還會拿 CDK 與 CloudFormation StackSets 進行多帳戶部署的對比、CDK Pipelines 與 CodePipeline + CloudFormation 操作的對比,以及 SAM 與 Serverless Framework 的對比。了解每種工具的精確範圍是區分 30 秒得出答案與 4 分鐘排除法難題的關鍵。
- AWS CDK: 一種開源 IaC 框架,讓你能使用通用程式語言 (TypeScript, Python, Java, C#, Go) 定義雲端資源並合成 CloudFormation 範本。
- 構造 (Construct): CDK 的基本建置區塊;代表一個或多個 AWS 資源的類別。
- L1 構造 (CFN 資源): 自動生成的與 CloudFormation 資源 1:1 映射的構造(例如
CfnBucket)。 - L2 構造 (策劃級): 經過人工設計的構造,具有合理的預設值和輔助方法(例如帶有
grantRead(role)的Bucket)。 - L3 構造 (模式級): 結合多個資源的高級模式(例如
ApplicationLoadBalancedFargateService)。 cdk synth: 將 CDK 程式碼合成 CloudFormation 範本到cdk.out目錄中。cdk deploy: 執行合成並透過 CloudFormation 進行部署。cdk bootstrap: 在目標帳戶與區域對中佈署 CDK 工具箱堆疊(S3 儲存桶、ECR 儲存庫、IAM 角色),每個目標需執行一次。- CDK Pipelines: 一種 L3 構造,能完全在 CDK 程式碼中建立自我突變的 CodePipeline 定義。
- CDK Aspect: 實作
IAspect.visit(node)的類別,用於遍歷構造樹並套用橫切 (cross-cutting) 修改(例如強制對所有資源加上標籤)。 - AWS SAM: 一種 CloudFormation 轉換 (
Transform: AWS::Serverless-2016-10-31) 和 CLI 工具,簡化了無伺服器應用程式範本。 - SAM 範本: 使用 SAM 無伺服器資源類型 (
AWS::Serverless::Function,AWS::Serverless::Api,AWS::Serverless::HttpApi,AWS::Serverless::StateMachine) 的 CloudFormation 範本。 - SAM 漸進式部署: 一項 SAM 功能,透過
AutoPublishAlias+DeploymentPreference在 Lambda 函式別名上接入 CodeDeploy 流量轉移。 - SAM 政策範本: 具名且參數化的 IAM 政策片段(例如
DynamoDBCrudPolicy),由 SAM 注入 Lambda 執行角色中。 - 參考資料: https://docs.aws.amazon.com/cdk/v2/guide/home.html
白話文解釋 CDK 與 SAM
這些工具將數百行 CloudFormation 壓縮成數十行程式碼。類比法可以揭示抽象層次從何而來,以及何處可能出現問題。
類比 1:IKEA 家具層次結構
想像買家具。純 CloudFormation 是 購買原始木材、螺絲和說明書 —— 你必須指定每一塊板子、每個螺帽、每個墊片。可靠但繁瑣。L1 CDK 構造 是同樣的木材和螺絲,但透過程式化的目錄下單 —— 原子層級相同,但訂購速度稍快。L2 CDK 構造 是 IKEA 平整包裝箱 —— 你指定「Billy 書架,白色,80 公分」,箱子裡就自動包含了正確的板材、螺絲和說明書。你仍可自定義(「加裝玻璃門」),但不再需要計算單個螺絲的數量。L3 CDK 構造 是 完全組裝、送貨到府並安裝好 的產品 —— 你說「兩人辦公工作站」,整個桌椅螢幕電纜包就按配置送達。
SAM 是 專屬的居家辦公家具目錄 —— 狹義地專注於無伺服器桌椅,內置「人體工學調節」(漸進式部署)和「語音激活組裝」(sam local) 等一般家具目錄懶得優化的功能。
類比 2:軟體程式語言堆疊
CloudFormation YAML 是 組合語言:每個暫存器、每個記憶體地址都必須顯式指定。CDK L1 是 帶有巨集的 C 語言 —— 底層仍是同樣的組合語言,但有了具名常數。CDK L2 是 帶有標準函式庫的 C++ —— 你寫 Bucket(grantRead: role) 而非手寫儲存桶政策。CDK L3 是 像 Spring 或 Rails 這樣的框架 —— 一行程式碼就能給你一個完整配置的 ALB-ECS-CloudWatch 三元組。
SAM 是針對一種工作負載類型(無伺服器)的 領域特定語言 (DSL),就像 SQL 之於資料庫。對於無伺服器應用,它比 CloudFormation 更簡短,因為它了解這些模式,但它無法表達非無伺服器的工作負載。
cdk synth 是編譯器,將你的高級程式碼轉回 CloudFormation 引擎真正執行的組合語言。CDK Aspects 是 linter 或靜態分析器,遍歷合成後程式的每一行,強制執行「禁止未加密 S3」之類的規則。
類比 3:餐廳廚房設備等級
餐廳選擇廚房設備有三個等級。第 1 級 (L1) 是 單獨購買每個組件 —— 加熱元件、恆溫器、控制板、外殼 —— 並自行組裝。完全掌控,但工作量巨大。第 2 級 (L2) 是 購買商用烤箱 —— 製造商將組件與合理的預設值(溫度範圍、安全切斷)結合在一起;你可以微調設置,但不需要重新連接恆溫器線路。第 3 級 (L3) 是 購買完整的披薩工作站 —— 烤箱、揉麵機、備料台、冷卻架,全部整合並預先配置好。
SAM 是 僅限披薩工作站的專業供應商 —— 它不賣壽司台或燒烤台,但披薩工作站的出貨速度和價格比從通用供應商訂購要快且便宜。
CDK Pipelines 是 自我安裝的廚房承包商:你描述「我希望這個披薩工作站每週五從製造商那裡升級最新韌體」,承包商就會設置好自己的排程、訂購和安裝系統 —— 包括承包商自己,當自己的定義發生變化時,會先升級自己(自我突變)。
對於 CDK 構造層級,IKEA 層次結構 最貼切。對於「為什麼 CDK 會輸出 CloudFormation」,程式語言堆疊 捕捉到了合成/編譯步驟。對於 SAM 與 CDK 的範圍對比,廚房設備等級 讓權衡變得鮮活。參考資料: https://docs.aws.amazon.com/cdk/v2/guide/constructs.html
CDK 構造層次結構
L1/L2/L3 的劃分是測試最多的 CDK 概念。每個層級都有特定的用例和失效模式。
L1 構造 (CFN 資源)
L1 的名稱以 Cfn 開頭(例如 CfnBucket, CfnFunction)。它們是根據 CloudFormation 資源規格自動生成的 —— 每個 CloudFormation 資源類型對應一個 CDK 類別。屬性與 CloudFormation 屬性 1:1 映射。
L1 構造的正確選擇時機:
- 你需要一個尚未有 L2 的全新資源類型。
- 你需要一個 L2 尚未公開的 CloudFormation 屬性。
- 你正在從現有的 CloudFormation 遷移並希望進行結構化轉換。
L2 構造 (策劃級)
L2 構造由 AWS 或社群人工設計。它們對 L1 進行了封裝:
- 合理的預設值(例如
Bucket在你調用versioned: true時啟用版本控制,並透過輔助方法添加儲存桶政策)。 - 輔助方法(如
grantRead(grantee))可正確組合 IAM 政策。 - 類型安全的列舉 (enums) 和驗證。
L2 是生產級 CDK 程式碼的預設選擇。命名約定是去掉 Cfn 前綴(Bucket, Function, Vpc)。
L3 構造 (模式級)
L3 構造將多個資源結合成一個架構模式。範例:
ApplicationLoadBalancedFargateService: ALB + Fargate 服務 + 任務定義 + 目標群組 + 記錄群組。LambdaRestApi: API Gateway REST API + Lambda 整合 + 部署。BackgroundQueue(社群): SQS + DLQ + Lambda 取用者。
L3 構造以靈活性換取簡潔性。如果考試場景提到「團隊必須遵守安全性基準,要求自定義 KMS 金鑰、特定的子網放置以及已加標記但不被修改的 ALB 屬性」,通常會排除 L3,因為該模式的預設值與基準衝突。答案通常是帶有顯式配置的 L2。參考資料: https://docs.aws.amazon.com/cdk/v2/guide/constructs.html
CDK 引導 (Bootstrap) 與合成生命週期
CDK 不會直接寫入 AWS API —— 它合成 CloudFormation。引導和合成步驟是可測試的概念。
cdk bootstrap
在向新的帳戶-區域對佈署 CDK 之前,你需要執行 cdk bootstrap aws://ACCOUNT/REGION。這會佈署 CDK 工具箱堆疊:一個用於成果物上傳的 S3 儲存桶(Lambda zip、Docker 上下文)、一個用於容器映像的 ECR 儲存庫,以及 CDK 在 CodePipeline 或本地 CLI 中佈署時使用的 IAM 角色 (cdk-hnb659fds-cfn-exec-role, cdk-hnb659fds-deploy-role 等)。
對於多帳戶部署,你需要為每個目標帳戶使用 --trust ACCOUNT_ID 進行引導,以允許來源管道帳戶跨帳戶切換 (assume) 部署角色。
常見場景:你在工具帳戶設置了目標為生產帳戶的 CDK Pipelines;佈署因「無法切換角色 (cannot assume role)」而失敗。解決方法是使用 --trust TOOLING_ACCOUNT_ID --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess 重新引導生產帳戶。信任關係是在引導時設置的,而非在建立管道時。參考資料: https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html
cdk synth
cdk synth 執行你的 CDK 應用,遍歷構造樹,並將 CloudFormation 範本和成果物寫入 cdk.out/。輸出結果稱為 雲端組件 (cloud assembly)。CDK Pipelines 中的 CodeBuild 階段會調用 cdk synth 並將組件傳遞到下一個階段。
重要的是,在給定相同上下文輸入的情況下,cdk synth 是確定性的。CDK 使用 Context (上下文)(cdk.context.json 中的 JSON 快取)將 Vpc.fromLookup 之類的查找操作固定到特定值 —— 如果你不提交 cdk.context.json,你的 CI 建置可能會解析出不同的 VPC 並產生不同的範本。
CDK Pipelines:自我突變的 CD
CDK Pipelines 是一種 L3 構造,它建立的 CodePipeline 其定義本身就在 CDK 程式碼中。最顯著的特性是 自我突變 (self-mutation):當你更改管道定義(添加階段、更改部署動作)時,管道會在執行部署前,在第一階段自我更新。
標準的 CDK Pipelines 流程:
- Source: 從 CodeCommit、GitHub 或 S3 拉取。
- Synth: CodeBuild 執行
cdk synth產生雲端組件。 - UpdatePipeline (自我突變): 佈署任何管道定義的變更。
- Assets: 將 Lambda zip、Docker 映像上傳到引導 S3/ECR。
- DeployStages: 你定義的每個
Stage各佔一個階段,可包含可選的pre和post步驟。
跨帳戶 CDK Pipelines 部署之所以有效,是因為每個目標帳戶都已使用 --trust SOURCE_ACCOUNT 進行引導,授予來源帳戶切換部署角色的權限。管道定義本身不需要單獨的跨帳戶角色配置 —— 信任關係存在於引導堆疊中。參考資料: https://docs.aws.amazon.com/cdk/v2/guide/cdk_pipeline.html
CDK Aspects:橫切政策注入
Aspects 實作了帶有 visit(node: IConstruct) 方法的 IAspect。CDK 應用調用 Aspects.of(scope).add(new MyAspect()) 在某個範圍內註冊 Aspect;Aspect 會在合成前針對該範圍子樹中的每個構造被調用一次。
常見的 DOP-C02 Aspect 模式:
- 強制標籤:遍歷樹狀結構,確保每個可加標記的資源都具備
Environment,CostCenter,Owner標籤。 - S3 加密基準:遍歷樹狀結構,查找每個
CfnBucket,如果bucketEncryption未設置或設置為AES256而非 KMS-CMK,則使合成失敗。 - 自定義資源配置驗證:強制要求所有 RDS 實例的
BackupRetentionPeriod >= 7。
Aspects 在 CloudFormation 運行前就能合成錯誤 —— 它們是 IaC 層級的預提交 lint 規則。
SAM:為無伺服器優化的 CloudFormation
SAM 是一種 CloudFormation 轉換。頂部的 Transform: AWS::Serverless-2016-10-31 行告訴 CloudFormation 在佈署前將 SAM 資源展開為普通 CloudFormation。
SAM 資源類型
AWS::Serverless::Function: 展開為AWS::Lambda::Function+ IAM 角色 + 記錄群組 + 可選的事件源映射。AWS::Serverless::Api: 展開為AWS::ApiGateway::RestApi+ Deployment + Stage + Lambda 整合的許可。AWS::Serverless::HttpApi: 類似,但針對 API Gateway HTTP API。AWS::Serverless::StateMachine: 展開為AWS::StepFunctions::StateMachine+ 角色。AWS::Serverless::SimpleTable: 一個極簡的 DynamoDB 快捷方式。AWS::Serverless::Application: 巢狀另一個 SAM 範本(常用於 Serverless Application Repository)。
SAM CLI 命令
sam init: 從運行時 + 用例腳手架出一個範本。sam build: 建置 Lambda 成果物(已編譯、已解析依賴)。sam local invoke/sam local start-api: 使用 Docker 本地模擬 Lambda 和 API Gateway。sam package/sam deploy: 上傳成果物到 S3 並執行 CloudFormation。sam deploy --guided: 引導你完成部署參數並將其保存到samconfig.toml。
SAM 漸進式部署 (CodeDeploy 整合)
測試最多的 SAM 功能。添加到 AWS::Serverless::Function 中:
AutoPublishAlias: live
DeploymentPreference:
Type: Canary10Percent5Minutes
Alarms:
- !Ref ErrorRateAlarm
Hooks:
PreTraffic: !Ref PreTrafficLambdaFn
PostTraffic: !Ref PostTrafficLambdaFn
SAM 會佈署:
- 一個指向最新版本的 Lambda 別名
live。 - 一個 CodeDeploy 應用程式 + 部署群組。
- 按配置進行流量轉移:
Canary10Percent5Minutes、Linear10PercentEvery1Minute、AllAtOnce等。 - 如果在部署窗口期間觸發了列出的任何警示,則執行基於警示的自動回滾。
- 用於自定義驗證的流量切換前/後 Lambda 勾子。
如果沒有 AutoPublishAlias,SAM 不會建立別名,CodeDeploy 就沒有可以轉移流量的目標。DeploymentPreference 中的部署配置在沒有 AutoPublishAlias 的情況下會被忽略。請務必同時包含這兩者。參考資料: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html
SAM 政策範本
SAM 提供了約 70 個具名政策範本,可將限縮範圍的 IAM 注入 Lambda 執行角色。範例:
DynamoDBCrudPolicy: 對具名 DynamoDB 表的完整 CRUD。DynamoDBReadPolicy: 唯讀。S3ReadPolicy: 對具名儲存桶的 GetObject + ListBucket。SQSPollerPolicy: 對具名佇列的 ReceiveMessage + DeleteMessage。KMSDecryptPolicy: 對具名金鑰的解密。
用法:
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref OrdersTable
這會展開為正確範圍的政策,無需你手寫 IAM JSON。
CDK vs SAM vs CloudFormation 選擇
DOP-C02 選擇矩陣:
| 需求 | 選擇 |
|---|---|
| 純無伺服器應用,想要最短的範本 | SAM |
| 混合無伺服器 + 容器 + RDS,偏好強型別程式碼 | CDK |
| 現有團隊熟悉 CloudFormation,不引入新工具 | CloudFormation |
| 需要自我突變的 CD 管道 | CDK Pipelines |
| 需要組織範圍的橫切政策強制執行 | CDK Aspects |
| Lambda 需要內置畫線部署 (Canary) | SAM |
| 對多個帳戶分發相同的基準配置 | CloudFormation StackSets |
| 以上皆需 | CDK (合成出 CFN,透過 CfnInclude 與 StackSets 整合) |
SAM 沒有與 CloudFormation StackSets 對應的功能。要將 SAM 應用部署到許多帳戶,你需要將 sam deploy 包裝在 CodePipeline 跨帳戶操作或 CDK Pipelines 階段中。考生常在多帳戶 Lambda 基準配置問題中誤選「使用 SAM」;正確答案是「使用具有多個 Stage 目標的 CDK Pipelines」或「在 sam package 後使用 CloudFormation StackSets」。參考資料: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html
CDK 測試
CDK 提供了一個 assertions 模組,用於對合成後的範本進行單元測試:
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::S3::Bucket', {
BucketEncryption: { ... }
});
template.resourceCountIs('AWS::Lambda::Function', 3);
這能在 CI 執行 cdk deploy 前,捕捉意圖與合成輸出之間的漂移。結合基於 Aspect 的 linting 和 cdk synth --strict,構成了可靠的 IaC 測試金字塔。
常見陷阱 (Common Pitfalls)
- 對非無伺服器工作負載選擇 SAM:SAM 無法優雅地建模 EKS、ALB+Fargate 或 RDS。請選擇 CDK 或純 CloudFormation。
- 忘記為每個帳戶-區域對執行
cdk bootstrap:每個新目標都需要引導,跨帳戶還需加上--trust。否則cdk deploy會因缺失工具箱堆疊而失敗。 - 將 L3 視為免費升級:L3 構造隱藏了安全性基準可能要求的配置。對於規範嚴格的基準,L2 更安全。
- 混淆
cdk diff與 CloudFormation 變更集:cdk diff顯示的是合成範本的文字差異,而非 CloudFormation API 變更集。實際的變更集是在cdk deploy期間建立的。 - SAM 漸進式部署缺失
AutoPublishAlias:部署偏好會被默默忽略。 - 假設 CDK Pipelines 會自動引導目標帳戶:它不會 —— 引導是針對每個帳戶的一次性手動步驟。
- 無謂地使用 L1 構造:L1 犧牲了讓 L2 變得安全的 IAM 輔助方法和驗證;僅當 L2 尚未公開某些屬性時才降級到 L1。
FAQ
Q1:何時應偏好 CDK 而非 CloudFormation?
當你有邏輯繁重的基礎架構(循環、基於環境的條件判斷)、想要強型別自動完成、想要透過 npm/pip 套件跨團隊共享基礎架構函式庫,或想要透過 CDK Pipelines 實現自我突變管道時,CDK 勝出。當團隊是非開發人員(運運維或安全團隊),或你需要佈署到沒有 Node.js/Python 工具鏈的環境時,純 CloudFormation 勝出。
Q2:對於無伺服器應用,何時應偏好 SAM 而非 CDK?
對於純無伺服器應用,SAM 更快 —— 範本更短,內置 sam local,透過 DeploymentPreference 內置漸進式部署。CDK 對於混合工作負載或需要 TypeScript 級別抽象時更好。許多團隊在 SAM 中編寫 Lambda 應用,並在 CDK Stages 中編排它們。
Q3:我可以將現有的 CloudFormation 堆疊導入 CDK 嗎?
可以,透過 aws-cdk-lib/cloudformation-include 中的 CfnInclude。它將 YAML/JSON 範本載入 CDK 堆疊,並允許你在旁邊添加新構造。適用於增量遷移。
Q4:CDK 如何在刪除堆疊時處理具狀態 (stateful) 資源?
預設情況下,L2 具狀態構造(DynamoDB 表、RDS 實例、有內容的 S3 儲存桶)設置為 removalPolicy: RETAIN —— 資源在堆疊刪除後依然保留。你可以用 removalPolicy: DESTROY 覆蓋它。L1 構造則使用 CloudFormation 預設值 (Delete),因此降級到 L1 會重新引入意外刪除的風險。
Q5:CDK Pipelines 與 CodePipeline 的關係是什麼?
CDK Pipelines 合成 CodePipeline 定義。在運行時,執行的是 CodePipeline。CDK Pipelines 增加了自我突變來源階段和引導感知的部署動作。你仍可透過 CodePipeline 控制台檢查、監控和排查管道故障。
Q6:SAM 可以像普通 CloudFormation 一樣使用 Conditions 和 Mappings 嗎?
可以。SAM 範本本質上是疊加了 SAM 轉換的 CloudFormation 範本。Conditions, Mappings, Outputs, Parameters, Metadata —— 都能正常運作。SAM 僅增加了資源類型擴展,並未取代 CFN 語言。
Q7:如何在不部署的情況下測試 CDK 堆疊?
使用 aws-cdk-lib/assertions 模組對合成範本編寫單元測試。在 CI 中執行 cdk synth 並斷言輸出。對於整合測試,部署到隔離的開發帳戶並執行黑箱測試,然後執行 cdk destroy。合成時斷言能廉價地捕捉大多數回歸。
總結
CDK 和 SAM 將數百行 CloudFormation 壓縮為數十行程式碼。CDK 給你強型別語言、L1/L2/L3 層次結構、用於全組織政策的 Aspect 以及自我突變管道。SAM 為無伺服器應用提供了最短路徑,內置畫線部署和政策範本。異質平台選 CDK,僅限無伺服器選 SAM,非開發團隊選純 CloudFormation。跨帳戶工作請為每個目標帳戶引導一次並加上 --trust,使用 SAM 漸進部署切勿漏掉 AutoPublishAlias,且除非有特定的 L3 模式適用或 L1 才能填補的基準缺口,否則首選 L2 構造。