Kubernetes: pourquoi est-il si important de configurer la gestion des ressources systĂšme?

En rĂšgle gĂ©nĂ©rale, il est toujours nĂ©cessaire de fournir un pool de ressources dĂ©diĂ© Ă  toute application pour son fonctionnement correct et stable. Mais que se passe-t-il si plusieurs applications fonctionnent sur les mĂȘmes capacitĂ©s Ă  la fois? Comment fournir le minimum de ressources nĂ©cessaires pour chacun d'eux? Comment puis-je limiter la consommation de ressources? Comment rĂ©partir correctement la charge entre les nƓuds? Comment assurer le mĂ©canisme de mise Ă  l'Ă©chelle horizontale en cas de charge accrue sur l'application?



Vous devez commencer par quels types de ressources de base existent dans le systÚme - bien sûr, le temps processeur et la RAM. Dans les manifestes k8s, ces types de ressources sont mesurés dans les unités suivantes:


  • CPU - dans les cƓurs
  • RAM - en octets

De plus, pour chaque ressource, il est possible de dĂ©finir deux types d'exigences: les demandes et les limites . Demandes - dĂ©crit les exigences minimales pour les ressources libres du nƓud pour exĂ©cuter le conteneur (et l'Ăątre dans son ensemble), tandis que limits dĂ©finit une limite stricte sur les ressources disponibles pour le conteneur.


Il est important de comprendre que dans le manifeste, il n'est pas nécessaire de définir explicitement les deux types, et le comportement sera le suivant:


  • Si seules les limites de la ressource sont dĂ©finies explicitement, les demandes pour cette ressource prennent automatiquement une valeur Ă©gale aux limites (cela peut ĂȘtre vĂ©rifiĂ© en appelant des entitĂ©s de description). C'est-Ă -dire en fait, le fonctionnement du conteneur sera limitĂ© par la mĂȘme quantitĂ© de ressources dont il a besoin pour fonctionner.
  • Si seules les demandes sont explicitement dĂ©finies pour une ressource, aucune restriction n'est dĂ©finie au-dessus de cette ressource, c'est-Ă -dire le conteneur n'est limitĂ© que par les ressources du nƓud lui-mĂȘme.

Il est également possible de configurer la gestion des ressources non seulement au niveau d'un conteneur spécifique, mais également au niveau de l'espace de noms à l'aide des entités suivantes:


  • LimitRange - dĂ©crit la politique de restriction au niveau du conteneur / foyer en ns et est nĂ©cessaire pour dĂ©crire les restrictions par dĂ©faut sur le conteneur / foyer, ainsi que pour empĂȘcher la crĂ©ation de conteneurs / foyers manifestement gras (ou vice versa), limiter leur nombre et dĂ©terminer la diffĂ©rence possible entre les limites et demandes
  • ResourceQuotas - dĂ©crivent la politique de restriction en gĂ©nĂ©ral pour tous les conteneurs en ns et est utilisĂ©, en rĂšgle gĂ©nĂ©rale, pour diffĂ©rencier les ressources entre les environnements (utile lorsque les environnements ne sont pas rigoureusement dĂ©limitĂ©s au niveau des nƓuds)

Voici des exemples de manifestes dans lesquels des limites de ressources sont définies:


  • Au niveau du conteneur spĂ©cifique:


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

    C'est-Ă -dire dans ce cas, pour dĂ©marrer un conteneur avec nginx, vous aurez besoin d'au moins la prĂ©sence d'OP 1G gratuit et de 0,2 CPU sur le nƓud, tandis que le conteneur maximum peut consommer 0,2 CPU et tous les OP disponibles sur le nƓud.


  • Au niveau entier ns:


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

    C'est-à-dire la somme de tous les conteneurs de demande dans les n par défaut ne peut pas dépasser 300 m pour le CPU et 1 G pour l'OP, et la somme de toutes les limites est de 700 m pour le CPU et 2 G pour l'OP.


  • Restrictions par dĂ©faut pour les conteneurs en 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 

    C'est-Ă -dire dans l'espace de noms par dĂ©faut pour tous les conteneurs, par dĂ©faut, la demande sera dĂ©finie Ă  100 m pour le CPU et 1G pour l'OP, limite - 1 CPU et 2G. Dans le mĂȘme temps, une restriction a Ă©galement Ă©tĂ© Ă©tablie sur les valeurs possibles dans la demande / limite pour le CPU (50m <x <2) et la RAM (500M <x <4G).


  • Limitations au niveau du foyer ns:


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

    C'est-à-dire pour chaque foyer dans les ns par défaut, une limite de 4 vCPU et 1G sera fixée.



J'aimerais maintenant vous dire quels avantages l'installation de ces restrictions peut nous apporter.


Le mĂ©canisme d'Ă©quilibrage de charge entre les nƓuds


Comme vous le savez, le composant k8s tel que l' ordonnanceur , qui fonctionne selon un certain algorithme, est responsable de la rĂ©partition des foyers par noeuds. Cet algorithme en train de choisir le nƓud optimal Ă  exĂ©cuter passe par deux Ă©tapes:


  1. Filtrage
  2. Classement

C'est-Ă -dire selon la politique dĂ©crite, les nƓuds sont initialement sĂ©lectionnĂ©s sur lesquels un foyer peut ĂȘtre lancĂ© en fonction d'un ensemble de prĂ©dicats (y compris si le nƓud a suffisamment de ressources pour faire fonctionner un foyer - PodFitsResources), puis des points sont attribuĂ©s pour chacun de ces nƓuds, selon des prioritĂ©s (y compris, plus le nƓud dispose de ressources libres - plus il lui est attribuĂ© de points - LeastResourceAllocation / LeastRequestedPriority / BalancedResourceAllocation) et est exĂ©cutĂ© sur le nƓud avec le plus de points (si plusieurs nƓuds remplissent cette condition Ă  la fois, un alĂ©atoire est sĂ©lectionnĂ©).


Dans le mĂȘme temps, vous devez comprendre que le planificateur, lors de l'Ă©valuation des ressources disponibles du nƓud, se concentre sur les donnĂ©es stockĂ©es dans etcd - c'est-Ă -dire par la quantitĂ© de ressource demandĂ©e / limite de chaque pod s'exĂ©cutant sur ce nƓud, mais pas par la consommation rĂ©elle de ressources. Ces informations peuvent ĂȘtre obtenues dans la sortie de la commande kubectl describe node $NODE , par exemple:


 # 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, ie, overcommitted.) Resource Requests Limits -------- -------- ------ cpu 487m (3%) 822m (5%) memory 15856217600 (2%) 749976320 (3%) ephemeral-storage 0 (0%) 0 (0%) 

Ici, nous voyons tous les pods s'exĂ©cutant sur un nƓud particulier, ainsi que les ressources que chacun des pods demande. Et voici Ă  quoi ressemblent les journaux du planificateur lors du dĂ©marrage du pod cronjob-cron-events-1573793820-xt6q9 (ces informations apparaissent dans le journal du planificateur lors de la dĂ©finition du 10e niveau de journalisation dans les arguments de la commande de dĂ©marrage --v = 10):


goéland large
 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 

On voit ici qu'initialement le planificateur effectue un filtrage et forme une liste de 3 nƓuds sur lesquels il est possible de s'exĂ©cuter (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Il calcule ensuite des points selon plusieurs paramĂštres (dont BalancedResourceAllocation, LeastResourceAllocation) pour chacun de ces nƓuds afin de dĂ©terminer le nƓud le plus adaptĂ©. En fin de compte, il est prĂ©vu sous le nƓud avec le plus de points (ici, deux nƓuds ont Ă  la fois le mĂȘme nombre de points 100037, donc un alĂ©atoire est sĂ©lectionnĂ© - nxs-k8s-s10).


Conclusion : si les pods fonctionnent sur le nƓud pour lequel aucune restriction n'est dĂ©finie, alors pour les k8 (du point de vue de la consommation des ressources), cela sera Ă©quivalent Ă  comme si ces pods Ă©taient complĂštement absents sur ce nƓud. Par consĂ©quent, si vous avez, par convention, un pod avec un processus vorace (par exemple, wowza) et qu'il n'y a pas de restrictions pour cela, alors une situation peut se produire lorsque en fait celui donnĂ© a mangĂ© toutes les ressources du nƓud, mais en mĂȘme temps pour k8, ce nƓud est considĂ©rĂ© comme dĂ©chargĂ© et il se verra attribuer le mĂȘme nombre de points lors du classement (Ă  savoir, en points avec une Ă©valuation des ressources disponibles), ainsi qu'un nƓud qui n'a pas de pas de travail, ce qui peut finalement conduire Ă  une rĂ©partition inĂ©gale de la charge entre les nƓuds.


Expulsion du foyer


Comme vous le savez, chacun des pods se voit attribuer l'une des 3 classes QoS:


  1. guaranuted - est attribué lorsque la demande et la limite sont définies pour chaque conteneur dans l'ùtre pour la mémoire et le processeur, et ces valeurs doivent correspondre
  2. Ă©clatable - au moins un conteneur dans le foyer a une demande et une limite, tandis que la demande <limite
  3. meilleur effort - quand aucun récipient dans le foyer est limité en ressources

Dans le mĂȘme temps, lorsqu'il y a une pĂ©nurie de ressources (disque, mĂ©moire) sur le nƓud, kubelet commence Ă  classer et Ă  expulser les pods selon un certain algorithme qui prend en compte la prioritĂ© du pod et de sa classe QoS. Par exemple, si nous parlons de RAM, alors sur la base de la classe QoS, les points sont attribuĂ©s selon le principe suivant:


  • Garanti : -998
  • BestEffort : 1000
  • Burstable : min (max (2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

C'est-Ă -dire avec la mĂȘme prioritĂ©, kubelet expulsera d'abord les pods avec la classe de QoS avec le meilleur effort du nƓud.


Conclusion : si vous souhaitez rĂ©duire la probabilitĂ© d'expulsion du pod nĂ©cessaire du nƓud en cas de ressources insuffisantes, alors avec la prioritĂ©, vous devez Ă©galement prendre soin de dĂ©finir la demande / limite pour celui-ci.


MĂ©canisme de mise Ă  l'Ă©chelle horizontale du foyer d'application (HPA)


Lorsque la tùche consiste à augmenter et diminuer automatiquement le nombre de pod en fonction de l'utilisation des ressources (systÚme - CPU / RAM ou utilisateur - rps), une entité k8 comme HPA (Horizontal Pod Autoscaler) peut aider dans sa solution. Dont l'algorithme est le suivant:


  1. Les lectures actuelles de la ressource observée (currentMetricValue) sont déterminées
  2. Les valeurs souhaitées pour la ressource (desireMetricValue) sont déterminées, qui sont définies pour les ressources systÚme à l'aide de la demande
  3. Le nombre actuel de répliques est déterminé (currentReplicas)
  4. La formule suivante calcule le nombre souhaité de répliques (répliques souhaitées)
    desireReplicas = [currentReplicas * (currentMetricValue / desireMetricValue)]

Cependant, la mise Ă  l'Ă©chelle ne se produira pas lorsque le coefficient (currentMetricValue / desireMetricValue) est proche de 1 (nous pouvons dĂ©finir l'erreur admissible nous-mĂȘmes, par dĂ©faut, il est de 0,1).


Envisagez hpa en utilisant l'application de test d'application (dĂ©crite comme DĂ©ploiement), oĂč il est nĂ©cessaire de modifier le nombre de rĂ©pliques, en fonction de la consommation du processeur:


  • Manifeste d'application


     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 

    C'est-Ă -dire nous voyons que sous l'application, elle est initialement lancĂ©e dans deux instances, chacune contenant deux conteneurs nginx et nginx-exporter, pour chacun desquels des requĂȘtes pour le CPU sont donnĂ©es.


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

    C'est-à-dire nous avons créé un hpa qui surveillera le test d'application de déploiement et ajustera le nombre de foyers avec l'application en fonction de l'indicateur cpu (nous nous attendons à ce que le foyer consomme 30% pour cent du CPU demandé par lui), tandis que le nombre de répliques est compris entre 2 et 10.


    Maintenant, nous considérerons le mécanisme de fonctionnement hpa si nous appliquons une charge à l'un des foyers:


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


Au total, nous avons les éléments suivants:


  • Valeur souhaitĂ©e (dĂ©sirĂ©MetricValue) - selon les paramĂštres hpa, nous avons 30%
  • Valeur actuelle (currentMetricValue) - pour le calcul, le contrĂŽleur-gestionnaire calcule la valeur moyenne de la consommation de ressources en%, c'est-Ă -dire fait conditionnellement ce qui suit:
    1. Obtient les valeurs absolues des mesures de foyer du serveur de mesures, c.-Ă -d. 101m et 4m
    2. Calcule la valeur absolue moyenne, c'est-Ă -dire (101m + 4m) / 2 = 53m
    3. Obtient la valeur absolue de la consommation de ressources souhaitée (pour cela, la demande de tous les conteneurs est sommée) 60m + 30m = 90m
    4. Calcule le pourcentage moyen de la consommation du processeur par rapport au foyer de la demande 53 m / 90 m * 100% = 59%

Maintenant, nous avons tout le nécessaire pour déterminer s'il est nécessaire de changer le nombre de répliques, pour cela nous calculons le coefficient:


ratio = 59% / 30% = 1.96


C'est-Ă -dire le nombre de rĂ©pliques doit ĂȘtre augmentĂ© ~ 2 fois et constituer [2 * 1,96] = 4.


Conclusion: Comme vous pouvez le voir, pour que ce mécanisme fonctionne, une condition préalable est d'inclure la disponibilité des demandes pour tous les conteneurs dans l'ùtre observé.


Le mĂ©canisme de mise Ă  l'Ă©chelle automatique horizontale des nƓuds (Cluster Autoscaler)


Afin de neutraliser l'impact nĂ©gatif sur le systĂšme lors d'Ă©clats de charge, la prĂ©sence d'un hpa rĂ©glĂ© n'est pas suffisante. Par exemple, selon les paramĂštres du gestionnaire de contrĂŽleur hpa dĂ©cide que le nombre de rĂ©pliques doit ĂȘtre augmentĂ© de 2 fois, cependant, il n'y a pas de ressources libres sur les nƓuds pour exĂ©cuter un tel nombre de pods (c'est-Ă -dire que le nƓud ne peut pas fournir les ressources demandĂ©es pour les demandes de pod) et ces pods entrer dans l'Ă©tat En attente.


Dans ce cas, si le fournisseur dispose des IaaS / PaaS appropriĂ©s (par exemple, GKE / GCE, AKS, EKS, etc.), un outil tel que Node Autoscaler peut nous aider. Il vous permet de dĂ©finir le nombre maximal et minimal de nƓuds dans le cluster et d'ajuster automatiquement le nombre actuel de nƓuds (en accĂ©dant Ă  l'API du fournisseur de cloud pour commander / supprimer des nƓuds) lorsqu'il y a une pĂ©nurie de ressources dans le cluster et que les pods ne peuvent pas ĂȘtre planifiĂ©s (dans l'Ă©tat En attente).


Conclusion: pour pouvoir dimensionner automatiquement les nƓuds, il est nĂ©cessaire de spĂ©cifier des requĂȘtes dans les conteneurs de foyer afin que les k8 puissent Ă©valuer correctement la charge des nƓuds et signaler en consĂ©quence qu'il n'y a pas de ressources dans le cluster pour dĂ©marrer le foyer suivant.




Conclusion


Il convient de noter que la définition de limites de ressources pour le conteneur n'est pas une condition préalable au lancement réussi de l'application, mais il est toujours préférable de le faire pour les raisons suivantes:


  1. Pour un fonctionnement plus prĂ©cis du planificateur en termes d'Ă©quilibrage de charge entre les nƓuds k8s
  2. Pour réduire la probabilité d'un événement d'éviction du foyer
  3. Pour les foyers d'application Ă  mise Ă  l'Ă©chelle horizontale (HPA)
  4. Pour une mise Ă  l'Ă©chelle automatique horizontale des nƓuds (mise Ă  l'Ă©chelle automatique de cluster) pour les fournisseurs de cloud

Lisez Ă©galement d'autres articles sur notre blog:


Source: https://habr.com/ru/post/fr480072/


All Articles