Kubernetes: Warum ist es so wichtig, die Systemressourcenverwaltung zu konfigurieren?

Grundsätzlich besteht immer die Notwendigkeit, einer Anwendung einen dedizierten Ressourcenpool für ihren korrekten und stabilen Betrieb zur Verfügung zu stellen. Was aber, wenn mehrere Anwendungen mit derselben Leistung laufen? Wie kann jeder von ihnen mit den minimal notwendigen Ressourcen ausgestattet werden? Wie können Sie den Ressourcenverbrauch begrenzen? Wie verteilt man die Last richtig zwischen den Knoten? Wie kann sichergestellt werden, dass der horizontale Skalierungsmechanismus funktioniert, wenn die Anwendungslast steigt?

Kubernetes: Warum ist es so wichtig, die Systemressourcenverwaltung zu konfigurieren?

Sie müssen damit beginnen, welche Hauptressourcentypen im System vorhanden sind – das sind natürlich Prozessorzeit und RAM. In k8s-Manifesten werden diese Ressourcentypen in den folgenden Einheiten gemessen:

  • CPU – in Kernen
  • RAM – in Bytes

Darüber hinaus ist es für jede Ressource möglich, zwei Arten von Anforderungen festzulegen: Zugriffe и Grenzen. Anfragen – beschreibt die Mindestanforderungen an freie Ressourcen eines Knotens zum Ausführen eines Containers (und eines Pods als Ganzes), während „Limits“ eine feste Grenze für die für den Container verfügbaren Ressourcen festlegen.

Es ist wichtig zu verstehen, dass das Manifest nicht beide Typen explizit definieren muss, das Verhalten jedoch wie folgt sein wird:

  • Wenn nur die Grenzwerte einer Ressource explizit angegeben werden, nehmen Anforderungen für diese Ressource automatisch einen Wert an, der den Grenzwerten entspricht (Sie können dies überprüfen, indem Sie „describe entities“ aufrufen). Diese. Tatsächlich ist der Container auf die gleiche Menge an Ressourcen beschränkt, die er zum Ausführen benötigt.
  • Wenn für eine Ressource nur Anfragen explizit angegeben werden, dann werden für diese Ressource keine Obergrenzen festgelegt, d. h. Der Container ist nur durch die Ressourcen des Knotens selbst begrenzt.

Es ist auch möglich, die Ressourcenverwaltung nicht nur auf der Ebene eines bestimmten Containers, sondern auch auf der Namespace-Ebene mithilfe der folgenden Entitäten zu konfigurieren:

  • Grenzbereich – beschreibt die Einschränkungsrichtlinie auf Container-/Pod-Ebene in ns und wird benötigt, um die Standardgrenzen für den Container/Pod zu beschreiben sowie die Erstellung offensichtlich fetter Container/Pods (oder umgekehrt) zu verhindern und deren Anzahl zu begrenzen und ermitteln Sie den möglichen Unterschied in den Werten in Grenzwerten und Anforderungen
  • Ressourcenquoten – beschreibt die allgemeine Einschränkungsrichtlinie für alle Container in NS und wird in der Regel verwendet, um Ressourcen zwischen Umgebungen abzugrenzen (nützlich, wenn Umgebungen auf Knotenebene nicht streng abgegrenzt sind).

Im Folgenden finden Sie Beispiele für Manifeste, die Ressourcengrenzen festlegen:

  • Auf der spezifischen Containerebene:

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

    Diese. In diesem Fall benötigen Sie zum Ausführen eines Containers mit Nginx mindestens 1 GB freien RAM und 0.2 CPU auf dem Knoten, während der Container höchstens 0.2 CPU und den gesamten verfügbaren RAM auf dem Knoten verbrauchen kann.

  • Auf der Ganzzahlebene ns:

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

    Diese. Die Summe aller Anforderungscontainer im Standard-NS darf 300 m für die CPU und 1 G für das OP nicht überschreiten, und die Summe aller Grenzwerte beträgt 700 m für die CPU und 2 G für das OP.

  • Standardgrenzen für Container 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

    Diese. Im Standard-Namespace für alle Container wird die Anforderung auf 100 m für die CPU und 1 GB für OP festgelegt, die Grenze beträgt 1 CPU und 2 GB. Gleichzeitig wird auch eine Begrenzung der möglichen Werte in Anfrage/Limit für CPU (50m < x < 2) und RAM (500M < x < 4G) festgelegt.

  • Einschränkungen auf Pod-Ebene ns:

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

    Diese. Für jeden Pod im Standard-NS gibt es ein Limit von 4 vCPU und 1G.

Nun möchte ich Ihnen erläutern, welche Vorteile uns die Festlegung dieser Beschränkungen bringen kann.

Lastausgleichsmechanismus zwischen Knoten

Wie Sie wissen, ist die k8s-Komponente für die Verteilung von Pods auf Knoten verantwortlich, z Scheduler, das nach einem bestimmten Algorithmus funktioniert. Dieser Algorithmus durchläuft bei der Auswahl des optimalen Startknotens zwei Phasen:

  1. Filter
  2. Reichweite

Diese. Gemäß der beschriebenen Richtlinie werden zunächst Knoten ausgewählt, auf denen basierend auf einem Set ein Pod gestartet werden kann Prädikate (einschließlich der Überprüfung, ob der Knoten über genügend Ressourcen verfügt, um den Pod auszuführen – PodFitsResources) und dann für jeden dieser Knoten entsprechend Prioritäten Es werden Punkte vergeben (je mehr freie Ressourcen ein Knoten hat, desto mehr Punkte werden ihm zugewiesen – LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) und der Pod wird auf dem Knoten mit den meisten Punkten gestartet (wenn mehrere Knoten gleichzeitig diese Bedingung erfüllen). es wird ein zufälliges ausgewählt).

Gleichzeitig müssen Sie verstehen, dass sich der Scheduler bei der Bewertung der verfügbaren Ressourcen eines Knotens an den Daten orientiert, die in etcd gespeichert sind – d. h. für die Menge der angeforderten/begrenzten Ressource jedes auf diesem Knoten ausgeführten Pods, jedoch nicht für den tatsächlichen Ressourcenverbrauch. Diese Informationen können der Befehlsausgabe entnommen werden kubectl describe node $NODEzum Beispiel:

# 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 sehen wir alle Pods, die auf einem bestimmten Knoten ausgeführt werden, sowie die Ressourcen, die jeder Pod anfordert. Und so sehen die Scheduler-Protokolle aus, wenn der Pod „cronjob-cron-events-1573793820-xt6q9“ gestartet wird (diese Informationen werden im Scheduler-Protokoll angezeigt, wenn Sie die 10. Protokollierungsstufe in den Startbefehlsargumenten -v=10 festlegen):

breite Möwe

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

Hier sehen wir, dass der Scheduler zunächst eine Liste von 3 Knoten filtert und generiert, auf denen er gestartet werden kann (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Anschließend berechnet es Bewertungen basierend auf mehreren Parametern (einschließlich BalancedResourceAllocation, LeastResourceAllocation) für jeden dieser Knoten, um den am besten geeigneten Knoten zu bestimmen. Letztendlich wird der Pod auf dem Knoten mit der höchsten Anzahl an Punkten geplant (hier haben zwei Knoten gleichzeitig die gleiche Anzahl an Punkten 100037, daher wird ein zufälliger Knoten ausgewählt – nxs-k8s-s10).

Abschluss: Wenn auf einem Knoten Pods ausgeführt werden, für die keine Einschränkungen festgelegt sind, ist dies für k8s (aus Sicht des Ressourcenverbrauchs) so, als ob es auf diesem Knoten überhaupt keine solchen Pods gäbe. Wenn Sie also bedingt einen Pod mit einem gefräßigen Prozess (z. B. Wowza) haben und keine Einschränkungen dafür festgelegt sind, kann es vorkommen, dass dieser Pod tatsächlich alle Ressourcen des Knotens verbraucht, für k8s jedoch dieser Knoten gilt als entladen und erhält beim Ranking die gleiche Anzahl an Punkten (genau in Punkten zur Bewertung der verfügbaren Ressourcen) wie ein Knoten, der keine funktionierenden Pods hat, was letztendlich zu einer ungleichmäßigen Lastverteilung zwischen den Knoten führen kann.

Pods Räumung

Wie Sie wissen, wird jedem Pod eine von drei QoS-Klassen zugewiesen:

  1. garantiert – wird zugewiesen, wenn für jeden Container im Pod eine Anforderung und ein Limit für Speicher und CPU angegeben werden und diese Werte übereinstimmen müssen
  2. platzbar – Mindestens ein Container im Pod hat eine Anfrage und ein Limit, wobei Anfrage < Limit ist
  3. beste Anstrengung – wenn kein einziger Container im Pod ressourcenbeschränkt ist

Wenn ein Knoten gleichzeitig einen Mangel an Ressourcen (Festplatte, Speicher) feststellt, beginnt Kubelet, Pods nach einem bestimmten Algorithmus zu ordnen und zu entfernen, der die Priorität des Pods und seine QoS-Klasse berücksichtigt. Wenn es sich beispielsweise um RAM handelt, werden basierend auf der QoS-Klasse Punkte nach folgendem Prinzip vergeben:

  • Garantierter: -998
  • BestEffort: 1000
  • Berstbar: min(max(2, 1000 - (1000 * MemoryRequestBytes) / machineMemoryCapacityBytes), 999)

Diese. Bei gleicher Priorität entfernt das Kubelet zunächst Pods mit der QoS-Klasse „Best Effort“ vom Knoten.

Abschluss: Wenn Sie die Wahrscheinlichkeit verringern möchten, dass der gewünschte Pod bei einem Mangel an Ressourcen aus dem Knoten entfernt wird, müssen Sie neben der Priorität auch darauf achten, die Anforderung/das Limit dafür festzulegen.

Mechanismus zur horizontalen automatischen Skalierung von Anwendungs-Pods (HPA)

Wenn die Aufgabe darin besteht, die Anzahl der Pods abhängig von der Ressourcennutzung (System – CPU/RAM oder Benutzer – RPS) automatisch zu erhöhen und zu verringern, kann eine k8s-Entität wie z HPA (Horizontaler Pod-Autoscaler). Der Algorithmus lautet wie folgt:

  1. Die aktuellen Messwerte der beobachteten Ressource werden ermittelt (currentMetricValue)
  2. Es werden die gewünschten Werte für die Ressource ermittelt (desiredMetricValue), die für Systemressourcen per Request gesetzt werden
  3. Es wird die aktuelle Anzahl der Replikate ermittelt (currentReplicas)
  4. Die folgende Formel berechnet die gewünschte Anzahl an Replikaten (desiredReplicas)
    gewünschteReplicas = [ currentReplicas * ( currentMetricValue / gewünschteMetricValue )]

In diesem Fall erfolgt keine Skalierung, wenn der Koeffizient (currentMetricValue / gewünschter MetricValue) nahe bei 1 liegt (in diesem Fall können wir den zulässigen Fehler selbst festlegen; standardmäßig beträgt er 0.1).

Schauen wir uns die Funktionsweise von hpa am Beispiel der App-Test-Anwendung (beschrieben als Deployment) an, bei der es notwendig ist, die Anzahl der Replikate abhängig vom CPU-Verbrauch zu ändern:

  • Anwendungsmanifest

    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

    Diese. Wir sehen, dass der Anwendungs-Pod zunächst in zwei Instanzen gestartet wird, von denen jede zwei Nginx- und Nginx-Exporter-Container enthält, für die jeweils ein angegebener Wert angegeben ist Zugriffe für CPU.

  • HPA-Manifest

    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

    Diese. Wir haben ein HPA erstellt, das den Deployment-App-Test überwacht und die Anzahl der Pods mit der Anwendung basierend auf dem CPU-Indikator reguliert (wir gehen davon aus, dass der Pod 30 % der von ihm angeforderten CPU verbrauchen sollte), wobei die Anzahl der Replikate beträgt im Bereich von 2-10.

    Schauen wir uns nun den Mechanismus des HPA-Betriebs an, wenn wir eine Last auf einen der Herde aufbringen:

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

Insgesamt haben wir Folgendes:

  • Der gewünschte Wert (desiredMetricValue) – gemäß den HPA-Einstellungen haben wir 30 %
  • Aktueller Wert (currentMetricValue) – zur Berechnung berechnet der Controller-Manager den Durchschnittswert des Ressourcenverbrauchs in %, d. h. führt bedingt Folgendes aus:
    1. Erhält absolute Werte der Pod-Metriken vom Metrikserver, d. h. 101m und 4m
    2. Berechnet den durchschnittlichen Absolutwert, d. h. (101 m + 4 m) / 2 = 53 m
    3. Ermittelt den absoluten Wert für den gewünschten Ressourcenverbrauch (dazu werden die Anfragen aller Container aufsummiert) 60m + 30m = 90m
    4. Berechnet den durchschnittlichen Prozentsatz des CPU-Verbrauchs im Verhältnis zum Anforderungs-Pod, d. h. 53m / 90m * 100% = 59%

Jetzt haben wir alles, was wir brauchen, um zu bestimmen, ob wir die Anzahl der Replikate ändern müssen; dazu berechnen wir den Koeffizienten:

ratio = 59% / 30% = 1.96

Diese. Die Anzahl der Replikate sollte um das ~2-fache erhöht werden und [2 * 1.96] = 4 betragen.

Fazit: Wie Sie sehen, ist für das Funktionieren dieses Mechanismus eine notwendige Voraussetzung das Vorhandensein von Anforderungen für alle Container im beobachteten Pod.

Mechanismus zur horizontalen Autoskalierung von Knoten (Cluster Autoscaler)

Um die negativen Auswirkungen auf das System bei Lastspitzen zu neutralisieren, reicht es nicht aus, einen konfigurierten HPA zu haben. Gemäß den Einstellungen im HPA-Controller-Manager wird beispielsweise entschieden, dass die Anzahl der Replikate um das Zweifache erhöht werden muss, die Knoten jedoch nicht über freie Ressourcen verfügen, um eine solche Anzahl von Pods auszuführen (d. h. der Knoten kann dies nicht bereitstellen). angeforderte Ressourcen an den Anforderungs-Pod) und diese Pods wechseln in den Status „Ausstehend“.

Wenn der Anbieter in diesem Fall über ein entsprechendes IaaS/PaaS (z. B. GKE/GCE, AKS, EKS usw.) verfügt, kann ein Tool wie z Knoten-Autoscaler. Es ermöglicht Ihnen, die maximale und minimale Anzahl von Knoten im Cluster festzulegen und die aktuelle Anzahl von Knoten automatisch anzupassen (durch Aufruf der Cloud-Anbieter-API, um einen Knoten zu bestellen/zu entfernen), wenn im Cluster und in den Pods ein Mangel an Ressourcen vorliegt können nicht geplant werden (befinden sich im Status „Ausstehend“).

Fazit: Um Knoten automatisch skalieren zu können, müssen Anforderungen in den Pod-Containern eingestellt werden, damit k8s die Auslastung der Knoten richtig einschätzen und dementsprechend melden kann, dass im Cluster keine Ressourcen zum Starten des nächsten Pods vorhanden sind.

Abschluss

Es ist zu beachten, dass das Festlegen von Containerressourcengrenzen keine Voraussetzung für die erfolgreiche Ausführung der Anwendung ist, es aber aus folgenden Gründen dennoch besser ist, dies zu tun:

  1. Für einen genaueren Betrieb des Schedulers im Hinblick auf den Lastausgleich zwischen k8s-Knoten
  2. Um die Wahrscheinlichkeit zu verringern, dass ein „Pod-Eviction“-Ereignis eintritt
  3. Damit die horizontale automatische Skalierung von Anwendungs-Pods (HPA) funktioniert
  4. Zur horizontalen Autoskalierung von Knoten (Cluster Autoscaling) für Cloud-Anbieter

Lesen Sie auch andere Artikel in unserem Blog:

Source: habr.com

Kommentar hinzufügen