Questa pagina descrive le best practice generali per la progettazione di cluster GKE scalabili. Puoi applicare questi consigli a tutti i cluster e i carichi di lavoro per ottenere un rendimento ottimale. Questi consigli sono particolarmente importanti per i cluster che prevedi di scalare notevolmente. Le best practice sono destinate agli amministratori responsabili del provisioning dell'infrastruttura e agli sviluppatori che preparano componenti e carichi di lavoro Kubernetes.
Che cos'è la scalabilità?
In un cluster Kubernetes, la scalabilità si riferisce alla capacità del cluster di crescere rispettando i suoi obiettivi del livello di servizio (SLO). Kubernetes ha anche il suo insieme di SLO
Kubernetes è un sistema complesso e la sua capacità di scalare è determinata da diversi fattori. Alcuni di questi fattori includono il tipo e il numero di nodi in un pool di nodi, i tipi e i numeri 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à
Scegliere un piano di controllo regionale o zonale
A causa delle differenze di architettura, i cluster a livello di regione sono più adatti per la disponibilità elevata. I cluster a livello di regione hanno più piani di controllo in più zone di calcolo di una regione, mentre i cluster di zona hanno un piano di controllo in un'unica zona di computing.
Se viene eseguito l'upgrade di un cluster zonale, la VM del piano di controllo presenta un tempo di riposo durante il quale l'API Kubernetes non è disponibile fino al completamento dell'upgrade.
Nei cluster regionali, il piano di controllo rimane disponibile durante la manutenzione del cluster, ad esempio la rotazione degli IP, l'upgrade delle VM del piano di controllo o il ridimensionamento dei cluster o dei node pool. Durante l'upgrade di un cluster regionale, due VM del piano di controllo su tre sono sempre in esecuzione durante l'upgrade graduale, quindi l'API Kubernetes è ancora disponibile. Analogamente, un'interruzione del servizio in una singola zona non causerà tempi di inattività nel piano di controllo regionale.
Tuttavia, i cluster regionali con una maggiore disponibilità comportano alcuni compromessi:
Le modifiche alla configurazione del cluster richiedono più tempo perché devono essere propagate a tutti i control plane in un cluster a livello di regione anziché al singolo control plane nei cluster di zona.
Potresti non essere in grado di creare o eseguire l'upgrade dei cluster regionali con la stessa frequenza dei cluster zonali. Se non è possibile creare VM in una delle zone, per mancanza di capacità o per altri problemi temporanei, non è possibile creare o eseguire l'upgrade dei cluster.
A causa di questi compromessi, i cluster zonali e regionali hanno casi d'uso diversi:
- Utilizza i cluster di zona per creare o eseguire l'upgrade dei cluster rapidamente quando la disponibilità non è un problema.
- Utilizza i cluster a livello di regione quando la disponibilità è più importante della flessibilità.
Seleziona attentamente il tipo di cluster quando lo crei, perché non potrai modificarlo dopo la creazione. Devi invece creare un nuovo cluster e poi eseguire la migrazione del traffico al suo interno. La migrazione del traffico di produzione tra i cluster è possibile, ma difficile su larga scala.
Scegliere pool di nodi multizonali o a zona singola
Per ottenere un'alta disponibilità, il piano di controllo di Kubernetes e i relativi nodi devono essere distribuiti in zone diverse. 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 carico di lavoro su più zone di calcolo in una regione utilizzando pool di nodi multizonali 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 irraggiungibile. L'utilizzo di pool di nodi multizonali comporta alcuni compromessi:
Le GPU sono disponibili solo in zone specifiche. Potrebbe non essere possibile acquistarli in tutte le zone della regione.
La latenza di andata e ritorno tra le zone all'interno di una singola regione potrebbe essere superiore a quella tra le risorse di una singola zona. La differenza dovrebbe essere irrilevante per la maggior parte dei workload.
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, calcolo e archiviazione. Devi fornire CPU e memoria sufficienti per eseguire i pod. Tuttavia, esistono altri parametri dell'infrastruttura di base che possono influire sul rendimento e sulla scalabilità di un cluster GKE.
Networking per il cluster
L'utilizzo di un cluster nativo VPC è l'impostazione predefinita per il networking e la scelta consigliata per la configurazione di nuovi cluster GKE. I cluster nativi VPC consentono carichi di lavoro più grandi, un numero maggiore di nodi e altri vantaggi.
In questa modalità, la rete VPC ha un intervallo secondario per tutti gli indirizzi IP del pod. A ogni nodo viene quindi assegnato un segmento dell'intervallo secondario per i suoi indirizzi IP del pod. In questo modo, la rete VPC può 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, deprecato e che non supporta più di 1500 nodi, consiste nell'utilizzare un cluster basato su route. Un cluster basato su route non è adatto per carichi di lavoro di grandi dimensioni. Consuma la quota delle route VPC e non offre gli altri vantaggi della rete VPC nativa. Funziona aggiungendo una nuova route personalizzata alla tabella di routing nella rete VPC per ogni nuovo nodo.
Dimensione cluster
I cluster con più di 5000 nodi devono utilizzare Private Service Connect. Private Service Connect collega in modo privato i nodi e il piano di controllo e offre una maggiore sicurezza e prestazioni della rete.
Bilanciamento del carico del cluster
GKE Ingress e Cloud Load Balancing configurano ed eseguono il deployment di bilanciatori del carico per esporre i carichi di lavoro Kubernetes all'esterno del cluster e anche all'internet pubblico. I controller Ingress e Service di GKE eseguono il deployment di oggetti come regole di inoltro, 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 insiti e questi limiti si applicano anche in GKE. Quando una determinata risorsa Cloud Load Balancing ha raggiunto la quota, impedisce l'implementazione corretta di un determinato Ingress o Service 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 |
Application Load Balancer esterno |
|
Bilanciatore del carico delle applicazioni interno | Nessun limite di nodi |
Se hai bisogno di aumentare ulteriormente le dimensioni, contatta il team di vendita Google Cloud per aumentare questo limite.
DNS
La Service Discovery in GKE viene fornita tramite kube-dns, una risorsa centralizzata che fornisce la risoluzione DNS ai pod in esecuzione all'interno del cluster. Ciò può diventare un collo di bottiglia in cluster di grandi dimensioni o per carichi di lavoro con un elevato carico di richieste. GKE scala automaticamente kube-dns in base alle dimensioni del cluster per aumentarne la capacità. Se questa capacità non è ancora sufficiente, GKE offre la risoluzione distribuita e locale delle query DNS su ogni nodo con NodeLocal DNSCache. In questo modo viene fornita una cache DNS locale su ogni nodo GKE che risponde alle query localmente, distribuendo il carico e offrendo tempi di risposta più rapidi.
Gestione degli indirizzi IP nei cluster VPC nativi
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 del pod: il valore predefinito è /14 (262.144 indirizzi IP). Tuttavia, puoi configurare la subnet del pod.
- Intervallo secondario per la subnet di servizio: il valore predefinito è /20 (4096 indirizzi). Tuttavia, non puoi modificare questo intervallo dopo aver creato questa sottorete di servizio.
Per saperne di più, consulta Intervalli di indirizzi IP per i cluster VPC-native.
Limitazioni e consigli per gli indirizzi IP:
- Limite di nodi: il limite di nodi è determinato sia dagli indirizzi IP primari sia da quelli dei pod per nodo. Negli intervalli di indirizzi IP dei nodi e dei pod devono essere presenti indirizzi sufficienti 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.
- Numero massimo di pod per nodo: per impostazione predefinita, il numero massimo di pod per nodo è 110. Tuttavia, puoi configurare CIDR dei pod più piccoli per un utilizzo efficiente con meno pod per nodo.
- Escalabilità oltre RFC 1918: se hai bisogno di più indirizzi IP di quelli disponibili all'interno dello 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 secondario per servizio e pod: per impostazione predefinita, puoi configurare 4096 servizi. Tuttavia, puoi configurare più servizi scegliendo l'intervallo di subnet dei servizi. Non puoi modificare gli intervalli secondari dopo la creazione. Quando crei un cluster, assicurati di scegliere intervalli sufficientemente ampi da soddisfare la crescita prevista. Tuttavia, puoi aggiungere altri indirizzi IP per i pod in un secondo momento utilizzando CIDR multi-pod non contiguo. Per saperne di più, vedi Spazio indirizzi IP libero insufficiente per i pod.
Per ulteriori informazioni, consulta gli intervalli di limitazione dei nodi e Pianifica 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 di questi parametri, ad esempio il numero di core o le dimensioni del disco, possono influire sul rendimento dei cluster GKE.
Riduzione dei tempi di inizializzazione del pod
Puoi utilizzare Image streaming per eseguire lo streaming di dati dalle immagini container idonee man mano che i tuoi carichi di lavoro li richiedono, il che porta a tempi di inizializzazione più rapidi.
Traffico in uscita
In Google Cloud, il tipo di macchina e il numero di core allocati all'istanza determinano la sua capacità di rete. La larghezza di banda in uscita massima varia da 1 a 32 Gbps, mentre la larghezza di banda in uscita massima per le macchine e2-medium-2 predefinite è di 2 Gbps. Per informazioni dettagliate sui limiti di larghezza di banda, consulta Tipi di macchine con core in comune.
IOPS e velocità effettiva del disco
In Google Cloud, le dimensioni dei dischi permanenti determinano le IOPS e la velocità effettiva del disco. In genere, GKE utilizza i dischi permanenti come dischi di avvio e per eseguire il backup dei volumi permanenti di Kubernetes. L'aumento delle dimensioni del disco aumenta sia le IOPS sia la velocità effettiva, fino a determinati limiti.
Ogni operazione di scrittura sul disco permanente contribuisce al limite di uscita della rete cumulativo dell'istanza della macchina virtuale. Pertanto, le prestazioni IOPS dei dischi, in particolare delle unità SSD, dipendono anche dal numero di vCPU nell'istanza, oltre che dalle dimensioni del disco. Le VM con meno core hanno limiti di IOPS di scrittura inferiori a causa dei limiti di traffico in uscita della rete sulla velocità effettiva di scrittura.
Se l'istanza della macchina virtuale non dispone di CPU sufficienti, l'applicazione non potrà avvicinarsi al limite di IOPS. Come regola generale, devi avere una CPU disponibile per ogni 2000-2500 IOPS di trafico previsto.
I carichi di lavoro che richiedono una grande capacità o un numero elevato di dischi devono tenere conto dei limiti del numero di PD che possono essere collegati a una singola VM. Per le VM normali, il limite è di 128 dischi con una dimensione complessiva di 64 TB, mentre le VM con core condivisi hanno un limite di 16 DP con una dimensione complessiva 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 monitorare l'integrità del cluster, i risultati delle modifiche alla configurazione del cluster (ad esempio il deployment di carichi di lavoro aggiuntivi o componenti di terze parti) o per risolvere i problemi.
Una delle metriche più importanti da monitorare è la latenza dell'API Kubernetes. Quando la latenza aumenta, significa che il sistema è sovraccaricato. 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 causato anche dalla lenta risposta dei webhook di ammissione di terze parti. Puoi utilizzare le metriche per misurare la latenza dei webhook al fine di rilevare questi problemi comuni.
Best practice per gli sviluppatori Kubernetes
Utilizza il modello di elenco e visualizzazione anziché la scheda periodica
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 ogni 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, si tratta di un approccio inefficiente e costoso sia per il chiamante che per il server perché tutti gli oggetti devono essere caricati nella memoria, serializzati e trasferiti ogni volta. L'uso eccessivo delle richieste LIST potrebbe sovraccaricare il piano di controllo o generare un'elevata limitazione di queste richieste.
Puoi migliorare il componente impostando il parametro resourceVersion=0 sulle chiamate LIST. In questo modo, kube-apiserver può utilizzare la cache di oggetti in memoria e ridurre il numero di interazioni interne tra kube-apiserver e il database etcd e l'elaborazione correlata.
Ti consigliamo vivamente di evitare le chiamate LIST ripetibili e di sostituirle con il pattern list e watch. Elenca gli oggetti una volta e poi utilizza l'API Watch per ottenere modifiche incrementali dello stato. Questo approccio riduce i tempi di elaborazione e riduce al minimo il traffico rispetto alle chiamate LIST periodiche. Quando 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.
Limitare il traffico non necessario generato da visualizzazioni ed elenchi
Kubernetes utilizza internamente watch per inviare notifiche sugli aggiornamenti degli oggetti. Anche se gli osservatori richiedono molto meno risorse rispetto alle chiamate LIST periodiche, l'elaborazione degli osservatori in cluster di grandi dimensioni può richiedere una parte significativa delle risorse del cluster e influire sul rendimento del cluster. L'impatto negativo maggiore è generato dalla creazione di orologi che osservano oggetti in rapida evoluzione da più luoghi. 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 nel tuo cluster, queste possono creare questi monitor sotto il cofano.
Consigliamo le seguenti best practice:
- Riduci l'elaborazione e il traffico non necessari generati da chiamate LIST e da orologi.
- Evita di creare monitor che osservano oggetti in continua evoluzione da più posizioni (ad esempio i DaemonSet).
- (Molto consigliato) Crea un controller centrale che monitora ed elabora i dati richiesti su un singolo nodo.
- Monitora solo un sottoinsieme di oggetti, ad esempio kubelet su ogni nodo osserva solo i pod pianificati sullo stesso nodo.
- Evita di implementare componenti o estensioni di terze parti che potrebbero influire sul rendimento del cluster generando un volume elevato di visualizzazioni o chiamate LIST.
Utilizza gli aggiornamenti in sequenza con i DaemonSet per evitare aumenti improvvisi del traffico
Quando viene creato un DaemonSet in un cluster, viene pianificato immediatamente un nuovo pod in ogni nodo. Se tutti questi nuovi pod si connettono allo stesso endpoint di rete,
le richieste si verificano contemporaneamente, imponendo un carico elevato sull'host di destinazione.
Per evitare questo problema, configura i DaemonSet con aggiornamenti incrementali con pod maxSurge
limitati.
Limita la dimensione del manifest degli oggetti Kubernetes
Se hai bisogno di operazioni rapide che richiedono una maggiore velocità in termini di throughput dei pod, come la ridimensionamento o l'aggiornamento di carichi di lavoro di grandi dimensioni, assicurati di mantenere ridotte le dimensioni del manifest del pod, idealmente al di sotto di 10 KiB.
Kubernetes memorizza i manifest delle risorse in etcd. L'intero manifest viene inviato ogni volta che la risorsa viene recuperata, ad esempio quando utilizzi l'elenco e il pattern di visualizzazione.
Le dimensioni del file manifest presentano le seguenti limitazioni:
- Dimensione massima per ogni oggetto in etcd: circa 1,5 MB.
- Quota totale per tutti gli oggetti etcd nel cluster: la dimensione della quota preconfigurata è 6 GiB. È incluso un log delle modifiche con tutti gli aggiornamenti a tutti gli oggetti nei 150 secondi più recenti della cronologia del cluster.
- Prestazioni del piano di controllo durante i periodi di traffico elevato: i manifest di dimensioni maggiori aumentano il carico sul server API.
Per oggetti singoli elaborati raramente, le dimensioni del manifest di solito non sono un problema, purché non superino 1,5 MB. Tuttavia, dimensioni dei manifest superiori a 10 KiB per numerosi oggetti elaborati di frequente, come i pod in carichi di lavoro molto grandi, possono causare un aumento della latenza delle chiamate API e una diminuzione delle prestazioni complessive. In particolare, gli elenchi e le visualizzazioni possono essere notevolmente influenzati da dimensioni dei 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 elevato traffico del server API.
Per ridurre le dimensioni del file manifest di un pod, puoi utilizzare i ConfigMap di Kubernetes per memorizzare parte della configurazione, in particolare la parte 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, di grandi dimensioni ed elaborati con la stessa frequenza dei pod. L'estrazione di parte della configurazione è più utile quando diminuisce il traffico complessivo.
Disattivare il montaggio automatico dell'account di servizio predefinito
Se la logica in esecuzione nei pod non deve accedere all'API Kubernetes, devi disattivare il montaggio automatico predefinito dell'account di servizio per evitare la creazione di secret e monitor relativi.
Quando crei un pod senza specificare un account di servizio, Kubernetes svolge automaticamente le seguenti azioni:
- Assegna il account di servizio predefinito al pod.
- Monta le credenziali dell'account di servizio come secret per il pod.
- Per ogni segreto montato, il kubelet crea un'osservazione per monitorare le modifiche apportate al segreto su ogni nodo.
In cluster di grandi dimensioni, queste azioni rappresentano migliaia di monitoraggi non necessari che potrebbero comportare un carico significativo su kube-apiserver.
Utilizzare Protocol Buffers anziché JSON per le richieste API
Utilizza i protocol buffer per implementare componenti altamente scalabili, come descritto in Concetti di base dell'API Kubernetes.
L'API REST di Kubernetes supporta JSON e protocol buffer come formato di serializzazione per gli oggetti. Per impostazione predefinita viene utilizzato JSON, ma i buffer del protocollo sono più efficienti per le prestazioni su larga scala perché richiedono un'elaborazione meno intensiva della CPU e inviano meno dati sulla rete. Il sovraccarico relativo all'elaborazione di JSON può causare timeout durante l'elenco di dati di grandi dimensioni.