CodeBuild 是 AWS DevOps 堆疊中默默耕耘的主力。DOP-C02 中的每個 CI/CD 管線至少包含一個 CodeBuild 專案,且每個現實的建置情境都迫使你必須在基礎映像、buildspec 階段、環境變數、機密、快取和 VPC 連線能力之間做出決策。考試從不問「什麼是 CodeBuild」 —— 它考的是在給定限制下,哪些設定組合能產生快速、確定性 (deterministic) 且安全的建置,以及哪些組合會導致題目描述的失敗模式。
本指南將 buildspec.yml 視為必須熟記的內容(考試不會讓你查閱),接著加入專業級模式:存儲在 ECR 並具備私有登錄身份驗證的自訂映像、用於並行測試分片的批次建置、用於存取私有 RDS 或 ElastiCache 的 VPC 組態、透過 Parameter Store 和 Secrets Manager 注入機密,以及三種快取後端(S3、本機、自訂)。讀完後,你應該能在幾秒鐘內識別出每個常見的 CodeBuild 失敗模式 —— 無法存取登錄 (unable to access registry)、無法連接私有子網中的 RDS、因快取金鑰變更導致快取未命中、機密參考未被替換。
為什麼掌握 CodeBuild 決定了 DOP-C02 建置問題的勝負
考試中的 CodeBuild 問題乍看之下幾乎完全相同:「建置執行緩慢,工程師該怎麼辦?」、「建置無法存取私有資料庫,哪裡出錯了?」、「建置需要注入機密,哪種方法最安全?」。答案會根據關於快取後端、VPC 子網、NAT 閘道以及 buildspec 中 env.variables、env.parameter-store 和 env.secrets-manager 之間區別的細節而有所不同。
有三種力量解釋了為什麼 CodeBuild 佔據了 SDLC 自動化網域的大部分內容。第一,基礎映像選擇決定了建置速度(預裝工具)和安全姿態(符合 CIS 的映像)。第二,buildspec 階段語義決定了命令在何處執行以及如何產生完成品和報告 —— install vs pre_build vs build vs post_build 是不可互換的。第三,VPC 組態在連線能力與效能之間進行權衡(VPC 建置較慢,因為需要佈建 ENI),且這是建置期間存取私有資源的唯一方法。掌握這三點,其餘的只是細節。
- 建置環境 (Build environment):執行 CodeBuild 專案的運算與 Docker 映像組合;由
environment.type(例如LINUX_CONTAINER) 和environment.image(受管或自訂) 指定。 - 自訂映像 (Custom image):存儲在 ECR (私有)、Docker Hub (公開) 或經過身份驗證的 Docker Hub 中的 Docker 映像,用作建置環境而非使用 AWS 受管映像。
- buildspec.yml:一個 YAML 檔案 (位於原始碼根目錄或內嵌在專案中),描述建置階段、環境變數、成品 (artifacts) 和報告。
- 階段 (Phase):
install、pre_build、build、post_build之一 —— 執行命令的 buildspec 順序區段。 - 成品 (Artifact):上傳到 S3 的建置輸出;在 buildspec 的
artifacts下描述。 - 報告 (Reports):CodeBuild 受管的測試報告和程式碼覆蓋率資料,在
reports下聲明並可在主控台查看。 - 快取 (Cache):一種建置加速機制,具有三種後端 —— S3 (基於成品)、本機 (建置主機上的 Docker 圖層 / 原始碼 / 自訂) 和停用。
- 批次建置 (Batch build):一種 CodeBuild 功能,可並行執行多個建置,透過 buildspec 中的
build-list、build-matrix或build-graph定義。 - 建置環境變數:呈現在 Shell 中的類型化值 —— 明文、Parameter Store 參考或 Secrets Manager 參考。
- 參考:https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html
白話文解釋 CodeBuild 建置環境
CodeBuild 可能感覺像個黑盒子,因為在「git push」和「成品上傳」之間發生了很多事情。三種類比可以解開其中的機制。
類比 1:專業廚房的準備工作 (Mise en Place)
想像一個精緻餐飲廚房正在準備多道菜餐點。建置環境映像就是工作站 —— 義大利麵站、甜點站、燒烤站 —— 預先配備了正確的工具和食材。AWS 受管映像是租用廚房提供的預建工作站;自訂 ECR 映像是你從自己餐廳帶來的專屬工作站,完全按照廚師的喜好配置。
buildspec.yml 就是貼在工作站上的準備卡。它有四個階段,完美對應廚房的節奏。install 是「點燃爐火並拆封特殊設備」 —— 安裝語言執行階段、設定 NPM、安裝 AWS CLI 外掛程式。pre_build 是「清洗並切好所需的一切」 —— 登入 ECR、提取依賴項、獲取機密。build 是「實際烹飪菜餚」 —— 編譯、執行單元測試、建置 Docker 映像。post_build 是「擺盤、裝飾並送至出餐口」 —— 將 Docker 映像推送到 ECR、產生測試報告、編寫下游階段所需的 imagedefinitions.json 成品檔案。
快取是兩次服務之間的步入式冰箱 —— 預先準備好的食材 (編譯好的 node_modules、下載好的 Maven 依賴項),你可以直接拿取而無需重複切菜步驟。環境變數是今日特餐看板 —— 廚師在整個輪班期間參考的值。Secrets Manager 參考是辦公室裡的保險箱 —— 僅在需要時才取出酒窖鑰匙,絕不寫在準備卡上。
類比 2:工業流水線
想像一家生產電子的工廠。建置環境就是流水線本身 —— 傳送帶速度、機械臂、焊接站。自訂映像是針對特定產品類別的專業流水線;更換產品意味著切換流水線,而不是現場重新調整工具。buildspec 階段是產品經過的工站序列 —— 入庫 QA (install)、零件準備 (pre_build)、組裝 (build)、出庫 QA 與包裝 (post_build)。批次建置是多條並行流水線同時生產變體 —— A 線生產 iOS 變體,B 線生產 Android 變體,C 線生產 Web 變體,全部由單一工單觸發。
VPC 組態是工廠車間的位置 —— 當建置需要存取私有資料庫時,你實際上是將流水線放置在客戶的安全倉庫內,而不是公共工業園區;這會減慢設置速度 (ENI 佈建需要 30 秒),但這是存取倉庫內部條碼服務的唯一方法。
類比 3:電影製作現場
電影製作包含正片拍攝 (build)、前期製作 (pre_build) 和後期製作 (post_build)。CodeBuild 專案就是製作公司的合約,聲明了工作人員 (運算類型)、地點 (映像)、時間表 (逾時) 以及交付成果 (成品和報告)。環境變數是通告表 (call sheet) —— 每個工作人員當天需要知道的事情。機密是鎖定的劇本 —— 僅在讀劇本的那一刻交付給演員;絕不印在通告表上。
服務角色是拍攝許可證 —— 沒有它,工作人員無法進入現場、租用設備或上傳毛片。VPC 組態是封閉式片場 —— 影業在守衛嚴密的設施內租用攝影棚,因為在戶外拍攝會洩露未發佈的預告片。這總是會減慢製作進度,但有時是影業合規團隊的要求。
廚房類比在日常工作中開發最有用,因為階段能乾淨地對應到 install/pre_build/build/post_build。工廠類比最適合用於批次建置和 VPC 推理。電影類比則是當考試強調治理、機密和稽核時的正確模型。參考:https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html
buildspec.yml 階段 — 什麼在哪裡執行
buildspec 的四個順序階段各有其語義含義。放錯命令是常見的 Bug 來源,也是高頻的考試陷阱。
install 在建置環境啟動後但在複製原始碼之前執行。用於環境設定:安裝語言執行階段 (runtime-versions)、套件管理員、AWS CLI 外掛程式。避免在這裡放置業務邏輯。
pre_build 在複製原始碼後執行,是建置前必須執行的外傳效應的正確位置:ECR 登入 (aws ecr get-login-password | docker login)、npm install、mvn 依賴項解析、從 S3 獲取組態檔案。
build 是主要工作負載:編譯、單元測試、打包、Docker 映像構建。除非被 on-failure 覆蓋,否則此階段最後一個命令的結束代碼決定建置是否成功。
post_build 無論 build 成功或失敗都會執行 (除非設定 on-failure: ABORT)。用於清理、將映像推送到 ECR (僅在成功時 —— 封裝在 if [ "$CODEBUILD_BUILD_SUCCEEDING" = "1" ]; then ...; fi 中)、測試報告最終化以及編寫成品定義檔案。
考試喜歡出陷阱題,例如將 docker push 放在 build 中,速率限制錯誤觸發了階段失敗,但映像仍然上傳了 —— 了解 post_build 在失敗時也會執行是關鍵洞察。
來自 ECR 的自訂映像
對於需要特殊工具鏈 (特定 Java 版本、Node + Python 多執行階段、嵌入式工具鏈) 的建置,AWS 受管映像是不夠的。存儲在 ECR 中的自訂 Docker 映像是標準答案。
要使用 ECR 映像,請將 environment.image 設定為映像 URI (例如 123456789012.dkr.ecr.us-east-1.amazonaws.com/build-toolchain:v1.2),並將 environment.imagePullCredentialsType 設定為 SERVICE_ROLE (CodeBuild 使用專案服務角色提取) 或 CODEBUILD (CodeBuild 使用自己的服務主體 —— 適用於 Docker Hub 但不適用於 ECR)。服務角色必須包含對該映像存儲庫的 ecr:GetAuthorizationToken、ecr:BatchCheckLayerAvailability、ecr:GetDownloadUrlForLayer 和 ecr:BatchGetImage 權限。
ECR 公開登錄映像使用 public.ecr.aws/... URI,提取時不需要身份驗證,但可能有速率限制。
當建置失敗並顯示 error pulling image: Unable to authenticate to ECR 時,原因幾乎總是以下之一:(1) 對於 ECR 映像,imagePullCredentialsType 設定為 CODEBUILD 而非 SERVICE_ROLE;(2) 服務角色缺少 ecr:GetAuthorizationToken;或 (3) ECR 存儲庫政策缺少服務角色的主體權限。考試會測試這種精確的排錯。參考:https://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker-custom-image.html
環境變數、Parameter Store 和 Secrets Manager
CodeBuild 的 buildspec 中的 env 區塊支援三種環境變數。
env.variables 是內嵌定義的明文值。適用於非敏感組態,如 BUILD_ENV: production 或 REGION: us-east-1。
env.parameter-store 參考 SSM Parameter Store 路徑,CodeBuild 在建置啟動時獲取值。適用於非敏感的結構化組態 —— 功能旗標、版本鎖定、環境 URL。階層路徑 (/build/prod/dbHost) 讓多環境管理更簡潔。
env.secrets-manager 參考 Secrets Manager 機密 ARN,CodeBuild 在建置啟動時獲取值。適用於需要輪換的認證:資料庫密碼、第三方 API 金鑰、OAuth 權杖。服務角色需要對特定機密 ARN 具備 secretsmanager:GetSecretValue 權限;應遵循最小權限原則。
一個微妙的 DOP-C02 陷阱:將機密以明文寫入 env.variables 會使其在 CloudFormation 模板、專案描述和 CloudTrail 中被看見。務必對敏感值使用 env.secrets-manager。Buildspec 參考可以使用 secret-id:json-key:version-stage:version-id 語法來提取機密的特定 JSON 欄位。
直接將 DB_PASSWORD: mySecret123 放在 env.variables 中,會將該值暴露在 CodeBuild 專案組態、CloudFormation 模板以及建立專案的任何管線定義中。修正方法是使用 env.secrets-manager: DB_PASSWORD: rds/prod/password,這樣值會在建置時獲取,永遠不會序列化到組態中。只要題目提到認證、權杖或金鑰,考試都會將 env.variables 標記為錯誤。參考:https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html
用於私有資源存取的 VPC 組態
預設情況下,CodeBuild 執行在 AWS 受管的 VPC 中,具備公開網際網路存取權,但沒有通往你私有子網的路由。要存取私有資源 (RDS, ElastiCache, 僅限內部的端點),請為專案配置 VPC、子網和安全群組。
權衡是真實存在的。連接 VPC 的建置在建置開始前需要花費 20–60 秒佈建 ENI (在較少使用的子網中冷啟動時間更長)。它們會失去直接的網際網路存取權 —— 要存取套件登錄、ECR 或 S3,你需要 NAT 閘道、VPC 端點或兩者兼具。子網必須是私有子網並具備 NAT 以便進行面向網際網路的提取;將建置放置在公有子網中是行不通的,因為 CodeBuild 不會為 ENI 分配公有 IP。
VPC 建置的最佳實務:預先構建已安裝所有工具鏈依賴項的自訂建置映像,這樣建置就不需要網際網路存取來安裝套件。透過 VPC 端點 (com.amazonaws.region.ecr.dkr 和 com.amazonaws.region.ecr.api) 而非 NAT 從 ECR 提取,以節省頻寬成本。
快取後端 — S3、本機、自訂
CodeBuild 支援三種快取模式,透過 cache.type 配置。
S3 快取將任意快取檔案 (在 buildspec 的 cache.paths 下聲明) 存儲在 S3 儲存桶中。最適合跨建置快取:Maven ~/.m2、NPM ~/.npm、Gradle ~/.gradle。第一次建置填充快取;後續建置在 install 之前還原快取。S3 快取是最終一致性的 —— 並行建置可能會相互覆蓋。
本機快取 (Local cache) 將快取存儲在建置主機的本機磁碟上,並在同一執行個體的建置之間保留。有三量子模式:LOCAL_DOCKER_LAYER_CACHE (快取 Docker 圖層,需要特權模式)、LOCAL_SOURCE_CACHE (快取 Git 原始碼樹) 和 LOCAL_CUSTOM_CACHE (快取 buildspec 中聲明的路徑)。比 S3 快取快,但僅在建置重複使用同一個溫暖主機時才有效 —— 通常僅在建置頻率很高時發生。
自訂快取 僅限 buildspec 中聲明的本機自訂路徑。
快取選擇取決於工作負載。重度使用 Docker 的建置受益於本機 Docker 圖層快取。跨團隊共享的依賴項 (Maven 倉庫) 受益於 S3 快取。單一團隊的高頻建置受益於本機自訂快取。務必聲明 cache.paths 列表 —— 沒有它,S3 快取僅寫入編譯器管理的路徑,經常會遺漏。
對於重度使用 Docker 的管線,LOCAL_DOCKER_LAYER_CACHE 是最有效的快取 (在溫暖主機上,各層快取可將典型的容器建置時間縮短一半)。它要求 environment.privilegedMode: true 且僅在重複使用建置主機時才有效 —— 考試經常考「第一次建置慢,第二次建置快,為什麼?」,答案就是這個。參考:https://docs.aws.amazon.com/codebuild/latest/userguide/build-caching.html
用於並行測試分片的批次建置 (Batch Builds)
批次建置讓一個 CodeBuild 專案並行執行多個建置,這對於並行測試分片、多架構容器建置以及跨語言版本的矩陣測試非常有用。
存在三種批次類型。build-list 是變體組態的靜態陣列,每個變體獨立執行。適用於「每個測試分片一個建置」。build-matrix 是各維度的笛卡兒積 (例如 3 種作業系統 × 4 個 Node 版本 = 12 個建置)。build-graph 是具備依賴關係的 DAG,下游建置等待上游完成。適用於「編譯一次,然後並行測試,最後發佈」。
批次建置發出單一彙總結果;任何子建置失敗都可能導致批次失敗 (combine-artifacts 和 ignore-failure 設定可對此進行調整)。使用批次建置的管線動作使用 BatchEnabled: true 組態。
用於測試結果與程式碼覆蓋率的報告群組
CodeBuild 報告無需外部工具即可在主控台中呈現單元測試結果和程式碼覆蓋率。在 buildspec 中聲明 reports 區塊,列出報告群組 ARN、檔案格式 (JUnit XML, Cucumber JSON 等) 以及報告檔案的基準目錄。
報告群組可以跨多個專案引用,彙整結果以用於儀表板。服務角色需要 codebuild:CreateReport、codebuild:UpdateReport 和 codebuild:BatchPutTestCases 權限。
對於 DOP-C02,了解報告是 CodeBuild 的一等公民 (而非外部整合) 就足夠了;深層的 XML 格式細節在非專業級考試中才會考。
Webhook 與來源觸發器
CodeBuild 專案可以由來自 CodeCommit、GitHub、Bitbucket 的 Webhook 以及 S3 事件觸發。Webhook 過濾器群組讓你縮小觸發範圍 —— 例如,僅在 push 到 main 分支時執行,或僅在路徑符合 src/** 的 pull_request 事件上執行。
對於 DOP-C02,關鍵洞察是 Webhook 過濾器在 CodeBuild 啟動前由 SCM 端進行伺服器端評估,從而節省建置分鐘數。一個常見的情境:開發人員想要 PR 建置但不想要分支推送建置;配置兩個過濾器群組,一個用於 PR 事件,另一個排除分支推送。
端到端建置管線模式
一個代表性的 DOP-C02 建置管線組裝如下。Source 動作從 CodeCommit 提取。Build 動作執行一個 CodeBuild 專案,具備:一個預裝了 Java 17 和 Node 18 的自訂 ECR 映像、一個用於 ~/.m2 和 ~/.npm 的 S3 快取、從 Secrets Manager 提取用於 ECR 推送 (跨帳戶 ECR) 的機密、一個用於存取內部成品倉庫的 VPC 組態,以及一個執行單元測試、建置 Docker 映像、執行容器安全掃描並推送到 ECR 的 buildspec。建置會發出一個成品 imagedefinitions.json,供下游 ECS 部署動作取用。
這個管線的 buildspec 大約 60 行,並在一個地方展示了每個專業級模式。記住這個形狀可以讓你識別出任何考試題目中的缺漏。
記住任何 buildspec 問題的這五部分結構:
version: 0.2(一律使用;0.1 已棄用且不支援新功能)。env區塊,包含variables、parameter-store、secrets-manager以及 (可選的)git-credential-helper: yes。phases包含install、pre_build、build、post_build,並在 Linux 受管映像的 install 中明確指定runtime-versions。artifacts區塊,包含files、discard-paths以及 (針對多個成品)secondary-artifacts。reports區塊引用報告群組 ARN,加上用於跨建置加速的cache.paths。
任何 buildspec 問題都可以根據這五個部分進行分析。參考:https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html
常考陷阱(Common Exam Traps)
CodeBuild 有一組考試喜歡拋出的循環失敗模式。
陷阱 1:針對 ECR 映像使用 imagePullCredentialsType: CODEBUILD。CodeBuild 自己的服務主體無法讀取你的 ECR 存儲庫;必須是 SERVICE_ROLE 且服務角色具備 ecr:* 權限。
陷阱 2:VPC 建置無法存取網際網路,因為子網沒有 NAT 閘道或通往套件登錄的 VPC 端點。
陷阱 3:快取未命中,因為沒有聲明 cache.paths,而 S3 快取僅存儲編譯器管理的預設路徑。
陷阱 4:在 env.variables 中使用明文機密。一律對敏感值使用 env.secrets-manager 或 env.parameter-store 並指定 type: SECRETS_MANAGER。
陷阱 5:post_build 執行 ECR 推送時未檢查 CODEBUILD_BUILD_SUCCEEDING,導致失敗的建置推送了損壞的映像。
如果建置執行 docker build、docker run 或任何 Docker 命令,專案必須設定 environment.privilegedMode: true。若無此設定,建置將失敗並顯示 Cannot connect to the Docker daemon。考試經常透過一個建置 Docker 映像的 buildspec 以及一個忽略了特權模式的專案組態來測試這一點 —— 修正方法是組態旗標,而非 buildspec。參考:https://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker-custom-image.html
FAQ
Q1:我何時應優先選擇自訂 ECR 映像而非 AWS 受管映像?
在以下情況下使用自訂映像:(a) 你需要 AWS 未捆綁的工具鏈,(b) 法規合規性要求加固的基礎映像,或 (c) 建置速度受制於 apt-get install 操作,而預先構建可以消除這些操作。否則,AWS 受管的 aws/codebuild/standard:7.0 映像維護起來最快,因為 AWS 會修補 CVE。
Q2:單個 CodeBuild 專案可以在 Linux 和 Windows 上執行嗎?
不可以。environment.type (例如 LINUX_CONTAINER、WINDOWS_SERVER_2019_CONTAINER、ARM_CONTAINER) 每個專案是固定的。對於多平台建置,請使用批次建置,每個變體對應一個平台,分別指向不同的專案或批次項目,或者在並行管線動作中執行不同的專案。
Q3:如何在不洩露成品的情況下跨團隊共享建置快取?
使用具備儲存桶層級存取控制的 S3 快取。每個團隊的 CodeBuild 服務角色僅在自己的團隊前綴上獲得 s3:GetObject 權限。共通依賴項快取 (Maven Central 鏡像) 可以從中央前綴以唯讀方式跨所有團隊共享。
Q4:如果 buildspec 階段結束代碼為非零會發生什麼?
預設情況下,整個建置會失敗,且 post_build 仍然會執行 (除非設定 on-failure: ABORT)。在階段開始時使用 set -e 讓任何失敗的命令中止該階段,或者使用 if ! command; then ...; fi 模式進行明確的錯誤處理。建置狀態由最終階段的結束代碼決定,除非被覆蓋。
Q5:如何讓 CodeBuild 專案跨帳戶部署到 ECR?
兩步 IAM。服務角色需要對跨帳戶 ECR 存儲庫具備 ecr:PutImage 權限。跨帳戶 ECR 存儲庫政策需要允許服務角色的 ARN 作為主體。ECR 是區域性的,因此跨區域跨帳戶推送還需要目標區域的存儲庫具備匹配的存儲庫政策。
Q6:批次建置在計費時算作一個建置還是多個? 多個。批次建置的每個子建置都根據其運算分鐘數單獨計費。批次建置主要透過並行化節省掛鐘時間 (wall-clock time);與按順序執行相同的建置相比,它們不會節省成本。
Q7:Docker Hub 的 Docker 速率限制如何影響 CodeBuild? 匿名 Docker Hub 提取是受限的 (目前每個 IP 每 6 小時 100 次提取)。CodeBuild 的 NAT 閘道 IP 是由許多建置共享的,會很快達到限制。緩解措施:從 ECR Public 提取 (免費,對大多數映像無速率限制)、透過 Secrets Manager 支援的認證對 Docker Hub 進行身份驗證,或者將常用映像預先鏡像到 ECR 私有存儲庫。
Q8:CodeBuild 報告可以作為質量門檻 (quality gate) 來使管線失敗嗎?
報告本身不會使管線失敗 —— 它們記錄結果。要強制執行質量門檻,請在 post_build 中解析報告檔案,如果覆蓋率低於閾值或測試失敗次數超過計數,則以非零代碼結束。建置失敗狀態隨後會傳遞到管線。