Vytvoření dalšího plánovače kube s vlastní sadou pravidel plánování

Vytvoření dalšího plánovače kube s vlastní sadou pravidel plánování

Kube-scheduler je nedílnou součástí Kubernetes, která je zodpovědná za plánování podů napříč uzly v souladu se stanovenými zásadami. Během provozu clusteru Kubernetes často nemusíme přemýšlet o tom, které zásady se používají k plánování podů, protože sada zásad výchozího plánovače kube je vhodná pro většinu každodenních úkolů. Existují však situace, kdy je pro nás důležité doladit proces přidělování podů, a existují dva způsoby, jak tento úkol splnit:

  1. Vytvořte plánovač kube s vlastní sadou pravidel
  2. Napište si svůj vlastní plánovač a naučte ho pracovat s požadavky API serveru

V tomto článku popíšu implementaci prvního bodu k vyřešení problému nerovnoměrného rozvržení topenišť na jednom z našich projektů.

Krátký úvod k tomu, jak kube-scheduler funguje

Za zmínku stojí zejména skutečnost, že kube-scheduler není zodpovědný za přímé plánování podů - je zodpovědný pouze za určení uzlu, na který se pod umístí. Jinými slovy, výsledkem práce kube-scheduler je název uzlu, který vrací na API server pro žádost o plánování, a tam jeho práce končí.

Nejprve kube-scheduler sestaví seznam uzlů, na kterých lze naplánovat pod v souladu se zásadami predikátů. Dále každý uzel z tohoto seznamu obdrží určitý počet bodů v souladu se zásadami priorit. V důsledku toho je vybrán uzel s maximálním počtem bodů. Pokud existují uzly, které mají stejné maximální skóre, vybere se náhodně. Seznam a popis politik predikátů (filtrování) a priorit (bodování) naleznete v dokumentace.

Popis těla problému

Navzdory velkému množství různých clusterů Kubernetes spravovaných v Nixys jsme se poprvé setkali s problémem plánování podů teprve nedávno, když jeden z našich projektů potřeboval spouštět velké množství periodických úloh (~100 entit CronJob). Abychom popis problému co nejvíce zjednodušili, uvedeme si jako příklad jednu mikroslužbu, v rámci které se jednou za minutu spouští úloha cron, čímž dochází k určité zátěži CPU. Pro spuštění úlohy cron byly přiděleny tři uzly s naprosto identickými charakteristikami (24 vCPU na každém).

Zároveň nelze s přesností říci, jak dlouho bude CronJob trvat, než se vykoná, protože objem vstupních dat se neustále mění. V průměru během normálního provozu kube-scheduler každý uzel spouští 3-4 instance úloh, které vytvářejí ~20-30 % zátěže CPU každého uzlu:

Vytvoření dalšího plánovače kube s vlastní sadou pravidel plánování

Samotný problém je v tom, že někdy cron task pody přestaly být plánovány na jednom ze tří uzlů. To znamená, že v určitém okamžiku nebyl pro jeden z uzlů plánován ani jeden modul, zatímco na ostatních dvou uzlech běželo 6–8 kopií úlohy, což vytvářelo ~40–60 % zatížení CPU:

Vytvoření dalšího plánovače kube s vlastní sadou pravidel plánování

Problém se opakoval s naprosto náhodnou frekvencí a občas koreloval s okamžikem, kdy byla vydána nová verze kódu.

Zvýšením úrovně protokolování plánovače kube na úroveň 10 (-v=10) jsme začali zaznamenávat, kolik bodů získal každý uzel během procesu hodnocení. Během normálního plánování lze v protokolech vidět následující informace:

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

Tito. soudě podle informací získaných z protokolů získal každý z uzlů stejný počet konečných bodů a pro plánování byl vybrán jeden náhodný. V době problematického plánování vypadaly protokoly takto:

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

Z čehož je vidět, že jeden z uzlů získal méně konečných bodů než ostatní, a proto bylo plánování provedeno pouze pro dva uzly, které dosáhly maximálního skóre. Definitivně jsme se tedy přesvědčili, že problém spočívá právě v naplánování lusků.

Další algoritmus pro řešení problému byl pro nás zřejmý - analyzovat protokoly, pochopit, jakou prioritou uzel nezískal body, a v případě potřeby upravit zásady výchozího plánovače kube. Zde však čelíme dvěma závažným problémům:

  1. Při maximální úrovni protokolování (10) se odrážejí body získané pouze za některé priority. Ve výše uvedeném úryvku protokolů můžete vidět, že pro všechny priority reflektované v protokolech získávají uzly stejný počet bodů v normálním a problémovém plánování, ale konečný výsledek v případě plánování problémů je jiný. Můžeme tedy dojít k závěru, že u některých priorit se bodování vyskytuje „za scénou“ a my nemáme způsob, jak pochopit, za jakou prioritu uzel body nezískal. Tento problém jsme podrobně popsali v otázka Repozitář Kubernetes na Github. V době psaní tohoto článku byla od vývojářů obdržena odpověď, že podpora protokolování bude přidána v aktualizacích Kubernetes v1.15,1.16, 1.17 a XNUMX.
  2. Neexistuje snadný způsob, jak pochopit, se kterou konkrétní sadou zásad kube-scheduler aktuálně pracuje. Ano, v dokumentace tento seznam je uveden, ale neobsahuje informace o tom, jaké konkrétní váhy jsou přiřazeny každé z prioritních politik. Váhy nebo úpravy zásad výchozího plánovače kube můžete zobrazit pouze v zdrojové kódy.

Stojí za zmínku, že jakmile jsme byli schopni zaznamenat, že uzel nezískal body podle zásady ImageLocalityPriority, která přiděluje body uzlu, pokud již má obrázek nezbytný ke spuštění aplikace. To znamená, že v době, kdy byla spuštěna nová verze aplikace, se úloha cron podařilo spustit na dvou uzlech a stáhnout do nich nový obraz z registru dockerů, takže dva uzly získaly vyšší konečné skóre ve srovnání s třetím uzlem. .

Jak jsem psal výše, v protokolech nevidíme informace o vyhodnocení zásady ImageLocalityPriority, takže abychom ověřili náš předpoklad, vyhodili jsme obrázek s novou verzí aplikace na třetí uzel, po kterém plánování fungovalo správně . Právě kvůli politice ImageLocalityPriority byl problém s plánováním pozorován poměrně zřídka, častěji byl spojen s něčím jiným. Vzhledem k tomu, že jsme nemohli plně odladit každou ze zásad v seznamu priorit výchozího plánovače kube, potřebovali jsme flexibilní správu zásad plánování pod.

Formulace problému

Chtěli jsme, aby řešení problému bylo co nejkonkrétnější, to znamená, že hlavní entity Kubernetes (zde máme na mysli výchozí kube-scheduler) by měly zůstat nezměněny. Nechtěli jsme řešit problém na jednom místě a vytvářet ho na jiném. Tím jsme se dostali ke dvěma možnostem řešení problému, které byly avizovány v úvodu článku – vytvoření dalšího plánovače nebo napsání vlastního. Hlavním požadavkem pro plánování úloh cronu je rozložení zátěže rovnoměrně mezi tři uzly. Tento požadavek může být splněn stávajícími zásadami plánovače kube, takže pro vyřešení našeho problému nemá smysl psát svůj vlastní plánovač.

Pokyny pro vytvoření a nasazení dalšího plánovače kube jsou popsány v dokumentace. Zdálo se nám však, že entita Deployment nestačí zajistit odolnost proti chybám při provozu tak kritické služby, jako je kube-scheduler, a proto jsme se rozhodli nasadit nový kube-scheduler jako Static Pod, který by byl přímo monitorován od Kubeleta. Na nový plánovač kube tedy máme následující požadavky:

  1. Služba musí být nasazena jako statický modul na všech hlavních clusterech
  2. V případě, že aktivní modul s plánovačem kube není k dispozici, musí být poskytnuta tolerance chyb
  3. Hlavní prioritou při plánování by měl být počet dostupných zdrojů na uzlu (LeastRequestedPriority)

Implementace řešení

Okamžitě stojí za zmínku, že veškerou práci budeme provádět v Kubernetes v1.14.7, protože Toto je verze, která byla použita v projektu. Začněme tím, že napíšeme manifest pro náš nový plánovač kube. Vezměme výchozí manifest (/etc/kubernetes/manifests/kube-scheduler.yaml) jako základ a převedeme jej do následující podoby:

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

Stručně o hlavních změnách:

  1. Změněn název podu a kontejneru na kube-scheduler-cron
  2. Specifikováno použití portů 10151 a 10159, protože byla definována možnost hostNetwork: true a nemůžeme použít stejné porty jako výchozí plánovač kube (10251 a 10259)
  3. Pomocí parametru --config jsme specifikovali konfigurační soubor, se kterým má být služba spuštěna
  4. Konfigurované připojení konfiguračního souboru (scheduler-custom.conf) a souboru zásad plánování (scheduler-custom-policy-config.json) z hostitele

Nezapomeňte, že náš plánovač kube bude potřebovat práva podobná výchozímu. Upravit jeho roli clusteru:

kubectl edit clusterrole system:kube-scheduler

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

Nyní si promluvme o tom, co by mělo obsahovat konfigurační soubor a soubor zásad plánování:

  • Konfigurační soubor (scheduler-custom.conf)
    Chcete-li získat výchozí konfiguraci plánovače kube, musíte použít parametr --write-config-to z dokumentace. Výslednou konfiguraci umístíme do souboru /etc/kubernetes/scheduler-custom.conf a zmenšíme do následující podoby:

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"

Stručně o hlavních změnách:

  1. Nastavili jsme schedulerName na název naší služby kube-scheduler-cron.
  2. V parametru lockObjectName musíte také nastavit název naší služby a ujistit se, že parametr leaderElect nastavte na hodnotu true (pokud máte jeden hlavní uzel, můžete jej nastavit na hodnotu false).
  3. V parametru byla zadána cesta k souboru s popisem zásad plánování algorithmSource.

Stojí za to se blíže podívat na druhý bod, kde upravujeme parametry klíče leaderElection. Abychom zajistili odolnost proti chybám, povolili jsme (leaderElect) proces výběru vedoucího (hlavního) mezi pody našeho plánovače kube pomocí jediného koncového bodu (resourceLock) s názvem kube-scheduler-cron (lockObjectName) ve jmenném prostoru systému kube (lockObjectNamespace). Jak Kubernetes zajišťuje vysokou dostupnost hlavních komponent (včetně kube-scheduleru) najdete v článek.

  • Soubor zásad plánování (scheduler-custom-policy-config.json)
    Jak jsem psal dříve, můžeme zjistit, se kterými konkrétními politikami výchozí kube-scheduler pracuje, pouze analýzou jeho kódu. To znamená, že nemůžeme získat soubor se zásadami plánování pro výchozí plánovač kube stejným způsobem jako konfigurační soubor. Popišme zásady plánování, které nás zajímají, v souboru /etc/kubernetes/scheduler-custom-policy-config.json takto:

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

Proto kube-scheduler nejprve sestaví seznam uzlů, do kterých lze pod naplánovat podle zásady GeneralPredicates (která zahrnuje sadu zásad PodFitsResources, PodFitsHostPorts, HostName a MatchNodeSelector). A pak je každý uzel vyhodnocen v souladu se sadou zásad v poli priorit. Abychom splnili podmínky našeho úkolu, považovali jsme takový soubor politik za optimální řešení. Dovolte mi připomenout, že sada zásad s jejich podrobným popisem je k dispozici v dokumentace. Chcete-li svůj úkol splnit, můžete jednoduše změnit sadu použitých zásad a přiřadit jim odpovídající váhy.

Nazvěme manifest nového kube-scheduler, který jsme vytvořili na začátku kapitoly, kube-scheduler-custom.yaml a umístěte jej do následující cesty /etc/kubernetes/manifests na tři hlavní uzly. Pokud je vše provedeno správně, Kubelet spustí modul na každém uzlu a v protokolech našeho nového plánovače kube uvidíme informaci, že náš soubor zásad byl úspěšně aplikován:

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

Nyní zbývá pouze uvést ve specifikaci našeho CronJob, že všechny požadavky na plánování jeho modulů by měly být zpracovány naším novým plánovačem kube:

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

Závěr

Nakonec jsme získali další plánovač kube s unikátní sadou plánovacích politik, jejichž práci sleduje přímo kubelet. Kromě toho jsme nastavili volbu nového vůdce mezi moduly našeho kube-plánovače pro případ, že by starý vůdce z nějakého důvodu přestal být dostupný.

Běžné aplikace a služby jsou nadále plánovány prostřednictvím výchozího plánovače kube a všechny úlohy cron byly zcela převedeny do nového. Zátěž vytvořená úlohami cron je nyní rovnoměrně rozložena mezi všechny uzly. Vzhledem k tomu, že většina úloh cron se provádí na stejných uzlech jako hlavní aplikace projektu, výrazně se tím snížilo riziko přesunu modulů kvůli nedostatku zdrojů. Po zavedení dodatečného plánovače kube již nevznikaly problémy s nerovnoměrným plánováním úloh cron.

Přečtěte si také další články na našem blogu:

Zdroj: www.habr.com

Přidat komentář