5.5. Configuration de la mémoire cluster pour répondre aux exigences de mémoire de conteneur et de risque
En tant qu’administrateur de clusters, vous pouvez aider vos clusters à fonctionner efficacement grâce à la gestion de la mémoire d’application en:
- Déterminer les exigences en matière de mémoire et de risque d’un composant d’application conteneurisé et configurer les paramètres de mémoire du conteneur pour répondre à ces exigences.
- Configuration d’exécutions d’applications conteneurisées (par exemple, OpenJDK) pour adhérer de manière optimale aux paramètres de mémoire de conteneur configurés.
- Diagnostiquer et résoudre les conditions d’erreur liées à la mémoire associées à l’exécution dans un conteneur.
5.5.1. Comprendre la gestion de la mémoire applicative Copier lienLien copié sur presse-papiers!
Il est recommandé de lire pleinement l’aperçu de la façon dont Red Hat OpenShift Service sur AWS gère les ressources de calcul avant de procéder.
Dans chaque type de ressource (mémoire, CPU, stockage), Red Hat OpenShift Service sur AWS permet de placer des valeurs de requête et limites optionnelles sur chaque conteneur dans un pod.
À noter ce qui suit au sujet des requêtes de mémoire et des limites de mémoire:
Demande de mémoire
- La valeur de la demande de mémoire, si elle est spécifiée, influence le service Red Hat OpenShift sur AWS. Le planificateur prend en compte la demande de mémoire lors de la planification d’un conteneur à un nœud, puis clôture la mémoire demandée sur le nœud choisi pour l’utilisation du conteneur.
- En cas d’épuisement de la mémoire d’un nœud, Red Hat OpenShift Service sur AWS donne la priorité à l’expulsion de ses conteneurs dont l’utilisation de la mémoire dépasse le plus leur demande de mémoire. Dans les cas graves d’épuisement de la mémoire, le tueur OOM peut sélectionner et tuer un processus dans un conteneur en fonction d’une métrique similaire.
- L’administrateur du cluster peut attribuer un quota ou attribuer des valeurs par défaut pour la valeur de demande de mémoire.
- L’administrateur de cluster peut outrepasser les valeurs de requête de mémoire qu’un développeur spécifie, pour gérer le cluster overcommit.
Limite de mémoire
- La valeur limite de mémoire, si spécifiée, fournit une limite dure sur la mémoire qui peut être allouée sur tous les processus d’un conteneur.
- Lorsque la mémoire allouée par tous les processus d’un conteneur dépasse la limite de mémoire, le tueur hors mémoire (OOM) sélectionne et tue immédiatement un processus dans le conteneur.
- Lorsque la requête mémoire et la limite sont spécifiées, la valeur limite de mémoire doit être supérieure ou égale à la requête mémoire.
- L’administrateur du cluster peut attribuer un quota ou attribuer des valeurs par défaut pour la valeur limite de mémoire.
- La limite minimale de mémoire est de 12 Mo. En cas de démarrage d’un conteneur en raison d’un événement de Pod de mémoire impossible, la limite de mémoire est trop faible. Augmentez ou supprimez la limite de mémoire. La suppression de la limite permet aux gousses de consommer des ressources de nœuds non limitées.
5.5.1.1. Gestion de la stratégie de mémoire des applications Copier lienLien copié sur presse-papiers!
Les étapes de dimensionnement de la mémoire de l’application sur Red Hat OpenShift Service sur AWS sont les suivantes:
Déterminer l’utilisation prévue de la mémoire de conteneur
Déterminer l’utilisation prévue de la mémoire moyenne et maximale du conteneur, empiriquement si nécessaire (par exemple, par des tests de charge séparés). Considérez tous les processus qui peuvent potentiellement s’exécuter en parallèle dans le conteneur: par exemple, l’application principale génère-t-elle des scripts auxiliaires?
Déterminer l’appétit du risque
Déterminer l’appétit de risque pour l’expulsion. Lorsque l’appétit de risque est faible, le conteneur doit demander de la mémoire en fonction de l’utilisation maximale prévue plus un pourcentage de marge de sécurité. Lorsque l’appétit de risque est plus élevé, il peut être plus approprié de demander de la mémoire en fonction de l’utilisation moyenne prévue.
Définir la demande de mémoire de conteneur
Définissez la demande de mémoire de conteneur en fonction de ce qui précède. Le plus précisément la demande représente l’utilisation de la mémoire de l’application, mieux c’est. Lorsque la demande est trop élevée, l’utilisation des grappes et des quotas sera inefficace. Lorsque la demande est trop faible, les chances d’expulsion de l’application augmentent.
Définir la limite de mémoire du conteneur, si nécessaire
Définissez la limite de mémoire du conteneur, si nécessaire. Fixer une limite a pour effet de tuer immédiatement un processus de conteneur si l’utilisation combinée de la mémoire de tous les processus dans le conteneur dépasse la limite, et est donc une bénédiction mixte. D’une part, il peut rendre l’utilisation excessive de mémoire imprévue évidente tôt ("échec rapide"); d’autre part, il met également fin aux processus brusquement.
Il est à noter que certains Red Hat OpenShift Service sur les clusters AWS peuvent nécessiter une valeur limite à définir; certains peuvent outrepasser la demande en fonction de la limite; et certaines images de l’application dépendent d’une valeur limite définie car cela est plus facile à détecter qu’une valeur de requête.
Lorsque la limite de mémoire est définie, elle ne doit pas être inférieure à l’utilisation prévue de la mémoire du conteneur de pointe plus une marge de sécurité en pourcentage.
Assurez-vous que l’application est réglée
Assurez-vous que l’application est réglée en ce qui concerne les valeurs de requête configurées et les valeurs limites, le cas échéant. Cette étape est particulièrement pertinente pour les applications qui mettent en commun la mémoire, comme le JVM. Le reste de cette page en traite.
5.5.2. Comprendre les paramètres OpenJDK pour Red Hat OpenShift Service sur AWS Copier lienLien copié sur presse-papiers!
Les paramètres OpenJDK par défaut ne fonctionnent pas bien avec les environnements conteneurisés. En conséquence, certains paramètres de mémoire Java supplémentaires doivent toujours être fournis chaque fois qu’on exécute l’OpenJDK dans un conteneur.
La mise en page de la mémoire JVM est complexe, dépendante de la version, et la décrire en détail dépasse le champ d’application de cette documentation. Cependant, comme point de départ pour l’exécution d’OpenJDK dans un conteneur, au moins les trois tâches suivantes liées à la mémoire sont essentielles:
- Dépassement de la taille maximale du tas JVM.
- Encourager le JVM à libérer la mémoire inutilisée au système d’exploitation, le cas échéant.
- Assurer la configuration appropriée de tous les processus JVM dans un conteneur.
Le réglage optimal des charges de travail JVM pour l’exécution dans un conteneur est au-delà de la portée de cette documentation, et peut impliquer la définition de plusieurs options JVM supplémentaires.
5.5.2.1. Comprendre comment remplacer la taille maximale du tas JVM Copier lienLien copié sur presse-papiers!
« pour de nombreuses charges de travail Java, le tas JVM est le plus grand consommateur de mémoire. Actuellement, l’OpenJDK permet par défaut de permettre jusqu’à 1/4 (1/-XX:MaxRAMFraction) de la mémoire du nœud de calcul à utiliser pour le tas, que l’OpenJDK fonctionne ou non dans un conteneur. Il est donc essentiel de remplacer ce comportement, surtout si une limite de mémoire de conteneur est également définie.
Il y a au moins deux façons d’atteindre ce qui précède:
Lorsque la limite de mémoire du conteneur est définie et que les options expérimentales sont prises en charge par le JVM, set -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap.
NoteL’option UseCGroupMemoryLimitForHeap a été supprimée dans JDK 11. À la place, utilisez -XX:+UseContainerSupport.
Ceci définit -XX:MaxRAM à la limite de mémoire du conteneur, et la taille maximale du tas (-XX:MaxHeapSize / -Xmx) à 1/-XX:MaxRAMFraction (1/4 par défaut).
Remplacez directement l’un des -XX:MaxRAM, -XX:MaxHeapSize ou -Xmx.
Cette option implique un codage dur d’une valeur, mais a l’avantage de permettre le calcul d’une marge de sécurité.
5.5.2.2. Comprendre comment encourager le JVM à libérer de la mémoire inutilisée au système d’exploitation Copier lienLien copié sur presse-papiers!
L’OpenJDK ne renvoie pas de manière agressive la mémoire inutilisée au système d’exploitation. Cela peut être approprié pour de nombreuses charges de travail Java conteneurisées, mais des exceptions notables incluent des charges de travail où des processus actifs supplémentaires coexistent avec un JVM dans un conteneur, que ces processus supplémentaires soient natifs, JVM supplémentaires ou une combinaison des deux.
Les agents basés sur Java peuvent utiliser les arguments JVM suivants pour encourager le JVM à libérer de la mémoire inutilisée au système d’exploitation:
-XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90.
-XX:+UseParallelGC
-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:GCTimeRatio=4
-XX:AdaptiveSizePolicyWeight=90.
Ces arguments sont destinés à renvoyer la mémoire tas au système d’exploitation chaque fois que la mémoire allouée dépasse 110% de la mémoire en usage (-XX:MaxHeapFreeRatio), passant jusqu’à 20% du temps CPU dans le collecteur d’ordures (-XX:GCTimeRatio). À aucun moment, l’allocation du tas d’application ne sera inférieure à l’allocation initiale du tas (surpassée par -XX:InitialHeapSize / -Xms). L’empreinte de Java dans OpenShift (Partie 1), l’empreinte de Java dans OpenShift (Partie 2) et OpenJDK et Containers.
5.5.2.3. Comprendre comment s’assurer que tous les processus JVM dans un conteneur sont correctement configurés Copier lienLien copié sur presse-papiers!
Dans le cas où plusieurs JVM s’exécutent dans le même conteneur, il est essentiel de s’assurer qu’ils sont tous configurés de manière appropriée. Dans de nombreuses charges de travail, il sera nécessaire d’accorder à chaque JVM un budget de mémoire en pourcentage, laissant une marge de sécurité supplémentaire peut-être substantielle.
De nombreux outils Java utilisent différentes variables d’environnement (JAVA_OPTS, GRADLE_OPTS, etc.) pour configurer leurs JVM et il peut être difficile de s’assurer que les bons paramètres sont passés au bon JVM.
La variable d’environnement JAVA_TOOL_OPTIONS est toujours respectée par OpenJDK, et les valeurs spécifiées dans JAVA_TOOL_OPTIONS seront remplacées par d’autres options spécifiées sur la ligne de commande JVM. Afin de s’assurer que ces options sont utilisées par défaut pour toutes les charges de travail JVM exécutées dans l’image de l’agent basé sur Java, le Red Hat OpenShift Service sur AWS Jenkins Maven jeu d’image d’agent:
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Dsun.zip.disableMemoryMapping=true"
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap -Dsun.zip.disableMemoryMapping=true"
L’option UseCGroupMemoryLimitForHeap a été supprimée dans JDK 11. À la place, utilisez -XX:+UseContainerSupport.
Cela ne garantit pas que d’autres options ne sont pas nécessaires, mais est destinée à être un point de départ utile.
5.5.3. La recherche de la requête et de la limite de mémoire à l’intérieur d’un pod Copier lienLien copié sur presse-papiers!
L’application qui souhaite découvrir dynamiquement sa demande de mémoire et sa limite à partir d’un pod doit utiliser l’API Downward.
Procédure
Configurez le pod pour ajouter les sanzas MEMORY_REQUEST et MEMORY_LIMIT:
Créez un fichier YAML similaire à ce qui suit:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Créez le pod en exécutant la commande suivante:
oc create -f <file_name>.yaml
$ oc create -f <file_name>.yaml
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
La vérification
Accédez au pod à l’aide d’un shell distant:
oc rsh test
$ oc rsh test
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Assurez-vous que les valeurs demandées ont été appliquées:
env | grep MEMORY | sort
$ env | grep MEMORY | sort
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
MEMORY_LIMIT=536870912 MEMORY_REQUEST=402653184
MEMORY_LIMIT=536870912 MEMORY_REQUEST=402653184
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
La valeur limite de mémoire peut également être lue à l’intérieur du conteneur par le fichier /sys/fs/cgroup/memory.limit_in_bytes.
5.5.4. Comprendre la politique de l’OOM Copier lienLien copié sur presse-papiers!
Le service OpenShift de Red Hat sur AWS peut tuer un processus dans un conteneur si l’utilisation totale de la mémoire de tous les processus dans le conteneur dépasse la limite de mémoire, ou dans les cas graves d’épuisement de la mémoire des nœuds.
Lorsqu’un processus est hors mémoire (OOM) tué, cela peut entraîner la sortie immédiate du conteneur. Lorsque le procédé PID 1 du conteneur reçoit le SIGKILL, le conteneur sortira immédiatement. Dans le cas contraire, le comportement du conteneur dépend du comportement des autres processus.
À titre d’exemple, un processus de conteneur est sorti avec le code 137, indiquant qu’il a reçu un signal SIGKILL.
Dans le cas où le conteneur ne sort pas immédiatement, une mise à mort d’OOM est détectable comme suit:
Accédez au pod à l’aide d’un shell distant:
oc rsh test
# oc rsh test
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exécutez la commande suivante pour voir le compte de destruction OOM actuel dans /sys/fs/cgroup/memory/memory.oom_control:
grep '^oom_kill ' /sys/fs/cgroup/memory/memory.oom_control
$ grep '^oom_kill ' /sys/fs/cgroup/memory/memory.oom_control
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
oom_kill 0
oom_kill 0
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exécutez la commande suivante pour provoquer un meurtre d’OOM:
sed -e '' </dev/zero
$ sed -e '' </dev/zero
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
Killed
Killed
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exécutez la commande suivante pour afficher l’état de sortie de la commande sed:
echo $?
$ echo $?
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
137
137
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Le code 137 indique le processus de conteneur sorti avec le code 137, indiquant qu’il a reçu un signal SIGKILL.
Exécutez la commande suivante pour voir que le compteur OOM kill dans /sys/fs/cgroup/memory/memory.oom_control incrémented:
grep '^oom_kill ' /sys/fs/cgroup/memory/memory.oom_control
$ grep '^oom_kill ' /sys/fs/cgroup/memory/memory.oom_control
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
oom_kill 1
oom_kill 1
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Lorsqu’un ou plusieurs processus dans une gousse sont tués, lorsque la gousse quitte par la suite, que ce soit immédiatement ou non, elle aura échoué et raisonne OOMKilled. Il est possible qu’une gousse tuée par OOM soit redémarrée en fonction de la valeur de redémarragePolicy. En cas de redémarrage, les contrôleurs tels que le contrôleur de réplication remarqueront l’état raté du pod et créeront un nouveau pod pour remplacer l’ancien.
Faites appel à la commande follwing pour obtenir le statut du pod:
oc get pod test
$ oc get pod test
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
NAME READY STATUS RESTARTS AGE test 0/1 OOMKilled 0 1m
NAME READY STATUS RESTARTS AGE test 0/1 OOMKilled 0 1m
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Lorsque le pod n’a pas redémarré, exécutez la commande suivante pour afficher le pod:
oc get pod test -o yaml
$ oc get pod test -o yaml
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
Copy to Clipboard Copied! Toggle word wrap Toggle overflow En cas de redémarrage, exécutez la commande suivante pour afficher le pod:
oc get pod test -o yaml
$ oc get pod test -o yaml
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Exemple de sortie
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
5.5.5. Comprendre l’expulsion des pod Copier lienLien copié sur presse-papiers!
Le service OpenShift Red Hat sur AWS peut expulser un pod de son nœud lorsque la mémoire du nœud est épuisée. En fonction de l’ampleur de l’épuisement de la mémoire, l’expulsion peut ou peut ne pas être gracieuse. L’expulsion gracieuse implique le processus principal (PID 1) de chaque conteneur recevant un signal SIGTERM, puis quelque temps plus tard un signal SIGKILL si le processus n’est pas déjà sorti. L’expulsion non gracieuse implique le processus principal de chaque conteneur recevant immédiatement un signal SIGKILL.
La phase d’expulsion d’une gousse a échoué et la raison de l’expulsion. Il ne sera pas redémarré, quelle que soit la valeur de redémarragePolicy. Cependant, les contrôleurs tels que le contrôleur de réplication remarqueront l’état défaillant du pod et créeront un nouveau pod pour remplacer l’ancien.
oc get pod test
$ oc get pod test
Exemple de sortie
NAME READY STATUS RESTARTS AGE test 0/1 Evicted 0 1m
NAME READY STATUS RESTARTS AGE
test 0/1 Evicted 0 1m
oc get pod test -o yaml
$ oc get pod test -o yaml
Exemple de sortie
... status: message: 'Pod The node was low on resource: [MemoryPressure].' phase: Failed reason: Evicted
...
status:
message: 'Pod The node was low on resource: [MemoryPressure].'
phase: Failed
reason: Evicted