Risolvere i problemi relativi allo scheduler Kubernetes

Questa pagina mostra come risolvere i problemi relativi allo scheduler Kubernetes (kube-scheduler) per Google Distributed Cloud.

Kubernetes pianifica sempre i pod nello stesso insieme di nodi

Questo errore può essere osservato in diversi modi:

  • Utilizzo del cluster non bilanciato. Puoi esaminare l'utilizzo del cluster per ogni nodo con il comando kubectl top nodes. L'output di esempio esagerato mostra un utilizzo pronunciato su determinati nodi:

    NAME                   CPU(cores)   CPU%      MEMORY(bytes)   MEMORY%
    XXX.gke.internal       222m         101%       3237Mi          61%
    YYY.gke.internal       91m          0%         2217Mi          0%
    ZZZ.gke.internal       512m         0%         8214Mi          0%
    
  • Troppe richieste. Se pianifichi molti pod contemporaneamente sullo stesso nodo e questi pod effettuano richieste HTTP, è possibile che il nodo venga limitato dalla frequenza. L'errore comune restituito dal server in questo scenario è 429 Too Many Requests.

  • Servizio non disponibile. Un web server, ad esempio, ospitato su un nodo con carico elevato potrebbe rispondere a tutte le richieste con errori 503 Service Unavailable finché il carico non diminuisce.

Per verificare se hai pod sempre pianificati sugli stessi nodi, segui questi passaggi:

  1. Esegui questo comando kubectl per visualizzare lo stato dei pod:

    kubectl get pods -o wide -n default
    

    Per visualizzare la distribuzione dei pod nei nodi, controlla la colonna NODE nell'output. Nell'output di esempio seguente, tutti i pod sono pianificati sullo stesso nodo:

    NAME                               READY  STATUS   RESTARTS  AGE  IP             NODE
    nginx-deployment-84c6674589-cxp55  1/1    Running  0         55s  10.20.152.138  10.128.224.44
    nginx-deployment-84c6674589-hzmnn  1/1    Running  0         55s  10.20.155.70   10.128.226.44
    nginx-deployment-84c6674589-vq4l2  1/1    Running  0         55s  10.20.225.7    10.128.226.44
    

I pod hanno una serie di funzionalità che ti consentono di perfezionare il loro comportamento di pianificazione. Queste funzionalità includono vincoli di distribuzione della topologia e regole di anti-affinità. Puoi utilizzare una o una combinazione di queste funzionalità. I requisiti che definisci sono uniti da AND tramite kube-scheduler.

I log dello scheduler non vengono acquisiti al livello di verbosità di logging predefinito. Se hai bisogno dei log dello scheduler per la risoluzione dei problemi, segui questi passaggi per acquisirli:

  1. Aumenta il livello di dettaglio dei log:

    1. Modifica il deployment kube-scheduler:

      kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \
        -n USER_CLUSTER_NAMESPACE
      
    2. Aggiungi il flag --v=5 nella sezione spec.containers.command:

      containers:
      - command:
      - kube-scheduler
      - --profiling=false
      - --kubeconfig=/etc/kubernetes/scheduler.conf
      - --leader-elect=true
      - --v=5
      
  2. Una volta terminata la risoluzione dei problemi, reimposta il livello di verbosità sul livello predefinito:

    1. Modifica il deployment kube-scheduler:

      kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \
        -n USER_CLUSTER_NAMESPACE
      
    2. Imposta di nuovo il livello di verbosità sul valore predefinito:

      containers:
      - command:
      - kube-scheduler
      - --profiling=false
      - --kubeconfig=/etc/kubernetes/scheduler.conf
      - --leader-elect=true
      

Vincoli di distribuzione della topologia

I vincoli di distribuzione della topologia possono essere utilizzati per distribuire uniformemente i pod tra i nodi in base a zones, regions, node o ad altre topologie definite personalizzate.

Il seguente manifest di esempio mostra un deployment che distribuisce le repliche in modo uniforme tra tutti i nodi pianificabili utilizzando i vincoli di distribuzione della topologia:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: topology-spread-deployment
  labels:
    app: myapp
spec:
  replicas: 30
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      topologySpreadConstraints:
      - maxSkew: 1 # Default. Spreads evenly. Maximum difference in scheduled Pods per Node.
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule # Default. Alternatively can be ScheduleAnyway
        labelSelector:
          matchLabels:
            app: myapp
        matchLabelKeys: # beta in 1.27
        - pod-template-hash
      containers:
      # pause is a lightweight container that simply sleeps
      - name: pause
        image: registry.k8s.io/pause:3.2

Quando utilizzi i vincoli di distribuzione della topologia, tieni presenti le seguenti considerazioni:

  • Il labels.app: myapp di un pod corrisponde al labelSelector del vincolo.
  • topologyKey specifica kubernetes.io/hostname. Questa etichetta viene allegata automaticamente a tutti i nodi e viene compilata con il nome host del nodo.
  • matchLabelKeys impedisce alle implementazioni di nuovi deployment di prendere in considerazione i pod delle revisioni precedenti quando calcolano dove pianificare un pod. L'etichetta pod-template-hash viene compilata automaticamente da un deployment.

Anti-affinità dei pod

L'anti-affinità dei pod consente di definire vincoli per i pod che possono essere collocati insieme sullo stesso nodo.

Il seguente manifest di esempio mostra un deployment che utilizza l'anti-affinità per limitare le repliche a un pod per nodo:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-affinity-deployment
  labels:
    app: myapp
spec:
  replicas: 30
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: with-pod-affinity
      labels:
        app: myapp
    spec:
      affinity:
        podAntiAffinity:
          # requiredDuringSchedulingIgnoredDuringExecution
          # prevents Pod from being scheduled on a Node if it
          # does not meet criteria.
          # Alternatively can use 'preferred' with a weight
          # rather than 'required'.
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - myapp
            # Your nodes might be configured with other keys
            # to use as `topologyKey`. `kubernetes.io/region`
            # and `kubernetes.io/zone` are common.
            topologyKey: kubernetes.io/hostname
      containers:
      # pause is a lightweight container that simply sleeps
      - name: pause
        image: registry.k8s.io/pause:3.2

Questo deployment di esempio specifica 30 repliche, ma si espande solo al numero di nodi disponibili nel cluster.

Quando utilizzi l'anti-affinità dei pod, tieni presente le seguenti considerazioni:

  • Il labels.app: myapp di un pod corrisponde al labelSelector del vincolo.
  • topologyKey specifica kubernetes.io/hostname. Questa etichetta viene allegata automaticamente a tutti i nodi e viene compilata con il nome host del nodo. Puoi scegliere di utilizzare altre etichette se il tuo cluster le supporta, ad esempio region o zone.

Eseguire il pull delle immagini container

In assenza di altri vincoli, per impostazione predefinita kube-scheduler preferisce pianificare i pod sui nodi su cui è già stata scaricata l'immagine container. Questo comportamento potrebbe essere interessante nei cluster più piccoli senza altre configurazioni di pianificazione in cui sarebbe possibile scaricare le immagini su ogni nodo. Tuttavia, fare affidamento su questo concetto dovrebbe essere considerato l'ultima risorsa. Una soluzione migliore è utilizzare nodeSelector, i vincoli di distribuzione della topologia o l'affinità / anti-affinità. Per ulteriori informazioni, consulta la sezione Assegnazione di pod ai nodi.

Se vuoi assicurarti che le immagini dei container vengano precaricate su tutti i nodi, puoi utilizzare un DaemonSet come nel seguente esempio:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: prepulled-images
spec:
  selector:
    matchLabels:
      name: prepulled-images
  template:
    metadata:
      labels:
        name: prepulled-images
    spec:
      initContainers:
        - name: prepulled-image
          image: IMAGE
          # Use a command the terminates immediately
          command: ["sh", "-c", "'true'"]
      containers:
      # pause is a lightweight container that simply sleeps
      - name: pause
        image: registry.k8s.io/pause:3.2

Dopo che il pod è Running su tutti i nodi, esegui di nuovo il deployment dei pod per verificare se i container sono ora distribuiti in modo uniforme tra i nodi.

Passaggi successivi

Se hai bisogno di ulteriore assistenza, contatta l'assistenza clienti Google Cloud. Puoi anche consultare la sezione Richiedere assistenza per ulteriori informazioni sulle risorse di assistenza, tra cui:

  • Requisiti per l'apertura di una richiesta di assistenza.
  • Strumenti per aiutarti a risolvere i problemi, ad esempio la configurazione dell'ambiente, i log e le metriche.
  • Componenti supportati.