Kubernetes: perché è così importante configurare la gestione delle risorse di sistema?

Di norma, è sempre necessario fornire un pool dedicato di risorse a un'applicazione per il suo funzionamento corretto e stabile. Ma cosa succede se più applicazioni funzionano con la stessa potenza? Come fornire a ciascuno di essi le risorse minime necessarie? Come limitare il consumo di risorse? Come distribuire correttamente il carico tra i nodi? Come garantire il funzionamento del meccanismo di ridimensionamento orizzontale se il carico dell'applicazione aumenta?

Kubernetes: perché è così importante configurare la gestione delle risorse di sistema?

È necessario iniziare con i principali tipi di risorse esistenti nel sistema: questo, ovviamente, è il tempo del processore e la RAM. Nei manifest k8 questi tipi di risorse sono misurati nelle seguenti unità:

  • CPU: in core
  • RAM - in byte

Inoltre per ciascuna risorsa è possibile impostare due tipologie di requisiti: richieste и limiti. Richieste: descrive i requisiti minimi per le risorse gratuite di un nodo per eseguire un contenitore (e il pod nel suo insieme), mentre i limiti impostano un limite rigido alle risorse disponibili per il contenitore.

È importante comprendere che il manifest non deve definire esplicitamente entrambi i tipi, ma il comportamento sarà il seguente:

  • Se vengono specificati esplicitamente solo i limiti di una risorsa, le richieste per questa risorsa assumono automaticamente un valore uguale a limiti (puoi verificarlo chiamando le entità description). Quelli. infatti, il contenitore sarà limitato alla stessa quantità di risorse necessarie per essere eseguito.
  • Se per una risorsa vengono specificate esplicitamente solo le richieste, su questa risorsa non vengono impostate restrizioni superiori, ad es. il contenitore è limitato solo dalle risorse del nodo stesso.

È anche possibile configurare la gestione delle risorse non solo a livello di un contenitore specifico, ma anche a livello di namespace utilizzando le seguenti entità:

  • LimitRange — descrive la politica di restrizione a livello di contenitore/pod in ns ed è necessaria per descrivere i limiti predefiniti sul contenitore/pod, nonché impedire la creazione di contenitori/pod ovviamente grassi (o viceversa), limitarne il numero e determinare l'eventuale differenza nei valori dei limiti e delle richieste
  • ResourceQuotas — descrive la politica di restrizione in generale per tutti i contenitori in ns e viene utilizzato, di regola, per delimitare le risorse tra gli ambienti (utile quando gli ambienti non sono strettamente delimitati a livello di nodo)

Di seguito sono riportati esempi di manifest che impostano i limiti delle risorse:

  • A livello di contenitore specifico:

    containers:
    - name: app-nginx
      image: nginx
      resources:
        requests:
          memory: 1Gi
        limits:
          cpu: 200m

    Quelli. in questo caso, per eseguire un container con nginx, avrete bisogno di almeno 1G di RAM libera e 0.2 CPU sul nodo, mentre al massimo il container potrà consumare 0.2 CPU e tutta la RAM disponibile sul nodo.

  • A livello intero ns:

    apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: nxs-test
    spec:
      hard:
        requests.cpu: 300m
        requests.memory: 1Gi
        limits.cpu: 700m
        limits.memory: 2Gi

    Quelli. la somma di tutti i contenitori di richieste nel ns predefinito non può superare 300 m per la CPU e 1 G per l'OP, e la somma di tutti i limiti è 700 m per la CPU e 2 G per l'OP.

  • Limiti predefiniti per i contenitori in ns:

    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: 4Gi

    Quelli. nello spazio dei nomi predefinito per tutti i contenitori, la richiesta sarà impostata su 100 m per CPU e 1G per OP, limite: 1 CPU e 2G. Allo stesso tempo viene fissato anche un limite sui possibili valori in request/limit per CPU (50m < x < 2) e RAM (500M < x < 4G).

  • Restrizioni a livello di pod ns:

    apiVersion: v1
    kind: LimitRange
    metadata:
     name: nxs-limit-pod
    spec:
     limits:
     - type: Pod
       max:
         cpu: 4
         memory: 1Gi

    Quelli. per ogni pod di default ci sarà un limite di 4 vCPU e 1G.

Adesso vorrei raccontarvi quali vantaggi ci può dare l’introduzione di queste restrizioni.

Meccanismo di bilanciamento del carico tra i nodi

Come sai, il componente k8s è responsabile della distribuzione dei pod tra i nodi, come scheduler, che funziona secondo un algoritmo specifico. Questo algoritmo attraversa due fasi durante la selezione del nodo ottimale da avviare:

  1. filtraggio
  2. Variando

Quelli. in base alla policy descritta vengono inizialmente selezionati i nodi sui quali è possibile lanciare un pod in base ad un set predicati (incluso il controllo se il nodo dispone di risorse sufficienti per eseguire il pod - PodFitsResources), quindi per ciascuno di questi nodi, secondo priorità vengono assegnati punti (incluso, più risorse libere ha un nodo, più punti gli vengono assegnati - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) e il pod viene avviato sul nodo con il maggior numero di punti (se più nodi soddisfano questa condizione contemporaneamente, allora ne viene selezionato uno casuale).

Allo stesso tempo, è necessario comprendere che lo scheduler, nel valutare le risorse disponibili di un nodo, è guidato dai dati memorizzati in etcd, ad es. per la quantità di risorse richieste/limitate di ciascun pod in esecuzione su questo nodo, ma non per il consumo effettivo delle risorse. Queste informazioni possono essere ottenute 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 vediamo tutti i pod in esecuzione su un nodo specifico, nonché le risorse richieste da ciascun pod. Ed ecco come appaiono i log dello scheduler quando viene avviato il pod cronjob-cron-events-1573793820-xt6q9 (queste informazioni verranno visualizzate nel log dello scheduler quando imposti il ​​10° livello di registrazione negli argomenti del comando di avvio -v=10):

ampio gabbiano

I1115 07:57:21.637791       1 scheduling_queue.go:908] About to try and schedule pod nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                           
I1115 07:57:21.637804       1 scheduler.go:453] Attempting to schedule pod: nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                                    
I1115 07:57:21.638285       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s5 is allowed, Node is running only 16 out of 110 Pods.                                                                               
I1115 07:57:21.638300       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s6 is allowed, Node is running only 20 out of 110 Pods.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s3 is allowed, Node is running only 20 out of 110 Pods.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s4 is allowed, Node is running only 17 out of 110 Pods.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, Node is running only 16 out of 110 Pods.                                                                              
I1115 07:57:21.638365       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s12 is allowed, Node is running only 9 out of 110 Pods.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s11 is allowed, Node is running only 11 out of 110 Pods.                                                                              
I1115 07:57:21.638385       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s1 is allowed, Node is running only 19 out of 110 Pods.                                                                               
I1115 07:57:21.638402       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s2 is allowed, Node is running only 21 out of 110 Pods.                                                                               
I1115 07:57:21.638383       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, Node is running only 16 out of 110 Pods.                                                                               
I1115 07:57:21.638335       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, Node is running only 18 out of 110 Pods.                                                                               
I1115 07:57:21.638408       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s13 is allowed, Node is running only 8 out of 110 Pods.                                                                               
I1115 07:57:21.638478       1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, existing pods anti-affinity terms satisfied.                                                                         
I1115 07:57:21.638505       1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, existing pods anti-affinity terms satisfied.                                                                          
I1115 07:57:21.638577       1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, existing pods anti-affinity terms satisfied.                                                                          
I1115 07:57:21.638583       1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s7 is allowed, Node is running only 25 out of 110 Pods.                                                                               
I1115 07:57:21.638932       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 9        
I1115 07:57:21.638946       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 8           
I1115 07:57:21.638961       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: BalancedResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 9        
I1115 07:57:21.638971       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7        
I1115 07:57:21.638975       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: LeastResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 8           
I1115 07:57:21.638990       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7           
I1115 07:57:21.639022       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: TaintTolerationPriority, Score: (10)                                                                                                        
I1115 07:57:21.639030       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: TaintTolerationPriority, Score: (10)                                                                                                         
I1115 07:57:21.639034       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: TaintTolerationPriority, Score: (10)                                                                                                         
I1115 07:57:21.639041       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: NodeAffinityPriority, Score: (0)                                                                                                            
I1115 07:57:21.639053       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: NodeAffinityPriority, Score: (0)                                                                                                             
I1115 07:57:21.639059       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: NodeAffinityPriority, Score: (0)                                                                                                             
I1115 07:57:21.639061       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: InterPodAffinityPriority, Score: (0)                                                                                                                   
I1115 07:57:21.639063       1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)                                                                                                                   
I1115 07:57:21.639073       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: InterPodAffinityPriority, Score: (0)                                                                                                                    
I1115 07:57:21.639077       1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)                                                                                                                    
I1115 07:57:21.639085       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: InterPodAffinityPriority, Score: (0)                                                                                                                    
I1115 07:57:21.639088       1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)                                                                                                                    
I1115 07:57:21.639103       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)                                                                                                         
I1115 07:57:21.639109       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)                                                                                                          
I1115 07:57:21.639114       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)                                                                                                          
I1115 07:57:21.639127       1 generic_scheduler.go:781] Host nxs-k8s-s10 => Score 100037                                                                                                                                                                            
I1115 07:57:21.639150       1 generic_scheduler.go:781] Host nxs-k8s-s8 => Score 100034                                                                                                                                                                             
I1115 07:57:21.639154       1 generic_scheduler.go:781] Host nxs-k8s-s9 => Score 100037                                                                                                                                                                             
I1115 07:57:21.639267       1 scheduler_binder.go:269] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10"                                                                                                               
I1115 07:57:21.639286       1 scheduler_binder.go:279] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10": all PVCs bound and nothing to do                                                                             
I1115 07:57:21.639333       1 factory.go:733] Attempting to bind cronjob-cron-events-1573793820-xt6q9 to nxs-k8s-s10

Qui vediamo che inizialmente lo scheduler filtra e genera una lista di 3 nodi su cui può essere lanciato (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Quindi 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 pod viene programmato sul nodo con il maggior numero di punti (qui due nodi contemporaneamente hanno lo stesso numero di punti 100037, quindi ne viene selezionato uno casuale - nxs-k8s-s10).

conclusione: se un nodo esegue pod per i quali non sono impostate restrizioni, allora per k8 (dal punto di vista del consumo di risorse) ciò sarà equivalente a come se non ci fossero affatto pod di questo tipo su questo nodo. Pertanto, se, condizionatamente, hai un pod con un processo goloso (ad esempio wowza) e non sono impostate restrizioni per esso, potrebbe verificarsi una situazione in cui questo pod ha effettivamente mangiato tutte le risorse del nodo, ma per k8 questo nodo è considerato scarico e gli verrà assegnato lo stesso numero di punti quando si classificherà (precisamente in punti che valutano le risorse disponibili) come un nodo che non dispone di pod funzionanti, il che alla fine può portare a una distribuzione non uniforme del carico tra i nodi.

Lo sfratto di Pod

Come sai, a ogni pod viene assegnata una delle 3 classi QoS:

  1. garantito — viene assegnato quando per ciascun contenitore nel pod vengono specificati una richiesta e un limite per memoria e CPU e questi valori devono corrispondere
  2. scoppiabile — almeno un contenitore nel pod ha una richiesta e un limite, con richiesta < limite
  3. miglior sforzo — quando nessun contenitore nel pod ha risorse limitate

Allo stesso tempo, quando un nodo sperimenta una mancanza di risorse (disco, memoria), kubelet inizia a classificare ed eliminare i pod secondo un algoritmo specifico che tiene conto della priorità del pod e della sua classe QoS. Ad esempio, se stiamo parlando di RAM, in base alla classe QoS, i punti vengono assegnati secondo il seguente principio:

  • Garantito:-998
  • Miglior sforzo: 1000
  • Esplosiva: min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

Quelli. con la stessa priorità, il kubelet eliminerà prima i pod con la classe QoS con il miglior sforzo dal nodo.

conclusione: se vuoi ridurre la probabilità che il pod desiderato venga sfrattato dal nodo in caso di mancanza di risorse su di esso, oltre alla priorità devi occuparti anche di impostare la richiesta/limite per esso.

Meccanismo per la scalabilità automatica orizzontale dei pod dell'applicazione (HPA)

Quando il compito è aumentare e diminuire automaticamente il numero di pod in base all'uso delle risorse (sistema - CPU/RAM o utente - rps), un'entità k8s come HPA (Scalatore automatico pod orizzontale). Il cui algoritmo è il seguente:

  1. Vengono determinate le letture correnti della risorsa osservata (currentMetricValue)
  2. Vengono determinati i valori desiderati per la risorsa (desiredMetricValue), che per le risorse di sistema vengono impostati utilizzando request
  3. Viene determinato il numero corrente di repliche (currentReplicas)
  4. La seguente formula calcola il numero desiderato di repliche (desiredReplicas)
    Repliche desiderate = [Replichecorrenti * (ValoreMetricoCorrente / ValoreMetricoDesiderato)]

In questo caso, il ridimensionamento non avverrà quando il coefficiente (currentMetricValue / wantedMetricValue) è vicino a 1 (in questo caso possiamo impostare noi stessi l'errore consentito; per impostazione predefinita è 0.1).

Diamo un'occhiata a come funziona hpa utilizzando l'esempio dell'applicazione app-test (descritta come Deployment), dove è necessario modificare il numero di repliche a seconda del consumo 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-status

    Quelli. vediamo che il pod dell'applicazione viene inizialmente avviato in due istanze, ciascuna delle quali contiene due contenitori nginx e nginx-exporter, per ognuno dei quali uno specifico richieste per CPU.

  • Manifesto dell’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: 30

    Quelli. Abbiamo creato un hpa che monitorerà il test dell'app di distribuzione e regolerà il numero di pod con l'applicazione in base all'indicatore della CPU (prevediamo che il pod dovrebbe consumare il 30% della CPU richiesta), con il numero di repliche in l'intervallo di 2-10.

    Consideriamo ora il meccanismo di funzionamento dell'hpa se applichiamo un carico a uno dei focolari:

     # kubectl top pod
    NAME                                                   CPU(cores)   MEMORY(bytes)
    app-test-78559f8f44-pgs58            101m         243Mi
    app-test-78559f8f44-cj4jz            4m           240Mi

In totale abbiamo quanto segue:

  • Il valore desiderato (desiredMetricValue): in base alle impostazioni hpa, abbiamo il 30%
  • Valore corrente (currentMetricValue) - per il calcolo, il controller-manager calcola il valore medio del consumo di risorse in %, ovvero condizionatamente fa quanto segue:
    1. Riceve valori assoluti delle metriche pod dal server metrico, ad es. 101 metri e 4 metri
    2. Calcola il valore medio assoluto, ovvero (101m + 4m) / 2 = 53m
    3. Ottiene il valore assoluto per il consumo di risorse desiderato (per questo vengono sommate le richieste di tutti i container) 60 m + 30 m = 90 m
    4. Calcola la percentuale media del consumo di CPU relativa al pod di richiesta, ovvero 53 m / 90 m * 100% = 59%

Ora abbiamo tutto quello che ci serve per stabilire se è necessario modificare il numero di repliche; per fare questo calcoliamo il coefficiente:

ratio = 59% / 30% = 1.96

Quelli. il numero di repliche dovrebbe essere aumentato di ~2 volte e ammontare a [2 * 1.96] = 4.

Conclusione: Come puoi vedere, affinché questo meccanismo funzioni, una condizione necessaria è la presenza di richieste per tutti i contenitori presenti nel pod osservato.

Meccanismo per l'autoscaling orizzontale dei nodi (Cluster Autoscaler)

Per neutralizzare l'impatto negativo sul sistema durante i picchi di carico, non è sufficiente avere un hpa configurato. Ad esempio, in base alle impostazioni nel gestore del controller hpa, decide che il numero di repliche deve essere aumentato di 2 volte, ma i nodi non hanno risorse libere per eseguire un tale numero di pod (ovvero il nodo non può fornire il risorse richieste al pod delle richieste) e questi pod passeranno allo stato In sospeso.

In questo caso, se il provider dispone di un IaaS/PaaS corrispondente (ad esempio, GKE/GCE, AKS, EKS, ecc.), uno strumento come Scalabilità automatica dei nodi. Ti consente di impostare il numero massimo e minimo di nodi nel cluster e di regolare automaticamente il numero corrente di nodi (chiamando l'API del fornitore di servizi cloud per ordinare/rimuovere un nodo) quando mancano risorse nel cluster e nei pod non possono essere pianificati (sono nello stato In sospeso).

Conclusione: Per poter scalare automaticamente i nodi, è necessario impostare le richieste nei contenitori dei pod in modo che i k8 possano valutare correttamente il carico sui nodi e di conseguenza segnalare che non ci sono risorse nel cluster per avviare il pod successivo.

conclusione

Va notato che l'impostazione dei limiti delle risorse del contenitore non è un requisito per il corretto funzionamento dell'applicazione, ma è comunque meglio farlo per i seguenti motivi:

  1. Per un funzionamento più accurato dello scheduler in termini di bilanciamento del carico tra i nodi k8s
  2. Per ridurre la probabilità che si verifichi un evento di “sfratto del pod”.
  3. Affinché la scalabilità automatica orizzontale dei pod dell'applicazione (HPA) funzioni
  4. Per la scalabilità automatica orizzontale dei nodi (Cluster Autoscaling) per i fornitori di servizi cloud

Leggi anche altri articoli sul nostro blog:

Fonte: habr.com

Aggiungi un commento