Kubernetes: waarom het zo belangrijk is om het resourcebeheer van het systeem in te stellen?

Over het algemeen is er altijd de noodzaak om een specifieke pool van bronnen voor een applicatie te waarborgen voor een correcte en stabiele werking. Maar wat als meerdere applicaties op dezelfde capaciteit draaien? Hoe kunnen we ervoor zorgen dat elk van hen de minimaal benodigde middelen heeft? Op welke manier kunnen we het verbruik van middelen beperken? Hoe kunnen we de belasting effectief verdelen over de nodes? Hoe kunnen we de werking van het horizontale schaalmechanisme garanderen in geval van toenemende belasting op de applicaties?

Kubernetes: waarom het zo belangrijk is om het resourcebeheer van het systeem in te stellen?

We moeten beginnen met de belangrijkste soorten middelen die in het systeem bestaan — dit zijn natuurlijk de processortijd en het werkgeheugen. In de k8s-manifesten worden deze soorten middelen gemeten in de volgende eenheden:

  • CPU — in cores
  • RAM — in bytes

Voor elk type hulpbron is er de mogelijkheid om twee soorten eisen op te geven — requests en limits. Requests beschrijft de minimale eisen aan de beschikbare middelen van de node voor het opstarten van de container (en de pod in het algemeen), terwijl limits een strikte beperking vaststelt van de middelen die aan de container beschikbaar zijn.

Het is belangrijk te begrijpen dat het in het manifest niet noodzakelijk is om beide typen expliciet te definiƫren, terwijl het gedrag als volgt zal zijn:

  • Als alleen de limits voor de hulpbron expliciet zijn gedefinieerd, dan neemt de requests voor deze hulpbron automatisch de waarde aan die gelijk is aan de limits (dit kan worden bevestigd door de beschrijving van de entiteit aan te roepen). Dat wil zeggen, de werking van de container zal feitelijk worden beperkt door precies dezelfde hoeveelheid middelen die nodig zijn voor de opstart.
  • Als voor de hulpbron alleen de requests expliciet zijn gedefinieerd, dan zijn er geen bovenlimieten voor deze hulpbron — dat wil zeggen, de container is alleen beperkt door de middelen van de node zelf.

Er is ook de mogelijkheid om het middelenbeheer niet alleen op container-niveau, maar ook op namespace-niveau in te stellen met behulp van de volgende entiteiten:

  • LimitRange — beschrijft het beleid voor beperking op het niveau van container/pod in ns en is nodig om standaardbeperkingen voor de container/pod te beschrijven, evenals om het creĆ«ren van duidelijk te zware containers/pods (of omgekeerd) te voorkomen, hun aantal te beperken en mogelijke verschillen in waarden tussen limits en requests te bepalen.
  • ResourceQuotas — beschrijft het algemene beperkingbeleid voor alle containers in de ns en wordt meestal gebruikt om middelen tussen omgevingen te scheiden (handig wanneer omgevingen niet strikt zijn gescheiden op het niveau van knooppunten)

Hieronder staan voorbeelden van manifesten waarin de middelenbeperkingen zijn vastgesteld:

  • Op het niveau van een specifieke container:

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

    Dat wil zeggen, in dit geval is er minimaal 1G RAM en 0.2 CPU op het knooppunt vereist om de nginx-container te starten, terwijl de container maximaal 0.2 CPU en al het beschikbare RAM op het knooppunt kan gebruiken.

  • Op het niveau van de hele ns:

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

    Dat wil zeggen, de som van alle aanvragen (requests) van de containers in de standaard ns mag niet meer zijn dan 300m voor CPU en 1G voor RAM, terwijl de som van alle limieten niet meer dan 700m voor CPU en 2G voor RAM mag zijn.

  • Standaard beperkingen voor containers in de 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

    Dat wil zeggen, in de standaard namespace zal voor alle containers standaard een aanvraag van 100m voor CPU en 1G voor RAM worden ingesteld, met een limiet van 1 CPU en 2G. Er zijn ook beperkingen ingesteld voor de mogelijke waarde in aanvragen/lijsten voor CPU (50m < x < 2) en RAM (500M < x < 4G).

  • Beperkingen op het niveau van pods in de ns:

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

    Dat wil zeggen, voor elke pod in de standaard ns is er een beperking van 4 vCPU en 1G ingesteld.

Nu willen we graag bespreken welke voordelen het instellen van deze beperkingen kan bieden.

Het mechanisme voor load balancing tussen knooppunten

Zoals bekend, is er een component in k8s, genaamd scheduler, die verantwoordelijk is voor het toewijzen van pods aan knooppunten volgens een bepaald algoritme. Dit algoritme doorloopt twee fasen bij het selecteren van de optimale knoop voor de uitvoering:

  1. Filtering
  2. Ranking

Dat wil zeggen, volgens het beschreven beleid worden in eerste instantie de knooppunten geselecteerd waar de pod kan worden uitgevoerd op basis van een set predicates (waaronder wordt gecontroleerd of er voldoende middelen op de knoop zijn voor het uitvoeren van de pod — PodFitsResources), en vervolgens, voor elk van deze knooppunten, volgens priorities punten worden toegekend (waarbij geldt: hoe meer vrije bronnen er beschikbaar zijn op de node, hoe meer punten deze krijgt: LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) en het wordt gestart op de node met het hoogste aantal punten (als meerdere nodes aan deze voorwaarde voldoen, wordt er willekeurig ƩƩn gekozen).

Het is belangrijk te begrijpen dat de scheduler bij het evalueren van de beschikbare bronnen van de node kijkt naar de gegevens die zijn opgeslagen in etcd - dat wil zeggen, naar de som van de gevraagde/l Limiet van elke pod die op deze node draait, maar niet naar het daadwerkelijke bronnenverbruik. Deze informatie kan worden verkregen met de output van de opdracht kubectl describe node $NODE, bijvoorbeeld:

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

Hier zien we alle pods die op een specifieke node draaien, evenals de bronnen die elke pod vraagt. En zo zien de logs van de scheduler eruit bij het starten van de pod cronjob-cron-events-1573793820-xt6q9 (deze informatie verschijnt in de log van de scheduler bij het instellen van level 10 logging in de opstartargumenten —v=10):

log

I1115 07:57:21.637791       1 scheduling_queue.go:908] Bezig met het plannen van pod nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                           
I1115 07:57:21.637804       1 scheduler.go:453] Poging om pod te plannen: nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                                    
I1115 07:57:21.638285       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s5 is toegestaan, Node draait slechts 16 van de 110 Pods.                                                                               
I1115 07:57:21.638300       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s6 is toegestaan, Node draait slechts 20 van de 110 Pods.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s3 is toegestaan, Node draait slechts 20 van de 110 Pods.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s4 is toegestaan, Node draait slechts 17 van de 110 Pods.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s10 is toegestaan, Node draait slechts 16 van de 110 Pods.                                                                              
I1115 07:57:21.638365       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s12 is toegestaan, Node draait slechts 9 van de 110 Pods.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s11 is toegestaan, Node draait slechts 11 van de 110 Pods.                                                                              
I1115 07:57:21.638385       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s1 is toegestaan, Node draait slechts 19 van de 110 Pods.                                                                               
I1115 07:57:21.638402       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s2 is toegestaan, Node draait slechts 21 van de 110 Pods.                                                                               
I1115 07:57:21.638383       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s9 is toegestaan, Node draait slechts 16 van de 110 Pods.                                                                               
I1115 07:57:21.638335       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s8 is toegestaan, Node draait slechts 18 van de 110 Pods.                                                                               
I1115 07:57:21.638408       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s13 is toegestaan, Node draait slechts 8 van de 110 Pods.                                                                               
I1115 07:57:21.638478       1 predicates.go:1369] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s10 is toegestaan, bestaande pods anti-affiniteitsvoorwaarden zijn vervuld.                                                                         
I1115 07:57:21.638505       1 predicates.go:1369] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s8 is toegestaan, bestaande pods anti-affiniteitsvoorwaarden zijn vervuld.                                                                          
I1115 07:57:21.638577       1 predicates.go:1369] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s9 is toegestaan, bestaande pods anti-affiniteitsvoorwaarden zijn vervuld.                                                                          
I1115 07:57:21.638583       1 predicates.go:829] Plannen van Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 op Node nxs-k8s-s7 is toegestaan, Node draait slechts 25 van de 110 Pods.                                                                               
I1115 07:57:21.638932       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: BalancedResourceAllocation, capaciteit 39900 millicores 66620178432 geheugenen bytes, totale aanvraag 2343 millicores 9640186880 geheugenen bytes, score 9        
I1115 07:57:21.638946       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: LeastResourceAllocation, capaciteit 39900 millicores 66620178432 geheugenen bytes, totale aanvraag 2343 millicores 9640186880 geheugenen bytes, score 8           
I1115 07:57:21.638961       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: BalancedResourceAllocation, capaciteit 39900 millicores 66620170240 geheugenen bytes, totale aanvraag 4107 millicores 11307422720 geheugenen bytes, score 9        
I1115 07:57:21.638971       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: BalancedResourceAllocation, capaciteit 39900 millicores 66620178432 geheugenen bytes, totale aanvraag 5847 millicores 24333637120 geheugenen bytes, score 7        
I1115 07:57:21.638975       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: LeastResourceAllocation, capaciteit 39900 millicores 66620170240 geheugenen bytes, totale aanvraag 4107 millicores 11307422720 geheugenen bytes, score 8           
I1115 07:57:21.638990       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: LeastResourceAllocation, capaciteit 39900 millicores 66620178432 geheugenen bytes, totale aanvraag 5847 millicores 24333637120 geheugenen 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 voor pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10"                                                                                                               
I1115 07:57:21.639286       1 scheduler_binder.go:279] AssumePodVolumes voor pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10": alle PVC's gebonden en niets te doen                                                                             
I1115 07:57:21.639333       1 factory.go:733] Poging om cronjob-cron-events-1573793820-xt6q9 te binden aan nxs-k8s-s10

Hier zien we dat de scheduler aanvankelijk filtert en een lijst vormt van 3 knooppunten waarop de uitvoering mogelijk is (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Vervolgens wordt het aantal punten berekend op basis van verschillende parameters (waaronder BalancedResourceAllocation, LeastResourceAllocation) voor elk van deze knooppunten om de meest geschikte node te bepalen. Uiteindelijk wordt er gepland op de node met het hoogste puntenaantal (hier hebben twee nodes tegelijk 100037 punten, dus wordt er een willekeurige gekozen - nxs-k8s-s10).

Uitslag: als er pods op de node draaien waarvoor geen beperkingen zijn ingesteld, is dit voor k8s (qua resourcegebruik) equivalent aan de situatie waarin dergelijke pods helemaal niet op deze node aanwezig zijn. Daarom, als je bijvoorbeeld een pod hebt met een hongerig proces (bijvoorbeeld wowza) en voor deze pod geen beperkingen zijn ingesteld, kan het gebeuren dat deze pod feitelijk alle resources van de node verbruikt, terwijl de node voor k8s als niet belast wordt beschouwd en hetzelfde aantal punten krijgt bij de ranking (precies zoals de node zonder actieve pods), wat uiteindelijk kan leiden tot een ongelijke verdeling van de belasting tussen nodes.

Uitzetting van de pod

Zoals bekend - elke pod krijgt een van de 3 QoS-klassen toegewezen:

  1. gegarandeerd - wordt toegewezen wanneer voor elke container in de pod een request en limit voor geheugen en cpu is ingesteld, en deze waarden moeten identiek zijn
  2. burstable - ten minste ƩƩn container in de pod heeft een request en limit, waarbij request < limit is
  3. beste inspanning - wanneer geen enkele container in de pod beperkt is in resources

Wanneer er echter een tekort aan resources (schijf, geheugen) op de node wordt waargenomen, begint kubelet met het rangschikken en uitzetten van pods volgens een bepaald algoritme, dat rekening houdt met de prioriteit van de pod en zijn QoS-klasse. Bijvoorbeeld, als het om RAM gaat, worden op basis van de QoS-klasse punten toegewezen volgens het volgende principe:

  • Gegarandeerd: -998
  • Beste inspanning: 1000
  • Burstable: min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

Dus bij gelijke prioriteit zal kubelet in de eerste plaats pods met de QoS-klasse beste inspanning van de node zetten.

Uitslag: als je de kans wilt verkleinen dat een belangrijke pod van de node wordt gezet bij een tekort aan resources, is het naast de prioriteit ook noodzakelijk om zorgen voor het instellen van request/limit voor deze pod.

Mechanisme voor horizontale automatische schaling van toepassing pods (HPA)

Wanneer de taak bestaat om automatisch het aantal pods te verhogen of verlagen op basis van resourcegebruik (systeem - CPU / RAM of gebruiker - rps), kan een K8s-entiteit zoals HPA (Horizontal Pod Autoscaler) helpen. Het algoritme is als volgt:

  1. De huidige waardes van de te monitoren resource (currentMetricValue) worden bepaald.
  2. De gewenste waardes voor de resource (desiredMetricValue) worden ingesteld, die voor systeemresources worden opgegeven via request.
  3. Het huidige aantal replicas (currentReplicas) wordt vastgesteld.
  4. Volgens de volgende formule wordt het gewenste aantal replicas (desiredReplicas) berekend.
    desiredReplicas = [ currentReplicas * ( currentMetricValue / desiredMetricValue )]

Er zal echter geen schaalvergroting plaatsvinden wanneer de ratio (currentMetricValue / desiredMetricValue) dicht bij 1 ligt (de toelaatbare afwijking kunnen we zelf instellen, standaard is dit 0.1).

Laten we het functioneren van hpa bekijken aan de hand van een voorbeeldapplicatie app-test (beschreven als Deployment), waar het aantal replicas moet worden gewijzigd op basis van CPU-verbruik:

  • Manifest van de applicatie

    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

    Dat wil zeggen, we zien dat de pod met de applicatie aanvankelijk in twee exemplaren draait, waarvan elk twee containers heeft: nginx en nginx-exporter, waarvoor is ingesteld requests voor CPU.

  • Manifest voor 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

    Dat wil zeggen, we hebben een hpa gecreƫerd die toezicht houdt op de Deployment app-test en het aantal pods met de applicatie reguleert op basis van de CPU-metrics (we verwachten dat de pod 30% van de aangevraagde CPU gebruikt), terwijl het aantal replicas tussen 2-10 ligt.

    Laten we nu het werkmechanisme van hpa bekijken als we belasting op een van de pods leggen:

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

In totaal hebben we het volgende:

  • De gewenste waarde (desiredMetricValue) is volgens de hpa-instellingen gelijk aan 30%
  • De huidige waarde (currentMetricValue) wordt berekend door de controller-manager de gemiddelde waarde van het resourceverbruik in % te berekenen, dat wil zeggen dat het ongeveer het volgende doet:
    1. Ontvangt absolute waarden van de pods-metrics van de metric-server, dat wil zeggen 101m en 4m
    2. Berechnet het gemiddelde absolute waarde, dat wil zeggen (101m + 4m) / 2 = 53m
    3. Ontvangt de absolute waarde voor het gewenste resourceverbruik (hiervoor worden de requests van alle containers bij elkaar opgeteld) 60m + 30m = 90m
    4. Berechnet het gemiddelde percentage CPU-verbruik ten opzichte van de pod-request, dat wil zeggen 53m / 90m * 100% = 59%

Nu hebben we alles wat we nodig hebben om te bepalen of het aantal replicas moet worden gewijzigd. We berekenen de ratio:

ratio = 59% / 30% = 1.96

Dat wil zeggen, het aantal replicas moet met ~2 keer verhoogd worden en bedraagt [2 * 1.96] = 4.

Uitvoer: Zoals opgemerkt, is een noodzakelijke voorwaarde voor de werking van dit mechanisme ook de aanwezigheid van requests voor alle containers in de geobserveerde pod.

Mechanisme voor horizontale autoscaling van nodes (Cluster Autoscaler)

Om de negatieve impact op het systeem bij pieken in de belasting te verminderen, is het inregelen van hpa soms niet voldoende. Bijvoorbeeld, volgens de instellingen in hpa beslist de controller-manager dat het aantal replicas met 2 keer moet worden verhoogd, maar er zijn geen vrije resources op de nodes om zo veel pods te starten (dat wil zeggen dat de node de gevraagde resources van de pod niet kan leveren) en deze pods gaan in de status Pending.

In dit geval, als de provider de overeenkomstige IaaS/PaaS heeft (bijvoorbeeld GKE/GCE, AKS, EKS, enz.), kan een hulpmiddel zoals Node Autoscalerons helpen. Het stelt in staat om het maximale en minimale aantal nodes in de cluster in te stellen en automatisch het huidige aantal nodes te reguleren (door het API van de cloudprovider aan teroepen om een node te bestellen/verwijderen) wanneer er een tekort aan resources in de cluster is en pods niet kunnen worden gepland (in de status Pending zijn).

Uitvoer: Voor de mogelijkheid van autoscaling van nodes moeten requests in de container pods worden gedefinieerd, zodat k8s correct de belasting op de nodes kan inschatten en overeenkomstig kan melden dat er onvoldoende resources in de cluster zijn om de volgende pod te starten.

Conclusie

Het is belangrijk op te merken dat het instellen van resourcebeperkingen voor de container geen vereiste is voor het succesvol draaien van een applicatie, maar het is toch beter om dit te doen om de volgende redenen:

  1. Voor nauwkeurigere werking van de scheduler bij het balanceren van de belasting tussen k8s-nodes
  2. Om de kans op een 'pod eviction'-evenement te verkleinen
  3. Voor de werking van de horizontale autoscaling van applicatiepods (HPA)
  4. Voor de werking van de horizontale autoscaling van nodes (Cluster Autoscaling) bij cloudproviders

Lees ook andere artikelen op onze blog:

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster