Crearea unui kube-scheduler suplimentar cu un set personalizat de reguli de programare

Crearea unui kube-scheduler suplimentar cu un set personalizat de reguli de programare

Kube-scheduler este o componentă integrală a Kubernetes, care este responsabilă pentru programarea podurilor între noduri în conformitate cu politicile specificate. Adesea, în timpul funcționării unui cluster Kubernetes, nu trebuie să ne gândim la ce politici sunt utilizate pentru a programa pod-urile, deoarece setul de politici al programului kube-scheduler implicit este potrivit pentru majoritatea sarcinilor de zi cu zi. Cu toate acestea, există situații în care este important pentru noi să perfecționăm procesul de alocare a podurilor și există două moduri de a îndeplini această sarcină:

  1. Creați un kube-scheduler cu un set personalizat de reguli
  2. Scrieți-vă propriul planificator și învățați-l să funcționeze cu solicitările de server API

În acest articol, voi descrie implementarea primului punct pentru a rezolva problema programării inegale a vetrelor pe unul dintre proiectele noastre.

O scurtă introducere a modului în care funcționează kube-scheduler

Este de remarcat în special faptul că kube-scheduler nu este responsabil pentru programarea directă a podurilor - este responsabil doar de determinarea nodului pe care să plaseze podul. Cu alte cuvinte, rezultatul muncii lui kube-scheduler este numele nodului, pe care îl returnează serverului API pentru o solicitare de programare și acolo se termină munca sa.

În primul rând, kube-scheduler compilează o listă de noduri pe care podul poate fi programat în conformitate cu politicile de predicate. În continuare, fiecare nod din această listă primește un anumit număr de puncte în conformitate cu politicile de priorități. Ca rezultat, este selectat nodul cu numărul maxim de puncte. Dacă există noduri care au același scor maxim, se selectează unul aleatoriu. O listă și o descriere a politicilor de predicate (filtrare) și priorități (punctajare) pot fi găsite în documentație.

Descrierea corpului cu probleme

În ciuda numărului mare de clustere Kubernetes diferite menținute la Nixys, am întâlnit pentru prima dată problema programării podurilor abia recent, când unul dintre proiectele noastre trebuia să ruleze un număr mare de sarcini periodice (~100 de entități CronJob). Pentru a simplifica cât mai mult descrierea problemei, vom lua ca exemplu un microserviciu, în cadrul căruia se lansează o sarcină cron o dată pe minut, creând o oarecare încărcare pe CPU. Pentru a rula sarcina cron, au fost alocate trei noduri cu caracteristici absolut identice (24 vCPU-uri pe fiecare).

În același timp, este imposibil să spunem cu exactitate cât timp va dura CronJob pentru a se executa, deoarece volumul datelor de intrare se schimbă constant. În medie, în timpul funcționării normale a kube-scheduler, fiecare nod rulează 3-4 instanțe de job, care creează ~20-30% din sarcina CPU-ului fiecărui nod:

Crearea unui kube-scheduler suplimentar cu un set personalizat de reguli de programare

Problema în sine este că, uneori, podurile de activități cron nu mai sunt programate pe unul dintre cele trei noduri. Adică, la un moment dat, nu a fost planificat un singur pod pentru unul dintre noduri, în timp ce pe celelalte două noduri rulau 6-8 copii ale sarcinii, creând ~40-60% din încărcarea procesorului:

Crearea unui kube-scheduler suplimentar cu un set personalizat de reguli de programare

Problema s-a repetat cu o frecvență absolut aleatorie și s-a corelat ocazional cu momentul în care a fost lansată o nouă versiune a codului.

Prin creșterea nivelului de înregistrare kube-scheduler la nivelul 10 (-v=10), am început să înregistrăm câte puncte a câștigat fiecare nod în timpul procesului de evaluare. În timpul operațiunii normale de planificare, următoarele informații pot fi văzute în jurnale:

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

Acestea. judecând după informațiile obținute din jurnalele, fiecare dintre noduri a obținut un număr egal de puncte finale și a fost selectat unul aleatoriu pentru planificare. La momentul planificării problematice, jurnalele arătau astfel:

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

Din care se poate observa că unul dintre noduri a obținut mai puține puncte finale decât celelalte și, prin urmare, planificarea s-a realizat doar pentru cele două noduri care au obținut punctajul maxim. Astfel, am fost cu siguranță convinși că problema constă tocmai în programarea păstăilor.

Algoritmul suplimentar pentru rezolvarea problemei ne-a fost evident - analizați jurnalele, înțelegeți cu ce prioritate nodul nu a obținut puncte și, dacă este necesar, ajustați politicile programului kube-scheduler implicit. Cu toate acestea, aici ne confruntăm cu două dificultăți semnificative:

  1. La nivelul maxim de înregistrare (10), sunt reflectate punctele câștigate doar pentru unele priorități. În fragmentul de mai sus al jurnalelor, puteți vedea că pentru toate prioritățile reflectate în jurnale, nodurile obțin același număr de puncte în programarea normală și a problemelor, dar rezultatul final în cazul planificării problemelor este diferit. Astfel, putem concluziona că pentru unele priorități, scorul are loc „în culise”, și nu avem cum să înțelegem pentru ce prioritate nodul nu a obținut puncte. Am descris această problemă în detaliu în problema Depozitul Kubernetes pe Github. La momentul redactării acestui articol, a fost primit un răspuns de la dezvoltatori că suportul pentru înregistrare va fi adăugat în actualizările Kubernetes v1.15,1.16, 1.17 și XNUMX.
  2. Nu există o modalitate ușoară de a înțelege cu ce set specific de politici lucrează în prezent kube-scheduler. Da, în documentație această listă este listată, dar nu conține informații despre ce ponderi specifice sunt atribuite fiecărei politici de priorități. Puteți vedea ponderile sau edita politicile kube-scheduler-ului implicit numai în codurile sursă.

Este de remarcat faptul că, odată ce am reușit să înregistrăm că un nod nu a primit puncte conform politicii ImageLocalityPriority, care acordă puncte unui nod dacă are deja imaginea necesară rulării aplicației. Adică, în momentul în care a fost lansată o nouă versiune a aplicației, sarcina cron a reușit să ruleze pe două noduri, descarcându-le o nouă imagine din registrul docker și, astfel, două noduri au primit un scor final mai mare față de cel de-al treilea. .

După cum am scris mai sus, în jurnale nu vedem informații despre evaluarea politicii ImageLocalityPriority, așa că pentru a verifica presupunerea noastră, am aruncat imaginea cu noua versiune a aplicației pe al treilea nod, după care programarea a funcționat corect . Tocmai din cauza politicii ImageLocalityPriority problema de programare a fost observată destul de rar; mai des a fost asociată cu altceva. Datorită faptului că nu am putut depana complet fiecare dintre politicile din lista de priorități a programului kube-scheduler implicit, am avut nevoie de un management flexibil al politicilor de programare a podului.

Declarație de problemă

Ne-am dorit ca soluția problemei să fie cât mai precisă, adică principalele entități ale Kubernetes (aici ne referim la kube-scheduler implicit) să rămână neschimbate. Nu am vrut să rezolvăm o problemă într-un loc și să o creăm în altul. Astfel, am ajuns la două opțiuni pentru rezolvarea problemei, care au fost anunțate în introducerea articolului - crearea unui planificator suplimentar sau scrierea propriei dvs. Principala cerință pentru programarea sarcinilor cron este distribuirea uniformă a încărcăturii pe trei noduri. Această cerință poate fi satisfăcută de politicile kube-scheduler existente, așa că pentru a ne rezolva problema nu are rost să scrieți propriul dvs. planificator.

Instrucțiunile pentru crearea și implementarea unui kube-scheduler suplimentar sunt descrise în documentație. Cu toate acestea, ni s-a părut că entitatea de implementare nu era suficientă pentru a asigura toleranța la erori în funcționarea unui serviciu atât de critic precum kube-scheduler, așa că am decis să implementăm un nou kube-scheduler ca un pod static, care să fie monitorizat direct. de Kubelet. Astfel, avem următoarele cerințe pentru noul kube-scheduler:

  1. Serviciul trebuie să fie implementat ca un pod static pe toate clusterele master
  2. Trebuie furnizată toleranță la erori în cazul în care podul activ cu programul kube nu este disponibil
  3. Prioritatea principală la planificare ar trebui să fie numărul de resurse disponibile pe nod (LeastRequestedPriority)

Implementarea soluției

Merită remarcat imediat că vom efectua toate lucrările în Kubernetes v1.14.7, deoarece Aceasta este versiunea care a fost folosită în proiect. Să începem prin a scrie un manifest pentru noul nostru kube-scheduler. Să luăm manifestul implicit (/etc/kubernetes/manifests/kube-scheduler.yaml) ca bază și să îl aducem în următoarea formă:

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

Pe scurt despre principalele modificări:

  1. S-a schimbat numele podului și al containerului în kube-scheduler-cron
  2. A specificat utilizarea porturilor 10151 și 10159, deoarece opțiunea a fost definită hostNetwork: true și nu putem folosi aceleași porturi ca și programatorul kube implicit (10251 și 10259)
  3. Folosind parametrul --config, am specificat fișierul de configurare cu care trebuie pornit serviciul
  4. Montarea configurată a fișierului de configurare (scheduler-custom.conf) și a fișierului de politică de programare (scheduler-custom-policy-config.json) de la gazdă

Nu uitați că kube-scheduler-ul nostru va avea nevoie de drepturi similare cu cea implicită. Editați rolul său de cluster:

kubectl edit clusterrole system:kube-scheduler

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

Acum să vorbim despre ce ar trebui să fie conținut în fișierul de configurare și fișierul de politică de programare:

  • Fișier de configurare (scheduler-custom.conf)
    Pentru a obține configurația implicită kube-scheduler, trebuie să utilizați parametrul --write-config-to de documentație. Vom plasa configurația rezultată în fișierul /etc/kubernetes/scheduler-custom.conf și o vom reduce la următoarea formă:

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"

Pe scurt despre principalele modificări:

  1. Setăm schedulerName la numele serviciului nostru kube-scheduler-cron.
  2. În parametru lockObjectName de asemenea, trebuie să setați numele serviciului nostru și să vă asigurați că parametrul leaderElect setat la adevărat (dacă aveți un nod master, îl puteți seta la fals).
  3. Specificați calea către fișier cu o descriere a politicilor de programare în parametru algorithmSource.

Merită să aruncăm o privire mai atentă la al doilea punct, unde edităm parametrii pentru cheie leaderElection. Pentru a asigura toleranța la erori, am activat (leaderElect) procesul de selectare a unui lider (master) între podurile kube-scheduler-ului nostru folosind un singur punct final pentru ele (resourceLock) numit kube-scheduler-cron (lockObjectName) în spațiul de nume kube-system (lockObjectNamespace). Modul în care Kubernetes asigură disponibilitatea ridicată a componentelor principale (inclusiv kube-scheduler) poate fi găsit în articol.

  • Fișierul politicii de programare (scheduler-custom-policy-config.json)
    După cum am scris mai devreme, putem afla cu ce politici specifice funcționează programul kube-scheduler doar analizând codul său. Adică, nu putem obține un fișier cu politici de programare pentru kube-scheduler implicit în același mod ca un fișier de configurare. Să descriem politicile de programare care ne interesează în fișierul /etc/kubernetes/scheduler-custom-policy-config.json după cum urmează:

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

Astfel, kube-scheduler compilează mai întâi o listă de noduri la care un pod poate fi programat conform politicii GeneralPredicates (care include un set de politici PodFitsResources, PodFitsHostPorts, HostName și MatchNodeSelector). Și apoi fiecare nod este evaluat în conformitate cu setul de politici din matricea priorități. Pentru a îndeplini condițiile sarcinii noastre, am considerat că un astfel de set de politici ar fi soluția optimă. Permiteți-mi să vă reamintesc că un set de politici cu descrierile lor detaliate este disponibil în documentație. Pentru a vă îndeplini sarcina, puteți pur și simplu să schimbați setul de politici utilizate și să le atribuiți ponderi adecvate.

Să numim manifestul noului kube-scheduler, pe care l-am creat la începutul capitolului, kube-scheduler-custom.yaml și să-l plasăm în următoarea cale /etc/kubernetes/manifests pe trei noduri master. Dacă totul este făcut corect, Kubelet va lansa un pod pe fiecare nod, iar în jurnalele noului nostru kube-scheduler vom vedea informații că fișierul nostru de politici a fost aplicat cu succes:

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

Acum, tot ce rămâne este să indicăm în specificațiile CronJob-ului nostru că toate cererile de programare a podurilor sale ar trebui să fie procesate de noul nostru kube-scheduler:

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

Concluzie

În cele din urmă, am primit un kube-scheduler suplimentar cu un set unic de politici de programare, a cărui activitate este monitorizată direct de kubelet. În plus, am stabilit alegerea unui nou lider între podurile kube-scheduler-ului nostru în cazul în care vechiul lider devine indisponibil dintr-un motiv oarecare.

Aplicațiile și serviciile obișnuite continuă să fie programate prin programul kube-scheduler implicit, iar toate sarcinile cron au fost complet transferate la cel nou. Sarcina creată de sarcinile cron este acum distribuită uniform pe toate nodurile. Având în vedere că majoritatea sarcinilor cron sunt executate pe aceleași noduri ca și principalele aplicații ale proiectului, acest lucru a redus semnificativ riscul de a muta pod-urile din cauza lipsei de resurse. După introducerea kube-scheduler-ului suplimentar, problemele cu programarea neuniformă a sarcinilor cron nu au mai apărut.

Citiți și alte articole de pe blogul nostru:

Sursa: www.habr.com

Adauga un comentariu