Skip to content

BackendConfig & FrontendConfig CRDs — Cấu Hình Nâng Cao cho GKE Ingress

Tại sao các CRD này tồn tại

GKE Ingress ban đầu chỉ hỗ trợ cấu hình qua annotations trên Ingress resource. Approach này có giới hạn cơ bản: một Ingress annotation áp dụng cho toàn bộ LB frontend, không thể cấu hình per-backend. Khi GKE cần expose các tính năng phức tạp như health check per-service, Cloud Armor per-backend, hay CDN settings — annotations không đủ expressive.

BackendConfig và FrontendConfig CRDs giải quyết vấn đề này bằng cách tách cấu hình ra khỏi Ingress resource và attach vào đúng đối tượng phù hợp: BackendConfig attach vào Service (vì backend service trong GCP LB tương ứng với Service trong Kubernetes), FrontendConfig attach vào Ingress (vì frontend config tương ứng với target proxy và forwarding rule).

BackendConfig — Binding mechanism

Cách BackendConfig bind vào Service

BackendConfig không tự biết Service nào nó thuộc về — Service phải khai báo tham chiếu đến BackendConfig qua annotation:

yaml
apiVersion: v1
kind: Service
metadata:
  name: api-service
  annotations:
    cloud.google.com/backend-config: '{"default": "api-backendconfig"}'
spec:
  selector:
    app: api
  ports:
    - name: http
      port: 8080
      targetPort: 8080

Annotation cloud.google.com/backend-config nhận một JSON object với hai dạng:

Dạng 1 — Default (áp dụng cho tất cả ports):

json
{"default": "my-backendconfig"}

Dạng 2 — Per-port (áp dụng cho port cụ thể):

json
{"ports": {"8080": "api-backendconfig", "9090": "admin-backendconfig"}}

Port key trong dạng per-port tham chiếu đến spec.ports[].port của Service (không phải targetPort hay nodePort).

Reconciliation của BackendConfig

Một trong những điểm quan trọng nhất: "Changes to a BackendConfig resource are constantly reconciled." Controller liên tục watch BackendConfig objects và ngay khi có thay đổi, nó sẽ update GCP Backend Service tương ứng — không cần delete/recreate Ingress.

Nhưng có một subtlety quan trọng: khi bạn xóa một field khỏi BackendConfig, controller không tự xóa cấu hình đó khỏi GCP Backend Service. Bạn phải explicitly set field đó về giá trị "empty" (empty string hoặc false) trước khi xóa field. Nếu xóa thẳng, cấu hình cũ vẫn còn trong GCP LB.

yaml
# Đúng: remove Cloud Armor bằng cách set empty string trước
spec:
  securityPolicy:
    name: ""  # Explicitly remove
---
# Sai: xóa section securityPolicy → Cloud Armor vẫn còn trong GCP LB

BackendConfig fields — Cơ chế bên trong

Health Check configuration

Mặc định, GKE Ingress tạo health check tự động dựa trên port và path của Service. BackendConfig cho phép override toàn bộ:

yaml
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: api-backendconfig
spec:
  healthCheck:
    checkIntervalSec: 15
    timeoutSec: 5
    healthyThreshold: 1
    unhealthyThreshold: 3
    type: HTTP
    requestPath: /healthz
    port: 8080

Cơ chế bên trong: GCP Backend Service yêu cầu một Health Check resource. Health check này là ngoài cluster, chạy từ GCP infrastructure. Nó probe vào Pod endpoint trực tiếp (nếu dùng NEG container-native) theo chu kỳ checkIntervalSec.

Một Pod bị mark unhealthy sau unhealthyThreshold consecutive failures. Sau khi Pod bị đánh dấu unhealthy, GCP LB ngay lập tức ngừng gửi traffic đến đó (không cần chờ Kubernetes readiness probe).

Constraint quan trọng: BackendConfig chỉ hỗ trợ HTTP, HTTPS, HTTP/2 protocols cho health check. Không hỗ trợ TCP hay gRPC health check.

Sự khác biệt giữa timeoutSeccheckIntervalSec: timeoutSec phải nhỏ hơn hoặc bằng checkIntervalSec. Nếu timeoutSec > checkIntervalSec, GCP API sẽ reject cấu hình.

Cloud Armor integration

Cloud Armor security policy được attach vào Backend Service, không phải Frontend:

yaml
spec:
  securityPolicy:
    name: "my-cloud-armor-policy"

Cơ chế: Controller gọi GCP API để set securityPolicy field trên Backend Service resource. Traffic từ GFE đến backend đi qua Cloud Armor policy được evaluate trước khi forward đến NEG endpoint.

Điểm quan trọng về isolation: vì một Service:port pair map đến một GCP Backend Service, tất cả Ingresses tham chiếu cùng Service:port sẽ chịu cùng Cloud Armor policy. Không thể có hai Ingresses tham chiếu cùng Service nhưng với Cloud Armor policies khác nhau — controller sẽ overwrite.

Constraint: Không thể enable cả Cloud Armor và IAP trong cùng một BackendConfig. Hai tính năng này xung đột về mặt authentication flow.

Session Affinity

yaml
spec:
  sessionAffinity:
    affinityType: "GENERATED_COOKIE"
    affinityCookieTtlSec: 3600

Hai loại session affinity:

  • CLIENT_IP: hash source IP của client → backend endpoint
  • GENERATED_COOKIE: GFE tạo cookie, client phải gửi cookie trong subsequent requests

Cơ chế: Session affinity được implement tại GFE layer, không phải tại Pod. GFE maintain affinity table ánh xạ client identity → backend endpoint. Khi endpoint trở thành unhealthy, affinity session tự động chuyển sang endpoint khác — không phải "sticky" tuyệt đối.

Requirement: Phải dùng VPC-native cluster (alias IP) để session affinity hoạt động. Instance group-based backends không hỗ trợ session affinity đầy đủ.

Cloud CDN

yaml
spec:
  cdn:
    enabled: true
    cachePolicy:
      includeHost: true
      includeProtocol: true
      includeQueryString: false
    cacheMode: CACHE_ALL_STATIC
    defaultTtl: 3600
    maxTtl: 86400
    clientTtl: 600
    negativeCaching: true

Cơ chế: Khi CDN được enable, GFE cache responses tại PoP layer. Subsequent requests cho cùng cache key được serve từ GFE memory mà không cần forward đến backend Pod. Cache key được tính dựa trên cachePolicy — thường là host + URL path + protocol, optionally bao gồm query string.

cacheMode: CACHE_ALL_STATIC tự động cache các content types static (JS, CSS, images) dựa trên Content-Type header. USE_ORIGIN_HEADERS tin tưởng hoàn toàn vào cache headers từ backend.

Constraint: CDN và IAP không thể dùng cùng nhau. Nếu backend yêu cầu authentication qua IAP, CDN không biết user identity nên không thể cache per-user.

Connection Draining

yaml
spec:
  connectionDraining:
    drainingTimeoutSec: 60

Cơ chế: Khi một backend endpoint bị remove khỏi NEG (do Pod bị terminate), GCP LB không ngay lập tức cắt connection đang in-flight. Trong drainingTimeoutSec giây, backend service tiếp tục hoàn thành các requests đã được forwarded, nhưng không nhận requests mới.

Giá trị 0 nghĩa là disable connection draining — connections bị cắt ngay lập tức khi endpoint bị remove.

Trade-off quan trọng: drainingTimeoutSec cao (vài trăm giây) trên instance group backends có thể block các Ingress operations khác. Theo tài liệu GKE: "A high value for drainingTimeoutSec on instance group backends can delay Ingress updates for other backends." Điều này không áp dụng cho NEG backends.

Backend Timeout

yaml
spec:
  timeoutSec: 30

Đây là timeout cho request processing tại backend, không phải connection timeout. Nếu Pod không trả response trong timeoutSec giây, GFE trả 504 Gateway Timeout cho client. Default là 30 giây.

Custom Headers

yaml
spec:
  customRequestHeaders:
    headers:
      - "X-User-Role: {client_region}"
      - "X-LB-IP: {load_balancer_ip}"
  customResponseHeaders:
    headers:
      - "Cache-Control: no-store"
      - "X-Content-Type-Options: nosniff"

Custom headers hỗ trợ một số dynamic variables được GFE populate:

  • {client_region}: region của client
  • {load_balancer_ip}: IP của load balancer
  • {cdn_cache_status}: cache hit/miss status

customResponseHeaders chỉ available cho external Ingress (GKE 1.25+), không hỗ trợ cho Internal ALB.

FrontendConfig — Binding mechanism

FrontendConfig bind vào Ingress (không phải Service), qua annotation trên Ingress resource:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    networking.gke.io/v1beta1.FrontendConfig: "my-frontendconfig"

FrontendConfig chỉ apply cho External Application LB. Internal ALB không hỗ trợ FrontendConfig.

FrontendConfig fields

SSL Policy

yaml
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: my-frontendconfig
spec:
  sslPolicy: "my-ssl-policy"

SSL Policy trong GCP kiểm soát:

  • Minimum TLS version: TLS_1_0, TLS_1_1, TLS_1_2, TLS_1_3
  • Cipher profiles: COMPATIBLE, MODERN, RESTRICTED, CUSTOM

Cơ chế: SSL Policy được attach vào Target HTTPS Proxy (không phải Backend Service). Khi client TLS handshake với GFE, GFE enforce cipher suites và TLS version theo policy. Nếu client propose một cipher không có trong policy, handshake fail.

Ví dụ: Policy RESTRICTED chỉ cho phép TLS 1.2+ và một subset nhỏ của strong cipher suites — phù hợp cho PCI-DSS compliance nhưng có thể break old clients.

Nếu không có FrontendConfig với SSL Policy, GKE dùng COMPATIBLE profile mặc định — cho phép TLS 1.0+ và nhiều cipher suites để maximize compatibility.

HTTPS Redirect

yaml
spec:
  redirectToHttps:
    enabled: true
    responseCodeName: "MOVED_PERMANENTLY_DEFAULT"  # 301

Cơ chế: Controller tạo thêm một forwarding rule trên port 80 với URL Map rule redirect tất cả traffic lên HTTPS. responseCodeName có thể là:

  • MOVED_PERMANENTLY_DEFAULT (301)
  • FOUND (302)
  • SEE_OTHER (303)
  • TEMPORARY_REDIRECT (307)
  • PERMANENT_REDIRECT (308)

Requirement: Ingress phải được cấu hình với cả HTTP lẫn HTTPS listeners (cả port 80 và 443 trong spec). Nếu chỉ có HTTPS, không cần redirect — chỉ expose port 443.

Constraint matrix — Giới hạn quan trọng

Tính năngExternal ALBInternal ALB
BackendConfig health check
Cloud Armor
CDNKhông
IAP
Session affinity
Custom request headers
Custom response headersCó (GKE 1.25+)Không
FrontendConfig SSL PolicyKhông
FrontendConfig HTTPS redirectKhông

Vòng đời xóa CRD — Cẩn thận với thứ tự

Thứ tự xóa BackendConfig sai gây ra orphaned GCP resources:

Sai (gây orphan):

bash
kubectl delete backendconfig api-backendconfig  # Xóa CRD trước
# GCP Backend Service giữ cấu hình cũ, không ai clean up

Đúng:

bash
# Bước 1: Remove reference từ Service annotation
kubectl annotate service api-service cloud.google.com/backend-config-

# Bước 2: Đợi controller reconcile (vài phút)

# Bước 3: Sau đó mới xóa CRD
kubectl delete backendconfig api-backendconfig

Khi Service annotation được remove, controller biết BackendConfig đã không còn được bind và sẽ remove cấu hình tương ứng khỏi GCP Backend Service. Chỉ sau đó việc xóa CRD object mới an toàn.

References