7.4. Pratiques recommandées pour les hôtes de nœuds
Le fichier de configuration des nœuds d'OpenShift Container Platform contient des options importantes. Par exemple, deux paramètres contrôlent le nombre maximum de pods qui peuvent être planifiés sur un nœud : podsPerCore
et maxPods
.
Lorsque les deux options sont utilisées, la plus faible des deux valeurs limite le nombre de pods sur un nœud. Le dépassement de ces valeurs peut avoir les conséquences suivantes
- Augmentation de l'utilisation de l'unité centrale.
- Lenteur de la programmation des pods.
- Scénarios potentiels de dépassement de mémoire, en fonction de la quantité de mémoire dans le nœud.
- Epuisement de la réserve d'adresses IP.
- Surcharge des ressources, entraînant de mauvaises performances pour les applications utilisateur.
Dans Kubernetes, un pod qui contient un seul conteneur utilise en réalité deux conteneurs. Le deuxième conteneur est utilisé pour mettre en place le réseau avant le démarrage du conteneur proprement dit. Par conséquent, un système exécutant 10 pods aura en réalité 20 conteneurs en cours d'exécution.
La limitation des IOPS disque par le fournisseur de cloud peut avoir un impact sur CRI-O et kubelet. Ils peuvent être surchargés lorsqu'un grand nombre de pods à forte intensité d'E/S s'exécutent sur les nœuds. Il est recommandé de surveiller les E/S disque sur les nœuds et d'utiliser des volumes avec un débit suffisant pour la charge de travail.
podsPerCore
définit le nombre de modules que le nœud peut exécuter en fonction du nombre de cœurs de processeur du nœud. Par exemple, si podsPerCore
est défini sur 10
sur un nœud avec 4 cœurs de processeur, le nombre maximum de modules autorisés sur le nœud sera 40
.
kubeletConfig: podsPerCore: 10
Le fait de régler podsPerCore
sur 0
désactive cette limite. La valeur par défaut est 0
. podsPerCore
ne peut pas dépasser maxPods
.
maxPods
fixe le nombre de pods que le nœud peut exécuter à une valeur fixe, quelles que soient les propriétés du nœud.
kubeletConfig: maxPods: 250
7.4.1. Création d'un CRD KubeletConfig pour éditer les paramètres des kubelets
La configuration du kubelet est actuellement sérialisée comme une configuration Ignition, elle peut donc être directement éditée. Cependant, une nouvelle adresse kubelet-config-controller
a été ajoutée au contrôleur de configuration de la machine (MCC). Cela vous permet d'utiliser une ressource personnalisée (CR) KubeletConfig
pour modifier les paramètres du kubelet.
Comme les champs de l'objet kubeletConfig
sont transmis directement au kubelet par Kubernetes en amont, le kubelet valide ces valeurs directement. Des valeurs non valides dans l'objet kubeletConfig
peuvent entraîner l'indisponibilité des nœuds du cluster. Pour connaître les valeurs valides, consultez la documentation de Kubernetes.
Examinez les conseils suivants :
-
Créez un CR
KubeletConfig
pour chaque pool de configuration de machine avec toutes les modifications de configuration que vous souhaitez pour ce pool. Si vous appliquez le même contenu à tous les pools, vous n'avez besoin que d'un seul CRKubeletConfig
pour tous les pools. -
Modifiez un CR
KubeletConfig
existant pour modifier les paramètres existants ou en ajouter de nouveaux, au lieu de créer un CR pour chaque changement. Il est recommandé de ne créer un CR que pour modifier un pool de configuration de machine différent, ou pour des changements qui sont censés être temporaires, afin de pouvoir revenir sur les modifications. -
Si nécessaire, créez plusieurs CR
KubeletConfig
dans la limite de 10 par cluster. Pour le premier CRKubeletConfig
, l'opérateur de configuration de machine (MCO) crée une configuration de machine avec l'extensionkubelet
. Pour chaque CR suivant, le contrôleur crée une autre configuration machinekubelet
avec un suffixe numérique. Par exemple, si vous avez une configuration machinekubelet
avec un suffixe-2
, la configuration machinekubelet
suivante est complétée par-3
.
Si vous souhaitez supprimer les configurations de machine, supprimez-les dans l'ordre inverse pour éviter de dépasser la limite. Par exemple, vous supprimez la configuration de la machine kubelet-3
avant de supprimer la configuration de la machine kubelet-2
.
Si vous avez une configuration de machine avec un suffixe kubelet-9
et que vous créez une autre CR KubeletConfig
, une nouvelle configuration de machine n'est pas créée, même s'il y a moins de 10 configurations de machine kubelet
.
Exemple KubeletConfig
CR
$ oc get kubeletconfig
NAME AGE set-max-pods 15m
Exemple de configuration d'une machine KubeletConfig
$ oc get mc | grep kubelet
... 99-worker-generated-kubelet-1 b5c5119de007945b6fe6fb215db3b8e2ceb12511 3.2.0 26m ...
La procédure suivante est un exemple qui montre comment configurer le nombre maximum de pods par nœud sur les nœuds de travail.
Conditions préalables
Obtenez l'étiquette associée au CR statique
MachineConfigPool
pour le type de nœud que vous souhaitez configurer. Effectuez l'une des opérations suivantes :Voir le pool de configuration de la machine :
oc describe machineconfigpool <name> $ oc describe machineconfigpool <name>
Par exemple :
$ oc describe machineconfigpool worker
Exemple de sortie
apiVersion: machineconfiguration.openshift.io/v1 kind: MachineConfigPool metadata: creationTimestamp: 2019-02-08T14:52:39Z generation: 1 labels: custom-kubelet: set-max-pods 1
- 1
- Si un label a été ajouté, il apparaît sous
labels
.
Si l'étiquette n'est pas présente, ajoutez une paire clé/valeur :
$ oc label machineconfigpool worker custom-kubelet=set-max-pods
Procédure
Affichez les objets de configuration de la machine disponibles que vous pouvez sélectionner :
$ oc get machineconfig
Par défaut, les deux configurations liées à kubelet sont
01-master-kubelet
et01-worker-kubelet
.Vérifier la valeur actuelle du nombre maximum de pods par nœud :
oc describe node <node_name>
Par exemple :
$ oc describe node ci-ln-5grqprb-f76d1-ncnqq-worker-a-mdv94
Cherchez
value: pods: <value>
dans la stropheAllocatable
:Exemple de sortie
Allocatable: attachable-volumes-aws-ebs: 25 cpu: 3500m hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 15341844Ki pods: 250
Définissez le nombre maximum de pods par nœud sur les nœuds de travail en créant un fichier de ressources personnalisé qui contient la configuration du kubelet :
apiVersion: machineconfiguration.openshift.io/v1 kind: KubeletConfig metadata: name: set-max-pods spec: machineConfigPoolSelector: matchLabels: custom-kubelet: set-max-pods 1 kubeletConfig: maxPods: 500 2
NoteLe taux auquel le kubelet parle au serveur API dépend des requêtes par seconde (QPS) et des valeurs de rafale. Les valeurs par défaut,
50
pourkubeAPIQPS
et100
pourkubeAPIBurst
, sont suffisantes si le nombre de pods fonctionnant sur chaque nœud est limité. Il est recommandé de mettre à jour les taux de QPS et de burst du kubelet s'il y a suffisamment de ressources de CPU et de mémoire sur le nœud.apiVersion: machineconfiguration.openshift.io/v1 kind: KubeletConfig metadata: name: set-max-pods spec: machineConfigPoolSelector: matchLabels: custom-kubelet: set-max-pods kubeletConfig: maxPods: <pod_count> kubeAPIBurst: <burst_rate> kubeAPIQPS: <QPS>
Mettre à jour le pool de configuration des machines pour les travailleurs avec le label :
$ oc label machineconfigpool worker custom-kubelet=set-max-pods
Créer l'objet
KubeletConfig
:$ oc create -f change-maxPods-cr.yaml
Vérifiez que l'objet
KubeletConfig
est créé :$ oc get kubeletconfig
Exemple de sortie
NAME AGE set-max-pods 15m
En fonction du nombre de nœuds de travail dans la grappe, attendez que les nœuds de travail soient redémarrés un par un. Pour une grappe de 3 nœuds de travail, cela peut prendre de 10 à 15 minutes.
Vérifiez que les modifications sont appliquées au nœud :
Vérifier sur un nœud de travail que la valeur de
maxPods
a changé :oc describe node <node_name>
Repérez la strophe
Allocatable
:... Allocatable: attachable-volumes-gce-pd: 127 cpu: 3500m ephemeral-storage: 123201474766 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 14225400Ki pods: 500 1 ...
- 1
- Dans cet exemple, le paramètre
pods
doit indiquer la valeur que vous avez définie dans l'objetKubeletConfig
.
Vérifiez la modification de l'objet
KubeletConfig
:$ oc get kubeletconfigs set-max-pods -o yaml
L'état de
True
ettype:Success
devrait apparaître, comme le montre l'exemple suivant :spec: kubeletConfig: maxPods: 500 machineConfigPoolSelector: matchLabels: custom-kubelet: set-max-pods status: conditions: - lastTransitionTime: "2021-06-30T17:04:07Z" message: Success status: "True" type: Success
7.4.3. Dimensionnement des nœuds du plan de contrôle
Les besoins en ressources des nœuds du plan de contrôle dépendent du nombre et du type de nœuds et d'objets dans le cluster. Les recommandations suivantes concernant la taille des nœuds du plan de contrôle sont basées sur les résultats d'un test focalisé sur la densité du plan de contrôle, ou Cluster-density. Ce test crée les objets suivants dans un nombre donné d'espaces de noms :
- 1 flux d'images
- 1 construire
-
5 déploiements, avec 2 répliques de pods à l'état
sleep
, montant chacun 4 secrets, 4 cartes de configuration et 1 volume d'API descendant - 5 services, chacun pointant vers les ports TCP/8080 et TCP/8443 d'un des déploiements précédents
- 1 itinéraire menant au premier des services précédents
- 10 secrets contenant 2048 caractères aléatoires
- 10 cartes de configuration contenant 2048 caractères aléatoires
Number of worker nodes | Densité de la grappe (espaces nominatifs) | Cœurs de l'unité centrale | Mémoire (GB) |
---|---|---|---|
24 | 500 | 4 | 16 |
120 | 1000 | 8 | 32 |
252 | 4000 | 16, mais 24 si l'on utilise le plug-in réseau OVN-Kubernetes | 64, mais 128 si l'on utilise le plug-in réseau OVN-Kubernetes |
501, mais non testé avec le plug-in réseau OVN-Kubernetes | 4000 | 16 | 96 |
Les données du tableau ci-dessus sont basées sur une plateforme de conteneurs OpenShift fonctionnant au-dessus d'AWS, utilisant des instances r5.4xlarge comme nœuds de plan de contrôle et des instances m5.2xlarge comme nœuds de travail.
Dans un grand cluster dense comprenant trois nœuds de plan de contrôle, l'utilisation du processeur et de la mémoire augmente lorsque l'un des nœuds est arrêté, redémarré ou tombe en panne. Les pannes peuvent être dues à des problèmes inattendus d'alimentation, de réseau, d'infrastructure sous-jacente, ou à des cas intentionnels où le cluster est redémarré après avoir été arrêté pour réduire les coûts. Les deux nœuds restants du plan de contrôle doivent gérer la charge afin d'être hautement disponibles, ce qui entraîne une augmentation de l'utilisation des ressources. Ce phénomène se produit également lors des mises à niveau, car les nœuds du plan de contrôle sont isolés, vidés et redémarrés en série pour appliquer les mises à jour du système d'exploitation, ainsi que la mise à jour des opérateurs du plan de contrôle. Pour éviter les défaillances en cascade, maintenez l'utilisation globale des ressources CPU et mémoire sur les nœuds du plan de contrôle à un maximum de 60 % de la capacité disponible afin de gérer les pics d'utilisation des ressources. Augmentez l'UC et la mémoire des nœuds du plan de contrôle en conséquence pour éviter les temps d'arrêt potentiels dus au manque de ressources.
Le dimensionnement des nœuds varie en fonction du nombre de nœuds et d'objets dans la grappe. Il dépend également de la création active d'objets sur la grappe. Pendant la création des objets, le plan de contrôle est plus actif en termes d'utilisation des ressources que lorsque les objets sont dans la phase running
.
Operator Lifecycle Manager (OLM) s'exécute sur les nœuds du plan de contrôle et son empreinte mémoire dépend du nombre d'espaces de noms et d'opérateurs installés par l'utilisateur qu'OLM doit gérer sur la grappe. Les nœuds du plan de contrôle doivent être dimensionnés en conséquence afin d'éviter les pertes de mémoire (OOM kills). Les points de données suivants sont basés sur les résultats des tests de maximisation des grappes.
Nombre d'espaces de noms | Mémoire OLM au repos (GB) | Mémoire OLM avec 5 opérateurs utilisateurs installés (GB) |
---|---|---|
500 | 0.823 | 1.7 |
1000 | 1.2 | 2.5 |
1500 | 1.7 | 3.2 |
2000 | 2 | 4.4 |
3000 | 2.7 | 5.6 |
4000 | 3.8 | 7.6 |
5000 | 4.2 | 9.02 |
6000 | 5.8 | 11.3 |
7000 | 6.6 | 12.9 |
8000 | 6.9 | 14.8 |
9000 | 8 | 17.7 |
10,000 | 9.9 | 21.6 |
Vous pouvez modifier la taille des nœuds du plan de contrôle dans un cluster OpenShift Container Platform 4.12 en cours d'exécution pour les configurations suivantes uniquement :
- Clusters installés avec une méthode d'installation fournie par l'utilisateur.
- Clusters AWS installés avec une méthode d'installation d'infrastructure fournie par l'installateur.
- Les clusters qui utilisent un jeu de machines du plan de contrôle pour gérer les machines du plan de contrôle.
Pour toutes les autres configurations, vous devez estimer le nombre total de nœuds et utiliser la taille de nœud suggérée pour le plan de contrôle lors de l'installation.
Les recommandations sont basées sur les points de données capturés sur les clusters OpenShift Container Platform avec OpenShift SDN comme plugin réseau.
Dans OpenShift Container Platform 4.12, la moitié d'un cœur de CPU (500 millicores) est désormais réservée par le système par défaut par rapport à OpenShift Container Platform 3.11 et aux versions précédentes. Les tailles sont déterminées en tenant compte de cela.
7.4.4. Configuration du gestionnaire de CPU
Procédure
Facultatif : Étiqueter un nœud :
# oc label node perf-node.example.com cpumanager=true
Modifiez le site
MachineConfigPool
des nœuds pour lesquels le gestionnaire de CPU doit être activé. Dans cet exemple, tous les travailleurs ont activé le gestionnaire de CPU :# oc edit machineconfigpool worker
Ajouter une étiquette au pool de configuration de la machine de travail :
metadata: creationTimestamp: 2020-xx-xxx generation: 3 labels: custom-kubelet: cpumanager-enabled
Créez une ressource personnalisée (CR)
KubeletConfig
,cpumanager-kubeletconfig.yaml
. Référez-vous à l'étiquette créée à l'étape précédente pour que les nœuds corrects soient mis à jour avec la nouvelle configuration du kubelet. Voir la sectionmachineConfigPoolSelector
:apiVersion: machineconfiguration.openshift.io/v1 kind: KubeletConfig metadata: name: cpumanager-enabled spec: machineConfigPoolSelector: matchLabels: custom-kubelet: cpumanager-enabled kubeletConfig: cpuManagerPolicy: static 1 cpuManagerReconcilePeriod: 5s 2
- 1
- Spécifier une politique :
-
none
. Cette politique active explicitement le schéma d'affinité CPU par défaut existant, ne fournissant aucune affinité au-delà de ce que le planificateur fait automatiquement. Il s'agit de la stratégie par défaut. -
static
. Cette politique autorise les conteneurs dans les pods garantis avec des demandes de CPU entières. Elle limite également l'accès aux CPU exclusifs sur le nœud. Sistatic
, vous devez utiliser une minuscules
.
-
- 2
- Facultatif. Indiquez la fréquence de rapprochement du gestionnaire de CPU. La valeur par défaut est
5s
.
Créer la configuration dynamique du kubelet :
# oc create -f cpumanager-kubeletconfig.yaml
Cela ajoute la fonction CPU Manager à la configuration du kubelet et, si nécessaire, le Machine Config Operator (MCO) redémarre le nœud. Pour activer le gestionnaire de CPU, un redémarrage n'est pas nécessaire.
Vérifier la configuration du kubelet fusionné :
# oc get machineconfig 99-worker-XXXXXX-XXXXX-XXXX-XXXXX-kubelet -o json | grep ownerReference -A7
Exemple de sortie
"ownerReferences": [ { "apiVersion": "machineconfiguration.openshift.io/v1", "kind": "KubeletConfig", "name": "cpumanager-enabled", "uid": "7ed5616d-6b72-11e9-aae1-021e1ce18878" } ]
Consultez le travailleur pour obtenir la mise à jour de
kubelet.conf
:# oc debug node/perf-node.example.com sh-4.2# cat /host/etc/kubernetes/kubelet.conf | grep cpuManager
Exemple de sortie
cpuManagerPolicy: static 1 cpuManagerReconcilePeriod: 5s 2
Créer un pod qui demande un ou plusieurs cœurs. Les limites et les demandes doivent avoir une valeur CPU égale à un entier. Il s'agit du nombre de cœurs qui seront dédiés à ce module :
# cat cpumanager-pod.yaml
Exemple de sortie
apiVersion: v1 kind: Pod metadata: generateName: cpumanager- spec: containers: - name: cpumanager image: gcr.io/google_containers/pause-amd64:3.0 resources: requests: cpu: 1 memory: "1G" limits: cpu: 1 memory: "1G" nodeSelector: cpumanager: "true"
Créer la capsule :
# oc create -f cpumanager-pod.yaml
Vérifiez que le pod est planifié sur le nœud que vous avez étiqueté :
# oc describe pod cpumanager
Exemple de sortie
Name: cpumanager-6cqz7 Namespace: default Priority: 0 PriorityClassName: <none> Node: perf-node.example.com/xxx.xx.xx.xxx ... Limits: cpu: 1 memory: 1G Requests: cpu: 1 memory: 1G ... QoS Class: Guaranteed Node-Selectors: cpumanager=true
Vérifiez que l'adresse
cgroups
est correctement configurée. Obtenir l'ID du processus (PID) du processuspause
:# ├─init.scope │ └─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 17 └─kubepods.slice ├─kubepods-pod69c01f8e_6b74_11e9_ac0f_0a2b62178a22.slice │ ├─crio-b5437308f1a574c542bdf08563b865c0345c8f8c0b0a655612c.scope │ └─32706 /pause
Les pods du niveau de qualité de service (QoS)
Guaranteed
sont placés à l'intérieur du sitekubepods.slice
. Les pods des autres niveaux de QoS se retrouvent dans les enfantscgroups
dekubepods
:# cd /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod69c01f8e_6b74_11e9_ac0f_0a2b62178a22.slice/crio-b5437308f1ad1a7db0574c542bdf08563b865c0345c86e9585f8c0b0a655612c.scope # for i in `ls cpuset.cpus tasks` ; do echo -n "$i "; cat $i ; done
Exemple de sortie
cpuset.cpus 1 tasks 32706
Vérifiez la liste des unités centrales autorisées pour la tâche :
# grep ^Cpus_allowed_list /proc/32706/status
Exemple de sortie
Cpus_allowed_list: 1
Vérifiez qu'un autre pod (dans ce cas, le pod du niveau de qualité de service
burstable
) sur le système ne peut pas fonctionner sur le cœur alloué au podGuaranteed
:# cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podc494a073_6b77_11e9_98c0_06bba5c387ea.slice/crio-c56982f57b75a2420947f0afc6cafe7534c5734efc34157525fa9abbf99e3849.scope/cpuset.cpus 0 # oc describe node perf-node.example.com
Exemple de sortie
... Capacity: attachable-volumes-aws-ebs: 39 cpu: 2 ephemeral-storage: 124768236Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 8162900Ki pods: 250 Allocatable: attachable-volumes-aws-ebs: 39 cpu: 1500m ephemeral-storage: 124768236Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 7548500Ki pods: 250 ------- ---- ------------ ---------- --------------- ------------- --- default cpumanager-6cqz7 1 (66%) 1 (66%) 1G (12%) 1G (12%) 29m Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 1440m (96%) 1 (66%)
Cette VM dispose de deux cœurs de processeur. Le paramètre
system-reserved
réserve 500 millicores, ce qui signifie que la moitié d'un cœur est soustraite de la capacité totale du nœud pour obtenir la quantitéNode Allocatable
. Vous pouvez voir queAllocatable CPU
est de 1500 millicores. Cela signifie que vous pouvez exécuter l'un des pods du gestionnaire de CPU, puisque chacun d'entre eux prendra un cœur entier. Un cœur entier est équivalent à 1000 millicores. Si vous essayez de planifier un deuxième module, le système acceptera le module, mais il ne sera jamais planifié :NAME READY STATUS RESTARTS AGE cpumanager-6cqz7 1/1 Running 0 33m cpumanager-7qc2t 0/1 Pending 0 11s