Comment accéder aux ressources du pod Kubernetes

Comment accéder aux ressources du pod KubernetesLa récompense par Tohad

Lorsqu'on débute avec Kubernetes, il est courant d'oublier de configurer les ressources du conteneur. À ce stade, il suffit de s'assurer que l'image Docker fonctionne et peut être déployée sur le cluster Kubernetes.

Mais plus tard, l'application doit être déployée dans un cluster de production avec d'autres applications. Pour ce faire, vous devez allouer des ressources au conteneur et vous assurer qu'il y en a suffisamment pour que l'application soit opérationnelle et que les autres applications en cours d'exécution ne rencontreront pas de problèmes.

Équipe Kubernetes aaS de Mail.ru traduction d'un article sur les ressources du conteneur (CPU et MEM), les requêtes et les limitations des ressources. Vous découvrirez les avantages de ces paramètres et ce qui se passe si vous ne les définissez pas.

Ressources informatiques

Nous disposons de 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 Pod YAML suivant, vous verrez une section de ressources qui contient les ressources demandées et limitées :

  • Ressources de pod demandées = somme des ressources demandées de tous les conteneurs ;
  • Limite de ressources de pod = Somme de toutes les limites de ressources de pod.

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 limitées

Champ resources.requested de la spécification Pod est l'un des éléments utilisés pour trouver le nœud souhaité. Vous pouvez déjà planifier le déploiement de Pods pour cela. Comment trouver un nœud approprié ?

Kubernetes se compose de plusieurs composants, dont un nœud maître ou nœud maître (Kubernetes Control Plane). Le nœud maître comporte plusieurs processus : kube-apiserver, kube-controller-manager et kube-scheduler.

Le processus kube-scheduler est chargé d'examiner les pods nouvellement créés et de trouver d'éventuels nœuds de travail correspondant à toutes les demandes de pods, y compris le nombre de ressources demandées. La liste des nœuds trouvés par kube-scheduler est classée. Le pod est planifié sur le nœud avec les scores les plus élevés.

Comment accéder aux ressources du pod KubernetesOù sera placé le Pod violet ?

Sur l'image, vous pouvez voir que kube-scheduler devrait planifier 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 demandées) ne correspondent pas aux demandes du Pod violet. Ainsi, les 1 Go de mémoire demandés par le Pod violet ne tiendront pas sur le nœud A, puisque la mémoire disponible est de 0,5 Go. Mais le nœud B dispose de suffisamment de ressources. En conséquence, kube-scheduler décide que la destination du Pod violet est le nœud B.

Nous savons désormais comment les ressources demandées affectent le choix du nœud pour exécuter le Pod. Mais quel est l’impact des ressources marginales ?

La limite de ressources est une limite que le CPU/MEM ne peut pas franchir. Cependant, la ressource CPU est flexible, de sorte que les conteneurs qui atteignent leurs limites de CPU n'entraîneront pas la fermeture du Pod. Au lieu de cela, la limitation du processeur démarrera. 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 le permet.

Ressources demandées et maximales en détail

Comment accéder aux ressources du pod KubernetesCommunication de ressources entre Docker et Kubernetes

La meilleure façon d'expliquer le fonctionnement des demandes de ressources et des limites de ressources est de présenter la relation entre Kubernetes et Docker. Dans l'image ci-dessus, vous pouvez voir comment les champs Kubernetes et les indicateurs de démarrage Docker sont liés.

Mémoire : demande et limitation

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

Comme mentionné ci-dessus, la mémoire est mesurée en octets. Basé sur Documentation Kubernetes, nous pouvons spécifier la mémoire sous forme de nombre. Il s'agit généralement d'un nombre entier, par exemple 2678, soit 2678 octets. Vous pouvez également utiliser des suffixes G и Gi, l'essentiel est de se rappeler qu'ils ne sont pas équivalents. Le premier est décimal et le second est binaire. Comme l'exemple mentionné dans la documentation de k8s : 128974848, 129e6, 129M, 123Mi - ils sont pratiquement équivalents.

Option Kubernetes limits.memory correspond au drapeau --memory de Docker. En cas de request.memory Il n'y a pas de flèche pour Docker car Docker n'utilise pas ce champ. Vous vous demanderez peut-être : est-ce vraiment nécessaire ? 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 si vous définissez une mémoire insuffisante pour une requête ?

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

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

Si le conteneur dépasse la limite de mémoire, il sera arrêté en raison d'un OOM-Killed. Et redémarrera 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 valeur limite et la définira comme valeur par défaut.

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

Le conteneur n'a aucune restriction ; 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 ?

Il s'agit du pire des cas : le planificateur ne sait pas combien de ressources le conteneur a besoin, ce qui peut entraîner de sérieux problèmes sur le nœud. Dans ce cas, ce serait bien d'avoir des limites par défaut sur l'espace de noms (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 que Requests.memory - pas la valeur minimale. Il s'agit d'une description de la quantité de mémoire suffisante pour que le conteneur continue de fonctionner en continu.

Il est généralement recommandé de définir la même valeur pour request.memory и limit.memory. Cela garantit que Kubernetes ne planifiera pas de pod sur un nœud disposant de suffisamment de mémoire pour exécuter le pod, mais pas suffisamment pour l'exécuter. Gardez à l'esprit : la planification des pods Kubernetes ne prend en compte que requests.memoryEt limits.memory ne prend pas en compte.

CPU : demande et limite

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

Avec un CPU, tout est un peu plus compliqué. En revenant à l'image de la relation entre Kubernetes et Docker, vous pouvez voir que request.cpu match --cpu-sharesAlors que limit.cpu correspond au drapeau cpus dans Docker.

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

Demander un noyau complet (proportion = 1024) ne signifie pas que votre conteneur le recevra. Si votre machine hôte ne possède qu'un seul cœur et que vous exécutez plusieurs conteneurs, tous les conteneurs doivent partager le processeur disponible entre eux. Comment cela peut-il arriver? Regardons la photo.

Comment accéder aux ressources du pod Kubernetes
Demande de CPU - Système monocœur

Imaginons que vous disposiez d'un système hôte monocœur exécutant des conteneurs. Maman (Kubernetes) a préparé une tarte (CPU) et souhaite la partager entre les enfants (conteneurs). Trois enfants veulent une tarte entière (proportion = 1024), un autre enfant veut une demi-tarte (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%

Selon le calcul, trois enfants recevront 28 % du noyau, et non la totalité. Le quatrième enfant recevra 14 % du noyau complet, et non la moitié. Mais les choses seront différentes si vous disposez d’un système multicœur.

Comment accéder aux ressources du pod Kubernetes
Demande de 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 préparé quatre tartes, chacun de ses enfants en aura 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 réparti entre les conteneurs. Bien entendu, outre les conteneurs eux-mêmes, il existe d'autres processus qui utilisent également les ressources du processeur. Lorsque les processus d'un conteneur sont inactifs, d'autres peuvent utiliser sa ressource. CPU: "200m" match CPU: 0,2, ce qui signifie environ 20 % d'un noyau.

Parlons maintenant de limit.cpu. Le processeur limité par Kubernetes est multiplié par 100. Le résultat est la durée que le conteneur peut utiliser toutes les 100 µs (cpu-period).

limit.cpu correspond au drapeau Docker --cpus. C'est une nouvelle combinaison d'anciens --cpu-period и --cpu-quota. En le définissant, nous indiquons combien de ressources CPU disponibles le conteneur peut utiliser au maximum avant le début de la limitation :

  • cpus - combinaison cpu-period и cpu-quota. cpus = 1.5 équivalent au réglage cpu-period = 100000 и cpu-quota = 150000;
  • Période CPU - période Planificateur CFS du processeur, par défaut 100 microsecondes ;
  • quota CPU - nombre de microsecondes à l'intérieur cpu-period, qui est délimité par le conteneur.

Que se passe-t-il si vous installez un processeur demandé insuffisant ?

Si le conteneur a besoin de plus que ce qu’il a installé, il volera le processeur des autres processus.

Que se passe-t-il si vous définissez la limite du processeur trop basse ?

Étant donné que la ressource CPU est réglable, la limitation sera activée.

Que se passe-t-il si vous ne spécifiez pas de requête CPU ?

Comme pour la mémoire, la valeur demandée est égale à la limite.

Que se passe-t-il si vous ne spécifiez pas de limite de CPU ?

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 requête ni limite de CPU ?

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 des limites par défaut pour les espaces de noms (LimitRange).

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

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

Nous avons pris connaissance de 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’existe pas de réponses claires à ces questions. Si vous ne savez pas comment fonctionne votre application ni la quantité de CPU ou de mémoire dont 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, surveillez le comportement de l'application en monitoring pendant une semaine. Si les graphiques indiquent que votre application consomme moins de ressources que ce que vous aviez demandé, vous pouvez réduire la quantité de CPU ou de mémoire demandée.

A titre d'exemple, voyez ceci Tableau de bord Grafana. Il affiche la différence entre les ressources demandées ou la limite de ressources et l'utilisation actuelle des ressources.

Conclusion

Demander et limiter des ressources permet de maintenir votre cluster Kubernetes en bonne santé. Une configuration appropriée des limites minimise les coûts et permet aux applications de fonctionner à tout moment.

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

  1. Les ressources demandées sont une configuration qui est prise en compte au démarrage (lorsque Kubernetes envisage d'héberger l'application). En revanche, limiter les ressources est important au moment de l'exécution, lorsque l'application est déjà en cours d'exécution sur le nœud.
  2. Comparé à la mémoire, le CPU est une ressource réglementée. S'il n'y a pas assez de processeur, votre Pod ne s'éteindra pas et le mécanisme de limitation s'activera.
  3. Les ressources demandées et la limite de ressources ne sont pas des valeurs minimales et maximales ! En définissant les ressources demandées, vous vous assurez que l'application fonctionnera sans problème.
  4. Une bonne pratique consiste à définir la demande de mémoire égale à la limite de mémoire.
  5. Ok installation demandée CPU <=1, si l'application n'effectue pas de calculs complexes.
  6. Si vous demandez plus de ressources que celles disponibles sur un nœud, le pod ne sera jamais planifié sur ce nœud.
  7. Pour déterminer la quantité correcte de ressources demandées/limites de ressources, utilisez les tests de charge et la surveillance.

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

Bonne chance!

Quoi lire d'autre :

  1. Observabilité SRE : espaces de noms et structure métrique.
  2. Plus de 90 outils utiles pour Kubernetes : déploiement, gestion, surveillance, sécurité, etc..
  3. Notre chaîne Autour de Kubernetes dans Telegram.

Source: habr.com

Ajouter un commentaire