Skalierbarkeit planen


Auf dieser Seite werden allgemeine Best Practices für die Architektur von skalierbaren GKE-Clustern beschrieben. Sie können diese Empfehlungen auf alle Cluster und Arbeitslasten anwenden, um die optimale Leistung zu erzielen. Diese Empfehlungen sind besonders wichtig für Cluster, die Sie weitgehend skalieren möchten. Best Practices richten sich an Administratoren, die für die Bereitstellung der Infrastruktur verantwortlich sind, und für Entwickler, die Kubernetes-Komponenten und -Arbeitslasten vorbereiten.

Was ist Skalierbarkeit?

In einem Kubernetes-Cluster bezieht sich Skalierbarkeit auf die Fähigkeit des Clusters, zu wachsen, ohne seine Service Level Objectives (SLOs) zu überschreiten. Kubernetes hat auch eine Reihe von SLOs.

Kubernetes ist ein komplexes System, dessen Skalierbarkeit von mehreren Faktoren bestimmt wird. Zu diesen Faktoren gehören unter anderem der Typ und die Anzahl der Knoten in einem Knotenpool, die Typen und die Anzahl der Knotenpools, die Anzahl der verfügbaren Pods, die Methode zur Zuweisung von Ressourcen zu Pods und die Anzahl der Dienste oder Back-Ends hinter einem Dienst.

Best Practices für die Verfügbarkeit

Regionale oder zonale Steuerungsebene auswählen

Aufgrund von Architekturunterschieden eignen sich regionale Cluster besser für Hochverfügbarkeit. Regionale Cluster haben in einer Region mehrere Steuerungsebenen in mehreren Computing-Zonen. Zonale Cluster haben eine Steuerungsebene in einer einzelnen Computing-Zone.

Wenn ein zonaler Cluster aktualisiert wird, kommt es bei der VM der Steuerungsebene zu Ausfallzeiten. Die Kubernetes API ist erst nach Abschluss des Upgrades wieder verfügbar.

In regionalen Clustern bleibt die Steuerungsebene während der Clusterwartung verfügbar, beispielsweise während der Änderung von IP-Adressen, der Aktualisierung von VMs der Steuerungsebene sowie der Anpassung von Cluster- oder Knotenpool-Größen. Beim Upgrade eines regionalen Clusters werden während des Rolling Upgrades immer zwei von drei VMs der Steuerungsebene ausgeführt, sodass die Kubernetes API weiterhin verfügbar ist. Auch ein Ausfall einer Zone verursacht keine Ausfallzeiten in der regionalen Steuerungsebene.

Bei den regional verfügbaren Clustern mit höherer Verfügbarkeit gibt es jedoch bestimmte Einschränkungen:

  • Änderungen an der Clusterkonfiguration dauern länger, da sie auf alle Steuerungsebenen in einem regionalen Cluster anstatt auf die einzelne Steuerungsebene in zonalen Clustern angewendet werden müssen.

  • Regionale Cluster können Sie möglicherweise nicht so oft wie zonale Cluster erstellen und upgraden. Wenn in einer der Zonen wegen fehlender Kapazität oder anderer vorübergehender Probleme keine VMs erstellt werden können, können auch keine Cluster erstellt oder aktualisiert werden.

Aufgrund dieser Kompromisse haben zonale und regionale Cluster unterschiedliche Anwendungsfälle:

  • Verwenden Sie zonale Cluster, um Cluster schnell zu erstellen oder zu aktualisieren, wenn die Verfügbarkeit weniger wichtig ist.
  • Verwenden Sie regionale Cluster, wenn Verfügbarkeit wichtiger ist als Flexibilität.

Wählen Sie beim Erstellen eines Clusters den Clustertyp sorgfältig aus, da er nach dem Erstellen des Clusters nicht mehr geändert werden kann. Stattdessen müssen Sie einen neuen Cluster erstellen und den Traffic dann dorthin migrieren. Die Migration des Produktionstraffics zwischen Clustern ist möglich, aber in größerem Umfang schwierig.

Knotenpools mit mehreren oder einzelnen Zonen auswählen

Sie können eine hohe Verfügbarkeit erreichen, indem Sie die Steuerungsebene von Kubernetes und ihre Knoten auf verschiedene Zonen verteilen. GKE bietet zwei Arten von Knotenpools: solche mit einzelnen oder mit mehreren Zonen.

Verteilen Sie Ihre Arbeitslast über mehrere Computing-Zonen in einer Region, um eine hochverfügbare Anwendung bereitzustellen. Verwenden Sie dazu multizonale Knotenpools, die Knoten gleichmäßig über Zonen verteilen.

Wenn sich alle Knoten in derselben Zone befinden und diese Zone nicht mehr erreichbar ist, können Sie keine Pods planen. Wenn Sie multizonale Knotenpools verwenden, sollten Sie folgendes beachten:

  • GPUs sind nur in bestimmten Zonen verfügbar. Es ist vielleicht nicht möglich, sie in allen Zonen der Region abzurufen.

  • Die Umlauflatenz zwischen Zonen innerhalb einer einzelnen Region kann höher sein als die von Ressourcen in einer einzelnen Zone. Die Differenz sollte für die meisten Arbeitslasten unwesentlich sein.

  • Den Preis für den ausgehenden Traffic zwischen Zonen in derselben Region können Sie der Preisseite für Compute Engine entnehmen.

Best Practices für Skalierung

Basisinfrastruktur

Kubernetes-Arbeitslasten erfordern ein Netzwerk, Computing-Ressourcen und Speicher. Sie müssen genügend CPU-Kapazität und Arbeitsspeicher bereitstellen, um Pods ausführen zu können. In der zugrunde liegenden Infrastruktur gibt es allerdings mehrere Parameter, welche die Leistung und Skalierbarkeit eines GKE-Clusters beeinflussen können.

Clusternetzwerk

Die Verwendung eines VPC-nativen Clusters ist die Standardeinstellung für Netzwerke und die empfohlene Option für die Einrichtung neuer GKE-Cluster. VPC-native Cluster ermöglichen größere Arbeitslasten, eine höhere Anzahl von Knoten und weitere Vorteile.

In diesem Modus hat das VPC-Netzwerk für alle Pod-IP-Adressen einen sekundären Bereich. Jedem Knoten wird dann für seine eigenen Pod-IP-Adressen ein Segment des sekundären Bereichs zugewiesen. So kann das VPC-Netzwerk nativ erkennen, wie Traffic an Pods weitergeleitet wird, ohne benutzerdefinierte Routen zu verwenden. Ein einzelnes VPC-Netzwerk kann bis zu 15.000 VMs haben.

Ein weiterer Ansatz, der verworfen wurde und nicht mehr als 1.500 Knoten unterstützt, besteht in der Verwendung eines routenbasierten Clusters. Ein routenbasierter Cluster eignet sich nicht für große Arbeitslasten. Das Kontingent der VPC-Routen wird verbraucht und es fehlen andere Vorteile des VPC-nativen Netzwerks. Dazu wird für jeden neuen Knoten eine neue benutzerdefinierte Route zur Routingtabelle im VPC-Netzwerk hinzugefügt.

Private Cluster

In regulären GKE-Clustern haben alle Knoten öffentliche IP-Adressen. In privaten Clustern haben Knoten nur interne IP-Adressen, um Knoten von eingehenden und ausgehenden Verbindungen zum Internet zu isolieren. GKE verwendet VPC-Netzwerk-Peering, um VMs, auf denen der Kubernetes-API-Server ausgeführt wird, mit dem Rest des Clusters zu verbinden. Dies ermöglicht einen höheren Durchsatz zwischen GKE-Steuerungsebenen und Knoten, da der Traffic über private IP-Adressen weitergeleitet wird.

Die Verwendung privater Cluster bietet den zusätzlichen Sicherheitsvorteil, dass die Knoten nicht mit dem Internet verbunden sind.

Cluster-Load-Balancing

GKE-Ingress und Cloud Load Balancing konfigurieren Load-Balancer und stellen diese bereit, um Kubernetes-Arbeitslasten außerhalb des Clusters und auch im öffentlichen Internet verfügbar zu machen. Die GKE Ingress- und Dienst-Controller stellen im Auftrag von GKE-Arbeitslasten Objekte wie Weiterleitungsregeln, URL-Zuordnungen, Backend-Dienste, Netzwerkendpunktgruppen und vieles mehr bereit. Jede dieser Ressourcen hat von vornherein spezifische Kontingente und Limits, die auch in GKE gelten. Wenn eine der Cloud Load Balancing-Ressourcen ihr Kontingent erreicht hat, verhindert sie, dass ein bestimmtes Ingress oder ein bestimmter Dienst korrekt bereitgestellt werden, und in den Ereignissen der Ressource werden Fehler angezeigt.

In der folgenden Tabelle werden die Skalierungslimits bei Verwendung von GKE Ingress und Services beschrieben:

Load-Balancer Knotenlimit pro Cluster
Interner Passthrough-Network-Load-Balancer
Externer Passthrough-Network-Load-Balancer 1000 Knoten pro Zone
Externer Application Load Balancer
Interner Application Load Balancer Kein Knotenlimit

Wenn Sie eine höhere Skalierung benötigen, wenden Sie sich an Ihr Google Cloud-Vertriebsteam, um dieses Limit zu erhöhen.

DNS

Service Discovery in GKE erfolgt über kube-dns, eine zentralisierte Ressource, um die DNS-Auflösung für Pods bereitzustellen, die im Cluster ausgeführt werden. Daraus kann sich bei sehr großen Clustern oder bei Arbeitslasten mit hoher Anfragelast ein Engpass ergeben. GKE skaliert kube-dns auf Basis der Größe des Clusters automatisch, um dessen Kapazität zu erhöhen. Wenn sie immer noch nicht ausreicht, bietet GKE mit NodeLocal DNSCache die verteilte, lokale Auflösung von DNS-Abfragen auf jedem Knoten an. Dadurch wird auf jedem GKE-Knoten ein lokaler DNS-Cache bereitgestellt, der Abfragen lokal beantwortet, wodurch die Last verteilt wird und sich die Antwortzeiten verkürzen.

IP-Adressen in VPC-nativen Clustern verwalten

Ein VPC-nativer Cluster verwendet drei IP-Adressbereiche:

  • Primärer Bereich für Knoten-Subnetz: Die Standardeinstellung ist /20 (4.092 IP-Adressen).
  • Sekundärer Bereich für Pod-Subnetz: Die Standardeinstellung ist /14 (262.144 IP-Adressen). Sie können das Pod-Subnetz jedoch konfigurieren.
  • Sekundärer Bereich für Dienstsubnetz: Der Standardwert ist /20 (4.096 Adressen). Sie können diesen Bereich jedoch nach dem Erstellen dieses Dienstsubnetzes nicht mehr ändern.

Weitere Informationen finden Sie unter IP-Adressbereiche für VPC-native Cluster.

Einschränkungen und Empfehlungen für IP-Adressen:

  • Knotenlimit: Das Knotenlimit wird durch die primäre und die Pod-IP-Adresse pro Knoten bestimmt. Sowohl die Knoten- als auch die Pod-IP-Adressbereiche müssen genügend Adressen haben, um einen neuen Knoten bereitzustellen. Standardmäßig können Sie aufgrund von Einschränkungen bei Pod-IP-Adressen nur 1.024 Knoten erstellen.
  • Pod-Limit pro Knoten: Standardmäßig beträgt das Pod-Limit pro Knoten 110 Pods. Sie können jedoch kleinere Pod-CIDRs konfigurieren, um die Verwendung mit weniger Pods pro Knoten effizient zu gestalten.
  • Skalierung über RFC 1918: Wenn Sie mehr IP-Adressen benötigen, als im privaten Bereich gemäß RFC 1918 verfügbar sind, empfehlen wir die Verwendung von privatem Nicht-RFC 1918 Adressen oder PUPIs für zusätzliche Flexibilität.
  • Sekundärer IP-Adressbereich für Service und Pod: Standardmäßig können Sie 4.096-Dienste konfigurieren. Sie können jedoch weitere Dienste konfigurieren, indem Sie den Dienstsubnetzbereich auswählen. Sie können sekundäre Bereiche nach der Erstellung nicht mehr ändern. Achten Sie beim Erstellen eines Clusters darauf, dass die ausgewählten Bereiche groß genug für das erwartete Wachstum sind. Sie können jedoch später mit nicht zusammenhängendem Multi-Pod-CIDR weitere IP-Adressen für Pods hinzufügen. Weitere Informationen finden Sie unter Nicht genügend freier IP-Adressbereich für Pods.

Weitere Informationen finden Sie unter Knotenbegrenzungsbereiche und IP-Adressen bei der Migration zu GKE planen.

Knoten für bessere Leistung konfigurieren

GKE-Knoten sind reguläre virtuelle Google Cloud-Maschinen. Einige ihrer Parameter, z. B. die Anzahl der Kerne oder die Größe des Laufwerks, können die Leistung von GKE-Clustern beeinflussen.

Pod-Initialisierungszeiten reduzieren

Mit Image-Streaming können Sie Daten aus zulässigen Container-Images streamen, wenn Ihre Arbeitslasten diese anfordern. Dies führt zu schnelleren Initialisierungszeiten.

Ausgehender Traffic

In Google Cloud bestimmen der Maschinentyp und die Anzahl der Kerne der Instanz die Netzwerkkapazität. Die maximale Bandbreite für ausgehenden Traffic variiert zwischen 1 und 32 Gbit/s. Für e2-medium-2-Standardmaschinen beträgt die maximale Bandbreite für ausgehenden Traffic 2 Gbit/s beträgt. Weitere Informationen zu Bandbreitenbeschränkungen finden Sie unter Maschinentypen mit gemeinsam genutztem Kern.

IOPS und Laufwerkdurchsatz

In der Google Cloud bestimmt die Größe der nichtflüchtigen Speicher die IOPS und den Durchsatz des Laufwerks. GKE verwendet in der Regel nichtflüchtigen Speicher von Persistent Disk als Bootlaufwerk und zum Unterstützen der nichtflüchtigen Kubernetes-Volumes. Durch die Erhöhung der Laufwerkgröße werden sowohl die IOPS als auch der Durchsatz bis zu bestimmten Limits erhöht.

Jeder Schreibvorgang eines nichtflüchtigen Speichers trägt zur kumulativen Obergrenze für den ausgehenden Netzwerktraffic einer VM-Instanz bei. Daher hängt die IOPS-Leistung von Laufwerken (insbesondere SSDs) neben der Laufwerkgröße auch von der Anzahl der vCPUs in der Instanz ab. VMs mit weniger Kernen haben aufgrund von Einschränkungen für ausgehenden Netzwerktraffic beim Schreibdurchsatz niedrigere Schreib-IOPS-Limits.

Wenn Ihre VM-Instanz nicht über ausreichend CPUs verfügt, erreicht Ihre Anwendung das IOPS-Limit nicht. In der Regel sollte pro 2.000–2.500 IOPS des erwarteten Traffics eine CPU verfügbar sein.

Für Arbeitslasten, die eine hohe Kapazität oder eine große Anzahl von Laufwerken erfordern, müssen die Limits für die Anzahl der PDs berücksichtigt werden, die einer einzelnen VM zugeordnet werden können. Für reguläre VMs liegt das Limit bei 128 Laufwerken mit einer Gesamtgröße von 64 TB, während für VMs mit gemeinsam genutztem Kern ein Limit von 16 PDs mit einer Gesamtgröße von 3 TB gilt. Dieses Limit wird von Google Cloud erzwungen, nicht von Kubernetes.

Messwerte der Steuerungsebene überwachen

Verwenden Sie die verfügbaren Messwerte der Steuerungsebene, um Ihre Monitoring-Dashboards zu konfigurieren. Mit Messwerten der Steuerungsebene können Sie den Zustand des Clusters beobachten, die Ergebnisse von Änderungen der Clusterkonfiguration beobachten (z. B. Bereitstellung von zusätzlichen Arbeitslasten oder Komponenten von Drittanbietern) oder Probleme beheben.

Einer der wichtigsten zu überwachenden Messwerte ist die Latenz der Kubernetes API. Wenn die Latenz zunimmt, bedeutet dies, dass das System überlastet ist. Beachten Sie, dass LIST-Aufrufe, die große Datenmengen übertragen, erwartungsgemäß eine viel höhere Latenz als kleinere Anfragen haben.

Eine erhöhte Kubernetes API-Latenz kann auch durch die langsame Reaktionsfähigkeit von Zulassungs-Webhooks von Drittanbietern verursacht werden. Mit Messwerten können Sie die Latenz von Webhooks messen, um solche häufig auftretenden Probleme zu erkennen.

Best Practices für Kubernetes-Entwickler

Auflistungs- und Beobachtungsmuster anstelle von regelmäßigen Auflistungen verwenden

Als Kubernetes-Entwickler müssen Sie möglicherweise eine Komponentem mit den folgenden Anforderungen erstellen:

  • Die Komponente muss regelmäßig eine Liste einiger Kubernetes-Objekte abrufen.
  • Ihre Komponente muss in mehreren Instanzen ausgeführt werden (im Fall von DaemonSet sogar auf jedem Knoten).

Eine solche Komponente kann Lastspitzen auf dem kube-apiserver generieren, selbst wenn sich der Zustand der regelmäßig abgerufenen Objekte nicht ändert.

Die einfachste Methode ist die Verwendung regelmäßiger LIST-Aufrufe. Dies ist jedoch ineffizient und teuer für den Aufrufer und den Server, da alle Objekte jedes Mal in den Arbeitsspeicher geladen, serialisiert und übertragen werden müssen. Eine übermäßige Verwendung von LIST-Anfragen kann die Steuerungsebene überlasten oder eine starke Drosselung solcher Anfragen verursachen.

Sie können Ihre Komponente verbessern, indem Sie für LIST-Aufrufe den Parameter resourceVersion=0 festlegen. Dadurch kann kube-apiserver den In-Memory-Objektcache verwenden und die Anzahl der internen Interaktionen zwischen kube-apiserver und der etcd-Datenbank sowie die zugehörige Verarbeitung reduzieren.

Wir empfehlen dringend, wiederholbare LIST-Aufrufe zu vermeiden und durch das Listen- und Überwachungsmuster zu ersetzen. Listen Sie die Objekte einmal auf und verwenden Sie dann die Watch API, um inkrementelle Änderungen des Zustands abzurufen. Dieser Ansatz reduziert die Verarbeitungszeit und minimiert den Traffic im Vergleich zu regelmäßigen LIST-Aufrufen. Wenn sich Objekte nicht ändern, wird keine zusätzliche Last generiert.

Wenn Sie die Go-Sprache verwenden, suchen Sie nach SharedInformer und SharedInformerFactory für Go-Pakete, die dieses Muster implementieren.

Unnötigen Traffic beschränken, der durch Beobachtungen und Listen generiert wird

Kubernetes verwendet Beobachtungen, um Benachrichtigungen zu Objektaktualisierungen zu senden. Selbst wenn Beobachtungen viel weniger Ressourcen benötigen als regelmäßige LIST-Aufrufe, kann die Verarbeitung von Beobachtungen in großen Clustern einen erheblichen Teil der Clusterressourcen beanspruchen und die Clusterleistung beeinträchtigen. Die größte negative Auswirkung werden durch die Erstellung von Beobachtungen erzeugt, die sich häufig ändernde Objekte von mehreren Orten aus beobachten. Beispielsweise können Sie Daten zu allen Pods von einer Komponente aus beobachten, die auf allen Knoten ausgeführt wird. Wenn Sie Drittanbietercode oder -erweiterungen in Ihrem Cluster installieren, können sie derartige Beobachtungen im Hintergrund erstellen.

Wir empfehlen folgende Best Practices:

  • Reduzieren Sie unnötige Verarbeitung und unnötigen Traffic, der von Beobachtungen und LIST-Aufrufen generiert wird.
  • Erstellen Sie keine Beobachtungen, die sich häufig ändernde Objekte von mehreren Orten aus beobachten (z. B. DaemonSets).
  • (Sehr empfohlen) Erstellen Sie einen zentralen Controller, der die erforderlichen Daten auf einem einzelnen Knoten beobachtet und verarbeitet.
  • Beobachten Sie nur eine Teilmenge der Objekte, z. B. kubelet auf jedem Knoten, und beobachten Sie nur Pods, die auf demselben Knoten geplant sind.
  • Vermeiden Sie die Bereitstellung von Komponenten oder Erweiterungen von Drittanbietern, die sich auf die Clusterleistung auswirken können, indem sie viele Beobachtungen oder LIST-Aufrufe ausführen.

Größe des Kubernetes-Objektmanifests beschränken

Wenn Sie schnelle Vorgänge benötigen, die einen hohen Pod-Durchsatz erfordern, z. B. die Größenanpassung oder Aktualisierung großer Arbeitslasten, sollten Sie die Pod-Manifestgrößen auf ein Minimum beschränken, idealerweise unter 10 KiB.

Kubernetes speichert Ressourcenmanifeste in etcd. Das gesamte Manifest wird jedes Mal gesendet, wenn die Ressource abgerufen wird, einschließlich wenn Sie das Listen- und Überwachungsmuster verwenden.

Für die Manifestgröße gelten die folgenden Einschränkungen:

  • Maximale Größe für jedes Objekt in etcd: Etwa 1,5 MiB.
  • Gesamtkontingent für alle etcd-Objekte im Cluster: Die vorkonfigurierte Kontingentgröße beträgt 6 GiB. Dies schließt ein Änderungslog mit allen Aktualisierungen für alle Objekte in den letzten 150 Sekunden des Clusterverlaufs ein.
  • Leistung der Steuerungsebene während Zeiten mit hohem Traffic: Höhere Manifestgrößen erhöhen die Last auf dem API-Server.

Bei einzelnen, selten verarbeiteten Objekten ist die Manifestgröße in der Regel kein Problem, solange sie unter 1,5 MiB liegt. Manifestgrößen über 10 KiB für zahlreiche, häufig verarbeitete Objekte – wie Pods bei sehr großen Arbeitslasten – können jedoch die API-Aufruflatenz erhöhen und die Gesamtleistung beeinträchtigen. Insbesondere große Listen und Überwachungen können von großen Manifestgrößen stark betroffen sein. Außerdem kann es zu Problemen mit dem etcd-Kontingent kommen, da sich die Menge der Überarbeitungen in den letzten 150 Sekunden in Zeiten mit hohem API-Server-Traffic schnell ansammeln kann.

Zur Reduzierung der Manifestgröße eines Pods können Kubernetes-ConfigMaps verwendet werden, um einen Teil der Konfiguration zu speichern, insbesondere den Teil, der von mehreren Pods im Cluster gemeinsam genutzt wird. Zum Beispiel werden Umgebungsvariablen häufig von allen Pods in einer Arbeitslast gemeinsam genutzt.

Beachten Sie, dass es auch möglich ist, dass ähnliche Probleme bei ConfigMap-Objekten auftreten, wenn sie so zahlreich und so groß wie die Pods sind und ebenso häufig verarbeitet werden. Das Extrahieren eines Teils der Konfiguration ist besonders nützlich, wenn dadurch der Gesamt-Traffic verringert wird.

Automatische Bereitstellung des Standarddienstkontos deaktivieren

Wenn eine in Ihren Pods ausgeführte Logik nicht auf die Kubernetes API zugreifen muss, sollten Sie die standardmäßige automatische Bereitstellung von Dienstkonten deaktivieren, um die Erstellung zugehöriger Secrets und Beobachtungen zu vermeiden.

Wenn Sie einen Pod erstellen, ohne ein Dienstkonto anzugeben, führt Kubernetes automatisch die folgenden Aktionen aus:

  • Weist dem Pod das Standarddienstkonto zu.
  • Stellt die Anmeldedaten des Dienstkontos als Secret für den Pod bereit.
  • Für jedes bereitgestellte Secret erstellt das kubelet eine Beobachtung, um Änderungen an diesem Secret auf jedem Knoten zu verfolgen.

In großen Clustern sorgen diese Aktionen für Tausende unnötige Beobachtungen, was den kube-apiserver erheblich belasten kann.

Protokollzwischenspeicher anstelle von JSON für API-Anfragen verwenden

Verwenden Sie Protokollzwischenspeicher, wenn Sie hoch skalierbare Komponenten implementieren, wie unter Kubernetes API-Konzepte beschrieben.

Die Kubernetes REST API unterstützt JSON und Protokollzwischenspeicher als Serialisierungsformat für Objekte. JSON wird standardmäßig verwendet, aber Protokollzwischenspeicher sind bei der Verarbeitung in großem Maßstab effizienter, da dies eine weniger CPU-intensive Verarbeitung erfordert und weniger Daten über das Netzwerk sendet. Der Aufwand bei der Verarbeitung von JSON kann bei der Auflistung von großen Datenmengen zu Zeitüberschreitungen führen.

Nächste Schritte