GCP GKE Kubernetes autoscaling

GKE node pool zablokowany w stanie PROVISIONING: wyczerpanie limitów, zakresy IP i dostępność typów maszyn

Rozwiązanie problemu z GKE node pool zablokowanym w stanie PROVISIONING z powodu wyczerpania limitów, niewystarczających zakresów IP dla podów lub niedostępności wymaganego typu maszyny w skonfigurowanej strefie.

·
Twój GKE node pool jest zablokowany w stanie PROVISIONING lub nowe nody są NotReady. Pody pozostają w stanie Pending, autoscaler próbuje skalować w górę, ale żadne nowe nody się nie pojawiają. Przyczyna to niemal zawsze ograniczenie zasobów poza samym Kubernetes - quota GCP, wyczerpanie adresów IP lub dostępność typu maszyny.

Objawy

Node pool pokazuje status PROVISIONING przez dłuższy czas. Pody pozostają w stanie Pending z błędami planowania:

# Node pool zablokowany w stanie PROVISIONING
gcloud container node-pools describe default-pool \
  --cluster my-cluster \
  --zone europe-west1-b \
  --format="value(status)"
# Wynik: PROVISIONING

# Nody w stanie NotReady
kubectl get nodes
# NAME                                  STATUS     AGE   VERSION
# gke-my-cluster-default-pool-abc123    NotReady   15m   v1.29.4-gke.1234

# Pody zablokowane w Pending
kubectl get pods -A | grep Pending
# default   my-app-7b9f4d-xk2lm   0/1   Pending   0   12m

# Sprawdź dlaczego pody nie są planowane
kubectl describe pod my-app-7b9f4d-xk2lm | grep -A5 Events
# Events:
#   Warning  FailedScheduling  pod/my-app-7b9f4d-xk2lm
#   0/3 nodes are available: 3 Insufficient cpu.

# Logi cluster autoscalera
kubectl -n kube-system logs -l k8s-app=cluster-autoscaler --tail=50 | grep -i "scale up"
# Could not scale up node pool: RESOURCE_POOL_EXHAUSTED

Cluster autoscaler chce dodać nody, ale nie może ich utworzyć z powodu ograniczeń na poziomie infrastruktury.

Przyczyna

Tworzenie nodów GKE kończy się niepowodzeniem z trzech głównych przyczyn infrastrukturalnych:

  • Wyczerpanie limitów regionu (quota GCP). GCP wymusza limity per region na CPU, instancje, adresy IP i akceleratory GPU. Po osiągnięciu limitu Compute Engine odmawia tworzenia nowych VM. To najczęstsza przyczyna w projektach z wieloma klastrami lub takimi, które rosły organicznie.
  • Niewystarczający zakres IP dla podów. GKE używa wtórnych zakresów IP dla podów. Każdy nod rezerwuje domyślnie blok /24 (256 adresów IP). Jeśli zakres wtórny jest za mały, GKE nie może przypisać CIDR podów do nowego noda i tworzenie się blokuje.
  • Niedostępność typu maszyny w strefie. Nie wszystkie typy maszyn są dostępne we wszystkich strefach. Jeśli żądasz n2-standard-32 w strefie, gdzie ta rodzina jest wyprzedana, tworzenie czeka w nieskończoność. Dotyczy to szczególnie instancji GPU i dużych typów maszyn.

Rozwiązanie

Krok 1: Sprawdź wyczerpanie limitów

# Wylistuj wszystkie quota dla regionu z aktualnym zużyciem
gcloud compute regions describe europe-west1 \
  --format="table(quotas.metric,quotas.limit,quotas.usage)" \
  | grep -E "CPUS|INSTANCES|IN_USE_ADDRESSES|SSD_TOTAL_GB"

# Przykładowy wynik pokazujący wyczerpanie limitów CPU:
# CPUS                24.0    24.0    <-- na limicie
# INSTANCES           100.0   15.0
# IN_USE_ADDRESSES    23.0    20.0
# SSD_TOTAL_GB        2048.0  1500.0

# Sprawdź czy konkretne quota blokuje operacje
gcloud compute regions describe europe-west1 \
  --format="json(quotas)" | jq '.quotas[] | select(.usage >= .limit)'

Jeśli limit jest wyczerpany, poproś o podwyższenie:

# Poproś o podwyższenie limitu przez gcloud
gcloud compute regions describe europe-west1 --format="json(quotas)"

# Następnie poproś o podwyższenie w Console:
# IAM & Admin > Quotas > Filtruj po regionie/metryce > Edit Quotas
# Lub użyj gcloud:
gcloud alpha services quota update \
  --consumer=projects/my-project \
  --service=compute.googleapis.com \
  --metric=compute.googleapis.com/cpus \
  --unit=1/{project}/{region} \
  --dimensions=region=europe-west1 \
  --value=48

Krok 2: Sprawdź wyczerpanie zakresu IP dla podów

# Sprawdź zakresy wtórne na podsieci
gcloud compute networks subnets describe my-subnet \
  --region=europe-west1 \
  --format="table(secondaryIpRanges.rangeName,secondaryIpRanges.ipCidrRange)"

# Przykładowy wynik:
# RANGE_NAME     IP_CIDR_RANGE
# pods           10.4.0.0/20      <-- Tylko 16 bloków /24 = max 16 nodów
# services       10.8.0.0/20

# Sprawdź ile nodów zużywa CIDR podów
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'

Jeśli zakres podów jest pełny, rozszerz go lub utwórz nowy node pool z większym zakresem:

# Opcja 1: Utwórz nowy node pool z inną podsiecią mającą większy zakres podów
gcloud container node-pools create expanded-pool \
  --cluster=my-cluster \
  --zone=europe-west1-b \
  --machine-type=e2-standard-4 \
  --num-nodes=3 \
  --max-pods-per-node=64 \
  --enable-autoscaling \
  --min-nodes=1 \
  --max-nodes=10

# Opcja 2: Zmniejsz max-pods-per-node by używać mniejszych bloków CIDR per nod
# To pozwala na więcej nodów w tym samym zakresie wtórnym
gcloud container node-pools create efficient-pool \
  --cluster=my-cluster \
  --zone=europe-west1-b \
  --machine-type=e2-standard-4 \
  --max-pods-per-node=32 \
  --num-nodes=3

Krok 3: Obsługa niedostępności typu maszyny

# Sprawdź jakie typy maszyn są dostępne w strefie
gcloud compute machine-types list \
  --zones=europe-west1-b \
  --filter="name:n2-standard" \
  --format="table(name,zone,guestCpus,memoryMb)"

# Jeśli typ maszyny jest niedostępny, sprawdź inne strefy
gcloud compute machine-types list \
  --filter="name=n2-standard-8" \
  --format="table(name,zone)"

Użyj wielostrefowych node pool z zapasowymi typami maszyn:

# Utwórz regionalny (wielostrefowy) node pool z zapasowym typem maszyny
gcloud container node-pools create resilient-pool \
  --cluster=my-cluster \
  --region=europe-west1 \
  --machine-type=n2-standard-8 \
  --enable-autoscaling \
  --min-nodes=1 \
  --max-nodes=10 \
  --num-nodes=3

# Dla jeszcze większej odporności użyj spot VM
gcloud container node-pools create spot-pool \
  --cluster=my-cluster \
  --region=europe-west1 \
  --machine-type=n2-standard-8 \
  --spot \
  --enable-autoscaling \
  --min-nodes=0 \
  --max-nodes=20 \
  --node-labels=workload-type=batch

Krok 4: Skonfiguruj Node Auto-Provisioning (NAP) dla automatycznego przełączania

# Włącz node auto-provisioning z limitami zasobów
gcloud container clusters update my-cluster \
  --zone=europe-west1-b \
  --enable-autoprovisioning \
  --min-cpu=1 \
  --max-cpu=100 \
  --min-memory=1 \
  --max-memory=400 \
  --autoprovisioning-locations=europe-west1-b,europe-west1-c,europe-west1-d

NAP pozwala GKE automatycznie tworzyć node pool z innymi typami maszyn, gdy preferowany typ jest niedostępny.

Weryfikacja

Po zastosowaniu poprawek potwierdź, że nody mogą być tworzone:

# 1. Zweryfikuj, że node pool jest RUNNING (nie PROVISIONING)
gcloud container node-pools describe default-pool \
  --cluster my-cluster \
  --zone europe-west1-b \
  --format="value(status)"
# Oczekiwane: RUNNING

# 2. Zweryfikuj, że wszystkie nody są Ready
kubectl get nodes
# Oczekiwane: wszystkie STATUS = Ready

# 3. Zweryfikuj, że pody w stanie Pending zostały zaplanowane
kubectl get pods -A | grep Pending
# Oczekiwane: brak wyników

# 4. Zweryfikuj, że autoscaler może tworzyć nowe nody (wywołaj skalowanie)
kubectl run test-scale --image=nginx --requests='cpu=500m' --replicas=5
kubectl get pods -w
# Oczekiwane: pody są planowane w ciągu 2-3 minut wraz z pojawianiem się nowych nodów

# Sprzątanie po teście
kubectl delete deployment test-scale

# 5. Sprawdź status cluster autoscalera
kubectl -n kube-system describe configmap cluster-autoscaler-status | grep -A5 "Health"
# Oczekiwane: Healthy

Klaster GKE, który nie może się skalować, to tykająca bomba. Gdy ruch wzrasta lub wdrożenia wymagają więcej zasobów, pody pozostają w stanie Pending i aplikacja staje się niedostępna. Podwyższenie limitu wymaga minut na zgłoszenie, ale godzin na zatwierdzenie - planuj więc z wyprzedzeniem. Utrzymuj co najmniej 20% zapasu na limit CPU i IP w regionach produkcyjnych i zawsze używaj wielostrefowych node pool, by przetrwać problemy z pojemnością w pojedynczej strefie.

 

Jerzy Kopaczewski

Utrzymujesz GKE na produkcji?

Umów bezpłatną 30-minutową rozmowę. Projektujemy klastry GKE z prawidłowym autoskalowaniem, planowaniem IP i wielostrefową odpornością, byś nigdy nie wpadł w ścianę braku zasobów.