Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Kubernetes-Steuerebene
Die Kubernetes-Steuerebene besteht aus dem Kubernetes API-Server, dem Kubernetes Controller Manager, dem Scheduler und anderen Komponenten, die für das Funktionieren von Kubernetes erforderlich sind. Die Skalierbarkeitsgrenzen dieser Komponenten sind je nachdem, was Sie im Cluster ausführen, unterschiedlich. Zu den Bereichen mit den größten Auswirkungen auf die Skalierung gehören jedoch die Kubernetes-Version, die Auslastung und die Skalierung einzelner Knoten.
Begrenzen Sie Arbeitslast und Node-Bursting
Wichtig
Um zu vermeiden, dass API-Grenzwerte auf der Steuerungsebene erreicht werden, sollten Sie Skalierungsspitzen begrenzen, die die Clustergröße jeweils um zweistellige Prozentsätze erhöhen (z. B. 1000 Knoten auf 1100 Knoten oder 4000 bis 4500 Pods gleichzeitig).
Die EKS-Steuerungsebene wird automatisch skaliert, wenn Ihr Cluster wächst, aber es gibt Grenzen, wie schnell sie skaliert werden kann. Wenn Sie zum ersten Mal einen EKS-Cluster erstellen, kann die Steuerungsebene nicht sofort auf Hunderte von Knoten oder Tausende von Pods skaliert werden. Weitere Informationen darüber, wie EKS die Skalierung verbessert hat, finden Sie in diesem Blogbeitrag
Für die Skalierung großer Anwendungen muss sich die Infrastruktur anpassen, damit sie vollständig einsatzbereit ist (z. B. Load Balancer, die sich erwärmen). Um die Geschwindigkeit der Skalierung zu kontrollieren, stellen Sie sicher, dass Sie auf der Grundlage der richtigen Metriken für Ihre Anwendung skalieren. Die CPU- und Speicherskalierung kann Ihre Anwendungsbeschränkungen möglicherweise nicht genau vorhersagen, und die Verwendung benutzerdefinierter Metriken (z. B. Anfragen pro Sekunde) in Kubernetes Horizontal Pod Autoscaler (HPA) ist möglicherweise eine bessere Skalierungsoption.
Informationen zur Verwendung einer benutzerdefinierten Metrik finden Sie in den Beispielen in der Kubernetes-Dokumentation.
Skalieren Sie Knoten und Pods sicher herunter
Ersetzen Sie Instanzen mit langer Laufzeit
Durch den regelmäßigen Austausch von Knoten bleibt Ihr Cluster funktionsfähig, da Konfigurationsabweichungen und Probleme vermieden werden, die erst nach längerer Verfügbarkeit auftreten (z. B. langsame Speicherlecks). Durch den automatisierten Austausch erhalten Sie bewährte Verfahren und Verfahren für Knoten-Upgrades und Sicherheitspatches. Wenn jeder Knoten in Ihrem Cluster regelmäßig ausgetauscht wird, ist weniger Aufwand erforderlich, um separate Prozesse für die laufende Wartung aufrechtzuerhalten.
Verwenden Sie die TTL-Einstellungen (Time to Live) von Karpenter, um Instanzen zu ersetzen, nachdem sie eine bestimmte Zeit lang ausgeführt wurden. Selbstverwaltete Knotengruppen können die max-instance-lifetime
Einstellung verwenden, um Knoten automatisch zu wechseln. Verwaltete Knotengruppen verfügen derzeit nicht über diese Funktion, aber Sie können die Anfrage hier
Nicht ausgelastete Knoten entfernen
Sie können Knoten entfernen, wenn sie keine laufenden Workloads haben, indem Sie den Schwellenwert für das Herunterskalieren im Kubernetes Cluster Autoscaler mit --scale-down-utilization-threshold
ttlSecondsAfterEmpty
Verwenden Sie Budgets für Pod-Unterbrechungen und das sichere Herunterfahren von Knoten
Um Pods und Knoten aus einem Kubernetes-Cluster zu entfernen, müssen Controller Aktualisierungen an mehreren Ressourcen vornehmen (z. B. EndpointSlices). Wenn Sie dies häufig oder zu schnell tun, kann dies zu einer Drosselung des API-Servers und zu Anwendungsausfällen führen, wenn Änderungen auf die Controller übertragen werden. Budgets für Pod-Unterbrechungen
Verwenden Sie den clientseitigen Cache, wenn Sie Kubectl ausführen
Wenn Sie den Befehl kubectl ineffizient verwenden, kann dies zu zusätzlicher Belastung des Kubernetes-API-Servers führen. Sie sollten vermeiden, Skripts oder Automatisierungen auszuführen, die kubectl wiederholt verwenden (z. B. in einer For-Schleife), oder Befehle ohne lokalen Cache auszuführen.
kubectl
hat einen clientseitigen Cache, der Erkennungsinformationen aus dem Cluster zwischenspeichert, um die Anzahl der erforderlichen API-Aufrufe zu reduzieren. Der Cache ist standardmäßig aktiviert und wird alle 10 Minuten aktualisiert.
Wenn Sie kubectl aus einem Container oder ohne clientseitigen Cache ausführen, können Probleme mit der API-Drosselung auftreten. Es wird empfohlen, den Cluster-Cache beizubehalten, indem Sie ihn mounten, um unnötige API-Aufrufe --cache-dir
zu vermeiden.
Deaktivieren Sie die Kubectl-Komprimierung
Das Deaktivieren der kubectl-Komprimierung in Ihrer kubeconfig-Datei kann die API- und Client-CPU-Auslastung reduzieren. Standardmäßig komprimiert der Server die an den Client gesendeten Daten, um die Netzwerkbandbreite zu optimieren. Dadurch erhöht sich die CPU-Last auf dem Client und dem Server bei jeder Anfrage, und wenn Sie über ausreichend Bandbreite verfügen, können durch Deaktivieren der Komprimierung der Overhead und die Latenz reduziert werden. Um die Komprimierung zu deaktivieren, können Sie das --disable-compression=true
Flag verwenden oder es disable-compression: true
in Ihrer kubeconfig-Datei festlegen.
apiVersion: v1 clusters: - cluster: server: serverURL disable-compression: true name: cluster
Shard Cluster Autoscaler
Der Kubernetes Cluster Autoscaler wurde für die Skalierung auf bis zu 1000 Knoten getestet
ClusterAutoscaler-1
autoscalingGroups: - name: eks-core-node-grp-20220823190924690000000011-80c1660e-030d-476d-cb0d-d04d585a8fcb maxSize: 50 minSize: 2 - name: eks-data_m1-20220824130553925600000011-5ec167fa-ca93-8ca4-53a5-003e1ed8d306 maxSize: 450 minSize: 2 - name: eks-data_m2-20220824130733258600000015-aac167fb-8bf7-429d-d032-e195af4e25f5 maxSize: 450 minSize: 2 - name: eks-data_m3-20220824130553914900000003-18c167fa-ca7f-23c9-0fea-f9edefbda002 maxSize: 450 minSize: 2
ClusterAutoscaler-2
autoscalingGroups: - name: eks-data_m4-2022082413055392550000000f-5ec167fa-ca86-6b83-ae9d-1e07ade3e7c4 maxSize: 450 minSize: 2 - name: eks-data_m5-20220824130744542100000017-02c167fb-a1f7-3d9e-a583-43b4975c050c maxSize: 450 minSize: 2 - name: eks-data_m6-2022082413055392430000000d-9cc167fa-ca94-132a-04ad-e43166cef41f maxSize: 450 minSize: 2 - name: eks-data_m7-20220824130553921000000009-96c167fa-ca91-d767-0427-91c879ddf5af maxSize: 450 minSize: 2
API-Priorität und Fairness

Übersicht
Um sich bei häufigen Anfragen vor Überlastung zu schützen, begrenzt der API-Server die Anzahl der Inflight-Anfragen, die zu einem bestimmten Zeitpunkt noch ausstehen können. Sobald dieses Limit überschritten wird, beginnt der API-Server, Anfragen abzulehnen und gibt einen 429-HTTP-Antwortcode für „Zu viele Anfragen“ an die Clients zurück. Es ist vorzuziehen, dass der Server Anfragen verwirft und die Clients es später erneut versuchen, als keine serverseitigen Beschränkungen für die Anzahl der Anfragen festzulegen und die Steuerungsebene zu überlasten, was zu Leistungseinbußen oder Nichtverfügbarkeit führen könnte.
Der Mechanismus, mit dem Kubernetes konfiguriert, wie diese Inflight-Anfragen auf verschiedene Anfragetypen aufgeteilt werden, wird API-Priorität und Fairness genannt.--max-requests-inflight
--max-mutating-requests-inflight
EKS verwendet die Standardwerte von 400 und 200 Anfragen für diese Flags, sodass insgesamt 600 Anfragen zu einem bestimmten Zeitpunkt versendet werden können. Da die Steuerungsebene jedoch als Reaktion auf die zunehmende Auslastung und die Fluktuation der Arbeitslast auf größere Größen skaliert wird, wird die Quote für Anfragen während der Übertragung bis 2000 entsprechend erhöht (Änderungen vorbehalten). APF gibt an, wie diese Quote für Anfragen während des Fluges weiter auf verschiedene Anforderungstypen aufgeteilt wird. Beachten Sie, dass EKS-Kontrollebenen hochverfügbar sind und mindestens 2 API-Server für jeden Cluster registriert sind. Das bedeutet, dass die Gesamtzahl der Inflight-Anfragen, die Ihr Cluster verarbeiten kann, doppelt so hoch ist (oder höher, wenn die horizontale Skalierung weiter ausgebaut wird) wie die pro Kube-Apiserver festgelegte Inflight-Quote. Dies entspricht mehreren Tausend auf den größten EKS-Clustern. requests/second
Zwei Arten von Kubernetes-Objekten, genannt PriorityLevelConfigurations und FlowSchemas, konfigurieren, wie die Gesamtzahl der Anfragen auf verschiedene Anforderungstypen aufgeteilt wird. Diese Objekte werden vom API-Server automatisch verwaltet und EKS verwendet die Standardkonfiguration dieser Objekte für die jeweilige Kubernetes-Nebenversion. PriorityLevelConfigurations stellen einen Bruchteil der Gesamtzahl der zulässigen Anfragen dar. Beispielsweise werden dem Workload-High PriorityLevelConfiguration 98 der insgesamt 600 Anfragen zugewiesen. Die Summe der allen PriorityLevelConfigurations zugewiesenen Anfragen entspricht 600 (oder etwas mehr als 600, da der API-Server aufrundet, wenn einer bestimmten Stufe nur ein Bruchteil einer Anfrage gewährt wird). Um den Wert PriorityLevelConfigurations in Ihrem Cluster und die Anzahl der einzelnen Anfragen zu überprüfen, können Sie den folgenden Befehl ausführen. Dies sind die Standardeinstellungen für EKS 1.32:
$ kubectl get --raw /metrics | grep apiserver_flowcontrol_nominal_limit_seats apiserver_flowcontrol_nominal_limit_seats{priority_level="catch-all"} 13 apiserver_flowcontrol_nominal_limit_seats{priority_level="exempt"} 0 apiserver_flowcontrol_nominal_limit_seats{priority_level="global-default"} 49 apiserver_flowcontrol_nominal_limit_seats{priority_level="leader-election"} 25 apiserver_flowcontrol_nominal_limit_seats{priority_level="node-high"} 98 apiserver_flowcontrol_nominal_limit_seats{priority_level="system"} 74 apiserver_flowcontrol_nominal_limit_seats{priority_level="workload-high"} 98 apiserver_flowcontrol_nominal_limit_seats{priority_level="workload-low"} 245
Der zweite Objekttyp ist. FlowSchemas API-Serveranfragen mit einem bestimmten Satz von Eigenschaften werden denselben Kategorien zugeordnet FlowSchema. Zu diesen Eigenschaften gehören entweder der authentifizierte Benutzer oder Attribute der Anfrage, z. B. die API-Gruppe, der Namespace oder die Ressource. A gibt FlowSchema auch an, welcher Art von Anfrage PriorityLevelConfiguration dieser Anfragetyp zugeordnet werden soll. Die beiden Objekte zusammen sagen: „Ich möchte, dass diese Art von Anfrage auf diesen Anteil der Anfragen während des Fluges angerechnet wird.“ Wenn eine Anfrage den API-Server erreicht, überprüft dieser jede Anfrage, FlowSchemas bis eine gefunden wird, die allen erforderlichen Eigenschaften entspricht. Wenn mehrere mit einer Anfrage FlowSchemas übereinstimmen, wählt der API-Server die FlowSchema mit der kleinsten übereinstimmenden Priorität aus, die als Eigenschaft im Objekt angegeben ist.
Die Zuordnung von FlowSchemas to PriorityLevelConfigurations kann mit diesem Befehl eingesehen werden:
$ kubectl get flowschemas NAME PRIORITYLEVEL MATCHINGPRECEDENCE DISTINGUISHERMETHOD AGE MISSINGPL exempt exempt 1 <none> 7h19m False eks-exempt exempt 2 <none> 7h19m False probes exempt 2 <none> 7h19m False system-leader-election leader-election 100 ByUser 7h19m False endpoint-controller workload-high 150 ByUser 7h19m False workload-leader-election leader-election 200 ByUser 7h19m False system-node-high node-high 400 ByUser 7h19m False system-nodes system 500 ByUser 7h19m False kube-controller-manager workload-high 800 ByNamespace 7h19m False kube-scheduler workload-high 800 ByNamespace 7h19m False kube-system-service-accounts workload-high 900 ByNamespace 7h19m False eks-workload-high workload-high 1000 ByUser 7h14m False service-accounts workload-low 9000 ByUser 7h19m False global-default global-default 9900 ByUser 7h19m False catch-all catch-all 10000 ByUser 7h19m False
PriorityLevelConfigurations kann den Typ Queue, Reject oder Exempt haben. Bei den Typen Queue und Reject gilt für diese Prioritätsstufe ein Limit für die maximale Anzahl von Inflight-Anfragen. Das Verhalten ist jedoch unterschiedlich, wenn dieses Limit erreicht wird. Der Workload-High PriorityLevelConfiguration verwendet beispielsweise den Typ Queue und verfügt über 98 Anfragen, die vom Controller-Manager, Endpoint-Controller, Scheduler, EKS-bezogenen Controllern und von Pods, die im Kube-System-Namespace ausgeführt werden, verwendet werden können. Da der Typ Queue verwendet wird, versucht der API-Server, Anfragen im Speicher zu belassen und hofft, dass die Anzahl der Inflight-Anfragen unter 98 fällt, bevor diese Anfragen das Timeout überschreiten. Wenn bei einer bestimmten Anfrage ein Timeout in der Warteschlange auftritt oder wenn zu viele Anfragen bereits in der Warteschlange stehen, hat der API-Server keine andere Wahl, als die Anfrage zu verwerfen und dem Client eine 429 zurückzugeben. Beachten Sie, dass eine Warteschlange zwar verhindern kann, dass eine Anfrage eine 429-Nummer erhält, dass sie jedoch mit einer erhöhten end-to-end Latenz bei der Anfrage einhergeht.
Betrachten Sie nun den Catch-All FlowSchema , der dem Catch-All mit dem Typ Reject zugeordnet PriorityLevelConfiguration ist. Wenn Clients das Limit von 13 Inflight-Anfragen erreichen, führt der API-Server keine Warteschlangen durch und verwirft die Anfragen sofort mit dem Antwortcode 429. Und schließlich erhalten Anfragen, die einer PriorityLevelConfiguration vom Typ Exempt zugeordnet sind, niemals eine 429 und werden immer sofort versendet. Dies wird für Anfragen mit hoher Priorität wie Healthz-Anfragen oder Anfragen aus der Gruppe system:masters verwendet.
APF und verworfene Anfragen werden überwacht
Um zu überprüfen, ob Anfragen aufgrund von APF gelöscht wurden, apiserver_flowcontrol_rejected_requests_total
können die API-Server-Metriken überwacht werden, um die betroffenen FlowSchemas und zu überprüfen. PriorityLevelConfigurations Diese Metrik zeigt beispielsweise, dass 100 Anfragen von den Service-Accounts aufgrund eines Timeouts bei Anfragen in Warteschlangen mit niedriger Auslastung verworfen FlowSchema wurden:
% kubectl get --raw /metrics | grep apiserver_flowcontrol_rejected_requests_total
apiserver_flowcontrol_rejected_requests_total{flow_schema="service-accounts",priority_level="workload-low",reason="time-out"} 100
Um zu überprüfen, wie nah eine bestimmte Person daran PriorityLevelConfiguration ist, 429 Sekunden zu empfangen oder aufgrund von Warteschlangen eine erhöhte Latenz zu erleben, können Sie den Unterschied zwischen dem Parallelitätslimit und der verwendeten Parallelität vergleichen. In diesem Beispiel haben wir einen Puffer von 100 Anfragen.
% kubectl get --raw /metrics | grep 'apiserver_flowcontrol_nominal_limit_seats.*workload-low' apiserver_flowcontrol_nominal_limit_seats{priority_level="workload-low"} 245 % kubectl get --raw /metrics | grep 'apiserver_flowcontrol_current_executing_seats.*workload-low' apiserver_flowcontrol_current_executing_seats{flow_schema="service-accounts",priority_level="workload-low"} 145
Um zu überprüfen, ob bei einer bestimmten PriorityLevelConfiguration Anfrage Warteschlangen, aber nicht unbedingt verworfene Anfragen auftreten, apiserver_flowcontrol_current_inqueue_requests
kann auf die Metrik für verwiesen werden:
% kubectl get --raw /metrics | grep 'apiserver_flowcontrol_current_inqueue_requests.*workload-low'
apiserver_flowcontrol_current_inqueue_requests{flow_schema="service-accounts",priority_level="workload-low"} 10
Weitere nützliche Prometheus-Metriken sind:
-
apiserver_flowcontrol_dispatched_requests_total
-
apiserver_flowcontrol_request_execution_seconds
-
apiserver_flowcontrol_request_wait_duration_seconds
Eine vollständige Liste der APF-Metriken finden Sie in der Upstream-Dokumentation.
Verhinderung verworfener Anfragen
Vermeiden Sie 429s, indem Sie Ihren Workload ändern
Wenn APF Anfragen aufgrund einer bestimmten PriorityLevelConfiguration Überschreitung der maximal zulässigen Anzahl von Inflight-Anfragen verwirft, FlowSchemas können die betroffenen Clients die Anzahl der Anfragen, die zu einem bestimmten Zeitpunkt ausgeführt werden, verringern. Dies kann erreicht werden, indem die Gesamtzahl der Anfragen reduziert wird, die in dem Zeitraum gestellt wurden, in dem 429 Anfragen gestellt wurden. Beachten Sie, dass Anfragen mit langer Laufzeit, wie z. B. teure Listenanrufe, besonders problematisch sind, da sie für die gesamte Dauer ihrer Ausführung als Inflight-Anfragen gelten. Wenn Sie die Anzahl dieser teuren Anfragen reduzieren oder die Latenz dieser Listenaufrufen optimieren (z. B. indem Sie die Anzahl der pro Anfrage abgerufenen Objekte reduzieren oder zur Verwendung einer Überwachungsanforderung wechseln), können Sie dazu beitragen, die Gesamtparallelität zu reduzieren, die für die jeweilige Arbeitslast erforderlich ist.
Vermeiden Sie 429s, indem Sie Ihre APF-Einstellungen ändern
Warnung
Ändern Sie die APF-Standardeinstellungen nur, wenn Sie wissen, was Sie tun. Falsch konfigurierte APF-Einstellungen können zu verworfenen API-Serveranfragen und erheblichen Arbeitsauslastungsunterbrechungen führen.
Ein weiterer Ansatz zur Verhinderung verworfener Anfragen besteht darin, die Standardeinstellung FlowSchemas oder die PriorityLevelConfigurations Installation auf EKS-Clustern zu ändern. EKS installiert die Upstream-Standardeinstellungen für FlowSchemas und PriorityLevelConfigurations für die angegebene Kubernetes-Nebenversion. Der API-Server gleicht diese Objekte automatisch mit ihren Standardeinstellungen ab, sofern sie nicht geändert werden, es sei denn, die folgende Anmerkung zu den Objekten ist auf „Falsch“ gesetzt:
metadata: annotations: apf.kubernetes.io/autoupdate-spec: "false"
Auf hoher Ebene können die APF-Einstellungen wie folgt geändert werden:
-
Weisen Sie Anfragen, die Ihnen wichtig sind, mehr Kapazität an Bord zu.
-
Isolieren Sie unwichtige oder teure Anfragen, die zu Kapazitätsverlusten für andere Anforderungstypen führen können.
Dies kann erreicht werden, indem entweder die Standardeinstellung FlowSchemas geändert PriorityLevelConfigurations oder neue Objekte dieser Typen erstellt werden. Betreiber können die Werte assuredConcurrencyShares für die entsprechenden PriorityLevelConfigurations Objekte erhöhen, um den Anteil der ihnen zugewiesenen Anfragen während des Fluges zu erhöhen. Darüber hinaus kann die Anzahl der Anfragen, die zu einem bestimmten Zeitpunkt in die Warteschlange gestellt werden können, erhöht werden, wenn die Anwendung die zusätzliche Latenz bewältigen kann, die dadurch entsteht, dass Anfragen vor dem Versand in die Warteschlange gestellt werden.
Alternativ können neue FlowSchema PriorityLevelConfigurations Objekte erstellt werden, die speziell auf die Arbeitslast des Kunden zugeschnitten sind. Beachten Sie, dass die Anzahl der Anfragen, die von anderen Buckets bearbeitet PriorityLevelConfigurations werden können, reduziert wird, wenn Sie entweder vorhandenen PriorityLevelConfigurations oder neuen mehr assuredConcurrencyShares Anfragen zuweisen, da das Gesamtlimit bei 600 Inflight pro API-Server bleibt.
Wenn Sie Änderungen an den APF-Standardeinstellungen vornehmen, sollten diese Metriken auf einem Cluster außerhalb der Produktion überwacht werden, um sicherzustellen, dass eine Änderung der Einstellungen nicht zu unbeabsichtigten 429s führt:
-
Die Metrik für
apiserver_flowcontrol_rejected_requests_total
sollte für alle überwacht werden, FlowSchemas um sicherzustellen, dass keine Buckets anfangen, Anfragen zu verwerfen. -
Die Werte für
apiserver_flowcontrol_nominal_limit_seats
undapiserver_flowcontrol_current_executing_seats
sollten miteinander verglichen werden, um sicherzustellen, dass bei der Verwendung von Parallelität kein Risiko besteht, dass das Limit für diese Prioritätsstufe überschritten wird.
Ein häufiger Anwendungsfall für die Definition eines neuen FlowSchema und PriorityLevelConfiguration ist die Isolierung. Nehmen wir an, wir möchten lang andauernde Listenereignisaufrufe von Pods auf ihren eigenen Anteil an Anfragen isolieren. Dadurch wird verhindert, dass wichtige Anfragen von Pods, die die vorhandenen Dienstkonten verwenden, 429 Anfragen FlowSchema erhalten und ihnen die Anforderungskapazität entzogen wird. Denken Sie daran, dass die Gesamtzahl der Anfragen während der Übertragung begrenzt ist. Dieses Beispiel zeigt jedoch, dass die APF-Einstellungen geändert werden können, um die Anforderungskapazität besser auf die jeweilige Arbeitslast aufzuteilen:
FlowSchema Beispielobjekt zur Isolierung von Listenereignisanfragen:
apiVersion: flowcontrol.apiserver.k8s.io/v1 kind: FlowSchema metadata: name: list-events-default-service-accounts spec: distinguisherMethod: type: ByUser matchingPrecedence: 8000 priorityLevelConfiguration: name: catch-all rules: - resourceRules: - apiGroups: - '*' namespaces: - default resources: - events verbs: - list subjects: - kind: ServiceAccount serviceAccount: name: default namespace: default
-
Es FlowSchema erfasst alle Listenereignisaufrufen, die von Dienstkonten im Standard-Namespace getätigt wurden.
-
Die Vergleichspriorität 8000 ist niedriger als der Wert 9000, der von den vorhandenen Dienstkonten verwendet wird, FlowSchema sodass diese Listenereignisaufrufe eher mit list-events-default-service -accounts als mit service-accounts übereinstimmen.
-
Wir verwenden den Catch-All, um diese Anfragen PriorityLevelConfiguration zu isolieren. In diesem Bucket können nur 13 eingehende Anfragen für diese lang andauernden List-Event-Aufrufe verwendet werden. Pods erhalten ab sofort 429 Anfragen, sobald sie versuchen, mehr als 13 dieser Anfragen gleichzeitig zu stellen.
Ressourcen auf dem API-Server werden abgerufen
Das Abrufen von Informationen vom API-Server ist ein erwartetes Verhalten für Cluster jeder Größe. Wenn Sie die Anzahl der Ressourcen im Cluster skalieren, können die Häufigkeit der Anfragen und das Datenvolumen schnell zu einem Engpass für die Kontrollebene werden und zu Latenz und Langsamkeit der API führen. Je nach Schweregrad der Latenz kann es zu unerwarteten Ausfallzeiten kommen, wenn Sie nicht vorsichtig sind.
Zu wissen, was Sie anfordern und wie oft, sind die ersten Schritte, um diese Art von Problemen zu vermeiden. Im Folgenden finden Sie Anleitungen zur Begrenzung des Abfragevolumens auf der Grundlage der bewährten Skalierungsmethoden. In diesem Abschnitt werden die Vorschläge in der Reihenfolge gegeben, mit den Optionen zu beginnen, von denen bekannt ist, dass sie sich am besten skalieren lassen.
Verwenden Sie Shared Informers
Bei der Entwicklung von Controllern und Automatisierungen, die in die Kubernetes-API integriert sind, müssen Sie häufig Informationen aus Kubernetes-Ressourcen abrufen. Wenn Sie regelmäßig nach diesen Ressourcen fragen, kann dies zu einer erheblichen Belastung des API-Servers führen.
Wenn Sie einen Informer
Controller sollten es vermeiden, clusterweite Ressourcen ohne Labels und Feldselektoren abzufragen, insbesondere in großen Clustern. Bei jeder ungefilterten Abfrage müssen viele unnötige Daten von etcd über den API-Server gesendet werden, um vom Client gefiltert zu werden. Durch Filtern auf der Grundlage von Labels und Namespaces können Sie den Arbeitsaufwand reduzieren, den der API-Server ausführen muss, um die Anfrage und die an den Client gesendeten Daten zu erfüllen.
Optimieren Sie die Nutzung der Kubernetes-API
Wenn Sie die Kubernetes-API mit benutzerdefinierten Controllern oder Automatisierung aufrufen, ist es wichtig, dass Sie die Aufrufe nur auf die Ressourcen beschränken, die Sie benötigen. Ohne Einschränkungen können Sie den API-Server usw. unnötig belasten.
Es wird empfohlen, wann immer möglich das Watch-Argument zu verwenden. Ohne Argumente ist das Standardverhalten das Auflisten von Objekten. Um watch statt list zu verwenden, können Sie es ?watch=true
an das Ende Ihrer API-Anfrage anhängen. Um beispielsweise alle Pods im Standard-Namespace mit einer Uhr abzurufen, verwenden Sie:
/api/v1/namespaces/default/pods?watch=true
Wenn Sie Objekte auflisten, sollten Sie den Umfang dessen, was Sie auflisten, und die Menge der zurückgegebenen Daten einschränken. Sie können die zurückgegebenen Daten einschränken, indem Sie den Anfragen limit=500
Argumente hinzufügen. Das fieldSelector
Argument und der /namespace/
Pfad können nützlich sein, um sicherzustellen, dass Ihre Listen so eng wie nötig abgegrenzt sind. Um beispielsweise nur laufende Pods im Standard-Namespace aufzulisten, verwenden Sie den folgenden API-Pfad und die folgenden Argumente.
/api/v1/namespaces/default/pods?fieldSelector=status.phase=Running&limit=500
Oder listen Sie alle Pods auf, die ausgeführt werden mit:
/api/v1/pods?fieldSelector=status.phase=Running&limit=500
Eine weitere Option, um Watch-Aufrufe oder aufgelistete Objekte einzuschränken, ist resourceVersions
die Verwendung dieser Option. Weitere Informationen finden Sie in der Kubernetes-DokumentationresourceVersion
Argument erhalten Sie die neueste verfügbare Version, für die ein etcd-Quorum-Read erforderlich ist. Dies ist der teuerste und langsamste Lesevorgang für die Datenbank. Die ResourceVersion hängt davon ab, welche Ressourcen Sie abfragen möchten, und kann im Feld gefunden werden. metadata.resourseVersion
Dies wird auch empfohlen, wenn Sie Watch-Anrufe und nicht nur Listenanrufe verwenden
Es ist ein spezielles Programm resourceVersion=0
verfügbar, das Ergebnisse aus dem API-Server-Cache zurückgibt. Dies kann die Belastung von etcd reduzieren, unterstützt aber keine Paginierung.
/api/v1/namespaces/default/pods?resourceVersion=0
Es wird empfohlen, watch mit einer ResourceVersion zu verwenden, die auf den neuesten bekannten Wert gesetzt ist, der aus der vorherigen Liste oder Überwachung empfangen wurde. Dies wird automatisch in Client-Go abgewickelt. Es wird jedoch empfohlen, dies noch einmal zu überprüfen, wenn Sie einen k8s-Client in anderen Sprachen verwenden.
/api/v1/namespaces/default/pods?watch=true&resourceVersion=362812295
Wenn Sie die API ohne Argumente aufrufen, ist sie für den API-Server usw. am ressourcenintensivsten. Dieser Aufruf ruft alle Pods in allen Namespaces ab, ohne Seitennummerierung oder Einschränkung des Gültigkeitsbereichs und erfordert ein Quorum, das aus etcd gelesen wird.
/api/v1/pods
DaemonSet Beugen Sie donnernden Herden vor
A DaemonSet stellt sicher, dass auf allen (oder einigen) Knoten eine Kopie eines Pods ausgeführt wird. Wenn Knoten dem Cluster beitreten, erstellt der Daemonset-Controller Pods für diese Knoten. Wenn Knoten den Cluster verlassen, werden diese Pods im Müll gesammelt. Durch das Löschen eines DaemonSet werden die erstellten Pods bereinigt.
Einige typische Verwendungen von a DaemonSet sind:
-
Auf jedem Knoten wird ein Cluster-Speicher-Daemon ausgeführt
-
Auf jedem Knoten wird ein Daemon zur Erfassung von Protokollen ausgeführt
-
Auf jedem Knoten wird ein Daemon zur Knotenüberwachung ausgeführt
In Clustern mit Tausenden von Knoten kann das Erstellen eines neuen DaemonSet, das Aktualisieren eines DaemonSet oder das Erhöhen der Anzahl von Knoten zu einer hohen Belastung der Steuerungsebene führen. Wenn DaemonSet Pods beim Start des Pods teure API-Serveranfragen ausgeben, können sie aufgrund einer großen Anzahl gleichzeitiger Anfragen zu einem hohen Ressourcenverbrauch auf der Steuerungsebene führen.
Im Normalbetrieb können Sie a verwenden, RollingUpdate
um die schrittweise Einführung neuer DaemonSet Pods sicherzustellen. Bei einer RollingUpdate
Aktualisierungsstrategie beendet der Controller nach dem Aktualisieren einer DaemonSet Vorlage alte DaemonSet Pods und erstellt automatisch und kontrolliert neue DaemonSet Pods. Während des gesamten Aktualisierungsvorgangs DaemonSet wird auf jedem Knoten höchstens ein Pod von ausgeführt. Sie können einen schrittweisen Rollout durchführen, indem Sie maxUnavailable
die Werte maxSurge
auf 1, 0 und 60 minReadySeconds
einstellen. Wenn Sie keine Aktualisierungsstrategie angeben, erstellt Kubernetes standardmäßig eine RollingUpdate
mit maxUnavailable
den Werten 1, maxSurge
0 und minReadySeconds
0.
minReadySeconds: 60 strategy: type: RollingUpdate rollingUpdate: maxSurge: 0 maxUnavailable: 1
A RollingUpdate
gewährleistet die schrittweise Einführung neuer DaemonSet Pods, sofern der DaemonSet bereits erstellt wurde und die erwartete Anzahl von Ready
Pods auf allen Knoten aufweist. Unter bestimmten Bedingungen, die nicht durch Strategien abgedeckt sind, kann es zu Problemen mit donnernden Herden RollingUpdate
kommen.
Vermeiden Sie donnernde Herden auf der Erde DaemonSet
Standardmäßig erstellt der Daemonset-Controller im unabhängig von der RollingUpdate
Konfiguration Pods für alle passenden Knoten gleichzeitig, wenn kube-controller-manager Sie einen neuen erstellen. DaemonSet Um einen schrittweisen Rollout von Pods zu erzwingen, nachdem Sie einen erstellt haben DaemonSet, können Sie entweder ein oder verwenden. NodeSelector
NodeAffinity
Dadurch wird ein Knoten erstellt DaemonSet , der Null entspricht. Anschließend können Sie die Knoten schrittweise aktualisieren, sodass sie für die Ausführung eines Pods mit einer kontrollierten Geschwindigkeit DaemonSet in Frage kommen. Sie können diesem Ansatz folgen:
-
Fügen Sie allen Knoten für ein Label hinzu
run-daemonset=false
.
kubectl label nodes --all run-daemonset=false
-
Erstellen Sie Ihre DaemonSet mit einer
NodeAffinity
Einstellung, die zu jedem Knoten ohnerun-daemonset=false
Label passt. Dies führt zunächst dazu, DaemonSet dass Sie keine entsprechenden Pods haben.
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: run-daemonset operator: NotIn values: - "false"
-
Entfernen Sie das
run-daemonset=false
Etikett mit einer kontrollierten Geschwindigkeit von Ihren Knoten. Sie können dieses Bash-Skript als Beispiel verwenden:
#!/bin/bash
nodes=$(kubectl get --raw "/api/v1/nodes" | jq -r '.items | .[].metadata.name')
for node in ${nodes[@]}; do
echo "Removing run-daemonset label from node $node"
kubectl label nodes $node run-daemonset-
sleep 5
done
-
Optional können Sie die
NodeAffinity
Einstellung aus Ihrem DaemonSet Objekt entfernen. Beachten Sie, dass dadurch auch ein Pod ausgelöstRollingUpdate
und nach und nach alle vorhandenen DaemonSet Pods ersetzt werden, da sich die DaemonSet Vorlage geändert hat.
Vermeiden Sie donnernde Herden bei Node-Scale-Outs
Ähnlich wie bei der DaemonSet Erstellung kann die schnelle Erstellung neuer Knoten dazu führen, dass eine große Anzahl von DaemonSet Pods gleichzeitig gestartet wird. Sie sollten neue Knoten mit einer kontrollierten Geschwindigkeit erstellen, damit der Controller DaemonSet Pods mit derselben Geschwindigkeit erstellt. Falls dies nicht möglich ist, können Sie dafür sorgen, dass die neuen Knoten zunächst nicht für die vorhandenen Knoten in Frage kommen, DaemonSet indem Sie NodeAffinity
Als Nächstes können Sie den neuen Knoten schrittweise ein Label hinzufügen, sodass der Daemonset-Controller Pods mit einer kontrollierten Geschwindigkeit erzeugt. Sie können diesem Ansatz folgen:
-
Fügen Sie allen vorhandenen Knoten ein Label hinzu für
run-daemonset=true
kubectl label nodes --all run-daemonset=true
-
Aktualisieren Sie Ihre DaemonSet mit einer
NodeAffinity
Einstellung, die jedem Knoten mit einerrun-daemonset=true
Bezeichnung entspricht. Beachten Sie, dass dadurch auch ein Pod ausgelöstRollingUpdate
und nach und nach alle vorhandenen DaemonSet Pods ersetzt werden, da sich die DaemonSet Vorlage geändert hat. Sie sollten warten,RollingUpdate
bis der Vorgang abgeschlossen ist, bevor Sie mit dem nächsten Schritt fortfahren.
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: run-daemonset operator: In values: - "true"
-
Erstellen Sie neue Knoten in Ihrem Cluster. Beachten Sie, dass diese Knoten nicht mit der
run-daemonset=true
Bezeichnung versehen DaemonSet werden, sodass sie nicht mit diesen Knoten übereinstimmen. -
Fügen Sie das
run-daemonset=true
Label Ihren neuen Knoten (die derzeit nicht über dasrun-daemonset
Label verfügen) in kontrollierter Geschwindigkeit hinzu. Sie können dieses Bash-Skript als Beispiel verwenden:
#!/bin/bash
nodes=$(kubectl get --raw "/api/v1/nodes?labelSelector=%21run-daemonset" | jq -r '.items | .[].metadata.name')
for node in ${nodes[@]}; do
echo "Adding run-daemonset=true label to node $node"
kubectl label nodes $node run-daemonset=true
sleep 5
done
-
Entfernen Sie optional die
NodeAffinity
Einstellung von Ihrem DaemonSet Objekt und entfernen Sie dierun-daemonset
Bezeichnung von allen Knoten.
Vermeiden Sie donnernde Herden bei Updates DaemonSet
Eine RollingUpdate
Richtlinie berücksichtigt nur die maxUnavailable
Einstellung für DaemonSet Pods, bei denen dies der Fall ist. Ready
Wenn a nur NotReady
Pods oder einen großen Prozentsatz von NotReady
Pods DaemonSet hat und Sie seine Vorlage aktualisieren, erstellt der Daemonset-Controller gleichzeitig neue Pods für alle Pods. NotReady
Dies kann bei einer großen Anzahl von NotReady
Pods zu Problemen mit donnernden Herden führen, z. B. wenn die Pods ständig abstürzen oder keine Bilder abrufen können.
Um einen schrittweisen Rollout von Pods zu erzwingen, wenn Sie einen aktualisieren DaemonSet und es NotReady
Pods gibt, können Sie die Aktualisierungsstrategie auf der DaemonSet Seite Von bis vorübergehend ändern. RollingUpdate
OnDelete
Wenn Sie eine DaemonSet Vorlage aktualisiert haben, erstellt der Controller neue Pods, nachdem Sie die alten manuell gelöscht haben, sodass Sie den Rollout neuer Pods steuern können. OnDelete
Sie können diesem Ansatz folgen:
-
Überprüfen Sie, ob Sie irgendwelche
NotReady
Pods in Ihrem haben DaemonSet. -
Falls nein, können Sie die DaemonSet Vorlage problemlos aktualisieren und die
RollingUpdate
Strategie gewährleistet eine schrittweise Einführung. -
Falls ja, sollten Sie zuerst Ihre aktualisieren, DaemonSet um die
OnDelete
Strategie verwenden zu können.
updateStrategy: type: OnDelete
-
Aktualisieren Sie als Nächstes Ihre DaemonSet Vorlage mit den erforderlichen Änderungen.
-
Nach diesem Update können Sie die alten DaemonSet Pods löschen, indem Sie Anfragen zum Löschen von Pods mit kontrollierter Geschwindigkeit stellen. Sie können dieses Bash-Skript als Beispiel verwenden, bei dem der DaemonSet Name im Kube-System-Namespace fluentd-elasticsearch lautet:
#!/bin/bash
daemonset_pods=$(kubectl get --raw "/api/v1/namespaces/kube-system/pods?labelSelector=name%3Dfluentd-elasticsearch" | jq -r '.items | .[].metadata.name')
for pod in ${daemonset_pods[@]}; do
echo "Deleting pod $pod"
kubectl delete pod $pod -n kube-system
sleep 5
done
-
Schließlich können Sie Ihren Rücken zur früheren Strategie aktualisieren. DaemonSet
RollingUpdate