Rollback Procedures: Quy Trình Khẩn Cấp Khi Upgrade Đi Sai Hướng
Tại sao "rollback" trong GKE không có nghĩa giống như bạn nghĩ
Từ "rollback" gợi ý một hành động tức thời, đối xứng với "upgrade" — giống như git revert. Trong GKE, điều này sai ở gần như mọi cấp độ. Control plane không có cơ chế rollback minor version theo nghĩa thông thường. Node pool "rollback" không phải là một API xoá-và-khôi-phục tức thời — nó là một rolling operation khác, đi qua chính cơ chế cordon/drain/surge đã học ở các file trước, chỉ là theo hướng ngược lại. Hiểu sai bản chất này trong lúc một sự cố thật đang diễn ra dẫn tới quyết định tồi tệ nhất có thể: chờ đợi một "nút rollback" không tồn tại, trong khi lẽ ra cần hành động khác.
Internal model: rollback control plane — giới hạn cấu trúc, không phải giới hạn tính năng
Bạn không thể hạ minor version của control plane, chỉ có thể hạ patch
Đây là ràng buộc cứng nhất trong toàn bộ chương: control plane chỉ hỗ trợ patch downgrade trong cùng một minor version:
gcloud container clusters upgrade CLUSTER_NAME --master \
--location=CONTROL_PLANE_LOCATION --cluster-version=VERSION"Only patch downgrades are permitted within the same minor version" (Manually upgrade a cluster's control plane or node pools).
Lý do cấu trúc đằng sau: mỗi minor version upgrade có thể kèm theo migration định dạng lưu trữ trong etcd, hoặc kích hoạt feature gate mới mà một khi dữ liệu đã được viết theo định dạng mới, control plane cũ (minor thấp hơn) không đảm bảo đọc lại đúng. Kubernetes upstream không cam kết tính tương thích ngược của etcd storage format qua nhiều minor version — đây không phải là một hạn chế riêng của GKE, mà là hệ quả tất yếu từ chính bản chất Kubernetes. Vì vậy, một khi bạn đã commit một minor version upgrade cho control plane, đường lùi thật sự không tồn tại — chỉ có đường tiến (upgrade tiếp) hoặc khôi phục từ backup (được nói ở phần dưới).
Sau khi patch downgrade, phải tự chặn auto-upgrade tái diễn ngay
Một chi tiết vận hành dễ bị quên: patch downgrade không tự động "khoá" cluster ở version thấp hơn — nếu cluster đang enroll một release channel và có auto-upgrade target ở patch cao hơn, GKE có thể tự nâng cấp lại đúng version bạn vừa cố tình hạ xuống. Quy trình đúng là đặt maintenance exclusion trước khi thực hiện downgrade:
"Set maintenance exclusions first to prevent automatic re-upgrade" (Manually upgrade a cluster's control plane or node pools).
Two-step upgrade: cửa sổ rollback thật duy nhất, nhưng có hạn dùng
Đã nói ở file 04: cơ chế soak duration của two-step minor upgrade cho phép rollback binary trong khoảng soak (6 giờ đến 7 ngày) trước khi commit. Đây là cơ chế rollback minor version hợp lệ duy nhất — nhưng nó chỉ tồn tại nếu bạn chủ động chọn quy trình two-step từ đầu. Nếu bạn upgrade theo cách thông thường (một bước, commit ngay), bạn đã tự đóng cửa sổ rollback này từ trước khi cần tới nó. Bài học kiến thức quan trọng: quyết định "có cần khả năng rollback không" phải được đưa ra trước khi bắt đầu upgrade minor version, không phải sau khi phát hiện vấn đề — đây là một quyết định một-lần, không thể bổ sung giữa đường.
Khi minor version đã commit và có sự cố nghiêm trọng: backup, không phải rollback
Nếu bạn ở ngoài cửa sổ soak (đã commit, hoặc đã upgrade one-step) và phát hiện sự cố nghiêm trọng ở tầng control plane sau upgrade, công cụ đúng không phải "rollback" — mà là khôi phục cluster từ một bản backup được chụp trước khi upgrade, sử dụng Backup for GKE hoặc tái tạo cluster mới từ Infrastructure as Code và migrate workload sang. Đây là lý do một pre-upgrade checklist nghiêm túc (file 01) luôn nên bao gồm việc xác nhận có bản backup gần nhất của cluster state, không chỉ kiểm tra compatibility API — vì backup chính là "rollback plan B" thực sự cho control plane, không phải một API rollback nào đó không tồn tại ở tầng minor version.
Internal model: rollback node pool — một rolling operation ngược, không phải undo tức thời
gcloud container node-pools rollback chỉ áp dụng cho upgrade chưa hoàn tất
Lệnh rollback chính thức cho node pool:
gcloud container node-pools rollback NODE_POOL_NAME \
--cluster CLUSTER_NAME --location=CONTROL_PLANE_LOCATIONĐiều kiện áp dụng quan trọng cần nắm: lệnh này chỉ có ý nghĩa với upgrade chưa hoàn tất (đã dừng lại giữa đường, ví dụ do bạn chủ động cancel operation, hoặc do lỗi khiến một phần node pool đã ở version mới còn một phần vẫn ở version cũ). Cơ chế nội tại: rollback không "restore snapshot" — nó khởi tạo một rolling operation khác theo hướng ngược lại, đi qua đúng logic cordon/drain/surge (hoặc blue-green batch) đã học ở file 02 và 05, chỉ là version đích bây giờ là version cũ. Điều này có nghĩa rollback node pool tốn thời gian tương đương một upgrade thông thường — nó không phải một hành động tức thời, và bản thân quá trình rollback cũng chịu đúng những ràng buộc PDB, quota, health check gate đã phân tích ở các file trước.
Nếu node pool đã hoàn tất 100% upgrade, "rollback" thực chất là một downgrade upgrade mới
Với node pool đã hoàn tất hoàn toàn (mọi node đã ở version mới, operation đã DONE), không còn "upgrade chưa hoàn tất" để rollback theo nghĩa hẹp — hành động đúng là khởi tạo một upgrade mới với version đích là version cũ (miễn là version đó vẫn nằm trong ràng buộc version skew hợp lệ so với control plane hiện tại). Về bản chất kỹ thuật, đây không khác gì một upgrade thông thường — chỉ là hướng version đi xuống. Nó chịu đúng các constraint đã học: nếu control plane đã lên minor version mới và node pool cần hạ về một minor cũ hơn quá 2 bậc so với control plane hiện tại, downgrade này không hợp lệ — version skew policy áp dụng đối xứng cho cả hai hướng.
Blue-green cho khả năng rollback tốt hơn surge — nhưng chỉ trong đúng cửa sổ soak
Đây là lý do cốt lõi vì sao blue-green tồn tại như một chiến lược riêng biệt: trong Phase 4 (soak, file 05), blue pool vẫn còn tồn tại vật lý (đã cordon, đã drain, nhưng chưa xoá). Nếu vấn đề được phát hiện trong khoảng soak này, quy trình rollback có thể tái sử dụng chính blue pool đó — nhanh hơn đáng kể so với việc phải provision lại từ đầu như khi dùng surge upgrade (nơi node cũ đã bị xoá ngay sau khi node mới thay thế nó thành công). Đây chính là "bài học kiến thức" quan trọng nhất của file 05 áp dụng ngược lại vào rollback: soak duration bạn chọn ở file 05 chính là cửa sổ rollback thật của bạn — chọn soak quá ngắn đồng nghĩa tự giới hạn thời gian bạn có để phát hiện và phản ứng.
Autoscaled blue-green: đã đánh đổi rollback để lấy chi phí thấp — không có đường lùi
Nhắc lại ràng buộc đã nêu ở file 05: autoscaled blue-green không hỗ trợ rollback — chỉ hỗ trợ cancel (dừng ở trạng thái hiện tại) hoặc resume (tiếp tục). Đây không phải là một thiếu sót, mà là một trade-off có chủ đích của chính biến thể này: để đạt chi phí thấp (green pool khởi tạo 0 node, blue pool bị autoscaler âm thầm scale down), GKE phải hy sinh khả năng "giữ lại trạng thái cũ đầy đủ để quay về". Nếu khả năng rollback là ưu tiên cao hơn chi phí cho một lần upgrade cụ thể (ví dụ minor version lần đầu chưa được kiểm định), autoscaled blue-green là lựa chọn sai ngay từ bước chọn chiến lược, không phải một vấn đề có thể sửa bằng cấu hình tham số.
Constraints, trade-offs & failure modes
Failure mode: chờ "rollback" trong lúc control plane đang gặp sự cố sau minor upgrade
Đây là sai lầm quyết định nghiêm trọng nhất có thể xảy ra trong một sự cố thật: nếu control plane đã commit minor version upgrade và bộc lộ vấn đề (ví dụ một controller nội bộ không tương thích với hành vi API mới), thời gian bạn dành để tìm cách "rollback control plane" là thời gian lãng phí — con đường đó không tồn tại. Quyết định đúng cần được đưa ra nhanh: sửa nguyên nhân gốc ở tầng ứng dụng/controller để tương thích với version mới (tiến lên), hoặc kích hoạt kế hoạch khôi phục từ backup đã chuẩn bị trước (phương án đã lên kế hoạch từ trước, không phải phát minh giữa sự cố).
Trade-off: tốc độ rollback node pool so với việc lặp lại toàn bộ ràng buộc PDB/quota
Vì rollback node pool đi qua đúng cơ chế rolling như upgrade, nó không miễn trừ khỏi các vấn đề PDB chặn drain (file 03) hay quota giới hạn surge (file 02) đã phân tích. Trong tình huống khẩn cấp, một PDB quá chặt có thể khiến chính quy trình rollback bị chậm đúng như khi upgrade — đây là lý do quyết định rollback cần được đưa ra càng sớm càng tốt (khi cluster còn nhiều headroom), không nên để tới lúc hệ thống đã suy yếu nặng mới bắt đầu, vì bản thân rollback cũng cần thời gian và capacity để thực thi an toàn.
Constraint: rollback không xoá dấu vết đã ghi vào etcd bởi version mới
Nếu trong khoảng thời gian chạy ở version mới, một số object đã được ghi vào etcd theo API version chỉ tồn tại ở version đó (ví dụ một CRD conversion tự động, hoặc một field mới được API server tự điền), việc hạ control plane về patch cũ hơn (trong cùng minor) không đảm bảo các object này được đọc lại đúng như trước. Rollback (ở mức được phép — patch trong cùng minor) giải quyết vấn đề binary control plane, không giải quyết vấn đề dữ liệu đã bị biến đổi bởi version mới — hai lớp rủi ro độc lập cần được đánh giá riêng.
Pattern minh họa: quyết định rollback dựa trên vị trí bạn đang đứng trong quy trình, không dựa trên "mức độ hoảng loạn"
Bài học kiến thức tổng hợp toàn chương: quyết định đúng đắn nhất khi có sự cố không phải là một phản xạ ("rollback ngay!") mà là một câu hỏi có cấu trúc — bạn đang ở giai đoạn nào? Nếu còn trong soak của two-step control plane upgrade → rollback binary hợp lệ, làm ngay. Nếu control plane đã commit minor version → không có rollback, chỉ có tiến lên hoặc khôi phục từ backup. Nếu node pool upgrade chưa hoàn tất → node-pools rollback hợp lệ, nhưng cần thời gian tương đương một rolling operation. Nếu đang trong soak của blue-green → tái sử dụng blue pool, nhanh hơn các trường hợp khác. Nếu đang chạy autoscaled blue-green → chỉ có cancel/resume, không có rollback thật. Mỗi nhánh quyết định này bắt nguồn trực tiếp từ cơ chế đã học ở các file trước — không có nhánh nào là một "mẹo" độc lập, tất cả đều là hệ quả tự nhiên của cách GKE thiết kế từng chiến lược.
GCP-native implementation guidance
Hủy một operation upgrade đang chạy (bước đầu tiên trước khi quyết định rollback hay tiếp tục):
gcloud container operations cancel OPERATION_ID \
--location=CONTROL_PLANE_LOCATIONRollback node pool đang ở trạng thái upgrade chưa hoàn tất:
gcloud container node-pools rollback NODE_POOL_NAME \
--cluster CLUSTER_NAME --location=CONTROL_PLANE_LOCATIONĐặt maintenance exclusion trước khi patch downgrade control plane để tránh auto-upgrade tái diễn:
gcloud container clusters update CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--add-maintenance-exclusion-name=post-incident-freeze \
--add-maintenance-exclusion-start=START_TIME \
--add-maintenance-exclusion-end=END_TIME \
--add-maintenance-exclusion-scope=no_minor_or_node_upgradesXác nhận bản backup gần nhất tồn tại trước khi coi backup là phương án B khả dụng:
gcloud container backup-restore backups list \
--backup-plan=BACKUP_PLAN_NAME --location=LOCATION