Kubernetes: de ce este atât de important să configurați managementul resurselor sistemului?

De regulă, este întotdeauna necesar să se furnizeze un grup dedicat de resurse unei aplicații pentru funcționarea corectă și stabilă. Dar ce se întâmplă dacă mai multe aplicații rulează la aceeași putere? Cum să asigurăm fiecăruia dintre ei resursele minime necesare? Cum poți limita consumul de resurse? Cum se distribuie corect sarcina între noduri? Cum să vă asigurați că mecanismul de scalare orizontală funcționează dacă sarcina aplicației crește?

Kubernetes: de ce este atât de important să configurați managementul resurselor sistemului?

Trebuie să începeți cu ce tipuri principale de resurse există în sistem - acesta este, desigur, timpul procesorului și RAM. În manifestele k8s, aceste tipuri de resurse sunt măsurate în următoarele unități:

  • CPU - în nuclee
  • RAM - în octeți

Mai mult, pentru fiecare resursă este posibil să se stabilească două tipuri de cerințe - cereri de и Limitele. Cereri - descrie cerințele minime pentru resursele gratuite ale unui nod pentru a rula un container (și un pod în ansamblu), în timp ce limitele stabilește o limită strictă a resurselor disponibile pentru container.

Este important să înțelegeți că manifestul nu trebuie să definească în mod explicit ambele tipuri, dar comportamentul va fi după cum urmează:

  • Dacă doar limitele unei resurse sunt specificate în mod explicit, atunci cererile pentru această resursă iau automat o valoare egală cu limitele (puteți verifica acest lucru apelând entitățile descrie). Acestea. de fapt, containerul va fi limitat la aceeași cantitate de resurse de care are nevoie pentru a rula.
  • Dacă doar cererile sunt specificate în mod explicit pentru o resursă, atunci nu sunt stabilite restricții superioare pentru această resursă - de exemplu. containerul este limitat doar de resursele nodului însuși.

De asemenea, este posibil să configurați gestionarea resurselor nu numai la nivelul unui anumit container, ci și la nivelul spațiului de nume folosind următoarele entități:

  • LimitRange — descrie politica de restricție la nivel de container/pod în ns și este necesară pentru a descrie limitele implicite pentru container/pod, precum și pentru a preveni crearea de containere/pod-uri evident grase (sau invers), pentru a limita numărul acestora și determinați posibila diferență a valorilor în limite și solicitări
  • Cote de resurse — descrie politica de restricție în general pentru toate containerele în ns și este folosită, de regulă, pentru a delimita resursele între medii (utilă atunci când mediile nu sunt strict delimitate la nivel de nod)

Următoarele sunt exemple de manifeste care stabilesc limite de resurse:

  • La nivelul specific al containerului:

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

    Acestea. în acest caz, pentru a rula un container cu nginx, veți avea nevoie de cel puțin 1G de RAM liber și 0.2 CPU pe nod, în timp ce cel mult containerul poate consuma 0.2 CPU și toată RAM disponibilă pe nod.

  • La nivelul întregului ns:

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

    Acestea. suma tuturor containerelor de solicitare din ns implicit nu poate depăși 300m pentru CPU și 1G pentru OP, iar suma tuturor limitelor este de 700m pentru CPU și 2G pentru OP.

  • Limitele implicite pentru containere în 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

    Acestea. în spațiul de nume implicit pentru toate containerele, cererea va fi setată la 100m pentru CPU și 1G pentru OP, limită - 1 CPU și 2G. În același timp, se stabilește și o limită a valorilor posibile în cerere/limită pentru CPU (50m < x < 2) și RAM (500M < x < 4G).

  • Restricții la nivel de pod ns:

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

    Acestea. pentru fiecare pod din ns implicit va exista o limită de 4 vCPU și 1G.

Acum aș vrea să vă spun ce avantaje ne poate oferi stabilirea acestor restricții.

Mecanism de echilibrare a sarcinii între noduri

După cum știți, componenta k8s este responsabilă pentru distribuția podurilor între noduri, cum ar fi Scheduler, care funcționează conform unui algoritm specific. Acest algoritm trece prin două etape atunci când selectează nodul optim pentru lansare:

  1. filtrare
  2. Variind

Acestea. conform politicii descrise, inițial sunt selectate noduri pe care este posibilă lansarea unui pod pe baza unui set predicate (inclusiv verificarea dacă nodul are suficiente resurse pentru a rula podul - PodFitsResources), și apoi pentru fiecare dintre aceste noduri, conform priorități sunt acordate puncte (inclusiv, cu cât un nod are mai multe resurse libere, cu atât i se alocă mai multe puncte - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) și pod-ul este lansat pe nodul cu cele mai multe puncte (dacă mai multe noduri îndeplinesc această condiție deodată, atunci este selectat unul aleatoriu).

În același timp, trebuie să înțelegeți că planificatorul, atunci când evaluează resursele disponibile ale unui nod, este ghidat de datele care sunt stocate în etcd - i.e. pentru cantitatea de resursă solicitată/limită a fiecărui pod care rulează pe acest nod, dar nu pentru consumul real de resurse. Aceste informații pot fi obținute din ieșirea comenzii kubectl describe node $NODE, de exemplu:

# 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%)

Aici vedem toate podurile care rulează pe un anumit nod, precum și resursele pe care fiecare pod le solicită. Și iată cum arată jurnalele de planificare când este lansat pod-ul cronjob-cron-events-1573793820-xt6q9 (aceste informații vor apărea în jurnalul de planificare când este setat al 10-lea nivel de înregistrare în argumentele comenzii de lansare -v=10 ):

Buturuga

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

Aici vedem ca initial planificatorul filtreaza si genereaza o lista de 3 noduri pe care poate fi lansat (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Apoi calculează scorurile pe baza mai multor parametri (inclusiv BalancedResourceAllocation, LeastResourceAllocation) pentru fiecare dintre aceste noduri pentru a determina cel mai potrivit nod. În cele din urmă, pod-ul este programat pe nodul cu cel mai mare număr de puncte (aici două noduri simultan au același număr de puncte 100037, deci este selectat unul aleatoriu - nxs-k8s-s10).

Producție: dacă un nod rulează poduri pentru care nu sunt setate restricții, atunci pentru k8s (din punct de vedere al consumului de resurse) acest lucru va fi echivalent cu ca și cum nu ar exista astfel de poduri pe acest nod. Prin urmare, dacă aveți, în mod condiționat, un pod cu un proces lacom (de exemplu, wowza) și nu sunt stabilite restricții pentru acesta, atunci poate apărea o situație când acest pod a consumat de fapt toate resursele nodului, dar pentru k8s acest nod este considerat neîncărcat și i se va acorda același număr de puncte la clasare (mai exact în puncte care evaluează resursele disponibile) ca un nod care nu are pod-uri de lucru, ceea ce în cele din urmă poate duce la o distribuție neuniformă a sarcinii între noduri.

Evacuarea Podului

După cum știți, fiecărui pod îi este atribuită una dintre cele 3 clase QoS:

  1. garantat — este atribuit atunci când pentru fiecare container din pod sunt specificate o solicitare și o limită pentru memorie și CPU, iar aceste valori trebuie să se potrivească
  2. exploziv — cel puțin un container din pod are o cerere și o limită, cu cerere < limită
  3. cel mai bun efort — când niciun container din pod nu are resurse limitate

În același timp, atunci când un nod se confruntă cu o lipsă de resurse (disc, memorie), kubelet începe să clasifice și să elimine podurile conform unui algoritm specific care ține cont de prioritatea pod-ului și a clasei sale QoS. De exemplu, dacă vorbim despre RAM, atunci pe baza clasei QoS, punctele sunt acordate conform următorului principiu:

  • Garantat: -998
  • Cel mai bun efort: 1000
  • Burstable: min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

Acestea. cu aceeași prioritate, kubelet-ul va evacua mai întâi podurile cu cel mai bun efort de clasă QoS din nod.

Producție: dacă doriți să reduceți probabilitatea ca podul dorit să fie evacuat din nod în cazul unei lipse de resurse pe acesta, atunci împreună cu prioritatea, trebuie să vă ocupați și de stabilirea cererii/limitei pentru acesta.

Mecanism pentru scalarea automată orizontală a podurilor de aplicare (HPA)

Când sarcina este să crească și să scadă automat numărul de pod-uri în funcție de utilizarea resurselor (sistem - CPU/RAM sau utilizator - rps), o entitate k8s precum HPA (Horizontal Pod Autoscaler). Algoritmul căruia este următorul:

  1. Sunt determinate citirile curente ale resursei observate (currentMetricValue)
  2. Sunt determinate valorile dorite pentru resursă (desiredMetricValue), care pentru resursele de sistem sunt setate folosind cererea
  3. Numărul curent de replici este determinat (currentReplicas)
  4. Următoarea formulă calculează numărul dorit de replici (desiredReplicas)
    doritReplicas = [ currentReplicas * ( currentMetricValue / wantMetricValue )]

În acest caz, scalarea nu va avea loc atunci când coeficientul (currentMetricValue / wantedMetricValue) este aproape de 1 (în acest caz, putem seta singuri eroarea permisă; implicit este 0.1).

Să ne uităm la modul în care funcționează hpa folosind exemplul aplicației de testare a aplicației (descrisă ca Deployment), unde este necesar să se schimbe numărul de replici în funcție de consumul CPU:

  • Manifestul aplicației

    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

    Acestea. vedem că aplicația pod este lansată inițial în două instanțe, fiecare dintre ele conține două containere nginx și nginx-exporter, pentru fiecare dintre ele un specificat cereri de pentru CPU.

  • Manifestul 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

    Acestea. Am creat un hpa care va monitoriza testul aplicației de implementare și va ajusta numărul de poduri cu aplicația pe baza indicatorului CPU (ne așteptăm ca podul să consume 30% din CPU-ul pe care îl solicită), numărul de replici fiind în intervalul 2-10.

    Acum, să ne uităm la mecanismul de funcționare a hpa dacă aplicăm o sarcină uneia dintre focare:

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

În total avem următoarele:

  • Valoarea dorită (desiredMetricValue) - conform setărilor hpa, avem 30%
  • Valoarea curentă (currentMetricValue) - pentru calcul, controler-manager calculează valoarea medie a consumului de resurse în %, adică. în mod condiționat face următoarele:
    1. Primește valori absolute ale valorilor pod de la serverul de metrici, de exemplu. 101 m și 4 m
    2. Calculează valoarea medie absolută, de ex. (101m + 4m) / 2 = 53m
    3. Obține valoarea absolută pentru consumul de resurse dorit (pentru aceasta, solicitările tuturor containerelor sunt însumate) 60m + 30m = 90m
    4. Calculează procentul mediu al consumului CPU în raport cu podul de solicitare, adică 53m / 90m * 100% = 59%

Acum avem tot ce ne trebuie pentru a determina dacă trebuie să schimbăm numărul de replici; pentru a face acest lucru, calculăm coeficientul:

ratio = 59% / 30% = 1.96

Acestea. numărul de replici ar trebui să crească de ~2 ori și să se ridice la [2 * 1.96] = 4.

Concluzie: După cum puteți vedea, pentru ca acest mecanism să funcționeze, o condiție necesară este prezența solicitărilor pentru toate containerele din podul observat.

Mecanism pentru autoscaling orizontal a nodurilor (Cluster Autoscaler)

Pentru a neutraliza impactul negativ asupra sistemului în timpul supratensiunii de sarcină, a avea un hpa configurat nu este suficient. De exemplu, conform setărilor din managerul de controler hpa, acesta decide că numărul de replici trebuie mărit de 2 ori, dar nodurile nu au resurse libere pentru a rula un astfel de număr de pod-uri (adică nodul nu poate oferi resursele solicitate către podul de solicitări) și aceste poduri trec în starea În așteptare.

În acest caz, dacă furnizorul are un IaaS/PaaS corespunzător (de exemplu, GKE/GCE, AKS, EKS etc.), un instrument precum Autoscaler nod. Vă permite să setați numărul maxim și minim de noduri din cluster și să ajustați automat numărul actual de noduri (prin apelarea API-ului furnizorului de cloud pentru a comanda/elimina un nod) atunci când există o lipsă de resurse în cluster și pod-uri nu pot fi programate (sunt în starea În așteptare).

Concluzie: Pentru a putea autoscala nodurile, este necesar să setați cereri în containerele pod, astfel încât k8s să poată evalua corect încărcarea nodurilor și, în consecință, să raporteze că nu există resurse în cluster pentru a lansa următorul pod.

Concluzie

Trebuie remarcat faptul că stabilirea limitelor de resurse pentru container nu este o cerință pentru ca aplicația să ruleze cu succes, dar este totuși mai bine să faceți acest lucru din următoarele motive:

  1. Pentru o funcționare mai precisă a planificatorului în ceea ce privește echilibrarea sarcinii între nodurile k8s
  2. Pentru a reduce probabilitatea apariției unui eveniment de „evacuare a podului”.
  3. Pentru ca scalarea automată orizontală a aplicațiilor (HPA) să funcționeze
  4. Pentru autoscaling orizontal a nodurilor (Cluster Autoscaling) pentru furnizorii de cloud

Citiți și alte articole de pe blogul nostru:

Sursa: www.habr.com

Adauga un comentariu