En gĂ©nĂ©ral, il est toujours nĂ©cessaire de fournir un pool de ressources dĂ©diĂ©es Ă une application pour son bon fonctionnement. Mais que faire si plusieurs applications fonctionnent sur les mĂȘmes ressources ? Comment garantir que chacune d'elles dispose du minimum nĂ©cessaire ? Comment limiter la consommation de ressources ? Comment rĂ©partir efficacement la charge entre les nĆuds ? Comment faire en sorte que le mĂ©canisme de mise Ă l'Ă©chelle horizontale fonctionne lors d'une augmentation de la charge sur les applications ?

Il faut d'abord tenir compte des principaux types de ressources disponibles dans le systĂšme â Ă savoir le temps processeur et la mĂ©moire vive. Dans les manifestes k8s, ces types de ressources sont mesurĂ©s dans les unitĂ©s suivantes :
- CPU â en cĆurs
- RAM â en octets
Pour chaque ressource, il est possible de dĂ©finir deux types de demandes â requests et limits. Requests â dĂ©crit les exigences minimales en termes de ressources libre sur le nĆud pour faire fonctionner le conteneur (et le pod en gĂ©nĂ©ral), tandis que limits fixe une limite stricte des 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 seul limits est spĂ©cifiĂ© pour la ressource, alors requests pour cette ressource prend automatiquement la valeur de limits (ce qui peut ĂȘtre vĂ©rifiĂ© en appelant describe de l'entitĂ©). Cela signifie que le fonctionnement du conteneur sera limitĂ© au mĂȘme nombre de ressources dont il a besoin pour son lancement.
- Si seules requests sont spĂ©cifiĂ©es pour la ressource, aucune restriction supĂ©rieure n'est imposĂ©e â c'est-Ă -dire que le conteneur n'est limitĂ© que par les ressources du nĆud lui-mĂȘme.
Il est également possible de gérer les ressources non seulement au niveau du conteneur spécifique, mais aussi au niveau du namespace à l'aide des entités suivantes :
- LimitRange â dĂ©crit la politique de limitation au niveau du conteneur/pod dans le ns et est nĂ©cessaire pour dĂ©finir les limitations par dĂ©faut sur le conteneur/pod, ainsi que pour prĂ©venir la crĂ©ation de conteneurs/pods manifestement surdimensionnĂ©s (ou inversement), limiter leur quantitĂ© et dĂ©terminer la diffĂ©rence possible entre les limits et requests.
- ResourceQuotas â dĂ©crit la politique de limitation en gĂ©nĂ©ral pour tous les conteneurs dans le ns et est gĂ©nĂ©ralement utilisĂ©e pour la rĂ©partition des ressources par environnement (utile lorsque les environnements ne sont pas strictement sĂ©parĂ©s au niveau des nĆuds)
Ci-dessous sont des exemples de manifestes oĂč des limites de ressources sont Ă©tablies :
Au niveau d'un conteneur spécifique :
containers: - name: app-nginx image: nginx resources: requests: memory: 1Gi limits: cpu: 200mC'est-Ă -dire que, dans ce cas, pour exĂ©cuter un conteneur avec nginx, il faut au minimum avoir 1G de RAM libre et 0,2 CPU sur le nĆud, tout en sachant que le conteneur peut consommer jusqu'Ă 0,2 CPU et toute la RAM disponible sur le nĆud.
Au niveau de tout le ns :
apiVersion: v1 kind: ResourceQuota metadata: name: nxs-test spec: hard: requests.cpu: 300m requests.memory: 1Gi limits.cpu: 700m limits.memory: 2GiC'est-à -dire que la somme de toutes les demandes des conteneurs dans le ns par défaut ne peut pas dépasser 300m pour le CPU et 1G pour la RAM, tandis que la somme de toutes les limites ne peut pas dépasser 700m pour le CPU et 2G pour la RAM.
Limites par défaut pour les conteneurs dans le 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: 4GiC'est-à -dire que dans le namespace par défaut, une demande de 100m pour le CPU et 1G pour la RAM sera établie par défaut pour tous les conteneurs, avec une limite de 1 CPU et 2G. De plus, une restriction sur les valeurs possibles dans la demande/limite pour le CPU (50m < x < 2) et la RAM (500M < x < 4G) est également définie.
Limites au niveau des pods dans le ns :
apiVersion: v1 kind: LimitRange metadata: name: nxs-limit-pod spec: limits: - type: Pod max: cpu: 4 memory: 1GiC'est-à -dire que pour chaque pod dans le ns par défaut, une limite de 4 vCPU et 1G sera appliquée.
Maintenant, j'aimerais parler des avantages que nous pouvons tirer de l'établissement de ces limites.
MĂ©canisme d'Ă©quilibrage de charge entre les nĆuds
Comme nous le savons, la rĂ©partition des pods entre les nĆuds est assurĂ©e par un composant de k8s, scheduler, qui fonctionne selon un certain algorithme. Cet algorithme passe par deux Ă©tapes lors du choix du nĆud optimal pour le lancement :
- Filtrage
- Classement
C'est-Ă -dire qu'en fonction de la politique dĂ©crite, les nĆuds sur lesquels le pod peut ĂȘtre exĂ©cutĂ© sont initialement sĂ©lectionnĂ©s sur la base de plusieurs predicates (y compris la vĂ©rification que la ressource du nĆud est suffisante pour exĂ©cuter le pod â PodFitsResources), puis pour chacun de ces nĆuds, selon priorities des points sont attribuĂ©s (plus les ressources de la node sont libres, plus elle reçoit de points â LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) et se lance sur la node avec le plus de points (si plusieurs nodes remplissent cette condition, l'une d'elles est choisie au hasard).
Il faut comprendre que le scheduler Ă©value les ressources disponibles de la node en se basant sur les donnĂ©es stockĂ©es dans etcd â c'est-Ă -dire sur la somme des ressources demandĂ©es/limites de chaque pod lancĂ© sur cette node, mais pas sur la consommation rĂ©elle des ressources. Ces informations peuvent ĂȘtre obtenues en exĂ©cutant 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, i.e., 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 lancĂ©s sur une node spĂ©cifique ainsi que les ressources requises par chacun d'eux. Voici Ă quoi ressemblent les logs du scheduler lors du lancement du pod cronjob-cron-events-1573793820-xt6q9 (ces informations apparaĂźtront dans les logs du scheduler si le niveau de log est rĂ©glĂ© sur 10 lors de l'exĂ©cution en dĂ©finissant les arguments de la commande âv=10) :
log
I1115 07:57:21.637791 1 scheduling_queue.go:908] Tentative de planifier le pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.637804 1 scheduler.go:453] Tentative de planifier le pod : nxs-stage\/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.638285 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s5 est autorisĂ©e, le nĆud exĂ©cute seulement 16 sur 110 pods.
I1115 07:57:21.638300 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s6 est autorisĂ©e, le nĆud exĂ©cute seulement 20 sur 110 pods.
I1115 07:57:21.638322 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s3 est autorisĂ©e, le nĆud exĂ©cute seulement 20 sur 110 pods.
I1115 07:57:21.638322 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s4 est autorisĂ©e, le nĆud exĂ©cute seulement 17 sur 110 pods.
I1115 07:57:21.638334 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s10 est autorisĂ©e, le nĆud exĂ©cute seulement 16 sur 110 pods.
I1115 07:57:21.638365 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s12 est autorisĂ©e, le nĆud exĂ©cute seulement 9 sur 110 pods.
I1115 07:57:21.638334 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s11 est autorisĂ©e, le nĆud exĂ©cute seulement 11 sur 110 pods.
I1115 07:57:21.638385 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s1 est autorisĂ©e, le nĆud exĂ©cute seulement 19 sur 110 pods.
I1115 07:57:21.638402 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s2 est autorisĂ©e, le nĆud exĂ©cute seulement 21 sur 110 pods.
I1115 07:57:21.638383 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s9 est autorisĂ©e, le nĆud exĂ©cute seulement 16 sur 110 pods.
I1115 07:57:21.638335 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s8 est autorisĂ©e, le nĆud exĂ©cute seulement 18 sur 110 pods.
I1115 07:57:21.638408 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s13 est autorisĂ©e, le nĆud exĂ©cute seulement 8 sur 110 pods.
I1115 07:57:21.638478 1 predicates.go:1369] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s10 est autorisĂ©e, les termes d'anti-affinitĂ© des pods existants sont satisfaits.
I1115 07:57:21.638505 1 predicates.go:1369] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s8 est autorisĂ©e, les termes d'anti-affinitĂ© des pods existants sont satisfaits.
I1115 07:57:21.638577 1 predicates.go:1369] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s9 est autorisĂ©e, les termes d'anti-affinitĂ© des pods existants sont satisfaits.
I1115 07:57:21.638583 1 predicates.go:829] La planification du pod nxs-stage\/cronjob-cron-events-1573793820-xt6q9 sur le nĆud nxs-k8s-s7 est autorisĂ©e, le nĆud exĂ©cute seulement 25 sur 110 pods.
I1115 07:57:21.638932 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10 : AllocationRessourceĂquilibrĂ©e, capacitĂ© 39900 millicores 66620178432 octets mĂ©moire, demande totale 2343 millicores 9640186880 octets mĂ©moire, score 9
I1115 07:57:21.638946 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10 : AllocationRessourceMinimale, capacité 39900 millicores 66620178432 octets mémoire, demande totale 2343 millicores 9640186880 octets mémoire, score 8
I1115 07:57:21.638961 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9 : AllocationRessourceĂquilibrĂ©e, capacitĂ© 39900 millicores 66620170240 octets mĂ©moire, demande totale 4107 millicores 11307422720 octets mĂ©moire, score 9
I1115 07:57:21.638971 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8 : AllocationRessourceĂquilibrĂ©e, capacitĂ© 39900 millicores 66620178432 octets mĂ©moire, demande totale 5847 millicores 24333637120 octets mĂ©moire, score 7
I1115 07:57:21.638975 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9 : AllocationRessourceMinimale, capacité 39900 millicores 66620170240 octets mémoire, demande totale 4107 millicores 11307422720 octets mémoire, score 8
I1115 07:57:21.638990 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8 : AllocationRessourceMinimale, capacité 39900 millicores 66620178432 octets mémoire, demande totale 5847 millicores 24333637120 octets mémoire, score 7
I1115 07:57:21.639022 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10 : PrioritéToléranceTaints, Score : (10)
I1115 07:57:21.639030 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8 : PrioritéToléranceTaints, Score : (10)
I1115 07:57:21.639034 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9 : PrioritéToléranceTaints, Score : (10)
I1115 07:57:21.639041 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10 : PrioritĂ©AffinitĂ©NĆud, Score : (0)
I1115 07:57:21.639053 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8 : PrioritĂ©AffinitĂ©NĆud, Score : (0)
I1115 07:57:21.639059 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9 : PrioritĂ©AffinitĂ©NĆud, Score : (0)
I1115 07:57:21.639061 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10 : PrioritéAffinitéInterPod, Score : (0)
I1115 07:57:21.639063 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10 : PrioritéRépartitionSélecteur, Score : (10)
I1115 07:57:21.639073 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8 : PrioritéAffinitéInterPod, Score : (0)
I1115 07:57:21.639077 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8 : PrioritéRépartitionSélecteur, Score : (10)
I1115 07:57:21.639085 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9 : PrioritéAffinitéInterPod, Score : (0)
I1115 07:57:21.639088 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9 : PrioritéRépartitionSélecteur, Score : (10)
I1115 07:57:21.639103 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10 : PrioritéRépartitionSélecteur, Score : (10)
I1115 07:57:21.639109 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8 : PrioritéRépartitionSélecteur, Score : (10)
I1115 07:57:21.639114 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9 : PrioritéRépartitionSélecteur, Score : (10)
I1115 07:57:21.639127 1 generic_scheduler.go:781] HĂŽte nxs-k8s-s10 => Score 100037
I1115 07:57:21.639150 1 generic_scheduler.go:781] HĂŽte nxs-k8s-s8 => Score 100034
I1115 07:57:21.639154 1 generic_scheduler.go:781] HĂŽte nxs-k8s-s9 => Score 100037
I1115 07:57:21.639267 1 scheduler_binder.go:269] AssumerVolumesPod pour le pod "nxs-stage\/cronjob-cron-events-1573793820-xt6q9", nĆud "nxs-k8s-s10"
I1115 07:57:21.639286 1 scheduler_binder.go:279] AssumerVolumesPod pour le pod "nxs-stage\/cronjob-cron-events-1573793820-xt6q9", nĆud "nxs-k8s-s10" : tous les PVC sont liĂ©s et rien Ă faire
I1115 07:57:21.639333 1 factory.go:733] Tentative de lier cronjob-cron-events-1573793820-xt6q9 Ă nxs-k8s-s10Ici, nous voyons qu'initialement, le scheduler effectue une filtration et forme une liste de 3 nĆuds sur lesquels un dĂ©ploiement est possible (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Il procĂšde ensuite au calcul des points selon plusieurs paramĂštres (y compris BalancedResourceAllocation, LeastResourceAllocation) pour chacun de ces nĆuds afin de dĂ©terminer le nĆud le plus appropriĂ©. En fin de compte, le dĂ©ploiement se fait sur le nĆud avec le plus grand nombre de points (ici, deux nĆuds ont le mĂȘme score de 100037, donc un est choisi au hasard â nxs-k8s-s10).
Sortie: si des pods fonctionnent sur un nĆud sans limitations dĂ©finies, cela signifie pour k8s (en termes de consommation de ressources) qu'il est Ă©quivalent Ă la situation oĂč ces pods n'existent pas sur ce nĆud. Donc, si vous avez, par exemple, un pod avec un processus gourmand (comme wowza) et qu'aucune limite n'est dĂ©finie, il pourrait arriver que ce pod consomme toutes les ressources du nĆud, mais pour k8s, ce nĆud est considĂ©rĂ© comme non chargĂ© et recevra le mĂȘme nombre de points lors du classement (dans les points d'Ă©valuation des ressources disponibles), qu'un nĆud sans pods en fonctionnement, ce qui peut finalement conduire Ă une rĂ©partition inĂ©gale de la charge entre les nĆuds.
Ăviction d'un pod
Comme on le sait, à chaque pod est attribuée l'une des 3 classes QoS :
- garanti â attribuĂ©e lorsque, pour chaque conteneur dans le pod, un request et un limit de mĂ©moire et CPU sont dĂ©finis, ces valeurs devant coĂŻncider
- instances burstable. â lorsqu'au moins un conteneur dans le pod a un request et un limit, avec request < limit
- meilleur effort â lorsque aucun conteneur dans le pod n'est limitĂ© en ressources
Cependant, lorsque le nĆud manque de ressources (disque, mĂ©moire), kubelet commence Ă classer et Ă Ă©vincer les pods selon un algorithme dĂ©terminĂ©, tenant compte de la prioritĂ© du pod et de sa classe QoS. Par exemple, en ce qui concerne la RAM, des points sont attribuĂ©s selon la classe QoS selon le principe suivant :
- Guaranteed: -998
- BestEffort: 1000
- Burstable: min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
Ainsi, avec une priorité identique, kubelet évincera en priorité les pods avec la classe QoS meilleur effort.
Sortie: si vous souhaitez rĂ©duire la probabilitĂ© d'Ă©viction d'un pod important sur un nĆud en cas de manque de ressources, il est nĂ©cessaire, en plus de la prioritĂ©, de s'assurer de dĂ©finir un request/limit pour celui-ci.
Mécanisme de mise à l'échelle horizontale automatique des pods d'application (HPA)
Lorsqu'il s'agit d'augmenter ou de diminuer automatiquement le nombre de pods en fonction de l'utilisation des ressources (systĂšme â CPU/RAM ou utilisateur â rps), une entitĂ© k8s telle que HPA (Horizontal Pod Autoscaler) peut aider dans cette solution. Son algorithme est le suivant :
- Les valeurs des ressources observées actuelles (currentMetricValue) sont déterminées
- Les valeurs souhaitées pour la ressource (desiredMetricValue) sont déterminées, qui pour les ressources systÚme sont définies à l'aide de la demande
- Le nombre actuel de répliques (currentReplicas) est déterminé
- Le nombre de répliques souhaité (desiredReplicas) est calculé selon la formule suivante
desiredReplicas = [ currentReplicas * ( currentMetricValue / desiredMetricValue )]
Cependant, la mise Ă l'Ă©chelle ne se produira pas lorsque le coefficient (currentMetricValue / desiredMetricValue) est proche de 1 (nous pouvons dĂ©finir la tolĂ©rance nous-mĂȘmes, par dĂ©faut elle est de 0,1).
ConsidĂ©rons le fonctionnement de l'HPA Ă l'aide de l'application app-test (dĂ©crite comme un dĂ©ploiement), oĂč il est nĂ©cessaire de modifier le nombre de rĂ©pliques en fonction de la consommation du CPU :
Manifeste de l'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-statusC'est-à -dire que nous voyons que le pod avec l'application est initialement exécuté en deux exemplaires, chacun contenant deux conteneurs nginx et nginx-exporter, pour lesquels est défini requests pour le CPU.
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: 30C'est-à -dire que nous avons créé un HPA qui surveillera le déploiement app-test et régulera le nombre de pods avec l'application en fonction de l'indicateur de CPU (nous nous attendons à ce que le pod consomme 30 % de l'CPU qui lui est demandé), tout en maintenant le nombre de répliques dans la plage de 2 à 10.
Maintenant, considérons le mécanisme de fonctionnement de l'HPA, si une charge est appliquée à l'un des pods :
# kubectl top pod NAME CPU(cores) MEMORY(bytes) app-test-78559f8f44-pgs58 101m 243Mi app-test-78559f8f44-cj4jz 4m 240Mi
En résumé, nous avons ce qui suit :
- La valeur dĂ©sirĂ©e (desiredMetricValue) â selon les paramĂštres hpa, est de 30%
- La valeur actuelle (currentMetricValue) â pour le calcul, le controller-manager Ă©value la consommation moyenne des ressources en %, c'est-Ă -dire qu'il effectue l'opĂ©ration suivante :
- Il obtient les valeurs absolues des métriques des pods à partir du serveur de métriques, c'est-à -dire 101m et 4m
- Il calcule la valeur moyenne absolue, c'est-Ă -dire (101m + 4m) / 2 = 53m
- Il obtient la valeur absolue pour la consommation souhaitĂ©e de ressources (pour cela, il additionne les requĂȘtes de tous les conteneurs) 60m + 30m = 90m
- Il calcule le pourcentage moyen de consommation CPU par rapport Ă la demande du pod, c'est-Ă -dire 53m / 90m * 100% = 59%
Maintenant, nous avons tout ce qu'il faut pour dĂ©terminer si le nombre de rĂ©plicas doit ĂȘtre modifiĂ©, pour cela, nous calculons le ratio :
ratio = 59% / 30% = 1.96
C'est-Ă -dire que le nombre de rĂ©plicas doit ĂȘtre multipliĂ© par ~2, ce qui donne [2 * 1.96] = 4.
Conclusion : Comme on peut le constater, pour que ce mĂ©canisme fonctionne, il est Ă©galement nĂ©cessaire d'avoir des requĂȘtes pour tous les conteneurs dans le pod observĂ©.
MĂ©canisme d'autoscaling horizontal des nĆuds (Cluster Autoscaler)
Pour attĂ©nuer l'impact nĂ©gatif sur le systĂšme lors de pics de charge, le simple fait d'avoir un hpa configurĂ© peut ne pas suffire. Par exemple, selon les paramĂštres dans le hpa, le manager du contrĂŽleur dĂ©cide que le nombre de rĂ©plicas doit ĂȘtre multipliĂ© par 2, cependant, il n'y a pas de ressources libres sur les nĆuds pour exĂ©cuter ce nombre de pods (c'est-Ă -dire que le nĆud ne peut pas fournir les ressources demandĂ©es par les pods). Ces pods passent alors dans un Ă©tat Pending.
Dans ce cas, si le fournisseur dispose d'une IaaS/PaaS appropriĂ©e (par exemple, GKE/GCE, AKS, EKS, etc.), un outil tel que Node Autoscaler. Cela permet de dĂ©finir un nombre maximal et minimal de nĆuds dans le cluster et de rĂ©guler automatiquement le nombre actuel de nĆuds (en appelant l'API du fournisseur cloud pour commander/supprimer un nĆud), lorsque des pĂ©nuries de ressources sont observĂ©es dans le cluster et que les pods ne peuvent pas ĂȘtre programmĂ©s (se trouvent en Ă©tat Pending).
Conclusion : Pour permettre l'autoscaling des nĆuds, il est nĂ©cessaire de dĂ©finir des requĂȘtes dans les conteneurs des pods, afin que k8s puisse Ă©valuer correctement la charge des nĆuds et indiquer qu'il n'y a pas suffisamment de ressources dans le cluster pour dĂ©marrer le prochain pod.
Conclusion
Il convient de noter que la mise en place de limites de ressources pour le conteneur n'est pas une condition nécessaire au démarrage réussi de l'application, mais il est néanmoins préférable de le faire pour les raisons suivantes :
- Pour un fonctionnement plus prĂ©cis du scheduler en ce qui concerne la rĂ©partition de la charge entre les nĆuds k8s
- Pour réduire la probabilité de l'événement "expulsion du pod"
- Pour le fonctionnement de l'autoscaling horizontal des pods de l'application (HPA)
- Pour le fonctionnement de l'autoscaling horizontal des nĆuds (Cluster Autoscaling) chez les fournisseurs de cloud
Lisez aussi d'autres articles sur notre blog :
Source : habr.com
