Créer un kube-scheduler supplémentaire avec un ensemble personnalisé de règles de planification

Créer un kube-scheduler supplémentaire avec un ensemble personnalisé de règles de planification

Kube-scheduler fait partie intégrante de Kubernetes, qui est responsable de la planification des pods sur les nœuds conformément aux politiques spécifiées. Souvent, lors du fonctionnement d'un cluster Kubernetes, nous n'avons pas à penser aux politiques utilisées pour planifier les pods, car l'ensemble des politiques du kube-scheduler par défaut est adapté à la plupart des tâches quotidiennes. Cependant, il existe des situations dans lesquelles il est important pour nous d'affiner le processus d'attribution des pods, et il existe deux manières d'accomplir cette tâche :

  1. Créez un planificateur Kube avec un ensemble de règles personnalisées
  2. Écrivez votre propre planificateur et apprenez-lui à travailler avec les requêtes du serveur API

Dans cet article, je décrirai la mise en œuvre du premier point pour résoudre le problème de programmation inégale des foyers sur l'un de nos projets.

Une brève introduction au fonctionnement de Kube-Scheduler

Il convient particulièrement de noter le fait que kube-scheduler n'est pas responsable de la planification directe des pods - il est uniquement responsable de la détermination du nœud sur lequel placer le pod. En d'autres termes, le résultat du travail de kube-scheduler est le nom du nœud qu'il renvoie au serveur API pour une demande de planification, et c'est là que se termine son travail.

Tout d'abord, kube-scheduler compile une liste de nœuds sur lesquels le pod peut être planifié conformément aux politiques de prédicats. Ensuite, chaque nœud de cette liste reçoit un certain nombre de points conformément aux priorités politiques. En conséquence, le nœud avec le nombre maximum de points est sélectionné. S'il existe des nœuds qui ont le même score maximum, un nœud aléatoire est sélectionné. Une liste et une description des politiques de prédicats (filtrage) et de priorités (notation) peuvent être trouvées dans documentation.

Description du corps à problème

Malgré le grand nombre de clusters Kubernetes différents maintenus chez Nixys, nous n'avons rencontré le problème de planification des pods que récemment, lorsqu'un de nos projets devait exécuter un grand nombre de tâches périodiques (~ 100 entités CronJob). Pour simplifier au maximum la description du problème, nous prendrons comme exemple un microservice, au sein duquel une tâche cron est lancée une fois par minute, créant une certaine charge sur le CPU. Pour exécuter la tâche cron, trois nœuds avec des caractéristiques absolument identiques ont été alloués (24 vCPU sur chacun).

Dans le même temps, il est impossible de dire avec précision combien de temps il faudra pour exécuter le CronJob, car le volume des données d'entrée change constamment. En moyenne, pendant le fonctionnement normal de kube-scheduler, chaque nœud exécute 3 à 4 instances de tâche, qui créent environ 20 à 30 % de la charge sur le processeur de chaque nœud :

Créer un kube-scheduler supplémentaire avec un ensemble personnalisé de règles de planification

Le problème lui-même est que parfois les modules de tâches périodiques cessent d'être planifiés sur l'un des trois nœuds. Autrement dit, à un moment donné, aucun pod n'était prévu pour l'un des nœuds, tandis que sur les deux autres nœuds, 6 à 8 copies de la tâche étaient en cours d'exécution, créant environ 40 à 60 % de la charge CPU :

Créer un kube-scheduler supplémentaire avec un ensemble personnalisé de règles de planification

Le problème réapparaissait à une fréquence absolument aléatoire et était parfois corrélé au moment où une nouvelle version du code était déployée.

En augmentant le niveau de journalisation de Kube-Scheduler au niveau 10 (-v=10), nous avons commencé à enregistrer le nombre de points gagnés par chaque nœud au cours du processus d'évaluation. Pendant les opérations normales de planification, les informations suivantes peuvent être vues dans les journaux :

resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node03: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1387 millicores 4161694720 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node02: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1347 millicores 4444810240 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node03: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1387 millicores 4161694720 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node01: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1687 millicores 4790840320 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node02: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1347 millicores 4444810240 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node01: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1687 millicores 4790840320 memory bytes, score 9
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node01: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node02: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node03: NodeAffinityPriority, Score: (0)                                                                                       
interpod_affinity.go:237] cronjob-1574828880-mn7m4 -> Node01: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node01: TaintTolerationPriority, Score: (10)                                                                                   
interpod_affinity.go:237] cronjob-1574828880-mn7m4 -> Node02: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node02: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574828880-mn7m4 -> Node01: SelectorSpreadPriority, Score: (10)                                                                                                        
interpod_affinity.go:237] cronjob-1574828880-mn7m4 -> Node03: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node03: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574828880-mn7m4 -> Node02: SelectorSpreadPriority, Score: (10)                                                                                                        
selector_spreading.go:146] cronjob-1574828880-mn7m4 -> Node03: SelectorSpreadPriority, Score: (10)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node01: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node02: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node03: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:781] Host Node01 => Score 100043                                                                                                                                                                        
generic_scheduler.go:781] Host Node02 => Score 100043                                                                                                                                                                        
generic_scheduler.go:781] Host Node03 => Score 100043

Ceux. à en juger par les informations obtenues à partir des journaux, chacun des nœuds a obtenu un nombre égal de points finaux et un nœud aléatoire a été sélectionné pour la planification. Au moment de la planification problématique, les journaux ressemblaient à ceci :

resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node02: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1587 millicores 4581125120 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node03: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1087 millicores 3532549120 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node02: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1587 millicores 4581125120 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node01: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 987 millicores 3322833920 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node01: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 987 millicores 3322833920 memory bytes, score 9 
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node03: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1087 millicores 3532549120 memory bytes, score 9
interpod_affinity.go:237] cronjob-1574211360-bzfkr -> Node03: InterPodAffinityPriority, Score: (0)                                                                                                        
interpod_affinity.go:237] cronjob-1574211360-bzfkr -> Node02: InterPodAffinityPriority, Score: (0)                                                                                                        
interpod_affinity.go:237] cronjob-1574211360-bzfkr -> Node01: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node03: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574211360-bzfkr -> Node03: SelectorSpreadPriority, Score: (10)                                                                                                        
selector_spreading.go:146] cronjob-1574211360-bzfkr -> Node02: SelectorSpreadPriority, Score: (10)                                                                                                        
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node02: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574211360-bzfkr -> Node01: SelectorSpreadPriority, Score: (10)                                                                                                        
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node03: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node03: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node02: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node01: TaintTolerationPriority, Score: (10)                                                                                   
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node02: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node01: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node01: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:781] Host Node03 => Score 100041                                                                                                                                                                        
generic_scheduler.go:781] Host Node02 => Score 100041                                                                                                                                                                        
generic_scheduler.go:781] Host Node01 => Score 100038

D'où il ressort que l'un des nœuds a obtenu moins de points finaux que les autres et que la planification n'a donc été effectuée que pour les deux nœuds ayant obtenu le score maximum. Ainsi, nous étions définitivement convaincus que le problème réside précisément dans la programmation des pods.

L'algorithme supplémentaire pour résoudre le problème nous était évident - analyser les journaux, comprendre par quelle priorité le nœud n'a pas marqué de points et, si nécessaire, ajuster les politiques du planificateur kube par défaut. Cependant, nous sommes ici confrontés à deux difficultés importantes :

  1. Au niveau de journalisation maximum (10), les points gagnés uniquement pour certaines priorités sont reflétés. Dans l'extrait de journaux ci-dessus, vous pouvez voir que pour toutes les priorités reflétées dans les journaux, les nœuds obtiennent le même nombre de points dans la planification normale et dans la planification des problèmes, mais le résultat final dans le cas de la planification des problèmes est différent. Ainsi, nous pouvons conclure que pour certaines priorités, la notation se produit « en coulisses », et nous n'avons aucun moyen de comprendre pour quelle priorité le nœud n'a pas obtenu de points. Nous avons décrit ce problème en détail dans aide Dépôt Kubernetes sur Github. Au moment de la rédaction de cet article, les développeurs ont répondu que la prise en charge de la journalisation serait ajoutée dans les mises à jour de Kubernetes v1.15,1.16, 1.17 et XNUMX.
  2. Il n'existe pas de moyen simple de comprendre avec quel ensemble spécifique de politiques kube-scheduler travaille actuellement. Oui, dans documentation cette liste est répertoriée, mais elle ne contient pas d'informations sur les pondérations spécifiques attribuées à chacune des politiques prioritaires. Vous pouvez voir les pondérations ou modifier les politiques du kube-scheduler par défaut uniquement dans sources.

Il convient de noter qu'une fois, nous avons pu enregistrer qu'un nœud n'a pas reçu de points conformément à la politique ImageLocalityPriority, qui attribue des points à un nœud s'il possède déjà l'image nécessaire pour exécuter l'application. Autrement dit, au moment du déploiement d'une nouvelle version de l'application, la tâche cron a réussi à s'exécuter sur deux nœuds, en téléchargeant une nouvelle image du registre Docker vers eux, et ainsi deux nœuds ont reçu un score final plus élevé par rapport au troisième. .

Comme je l'ai écrit ci-dessus, dans les journaux, nous ne voyons pas d'informations sur l'évaluation de la politique ImageLocalityPriority, donc afin de vérifier notre hypothèse, nous avons vidé l'image avec la nouvelle version de l'application sur le troisième nœud, après quoi la planification a fonctionné correctement. . C'est précisément à cause de la politique ImageLocalityPriority que le problème de planification a été observé assez rarement ; le plus souvent, il était associé à autre chose. Étant donné que nous ne pouvions pas déboguer complètement chacune des politiques de la liste des priorités du kube-scheduler par défaut, nous avions besoin d'une gestion flexible des politiques de planification des pods.

Formulation du problème

Nous voulions que la solution au problème soit aussi spécifique que possible, c'est-à-dire que les principales entités de Kubernetes (nous entendons ici le kube-scheduler par défaut) devraient rester inchangées. Nous ne voulions pas résoudre un problème à un endroit et le créer à un autre. Ainsi, nous sommes arrivés à deux options pour résoudre le problème, qui ont été annoncées dans l'introduction de l'article : créer un planificateur supplémentaire ou écrire le vôtre. La principale exigence pour la planification des tâches cron est de répartir la charge uniformément sur trois nœuds. Cette exigence peut être satisfaite par les politiques de kube-scheduler existantes, donc pour résoudre notre problème, il ne sert à rien d'écrire votre propre planificateur.

Les instructions pour créer et déployer un kube-scheduler supplémentaire sont décrites dans documentation. Cependant, il nous a semblé que l'entité de déploiement n'était pas suffisante pour assurer la tolérance aux pannes dans le fonctionnement d'un service aussi critique que kube-scheduler, nous avons donc décidé de déployer un nouveau kube-scheduler en tant que pod statique, qui serait directement surveillé. par Kubelet. Ainsi, nous avons les exigences suivantes pour le nouveau kube-scheduler :

  1. Le service doit être déployé en tant que pod statique sur tous les maîtres de cluster
  2. Une tolérance aux pannes doit être fournie au cas où le pod actif avec kube-scheduler ne serait pas disponible
  3. La principale priorité lors de la planification doit être le nombre de ressources disponibles sur le nœud (LeastRequestedPriority)

Implémentation de la solution

Il convient de noter d'emblée que nous effectuerons tous les travaux dans Kubernetes v1.14.7, car Il s'agit de la version utilisée dans le projet. Commençons par rédiger un manifeste pour notre nouveau kube-scheduler. Prenons comme base le manifeste par défaut (/etc/kubernetes/manifests/kube-scheduler.yaml) et amenons-le sous la forme suivante :

kind: Pod
metadata:
  labels:
    component: scheduler
    tier: control-plane
  name: kube-scheduler-cron
  namespace: kube-system
spec:
      containers:
      - command:
        - /usr/local/bin/kube-scheduler
        - --address=0.0.0.0
        - --port=10151
        - --secure-port=10159
        - --config=/etc/kubernetes/scheduler-custom.conf
        - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
        - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
        - --v=2
        image: gcr.io/google-containers/kube-scheduler:v1.14.7
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 8
          httpGet:
            host: 127.0.0.1
            path: /healthz
            port: 10151
            scheme: HTTP
          initialDelaySeconds: 15
          timeoutSeconds: 15
        name: kube-scheduler-cron-container
        resources:
          requests:
            cpu: '0.1'
        volumeMounts:
        - mountPath: /etc/kubernetes/scheduler.conf
          name: kube-config
          readOnly: true
        - mountPath: /etc/localtime
          name: localtime
          readOnly: true
        - mountPath: /etc/kubernetes/scheduler-custom.conf
          name: scheduler-config
          readOnly: true
        - mountPath: /etc/kubernetes/scheduler-custom-policy-config.json
          name: policy-config
          readOnly: true
      hostNetwork: true
      priorityClassName: system-cluster-critical
      volumes:
      - hostPath:
          path: /etc/kubernetes/scheduler.conf
          type: FileOrCreate
        name: kube-config
      - hostPath:
          path: /etc/localtime
        name: localtime
      - hostPath:
          path: /etc/kubernetes/scheduler-custom.conf
          type: FileOrCreate
        name: scheduler-config
      - hostPath:
          path: /etc/kubernetes/scheduler-custom-policy-config.json
          type: FileOrCreate
        name: policy-config

En bref sur les principaux changements :

  1. Changement du nom du pod et du conteneur en kube-scheduler-cron
  2. Spécifié l'utilisation des ports 10151 et 10159 lors de la définition de l'option hostNetwork: true et nous ne pouvons pas utiliser les mêmes ports que le kube-scheduler par défaut (10251 et 10259)
  3. À l'aide du paramètre --config, nous avons spécifié le fichier de configuration avec lequel le service doit être démarré
  4. Montage configuré du fichier de configuration (scheduler-custom.conf) et du fichier de stratégie de planification (scheduler-custom-policy-config.json) à partir de l'hôte

N'oubliez pas que notre kube-scheduler aura besoin de droits similaires à ceux par défaut. Modifiez son rôle de cluster :

kubectl edit clusterrole system:kube-scheduler

...
   resourceNames:
    - kube-scheduler
    - kube-scheduler-cron
...

Parlons maintenant de ce qui doit être contenu dans le fichier de configuration et le fichier de politique de planification :

  • Fichier de configuration (scheduler-custom.conf)
    Pour obtenir la configuration par défaut de kube-scheduler, vous devez utiliser le paramètre --write-config-to de documentation. Nous placerons la configuration résultante dans le fichier /etc/kubernetes/scheduler-custom.conf et la réduirons à la forme suivante :

apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
schedulerName: kube-scheduler-cron
bindTimeoutSeconds: 600
clientConnection:
  acceptContentTypes: ""
  burst: 100
  contentType: application/vnd.kubernetes.protobuf
  kubeconfig: /etc/kubernetes/scheduler.conf
  qps: 50
disablePreemption: false
enableContentionProfiling: false
enableProfiling: false
failureDomains: kubernetes.io/hostname,failure-domain.beta.kubernetes.io/zone,failure-domain.beta.kubernetes.io/region
hardPodAffinitySymmetricWeight: 1
healthzBindAddress: 0.0.0.0:10151
leaderElection:
  leaderElect: true
  leaseDuration: 15s
  lockObjectName: kube-scheduler-cron
  lockObjectNamespace: kube-system
  renewDeadline: 10s
  resourceLock: endpoints
  retryPeriod: 2s
metricsBindAddress: 0.0.0.0:10151
percentageOfNodesToScore: 0
algorithmSource:
   policy:
     file:
       path: "/etc/kubernetes/scheduler-custom-policy-config.json"

En bref sur les principaux changements :

  1. Nous définissons SchedulerName sur le nom de notre service kube-scheduler-cron.
  2. Dans le paramètre lockObjectName vous devez également définir le nom de notre service et vous assurer que le paramètre leaderElect défini sur true (si vous avez un nœud maître, vous pouvez le définir sur false).
  3. Spécifié le chemin d'accès au fichier avec une description des politiques de planification dans le paramètre algorithmSource.

Cela vaut la peine d'examiner de plus près le deuxième point, où nous modifions les paramètres de la clé. leaderElection. Pour garantir la tolérance aux pannes, nous avons activé (leaderElect) le processus de sélection d'un leader (maître) entre les pods de notre kube-scheduler en utilisant un seul point de terminaison pour eux (resourceLock) nommé kube-scheduler-cron (lockObjectName) dans l'espace de noms du système Kube (lockObjectNamespace). La manière dont Kubernetes garantit la haute disponibilité des principaux composants (y compris Kube-scheduler) peut être trouvée dans article.

  • Fichier de stratégie de planification (scheduler-custom-policy-config.json)
    Comme je l'ai écrit plus tôt, nous pouvons découvrir avec quelles politiques spécifiques le kube-scheduler par défaut fonctionne uniquement en analysant son code. Autrement dit, nous ne pouvons pas obtenir un fichier avec des politiques de planification pour le kube-scheduler par défaut de la même manière qu'un fichier de configuration. Décrivons les politiques de planification qui nous intéressent dans le fichier /etc/kubernetes/scheduler-custom-policy-config.json comme suit :

{
  "kind": "Policy",
  "apiVersion": "v1",
  "predicates": [
    {
      "name": "GeneralPredicates"
    }
  ],
  "priorities": [
    {
      "name": "ServiceSpreadingPriority",
      "weight": 1
    },
    {
      "name": "EqualPriority",
      "weight": 1
    },
    {
      "name": "LeastRequestedPriority",
      "weight": 1
    },
    {
      "name": "NodePreferAvoidPodsPriority",
      "weight": 10000
    },
    {
      "name": "NodeAffinityPriority",
      "weight": 1
    }
  ],
  "hardPodAffinitySymmetricWeight" : 10,
  "alwaysCheckAllPredicates" : false
}

Ainsi, kube-scheduler compile d'abord une liste de nœuds sur lesquels un pod peut être planifié conformément à la politique GeneralPredicates (qui comprend un ensemble de politiques PodFitsResources, PodFitsHostPorts, HostName et MatchNodeSelector). Ensuite, chaque nœud est évalué conformément à l'ensemble de politiques du tableau des priorités. Pour remplir les conditions de notre tâche, nous avons considéré qu’un tel ensemble de politiques serait la solution optimale. Permettez-moi de vous rappeler qu'un ensemble de politiques avec leurs descriptions détaillées est disponible dans documentation. Pour accomplir votre tâche, vous pouvez simplement modifier l’ensemble des politiques utilisées et leur attribuer des pondérations appropriées.

Appelons le manifeste du nouveau kube-scheduler, que nous avons créé au début du chapitre, kube-scheduler-custom.yaml et plaçons-le dans le chemin suivant /etc/kubernetes/manifests sur trois nœuds maîtres. Si tout est fait correctement, Kubelet lancera un pod sur chaque nœud, et dans les journaux de notre nouveau kube-scheduler, nous verrons des informations indiquant que notre fichier de stratégie a été appliqué avec succès :

Creating scheduler from configuration: {{ } [{GeneralPredicates <nil>}] [{ServiceSpreadingPriority 1 <nil>} {EqualPriority 1 <nil>} {LeastRequestedPriority 1 <nil>} {NodePreferAvoidPodsPriority 10000 <nil>} {NodeAffinityPriority 1 <nil>}] [] 10 false}
Registering predicate: GeneralPredicates
Predicate type GeneralPredicates already registered, reusing.
Registering priority: ServiceSpreadingPriority
Priority type ServiceSpreadingPriority already registered, reusing.
Registering priority: EqualPriority
Priority type EqualPriority already registered, reusing.
Registering priority: LeastRequestedPriority
Priority type LeastRequestedPriority already registered, reusing.
Registering priority: NodePreferAvoidPodsPriority
Priority type NodePreferAvoidPodsPriority already registered, reusing.
Registering priority: NodeAffinityPriority
Priority type NodeAffinityPriority already registered, reusing.
Creating scheduler with fit predicates 'map[GeneralPredicates:{}]' and priority functions 'map[EqualPriority:{} LeastRequestedPriority:{} NodeAffinityPriority:{} NodePreferAvoidPodsPriority:{} ServiceSpreadingPriority:{}]'

Il ne reste plus qu'à indiquer dans la spec de notre CronJob que toutes les requêtes de planification de ses pods doivent être traitées par notre nouveau kube-scheduler :

...
 jobTemplate:
    spec:
      template:
        spec:
          schedulerName: kube-scheduler-cron
...

Conclusion

En fin de compte, nous avons obtenu un kube-scheduler supplémentaire avec un ensemble unique de politiques de planification, dont le travail est surveillé directement par le kubelet. De plus, nous avons mis en place l'élection d'un nouveau leader entre les pods de notre kube-scheduler au cas où l'ancien leader deviendrait indisponible pour une raison quelconque.

Les applications et services réguliers continuent d'être planifiés via le kube-scheduler par défaut, et toutes les tâches cron ont été entièrement transférées vers le nouveau. La charge créée par les tâches cron est désormais répartie uniformément sur tous les nœuds. Considérant que la plupart des tâches cron sont exécutées sur les mêmes nœuds que les principales applications du projet, cela a considérablement réduit le risque de déplacement des pods en raison du manque de ressources. Après l'introduction du kube-scheduler supplémentaire, les problèmes de planification inégale des tâches cron ne se sont plus posés.

Lisez également d'autres articles sur notre blog:

Source: habr.com

Ajouter un commentaire