Kapitel 4. Hinzufügen von Workloads zum Mesh
Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com
Linkerd in deinem Cluster zum Laufen zu bringen, ist ein guter erster Schritt. Aber es ist sinnlos, Linkerd mit nichts anderem laufen zu lassen: Um den tatsächlichen Wert deines Linkerd-Clusters zu nutzen, musst du Workloads in deinem Service Mesh zum Laufen bringen. In diesem Kapitel zeigen wir dir, wie du genau das tun kannst.
Arbeitsbelastungen versus Dienstleistungen
Wir werden in diesem Kapitel oft von "Workloads" sprechen, aber manchmal auch von "Services" und manchmal von "Diensten". Leider haben diese drei Begriffe alle etwas unterschiedliche Bedeutungen:
- Service
-
Eine Kubernetes-Ressource, die häufig verwendet wird, um zu steuern, wie Kubernetes DNS-Namen und IP-Adressen für Dienste zuweist (siehe Abbildung 4-1).
- Arbeitsbelastung
-
Eine Sache, die tatsächlich in deinem Namen arbeitet. Ein Workload empfängt Anfragen über das Netzwerk und führt Code aus, um Aktionen auszuführen. In Kubernetes handelt es sich in der Regel um einen oder mehrere Pods (die die Berechnungen durchführen), die oft von einer Deployment- oder DaemonSet-Ressource verwaltet werden, sowie um einen oder mehrere Services (die die Namen und IP-Adressen verwalten), wie in Abbildung 4-1 dargestellt.
- Service
-
Ein weniger formaler Begriff, der sich je nach Kontext entweder auf einen Service oder einen Workload beziehen kann. Diese Ungenauigkeit ist nur einer von vielen Fällen, in denen die Kubernetes-Terminologie viel verwirrender ist, als wir es gerne hätten.
Als Anwendungsentwickler kannst du in der Regel einfach "Dienst" sagen und darauf vertrauen, dass die Leute mit dieser Zweideutigkeit einverstanden sind. Leider müssen wir oft präziser sein, wenn wir über Dienstnetze sprechen - deshalb sprechen wir hier von Workloads und nicht von Diensten.
Was bedeutet es, einen Workload zum Mesh hinzuzufügen?
"Einen Workload zum Mesh hinzufügen" bedeutet eigentlich "den Linkerd-Sidecar zu jedem Pod deines Workloads hinzufügen", wie in Abbildung 4-2 gezeigt.
Letztendlich bedeutet das, dass du die Definition des Pods ändern musst, um den Sidecar-Container einzubinden. Du könntest dazu zwar die YAML-Definition des Pods manuell bearbeiten, aber es ist viel einfacher und sicherer, Linkerd die Arbeit machen zu lassen.
Linkerd beinhaltet einen Kubernetes admission controller, genanntlinkerd-proxy-injector
. Seine Aufgabe ist es, Linkerd-Proxys in die Pods der Workloads zu injizieren. Natürlich macht er das nicht blind, sondern sucht nach Kubernetes-Annotationen, die ihm sagen, welche Pods injiziert werden müssen (siehe Abbildung 4-3).
Injektion einzelner Workloads
Die gängigste Methode für Injektion besteht darin, die Annotation linkerd.io/inject:
enabled
direkt in den Pod selbst einzufügen, in der Regel durch Hinzufügen der Annotation zur Pod-Vorlage in einem Deployment, DaemonSet usw. Wennlinkerd-proxy-injector
einen neuen Pod mit dieser Annotation sieht, injiziert es das Proxy-Sidecar für dich in den Pod.
Es ist wichtig, darauf hinzuweisen, dass der Wert der Anmerkung wichtig ist:enabled
bedeutet, dass eine normale Sidecar Injection durchgeführt wird. Andere Werte werden wir uns in Kürze ansehen.
Alle Pods sind gleichwertig
Es spielt keine Rolle, welche Ressource zur Erstellung des Pods verwendet wird. Bereitstellungsressourcen, DaemonSets, handgefertigte ReplicaSets, Argo-Rollouts - sie alle erstellen ihre Pods auf genau dieselbe Weise. Der Linkerd-Injektor merkt nur, dass ein neuer Pod existiert, nicht aber, warum er erstellt wurde.
Alle Workloads in einen Namensraum injizieren
Du kannst die Annotation linkerd.io/inject
zu einem Namespace und nicht zu einem Pod hinzufügen. Wenn du das getan hast, wird jeder neue Pod, der in diesem Namensraum erstellt wird, injiziert (und auch hier spielt es keine Rolle, warum der neue Pod erstellt wird).
Das kann sehr nützlich sein, wenn die Automatisierung Pods erstellt, es aber schwierig oder fehleranfällig ist, die Annotationen der Pods selbst zu ändern. Einige Ingress-Controller erstellen zum Beispiel jedes Mal, wenn du eine Ressource änderst, neue Deployments. Anstatt die vom Ingress-Controller verwendete Pod-Vorlage mühsam zu ändern (falls das überhaupt möglich ist), kannst du einfach den Namensraum annotieren, in dem die Deployments erstellt werden sollen.
linkerd.io/inject Werte
Der Wert der Anmerkung linkerd.io/inject
spielt eine Rolle - es geht nicht nur darum, einen nicht leeren String zu haben. Es gibt drei bestimmte Werte, die von Bedeutung sind:
linkerd.io/inject: enabled
-
Der häufigste Fall:
linkerd-proxy-injector
fügt dem Pod einen Proxy-Container hinzu und weist den Proxy an, in seinem "normalen" Modus zu laufen. linkerd.io/inject: ingress
-
linkerd-proxy-injector
fügt dem Pod einen Proxy-Container hinzu, der jedoch im "Ingress"-Modus läuft (den wir in Kapitel 5 besprechen werden). linkerd.io/inject: disabled
-
Damit wird
linkerd-proxy-injector
explizit angewiesen, das Proxy-Sidecarnicht hinzuzufügen, auch wenn es eine Namespace-Annotation gibt, die andernfalls besagen würde, dass das Sidecar hinzugefügt werden soll.
Auf den Ingress-Modus gehen wir in Kapitel 5 näher ein: Er ist ein Workaround für Ingress-Controller, die nur Anfragen direkt an Workload-Endpunkte weiterleiten können. In den meisten Fällen solltest du linkerd.io/inject: enabled
verwenden, um den "normalen" Modus zu erhalten.
Warum solltest du dich entscheiden, einen Workload nichtzum Mesh hinzuzufügen?
-
Du willst immer deine Anwendungs-Workloads zum Netz hinzufügen.
-
Du willst niemals eine Cluster-Infrastruktur zum Netz hinzufügen.
So werden z.B. Dinge, die im kube-system
Namensraum stehen, niemals injiziert. Alle diese Pods sind so konzipiert, dass sie sich selbst schützen, egal was sonst noch passiert, und einige von ihnen müssen sicher sein, dass sich nichts zwischen ihnen und der Netzwerkschicht befindet, deshalb solltest du sie nicht injizieren.
Ebenso sollte ein Webhook für die Kubernetes-Konvertierung (wie im application-code
Namensraum in Abbildung 4-3 gezeigt) nicht im Mesh enthalten sein. Der Webhook-Mechanismus selbst stellt bereits besondere Anforderungen an TLS, und das Mesh wird dabei nicht helfen. (Ein weiteres gutes Beispiel sind CNI-Implementierungen: Sie benötigen direkten Zugriff auf die Netzwerkschicht und sollten daher nicht eingefügt werden.
Andererseits sollten die Workloads, die Teil deiner Anwendung sind, die im Cluster läuft, immer in das Mesh injiziert werden. Alle diese Richtlinien sind in Abbildung 4-4 dargestellt.
Andere Proxy-Konfigurationsoptionen
Obwohl die grundlegende linkerd.io/inject
Annotation die einzige Proxy-Konfigurationsoption ist, die du angeben musst, gibt es noch eine ganze Reihe anderer Dinge, die du für den Proxy konfigurieren kannst. Die vollständige Liste findest du in derLinkerd Proxy Configuration Dokumentation, aber zwei Bereiche, über die du dich von Anfang an informieren solltest, sind die Protokollerkennung und dieRessourcenbeschränkungen von Kubernetes.
Protokoll-Erkennung
Wie wir in Kapitel 1 besprochen haben, legt Linkerd großen Wert auf eine einfache Bedienung; wann immer es möglich ist, versucht Linkerd sicherzustellen, dass die Dinge einfach funktionieren, wenn du deine Anwendung ins Netz bringst. Die Protokollerkennung ist dabei ein wichtiger Bestandteil, denn Linkerd muss das Protokoll kennen, das über eine Verbindung verwendet wird, um die Verbindung korrekt zu verwalten, wie in Abbildung 4-5 gezeigt.
Es gibt mehrere Gründe, warum Linkerd (oder jedes andere Netz) das Protokoll kennen muss, das über die Leitung verwendet wird. Wir gehen hier nur auf ein paar davon ein:
- Beobachtbarkeit
-
Linkerd kann keine richtigen Messwerte liefern, ohne den Fluss des Protokolls zu verstehen. Die Identifizierung von Anfang und Ende einer Anfrage ist entscheidend für die Messung der Anfragerate und der Latenzzeit. Das Lesen des Status einer Anfrage ist entscheidend für die Messung der Erfolgsrate.
- Verlässlichkeit
-
Jede Zuverlässigkeitsfunktion, die über die grundlegendste hinausgeht, erfordert die Kenntnis des Protokolls im Flug. Nehmen wir zum Beispiel den Lastausgleich: Wenn Linkerd das Protokoll nicht kennt, kann er nur einen verbindungsbasierten Lastausgleich durchführen, bei dem eine eingehende TCP-Verbindung einem bestimmten Workload Pod zugewiesen wird.
Der verbindungsbasierte Lastausgleich funktioniert jedoch nicht sehr gut bei Protokollen wie HTTP/2 und gRPC. Bei diesen Protokollen kann eine einzige langlebige Verbindung viele Anfragen befördern, wobei mehrere Anfragen gleichzeitig aktiv sind. Linkerd kann die Zuverlässigkeit und Leistung drastisch verbessern, indem es einzelne Anfragen den Pods zuweist, anstatt eine ganze Verbindung an einen Pod zu binden. (Ein lustiger Linkerd-Faktor ist, dass er dies automatisch und ohne Konfiguration tut; installiere Linkerd einfach und du bekommst es kostenlos).
- Sicherheit
-
Wenn ein Workload eine TLS-Verbindung zu einem anderen Workload herstellt, sollte Linkerd nicht versuchen, sie neu zu verschlüsseln. Er sollte auch nicht versuchen, irgendetwas Ausgefallenes mit der Lastverteilung zu machen, da er nichts innerhalb der Verbindung sehen kann. (Das bedeutet, dass du die besten Ergebnisse mit Linkerd erzielst, wenn deine Workloads bei der Verbindung untereinander kein TLS verwenden: Lass Linkerd mTLS für dich machen!)
Wenn die Protokollerfassung schief läuft
Die automatische Protokollerkennung hat eine große Einschränkung: Sie funktioniert nur bei Protokollen, bei denen derjenige, der die Verbindung herstellt, auch der erste ist, der Daten sendet(Client-Speaks-First-Protokolle ). Sie schlägt bei Protokollen fehl, bei denen der Empfänger der Verbindung der erste ist, der Daten sendet(Server-Speaks-First-Protokolle ).
Der Grund für diese Einschränkung ist, dass Linkerd, solange er das Protokoll nicht kennt, keine vernünftigen Entscheidungen darüber treffen kann, wie er die Lastverteilung vornimmt, also kann er nicht entscheiden, mit welchem Server er sich verbinden soll. Jeder Proxy hat dieses frustrierende, zirkuläre Problem.
In der Welt der Cloud Natives sind viele - vielleicht sogar die meisten - der gängigen Protokolle glücklicherweise Client-Speaks-First-Protokolle, z.B. HTTP, gRPC und TLS selbst. Leider gibt es auch einige wichtige Server-Speaks-First-Protokolle: SMTP, MySQL und Redis sind alles Beispiele dafür.
Wenn Linkerd das Protokoll nicht erkennen kann, geht er davon aus, dass es sich um eine reine TCP-Verbindung handelt, weil das der kleinste gemeinsame Nenner ist, der immer funktioniert. Das Problem ist, dass Linkerd bei server-speaks-first-Protokollen 10 Sekunden wartet, bevor er annimmt, dass er das Protokoll nicht erkennen kann, und diese 10-Sekunden-Verzögerung ist natürlich nicht das, was du willst. Um das zu verhindern, musst du Linkerd sagen, dass er die Verbindung entweder ganz überspringen oder als undurchsichtig behandeln soll.
Opake Ports versus Skip Ports
Wenn du Linkerd sagst, dass es eine Verbindung überspringen soll, heißt das, dass es mit dieser Verbindung absolut nichts zu tun haben soll. Tatsächlich berühren die Linkerd-Proxys die Verbindung überhaupt nicht: Die Pakete fließen direkt von Workload zu Workload.
Das bedeutet, dass Linkerd kein mTLS, keinen Lastausgleich, keine Metriksammlung oderähnliches durchführen kann. Die Verbindung findet praktisch komplett außerhalb des Netzes statt.
Eine undurchsichtige Verbindung hingegen geht durch die Linkerd-Proxys, was bedeutet, dass sie über mTLS übertragen wird. Sie ist immer noch verschlüsselt und Linkerd setzt alle konfigurierten Richtlinien durch, aber du erhältst nur Metriken pro Verbindung und Lastausgleich (weil Linkerd weiß, dass es nicht in den Stream sehen kann, um einzelne Anfragen zu betrachten).
Diese Unterscheidung ist in Abbildung 4-6 dargestellt.
Wenn du brauchst, um Server-Speaks-First-Protokolle zu verwenden, ist es also besser, sie als undurchsichtig zu markieren, als sie ganz zu überspringen. Das Überspringen sollte nur notwendig sein, wenn das Ziel des Datenverkehrs nicht Teil deines Netzes ist. Da undurchsichtige Verbindungen immer noch auf einen Linkerd-Proxy angewiesen sind, um mTLS auszuführen, können sie nicht funktionieren, wenn es keinen Proxy gibt, der die Verbindung empfängt!
Konfigurieren der Protokoll-Erkennung
Es gibt zwei Möglichkeiten, Linkerd über Protokolle zu informieren. Du kannst eine Server-Ressource verwenden, die wir in Kapitel 8 behandeln werden, wenn wir über Richtlinien sprechen, oder du kannst die folgenden Anmerkungen verwenden, um bestimmte Ports als undurchsichtig oder übersprungen zu markieren:
config.linkerd.io/opaque-ports
-
Verbindungen zu oder von diesen Ports werden immer als undurchsichtig behandelt.
config.linkerd.io/skip-inbound-ports
-
Verbindungen, die über diese Ports in den Workload gelangen, werden immer übersprungen.
config.linkerd.io/skip-outbound-ports
-
Verbindungen, die diese Arbeitslast an diesen Ports verlassen, werden immer übersprungen.
Alle diese Optionen akzeptieren kommagetrennte Listen von Portnummern oder Portbereichen, so dass alle der folgenden Optionen zulässig sind:
config.linkerd.io/opaque-ports: 25
-
Dadurch wird nur Port 25 als undurchsichtig behandelt.
config.linkerd.io/skip-inbound-ports: 3300,9900
-
Dadurch werden Verbindungen übersprungen, die über Port 3300 oder 9900 eingehen.
config.linkerd.io/skip-inbound-ports: 8000-9000
-
Damit werden Verbindungen übersprungen, die an einem Port zwischen 8000 und 9000 eingehen.
config.linkerd.io/skip-outbound-ports: 25,587,8000-9000
-
Damit werden Verbindungen übersprungen, die über Port 25, Port 587 oder einen Port zwischen 8000 und 9000 (einschließlich) ausgehen.
Es gibt auch die Option config.linkerd.io/skip-subnets
, die jede Verbindung zu oder von einem der aufgelisteten Subnetze überspringt. Ihr Argument ist eine durch Kommata getrennte Liste von CIDR-Bereichen (Classless Inter-Domain Routing), zum Beispiel config.linkerd.io/skip-subnets: 10.0.0.0/8,192.168.1.0/24
.
Standardmäßige undurchsichtige Ports
Ab Linkerd 2.12 sind mehrere Ports standardmäßig als undurchsichtig markiert (siehe die Liste in "Standardmäßige undurchsichtige Ports" für weitere Details).
Die Standard-Ports sind dafür gedacht, dass verschiedene Server-Speaks-First-Protokolle wie MySQL und SMTP nahtlos mit Linkerd zusammenarbeiten können. Wenn du diese Ports für Client-Speaks-First-Protokolle verwendest, musst du eine Server-Ressource verwenden, um den Standard-Port zu überschreiben (oder - noch besser - einfach einen anderen Port für dein Client-Speaks-First-Protokoll wählen!).
Kubernetes Ressourcenlimits
Im Vergleich zur Protokollerkennung sind Kubernetes-Ressourcenlimits viel unkomplizierter. Es gibt einen einfachen Satz von Anmerkungen, mit denen du Ressourcenanforderungen und Limits festlegen kannst (siehe Tabelle 4-1).
Anmerkung | Wirkung |
---|---|
|
Maximale Anzahl von CPU-Einheiten, die der Proxy-Sidecar verwenden kann |
|
Anzahl der CPU-Einheiten, die der Proxy-Sidecar anfordert |
|
Wird verwendet, um die |
|
Wird verwendet, um die |
|
Maximale Menge an Speicher, die der Proxy-Sidecar verwenden kann |
|
Die Menge an Speicher, die der Proxy-Sidecar anfordert |
Zusammenfassung
Da hast du es also: eine Anleitung, wie du deine Workloads zu einem effektiven Teil des Linkerd-Netzes machen kannst. Hoffentlich hast du jetzt ein gutes Verständnis dafür, wie alles funktioniert, und kennst die Stolpersteine auf dem Weg dorthin (z.B. Server-Speaks-First-Protokolle). Als Nächstes geht es darum, Linkerd und Ingress-Controller zusammenzubringen.
Get Linkerd: Auf und davon now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.