Creazione di un kube-scheduler aggiuntivo con un set personalizzato di regole di pianificazione

Creazione di un kube-scheduler aggiuntivo con un set personalizzato di regole di pianificazione

Kube-Scheduler è un componente integrale di Kubernetes, che è responsabile della pianificazione di pod attraverso i nodi in conformità con le politiche specifiche. Spesso, durante il funzionamento di un cluster di Kubernetes, non dobbiamo pensare a quali politiche vengono utilizzate per pianificare i baccelli, poiché il set di politiche del kube-scheduler predefinito è adatto alla maggior parte delle attività quotidiane. Tuttavia, ci sono situazioni in cui è importante per noi perfezionare il processo di allocazione dei pod e ci sono due modi per svolgere questo compito:

  1. Crea un Kube-Scheduler con un set personalizzato di regole
  2. Scrivi il tuo scheduler e insegnalo a lavorare con le richieste del server API

In questo articolo, descriverò l'implementazione del primo punto per risolvere il problema della pianificazione irregolare dei focolari su uno dei nostri progetti.

Una breve introduzione a come funziona Kube-Scheduler

Vale la pena notare in particolare il fatto che kube-scheduler non è responsabile della pianificazione diretta dei pod, ma solo della determinazione del nodo su cui posizionare il pod. In altre parole, il risultato del lavoro di kube-scheduler è il nome del nodo, che restituisce al server API per una richiesta di pianificazione, ed è lì che finisce il suo lavoro.

Innanzitutto, Kube-Scheduler compila un elenco di nodi su cui il pod può essere programmato in conformità con le politiche dei predicati. Successivamente, ogni nodo di questo elenco riceve un certo numero di punti in conformità con le politiche delle priorità. Di conseguenza, viene selezionato il nodo con il numero massimo di punti. Se ci sono nodi che hanno lo stesso punteggio massimo, viene selezionato uno casuale. Un elenco e una descrizione delle politiche predicate (filtraggio) e priorite (punteggio) sono disponibili in documentazione.

Descrizione del problema del problema

Nonostante il gran numero di diversi cluster Kubernetes mantenuti presso Nixys, abbiamo riscontrato per la prima volta il problema della pianificazione dei pod solo di recente, quando uno dei nostri progetti aveva bisogno di eseguire un gran numero di attività periodiche (~ 100 entità CronJob). Per semplificare il più possibile la descrizione del problema, prenderemo come esempio un microservizio, all'interno del quale un'attività cron viene avviata una volta al minuto, creando un certo carico sulla CPU. Per eseguire l'attività cron sono stati allocati tre nodi con caratteristiche assolutamente identiche (24 vCPU ciascuno).

Allo stesso tempo, è impossibile dire con precisione quanto tempo impiegherà il Cronjob, poiché il volume dei dati di input è in costante cambiamento. In media, durante il normale funzionamento di Kube-Scheduler, ogni nodo esegue 3-4 istanze di lavoro, che creano ~ 20-30% del carico sulla CPU di ciascun nodo:

Creazione di un kube-scheduler aggiuntivo con un set personalizzato di regole di pianificazione

Il problema stesso è che a volte i pod di attività di Cron hanno smesso di essere programmati su uno dei tre nodi. Cioè, ad un certo punto, non è stato programmato un singolo pod per uno dei nodi, mentre sulle altre due copie 6-8 dei nodi dell'attività erano in esecuzione, creando ~ 40-60% del carico della CPU:

Creazione di un kube-scheduler aggiuntivo con un set personalizzato di regole di pianificazione

Il problema si è ripreso con frequenza assolutamente casuale e occasionalmente correlato al momento in cui è stata lanciata una nuova versione del codice.

Aumentando il livello di registrazione di Kube-Scheduler al livello 10 (-v = 10), abbiamo iniziato a registrare quanti punti ogni nodo ottenuto durante il processo di valutazione. Durante la normale operazione di pianificazione, nei registri potrebbero essere visualizzate le seguenti informazioni:

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

Quelli. A giudicare dalle informazioni ottenute dai registri, ciascuno dei nodi ha ottenuto un numero uguale di punti finali e uno casuale è stato selezionato per la pianificazione. Al momento della pianificazione problematica, i registri sembravano così:

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

Da cui si vede che uno dei nodi ha ottenuto meno punti finali degli altri, e quindi la pianificazione è stata effettuata solo per i due nodi che hanno ottenuto il punteggio massimo. Eravamo quindi decisamente convinti che il problema risiedesse proprio nella programmazione dei pod.

L'ulteriore algoritmo per risolvere il problema era ovvio per noi: analizzare i registri, capire con la priorità che il nodo non ha segnato punti e, se necessario, regola le politiche del kube -scheduler predefinito. Tuttavia, qui ci troviamo di fronte a due difficoltà significative:

  1. Al livello di registrazione massimo (10), i punti ottenuti solo per alcune priorità si riflettono. Nell'estratto di cui sopra, puoi vedere che per tutte le priorità riflesse nei registri, i nodi ottengono lo stesso numero di punti nella pianificazione normale e dei problemi, ma il risultato finale nel caso della pianificazione dei problemi è diverso. Pertanto, possiamo concludere che per alcune priorità, il punteggio si verifica "dietro le quinte" e non abbiamo modo di capire per quale priorità il nodo non ha ottenuto punti. Abbiamo descritto questo problema in dettaglio in problema Repository di Kubernetes su GitHub. Al momento della stesura, è stata ricevuta una risposta dagli sviluppatori che il supporto di registrazione verrà aggiunta negli aggiornamenti Kubernetes v1.15,1.16, 1.17 e XNUMX.
  2. Non esiste un modo semplice per capire con quale insieme specifico di policy kube-scheduler sta attualmente lavorando. Sì, dentro documentazione questo elenco è elencato, ma non contiene informazioni su quali pesi specifici sono assegnati a ciascuna delle politiche prioritarie. Puoi visualizzare i pesi o modificare le policy del kube-scheduler predefinito solo in Codici di origine.

Vale la pena notare che una volta che siamo stati in grado di registrare che un nodo non ha ricevuto punti in base alla politica di impriorità Imagity, che premi indica un nodo se ha già l'immagine necessaria per eseguire l'applicazione. Cioè, al momento che una nuova versione dell'applicazione è stata lanciata, l'attività Cron è riuscita a eseguire su due nodi, scaricando loro una nuova immagine dal registro Docker, e quindi due nodi hanno ricevuto un punteggio finale più alto rispetto al terzo .

Come ho scritto sopra, nei registri non vediamo informazioni sulla valutazione della politica della priorità Imagity, quindi per verificare la nostra ipotesi, abbiamo scaricato l'immagine con la nuova versione dell'applicazione sul terzo nodo, dopo di che la programmazione ha funzionato correttamente . Era proprio a causa della politica della priorità dell'immagini che il problema di programmazione fosse stato osservato in modo abbastanza raramente; più spesso era associato a qualcos'altro. A causa del fatto che non abbiamo potuto eseguire il debug completamente ciascuna delle politiche nell'elenco delle priorità del Kube-Scheduler predefinito, abbiamo avuto bisogno di una gestione flessibile delle politiche di pianificazione dei pod.

Formulazione del problema

Volevamo che la soluzione al problema fosse il più specifico possibile, cioè le principali entità di Kubernetes (qui intendiamo che il kube-scheduler predefinito) dovrebbe rimanere invariata. Non volevamo risolvere un problema in un posto e crearlo in un altro. Pertanto, siamo arrivati ​​a due opzioni per risolvere il problema, che sono state annunciate nell'introduzione all'articolo: creando un programma aggiuntivo o scrivendo il tuo. Il requisito principale per la pianificazione delle attività Cron è distribuire uniformemente il carico su tre nodi. Questo requisito può essere soddisfatto dalle politiche esistenti di Kube-Scheduler, quindi per risolvere il nostro problema non ha senso scrivere il proprio programma.

Le istruzioni per la creazione e la distribuzione di un kube-scheduler aggiuntivo sono descritte in documentazione. Tuttavia, ci è sembrato che l'entità Deployment non fosse sufficiente per garantire la tolleranza agli errori nel funzionamento di un servizio così critico come kube-scheduler, quindi abbiamo deciso di implementare un nuovo kube-scheduler come pod statico, che sarebbe stato monitorato direttamente di Kubelet. Pertanto, abbiamo i seguenti requisiti per il nuovo kube-scheduler:

  1. Il servizio deve essere distribuito come pod statico su tutti i maestri del cluster
  2. È necessario fornire la tolleranza agli errori nel caso in cui il pod attivo con kube-scheduler non sia disponibile
  3. La priorità principale quando la pianificazione dovrebbe essere il numero di risorse disponibili sul nodo (LeasTrequestpriority)

Soluzioni di implementazione

Vale la pena notare subito che svolgeremo tutto il lavoro in Kubernetes v1.14.7, perché Questa è la versione utilizzata nel progetto. Cominciamo scrivendo un manifesto per il nostro nuovo Kube-Scheduler. Prendiamo il manifest predefinito (/etc/kubernetes/manifests/kube-scheduler.yaml) come base e portiamolo al seguente modulo:

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

Brevemente le principali modifiche:

  1. Ha cambiato il nome del baccello e del contenitore in kube-scheduler-cron
  2. Specificato l'uso delle porte 10151 e 10159 come opzione è stata definita hostNetwork: true e non possiamo usare le stesse porte del Kube-Scheduler predefinito (10251 e 10259)
  3. Utilizzando il parametro - -config, abbiamo specificato il file di configurazione con cui il servizio dovrebbe essere avviato
  4. Montaggio configurato del file di configurazione (scheduler-custom.conf) e del file dei criteri di pianificazione (scheduler-custom-policy-config.json) dall'host

Non dimenticare che il nostro kube-scheduler avrà bisogno di diritti simili a quelli predefiniti. Modifica il suo ruolo del cluster:

kubectl edit clusterrole system:kube-scheduler

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

Ora parliamo di ciò che dovrebbe essere contenuto nel file di configurazione e nel file del criterio di pianificazione:

  • File di configurazione (scheduler-custom.conf)
    Per ottenere la configurazione predefinita di Kube-Scheduler, è necessario utilizzare il parametro --write-config-to di documentazione. Posizioneremo la configurazione risultante nel file /etc/kubernetes/scheduler-custom.conf e la ridurrà al seguente modulo:

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"

Brevemente le principali modifiche:

  1. Abbiamo impostato il programma di programmazione sul nome del nostro servizio Kube-Scheduler-Cron.
  2. Nel parametro lockObjectName È inoltre necessario impostare il nome del nostro servizio e assicurarti che il parametro leaderElect Imposta su true (se hai un nodo principale, puoi impostarlo su False).
  3. Specificato il percorso del file con una descrizione delle politiche di pianificazione nel parametro algorithmSource.

Vale la pena dare un'occhiata più da vicino al secondo punto, in cui modifichiamo i parametri per la chiave leaderElection. Per garantire la tolleranza ai guasti, abbiamo abilitato (leaderElect) Il processo di selezione di un leader (master) tra i baccelli del nostro Kube-Scheduler usando un singolo endpoint per loro (resourceLock) chiamato kube-scheduler-cron (lockObjectName) nello spazio dei nomi del sistema kube (lockObjectNamespace). Il modo in cui Kubernetes garantisce l'elevata disponibilità dei componenti principali (incluso kube-scheduler) può essere trovato in Articolo.

  • File dei criteri di pianificazione (Scheduler-Custom-Policy-Config.json)
    Come ho scritto in precedenza, possiamo scoprire con quali politiche specifiche il Kube-Scheduler predefinito funziona solo analizzando il suo codice. Cioè, non possiamo ottenere un file con politiche di pianificazione per il kube-scheduler predefinito allo stesso modo di un file di configurazione. Descriviamo le politiche di pianificazione a cui siamo interessati nel file /etc/kubernetes/scheduler-custom-policy-config.json come segue:

{
  "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
}

Pertanto, Kube-Scheduler compila per la prima volta un elenco di nodi a cui un pod può essere programmato secondo la politica GeneralPredicates (che include una serie di podfitsresources, podshostsports, nome host e politiche di matchnodeselector). E quindi ogni nodo viene valutato in conformità con l'insieme di politiche nell'array di priorità. Per adempiere alle condizioni del nostro compito, abbiamo ritenuto che tale insieme di politiche sarebbe la soluzione ottimale. Lascia che ti ricordi che è disponibile una serie di politiche con le loro descrizioni dettagliate documentazione. Per portare a termine il tuo compito, puoi semplicemente modificare l'insieme di policy utilizzate e assegnare loro i pesi appropriati.

Chiamiamo il manifest del nuovo Kube-Scheduler, che abbiamo creato all'inizio del capitolo, kube-scheduler-custom.yaml e posizionalo nel seguente percorso/etc/kubernetes/manifesti su tre nodi principali. Se tutto viene fatto correttamente, Kubelet lancerà un pod su ciascun nodo e nei registri del nostro nuovo Kube-Scheduler vedremo le informazioni che il nostro file di politica è stato applicato correttamente:

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:{}]'

Ora tutto ciò che rimane è indicare nella specifica del nostro Cronjob che tutte le richieste di pianificazione dei suoi pod dovrebbero essere elaborate dal nostro nuovo Kube-Scheduler:

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

conclusione

Alla fine, abbiamo ottenuto un ulteriore Kube-Scheduler con una serie unica di politiche di pianificazione, il cui lavoro è monitorato direttamente dal kubelet. Inoltre, abbiamo creato l'elezione di un nuovo leader tra i baccelli del nostro Kube-Scheduler nel caso in cui il vecchio leader non sia disponibile per qualche motivo.

Le applicazioni e i servizi regolari continuano a essere programmati tramite il Kube-Scheduler predefinito e tutte le attività Cron sono state completamente trasferite a quella nuova. Il carico creato dalle attività Cron è ora distribuito uniformemente su tutti i nodi. Considerando che la maggior parte delle attività CRON sono eseguite sugli stessi nodi delle principali applicazioni del progetto, ciò ha ridotto significativamente il rischio di spostare i baccelli a causa della mancanza di risorse. Dopo aver introdotto l'ulteriore Kube-Scheduler, i problemi con una pianificazione irregolare delle attività di Cron non sono più sorti.

Leggi anche altri articoli sul nostro blog:

Fonte: habr.com

Aggiungi un commento