Best Practices für erweiterte Schedulerfunktionen in Azure Kubernetes Service (AKS)

Beim Verwalten von Clustern in Azure Kubernetes Service (AKS) müssen Sie oft Teams oder Workloads isolieren. Mit erweiterten Funktionen, die vom Kubernetes-Scheduler bereitgestellt werden, können Sie Folgendes steuern:

  • Welche Pods auf bestimmten Knoten geplant werden können.
  • Wie Anwendungen mit mehreren Pods angemessen über den Cluster verteilt werden können.

Dieser Artikel zu Best Practices konzentriert sich auf erweiterten Kubernetes-Planungsfunktionen für Clusteroperatoren. In diesem Artikel werden folgende Vorgehensweisen behandelt:

  • Verwenden von Taints und Toleranzen, um einzuschränken welche Pods auf Knoten geplant werden können
  • Festlegen, dass Pods auf bestimmten Knoten ausgeführt werden, mit Knotenselektoren oder Knotenaffinität
  • Trennen oder Gruppieren von Pods mit Pod-interner Affinität oder Antiaffinität
  • Beschränken Sie die Planung von Workloads, die GPUs erfordern, nur auf Knoten mit planbaren GPUs.

Bereitstellen dedizierter Knoten mit Taints und Toleranzen

Best Practices-Leitfaden:

Beschränken Sie den Zugriff für ressourcenintensive Anwendungen, z. B. Eingangscontroller, auf bestimmte Knoten. Halten Sie Knotenressourcen für Workloads verfügbar, die sie benötigen, und erlauben Sie keine Planung anderer Workloads auf den Knoten.

Wenn Sie Ihren AKS-Cluster erstellen, können Sie Knoten mit GPU-Unterstützung oder einer großen Anzahl leistungsstarker CPUs bereitstellen. Weitere Informationen finden Sie unter Verwenden von GPUs in AKS. Sie können diese Knoten für große Datenverarbeitungsworkloads wie Machine Learning (ML) oder Künstliche Intelligenz (KI) verwenden.

Da diese Knotenressourcen-Hardware in der Regel teuer in der Bereitstellung ist, begrenzen Sie die Workloads, die auf diesen Knoten geplant werden können. Stattdessen widmen Sie einige Knoten im Cluster der Ausführung von Eingangsdiensten und dem Verhindern anderer Workloads.

Diese Unterstützung für verschiedene Knoten erhalten Sie durch die Verwendung von mehrerer Knotenpools. Ein AKS-Cluster bietet einen oder mehrere Knotenpools.

Der Kubernetes-Scheduler verwendet Taints und Toleranzen, um einzuschränken, welche Workloads auf Knoten ausgeführt werden können.

  • Wenden Sie ein Taint auf einen Knoten an, um anzugeben, dass nur bestimmte Pods auf ihm geplant werden können.
  • Dann wenden Sie eine Toleranz auf einen Pod an, sodass dieser den Taint des Knotens tolerieren kann.

Wenn Sie einen Pod in einem AKS-Cluster bereitstellen, plant Kubernetes nur Pods auf Knoten, deren Taint der Toleranz entspricht. Taints und Toleranzen arbeiten zusammen, um sicherzustellen, dass Pods nicht auf ungeeigneten Knoten geplant werden. Ein oder mehrere Taints werden auf einen Knoten angewendet und markieren den Knoten so, dass er keine Pods akzeptiert, die die Taints nicht tolerieren.

Angenommen, Sie haben Ihrem AKS-Cluster einen Knotenpool für Knoten mit GPU-Unterstützung hinzugefügt. Sie definieren einen Namen, z.B. gpu und dann einen Wert für die Planung. Wenn Sie diesen Wert auf NoSchedule festlegen, kann der Kubernetes-Scheduler keine Pods mit nicht definierter Toleranz auf dem Knoten planen.

az aks nodepool add \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name taintnp \
    --node-taints sku=gpu:NoSchedule \
    --no-wait

Wenn für Knoten im Knotenpool ein Taint angewendet wird, definieren Sie in den Podspezifikationen eine Toleranz, die eine Planung für die Knoten ermöglicht. Im folgenden Beispiel werden sku: gpu und effect: NoSchedule so definiert, dass der im vorherigen Schritt für den Knoten angewendete Taint toleriert wird:

kind: Pod
apiVersion: v1
metadata:
  name: tf-mnist
spec:
  containers:
  - name: tf-mnist
    image: mcr.microsoft.com/azuredocs/samples-tf-mnist-demo:gpu
    resources:
      requests:
        cpu: 0.5
        memory: 2Gi
      limits:
        cpu: 4.0
        memory: 16Gi
  tolerations:
  - key: "sku"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

Wenn dieser Pod mit kubectl apply -f gpu-toleration.yaml bereitgestellt wird, kann Kubernetes den Pod erfolgreich auf den Knoten mit dem angewandten Taint planen. Mit dieser logischen Isolation können Sie den Zugriff auf Ressourcen innerhalb eines Clusters steuern.

Wenn Sie Taints anwenden, arbeiten Sie mit Ihren Anwendungsentwicklern und -besitzern zusammen, damit sie die erforderlichen Toleranzen in ihren Bereitstellungen definieren können.

Weitere Informationen zur Verwendung mehrerer Knotenpools in AKS finden Sie unter Erstellen mehrerer Knotenpools für einen Cluster in AKS.

Verhalten von Taints und Toleranzen in AKS

Wenn Sie ein Upgrade für einen Knotenpool in AKS durchführen, folgen Taints und Toleranzen einem festen Muster, da sie für neue Knoten angewendet werden:

Standardcluster, die Azure-VM-Skalierungsgruppen verwenden

Sie können über die AKS-API einen Knotenpool mit Taints versehen, damit neu aufskalierte Knoten die von der API angegebenen Knotentaints erhalten.

Gehen Sie von folgender Annahme aus:

  1. Sie beginnen mit einem Cluster mit zwei Knoten: node1 und node2.
  2. Sie führen ein Upgrade für den Knotenpool durch.
  3. Zwei zusätzliche Knoten werden erstellt: node3 und node4.
  4. Die Taints werden entsprechend übergeben.
  5. Die ursprünglichen node1 und node2 werden gelöscht.

Cluster ohne Unterstützung für VM-Skalierungsgruppen

Gehen Sie noch einmal von folgender Annahme aus:

  1. Sie haben einen Cluster mit zwei Knoten: node1 und node2.
  2. Sie führen ein Upgrade für den Knotenpool durch.
  3. Ein zusätzlicher Knoten wird erstellt: node3.
  4. Die Taints aus node1 werden auf node3 angewendet.
  5. node1 wird gelöscht.
  6. Ein neuer node1 wird erstellt, um den ursprünglichen node1 zu ersetzen.
  7. Die Taints aus node2 werden auf den neuen node1 angewendet.
  8. node2 wird gelöscht.

Zusammengefasst wird node1 zu node3, und node2 wird zum neuen node1.

Wenn Sie einen Knotenpool in AKS skalieren, werden Taints und Toleranzen absichtlich nicht übertragen.

Steuern der Podplanung mit Knotenselektoren und Affinität

Best Practices-Leitfaden

Steuern Sie die Planung von Pods auf Knoten mithilfe von Knotenelektoren, Knotenaffinität oder Pod-interner Affinität. Diese Einstellungen ermöglichen es dem Kubernetes-Scheduler, Workloads logisch zu isolieren, z.B. durch Hardware im Knoten.

Mit Taints und Toleranzen werden Ressourcen durch eine harte Trennung logisch isoliert. Wenn der Pod den Taint eines Knotens nicht toleriert, wird er nicht auf dem Knoten geplant.

Alternativ können Sie Knotenselektoren verwenden. Beispielsweise bezeichnen Sie Knoten, um einen lokal angefügten SSD-Speicher oder eine große Menge an Speicher anzuzeigen, und definieren dann in der Podspezifikation einen Knotenselektor. Kubernetes plant diese Pods auf einem übereinstimmenden Knoten.

Im Gegensatz zu Toleranzen können Pods ohne einen übereinstimmenden Knotenselektor dennoch auf bezeichneten Knoten geplant werden. Dieses Verhalten ermöglicht es, ungenutzte Ressourcen auf den Knoten zu verwenden, priorisiert aber Pods, die den passenden Knotenselektor definieren.

Sehen wir uns ein Beispiel für Knoten mit einer hohe Menge an Arbeitsspeicher an. Diese Knoten priorisieren Pods, für die viel Speicher erforderlich ist. Um sicherzustellen, dass die Ressourcen nicht ungenutzt bleiben, können sie auch andere Pods ausführen. Der folgende Beispielbefehl fügt myAKSCluster in myResourceGroup einen Knotenpool mit der Bezeichnung hardware=highmem hinzu. Alle Knoten in diesem Knotenpool verfügen über diese Bezeichnung.

az aks nodepool add \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name labelnp \
    --node-count 1 \
    --labels hardware=highmem \
    --no-wait

Eine Podspezifikation fügt dann die Eigenschaft nodeSelector hinzu, um einen Knotenselektor zu definieren, der mit der auf einem Knoten festgelegten Bezeichnung übereinstimmt:

kind: Pod
apiVersion: v1
metadata:
  name: tf-mnist
spec:
  containers:
  - name: tf-mnist
    image: mcr.microsoft.com/azuredocs/samples-tf-mnist-demo:gpu
    resources:
      requests:
        cpu: 0.5
        memory: 2Gi
      limits:
        cpu: 4.0
        memory: 16Gi
  nodeSelector:
      hardware: highmem

Wenn Sie diese Scheduleroptionen verwenden, arbeiten Sie mit Ihren Anwendungsentwicklern und -besitzern zusammen, damit sie ihre Podspezifikationen korrekt definieren können.

Weitere Informationen zur Verwendung von Knotenselektoren finden Sie unter Zuweisen von Pods zu Knoten.

Knotenaffinität

Ein Knotenselektor ist eine grundlegende Methode zum Zuweisen von Pods zu einem bestimmten Knoten. Die Knotenaffinität bietet mehr Flexibilität. Hiermit können Sie definieren, was geschieht, wenn für den Pod kein übereinstimmender Knoten vorhanden ist. Ihre Möglichkeiten:

  • Anfordern, dass der Kubernetes-Scheduler einem Pod mit einem bezeichneten Host entspricht. Oder:
  • Eine Übereinstimmung bevorzugen, aber zulassen, dass der Pod auf einem anderen Host geplant wird, wenn keine Übereinstimmung vorhanden ist.

Im folgenden Beispiel wird die Knotenaffinität auf RequiredDuringSchedulingIgnoredDuringExecution festgelegt. Aufgrund dieser Affinität muss der Kubernetes-Scheduler einen Knoten mit einer übereinstimmenden Bezeichnung verwenden. Wenn kein Knoten verfügbar ist, muss der Pod warten, bis die Planung fortgesetzt wird. Damit der Pod auf einem anderen Knoten geplant werden kann, können Sie den Wert stattdessen auf preferredDuringSchedulingIgnoreDuringExecution festlegen:

kind: Pod
apiVersion: v1
metadata:
  name: tf-mnist
spec:
  containers:
  - name: tf-mnist
    image: mcr.microsoft.com/azuredocs/samples-tf-mnist-demo:gpu
    resources:
      requests:
        cpu: 0.5
        memory: 2Gi
      limits:
        cpu: 4.0
        memory: 16Gi
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: hardware
            operator: In
            values:
            - highmem

Der IgnoredDuringExecution-Teil der Einstellung gibt an, dass der Pod nicht vom Knoten entfernt werden soll, wenn sich die Bezeichnung des Knotens ändert. Der Kubernetes-Scheduler verwendet nur die aktualisierten Knotenbezeichnungen für neue Pods, die geplant werden, nicht für bereits geplante Pods auf den Knoten.

Weitere Informationen finden Sie unter Affinität und Antiaffinität.

Pod-interne Affinität und Antiaffinität

Ein letzter Ansatz für den Kubernetes-Scheduler zur logischen Isolation von Workloads ist die Verwendung von Pod-interner Affinität oder Antiaffinität. Diese Einstellungen definieren, dass Pods auf einem Knoten mit einem übereinstimmenden Pod entweder geplant oder nicht geplant werden sollten. Standardmäßig versucht der Kubernetes-Scheduler mehrere Pods knotenübergreifend in einer Replikatgruppe zu planen. Sie können für dieses Verhalten spezifischer Regeln definieren.

Angenommen, Sie haben eine Webanwendung, die auch eine Azure Cache for Redis-Instanz verwendet.

  • Sie verwenden Regeln für die Pod-Antiaffinität, um anzufordern, dass der Kubernetes-Scheduler Replikate über Knoten verteilt.
  • Sie verwenden Affinitätsregeln, um sicherzustellen, dass jede Komponente der Webanwendung auf dem gleichen Host wie ein entsprechender Cache geplant ist.

Die Verteilung der Pods auf die Knoten sieht beispielsweise wie folgt aus:

Knoten 1 Knoten 2 Knoten 3
webapp-1 webapp-2 webapp-3
cache-1 cache-2 cache-3

Pod-interne Affinität und Antiaffinität ermöglichen eine komplexere Bereitstellung als Knotenselektoren oder Knotenaffinität. Mit der Bereitstellung nehmen Sie eine logische Isolierung von Ressourcen vor und steuern, wie Kubernetes Pods auf Knoten plant.

Ein vollständiges Beispiel dieser Webanwendung mit Azure Cache for Redis-Beispiel finden Sie unter Zusammenstellen von Pods auf demselben Knoten.

Nächste Schritte

Dieser Artikel konzentriert sich auf erweiterte Funktionen des Kubernetes-Schedulers. Weitere Informationen zu Clustervorgängen in AKS finden Sie in den folgenden Best Practices: