Calcolo e scalabilità automatica - Amazon EKS

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Calcolo e scalabilità automatica

In qualità di sviluppatore, farai delle stime sui requisiti di risorse della tua applicazione, ad esempio CPU e memoria, ma se non li aggiusti continuamente potrebbero diventare obsoleti, il che potrebbe aumentare i costi e peggiorare le prestazioni e l'affidabilità. Adeguare continuamente i requisiti di risorse di un'applicazione è più importante che soddisfarli correttamente al primo tentativo.

Le migliori pratiche menzionate di seguito vi aiuteranno a creare e gestire carichi di lavoro attenti ai costi che consentano di raggiungere risultati aziendali riducendo al minimo i costi e consentendo all'organizzazione di massimizzare il ritorno sull'investimento. Un ordine di importanza elevato per l'ottimizzazione dei costi di elaborazione del cluster è:

  1. Carichi di lavoro della giusta dimensione

  2. Riduci la capacità inutilizzata

  3. Ottimizza i tipi di capacità di elaborazione (ad esempio Spot) e gli acceleratori (ad es.) GPUs

Dimensiona correttamente i tuoi carichi di lavoro

Nella maggior parte dei cluster EKS, la maggior parte dei costi proviene dalle EC2 istanze utilizzate per eseguire i carichi di lavoro containerizzati. Non sarete in grado di dimensionare correttamente le risorse di elaborazione senza comprendere i requisiti dei vostri carichi di lavoro. Ecco perché è essenziale utilizzare le richieste e i limiti appropriati e apportare le modifiche necessarie a tali impostazioni. Inoltre, le dipendenze, come la dimensione dell'istanza e la selezione dello storage, possono influire sulle prestazioni del carico di lavoro, il che può avere una serie di conseguenze indesiderate su costi e affidabilità.

Le richieste devono essere in linea con l'utilizzo effettivo. Se le richieste di un container sono troppo elevate, ci sarà una capacità inutilizzata, che è un fattore importante nei costi totali del cluster. Ogni contenitore in un pod, ad esempio l'applicazione e i sidecar, dovrebbe avere le proprie richieste e limiti impostati per garantire che i limiti aggregati dei pod siano il più precisi possibile.

Utilizza strumenti come Goldilocks, KRR e Kubecost che stimano le richieste di risorse e i limiti per i tuoi contenitori. A seconda della natura delle applicazioni, dei requisiti di prestazioni/costi e della complessità, è necessario valutare su quali metriche è meglio scalare, in che punto le prestazioni dell'applicazione peggiorano (punto di saturazione) e come modificare di conseguenza le richieste e i limiti. Per ulteriori informazioni su questo argomento, consulta la sezione Application right sizing.

Ti consigliamo di utilizzare Horizontal Pod Autoscaler (HPA) per controllare quante repliche dell'applicazione devono essere in esecuzione, Vertical Pod Autoscaler (VPA) per regolare il numero di richieste e limiti necessari all'applicazione per replica e un nodo autoscaler come Karpenter o Cluster Autoscaler per regolare continuamente il numero totale di nodi nel cluster. Le tecniche di ottimizzazione dei costi che utilizzano Karpenter e Cluster Autoscaler sono documentate in una sezione successiva di questo documento.

Il Vertical Pod Autoscaler può regolare le richieste e i limiti assegnati ai container in modo che i carichi di lavoro funzionino in modo ottimale. È necessario eseguire il VPA in modalità di controllo in modo che non apporti automaticamente modifiche e non riavvii i pod. Suggerirà modifiche in base alle metriche osservate. In caso di modifiche che influiscono sui carichi di lavoro di produzione, è consigliabile esaminarle e testarle prima in un ambiente non di produzione, poiché possono avere un impatto sull'affidabilità e sulle prestazioni dell'applicazione.

Ridurre i consumi

Il modo migliore per risparmiare è fornire meno risorse. Un modo per farlo è adattare i carichi di lavoro in base ai requisiti attuali. Dovresti iniziare qualsiasi iniziativa di ottimizzazione dei costi assicurandoti che i carichi di lavoro definiscano i requisiti e si scalino dinamicamente. Ciò richiederà l'acquisizione di metriche dalle applicazioni e l'impostazione di configurazioni come Pod Readiness Gates per garantire che l'applicazione possa scalare verso l'alto PodDisruptionBudgetse verso il basso in modo sicuro e dinamico. È importante considerare che un approccio restrittivo PodDisruptionBudgets può impedire a Cluster Autoscaler e Karpenter di ridimensionare i nodi, poiché sia Cluster Autoscaler che Karpenter lo rispettano. PodDisruptionBudgets Il valore 'minAvailable' in PodDisruptionBudget deve essere sempre inferiore al numero di pod nella distribuzione e dovresti mantenere un buon buffer tra i due, ad esempio in una distribuzione di 6 pod in cui desideri che siano sempre attivi almeno 4 pod, imposta 'minAvailable' nel tuo PodDisruptionBidget su 4. Ciò consentirà a Cluster Autoscaler e Karpenter di drenare ed eliminare in sicurezza i pod dai nodi sottoutilizzati durante un evento di scale-down del nodo. Consulta il documento delle domande frequenti su Cluster Autoscaler.

Horizontal Pod Autoscaler è un autoscaler flessibile per carichi di lavoro in grado di regolare il numero di repliche necessarie per soddisfare i requisiti di prestazioni e affidabilità dell'applicazione. Dispone di un modello flessibile per definire quando scalare verso l'alto e verso il basso in base a varie metriche come CPU, memoria o metriche personalizzate, ad esempio profondità della coda, numero di connessioni a un pod, ecc.

Il Kubernetes Metrics Server consente la scalabilità in risposta a metriche integrate come l'utilizzo di CPU e memoria, ma se desideri scalare in base ad altre metriche, come la profondità della coda di Amazon CloudWatch o SQS, dovresti prendere in considerazione progetti di scalabilità automatica basati su eventi come KEDA. Fai riferimento a questo post del blog su come usare KEDA con le metriche. CloudWatch Se non sei sicuro delle metriche da monitorare e su cui basare la scalabilità, consulta le migliori pratiche per monitorare le metriche più importanti.

La riduzione del consumo del carico di lavoro crea un eccesso di capacità in un cluster e, con una corretta configurazione di scalabilità automatica, è possibile ridimensionare automaticamente i nodi e ridurre la spesa totale. Ti consigliamo di non cercare di ottimizzare la capacità di elaborazione manualmente. Lo scheduler Kubernetes e gli autoscaler dei nodi sono stati progettati per gestire questo processo al posto tuo.

Riduci la capacità inutilizzata

Dopo aver determinato la dimensione corretta per le applicazioni, riducendo le richieste in eccesso, è possibile iniziare a ridurre la capacità di elaborazione assegnata. Dovresti essere in grado di eseguire questa operazione in modo dinamico se hai impiegato il tempo necessario per dimensionare correttamente i carichi di lavoro illustrato nelle sezioni precedenti. Esistono due scaler automatici di nodi principali utilizzati con Kubernetes in AWS.

Karpenter e Cluster Autoscaler

Sia Karpenter che Kubernetes Cluster Autoscaler ridimensioneranno il numero di nodi del cluster man mano che i pod vengono creati o rimossi e i requisiti di elaborazione cambiano. L'obiettivo principale di entrambi è lo stesso, ma Karpenter adotta un approccio diverso per la gestione dei nodi, il provisioning e il de-provisioning, che può aiutare a ridurre i costi e ottimizzare l'utilizzo a livello di cluster.

Con l'aumentare delle dimensioni dei cluster e l'aumento della varietà di carichi di lavoro, diventa sempre più difficile preconfigurare gruppi di nodi e istanze. Proprio come per le richieste di carichi di lavoro, è importante impostare una linea di base iniziale e adattarla continuamente in base alle esigenze.

Se si utilizza Cluster Autoscaler, rispetterà i valori «minimo» e «massimo» di ciascun gruppo di Auto Scaling (ASG) e regolerà solo il valore «desiderato». È importante prestare attenzione durante l'impostazione di questi valori per l'ASG sottostante poiché Cluster Autoscaler non sarà in grado di ridimensionare un ASG oltre il numero «minimo». Imposta il conteggio «desiderato» come il numero di nodi necessari durante il normale orario lavorativo e «minimo» come il numero di nodi necessari durante le ore non lavorative. Consulta il documento delle domande frequenti su Cluster Autoscaler.

Cluster Autoscaler Priority Expander

Kubernetes Cluster Autoscaler funziona scalando gruppi di nodi, chiamati gruppi di nodi, verso l'alto e verso il basso man mano che le applicazioni si scalano verso l'alto e verso il basso. Se non stai scalando dinamicamente i carichi di lavoro, Cluster Autoscaler non ti aiuterà a risparmiare denaro. Cluster Autoscaler richiede che un amministratore del cluster crei in anticipo gruppi di nodi per l'utilizzo dei carichi di lavoro. I gruppi di nodi devono essere configurati per utilizzare istanze con lo stesso «profilo», ovvero all'incirca la stessa quantità di CPU e memoria.

È possibile avere più gruppi di nodi e Cluster Autoscaler può essere configurato per impostare livelli di scalabilità prioritari e ogni gruppo di nodi può contenere nodi di dimensioni diverse. I gruppi di nodi possono avere diversi tipi di capacità e l'espansore di priorità può essere utilizzato innanzitutto per scalare gruppi meno costosi.

Di seguito è riportato un esempio di un frammento di configurazione del cluster che utilizza ConfigMap` a per dare priorità alla capacità riservata prima di utilizzare istanze su richiesta. È possibile utilizzare la stessa tecnica per dare priorità alle istanze Graviton o Spot rispetto ad altri tipi.

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: my-cluster managedNodeGroups: - name: managed-ondemand minSize: 1 maxSize: 7 instanceType: m5.xlarge - name: managed-reserved minSize: 2 maxSize: 10 instanceType: c5.2xlarge
apiVersion: v1 kind: ConfigMap metadata: name: cluster-autoscaler-priority-expander namespace: kube-system data: priorities: |- 10: - .*ondemand.* 50: - .*reserved.*

L'uso dei gruppi di nodi può aiutare le risorse di elaborazione sottostanti a eseguire le operazioni previste per impostazione predefinita, ad esempio distribuendo i nodi tra i vari carichi di lavoro AZs, ma non tutti i carichi di lavoro hanno gli stessi requisiti o aspettative ed è meglio lasciare che le applicazioni dichiarino i propri requisiti in modo esplicito. Per ulteriori informazioni su Cluster Autoscaler, consulta la sezione sulle migliori pratiche.

Descheduler

Cluster Autoscaler può aggiungere e rimuovere la capacità dei nodi da un cluster in base alla necessità di pianificare nuovi pod o al sottoutilizzo dei nodi. Non fornisce una visione completa del posizionamento dei pod dopo che sono stati pianificati su un nodo. Se utilizzi Cluster Autoscaler, dovresti anche dare un'occhiata al descheduler Kubernetes per evitare di sprecare capacità nel tuo cluster.

Se hai 10 nodi in un cluster e ogni nodo è utilizzato al 60%, non stai utilizzando il 40% della capacità assegnata nel cluster. Con Cluster Autoscaler è possibile impostare la soglia di utilizzo per nodo al 60%, ma in questo modo si cercherà di ridurre un singolo nodo solo dopo che l'utilizzo è sceso al di sotto del 60%.

Con il descheduler può esaminare la capacità e l'utilizzo del cluster dopo che i pod sono stati pianificati o i nodi sono stati aggiunti al cluster. Tenta di mantenere la capacità totale del cluster al di sopra di una soglia specificata. Può anche rimuovere i pod in base a problemi di nodo o nuovi nodi che si uniscono al cluster per assicurarsi che i pod funzionino nel loro ambiente di calcolo ottimale. Nota che, descheduler non pianifica la sostituzione dei pod eliminati, ma a tale scopo si affida allo scheduler predefinito.

Consolidamento Karpenter

Karpenter adotta un approccio «senza gruppi» alla gestione dei nodi. Questo approccio è più flessibile per diversi tipi di carico di lavoro e richiede meno configurazioni iniziali per gli amministratori del cluster. Invece di predefinire i gruppi e scalare ogni gruppo in base alle esigenze dei carichi di lavoro, Karpenter utilizza i provisioner e i modelli di nodi per definire in generale il tipo di EC2 istanze che possono essere create e le impostazioni relative alle istanze man mano che vengono create.

Il bin packing è la pratica di utilizzare una maggiore quantità di risorse dell'istanza impacchettando più carichi di lavoro su un numero inferiore di istanze di dimensioni ottimali. Sebbene ciò contribuisca a ridurre i costi di elaborazione fornendo solo le risorse utilizzate dai carichi di lavoro, presenta un compromesso. L'avvio di nuovi carichi di lavoro può richiedere più tempo perché è necessario aggiungere capacità al cluster, specialmente durante eventi di scalabilità su larga scala. Considerate l'equilibrio tra ottimizzazione dei costi, prestazioni e disponibilità quando impostate l'imballaggio dei contenitori.

Karpenter può monitorare e comprimere continuamente per migliorare l'utilizzo delle risorse delle istanze e ridurre i costi di elaborazione. Karpenter può anche selezionare un nodo di lavoro più efficiente in termini di costi per il tuo carico di lavoro. Ciò può essere ottenuto attivando il flag «consolidation» su true nel provisioner (frammento di codice di esempio riportato di seguito). L'esempio seguente mostra un provider di esempio che consente il consolidamento. Al momento della stesura di questa guida, Karpenter non sostituirà un'istanza Spot in esecuzione con un'istanza Spot più economica. Per ulteriori dettagli sul consolidamento di Karpenter, consulta questo blog.

apiVersion: karpenter.sh/v1 kind: Provisioner metadata: name: enable-binpacking spec: consolidation: enabled: true

Per carichi di lavoro che potrebbero non essere interrompibili, ad esempio lavori in batch di lunga durata senza checkpoint, prendi in considerazione l'idea di annotare i pod con l'annotazione. do-not-evict Disattivando lo sfratto dai pod, stai dicendo a Karpenter che non deve rimuovere volontariamente i nodi che contengono questo pod. Tuttavia, se un do-not-evict pod viene aggiunto a un nodo mentre il nodo si sta esaurendo, i pod rimanenti verranno comunque espulsi, ma quel pod bloccherà la terminazione finché non viene rimosso. In entrambi i casi, il nodo verrà isolato per evitare che vengano pianificati lavori aggiuntivi sul nodo. Di seguito è riportato un esempio che mostra come impostare l'annotazione:

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "karpenter.sh/do-not-evict": "true" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80

Rimuovi i nodi sottoutilizzati regolando i parametri di Cluster Autoscaler

L'utilizzo dei nodi è definito come la somma delle risorse richieste divisa per la capacità. Per impostazione predefinita, scale-down-utilization-threshold è impostato al 50%. Questo parametro può essere utilizzato insieme a andscale-down-unneeded-time, che determina per quanto tempo un nodo non deve essere necessario prima che sia idoneo per la riduzione. L'impostazione predefinita è 10 minuti. I pod ancora in esecuzione su un nodo ridimensionato verranno programmati su altri nodi da kube-scheduler. La modifica di queste impostazioni può aiutare a rimuovere i nodi sottoutilizzati, ma è importante testare prima questi valori in modo da non forzare il cluster a ridimensionarsi prematuramente.

È possibile evitare il ridimensionamento assicurandosi che i pod costosi da rimuovere siano protetti da un'etichetta riconosciuta da Cluster Autoscaler. A tale scopo, assicuratevi che i pod costosi da rimuovere abbiano l'annotazione. cluster-autoscaler.kubernetes.io/safe-to-evict=false Di seguito è riportato un esempio di yaml per impostare l'annotazione:

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80