Cloud Build: Execution Model & Architecture
Tại sao lại quan trọng
Khi bạn submit một build đến Cloud Build, nó không chỉ "chạy command của bạn trên một server nào đó". Cloud Build là một distributed build system được thiết kế để vừa an toàn, vừa scalable, vừa auditable. Nếu bạn không hiểu cách nó thực sự hoạt động bên trong, bạn sẽ gặp phải:
- Bí ẩn về state: Tại sao step này không thấy output của step trước? (giải pháp là hiểu network model)
- Performance surprises: Tại sao build của tôi bị slow, hay sudden timeouts? (thường là ephemeral environment chưa warm)
- Debugging nightmares: Container của bạn crash ở bước 3 nhưng error message mơ hồ — không có cách để SSH vào và investigate live
- Scaling problems: Khi build volume tăng, bạn không hiểu tại sao queue lại backing up
Chương này sẽ dạy bạn mental model chính xác của Cloud Build execution, từ đó bạn sẽ dễ dàng design pipelines hiệu quả và debug failures nhanh chóng.
Internal Model: Cách Cloud Build Vận Hành
Cloud Build là gì?
Cloud Build là một managed CI/CD service trên GCP, nhưng nó không phải là những gì nhiều người tưởng. Nó không phải là một "server chạy mãi mãi" chạy các jobs của bạn — nó là một stateless, ephemeral build orchestrator mà:
- Nhận build request (thông qua trigger hoặc API call)
- Provisioning một worker (một VM mới) hoặc sử dụng available capacity từ shared default pool
- Execute các build steps trong sequence
- Capture outputs (logs, images, artifacts)
- Destroy worker (hoặc return nó về pool)
Toàn bộ quá trình này được thiết kế để immutable, auditable, và ephemeral.
Build Steps: Mô hình chính
Mỗi Cloud Build được định nghĩa là một sequence của build steps trong cloudbuild.yaml. Ví dụ:
steps:
- name: gcr.io/cloud-builders/git
args: ['clone', 'https://...']
- name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/app:$COMMIT_SHA', '.']
- name: gcr.io/cloud-builders/docker
args: ['push', 'gcr.io/$PROJECT_ID/app:$COMMIT_SHA']Thực tế hoạt động như thế nào:
Mỗi step là một Docker container execution. Cloud Build:
- Spins up container từ image được chỉ định (ví dụ:
gcr.io/cloud-builders/docker) - Mounts shared volume (workspace) vào container
- Executes command/args trong context của container đó
- Captures stdout/stderr để logging
- Waits for exit code (0 = success, non-zero = failure)
- Moves to next step nếu previous step thành công
Điểm quan trọng: Mỗi step chạy trong một container riêng, nhưng chúng chia sẻ cùng một workspace volume. Điều này nghĩa là:
- Step 1 tạo file
output.txt→ file này visible cho step 2, 3, 4, ... - Nếu step 1 install dependencies (ví dụ:
npm install), step 2 sẽ nhìn thấynode_modules/folder - Nhưng environment variables không chia sẻ — mỗi step là một process mới
Workers: Ephemeral Build Execution Environments
Đây là yếu tố critical mà nhiều people không hiểu rõ.
Default Pool Architecture:
Khi bạn submit một build, Cloud Build:
- Picks available worker từ shared default pool (hoặc waits nếu tất cả busy)
- Fresh VM provisioned — thường là Linux VM với Docker daemon sẵn sàng
- Workspace initialized — một ephemeral GCS bucket hoặc local disk được chuẩn bị
- Steps executed — lần lượt trong order
- Artifacts captured — logs written to Cloud Logging, images pushed to registry
- VM destroyed — sau khi build xong, worker được destroy hoặc reset
Tại sao ephemeral?
- Security: Mỗi build chạy trong isolated environment, không có state từ previous builds
- Failure isolation: Nếu step 1 crash, step 2 không execute (fail-fast model)
- Resource efficiency: Cloud Build không maintain idle workers — chỉ spin up khi cần
Worker capacity trong default pool:
Theo Google Cloud documentation, default pool có:
- Max 30 concurrent builds per project (mặc định)
- Machine types limited — thường là e2-standard machines
- No custom networking — worker chạy trên Google's managed network, không connect vào customer VPC
Nếu bạn cần private networking, higher concurrency, hoặc custom machine types, bạn phải dùng private worker pools (xem Chương 3).
Build Network Model: Isolation & Connectivity
Đây là part mà rất hay gây confusion.
Default Pool Network Topology:
Khi step chạy, nó chạy trong một container với:
- Internal hostname:
localhost(step có thể communicate với nhau qua localhost ports? Không, vì chúng chạy trong separate containers) - Shared volume:
/workspace— nơi source code được clone và artifacts được lưu - Cloud Logging agent: Built-in, automatic capture logs
- No persistent home directory — container filesystem là ephemeral
Connectivity to external services:
- Public internet: Default pool CÓ access to public internet (Google maintains egress routes)
- Cloud APIs: Fully accessible (built-in service account có IAM bindings)
- Customer VPC: NO direct access (unless you use private worker pools with VPC peering)
- Private databases behind VPC: Not accessible từ default pool
Đây là lý do tại sao private worker pools quan trọng — nếu bạn cần access private database hoặc internal services trong VPC, bạn không thể dùng default pool.
Build Storage: Workspace & Artifacts
Mỗi build có một ephemeral workspace:
Workspace location:
Khi bạn submit build, Google Cloud tạo một temporary directory (thường trên local disk của worker):
/workspace
├── (source code được clone vào đây)
├── .git/ (git history nếu source là từ Cloud Source Repos)
└── (artifacts được tạo ra ở đây)Workspace này được automatically mounted vào mỗi step container. Điều này cho phép steps chia sẻ files.
Artifact persistence:
Sau khi build xong, artifacts phải được explicitly pushed đến persistent storage:
- Docker images:
docker pushđến Artifact Registry hoặc Container Registry - Build outputs:
gsutil cpđến GCS bucket - Logs: Automatically captured by Cloud Logging
Nếu bạn KHÔNG explicitly push artifacts, chúng sẽ mất mãi sau khi build complete. Workspace là ephemeral.
Build Metadata & Environment Variables
Cloud Build injects built-in substitutions vào mỗi build:
substitutions:
_SERVICE_ACCOUNT: "cloud-builds@${PROJECT_ID}.iam.gserviceaccount.com"
steps:
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/${PROJECT_ID}/app:${SHORT_SHA}'
- '.'Built-in substitutions:
${PROJECT_ID}: GCP project ID${BUILD_ID}: Unique build ID${COMMIT_SHA}: Full commit hash (nếu trigger từ repo)${SHORT_SHA}: First 7 chars của commit hash${BRANCH_NAME}: Git branch name${REPO_NAME}: Repository name
Những variables này automatically populated bởi Cloud Build base trên trigger source. Nếu bạn define custom substitutions, bạn cần pass chúng qua gcloud builds submit --substitutions=KEY=VALUE.
Build Execution Guarantees & Failure Handling
Cloud Build có clear execution model:
- Sequential execution: Steps chạy theo thứ tự (step 1, sau đó step 2, ...)
- Fail-fast: Nếu step N fail (non-zero exit code), build stop tại đây. Step N+1 không execute
- No retry by default: Nếu step fail, build FAIL. Không auto-retry
- All-or-nothing per step: Step execute toàn bộ hoặc không — không có partial execution
Nếu bạn muốn conditional execution (ví dụ: run step A nếu step B fail), bạn phải dùng workaround — ví dụ: bash script check exit code và decide:
steps:
- name: 'gcr.io/cloud-builders/gke-deploy'
args: ['run', '--filename=k8s/', ...]
# nếu step này fail, step kế tiếp không execute
- name: 'gcr.io/cloud-builders/git'
args: ['log', '--oneline', '-1'] # This won't run if previous step failedĐể implement "run on failure" logic, bạn phải dùng shell script wrapper:
steps:
- name: 'gcr.io/cloud-builders/docker'
entrypoint: 'bash'
args:
- '-c'
- |
docker build . || echo "Build failed, but continuing..."Build Timeout & Resource Limits
Mỗi build có default timeout của 600 seconds (10 phút). Nếu build vẫn chạy sau 10 phút, Cloud Build sẽ kill nó và mark as FAILURE.
Bạn có thể override timeout:
timeout: '3600s' # 1 hourResource constraints:
- Default pool: Machine type được fixed, không thể customize
- Private pools: Bạn có thể chọn machine type (e2-standard, n2-standard, n2d-standard, ...)
- Memory: Tùy machine type (e2-standard-2 có 8 GB RAM, ...)
- Disk: Worker node có enough disk space cho workspace, nhưng không unbounded
Nếu build của bạn lại touch disk limit hoặc memory limit, nó sẽ được kill (thường với cryptic error message).
Build Logging & Observability
Cloud Build automatically logs tất cả output từ steps:
- stdout/stderr: Captured và written to Cloud Logging
- Build metadata: Build ID, trigger source, service account, start time, end time
- Step-level logs: Mỗi step có separate log stream
Bạn có thể query logs:
gcloud builds log BUILD_ID # View logs in terminalHoặc trong Cloud Console → Cloud Build → Build history → Click vào build ID → Logs tab.
Logging limitations:
- Logs retained for 30 days by default (configurable via Cloud Logging retention)
- Large logs (>100 MB) có thể bị truncated ở Cloud Console UI
- Nhưng full logs luôn available via API / Cloud Logging
Mental Model Summary
Cloud Build Execution:
submit build
↓
pick available worker from pool (or wait)
↓
provision fresh VM / container environment
↓
initialize workspace (empty or with source code)
↓
FOR EACH step:
├── Spin up container từ step image
├── Mount shared /workspace volume
├── Execute command/args
├── Capture logs
└── Check exit code (0 = success, non-zero = fail build)
↓
capture outputs (push to registry, write to GCS, ...)
↓
destroy worker / reset environment
↓
return build result (SUCCESS, FAILURE, TIMEOUT)Key constraints:
- Ephemeral: Mỗi build chạy clean, không share state với previous builds
- Isolated: Mỗi step là separate container, nhưng share workspace volume
- Sequential: Steps chạy một sau một
- Fail-fast: Build stop ở step đầu tiên fail
- Timeoutted: Max 600s by default
- Logged: Tất cả output captured to Cloud Logging
Constraints & Failure Modes
Resource Bottlenecks
Default pool saturation:
Nếu bạn có 20 concurrent build submissions nhưng default pool chỉ support 30 concurrent builds, builds mới sẽ queue và wait cho available worker. Queueing time có thể từ vài giây đến vài phút tùy queue depth.
Mitigation:
- Dùng private worker pools nếu cần higher concurrency
- Schedule builds strategically nếu possible (không chạy all tests every minute)
- Monitor build queue qua Cloud Build metrics → set up alerts nếu queue depth > threshold
Networking Limitations in Default Pool
You cannot:
- Access customer VPC resources (databases, caches, internal services)
- Use static IPs (Cloud Build assigns dynamic public IPs)
- Guarantee outbound IP address (NAT happens through Google's shared IPs)
Workaround:
- Move sensitive operations thành separate GCP services (Cloud Run, GKE) — Cloud Build triggers chúng từ default pool (public accessible), nhưng sensitive work happen trong VPC
- Dùng private worker pools nếu absolutely need VPC access
Build Failure Debugging
Khi build fail, investigation model:
- Check Cloud Build UI → Build logs tab
- Search for error messages ở tail của logs
- If error cryptic, reproduce locally:bash
# Clone same source git clone <repo> git checkout <commit> # Run same build steps locally docker build -t test . - If still unclear, enable Cloud Build debug (set
--verbosity=debugnếu dùng CLI)
Limitation: Bạn không thể SSH vào running worker — nó ephemeral, không có persistent identity. Nếu bạn perlu debug interactively, bạn phải:
- Modify build config để run một shell loop thay vì exit immediately
- Capture logs more verbosely (set
set -xở bash scripts)
Timeout-related Failures
Build timeout thường happen vì:
- Network timeout: Docker pull từ slow registry, hoặc download large dependencies
- Build step hanging: Step bị stuck waiting for I/O, lock, hoặc network response
- Insufficient resources: Machine out of disk space, runs out of memory
Mitigations:
- Increase timeout (nếu legitimate long-running step):yaml
timeout: '1800s' # 30 minutes - Use caching (xem Chương 5-6) để skip redundant work
- Parallelize build steps (nếu possible) bằng cách dùng multiple parallel jobs
Real-world Implication
Case: Slow Docker Builds
Scenario: Bạn có build step docker build . mà takes 5 phút. Tại sao?
Possible causes:
- No layer caching: Nếu bạn build ở default pool lần đầu, Docker layers không cached. Lần đầu build từ scratch takes much longer
- Large base image: Pulling
ubuntu:22.04từ Docker Hub takes time - Slow package managers:
apt-get installở default pool chạy slow vì network - Compilation steps: C++ / Go compilation step bị slow
Solutions:
- Use Dockerfile best practices: Put slow layers sau fast layers, chia RUN commands efficiently
- Dùng pre-built base images từ Artifact Registry (close to Cloud Build workers)
- Cache layers ở Artifact Registry:
docker build --cache-from gcr.io/$PROJECT_ID/app:latest