CodeBuild: Project, buildspec.yml và Lần Build Đầu Tiên

K
Kai··5 min read

Code đã nằm trên CodeCommit. Chặng tiếp theo của dây chuyền là build: lấy source đó, chạy các bước biên dịch/test/đóng gói, cho ra một artifact sẵn sàng để deploy. Đây là việc của CodeBuild. Bài này tạo một build project, viết file buildspec.yml định nghĩa các bước, chạy build thật trên app đã push ở bài trước, rồi đọc log để thấy chính xác CodeBuild làm gì.

Mục tiêu

Hiểu CodeBuild chạy một build ra sao (không chỉ "bấm build"), viết được buildspec.yml, tạo project bằng CLI và đọc kết quả qua phase và log.

buildspec.yml: công thức build

CodeBuild không đoán cách build app của bạn — bạn khai trong một file buildspec.yml đặt ở gốc repo. Tài liệu mô tả nó là "tập các lệnh build và thiết lập, dạng YAML, mà CodeBuild dùng để chạy build". Cấu trúc xoay quanh các phase chạy tuần tự:

version: 0.2

phases:
  install:
    commands:
      - echo "Install phase — preparing the build environment"
  pre_build:
    commands:
      - echo "Pre-build — validating the source"
      - test -f index.html && echo "index.html present"
  build:
    commands:
      - echo "Build phase — static site, packaging as-is"
      - echo "<!-- built by CodeBuild at $(date -u) -->" >> index.html
  post_build:
    commands:
      - echo "Post-build — build finished"

artifacts:
  files:
    - index.html
    - appspec.yml
    - 'scripts/**/*'
  name: awscicd-demo-app

Bốn phase bạn khai: install (cài công cụ/runtime), pre_build (chuẩn bị, đăng nhập registry, kiểm tra), build (lệnh build chính), post_build (đóng gói, đẩy image...). App của ta là trang tĩnh nên các lệnh chỉ minh hoạ; với app thật đây là nơi gọi npm run build, mvn package, go build... Khối artifacts khai những file nào sẽ được gói lại thành output — ở đây gồm index.html cùng appspec.ymlscripts/ mà bài deploy sẽ thêm. Commit file này vào repo và push lên CodeCommit (git push origin main).

Chọn môi trường build

CodeBuild chạy build trong một container Docker dựng sẵn. AWS cung cấp sẵn các image "curated"; đừng nhớ tên theo trí nhớ vì danh sách thay đổi — hỏi thẳng API:

$ aws codebuild list-curated-environment-images \
    --query "platforms[].languages[].images[].name" --output text \
    | tr '\t' '\n' | grep amazonlinux-x86_64-standard
aws/codebuild/amazonlinux-x86_64-standard:6.0
...

Bản chuẩn mới nhất lúc viết là aws/codebuild/amazonlinux-x86_64-standard:6.0 (dựa trên Amazon Linux 2023). Đây là image ta dùng. Mẹo: trong cấu hình bạn có thể chọn "luôn dùng bản mới nhất của runtime" để hưởng cache AMI và rút ngắn thời gian provisioning.

Tạo build project

Project gắn ba thứ lại: source (lấy code ở đâu), environment (build trong image nào), artifacts (đẩy output đi đâu), cộng service role (bài 2) để có quyền. Khai bằng một file JSON cho gọn:

{
  "name": "awscicd-demo-build",
  "source": {
    "type": "CODECOMMIT",
    "location": "https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/awscicd-demo-app",
    "buildspec": "buildspec.yml"
  },
  "sourceVersion": "refs/heads/main",
  "artifacts": {
    "type": "S3",
    "location": "awscicd-artifacts-111122223333-ap-southeast-1",
    "path": "builds", "packaging": "ZIP", "name": "awscicd-demo-app.zip"
  },
  "environment": {
    "type": "LINUX_CONTAINER",
    "image": "aws/codebuild/amazonlinux-x86_64-standard:6.0",
    "computeType": "BUILD_GENERAL1_SMALL"
  },
  "serviceRole": "arn:aws:iam::111122223333:role/awscicd-codebuild-role"
}
$ aws codebuild create-project --cli-input-json file://cb-project.json \
    --query 'project.[name,environment.image,serviceRole]' --output text
awscicd-demo-build  aws/codebuild/amazonlinux-x86_64-standard:6.0   arn:aws:iam::111122223333:role/awscicd-codebuild-role

Project trỏ source vào CodeCommit, artifact vào bucket S3 từ bài 2, và chạy dưới service role CodeBuild đã tạo — nhờ role đó nó có quyền codecommit:GitPull, ghi log, và ghi S3.

Chạy build thật

$ BUILD_ID=$(aws codebuild start-build --project-name awscicd-demo-build --query 'build.id' --output text)
$ echo "$BUILD_ID"
awscicd-demo-build:67099cde-784b-4788-a31c-dd8004c5cae8

Build chạy bất đồng bộ; poll trạng thái tới khi xong:

$ aws codebuild batch-get-builds --ids "$BUILD_ID" \
    --query 'builds[0].[buildStatus,currentPhase]' --output text
IN_PROGRESS PROVISIONING
...
SUCCEEDED   COMPLETED

Build thực sự gồm những gì

Đây là phần đáng mổ. Một build không chỉ là "chạy lệnh của bạn" — CodeBuild đi qua một chuỗi phase, trong đó phase bạn khai (install/pre_build/build/post_build) chỉ là phần giữa. Xem toàn bộ:

$ aws codebuild batch-get-builds --ids "$BUILD_ID" \
    --query 'builds[0].phases[].[phaseType,phaseStatus,durationInSeconds]' --output text
SUBMITTED         SUCCEEDED  0
QUEUED            SUCCEEDED  0
PROVISIONING      SUCCEEDED  4
DOWNLOAD_SOURCE   SUCCEEDED  5
INSTALL           SUCCEEDED  0
PRE_BUILD         SUCCEEDED  0
BUILD             SUCCEEDED  0
POST_BUILD        SUCCEEDED  0
UPLOAD_ARTIFACTS  SUCCEEDED  0
FINALIZING        SUCCEEDED  0
COMPLETED

PROVISIONING (4s) là lúc CodeBuild dựng container từ image; DOWNLOAD_SOURCE (5s) kéo code từ CodeCommit; rồi tới bốn phase từ buildspec.yml; UPLOAD_ARTIFACTS gói output đẩy lên S3; FINALIZING dọn dẹp. Container này phù du — dựng cho build này, chạy xong là vứt. Lần build sau dựng container mới, sạch hoàn toàn, nên build có tính tái lập: không có rác tồn từ lần trước.

   CodeCommit (refs/heads/main)
        │  DOWNLOAD_SOURCE
        ▼
   ┌─────── container tạm (amazonlinux-x86_64-standard:6.0) ───────┐
   │   chạy buildspec.yml:                                          │
   │   INSTALL → PRE_BUILD → BUILD → POST_BUILD                     │
   └───────┬───────────────────────────────────┬──────────────────┘
           │ UPLOAD_ARTIFACTS                   │ mỗi dòng lệnh → log
           ▼                                    ▼
      S3: builds/awscicd-demo-app.zip      CloudWatch Logs
                                           /aws/codebuild/awscicd-demo-build

Đọc log

Mỗi lệnh trong buildspec và đầu ra của nó được ghi lên CloudWatch Logs, nhóm /aws/codebuild/<project>. Xem vài dòng:

$ aws logs get-log-events --log-group-name /aws/codebuild/awscicd-demo-build \
    --log-stream-name 67099cde-... --query 'events[].message' --output text
...
Running command test -f index.html && echo "index.html present"
index.html present
Phase complete: PRE_BUILD State: SUCCEEDED
Entering phase BUILD
Running command echo "Build phase — static site, packaging as-is"
Build phase — static site, packaging as-is
...
Phase complete: POST_BUILD State: SUCCEEDED

Log cho thấy từng lệnh chạy, output của nó, và ranh giới mỗi phase. Khi build fail, đây là chỗ đầu tiên cần nhìn — phase nào fail, lệnh nào, lỗi gì.

Artifact đã nằm trên S3, đóng gói ZIP:

$ aws s3 ls s3://awscicd-artifacts-111122223333-ap-southeast-1/builds/ --recursive
2026-05-25 12:53:07        342 builds/awscicd-demo-app.zip

🧹 Dọn dẹp

Project này được pipeline ở Part V dùng lại, nên giữ tới cuối series. Khi muốn xóa:

$ aws codebuild delete-project --name awscicd-demo-build

CodeBuild chỉ tính tiền theo phút build thực tế, không có gì chạy nền, nên giữ project không build thì không tốn phí.

Tổng kết

CodeBuild build theo công thức trong buildspec.yml: các phase install/pre_build/build/post_build chạy tuần tự trong một container tạm dựng từ image curated (mới nhất amazonlinux-x86_64-standard:6.0). Một project gắn source (CodeCommit), environment (image + compute) và artifacts (S3) lại, chạy dưới service role. Build đi qua chuỗi phase rộng hơn phần bạn khai (PROVISIONING, DOWNLOAD_SOURCE, UPLOAD_ARTIFACTS...); mỗi lệnh ghi log lên CloudWatch; artifact ra ZIP trên S3. Container phù du nên build tái lập được.

Bài tới đào sâu CodeBuild: truyền biến môi trường và secret an toàn (từ SSM Parameter Store / Secrets Manager), bật cache để build nhanh hơn, và tinh chỉnh khối artifacts.