Comment accéder aux ressources du pod Kubernetes

La récompense de Tohad



Lorsque vous débutez avec Kubernetes, il est courant d'oublier la configuration des ressources du conteneur. À ce stade, il vous suffit de vous assurer que l'image Docker fonctionne et peut être déployée sur votre cluster Kubernetes.



Mais plus tard, l'application doit être déployée sur le cluster de production avec d'autres applications. Pour ce faire, vous devez allouer des ressources pour le conteneur et vous assurer qu'il y a suffisamment de ressources pour démarrer et exécuter l'application, et dans d'autres applications en cours d'exécution, il n'y aura aucun problème.



L'équipe aaS de Kubernetes de Mail.ru a traduit un article sur les ressources des conteneurs (CPU et MEM), les demandes et les limites de ressources. Vous découvrirez les avantages de ces paramètres et ce qui se passe si vous ne les installez pas.



Ressources informatiques



Nous avons deux types de ressources avec les unités suivantes:



  • Unité centrale de traitement (CPU) - cœurs;
  • Mémoire (MEM) - octets.


Les ressources sont spécifiées pour chaque conteneur. Dans le fichier de pod YAML suivant, vous verrez une section de ressources qui contient les ressources demandées et limites:



  • Ressources de pod demandées = la somme des ressources demandées de tous les pods;
  • Limiter les ressources de pod = la somme des ressources marginales de tous les conteneurs.


apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-name
  labels:
    application: backend
spec:
  containers:
    — name: main-container
      image: my-backend
      tag: v1
      ports:
      — containerPort: 8080
      resources:
        requests:
          cpu: 0.2 # REQUESTED CPU: 200m cores
          memory: "1Gi" # REQUESTED MEM: 1Gi
        limits:
          cpu: 1 # MAX CPU USAGE: 1 core
          memory: "1Gi" # MAX MEM USAGE:  1Gi
    — name: other-container
      image: other-app
      tag: v1
      ports:
      — containerPort: 8000
      resources:
        requests:
          cpu: "200m" # REQUESTED CPU: 200m cores
          memory: "0.5Gi" # REQUESTED MEM: 0.5Gi
        limits:
          cpu: 1 # MAX CPU USAGE: 1 core
          memory: "1Gi" # MAX MEM USAGE:  1Gi
Exemple de ressources demandées et limites Un



champ resources.requestedde la spécification du pod est l'un des éléments utilisés pour trouver le nœud souhaité. Déjà dessus, vous pouvez planifier un déploiement de pod. Comment trouvez-vous un nœud approprié?



Kubernetes se compose de plusieurs composants, y compris le nœud maître ou le nœud maître (plan de contrôle Kubernetes). Il existe plusieurs processus dans le nœud maître: kube-apiserver, kube-controller-manager et kube-scheduler.



Le processus kube-scheduler est chargé d'examiner les modules nouvellement créés et de rechercher les nœuds de travail possibles qui correspondent à toutes les demandes de module, y compris le nombre de ressources demandées. La liste des nœuds trouvés par kube-scheduler est classée. Le pod est prévu pour le site avec les scores les plus élevés.



Où le pod violet sera-t-il placé?



L'image montre que kube-scheduler devrait programmer un nouveau pod violet. Le cluster Kubernetes contient deux nœuds: A et B. Comme vous pouvez le voir, kube-scheduler ne peut pas planifier un pod sur le nœud A - les ressources disponibles (non sollicitées) ne correspondent pas aux demandes du pod violet. Par exemple, la mémoire de 1 Go demandée par le pod violet ne rentrera pas sur le nœud A, car la mémoire disponible est de 0,5 Go. Mais le nœud B a suffisamment de ressources. En conséquence, kube-scheduler décide que la destination du Pod violet est le Node B.



Maintenant, nous savons comment les ressources demandées affectent le choix du nœud pour démarrer le Pod. Mais comment les ressources marginales affectent-elles?



Les ressources limites sont une limite que la CPU / MEM ne peut pas franchir. Cependant, le processeur est flexible, de sorte que les conteneurs qui atteignent la limite du processeur ne provoquent pas l'arrêt du pod. Au lieu de cela, la limitation du processeur démarre. Si la limite d'utilisation de MEM est atteinte, le conteneur sera arrêté en raison de OOM-Killer et redémarré, si le paramètre RestartPolicy l'autorise.



Demandé et limiter les ressources en détail



Relation de ressources entre Docker et Kubernetes La



meilleure façon d'expliquer le fonctionnement des ressources demandées et limitées est de représenter la relation entre Kubernetes et Docker. Dans l'image ci-dessus, vous pouvez voir comment les champs Kubernetes et les indicateurs de lancement Docker sont liés.



Mémoire: demande et limite



containers:
...
 resources:
   requests:
     memory: "0.5Gi"
   limits:
     memory: "1Gi"


Comme mentionné ci-dessus, la mémoire est mesurée en octets. Sur la base de la documentation Kubernetes , nous pouvons spécifier la mémoire sous forme de nombre. Il s'agit généralement d'un entier, par exemple 2678 - soit 2678 octets. Vous pouvez également utiliser des suffixes Get Gi, surtout, rappelez-vous qu'ils ne sont pas équivalents. Le premier est décimal et le second est binaire. À titre d'exemple, mentionné dans la documentation K8S: 128974848, 129e6, 129M, 123Mi- ils sont pratiquement équivalents.



Le paramètre Kubernetes limits.memorycorrespond à l'indicateur --memoryde Docker. En cas derequest.memoryil n'y a pas de flèche pour Docker car Docker n'utilise pas ce champ. Vous pouvez demander si cela est nécessaire du tout? Oui besoin. Comme je l'ai déjà dit, le domaine est important pour Kubernetes. Sur la base des informations qu'il contient, kube-scheduler décide sur quel nœud planifier le pod.



Que se passe-t-il s'il n'y a pas assez de mémoire installée pour une requête?



Si le conteneur atteint les limites de la mémoire demandée, le pod est placé dans le groupe Pod, qui s'arrête lorsqu'il n'y a pas de mémoire dans le nœud.



Que se passe-t-il si vous définissez la limite de mémoire trop faible?



Si le conteneur dépasse la limite de mémoire, il sera arrêté en raison de OOM-Killed. Et sera redémarré si possible en fonction de RestartPolicy, où la valeur par défaut est Always.



Que se passe-t-il si vous ne spécifiez pas la mémoire demandée?



Kubernetes prendra la limite et la définira comme valeur par défaut.



Que peut-il se passer si vous ne spécifiez pas la limite de mémoire?



Le conteneur n'a pas de limites, il peut utiliser autant de mémoire qu'il le souhaite. S'il commence à utiliser toute la mémoire disponible du nœud, alors MOO le tuera. Le conteneur sera ensuite redémarré si possible en fonction de RestartPolicy.



Que se passe-t-il si vous ne spécifiez pas de limites de mémoire?



C'est le pire des cas: le planificateur ne sait pas de combien de ressources le conteneur a besoin, ce qui peut entraîner de graves problèmes sur le nœud. Dans ce cas, il serait bien d'avoir des contraintes d'espace de noms par défaut (définies par LimitRange). Il n'y a pas de limites par défaut - le Pod n'a pas de limites, il peut utiliser autant de mémoire qu'il le souhaite.



Si la mémoire demandée est supérieure à ce que le nœud peut offrir, le pod ne sera pas planifié. Il est important de se rappeler qu'il Requests.memoryne s'agit pas d'une valeur minimale. Il s'agit d'une description de la quantité de mémoire suffisante pour que le conteneur fonctionne en continu.



Il est généralement recommandé de définir la même valeur pour request.memoryetlimit.memory... Cela empêche Kubernetes de planifier un pod sur un nœud qui a suffisamment de mémoire pour exécuter le pod mais pas assez pour s'exécuter. Gardez à l'esprit: lors de la planification d'un pod, Kubernetes compte uniquement requests.memory, limits.memorypas compte.



CPU: demande et limite



containers:
...
 resources:
   requests:
     cpu: 1
   limits:
     cpu: "1200m"


Avec le CPU, tout est un peu plus compliqué. Pour en revenir à l'image de la relation entre Kubernetes et Docker, vous pouvez voir qu'elle request.cpucorrespond --cpu-shares, alors qu'elle limit.cpucorrespond à l'indicateur cpusdans Docker.



Le processeur demandé par Kubernetes est multiplié par 1024, la proportion de cycles du processeur. Si vous souhaitez demander 1 cœur complet, vous devez ajouter cpu: 1comme indiqué ci-dessus.



Demander un noyau complet (proportion = 1024) ne signifie pas que votre conteneur le recevra. Si votre machine hôte n'a qu'un seul cœur et que vous utilisez plusieurs conteneurs, tous les conteneurs doivent partager le processeur disponible entre eux. Comment cela peut-il arriver? Jetons un coup d'oeil à l'image.





Demande de CPU - Système à



un seul cœur Supposons que vous ayez un système hôte à un seul cœur exécutant des conteneurs. Maman (Kubernetes) a préparé un gâteau (CPU) et veut le partager avec les enfants (conteneurs). Trois enfants veulent un gâteau entier (proportion = 1024), un autre enfant veut la moitié du gâteau (512). Maman veut être juste et fait un calcul simple.



#    ?
# 3           
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
#   :
3 (/) * 1 ( / ) + 1 (/) * 0.5 ( / )
#   ?
availableCakesNumber = 1
#   ()    ?
newMaxRequest = 1 / 3.5 =~ 28%


Sur la base du calcul, trois enfants recevront 28% du noyau, et non le noyau entier. Le quatrième enfant recevra 14% du noyau complet, pas la moitié. Mais les choses seront différentes si vous avez un système multicœur.





Demande CPU - Système multicœur (4)



Dans l'image ci-dessus, vous pouvez voir que trois enfants veulent une tarte entière et un en veut la moitié. Puisque maman a cuisiné quatre gâteaux, chacun de ses enfants en recevra autant qu'il le souhaite. Dans un système multicœur, les ressources du processeur sont réparties sur tous les cœurs de processeur disponibles. Si un conteneur est limité à moins d'un cœur de processeur complet, il peut toujours l'utiliser à 100%.



Les calculs ci-dessus sont simplifiés pour comprendre comment le processeur est alloué entre les conteneurs. Bien sûr, en plus des conteneurs eux-mêmes, il existe d'autres processus qui utilisent également des ressources CPU. Lorsque les processus d'un conteneur sont inactifs, d'autres peuvent utiliser sa ressource. CPU: "200m"correspond CPU: 0,2, ce qui signifie environ 20% d'un noyau.



Maintenant parlons delimit.cpu... Le processeur qui limite Kubernetes est multiplié par 100. Le résultat est le temps que le conteneur peut utiliser toutes les 100 μs ( cpu-period).



limit.cpucorrespond à l'indicateur Docker --cpus. C'est une nouvelle combinaison d'ancien --cpu-periodet de --cpu-quota. En le définissant, nous spécifions le nombre maximal de ressources CPU disponibles que le conteneur peut utiliser jusqu'à ce qu'il commence la limitation:



  • cpus est une combinaison de cpu-periodet cpu-quota. cpus = 1.5équivaut au réglage cpu-period = 100000et cpu-quota = 150000;
  • cpu-period - Période du planificateur CFS du processeur , par défaut 100 microsecondes;
  • cpu-quota - le nombre de microsecondes à l'intérieur duquel cpu-periodle conteneur est limité.


Que se passe-t-il si le processeur demandé est insuffisant?



Si le conteneur a besoin de plus qu'il n'est installé, il volera le processeur d'autres processus.



Que se passe-t-il si vous définissez une limite de processeur insuffisante?



Étant donné que la ressource CPU est réglable, la limitation s'active.



Que se passe-t-il si vous ne spécifiez pas de demande de processeur?



Comme pour la mémoire, la valeur de la demande est égale à la limite.



Que se passe-t-il si vous ne spécifiez pas la limite du processeur?



Le conteneur utilisera autant de CPU qu'il en a besoin. Si une stratégie de processeur par défaut (LimitRange) est définie dans l'espace de noms, cette limite est également utilisée pour le conteneur.



Que se passe-t-il si vous ne spécifiez ni la demande ni la limite du processeur?



Comme pour la mémoire, c'est le pire des cas. Le planificateur ne sait pas de combien de ressources votre conteneur a besoin, ce qui peut entraîner de graves problèmes sur le nœud. Pour éviter cela, vous devez définir les limites par défaut pour les espaces de noms (LimitRange).



N'oubliez pas que si vous demandez plus de CPU que ce que les nœuds peuvent fournir, le pod ne sera pas planifié. Requests.cpu- pas une valeur minimale, mais une valeur suffisante pour démarrer le Pod et fonctionner sans échec. Si votre application n'effectue pas de calculs complexes, la meilleure option est d'installer request.cpu <= 1et d'exécuter autant de réplicas que nécessaire.



Quantité idéale de ressources demandées ou limite de ressources



Nous avons appris la limitation des ressources informatiques. Il est maintenant temps de répondre à la question: «De combien de ressources mon pod a-t-il besoin pour exécuter l'application sans problème? Quelle est la quantité idéale? "



Malheureusement, il n'y a pas de réponses définitives à ces questions. Si vous ne savez pas comment votre application fonctionne, combien de CPU ou de mémoire elle a besoin, la meilleure option est de donner à l'application beaucoup de mémoire et de CPU, puis d'exécuter des tests de performances.



En plus des tests de performances, observez le comportement de surveillance de l'application pendant une semaine. Si les graphiques montrent que votre application consomme moins de ressources que ce que vous avez demandé, vous pouvez réduire la quantité de CPU ou de mémoire demandée.



Voir ce tableau de bord Grafana comme exemple .... Il affiche la différence entre les ressources demandées ou la limite de ressources et l'utilisation actuelle des ressources.



Conclusion



L'interrogation et la limitation des ressources permettent de maintenir votre cluster Kubernetes sain. La configuration correcte des limites minimise les coûts et permet aux applications de fonctionner à tout moment.



En bref, il y a quelques points à garder à l'esprit:



  1. Les ressources demandées sont la configuration qui est prise en compte lors du démarrage (lorsque Kubernetes prévoit d'héberger l'application). En revanche, la limitation des ressources est importante au moment de l'exécution - lorsque l'application est déjà en cours d'exécution sur le nœud.
  2. Par rapport à la mémoire, le processeur est une ressource régulée. En cas de CPU insuffisant, votre Pod ne s'éteindra pas, il commencera à ralentir.
  3. Les ressources demandées et la limite de ressources ne sont pas des valeurs minimales et maximales! En identifiant les ressources demandées, vous vous assurez du bon fonctionnement de votre application.
  4. Il est recommandé de définir la demande de mémoire égale à la limite de mémoire.
  5. Il est bon d'installer comme demandé CPU <=1si l'application n'effectue pas de calculs complexes.
  6. Si vous demandez plus de ressources que le nœud n'en a, le pod ne sera jamais planifié pour ce nœud.
  7. Utilisez les tests de charge et la surveillance pour déterminer la quantité correcte de ressources / limites de ressources demandées.


J'espère que cet article vous aidera à comprendre le concept de base de la limitation des ressources. Et vous pouvez appliquer ces connaissances dans votre travail.



Bonne chance!



Quoi d'autre à lire:



  1. Observabilité SRE: espaces de noms et structure métrique .
  2. 90+ Kubernetes: , , , .
  3. Kubernetes .



All Articles