Creando un kube-scheduler adicional cun conxunto personalizado de regras de programación

Creando un kube-scheduler adicional cun conxunto personalizado de regras de programación

Kube-scheduler é un compoñente integral de Kubernetes, que se encarga de programar pods en nós de acordo coas políticas especificadas. Moitas veces, durante o funcionamento dun clúster de Kubernetes, non temos que pensar en que políticas se usan para programar pods, xa que o conxunto de políticas do programador predeterminado de kube é axeitado para a maioría das tarefas cotiás. Non obstante, hai situacións nas que é importante para nós afinar o proceso de asignación de pods e hai dúas formas de realizar esta tarefa:

  1. Crea un Kube-scheduler cun conxunto de regras personalizados
  2. Escribe o teu propio programador e ensínalle a traballar coas solicitudes do servidor API

Neste artigo, describirei a implementación do primeiro punto para resolver o problema da programación desigual dos fogares nun dos nosos proxectos.

Unha breve introdución ao funcionamento do kube-scheduler

Paga a pena destacar especialmente o feito de que kube-scheduler non se encarga de programar directamente os pods; só é responsable de determinar o nodo no que colocar o pod. Noutras palabras, o resultado do traballo de kube-scheduler é o nome do nodo, que devolve ao servidor da API para unha solicitude de programación, e aí remata o seu traballo.

En primeiro lugar, kube-scheduler compila unha lista de nós nos que se pode programar o pod de acordo coas políticas de predicados. A continuación, cada nodo desta lista recibe un determinado número de puntos de acordo coas políticas de prioridades. Como resultado, selecciónase o nodo co número máximo de puntos. Se hai nodos que teñen a mesma puntuación máxima, selecciónase un aleatorio. Pódese atopar unha lista e unha descrición das políticas de predicados (filtrado) e prioridades (puntuación). documentación.

Descrición do corpo problemático

A pesar da gran cantidade de diferentes clústeres de Kubernetes que se manteñen en Nixys, atopámonos co problema de programar pods só recentemente, cando un dos nosos proxectos necesitaba executar un gran número de tarefas periódicas (~100 entidades CronJob). Para simplificar ao máximo a descrición do problema, tomaremos como exemplo un microservizo, dentro do cal se inicia unha tarefa cron unha vez por minuto, creando algo de carga na CPU. Para executar a tarefa cron, asignáronse tres nodos con características absolutamente idénticas (24 vCPU en cada un).

Ao mesmo tempo, é imposible dicir con precisión canto tempo tardará en executarse o CronJob, xa que o volume de datos de entrada cambia constantemente. De media, durante o funcionamento normal de kube-scheduler, cada nodo executa 3-4 instancias de traballo, que crean ~20-30% da carga na CPU de cada nodo:

Creando un kube-scheduler adicional cun conxunto personalizado de regras de programación

O problema en si é que ás veces os pods de tarefas cron deixaron de programarse nun dos tres nodos. É dicir, nalgún momento, non se planificou nin un só pod para un dos nodos, mentres que nos outros dous nodos estaban executando 6-8 copias da tarefa, creando ~40-60% da carga da CPU:

Creando un kube-scheduler adicional cun conxunto personalizado de regras de programación

O problema volveu repetirse cunha frecuencia absolutamente aleatoria e ocasionalmente correlacionouse co momento en que se lanzou unha nova versión do código.

Ao aumentar o nivel de rexistro de kube-scheduler ata o nivel 10 (-v=10), comezamos a rexistrar cantos puntos gañou cada nodo durante o proceso de avaliación. Durante a operación de planificación normal, a seguinte información podería verse nos rexistros:

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

Eses. a xulgar pola información obtida dos rexistros, cada un dos nodos obtivo o mesmo número de puntos finais e seleccionouse un aleatorio para a planificación. No momento da planificación problemática, os rexistros tiñan o seguinte aspecto:

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

Polo que se desprende que un dos nodos obtivo menos puntos finais que os outros, polo que a planificación realizouse só para os dous nodos que obtiveron a máxima puntuación. Así, estabamos definitivamente convencidos de que o problema reside precisamente na programación das vainas.

O algoritmo adicional para resolver o problema era obvio para nós: analizar os rexistros, comprender con que prioridade o nodo non obtivo puntos e, se é necesario, axustar as políticas do programador de kube predeterminado. Non obstante, aquí estamos ante dúas dificultades importantes:

  1. No nivel máximo de rexistro (10), reflíctense os puntos gañados só para algunhas prioridades. No fragmento de rexistros anterior, podes ver que para todas as prioridades reflectidas nos rexistros, os nodos obteñen o mesmo número de puntos na programación normal e de problemas, pero o resultado final no caso da planificación de problemas é diferente. Así, podemos concluír que para algunhas prioridades, a puntuación ocorre "detrás de escena", e non temos forma de entender para que prioridade o nodo non obtivo puntos. Describimos este problema en detalle en cuestión Repositorio de Kubernetes en Github. No momento de escribir este artigo, recibiuse unha resposta dos desenvolvedores de que o soporte de rexistro engadirase nas actualizacións de Kubernetes v1.15,1.16, 1.17 e XNUMX.
  2. Non hai un xeito sinxelo de entender con que conxunto específico de políticas está a traballar actualmente kube-scheduler. Si, en documentación esta lista está listada, pero non contén información sobre que pesos específicos se asignan a cada unha das políticas de prioridades. Podes ver os pesos ou editar as políticas do kube-scheduler predeterminado só en códigos fonte.

Cabe destacar que unha vez puidemos rexistrar que un nodo non recibiu puntos segundo a política ImageLocalityPriority, que outorga puntos a un nodo se xa ten a imaxe necesaria para executar a aplicación. É dicir, no momento en que se lanzou unha nova versión da aplicación, a tarefa cron logrou executarse en dous nodos, descargandolles unha nova imaxe do rexistro docker e, polo tanto, dous nodos recibiron unha puntuación final máis alta en relación ao terceiro. .

Como escribín anteriormente, nos rexistros non vemos información sobre a avaliación da política ImageLocalityPriority, polo que, para comprobar a nosa suposición, botamos a imaxe coa nova versión da aplicación no terceiro nodo, despois de que a programación funcionou correctamente. . Precisamente debido á política ImageLocalityPriority, o problema de programación se observou moi poucas veces; máis a miúdo estivo asociado con outra cousa. Debido ao feito de que non puidemos depurar completamente cada unha das políticas da lista de prioridades do programador de kube predeterminado, necesitabamos unha xestión flexible das políticas de programación de pods.

Declaración de problemas

Queriamos que a solución ao problema fose o máis específica posible, é dicir, que as entidades principais de Kubernetes (aquí queremos dicir o programador de kube predeterminado) permanecesen sen cambios. Non queriamos resolver un problema nun lugar e crealo noutro. Así, chegamos a dúas opcións para resolver o problema, que se anunciaron na introdución do artigo: crear un programador adicional ou escribir o seu propio. O principal requisito para programar tarefas cron é distribuír a carga uniformemente en tres nodos. Este requisito pódese cumprir coas políticas existentes de kube-scheduler, polo que para resolver o noso problema non ten sentido escribir o teu propio planificador.

As instrucións para crear e implementar un programador de kube adicional descríbense en documentación. Non obstante, pareceunos que a entidade de Implementación non era suficiente para garantir a tolerancia a fallos no funcionamento dun servizo tan crítico como o kube-scheduler, polo que decidimos implantar un novo kube-scheduler como un Pod estático, que sería supervisado directamente. por Kubelet. Así, temos os seguintes requisitos para o novo kube-scheduler:

  1. O servizo debe implementarse como un Pod estático en todos os mestres do clúster
  2. Debe proporcionarse tolerancia a fallos no caso de que o pod activo con kube-scheduler non estea dispoñible
  3. A principal prioridade á hora de planificar debe ser o número de recursos dispoñibles no nodo (LeastRequestedPriority)

Solucións de implantación

Paga a pena sinalar de inmediato que realizaremos todo o traballo en Kubernetes v1.14.7, porque Esta é a versión que se utilizou no proxecto. Comecemos escribindo un manifesto para o noso novo programador de kube. Tomemos o manifesto predeterminado (/etc/kubernetes/manifests/kube-scheduler.yaml) como base e traémolo ao seguinte formulario:

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 sobre os principais cambios:

  1. Cambiouse o nome do pod e do contenedor a kube-scheduler-cron
  2. Especificou o uso dos portos 10151 e 10159 como se definiu a opción hostNetwork: true e non podemos usar os mesmos portos que o kube-scheduler predeterminado (10251 e 10259)
  3. Usando o parámetro --config, especificamos o ficheiro de configuración co que se debería iniciar o servizo
  4. Montaxe configurada do ficheiro de configuración (scheduler-custom.conf) e do ficheiro de política de programación (scheduler-custom-policy-config.json) desde o host

Non esquezas que o noso kube-scheduler necesitará dereitos similares aos predeterminados. Edita o seu rol de clúster:

kubectl edit clusterrole system:kube-scheduler

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

Agora imos falar do que debería conter o ficheiro de configuración e o ficheiro de política de programación:

  • Ficheiro de configuración (scheduler-custom.conf)
    Para obter a configuración predeterminada do kube-scheduler, debes usar o parámetro --write-config-to de documentación. Colocaremos a configuración resultante no ficheiro /etc/kubernetes/scheduler-custom.conf e reducirémola á seguinte forma:

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 sobre os principais cambios:

  1. Establecemos schedulerName co nome do noso servizo kube-scheduler-cron.
  2. En parámetro lockObjectName tamén cómpre definir o nome do noso servizo e asegurarse de que o parámetro leaderElect definido como verdadeiro (se tes un nodo mestre, podes configuralo como falso).
  3. Especificou o camiño ao ficheiro cunha descrición das políticas de programación no parámetro algorithmSource.

Paga a pena botar unha ollada máis atenta ao segundo punto, onde editamos os parámetros da clave leaderElection. Para garantir a tolerancia a fallos, activamos (leaderElect) o proceso de selección dun líder (mestre) entre os pods do noso programador de kube usando un único punto final para eles (resourceLock) chamado kube-scheduler-cron (lockObjectName) no espazo de nomes do sistema kube (lockObjectNamespace). Pódese atopar como Kubernetes garante a alta dispoñibilidade dos compoñentes principais (incluído o kube-scheduler). Artigo.

  • Ficheiro de políticas de programación (scheduler-custom-policy-config.json)
    Como escribín anteriormente, podemos descubrir con que políticas específicas funciona o programador de kube predeterminado só analizando o seu código. É dicir, non podemos obter un ficheiro con políticas de programación para o kube-scheduler predeterminado do mesmo xeito que un ficheiro de configuración. Imos describir as políticas de programación que nos interesan no ficheiro /etc/kubernetes/scheduler-custom-policy-config.json do seguinte xeito:

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

Así, kube-scheduler compila primeiro unha lista de nós nos que se pode programar un pod segundo a política GeneralPredicates (que inclúe un conxunto de políticas PodFitsResources, PodFitsHostPorts, HostName e MatchNodeSelector). E despois avalíase cada nodo de acordo co conxunto de políticas da matriz de prioridades. Para cumprir as condicións da nosa tarefa, consideramos que tal conxunto de políticas sería a solución óptima. Permíteme lembrarche que está dispoñible un conxunto de políticas coas súas descricións detalladas documentación. Para realizar a súa tarefa, simplemente pode cambiar o conxunto de políticas utilizadas e asignarlles ponderacións adecuadas.

Chamemos ao manifesto do novo kube-scheduler, que creamos ao comezo do capítulo, kube-scheduler-custom.yaml e colócao no seguinte camiño /etc/kubernetes/manifests en tres nodos mestres. Se todo está feito correctamente, Kubelet lanzará un pod en cada nodo e nos rexistros do noso novo programador de kube veremos información de que o noso ficheiro de políticas se aplicou correctamente:

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

Agora só queda indicar na especificación do noso CronJob que todas as solicitudes para programar os seus pods deben ser procesadas polo noso novo programador de kube:

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

Conclusión

En definitiva, obtivemos un programador de kube adicional cun conxunto único de políticas de programación, cuxo traballo é supervisado directamente polo kubelet. Ademais, configuramos a elección dun novo líder entre as vainas do noso programador de kube no caso de que o antigo líder non estea dispoñible por algún motivo.

As aplicacións e servizos habituais seguen a ser programados a través do programador predeterminado de kube e todas as tarefas cron foron completamente transferidas ao novo. A carga creada polas tarefas cron agora distribúese uniformemente en todos os nodos. Tendo en conta que a maioría das tarefas cron execútanse nos mesmos nodos que as principais aplicacións do proxecto, isto reduciu significativamente o risco de mover pods por falta de recursos. Despois de introducir o kube-scheduler adicional, xa non xurdiron problemas coa programación desigual das tarefas cron.

Lea tamén outros artigos no noso blog:

Fonte: www.habr.com

Engadir un comentario