Skip to content

Pre-upgrade Validation: Kiểm Tra Tương Thích Trước Khi Nâng Cấp

Tại sao bước này quan trọng trong production

Phần lớn incident liên quan đến cluster upgrade không xảy ra vì bug trong GKE — chúng xảy ra vì một giả định sai về tính tương thích mà không ai kiểm tra trước. Một Kubernetes minor version mới không chỉ thêm feature; nó xóa bỏ các API version đã deprecated ở phiên bản trước đó. Nếu cluster của bạn có một Deployment controller nội bộ, một admission webhook, hoặc một Helm chart cũ gọi vào một API đã bị gỡ, thì ngay sau khi control plane hoàn tất nâng cấp, những lệnh gọi đó bắt đầu trả về lỗi 404 — không có cảnh báo, không có thời gian ân hạn.

Vấn đề nằm ở việc GKE không thể đảm bảo phát hiện 100% các trường hợp exposure này một cách tự động. Đây là điều mà tài liệu chính thức nói rất rõ:

"You must independently assess your cluster environment's exposure to any upcoming deprecations before you upgrade your cluster to the next minor version" (Feature and API deprecations).

Nói cách khác: cơ chế phát hiện tự động của GKE là một lưới an toàn có lỗ, không phải một cổng chặn hoàn chỉnh. Hiểu đúng cách lưới này hoạt động — và biết chính xác nó không nhìn thấy gì — là điều kiện tiên quyết để một pre-upgrade validation thực sự đáng tin cậy.

Internal model: GKE phát hiện deprecated API bằng cách nào, và tại sao cơ chế đó có lỗ hổng cấu trúc

API server không lưu "ai đang dùng API nào" — nó chỉ log lời gọi

Điểm mấu chốt cần nắm: Kubernetes API server không duy trì một bảng tra cứu tĩnh về việc "resource nào trong etcd được tạo bằng API version nào". Version của một object chỉ tồn tại tại thời điểm request — khi một client gọi apps/v1beta1 (ví dụ), API server convert nó (nếu còn hỗ trợ) hoặc từ chối (nếu đã gỡ). Do đó, cách duy nhất để biết "ai đang dùng API deprecated" là quan sát các request đang thực sự bay vào API server, không phải là scan cấu hình YAML đang lưu trong cluster.

Đây chính xác là cách GKE Deprecation Insight hoạt động:

"GKE generates deprecation insights when user agents call deprecated APIs, not from the configuration of your Kubernetes objects" (Viewing deprecation insights and recommendations).

Điều này giải thích một hành vi thường gây nhầm lẫn: một Deployment YAML cũ trong Git repo của bạn dùng apps/v1beta1 sẽ không bị GKE gắn cờ nếu không có ai (controller, CI/CD pipeline, kubectl apply, Helm) thực sự gửi request đó lên API server trong thời gian gần đây. Ngược lại, nếu bạn chỉ chạy kubectl apply một lần bằng API cũ rồi không bao giờ đụng vào nữa, GKE cũng sẽ không thấy exposure này nếu khoảng thời gian quan sát đã trôi qua.

Cửa sổ quan sát 30 ngày — điểm mù có chủ đích

GKE chỉ tạo insight khi phát hiện lời gọi trong một khung thời gian quan sát gần đây; nếu một tính năng deprecated không được gọi trong 30 ngày gần nhất, GKE coi như "không có exposure" — dù thực tế production vẫn có thể phụ thuộc vào nó theo một lịch trình ít gặp hơn (ví dụ: một CronJob chạy hàng quý, hoặc một migration script chỉ chạy khi có sự cố):

"if a deprecated feature has not been used in the last 30 days, GKE does not detect any usage, and an insight and recommendation is not generated" (Feature and API deprecations).

Đây không phải là một bug — đó là một trade-off thiết kế bắt buộc: lưu vết mọi lời gọi API vĩnh viễn để dò deprecated usage sẽ tạo ra chi phí lưu trữ và xử lý không tưởng ở quy mô hàng triệu cluster. GKE chọn một cửa sổ quan sát hữu hạn, đủ để bắt các pattern sử dụng thường xuyên, nhưng có chủ đích bỏ qua các pattern hiếm gặp. Hệ quả vận hành trực tiếp: bạn không thể dựa 100% vào Deprecation Insight để quyết định "an toàn để upgrade" — bạn phải tự bổ sung bằng việc chủ động rà soát source code / Helm chart / CRD của toàn bộ hệ thống trước khi upgrade một minor version.

Auto-upgrade pause: GKE tự bảo vệ chính nó, nhưng chỉ khi nó "nhìn thấy"

Khi GKE phát hiện được cluster đang dùng một feature sẽ bị gỡ ở minor version kế tiếp, hành vi mặc định là tạm dừng auto-upgrade tới minor đó:

"If GKE detects that a cluster is using a feature that is removed in an upcoming minor version of Kubernetes, automatic cluster upgrades to the next minor version are paused, and GKE shares a deprecation insight and recommendation" (Feature and API deprecations).

Cơ chế này rất quan trọng để hiểu đúng: nó là một safety net cho auto-upgrade, không phải cho manual upgrade. Nếu bạn (hoặc một script CI/CD) chủ động chạy gcloud container clusters upgrade, GKE không chặn bạn dù phát hiện exposure — nó chỉ dừng khi chính GKE là bên khởi tạo upgrade. Đây là lý do một quy trình vận hành kỷ luật không thể coi "auto-upgrade chưa bị pause" là tín hiệu an toàn khi làm manual upgrade — hai luồng quyết định này độc lập với nhau.

Version skew policy: ràng buộc toán học giữa control plane và node

Trước khi chạm vào bất kỳ lệnh upgrade nào, cần nắm chính xác ràng buộc version skew — đây là quy tắc cứng, không phải khuyến nghị:

  • Node không được chạy version mới hơn control plane. Điều này hợp lý về mặt thiết kế: kubelet luôn phải nói API dialect cũ hơn hoặc bằng, không bao giờ mới hơn, API server nó kết nối tới.
  • Node có thể lệch tối đa 2 minor version so với control plane. Ví dụ nếu control plane ở 1.31, node hợp lệ ở 1.31, 1.30, hoặc 1.29 — không hợp lệ ở 1.28 hoặc thấp hơn.
  • Control plane không được nhảy cóc minor version. Bạn không thể upgrade trực tiếp từ 1.31 lên 1.33; bạn phải đi qua 1.32 trước. Nhưng bạn có thể skip patch version (ví dụ 1.31.1-gke.100 lên 1.31.5-gke.200 trực tiếp).
  • Node pool, ngược lại, có thể skip minor version khi upgrade — vì nâng cấp node thực chất là thay thế toàn bộ node bằng image mới (không phải cập nhật tại chỗ như control plane), nên không cần đi tuần tự qua từng minor.

"GKE does not allow skipping minor versions for the cluster control plane, however you can skip patch versions. Worker nodes can skip minor versions" (tổng hợp từ tài liệu versioning của Google Cloud).

Điểm thực dụng cần rút ra: nếu cluster của bạn đã "quá date" nhiều minor version (ví dụ node đang ở 1.27 trong khi control plane cần lên 1.32), bạn không thể một lần nâng cả hai đồng bộ. Bạn cần một chuỗi tuần tự cho control plane (1.27→1.28→...→1.32), nhưng cho node pool bạn có thể tính toán một lộ trình gọn hơn, miễn là tại mọi thời điểm khoảng lệch giữa node và control plane không vượt quá 2 minor.

GKE tự phát hiện vi phạm version skew — nhưng đây là detection, không phải prevention

GKE có cơ chế giám sát chủ động việc lệch version vượt ngưỡng cho phép, thông qua Recommender:

"GKE identifies clusters in which the nodes are running a version that is incompatible with the control plane due to version skew... delivering this guidance with an insight and recommendation through the Recommender service."

Đây là tín hiệu sau khi vi phạm đã xảy ra, không phải một rào chặn trước khi bạn thực hiện một thao tác gây vi phạm (ví dụ downgrade nhầm node pool). Điều này có nghĩa đội vận hành cần tự áp đặt kỷ luật: mọi kế hoạch upgrade/downgrade phải tính toán trước khoảng lệch version, không chờ Recommender cảnh báo sau khi đã sai.

Admission webhook & CRD conversion webhook: lớp compatibility dễ bị bỏ quên nhất

Deprecated core API là loại rủi ro dễ thấy nhất, nhưng trong một cluster production phức tạp, rủi ro lớn hơn thường nằm ở admission webhookCRD conversion webhook của các add-on bên thứ ba (service mesh, policy engine, operator của database, v.v). Cơ chế cần hiểu: mỗi ValidatingWebhookConfiguration hoặc MutatingWebhookConfiguration đăng ký chặn một apiVersions cụ thể. Khi API server nâng cấp minor version và một API group đổi phiên bản mặc định (ví dụ chuyển hoàn toàn từ v1beta1 sang v1), nếu webhook cấu hình cứng theo v1beta1 mà version đó đã bị gỡ hoàn toàn, hai kết cục có thể xảy ra:

  1. Webhook không còn được gọi cho request nào — mất luôn lớp validation/mutation mà không có lỗi hiển thị rõ ràng (silent failure nguy hiểm nhất).
  2. Nếu webhook có failurePolicy: Fail và API server không tìm được version tương thích để gọi webhook, request tạo/sửa resource bị chặn hoàn toàn — gây outage ngay lập tức cho bất kỳ ai cố deploy sau upgrade.

Tương tự, CRD conversion webhook (dùng khi một CRD hỗ trợ nhiều version schema) phải tương thích với version API server đang phục vụ; một conversion webhook lỗi thời có thể khiến toàn bộ custom resource của một operator (ví dụ cert-manager, một database operator nội bộ) trở nên không thể đọc/ghi sau upgrade.

Bài học kiến thức ở đây: pre-upgrade validation không thể chỉ giới hạn ở core Kubernetes API. Nó phải bao gồm audit toàn bộ ValidatingWebhookConfiguration, MutatingWebhookConfiguration, và CustomResourceDefinition.spec.versions đang tồn tại trong cluster, đối chiếu với changelog API deprecation của minor version đích.

Constraints, trade-offs & failure modes

Constraint cứng: bạn không kiểm soát được add-on do GKE quản lý

Một số component (CNI, kube-proxy tương đương của Dataplane V2, metrics-server mặc định) được GKE quản lý và tự động cập nhật cùng lúc với version cluster — bạn không tách riêng được để test trước. Điều này có nghĩa pre-upgrade validation trên một cluster staging phải phản ánh đúng managed add-on version mà production sẽ nhận, không chỉ là "cùng minor version Kubernetes".

Trade-off: tốc độ kiểm tra so với độ chính xác của audit log

Cách chính xác nhất để tìm deprecated API usage là truy vấn Cloud Audit Logs cho các apiVersion cụ thể trong lịch sử dài (ví dụ 90 ngày thay vì 30 ngày mà GKE Insight dùng). Trade-off là chi phí BigQuery/Cloud Logging query tăng theo khối lượng log, và với cluster nhiều namespace, việc lọc chính xác client/user-agent nào đang gọi API cũ tốn effort điều tra đáng kể. Tuy nhiên, so với chi phí một outage sau upgrade, đây là khoản đầu tư luôn đáng giá cho cluster production tier 1.

Failure mode: upgrade một minor version rồi mới phát hiện breaking change ảnh hưởng ba tầng phụ thuộc

Một lỗi vận hành phổ biến: coi deprecated API check chỉ là vấn đề của ứng dụng của bạn. Trong thực tế, chuỗi phụ thuộc thường sâu hơn: CI/CD pipeline (dùng kubectl phiên bản cũ tạo request bằng API cũ), Helm chart bên thứ ba chưa update, và operator quản lý hạ tầng (ingress controller, cert-manager, external-dns) đều là các "user agent" độc lập có thể gọi API deprecated mà chính team ứng dụng không hề biết. Một pre-upgrade validation nghiêm túc phải liệt kê toàn bộ user agent đang giao tiếp với API server, không chỉ workload của một team.

Pattern minh họa: staged validation trên cluster canary tách biệt release channel

Một cách áp dụng thực tế của các cơ chế trên: duy trì một cluster non-production ở cùng release channel nhưng được set một maintenance exclusion NO_MINOR_UPGRADES lệch pha so với production, để nó luôn nhận minor version mới trước production ít nhất một chu kỳ. Cluster này đóng vai trò "cảm biến sớm" — mọi deprecated API usage hoặc webhook breakage sẽ lộ ra ở đây trước, cho đội vận hành thời gian phản ứng trước khi minor version đó chạm production. Bài học kiến thức: đây là ứng dụng trực tiếp của việc hiểu rằng Deprecation Insight dựa trên lời gọi thực tế — nếu cluster canary có traffic pattern tương tự production, nó sẽ "kích hoạt" insight sớm hơn so với việc chỉ đọc changelog tĩnh.

Anti-pattern: coi "0 insight nào được GKE báo" là bằng chứng an toàn

Sai lầm gốc rễ ở đây là hiểu lầm cơ chế: nhiều team coi Deprecation Insight trống là "đã kiểm tra và pass", trong khi thực chất nó chỉ có nghĩa "trong 30 ngày qua, GKE không thấy lời gọi nào tới API sẽ bị gỡ — nhưng GKE không khẳng định bạn không dùng nó theo cách khác". Hệ quả ở scale: các hệ thống ít traffic, batch job chạy theo lịch dài, hoặc feature ít dùng (nhưng critical khi cần, ví dụ disaster recovery script) là nhóm rủi ro cao nhất bị bỏ sót chính vì chúng "im lặng" trong cửa sổ quan sát. Cách phòng tránh đúng: luôn bổ sung một bước audit static (rà soát source code, Helm values, CRD versions) độc lập với Deprecation Insight, thay vì thay thế cho nó.

GCP-native implementation guidance

Kiểm tra version khả dụng của control plane trước khi lên kế hoạch:

bash
gcloud container get-server-config --location=LOCATION

Xem danh sách deprecation insight hiện có của một cluster (thông qua Recommender API — insight type dành riêng cho GKE deprecation):

bash
gcloud recommender insights list \
  --project=PROJECT_ID \
  --location=LOCATION \
  --insight-type=google.container.DeprecationInsight \
  --recommender=google.container.DiagnosisRecommender

Truy vấn Cloud Logging để tìm lời gọi API deprecated trực tiếp từ audit log (bổ sung cho cửa sổ 30 ngày của Insight bằng một khoảng thời gian dài hơn tùy nhu cầu):

resource.type="k8s_cluster"
protoPayload.methodName:"io.k8s.apps.v1beta1"

Kiểm tra danh sách webhook và CRD version đang tồn tại để đối chiếu thủ công với changelog deprecation của minor version đích:

bash
kubectl get validatingwebhookconfigurations -o yaml
kubectl get mutatingwebhookconfigurations -o yaml
kubectl get crd -o jsonpath='{range .items[*]}{.metadata.name}{" -> "}{.spec.versions[*].name}{"\n"}{end}'

Đối chiếu với trang deprecation chính thức theo từng minor version đích, ví dụ Kubernetes 1.32 deprecated APIs — mỗi minor version có một trang riêng, cần đọc đúng trang tương ứng với version bạn sắp nhảy tới, không phải version hiện tại.

References