Allouer des ressources mémoire aux conteneurs et aux pods
Cette page montre comment assigner une mémoire request et une mémoire limit à un conteneur. Un conteneur est garanti d'avoir autant de mémoire qu'il le demande, mais n'est pas autorisé à consommer plus de mémoire que sa limite.
Pré-requis
Vous devez disposer d'un cluster Kubernetes et l'outil de ligne de commande kubectl doit être configuré pour communiquer avec votre cluster. Si vous ne possédez pas déjà de cluster, vous pouvez en créer un en utilisant Minikube, ou vous pouvez utiliser l'un de ces environnements Kubernetes:
Pour consulter la version, entrezkubectl version
.
Chaque nœud de votre cluster doit avoir au moins 300 MiB de mémoire.
Pour quelques étapes de cette page, vous devez lancer [metrics-server] (https://github.com/kubernetes-incubator/metrics-server) dans votre cluster. Si vous avez déjà metrics-server vous pouvez sauter ces étapes.
Si vous utilisez Minikube, exécutez la commande suivante pour activer metrics-server :
minikube addons enable metrics-server
Pour voir si le metrics-server fonctionne, ou un autre fournisseur de l'API des métriques de ressources (metrics.k8s.io
), exécutez la commande suivante :
kubectl get apiservices
Si l'API des métriques de ressources est disponible, la sortie inclura une référence à metrics.k8s.io
.
NAME
v1beta1.metrics.k8s.io
Créer un namespace
Créez un namespace de manière à ce que les ressources que vous créez dans cet exercice soient isolées du reste de votre cluster.
kubectl create namespace mem-example
Spécifier une demande de mémoire et une limite de mémoire
Pour spécifier une demande de mémoire pour un conteneur, incluez le champ resources:requests
.
dans le manifeste des ressources du conteneur. Pour spécifier une limite de mémoire, incluez resources:limits
.
Dans cet exercice, vous créez un pod qui possède un seul conteneur. Le conteneur dispose d'une demande de mémoire de 100 MiB et une limite de mémoire de 200 MiB. Voici le fichier de configuration pour le Pod :
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
La section args
de votre fichier de configuration fournit des arguments pour le conteneur lorsqu'il démarre.
Les arguments "--vm-bytes", "150M"
indiquent au conteneur d'allouer 150 MiB de mémoire.
Créez le Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example
Vérifiez que le Pod fonctionne :
kubectl get pod memory-demo --namespace=mem-example
Consultez des informations détaillées sur le Pod :
kubectl get pod memory-demo --output=yaml --namespace=mem-example
La sortie montre que le conteneur dans le Pod a une demande de mémoire de 100 MiB et une limite de mémoire de 200 MiB.
...
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
Exécutez kubectl top
pour récupérer les métriques du pod :
kubectl top pod memory-demo --namespace=mem-example
La sortie montre que le Pod utilise environ 162.900.000 bytes de mémoire, qui est d'environ 150 MiB. Ce qui est supérieur à la demande de 100 MiB du Pod, mais ne dépassant pas la limite de 200 Mio de Pod.
NAME CPU(cores) MEMORY(bytes)
memory-demo <something> 162856960
Supprimez votre Pod :
kubectl delete pod memory-demo --namespace=mem-example
Dépasser la limite de mémoire d'un conteneur
Un conteneur peut dépasser sa demande de mémoire si le nœud dispose de la mémoire disponible. Cependant, un conteneur n'est pas autorisé à utiliser plus que sa limite de mémoire. Si un conteneur alloue plus de mémoire que sa limite, le Conteneur devient un candidat à la terminaison. Si le conteneur continue à consommer de la mémoire au-delà de sa limite, le conteneur est arrêté. Si un conteneur terminé peut être redémarré, le kubelet le redémarre, comme pour tout autre type d'échec d'exécution.
Dans cet exercice, vous créez un Pod qui tente d'allouer plus de mémoire que sa limite. Voici le fichier de configuration d'un Pod qui contient un conteneur avec une demande de mémoire de 50 MiB et une limite de mémoire de 100 MiB :
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-2
namespace: mem-example
spec:
containers:
- name: memory-demo-2-ctr
image: polinux/stress
resources:
requests:
memory: "50Mi"
limits:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
Dans la section args
du fichier de configuration, vous pouvez voir que le conteneur
tentera d'allouer 250 MiB de mémoire, ce qui est bien au-dessus de la limite de 100 MiB.
Créez le Pod :
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example
Consultez des informations détaillées sur le Pod :
kubectl get pod memory-demo-2 --namespace=mem-example
A ce niveau, le conteneur est soit en train de tourner, soit stoppé. Répétez la commande précédente jusqu'à ce que le conteneur soit terminé :
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
Obtenez une vue plus détaillée de l'état du conteneur :
kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example
La sortie indique que le conteneur a été stoppé suite à un manque de mémoire (OOM) :
lastState:
terminated:
containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null
Le conteneur dans cet exercice pourra être redémarré, ainsi le kubelet le redémarre. Répéter cette commande plusieurs fois pour s'assurer que le conteneur est stoppé et redémarré d'une manière répététive :
kubectl get pod memory-demo-2 --namespace=mem-example
La sortie permet de voir que le conteneur est stoppé, redémarré, stoppé à nouveau, redémarré, et ainsi de suite :
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s
Affichez des informations détaillées sur l'historique du Pod :
kubectl describe pod memory-demo-2 --namespace=mem-example
La sortie indique que le conteneur se démarre et échoue continuellement :
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container
Affichez des informations détaillées sur les nœuds de votre cluster :
kubectl describe nodes
La sortie inclut un enregistrement de la mise à mort du conteneur suite à une condition hors mémoire :
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child
Supprimez votre Pod :
kubectl delete pod memory-demo-2 --namespace=mem-example
Spécifiez une demande de mémoire trop volumineuse pour vos nœuds.
Les demandes de mémoire et les limites sont associées aux conteneurs, mais il est utile de réfléchir avant tout à la capacité de demande et limite mémoire des pods. La demande de mémoire pour le Pod est la somme des demandes de mémoire pour tous ses conteneurs. De même, la mémoire limite pour le Pod est la somme des limites de tous ses Conteneurs.
L'ordonnancement des modules est basé sur les demandes. Un Pod est schedulé pour se lancer sur un Nœud uniquement si le Nœud dispose de suffisamment de mémoire disponible pour répondre à la demande de mémoire du Pod.
Dans cet exercice, vous allez créer un Pod dont la demande de mémoire est si importante qu'elle dépasse la capacité de la mémoire de n'importe quel nœud de votre cluster. Voici le fichier de configuration d'un Pod qui possède un seul conteneur avec une demande de 1000 GiB de mémoire, qui dépasse probablement la capacité de tous les nœuds de votre cluster.
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-3
namespace: mem-example
spec:
containers:
- name: memory-demo-3-ctr
image: polinux/stress
resources:
limits:
memory: "1000Gi"
requests:
memory: "1000Gi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
Créez le Pod :
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example
Affichez l'état du Pod :
kubectl get pod memory-demo-3 --namespace=mem-example
La sortie indique que l'état du Pod est PENDING. En d'autres termes, le Pod n'est pas programmé pour tourner sur aucun Nœud, et il restera indéfiniment dans l'état PENDING :
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
Affichez des informations détaillées sur le Pod, y compris les événements :
kubectl describe pod memory-demo-3 --namespace=mem-example
La sortie indique que le conteneur ne peut pas être planifié par manque de mémoire sur les nœuds :
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
Unités de mémoire
La ressource mémoire est mesurée en bytes. Vous pouvez exprimer la mémoire sous la forme d'un nombre entier simple ou d'un nombre avec l'un de ces suffixes : E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki. Par exemple, les valeurs suivantes représentent approximativement la même valeur :
128974848, 129e6, 129M , 123Mi
Supprimez votre Pod :
kubectl delete pod memory-demo-3 --namespace=mem-example
Si vous ne spécifiez pas de limite de mémoire
Si vous ne spécifiez pas de limite de mémoire pour un conteneur, l'une des situations suivantes s'applique :
-
Le conteneur n'a pas de limite maximale quant à la quantité de mémoire qu'il utilise. Le conteneur pourrait utiliser toute la mémoire disponible sur le nœud où il est en cours d'exécution, ce qui pourrait à son tour invoquer le OOM killer. De plus, dans le cas d'un OOM Kill, un conteneur sans limite de ressources aura plus de chance d'être stoppé.
-
Le conteneur s'exécute dans un namespace qui a une limite de mémoire par défaut, d'ou le conteneur est automatiquement affecté cette limite par defaut. Les administrateurs du cluster peuvent utiliser un LimitRange pour spécifier une valeur par défaut pour la limite de mémoire.
Motivation pour les demandes et les limites de mémoire
En configurant les demandes de mémoire et les limites pour les conteneurs qui s'exécutent dans votre cluster. vous pouvez utiliser efficacement les ressources mémoire disponibles sur les noeuds de votre cluster. En gardant la demande de mémoire d'un Pod basse, vous donnez au Pod une bonne chance d'être schedulé. En ayant une limite de mémoire supérieure à la demande de mémoire, vous accomplissez deux choses :
- Le Pod peut avoir des éclats d'activités où il fait usage de la mémoire qui se trouve être disponible.
- La quantité de mémoire qu'un Pod peut utiliser pendant un éclat d'activité est limitée à une quantité raisonnable.
Clean up
Supprimez votre namespace. Ceci va supprimer tous les Pods que vous avez créés dans cet exercice :
kubectl delete namespace mem-example
A suivre
Pour les développeurs d'applications
Pour les administrateurs de cluster
-
Configuration des demandes et des limites de mémoire par défaut pour un Namespace
-
Configuration des demandes et des limites par défaut de CPU pour un Namespace
-
Configuration des contraintes de mémoire minimales et maximales pour un Namespace
-
Configuration des contraintes minimales et maximales du CPU pour un Namespace
-
Configuration des quotas de mémoire et de CPU pour un Namespace