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:
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: 8080Annotation 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):
{"default": "my-backendconfig"}Dạng 2 — Per-port (áp dụng cho port cụ thể):
{"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.
# Đú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 LBBackendConfig 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ộ:
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: 8080Cơ 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 timeoutSec và checkIntervalSec: 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:
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
spec:
sessionAffinity:
affinityType: "GENERATED_COOKIE"
affinityCookieTtlSec: 3600Hai loại session affinity:
CLIENT_IP: hash source IP của client → backend endpointGENERATED_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
spec:
cdn:
enabled: true
cachePolicy:
includeHost: true
includeProtocol: true
includeQueryString: false
cacheMode: CACHE_ALL_STATIC
defaultTtl: 3600
maxTtl: 86400
clientTtl: 600
negativeCaching: trueCơ 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
spec:
connectionDraining:
drainingTimeoutSec: 60Cơ 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
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
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:
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
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
spec:
redirectToHttps:
enabled: true
responseCodeName: "MOVED_PERMANENTLY_DEFAULT" # 301Cơ 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ăng | External ALB | Internal ALB |
|---|---|---|
| BackendConfig health check | Có | Có |
| Cloud Armor | Có | Có |
| CDN | Có | Không |
| IAP | Có | Có |
| Session affinity | Có | Có |
| Custom request headers | Có | Có |
| Custom response headers | Có (GKE 1.25+) | Không |
| FrontendConfig SSL Policy | Có | Không |
| FrontendConfig HTTPS redirect | Có | Khô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):
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:
# 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-backendconfigKhi 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.