Skip to content

Skaffold Integration — Render & Deploy Pipeline

Tại sao Skaffold tồn tại trong Cloud Deploy

Câu hỏi đầu tiên nhiều engineer đặt ra: tại sao Cloud Deploy không trực tiếp dùng kubectl apply? Tại sao cần thêm một layer Skaffold?

Câu trả lời nằm ở vấn đề rendering: Kubernetes manifests hiếm khi là plain YAML tĩnh trong production. Chúng cần được render từ:

  • Helm charts với values khác nhau per environment
  • Kustomize overlays với patches per environment
  • Plain YAML với image substitution (placeholder → actual image digest)

Nếu Cloud Deploy tích hợp trực tiếp với từng rendering tool, nó phải hiểu semantics của Helm, Kustomize, và mọi tool khác. Thay vào đó, Cloud Deploy delegates rendering cho Skaffold — một tool abstraction layer đã hỗ trợ tất cả rendering tools phổ biến.

Điều này tạo ra sự tách biệt rõ ràng:

  • Cloud Deploy quản lý promotion workflow (ai deploy gì, khi nào, đến đâu)
  • Skaffold quản lý how to render và apply manifests

Theo tài liệu Cloud Deploy: "Cloud Deploy separates rendering tools from the delivery pipeline." Đây là kiến trúc cố ý — pipeline definition không phụ thuộc vào rendering tool, cho phép thay đổi rendering tool mà không cần thay đổi pipeline.


Skaffold trong Cloud Deploy — Không Phải "Toàn Bộ" Skaffold

Điều cần hiểu rõ: Cloud Deploy chỉ dùng một subset các tính năng Skaffold:

  • skaffold diagnose — validate config
  • skaffold render — render manifests
  • skaffold apply — apply manifests lên cluster

Cloud Deploy không dùng các tính năng Skaffold khác như local development workflow, file sync, hot reload, hay build. Container images đã được build bởi CI pipeline (Cloud Build hoặc system khác) trước khi đến Cloud Deploy.

Skaffold được pre-installed trong Cloud Build worker environment của Cloud Deploy — không cần cài thêm. Version Skaffold được chọn tự động dựa trên apiVersion trong skaffold.yaml.


Cấu Trúc skaffold.yaml cho Cloud Deploy

Minimal skaffold.yaml (plain YAML)

yaml
apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: my-app
manifests:
  rawYaml:
  - k8s/*.yaml

Trường manifests.rawYaml chỉ định glob pattern cho Kubernetes manifest files. Khi render, Skaffold sẽ:

  1. Load tất cả files matching pattern
  2. Thực hiện image substitution: thay image: my-app-image (placeholder) bằng actual image digest được truyền vào qua --images flag
  3. Output rendered YAML

skaffold.yaml với Helm

yaml
apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: my-app
manifests:
  helm:
    releases:
    - name: my-app
      chartPath: charts/my-app
      valuesFiles:
      - charts/my-app/values.yaml
      setValueTemplates:
        image.repository: "{{.IMAGE_REPO_my_app}}"
        image.tag: "{{.IMAGE_TAG_my_app}}@{{.IMAGE_DIGEST_my_app}}"

Với Helm, Skaffold gọi helm template để render chart thành Kubernetes YAML. Image substitution thông qua setValueTemplates — Skaffold inject image info vào Helm values.

skaffold.yaml với Kustomize

yaml
apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: my-app
manifests:
  kustomize:
    paths:
    - k8s/base

Với Kustomize, Skaffold gọi kustomize build và thực hiện image substitution sau khi render.

Profiles cho Multi-Environment

Profiles là tính năng quan trọng nhất cho Cloud Deploy integration:

yaml
apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: my-app
manifests:
  rawYaml:
  - k8s/base/*.yaml
profiles:
- name: staging
  manifests:
    kustomize:
      paths:
      - k8s/overlays/staging
- name: production
  manifests:
    kustomize:
      paths:
      - k8s/overlays/production

Pipeline definition reference profiles:

yaml
serialPipeline:
  stages:
  - targetId: dev-gke        # Không có profile → dùng base config
  - targetId: staging-gke
    profiles: [staging]       # Dùng Kustomize overlay staging
  - targetId: prod-gke
    profiles: [production]    # Dùng Kustomize overlay production

Khi render Release, Cloud Deploy gọi skaffold render một lần per stage với profile tương ứng. Mỗi stage nhận rendered manifests riêng biệt, stored trong GCS.


Render Phase — Chi Tiết Bên Trong

Khi gcloud deploy releases create được gọi:

Bước 1: skaffold diagnose

bash
skaffold diagnose -f skaffold.yaml

Validate Skaffold config: file syntax, referenced files tồn tại, chart dependencies đã download. Nếu fail → Release creation fail ngay, không proceed sang render.

Bước 2: skaffold render (per stage)

bash
skaffold render -f skaffold.yaml \
  --images=my-app=us-central1-docker.pkg.dev/project/repo/my-app@sha256:abc... \
  --profile=staging \
  --output=rendered-manifest.yaml

Skaffold:

  1. Load manifests theo profile
  2. Thực hiện image substitution: scan tất cả container image: fields, thay placeholder bằng actual image từ --images flag
  3. Nếu dùng Helm: gọi helm template, inject images vào values
  4. Nếu dùng Kustomize: gọi kustomize build, sau đó image substitution
  5. Output ra rendered-manifest.yaml

Output của render phase là pure Kubernetes YAML — không còn Helm templates, không còn Kustomize overlays. Đây là gì sẽ được apply lên cluster sau này.

Cloud Deploy lưu output này vào GCS. Từ thời điểm này, Release đã "frozen" — manifests không thay đổi dù Skaffold config hay Helm chart thay đổi.

Image Substitution Mechanics

Đây là điểm thường gây nhầm lẫn. Skaffold dùng placeholder matching để biết field nào cần substitute:

yaml
# Trong manifest (trước render):
containers:
- name: my-app
  image: my-app-image   # Đây là placeholder name

# Command:
skaffold render --images=my-app-image=repo/my-app@sha256:abc...

# Sau render:
containers:
- name: my-app
  image: repo/my-app@sha256:abc...   # Replaced

Placeholder phải match image name được pass qua --images flag. Nếu không match → không substitute, manifest chứa placeholder string → deploy fail hoặc pull image sai.


Deploy Phase — skaffold apply

Khi Rollout vào trạng thái IN_PROGRESS:

bash
skaffold apply rendered-manifest.yaml \
  --kube-context=gke_project_us-central1_my-cluster

skaffold apply về bản chất là server-side apply với một số logic thêm:

  1. Load rendered manifests từ GCS
  2. Gọi kubectl apply --server-side lên target cluster
  3. Wait cho Kubernetes resources converge (Deployments rollout hoàn thành)
  4. Check status của resources

Tại sao server-side apply? Server-side apply (SSA) cho phép multiple controllers quản lý cùng một resource mà không conflict (field ownership). Cloud Deploy sử dụng SSA để không "steal ownership" của fields từ các controllers khác (như HPA managing replicas, hay Cert-Manager managing TLS certs).

Connection đến Target Cluster

Cloud Deploy không access cluster trực tiếp từ control plane của mình. Thay vào đó, Cloud Build worker (khi chạy skaffold apply) cần network connectivity đến cluster API server:

  • Public cluster: Cloud Build worker dùng public endpoint → no special config needed
  • Private cluster: Cần Private Worker Pool trong cùng VPC với cluster, hoặc PSC endpoint, hoặc VPN/Interconnect

Đây là failure mode phổ biến: deploy fail với "connection refused" hoặc "timeout" khi Cloud Build không thể reach private cluster API server.


Skaffold Modules — Tổ Chức Code Phức Tạp

Với applications có nhiều components (microservices), Skaffold hỗ trợ modules:

yaml
# skaffold.yaml
apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: platform
requires:
- configs:
  - path: ./services/api/skaffold.yaml
  - path: ./services/worker/skaffold.yaml
  - path: ./infrastructure/skaffold.yaml

Mỗi service/component có skaffold.yaml riêng. File cha aggregate chúng. Khi Cloud Deploy render, nó render tất cả modules và merge outputs.

Modules cho phép:

  • Teams độc lập maintain Skaffold config của service mình
  • Selective rendering (chỉ render module cần thiết)
  • Shared base configuration qua inheritance

Execution Environment — Nơi Skaffold Chạy

Cả render và deploy đều chạy trong Cloud Build execution environment. Có thể customize environment này:

yaml
# Trong delivery pipeline stage:
stages:
- targetId: prod-gke
  executionConfigs:
  - usages: [RENDER, DEPLOY]
    privatePool:
      workerPool: projects/my-project/locations/us-central1/workerPools/private-pool
      artifactStorage: gs://my-bucket/artifacts
    serviceAccount: deploy-sa@my-project.iam.gserviceaccount.com

Private Worker Pool là bắt buộc khi:

  • Target cluster có private endpoint (không có public IP)
  • Muốn isolate build workers trong VPC riêng
  • Cần egress qua Cloud NAT hoặc specific routing

serviceAccount trong executionConfigs xác định identity mà Cloud Build jobs chạy với — đây là SA cần có permissions để access cluster, pull images, read GCS.


Giới Hạn và Trade-offs

Giới hạn Skaffold version

Cloud Deploy pin Skaffold version dựa trên apiVersion trong skaffold.yaml. Khi Skaffold release breaking changes, cần update apiVersion để dùng features mới. Không phải tất cả Skaffold features đều được hỗ trợ trong Cloud Deploy context.

Render time và Release creation latency

Render phase chạy Cloud Build job. Với pipeline có nhiều stages, mỗi stage cần riêng Cloud Build job → render time có thể là 2-5 phút per stage. Với pipeline 3 stages, Release creation có thể mất 5-15 phút trước khi Rollout đầu tiên bắt đầu.

Cách giảm latency: parallel rendering (Cloud Deploy tự động render stages song song nếu có thể), optimize Skaffold config để không download dependencies không cần thiết.

Không hỗ trợ runtime generation

Skaffold render là static rendering — không thể generate manifest dynamically dựa trên runtime state (ví dụ: query database để lấy config, call API). Nếu cần dynamic config, phải pre-generate manifests trong CI và pass vào Cloud Deploy.


Official References