In genere, c'è sempre la necessità di garantire un pool dedicato di risorse a un'applicazione per garantirne il corretto e stabile funzionamento. Ma cosa succede se più applicazioni operano sulla stessa infrastruttura? Come garantire a ciascuna di esse le risorse minime necessarie? Come limitare il consumo di risorse? In che modo è possibile distribuire il carico tra i nodi? Come garantire il funzionamento del meccanismo di scalabilità orizzontale in caso di aumento del carico sulle applicazioni?

Dobbiamo iniziare identificando i principali tipi di risorse esistenti nel sistema: ovviamente, il tempo di CPU e la memoria RAM. Nelle manifestazioni di k8s, questi tipi di risorse sono misurati nelle seguenti unità:
- CPU — in core
- RAM — in byte
Per ciascuna risorsa, è possibile specificare due tipi di requisiti — requests e limits. Requests — descrive i requisiti minimi delle risorse libere del nodo per avviare un contenitore (e il pod in generale), mentre limits stabilisce un limite rigido sulle risorse disponibili per il contenitore.
È importante capire che nel manifesto non è necessario definire esplicitamente entrambi i tipi; in tal caso, il comportamento sarà il seguente:
- Se viene specificato solo il limite delle risorse, le richieste per quella risorsa assumono automaticamente un valore pari al limite (è possibile verificarlo richiamando la descrizione dell'entità). Quindi, in pratica, il funzionamento del contenitore sarà limitato alla stessa quantità di risorse necessaria per il suo avvio.
- Se per la risorsa è stata specificata solo la richiesta, non ci sono limiti superiori su tale risorsa; quindi, il contenitore è limitato solo dalle risorse del nodo stesso.
Esiste anche la possibilità di configurare la gestione delle risorse non solo a livello di singolo contenitore, ma anche a livello di namespace utilizzando le seguenti entità:
- LimitRange — descrive la politica di limitazione a livello di contenitore/pod nel ns e serve a definire i limiti predefiniti per il contenitore/pod, oltre a prevenire la creazione di contenitori/pod eccessivamente grandi (o viceversa), limitare il loro numero e definire possibili differenze di valori tra limiti e richieste.
- ResourceQuotas — descrivono la politica di limitazione in generale per tutti i contenitori all'interno di un namespace e viene utilizzata, di norma, per delimitare le risorse tra gli ambienti (utile quando gli ambienti non sono rigidamente separati a livello di nodi)
Di seguito sono riportati esempi di manifesti che definiscono le limitazioni delle risorse:
A livello di un singolo contenitore:
containers: - name: app-nginx image: nginx resources: requests: memory: 1Gi limits: cpu: 200mCioè, in questo caso per avviare un contenitore con nginx saranno necessarie almeno 1G di RAM libera e 0.2 CPU nel nodo, mentre il massimo che il contenitore può utilizzare è 0.2 CPU e tutta la RAM disponibile nel nodo.
A livello di un intero namespace:
apiVersion: v1 kind: ResourceQuota metadata: name: nxs-test spec: hard: requests.cpu: 300m requests.memory: 1Gi limits.cpu: 700m limits.memory: 2GiCioè, la somma di tutte le richieste dei contenitori nel namespace predefinito non può superare 300m per la CPU e 1G per la RAM, mentre la somma di tutti i limiti deve essere di 700m per la CPU e 2G per la RAM.
Limitazioni predefinite per i contenitori nel namespace:
apiVersion: v1 kind: LimitRange metadata: name: nxs-limit-per-container spec: limits: - type: Container defaultRequest: cpu: 100m memory: 1Gi default: cpu: 1 memory: 2Gi min: cpu: 50m memory: 500Mi max: cpu: 2 memory: 4GiCioè, nel namespace predefinito per tutti i container, verrà impostato un request di 100m per CPU e 1G per RAM, con un limit di 1 CPU e 2G. Inoltre, è stato impostato un limite sui valori possibili per request/limit di CPU (50m < x < 2) e RAM (500M < x < 4G).
Limitazioni a livello di pod ns:
apiVersion: v1 kind: LimitRange metadata: name: nxs-limit-pod spec: limits: - type: Pod max: cpu: 4 memory: 1GiCioè, per ogni pod nel ns predefinito, sarà imposto un limite di 4 vCPU e 1G.
Ora vorrei discutere quali vantaggi può darci l'impostazione di queste limitazioni.
Meccanismo di bilanciamento del carico tra i nodi
Come è noto, la distribuzione dei pod tra i nodi è gestita da un componente k8s chiamato scheduler, che funziona secondo un algoritmo specifico. Questo algoritmo passa attraverso due fasi nella scelta del nodo ottimale per l'avvio:
- Filtraggio
- Classificazione
Cioè, secondo la politica descritta, inizialmente vengono selezionati i nodi sui quali è possibile avviare il pod in base a un insieme di predicates (tra cui viene controllato se il nodo dispone di risorse sufficienti per l'avvio del pod — PodFitsResources), e poi, per ciascuno di questi nodi, in base a priorities vengono assegnati punti (incluso che più risorse libere ha il nodo, più punti gli vengono assegnati - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) e si avvia sul nodo con il maggior numero di punti (se questo criterio è soddisfatto da più nodi, ne viene scelto uno a caso).
Inoltre, è importante capire che lo scheduler, quando valuta le risorse disponibili del nodo, si basa sui dati memorizzati in etcd - ossia sulla somma delle richieste/limiti delle risorse di ciascun pod avviato su quel nodo, ma non sul consumo effettivo delle risorse. Questa informazione può essere ottenuta dall'output del comando kubectl describe node $NODE, ad esempio:
# kubectl describe nodes nxs-k8s-s1
..
Non-terminated Pods: (9 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
ingress-nginx nginx-ingress-controller-754b85bf44-qkt2t 0 (0%) 0 (0%) 0 (0%) 0 (0%) 233d
kube-system kube-flannel-26bl4 150m (0%) 300m (1%) 64M (0%) 500M (1%) 233d
kube-system kube-proxy-exporter-cb629 0 (0%) 0 (0%) 0 (0%) 0 (0%) 233d
kube-system kube-proxy-x9fsc 0 (0%) 0 (0%) 0 (0%) 0 (0%) 233d
kube-system nginx-proxy-k8s-worker-s1 25m (0%) 300m (1%) 32M (0%) 512M (1%) 233d
nxs-monitoring alertmanager-main-1 100m (0%) 100m (0%) 425Mi (1%) 25Mi (0%) 233d
nxs-logging filebeat-lmsmp 100m (0%) 0 (0%) 100Mi (0%) 200Mi (0%) 233d
nxs-monitoring node-exporter-v4gdq 112m (0%) 122m (0%) 200Mi (0%) 220Mi (0%) 233d
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 487m (3%) 822m (5%)
memory 15856217600 (2%) 749976320 (3%)
ephemeral-storage 0 (0%) 0 (0%)Qui possiamo vedere tutti i pod avviati su un nodo specifico e le risorse richieste da ciascun pod. Ecco come appaiono i log dello scheduler quando si avvia il pod cronjob-cron-events-1573793820-xt6q9 (questa informazione apparirà nei log dello scheduler impostando il livello di logging a 10 nei parametri della riga di comando di avvio -v=10):
log
I1115 07:57:21.637791 1 scheduling_queue.go:908] Inizio tentativo di pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.637804 1 scheduler.go:453] Tentativo di pianificare il pod: nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.638285 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s5 è consentito, il nodo sta eseguendo solo 16 pod su 110.
I1115 07:57:21.638300 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s6 è consentito, il nodo sta eseguendo solo 20 pod su 110.
I1115 07:57:21.638322 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s3 è consentito, il nodo sta eseguendo solo 20 pod su 110.
I1115 07:57:21.638322 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s4 è consentito, il nodo sta eseguendo solo 17 pod su 110.
I1115 07:57:21.638334 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s10 è consentito, il nodo sta eseguendo solo 16 pod su 110.
I1115 07:57:21.638365 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s12 è consentito, il nodo sta eseguendo solo 9 pod su 110.
I1115 07:57:21.638334 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s11 è consentito, il nodo sta eseguendo solo 11 pod su 110.
I1115 07:57:21.638385 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s1 è consentito, il nodo sta eseguendo solo 19 pod su 110.
I1115 07:57:21.638402 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s2 è consentito, il nodo sta eseguendo solo 21 pod su 110.
I1115 07:57:21.638383 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s9 è consentito, il nodo sta eseguendo solo 16 pod su 110.
I1115 07:57:21.638335 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s8 è consentito, il nodo sta eseguendo solo 18 pod su 110.
I1115 07:57:21.638408 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s13 è consentito, il nodo sta eseguendo solo 8 pod su 110.
I1115 07:57:21.638478 1 predicates.go:1369] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s10 è consentito, i termini di anti-affinità dei pod esistenti sono soddisfatti.
I1115 07:57:21.638505 1 predicates.go:1369] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s8 è consentito, i termini di anti-affinità dei pod esistenti sono soddisfatti.
I1115 07:57:21.638577 1 predicates.go:1369] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s9 è consentito, i termini di anti-affinità dei pod esistenti sono soddisfatti.
I1115 07:57:21.638583 1 predicates.go:829] Pianificare il pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 sul nodo nxs-k8s-s7 è consentito, il nodo sta eseguendo solo 25 pod su 110.
I1115 07:57:21.638932 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Allocazione delle risorse bilanciata, capacità 39900 millicore 66620178432 byte di memoria, richiesta totale 2343 millicore 9640186880 byte di memoria, punteggio 9
I1115 07:57:21.638946 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Allocazione delle risorse minime, capacità 39900 millicore 66620178432 byte di memoria, richiesta totale 2343 millicore 9640186880 byte di memoria, punteggio 8
I1115 07:57:21.638961 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Allocazione delle risorse bilanciate, capacità 39900 millicore 66620170240 byte di memoria, richiesta totale 4107 millicore 11307422720 byte di memoria, punteggio 9
I1115 07:57:21.638971 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Allocazione delle risorse bilanciate, capacità 39900 millicore 66620178432 byte di memoria, richiesta totale 5847 millicore 24333637120 byte di memoria, punteggio 7
I1115 07:57:21.638975 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Allocazione delle risorse minime, capacità 39900 millicore 66620170240 byte di memoria, richiesta totale 4107 millicore 11307422720 byte di memoria, punteggio 8
I1115 07:57:21.638990 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Allocazione delle risorse minime, capacità 39900 millicore 66620178432 byte di memoria, richiesta totale 5847 millicore 24333637120 byte di memoria, punteggio 7
I1115 07:57:21.639022 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: Priorità di tolleranza a taint, punteggio: (10)
I1115 07:57:21.639030 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: Priorità di tolleranza a taint, punteggio: (10)
I1115 07:57:21.639034 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: Priorità di tolleranza a taint, punteggio: (10)
I1115 07:57:21.639041 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: Priorità di affinità del nodo, punteggio: (0)
I1115 07:57:21.639053 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: Priorità di affinità del nodo, punteggio: (0)
I1115 07:57:21.639059 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: Priorità di affinità del nodo, punteggio: (0)
I1115 07:57:21.639061 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Priorità di affinità inter-pod, punteggio: (0)
I1115 07:57:21.639063 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Priorità di distribuzione selettiva, punteggio: (10)
I1115 07:57:21.639073 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Priorità di affinità inter-pod, punteggio: (0)
I1115 07:57:21.639077 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Priorità di distribuzione selettiva, punteggio: (10)
I1115 07:57:21.639085 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Priorità di affinità inter-pod, punteggio: (0)
I1115 07:57:21.639088 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Priorità di distribuzione selettiva, punteggio: (10)
I1115 07:57:21.639103 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: Priorità di distribuzione selettiva, punteggio: (10)
I1115 07:57:21.639109 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: Priorità di distribuzione selettiva, punteggio: (10)
I1115 07:57:21.639114 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: Priorità di distribuzione selettiva, punteggio: (10)
I1115 07:57:21.639127 1 generic_scheduler.go:781] Host nxs-k8s-s10 -> Punteggio 100037
I1115 07:57:21.639150 1 generic_scheduler.go:781] Host nxs-k8s-s8 -> Punteggio 100034
I1115 07:57:21.639154 1 generic_scheduler.go:781] Host nxs-k8s-s9 -> Punteggio 100037
I1115 07:57:21.639267 1 scheduler_binder.go:269] Supponiamo i volumi del pod per il pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", nodo "nxs-k8s-s10"
I1115 07:57:21.639286 1 scheduler_binder.go:279] Supponiamo i volumi del pod per il pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", nodo "nxs-k8s-s10": tutti i PVC sono legati e non c'è niente da fareQui vediamo che inizialmente lo scheduler filtra e crea un elenco di 3 nodi su cui è possibile avviare (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Successivamente, calcola i punteggi in base a diversi parametri (tra cui BalancedResourceAllocation, LeastResourceAllocation) per ciascuno di questi nodi al fine di determinare il nodo più adatto. Alla fine, il piano viene eseguito sul nodo con il punteggio più alto (qui due nodi hanno entrambi un punteggio di 100037, quindi ne viene scelto uno a caso — nxs-k8s-s10).
Risultato: se i pod sono in esecuzione su un nodo per i quali non sono stati definiti limiti, per k8s (in termini di consumo di risorse) questo sarà equivalente a non avere affatto tali pod su questo nodo. Pertanto, se, ad esempio, hai un pod con un processo che consuma molte risorse (ad esempio, wowza) e per esso non sono stati definiti limiti, può insorgere una situazione in cui effettivamente questo pod ha consumato tutte le risorse del nodo, ma per k8s questo nodo risulta non sovraccarico e gli verranno attribuiti gli stessi punti nella classifica (proprio nei punteggi relativi alla valutazione delle risorse disponibili) di un nodo senza pod attivi, il che alla fine può portare a una distribuzione non uniforme del carico tra i nodi.
Espulsione del pod
Come noto, a ogni pod viene assegnata una delle 3 classi di QoS:
- garantito — viene assegnato quando per ogni contenitore nel pod sono stati definiti request e limit sia per la memoria che per la CPU, e questi valori devono corrispondere
- burstable — almeno un contenitore nel pod ha request e limit, con request < limit
- best effort — quando nessun contenitore nel pod è limitato in termini di risorse
Quando si verifica una carenza di risorse (disco, memoria) su un nodo, kubelet inizia a classificare ed espellere i pod secondo un algoritmo che tiene conto della priorità del pod e della sua classe QoS. Ad esempio, se si tratta di RAM, i punteggi vengono assegnati in base alla classe QoS secondo il principio seguente:
- Garantito: -998
- Miglior sforzo: 1000
- Variabile: min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
Cioè, a parità di priorità, kubelet espellerà prima i pod con la classe QoS di miglior sforzo.
Risultato: se si desidera ridurre la probabilità di espulsione di un pod importante dal nodo in caso di carenza di risorse, è necessario prestare attenzione anche alla definizione di request/limit per esso, oltre alla priorità.
Meccanismo di scalabilità automatica orizzontale dei pod dell'applicazione (HPA)
Quando si vuole aumentare e diminuire automaticamente il numero di pod in base all'utilizzo delle risorse (sistemiche — CPU/RAM o utente — rps), può aiutare una entità k8s come HPA (Horizontal Pod Autoscaler). Il cui algoritmo è il seguente:
- Si determinano le attuali letture della risorsa osservata (currentMetricValue)
- Vengono definiti i valori desiderati per la risorsa (desiredMetricValue), che per le risorse di sistema sono impostati tramite la richiesta
- Viene definito il numero attuale di repliche (currentReplicas)
- Il numero desiderato di repliche (desiredReplicas) viene calcolato secondo la seguente formula
desiredReplicas = [ currentReplicas * ( currentMetricValue / desiredMetricValue )]
In questo caso, non si verifica alcuna scalabilità quando il coefficiente (currentMetricValue / desiredMetricValue) è vicino a 1 (la tolleranza ammissibile può essere impostata da noi, di default è 0,1).
Consideriamo il funzionamento di hpa con l'esempio dell'applicazione app-test (descritta come Deployment), dove è necessario variare il numero di repliche in base all'utilizzo della CPU:
Manifesto dell'applicazione
kind: Deployment apiVersion: apps/v1beta2 metadata: name: app-test spec: selector: matchLabels: app: app-test replicas: 2 template: metadata: labels: app: app-test spec: containers: - name: nginx image: registry.nixys.ru/generic-images/nginx imagePullPolicy: Always resources: requests: cpu: 60m ports: - name: http containerPort: 80 - name: nginx-exporter image: nginx/nginx-prometheus-exporter resources: requests: cpu: 30m ports: - name: nginx-exporter containerPort: 9113 args: - -nginx.scrape-uri - http://127.0.0.1:80/nginx-statusQuindi vediamo che con l'applicazione si avvia inizialmente in due istanze, ciascuna contenente due contenitori nginx e nginx-exporter, per ciascuno dei quali è stato specificato requests per la CPU.
Manifesto HPA
apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: app-test-hpa spec: maxReplicas: 10 minReplicas: 2 scaleTargetRef: apiVersion: extensions/v1beta1 kind: Deployment name: app-test metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 30Quindi abbiamo creato un HPA che monitorerà il Deployment app-test e regolerà il numero di pod con l'applicazione in base al valore della CPU (ci aspettiamo che il pod consumi il 30% della CPU richiesta), mentre il numero di repliche è compreso tra 2 e 10.
Ora, consideriamo il meccanismo di funzionamento dell'HPA, se si applica un carico a uno dei pod:
# kubectl top pod NAME CPU(cores) MEMORY(bytes) app-test-78559f8f44-pgs58 101m 243Mi app-test-78559f8f44-cj4jz 4m 240Mi
In sintesi abbiamo quanto segue:
- Il valore desiderato (desiredMetricValue) — secondo le impostazioni dell'HPA è pari al 30%
- Il valore attuale (currentMetricValue) — per il calcolo il controller-manager calcola la media del consumo delle risorse in %, cioè fa in sostanza quanto segue:
- Ottiene i valori assoluti delle metriche dei pod dal metric-server, cioè 101m e 4m
- Calcola la media dei valori assoluti, cioè (101m + 4m) / 2 = 53m
- Ottiene il valore assoluto per il consumo di risorse desiderato (sommando i request di tutti i container) 60m + 30m = 90m
- Calcola la percentuale media di utilizzo della CPU rispetto ai request del pod, cioè 53m / 90m * 100% = 59%
Ora abbiamo tutto il necessario per determinare se è necessario modificare il numero di repliche, quindi calcoliamo il rapporto:
rapporto = 59% / 30% = 1.96
Cioè, il numero di repliche deve essere aumentato di circa 2 volte e diventare [2 * 1.96] = 4.
Risultato: Come si può notare, affinché questo meccanismo funzioni, è necessario avere requests per tutti i container nel pod monitorato.
Meccanismo di autoscaling orizzontale dei nodi (Cluster Autoscaler)
Per mitigare l'impatto negativo sul sistema durante i picchi di carico, avere un hpa configurato può non essere sufficiente. Ad esempio, secondo le impostazioni nel controller manager hpa, viene presa la decisione che il numero di repliche deve essere aumentato di 2 volte; tuttavia, sui nodi non ci sono risorse libere per avviare tale numero di pod (cioè, il nodo non può fornire le risorse richieste dal pod requests) e questi pod passano in stato di Pending.
In questo caso, se il provider dispone di un adeguato IaaS/PaaS (ad esempio, GKE/GCE, AKS, EKS, ecc.), uno strumento utile può essere Node Autoscaler. Questo strumento consente di impostare un numero massimo e minimo di nodi nel cluster e regola automaticamente il numero attuale di nodi (effettuando chiamate all'API del provider cloud per aggiungere/rimuovere nodi) quando ci sono carenze di risorse nel cluster e i pod non possono essere programmati (sono in stato di Pending).
Risultato: Per consentire l'autoscaling dei nodi, è necessario definire le richieste nei container dei pod affinché k8s possa valutare correttamente il carico dei nodi e segnalare che non ci sono risorse disponibili nel cluster per l'avvio di un nuovo pod.
Conclusione
Va notato che configurare i limiti delle risorse del container non è un requisito obbligatorio per l'avvio dell'applicazione con successo, tuttavia è comunque consigliato per le seguenti ragioni:
- Per un funzionamento più preciso dello scheduler in merito bilanciamento del carico tra i nodi di k8s
- Per ridurre la probabilità di eventi di ‘eviction dei pod’
- Per il funzionamento dell'autoscaling orizzontale dei pod dell'applicazione (HPA)
- Per il funzionamento dell'autoscaling orizzontale dei nodi (Cluster Autoscaling) nei provider di cloud
Leggi anche altri articoli nel nostro blog:
Fonte: habr.com
