Pianifica la scalabilità


Questa pagina descrive le best practice generali per la progettazione di cluster GKE scalabili. Puoi applicare questi suggerimenti a tutti i cluster e carichi di lavoro per ottenere prestazioni ottimali. Questi suggerimenti sono particolarmente importanti per i cluster che prevedi di scalare su larga scala. Le best practice sono rivolte agli amministratori responsabili del provisioning dell'infrastruttura e agli sviluppatori che preparano i componenti e i carichi di lavoro di Kubernetes.

Che cos'è la scalabilità?

In un cluster Kubernetes, per scalabilità si intende la capacità del cluster di crescere rimanendo all'interno dei suoi obiettivi del livello di servizio (SLO). Kubernetes ha anche un proprio set di SLO

Kubernetes è un sistema complesso e la sua scalabilità è determinata da diversi fattori. Alcuni di questi fattori includono il tipo e il numero di nodi in un pool di nodi, i tipi e il numero di pool di nodi, il numero di pod disponibili, la modalità di allocazione delle risorse ai pod e il numero di servizi o backend dietro un servizio.

Best practice per la disponibilità

Scelta di un piano di controllo a livello di regione o zona

A causa delle differenze architettoniche, i cluster regionali sono più adatti per un'alta disponibilità. I cluster a livello di regione hanno più piani di controllo in più zone di computing in un'area geografica, mentre i cluster di zona hanno un piano di controllo in una singola zona di computing.

Se viene eseguito l'upgrade di un cluster di zona, la VM del piano di controllo subisce un tempo di inattività durante il quale l'API Kubernetes non è disponibile fino al completamento dell'upgrade.

Nei cluster a livello di regione, il piano di controllo rimane disponibile durante la manutenzione del cluster, ad esempio durante la rotazione degli IP, l'upgrade delle VM del piano di controllo o il ridimensionamento di cluster o pool di nodi. Quando esegui l'upgrade di un cluster a livello di regione, due VM del piano di controllo su tre sono sempre in esecuzione durante l'upgrade in sequenza, quindi l'API Kubernetes è ancora disponibile. Analogamente, un'interruzione a zona singola non causerà tempi di inattività nel piano di controllo a livello di regione.

Tuttavia, i cluster regionali più ad alta disponibilità presentano determinati compromessi:

  • Le modifiche alla configurazione del cluster richiedono più tempo perché devono essere distribuite su tutti i piani di controllo in un cluster a livello di regione anziché nel singolo piano di controllo nei cluster di zona.

  • Potresti non essere in grado di creare o eseguire l'upgrade dei cluster a livello di regione con la stessa frequenza dei cluster di zona. Se non è possibile creare VM in una delle zone, a causa di una mancanza di capacità o di un altro problema temporaneo, non è possibile creare o eseguire l'upgrade dei cluster.

A causa di questi compromessi, i cluster di zona e regionali hanno casi d'uso diversi:

  • Utilizza i cluster di zona per creare o eseguire rapidamente l'upgrade dei cluster quando la disponibilità è meno problematica.
  • Utilizza cluster a livello di regione quando la disponibilità è più importante della flessibilità.

Seleziona con attenzione il tipo di cluster quando crei un cluster, perché non puoi modificarlo dopo averlo creato. Occorre creare un nuovo cluster e migrarvi il traffico. La migrazione del traffico di produzione tra cluster è possibile, ma difficile su larga scala.

Scelta di pool di nodi multi-zona o a zona singola

Per ottenere un'alta disponibilità, il piano di controllo Kubernetes e i suoi nodi devono essere distribuiti in diverse zone. GKE offre due tipi di pool di nodi: a zona singola e multi-zona.

Per eseguire il deployment di un'applicazione ad alta disponibilità, distribuisci il tuo carico di lavoro in più zone di computing di una regione utilizzando pool di nodi multi-zona, che distribuiscono i nodi in modo uniforme tra le zone.

Se tutti i nodi si trovano nella stessa zona, non potrai pianificare i pod se la zona diventa non raggiungibile. L'utilizzo di pool di nodi multi-zona prevede determinati compromessi:

  • Le GPU sono disponibili solo in zone specifiche. Potrebbe non essere possibile ottenerle in tutte le zone della regione.

  • La latenza di round trip tra le zone all'interno di una singola regione potrebbe essere superiore a quella tra le risorse in una singola zona. La differenza dovrebbe essere irrilevante per la maggior parte dei carichi di lavoro.

  • Il prezzo del traffico in uscita tra zone nella stessa regione è disponibile nella pagina dei prezzi di Compute Engine.

Best practice per la scalabilità

Infrastruttura di base

I carichi di lavoro Kubernetes richiedono networking, computing e archiviazione. Devi fornire CPU e memoria sufficienti per eseguire i pod. Tuttavia, esistono altri parametri dell'infrastruttura sottostante che possono influenzare le prestazioni e la scalabilità di un cluster GKE.

Networking per il cluster

L'utilizzo di un cluster nativo VPC è l'impostazione predefinita di networking e la scelta consigliata per la configurazione di nuovi cluster GKE. I cluster nativi di VPC consentono di carichi di lavoro più grandi, un numero maggiore di nodi e alcuni altri vantaggi.

In questa modalità, la rete VPC ha un intervallo secondario per tutti gli indirizzi IP dei pod. A ogni nodo viene quindi assegnata una sezione dell'intervallo secondario per i propri indirizzi IP dei pod. Ciò consente alla rete VPC di comprendere in modo nativo come instradare il traffico ai pod senza fare affidamento su route personalizzate. Una singola rete VPC può avere fino a 15.000 VM.

Un altro approccio, che è deprecato e supporta non più di 1500 nodi, prevede l'utilizzo di un cluster basato su route. Un cluster basato su route non è adatto a carichi di lavoro di grandi dimensioni. Consuma la quota di route VPC e non ha altri vantaggi delle reti native di VPC. Funziona aggiungendo una nuova route personalizzata alla tabella di routing nella rete VPC per ogni nuovo nodo.

Cluster privati

Nei cluster GKE normali, tutti i nodi hanno indirizzi IP pubblici. Nei cluster privati, i nodi hanno solo indirizzi IP interni per isolare i nodi dalla connettività in entrata e in uscita a internet. GKE utilizza il peering di rete VPC per connettere le VM che eseguono il server API Kubernetes al resto del cluster. Ciò consente una velocità effettiva maggiore tra i piani di controllo e i nodi di GKE, poiché il traffico viene instradato utilizzando indirizzi IP privati.

L'utilizzo di cluster privati offre l'ulteriore vantaggio di sicurezza che i nodi non sono esposti a internet.

Bilanciamento del carico del cluster

GKE Ingress e Cloud Load Balancing configurano ed eseguono il deployment dei bilanciatori del carico per esporre carichi di lavoro Kubernetes all'esterno del cluster e anche sulla rete internet pubblica. I controller GKE Ingress e di servizio eseguono il deployment di oggetti come regole di forwarding, mappe URL, servizi di backend, gruppi di endpoint di rete e altro ancora per conto dei carichi di lavoro GKE. Ognuna di queste risorse ha quote e limiti intrinseci e questi limiti si applicano anche a GKE. Quando una particolare risorsa di Cloud Load Balancing ha raggiunto la quota, impedisce il corretto deployment di un determinato servizio Ingress o di un servizio e vengono visualizzati errori negli eventi della risorsa.

La tabella seguente descrive i limiti di scalabilità quando utilizzi GKE Ingress e Services:

Bilanciatore del carico Limite di nodi per cluster
Bilanciatore del carico di rete passthrough interno
Bilanciatore del carico di rete passthrough esterno 1000 nodi per zona
Bilanciatore del carico delle applicazioni esterno
Bilanciatore del carico delle applicazioni interno Nessun limite di nodi

Se hai bisogno di scalare ulteriormente, contatta il team di vendita Google Cloud per aumentare questo limite.

DNS

Il Service Discovery in GKE viene fornito tramite kube-dns, una risorsa centralizzata per fornire una risoluzione DNS ai pod in esecuzione all'interno del cluster. Questo può diventare un collo di bottiglia per cluster molto grandi o per carichi di lavoro con un carico di richieste elevato. GKE scala automaticamente kube-dns in base alle dimensioni del cluster per aumentarne la capacità. Quando questa capacità non è ancora sufficiente, GKE offre una risoluzione locale e distribuita delle query DNS su ciascun nodo con NodeLocal DNSCache. In questo modo, su ogni nodo GKE viene fornita una cache DNS locale che risponde alle query localmente, distribuendo il carico e garantendo tempi di risposta più rapidi.

Gestione degli indirizzi IP nei cluster nativi di VPC

Un cluster nativo di VPC utilizza tre intervalli di indirizzi IP:

  • Intervallo principale per la subnet del nodo: il valore predefinito è /20 (4092 indirizzi IP).
  • Intervallo secondario per la subnet dei pod: il valore predefinito è /14 (262.144 indirizzi IP). Tuttavia, puoi configurare la subnet dei pod.
  • Intervallo secondario per la subnet del servizio: il valore predefinito è /20 (4096 indirizzi). Tuttavia, non puoi modificare questo intervallo dopo aver creato questa subnet di servizio.

Per ulteriori informazioni, consulta Intervalli di indirizzi IP per i cluster nativi di VPC.

Limitazioni e consigli relativi agli indirizzi IP:

  • Limite di nodi: il limite di nodi è determinato dagli indirizzi IP principali e dei pod per nodo. Gli intervalli di indirizzi IP del nodo e del pod devono avere un numero sufficiente di indirizzi per eseguire il provisioning di un nuovo nodo. Per impostazione predefinita, puoi creare solo 1024 nodi a causa delle limitazioni degli indirizzi IP dei pod.
  • Limite di pod per nodo: per impostazione predefinita, il limite di pod per nodo è di 110 pod. Tuttavia, puoi configurare CIDR pod più piccoli per un uso efficiente con un numero inferiore di pod per nodo.
  • Scalabilità oltre la RFC 1918: se hai bisogno di più indirizzi IP di quelli disponibili nello spazio privato definito da RFC 1918, ti consigliamo di utilizzare indirizzi privati non RFC 1918 o PUPI per una maggiore flessibilità.
  • Intervallo di indirizzi IP secondari per servizio e pod: per impostazione predefinita, puoi configurare i servizi 4096. Puoi tuttavia configurare altri servizi scegliendo l'intervallo di subnet dei servizi. Non puoi modificare intervalli secondari dopo la creazione. Quando crei un cluster, assicurati di scegliere intervalli sufficientemente grandi da supportare la crescita prevista. Tuttavia, potrai aggiungere altri indirizzi IP per i pod in un secondo momento utilizzando il CIDR multi-pod separato. Per maggiori informazioni, consulta Spazio libero di indirizzi IP insufficiente per i pod.

Per ulteriori informazioni, consulta Intervalli di limitazione dei nodi e Pianificare gli indirizzi IP durante la migrazione a GKE.

Configurazione dei nodi per migliorare le prestazioni

I nodi GKE sono normali macchine virtuali Google Cloud. Alcuni dei loro parametri, ad esempio il numero di core o le dimensioni del disco, possono influire sulle prestazioni dei cluster GKE.

Ridurre i tempi di inizializzazione dei pod

Puoi utilizzare il flusso di immagini per trasmettere dati da immagini container idonee quando i carichi di lavoro le richiedono, il che riduce i tempi di inizializzazione.

Traffico in uscita

In Google Cloud, il tipo di macchina e il numero di core allocati all'istanza ne determinano la capacità di rete. La larghezza di banda massima in uscita varia da 1 a 32 Gbps, mentre la massima larghezza di banda in uscita per le macchine e2-medium-2 predefinite è di 2 Gbps. Per maggiori dettagli sui limiti di larghezza di banda, vedi Tipi di macchina con core condivisi.

IOPS e velocità effettiva del disco

In Google Cloud, la dimensione dei dischi permanenti determina le IOPS e la velocità effettiva del disco. In genere GKE usa dischi permanenti come dischi di avvio e per il supporto dei volumi permanenti di Kubernetes. L'aumento delle dimensioni del disco aumenta sia IOPS che velocità effettiva, fino a determinati limiti.

Ogni operazione di scrittura di disco permanente contribuisce al limite di traffico di rete in uscita cumulativo dell'istanza della macchina virtuale. Di conseguenza, le prestazioni IOPS dei dischi, in particolare delle unità SSD, dipendono anche dal numero di vCPU nell'istanza, oltre che dalla dimensione del disco. Le VM core più bassi hanno limiti di IOPS di scrittura inferiori a causa delle limitazioni del traffico di rete in uscita sulla velocità effettiva di scrittura.

Se l'istanza della macchina virtuale ha CPU insufficienti, l'applicazione non potrà avvicinarsi al limite di IOPS. Come regola generale, dovresti avere una CPU disponibile per ogni 2000-2500 IOPS di traffico previsto.

I carichi di lavoro che richiedono capacità elevata o un numero elevato di dischi devono considerare i limiti del numero di DP associabili a una singola VM. Per le VM normali, il limite è di 128 dischi con una dimensione totale di 64 TB, mentre le VM con core condivisi hanno un limite di 16 DP con una dimensione totale di 3 TB. Questo limite viene applicato da Google Cloud, non da Kubernetes.

Monitora le metriche del piano di controllo

Utilizza le metriche del piano di controllo disponibili per configurare le dashboard di monitoraggio. Puoi utilizzare le metriche del piano di controllo per osservare l'integrità del cluster, osservare i risultati delle modifiche alla configurazione del cluster (ad esempio, il deployment di carichi di lavoro aggiuntivi o componenti di terze parti) o per la risoluzione dei problemi.

Una delle metriche più importanti da monitorare è la latenza dell'API Kubernetes. L'aumento della latenza indica un sovraccarico del sistema. Tieni presente che le chiamate LIST che trasferiscono grandi quantità di dati dovrebbero avere una latenza molto più elevata rispetto alle richieste più piccole.

L'aumento della latenza dell'API Kubernetes può essere causata anche dalla lentezza della reattività dei hook di ammissione di terze parti. Puoi utilizzare le metriche per misurare la latenza dei webhook e rilevare questi problemi comuni.

Best practice per gli sviluppatori Kubernetes

Usa elenco e sequenza di visualizzazione anziché elenco periodico

In qualità di sviluppatore Kubernetes, potresti dover creare un componente con i seguenti requisiti:

  • Il componente deve recuperare periodicamente l'elenco di alcuni oggetti Kubernetes.
  • Il componente deve essere eseguito in più istanze (in caso di DaemonSet, anche su ciascun nodo).

Un componente di questo tipo può generare picchi di carico su kube-apiserver, anche se lo stato degli oggetti recuperati periodicamente non cambia.

L'approccio più semplice consiste nell'utilizzare chiamate LIST periodiche. Tuttavia, questo è un approccio inefficiente e costoso sia per il chiamante che per il server, perché tutti gli oggetti devono essere caricati in memoria, serializzati e trasferiti ogni volta. L'uso eccessivo di richieste LIST potrebbe sovraccaricare il piano di controllo o generare notevoli limitazioni di tali richieste.

Puoi migliorare il tuo componente impostando il parametroresourceVersion=0 sulle chiamate LIST. Ciò consente a kube-apiserver di utilizzare la cache di oggetti in memoria e di ridurre il numero di interazioni interne tra kube-apiserver e il database etcd e la relativa elaborazione.

Consigliamo vivamente di evitare le chiamate LIST ripetibili e di sostituirle con gli elenchi e i pattern di visualizzazione. Elenca gli oggetti una volta, quindi utilizza l'API Watch per ricevere modifiche incrementali dello stato. Questo approccio riduce i tempi di elaborazione e riduce al minimo il traffico rispetto alle chiamate LIST periodiche. Se gli oggetti non cambiano, non viene generato alcun carico aggiuntivo.

Se utilizzi il linguaggio Go, controlla SharedInformer e SharedInformerFactory per i pacchetti Go che implementano questo pattern.

Limita il traffico non necessario generato da visualizzazioni ed elenchi

Kubernetes utilizza internamente gli orologi per inviare notifiche sugli aggiornamenti degli oggetti. Anche con gli smartwatch che richiedono molte meno risorse rispetto alle chiamate LIST periodiche, l'elaborazione degli smartwatch in cluster di grandi dimensioni può richiedere una parte significativa delle risorse del cluster e influire sulle prestazioni del cluster. Il maggiore impatto negativo è generato dalla creazione di orologi che osservano oggetti che cambiano spesso da più posizioni. Ad esempio, osservando i dati su tutti i pod di un componente in esecuzione su tutti i nodi. Se installi codice o estensioni di terze parti sul tuo cluster, possono creare questi orologi in background.

Consigliamo le seguenti best practice:

  • Riduci le elaborazioni non necessarie e il traffico generato da visualizzazioni ed LIST chiamate.
  • Evita di creare orologi che osservino oggetti che cambiano spesso in vari punti (ad esempio DaemonSet).
  • (Vivamente consigliato) Crea un controller centrale che controlla ed elabora i dati richiesti su un singolo nodo.
  • Controlla solo un sottoinsieme degli oggetti, ad esempio kubelet su ciascun nodo osserva solo i pod pianificati sullo stesso nodo.
  • Evita di eseguire il deployment di componenti o estensioni di terze parti che potrebbero influire sulle prestazioni del cluster eseguendo un volume elevato di smartwatch o chiamate LIST.

Limita le dimensioni del manifest dell'oggetto Kubernetes

Se hai bisogno di operazioni rapide che richiedono una velocità effettiva dei pod elevata, come il ridimensionamento o l'aggiornamento di carichi di lavoro di grandi dimensioni, assicurati di mantenere al minimo le dimensioni del manifest dei pod, idealmente inferiori a 10 KiB.

Kubernetes archivia i manifest delle risorse in etcd. L'intero manifest viene inviato ogni volta che viene recuperata la risorsa, anche quando utilizzi il pattern list e watch.

Le dimensioni del manifest presentano le seguenti limitazioni:

  • Dimensione massima per ogni oggetto in etcd: circa 1,5 MiB.
  • Quota totale per tutti gli oggetti etcd nel cluster: la dimensione preconfigurata della quota è di 6 GiB. Questo include un log delle modifiche con tutti gli aggiornamenti di tutti gli oggetti negli ultimi 150 secondi della cronologia del cluster.
  • Prestazioni del piano di controllo durante periodi di traffico elevato: dimensioni manifest più grandi aumentano il carico sul server API.

Per i singoli oggetti elaborati raramente, le dimensioni del file manifest solitamente non sono un problema, purché siano inferiori a 1,5 MiB. Tuttavia, dimensioni del manifest superiori a 10 KiB per numerosi oggetti elaborati di frequente, ad esempio pod in carichi di lavoro molto grandi, possono causare un aumento della latenza delle chiamate API e una riduzione delle prestazioni complessive. Gli elenchi e le visualizzazioni, in particolare, possono essere influenzati in modo significativo dai file manifest di grandi dimensioni. Potresti anche riscontrare problemi con la quota etcd, perché la quantità di revisioni negli ultimi 150 secondi può accumularsi rapidamente durante periodi di traffico elevato del server API.

Per ridurre le dimensioni del manifest di un pod, è possibile utilizzare i ConfigMap Kubernetes per archiviare una parte della configurazione, in particolare quella condivisa da più pod nel cluster. Ad esempio, le variabili di ambiente sono spesso condivise da tutti i pod in un carico di lavoro.

Tieni presente che è anche possibile riscontrare problemi simili con gli oggetti ConfigMap se sono numerosi, grandi ed elaborati con la stessa frequenza dei pod. L'estrazione di parte della configurazione è più utile quando diminuisce il traffico complessivo.

Disabilita il montaggio automatico dell'account di servizio predefinito

Se la logica in esecuzione nei pod non ha bisogno di accedere all'API Kubernetes, devi disabilitare il montaggio automatico predefinito dell'account di servizio per evitare la creazione di secret e orologi correlati.

Quando crei un pod senza specificare un account di servizio, Kubernetes esegue automaticamente le seguenti azioni:

  • Assegna l'account di servizio predefinito al pod.
  • Monta le credenziali dell'account di servizio come secret per il pod.
  • Per ogni secret montato, il kubelet crea uno smartwatch per osservare le modifiche al Secret su ogni nodo.

Nei cluster di grandi dimensioni, queste azioni rappresentano migliaia di orologi non necessari, che possono sovraccaricare kube-apiserver.

Utilizza i buffer di protocollo anziché JSON per le richieste API

Utilizza i buffer di protocollo quando implementi componenti altamente scalabili come descritto nei concetti dell'API Kubernetes.

L'API REST Kubernetes supporta JSON e buffer di protocollo come formato di serializzazione per gli oggetti. Per impostazione predefinita viene utilizzato JSON, ma i buffer di protocollo sono più efficienti per le prestazioni su larga scala perché richiede un'elaborazione meno intensiva della CPU e invia meno dati sulla rete. L'overhead associato all'elaborazione di JSON può causare timeout durante l'elenco di dati di grandi dimensioni.

Che cosa succede dopo?