Skip to content

VPC-Native Architecture — Alias IP, Pod CIDR Sizing & Migration

Vì sao chủ đề này quyết định tương lai của cluster

Quyết định về IP plan là một trong số ít quyết định mạng GKE gần như không thể sửa sau khi cluster vào production mà không đau đớn. Khi bạn chọn sai kích thước secondary range cho Pod, hậu quả không xuất hiện ngay; nó nằm im cho tới ngày cluster cần scale mạnh — đúng lúc traffic tăng hoặc đúng giữa một đợt upgrade surge — rồi node mới không nhận được Pod CIDR, autoscaler bất lực, và pod treo ở trạng thái Pending dù quota CPU/RAM còn dư thừa.

GKE mặc định tạo cluster ở chế độ VPC-native, trong đó Pod IP là alias IP được định tuyến tự nhiên (natively routable) trong VPC network và các VPC peer (VPC-native clusters). Đây không phải lựa chọn ngẫu nhiên: VPC-native loại bỏ phụ thuộc vào route quota, cho phép Pod IP được firewall và Cloud Router nhìn thấy như địa chỉ thật, và là điều kiện tiên quyết cho hàng loạt tính năng (container-native load balancing, Private Service Connect cho control plane, một số mô hình hybrid). Hiểu sâu mô hình này là điều kiện để không tự khóa mình vào ngõ cụt kiến trúc.

Internal model: VPC-native vs routes-based

Routes-based cluster: mô hình cũ và vì sao bị bỏ

Trong routes-based cluster (mô hình legacy), mỗi node được gán một Pod CIDR, và GKE tạo một custom static route trong VPC trỏ dải Pod CIDR đó về node tương ứng. Khi Pod ở node A muốn nói chuyện với Pod ở node B, VPC tra bảng route, thấy dải đích thuộc route trỏ về node B, rồi chuyển gói.

Cách này hoạt động, nhưng có những giới hạn cấu trúc:

  • Tiêu thụ route quota: mỗi node là một route. VPC có quota route giới hạn, nên cluster lớn ăn vào quota dùng chung với phần còn lại của tổ chức (Using routes-based clusters).
  • Pod IP không “thật” với VPC: vì định tuyến dựa trên route tĩnh chứ không phải địa chỉ được cấp phát chính danh, một số tính năng (đặc biệt là định tuyến trực tiếp tới Pod IP từ load balancer) không khả dụng.
  • Khó tích hợp hybrid: route tĩnh cho Pod CIDR dễ xung đột với các route khác trong VPC và phức tạp khi peering hoặc kết nối on-prem.

Google đã xác định VPC-native là default cho mọi cluster mới và khuyến nghị dùng nó cho production (VPC-native is the default). Routes-based về cơ bản chỉ còn xuất hiện ở cluster cũ chưa migrate.

VPC-native: alias IP là trái tim của mô hình

Trong VPC-native cluster, Pod IP không đến từ route tĩnh mà từ alias IP ranges gán trực tiếp lên giao diện mạng (NIC) của node VM. Cơ chế alias IP là tính năng của Compute Engine: một VM có IP chính (primary internal IP) và có thể có thêm nhiều dải alias IP, tất cả đều được Andromeda (SDN của GCP) biết và định tuyến (Alias IP ranges).

Cụ thể trong GKE:

  1. Subnet của cluster có một primary range (cấp IP cho node) và ít nhất hai secondary ranges: một cho Pod, một cho Service.
  2. Khi một node được tạo, GKE “khắc” (carve) một dải con — mặc định /24 — từ secondary range của Pod và gán dải này làm alias IP range trên NIC của node.
  3. Pod chạy trên node đó lấy IP từ chính dải /24 này. Vì đó là alias IP hợp lệ của VM, Andromeda biết cách định tuyến gói đến đúng node mà không cần bất kỳ route tĩnh nào.

Hệ quả quan trọng: Pod IP là công dân hạng nhất trong VPC. Firewall rule có thể nhắm vào Pod CIDR, Cloud Router có thể quảng bá nó qua BGP, và load balancer có thể trỏ thẳng tới Pod IP (container-native LB). Đây là nền tảng cho phần lớn nội dung của các file sau trong chương.

Tại sao /24 mỗi node và quan hệ với max-pods-per-node

Mặc định GKE cấp /24 (256 địa chỉ) cho mỗi node nhưng chỉ lên lịch tối đa khoảng 110 Pod trên node đó (Optimizing IP address allocation). Vì sao 256 địa chỉ nhưng chỉ 110 Pod?

Kubernetes (và GKE) cố tình giữ headroom để tránh tái sử dụng IP quá nhanh. Khi một Pod bị xóa, IP của nó không được cấp lại ngay cho Pod mới; có một khoảng đệm để tránh tình trạng gói tin còn “bay trên đường” đến IP cũ lại bị giao nhầm cho Pod mới. Với /24 và 110 Pod, tỷ lệ sử dụng tối đa khoảng 43%, đủ headroom cho churn cao.

GKE cho phép điều chỉnh max-pods-per-node, và kích thước dải cấp cho mỗi node co giãn theo giá trị này:

max-pods-per-nodeDải cấp mỗi nodeSố địa chỉ
8/2816
16/2732
32/2664
64/25128
110 (mặc định)/24256

Đây là một trong những đòn bẩy quan trọng nhất để tiết kiệm IP. Nếu workload của bạn là nhiều node nhưng mỗi node ít Pod, đặt max-pods-per-node thấp (ví dụ 32) giúp mỗi node chỉ ăn /26 thay vì /24, kéo dài tuổi thọ secondary range lên gấp bốn lần.

Theo tài liệu Google Cloud, max-pods-per-node được khóa ở cấp node pool và không sửa được sau khi node pool đã tạo — bạn phải tạo node pool mới với giá trị mong muốn (Configure max Pods per node).

Capacity planning cho Pod IP: tư duy thực chiến

Bài toán sizing đúng cách

Sai lầm kinh điển là tính secondary range theo “số node hiện tại”. Công thức đúng phải bao gồm cả các đỉnh tải tạm thời:

Node tối đa cần ≈ (node baseline)
               + (headroom autoscaling)
               + (node tạm thời cho surge/blue-green upgrade)
               + (dự phòng tăng trưởng 12–24 tháng)

Sau đó:

Số node mà secondary range chịu được = (số địa chỉ trong secondary range Pod)
                                       / (số địa chỉ cấp mỗi node)

Ví dụ: secondary range /14 cho Pod có 2^(32-14) = 262.144 địa chỉ. Với /24 mỗi node, range này chịu được khoảng 1.024 node. Nhưng nếu bạn dùng blue-green upgrade (nhân đôi tạm thời node pool), số node thực tế đỉnh có thể gấp đôi — và nếu không tính phần đó, upgrade sẽ kẹt giữa chừng vì hết Pod CIDR.

Sizing secondary range cho Service

Secondary range cho Service quyết định số ClusterIP tối đa. Trên các phiên bản cluster mới, GKE quản lý dải Service mặc định (ví dụ 34.118.224.0/20) thay vì lấy từ subnet do người dùng cấp (VPC-native clusters). Dù vậy, khi tự cấp dải Service, cần nhớ: mỗi Service kiểu ClusterIP ăn một IP, nên một dải /20 (4.096 địa chỉ) đủ cho phần lớn cluster, nhưng cluster multi-tenant với hàng nghìn Service cần tính kỹ.

Failure mode: IP exhaustion ngầm

Đây là failure mode nguy hiểm vì nó im lặng cho tới lúc tệ nhất:

Triệu chứng:

  • Cluster Autoscaler muốn thêm node nhưng node mới kẹt ở NotReady hoặc không được tạo.
  • Pod Pending với event liên quan đến IP/networking thay vì thiếu CPU/RAM.
  • Sự cố bùng lên đúng lúc scale event lớn hoặc rollout.

Chẩn đoán nhanh:

  • Kiểm tra tỷ lệ sử dụng secondary range của Pod (qua Cloud Console hoặc gcloud compute networks subnets describe).
  • Đối chiếu số node hiện tại + node mà autoscaler/upgrade cần với capacity của range.

Khắc phục:

  • Thêm Pod IP range mới bằng cơ chế discontiguous multi-Pod CIDR (xem dưới).
  • Tạo node pool mới với max-pods-per-node thấp hơn để tiết kiệm IP.

Discontiguous (flexible) Pod CIDR: cứu cánh khi đã production

Khi secondary range ban đầu sắp cạn mà bạn không muốn tạo lại cluster, GKE cho phép thêm các dải Pod IP mới, không cần liền kề với dải cũ (discontiguous) (Add Pod IPv4 address ranges). Cơ chế:

  1. Thêm một secondary range mới vào subnet (hoặc dùng range chưa dùng).
  2. Tạo node pool mới chỉ định dùng range mới đó cho Pod.
  3. Node pool cũ vẫn dùng range cũ; cluster vận hành với nhiều Pod range song song.

Đây là công cụ quan trọng nhất để “gia hạn tuổi thọ” một cluster đã chạy lâu. Tuy nhiên nó đánh đổi bằng độ phức tạp IPAM: bạn phải theo dõi nhiều range, đảm bảo không chồng lấn với kế hoạch hybrid/on-prem, và chuẩn hóa naming để troubleshooting không trở thành ác mộng.

Mở rộng primary range của subnet

Đôi khi điểm nghẽn không phải Pod range mà là primary range (IP cho node). GKE/Compute Engine cho phép mở rộng primary range của subnet mà không gián đoạn (expand subnet) (Expand subnet range). Nhưng lưu ý: mở rộng chỉ tăng được, không thu nhỏ, và phải tránh chồng lấn với subnet/range khác.

Production architecture patterns

Pattern 1: Tách secondary range theo môi trường và cluster

Đừng dùng chung một secondary range Pod khổng lồ cho nhiều cluster. Tài liệu Google cảnh báo: nếu nhiều cluster VPC-native chia sẻ chung một secondary range cho Pod, một cluster có thể ngốn phần lớn dải và làm cluster khác cạn IP (VPC-native clusters). Pattern an toàn:

  • Mỗi cluster có secondary range Pod riêng, đặt tên rõ ràng theo env-cluster-pods.
  • Lập bảng IPAM tổng ở cấp tổ chức để tránh chồng lấn và dễ mở rộng.

Pattern 2: max-pods-per-node theo profile node pool

  • Node pool cho service nặng tài nguyên (ít Pod/node): đặt max-pods-per-node thấp → tiết kiệm IP đáng kể.
  • Node pool cho service nhẹ, mật độ cao: giữ giá trị cao hơn nhưng tính kỹ headroom IP.
  • Không dùng một giá trị max-pods-per-node cho mọi pool chỉ vì “đỡ phải nghĩ”.

Pattern 3: Khóa IP plan trước, chọn dataplane sau

IP plan và dataplane (xem file 2) là hai quyết định tạo-cluster gần như bất biến. Quy trình chuẩn: quyết secondary range sizing và max-pods-per-node → quyết dataplane (Dataplane V2 hay không) → mới tạo cluster. Đảo thứ tự dễ dẫn tới phải tạo lại cluster.

Real-world scenarios

Scenario A: SaaS scale fail giữa Black Friday

Một nền tảng SaaS đặt secondary range Pod /20 (4.096 địa chỉ) vì “hiện chỉ có 10 node”. Khi traffic tăng đột biến, autoscaler cần lên ~20 node với /24 mỗi node = 5.120 địa chỉ → vượt range. Node mới không nhận được Pod CIDR, pod treo Pending, dịch vụ sập đúng đỉnh doanh thu.

Bài học: sizing phải theo đỉnh tải dự kiến + headroom, không theo hiện trạng. Khắc phục khẩn cấp: thêm discontiguous Pod range + node pool mới.

Scenario B: Fintech bị firewall on-prem chặn vì SNAT sai

Một fintech cần Pod gọi service nội bộ on-prem qua Interconnect. Firewall on-prem chỉ cho phép dải Pod CIDR đã đăng ký. Nhưng vì cấu hình ip-masq-agent mặc định SNAT mọi traffic ra ngoài cluster, gói đến on-prem mang IP node (không nằm trong allowlist) → bị chặn. (Chi tiết masquerade ở file 3.)

Bài học: VPC-native cho phép Pod IP “thật”, nhưng phải cấu hình nonMasqueradeCIDRs để giữ source Pod IP cho các dải cần thiết.

Scenario C: Cluster legacy routes-based chạm route quota

Một cluster routes-based 800 node ăn 800 route, cộng với route khác trong VPC làm tổ chức chạm quota route, chặn việc tạo tài nguyên mạng mới ở các project khác.

Bài học: migrate sang VPC-native. Vì không thể chuyển in-place giữa hai mô hình, lộ trình thực tế là tạo cluster VPC-native mới và migrate workload (blue-green ở cấp cluster).

Common mistakes / anti-patterns

  1. Sizing secondary range theo hiện trạng, bỏ qua surge/blue-green và tăng trưởng. Đây là nguyên nhân số một gây IP exhaustion.
  2. Đặt max-pods-per-node cao mặc định cho mọi pool. Lãng phí IP gấp nhiều lần so với nhu cầu thật.
  3. Chia sẻ một secondary range Pod cho nhiều cluster. Một cluster ngốn hết, cluster khác chết.
  4. Quên rằng max-pods-per-node bất biến theo node pool. Phải tạo node pool mới để đổi.
  5. Tạo cluster routes-based mới năm 2025+. Tự khóa khỏi container-native LB và các tính năng VPC-native.
  6. Không lập bảng IPAM tập trung. Khi cần thêm discontiguous range, không biết dải nào an toàn.

GCP-native implementation guidance

Tạo cluster VPC-native với secondary range tự quản lý

bash
# Tạo subnet với secondary ranges cho Pod và Service
gcloud compute networks subnets create gke-subnet \
  --network=prod-vpc \
  --region=asia-southeast1 \
  --range=10.0.0.0/20 \
  --secondary-range=pods=10.4.0.0/14,services=10.8.0.0/20

# Tạo cluster VPC-native dùng các range trên
gcloud container clusters create prod-cluster \
  --region=asia-southeast1 \
  --enable-ip-alias \
  --network=prod-vpc \
  --subnetwork=gke-subnet \
  --cluster-secondary-range-name=pods \
  --services-secondary-range-name=services \
  --default-max-pods-per-node=64

Thêm Pod range mới khi sắp cạn (discontiguous)

bash
# 1. Thêm secondary range mới vào subnet
gcloud compute networks subnets update gke-subnet \
  --region=asia-southeast1 \
  --add-secondary-ranges=pods-2=10.40.0.0/14

# 2. Tạo node pool dùng range mới
gcloud container node-pools create pool-expansion \
  --cluster=prod-cluster \
  --region=asia-southeast1 \
  --pod-ipv4-range=pods-2 \
  --max-pods-per-node=64

Kiểm tra mức sử dụng secondary range

bash
gcloud compute networks subnets describe gke-subnet \
  --region=asia-southeast1 \
  --format="yaml(secondaryIpRanges)"

Kết nối với Architecture Framework

  • Reliability: capacity planning phải bao gồm tài nguyên “vô hình” như Pod IP, không chỉ CPU/RAM; thiếu headroom IP là dạng rủi ro ẩn điển hình (Reliability pillar).
  • Operational excellence: chuẩn hóa IPAM và naming range giúp giảm toil và tăng tốc troubleshooting khi sự cố mạng xảy ra (Operational excellence).

References

Phụ lục: mô hình tư duy về IP như một tài nguyên hữu hạn

Vì sao IP đáng được theo dõi như CPU

Trong vận hành GKE, ba loại tài nguyên dễ cạn nhưng hay bị bỏ quên: Pod IP, conntrack entry và endpoint map. Khác với CPU/RAM hiện rõ trên dashboard mặc định, ba loại này thường chỉ lộ ra khi đã quá muộn. Pod IP là loại có hậu quả lan rộng nhất vì nó chặn trực tiếp khả năng scale.

Nên xây một dashboard riêng theo dõi:

  • Tỷ lệ sử dụng secondary range Pod theo từng cluster.
  • Số node tối đa còn thêm được theo cấu hình max-pods-per-node hiện tại.
  • Dự báo thời điểm cạn IP theo tốc độ tăng node trung bình.

Quan hệ giữa IP plan và chiến lược upgrade

Surge upgrade và blue-green upgrade (Chương 6) đều làm tăng số node tạm thời. Blue-green đặc biệt tốn IP vì nó dựng song song một node pool tương đương trước khi cutover. Nếu IP plan không dự phòng phần node tạm này, một đợt upgrade tưởng an toàn lại trở thành sự cố cạn IP. Quy tắc thực dụng: dành tối thiểu headroom đủ cho chiến lược upgrade tốn IP nhất mà bạn dùng.

Checklist IP plan trước khi tạo cluster

  1. Ước tính node đỉnh = baseline + autoscaling + upgrade headroom + tăng trưởng 12–24 tháng.
  2. Chọn max-pods-per-node theo profile workload, không để mặc định cho mọi pool.
  3. Tính secondary range Pod đủ cho node đỉnh × dải mỗi node, làm tròn lên.
  4. Cấp secondary range Service đủ cho số ClusterIP dự kiến (kể cả Service headless và multi-tenant).
  5. Đặt tên range theo chuẩn env-cluster-pods / env-cluster-services.
  6. Ghi vào bảng IPAM tổ chức, đối chiếu chồng lấn với hybrid/on-prem.
  7. Dự trù sẵn dải discontiguous để mở rộng mà không cần tạo lại cluster.

Bài học thực chiến

  • Cạn Pod IP đến chậm nhưng bùng nổ nhanh; luôn cảnh báo trước khi chạm ngưỡng an toàn nội bộ.
  • max-pods-per-node là đòn bẩy tiết kiệm IP mạnh nhất nhưng bất biến theo pool — quyết đúng ngay từ đầu.
  • VPC-native cho Pod IP “thật”, nhưng giá trị đó chỉ phát huy khi masquerade và firewall được cấu hình nhất quán (xem file 3).
  • Migrate routes-based sang VPC-native là việc cấp cluster, không phải bật/tắt cờ — lên kế hoạch như một dự án migration.

FAQ thực chiến

Có thể chuyển một cluster routes-based sang VPC-native không?

Không có đường chuyển in-place. Cách thực tế là tạo cluster VPC-native mới và migrate workload theo kiểu blue-green ở cấp cluster, rồi rút cluster cũ.

Đổi max-pods-per-node cho cluster đang chạy được không?

Không đổi được cho node pool đã tạo. Bạn phải tạo node pool mới với giá trị mong muốn rồi migrate workload sang, sau đó xóa pool cũ.

Secondary range Pod cạn thì làm gì ngay?

Thêm secondary range mới (discontiguous Pod CIDR) vào subnet và tạo node pool dùng range đó. Đây là cách mở rộng không cần tạo lại cluster.

Vì sao node có /24 (256 IP) nhưng chỉ chạy ~110 Pod?

Để giữ headroom tránh tái dùng IP quá nhanh khi Pod churn cao, giảm nguy cơ gói tin đến nhầm Pod mới mang IP vừa được cấp lại.

Pod IP có bị NAT khi nói chuyện trong VPC không?

Không, trong nội bộ VPC (và VPC peer) Pod IP là alias IP định tuyến tự nhiên nên không cần NAT. SNAT chỉ xảy ra khi đi ra ngoài các dải được cấu hình masquerade (xem file 3).