Likbez startet Istio


Isstio Service Mesh


Wir bei Namely verwenden Istio seit einem Jahr. Er ist dann einfach gegangen. Wir hatten einen großen Leistungsabfall im Kubernetes-Cluster, wir wollten verteiltes Tracing und nahmen Istio mit, um Jaeger auszuführen und es herauszufinden. Service Mesh passt so gut in unsere Infrastruktur, dass wir uns entschlossen haben, in dieses Tool zu investieren.


Ich musste leiden, aber wir haben es weit und breit studiert. Dies ist der erste Beitrag in einer Reihe, in der ich beschreiben werde, wie Istio sich in Kubernetes integriert und was wir über seine Arbeit gelernt haben. Manchmal wandern wir in die technische Wildnis, aber nicht sehr weit. Weiter wird es weitere Beiträge geben.


Was ist Istio?


Istio ist ein Service-Mesh-Konfigurationstool. Es liest den Status des Kubernetes-Clusters und aktualisiert die L7-Proxys (HTTP und gRPC), die als Sidecar in Kubernetes-Pods implementiert sind. Bei diesem Beiwagen handelt es sich um Envoy-Container, die die Konfiguration von der Istio Pilot-API (und dem gRPC-Dienst) lesen und den Verkehr durch diese leiten. Mit dem leistungsstarken L7-Proxy unter der Haube können wir Metriken, Traces, Wiederholungslogik, Leistungsschalter, Lastausgleich und kanarische Bereitstellungen verwenden.


Beginnen wir von vorne: Kubernetes


In Kubernetes erstellen wir unter Verwendung eines Deployments oder StatefulSets. Oder es kann einfach "Vanille" ohne einen High-Level-Controller sein. Dann bemüht sich Kubernetes, den gewünschten Status beizubehalten - es erstellt Pods im Cluster auf dem Knoten und stellt sicher, dass sie gestartet und neu gestartet werden. Wenn ein Under erstellt wird, durchläuft Kubernetes den API-Lebenszyklus, stellt sicher, dass jeder Schritt erfolgreich ist, und erstellt erst dann das Under im Cluster.


API-Lebenszyklusphasen:



Danke an Banzai Cloud für das coole Bild.


Einer der Schritte ist das Ändern von Zulassungs-Webhooks. Dies ist ein separater Teil des Lebenszyklus in Kubernetes, in dem Ressourcen angepasst werden, bevor sie in das etcd-Repository übertragen werden, die Quelle der Wahrheit für die Kubernetes-Konfiguration. Und hier macht Istio seine Magie.


Zulassungs-Webhooks ändern


Wenn ein Sub erstellt wird (über kubectl oder Deployment ), durchläuft es diesen Lebenszyklus, und durch Zugriff auf modifizierende Webhooks wird es geändert, bevor es für die große Welt freigegeben wird.


Während der Installation von Istio wird der Istio-Sidecar-Injektor als Konfigurationsressource zum Ändern von Webhooks hinzugefügt:


 $ kubectl get mutatingwebhookconfiguration NAME AGE istio-sidecar-injector 87d 

Und die Konfiguration:


 apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: labels: app: istio-sidecar-injector chart: sidecarInjectorWebhook-1.0.4 heritage: Tiller name: istio-sidecar-injector webhooks: - clientConfig: caBundle: redacted service: name: istio-sidecar-injector namespace: istio-system path: /inject failurePolicy: Fail name: sidecar-injector.istio.io namespaceSelector: matchLabels: istio-injection: enabled rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods 

Hier heißt es, dass Kubernetes alle istio-sidecar-injector an den istio-sidecar-injector istio-system im istio-system Namespace senden soll, wenn für den Namespace istio-injection=enabled . Der Injektor enthält zwei weitere Container in PodSpec: einen temporären zum Festlegen von Proxy-Regeln und einen zum Proxy selbst. Der Beiwageninjektor setzt diese Behälter gemäß der Vorlage aus der Konfigurationskarte des istio-sidecar-injector . Dieser Vorgang wird auch als Sidecaring bezeichnet.


Beiwagenkapseln


Beiwagen sind die Tricks unseres Magiers Istio. Istio dreht alles so geschickt, dass es von außen einfach magisch ist, wenn Sie die Details nicht kennen. Und es ist nützlich, sie zu kennen, wenn Sie plötzlich Netzwerkanforderungen debuggen müssen.


Init- und Proxy-Container


Kubernetes verfügt über temporäre einmalige Init-Container, die vor den Hauptcontainern ausgeführt werden können. Sie bündeln Ressourcen, migrieren Datenbanken oder konfigurieren, wie bei Istio, Netzwerkregeln.


Istio verwendet Envoy, um alle Anfragen an Einreichungen entlang der gewünschten Routen zu senden. Zu diesem Zweck erstellt Istio iptables Regeln, die eingehenden und ausgehenden Datenverkehr direkt an Envoy senden und den Datenverkehr sauber an sein Ziel weiterleiten. Der Datenverkehr macht einen kleinen Umweg, aber Sie haben die Ablaufverfolgung, Abfragemetriken und die Durchsetzung von Richtlinien verteilt. In dieser Datei können Sie im Istio-Repository sehen, wie Istio iptables-Regeln erstellt.


@jimmysongio hat ein hervorragendes Verbindungsdiagramm zwischen den iptables-Regeln und dem Envoy-Proxy erstellt:



Gesandter - Gesandterverkehr


Envoy empfängt den gesamten eingehenden und ausgehenden Verkehr, sodass sich der gesamte Verkehr im Allgemeinen innerhalb von Envoy bewegt, wie in der Abbildung dargestellt. Der Istio-Proxy ist ein weiterer Container, der allen vom Istio-Beiwageninjektor modifizierten Pods hinzugefügt wird. In diesem Container wird der Envoy-Prozess gestartet, der den gesamten Datenverkehr vom Herd empfängt (mit einigen Ausnahmen, z. B. Datenverkehr von Ihrem Kubernetes-Cluster).


Der Envoy-Prozess erkennt alle Routen über die Envoy v2-API, die Istio implementiert.


Gesandter und Pilot


Envoy selbst hat keine Logik zum Erkennen von Pods und Diensten in einem Cluster. Es ist eine Datenebene und benötigt eine Steuerebene zur Führung. Der Envoy-Konfigurationsparameter fordert den Host oder Service-Port auf, diese Konfiguration über die gRPC-API zu erhalten. Istio erfüllt über seinen Pilotdienst die Anforderungen für die gRPC-API. Envoy stellt eine Verbindung zu dieser API her, basierend auf einer Sidecar-Konfiguration, die über einen modifizierenden Webhook implementiert wird. Die API verfügt über alle Verkehrsregeln, die Envoy zum Erkennen und Weiterleiten für den Cluster benötigt. Dies ist das Service-Mesh.



Datenaustausch "unter dem <-> Piloten"


Pilot stellt eine Verbindung zum Kubernetes-Cluster her, liest den Clusterstatus und wartet auf Aktualisierungen. Es überwacht die Pods, Dienste und Endpunkte im Kubernetes-Cluster, um dann allen mit dem Piloten verbundenen Envoy-Beiwagen die richtige Konfiguration zu geben. Dies ist die Brücke zwischen Kubernetes und Envoy.



Vom Piloten zum Kubernetes


Wenn Pods, Dienste oder Endpunkte in Kubernetes erstellt oder aktualisiert werden, erfährt Pilot davon und sendet die erforderliche Konfiguration an alle verbundenen Envoy-Instanzen.


Welche Konfiguration wird gesendet?


Welche Konfiguration erhält der Gesandte vom Istio-Piloten?


Standardmäßig löst Kubernetes Ihre Netzwerkprobleme mit einem Dienst, der endpoint verwaltet. Die Liste der Endpunkte kann mit dem folgenden Befehl geöffnet werden:


 kubectl get endpoints 

Dies ist eine Liste aller IP-Adressen und Ports im Cluster und ihrer Adressen (normalerweise sind dies Pods, die aus einer Bereitstellung erstellt wurden). Istio ist wichtig zu wissen, um Routendaten zu konfigurieren und an Envoy zu senden.


Dienste, Listener und Routen


Wenn Sie einen Dienst in einem Kubernetes-Cluster erstellen, fügen Sie Verknüpfungen hinzu, mit denen alle geeigneten Pods ausgewählt werden. Wenn Sie Datenverkehr an die IP des Dienstes senden, wählt Kubernetes den Datenverkehr für diesen Datenverkehr aus. Zum Beispiel der Befehl


 curl my-service.default.svc.cluster.local:3000 

Zunächst wird die dem my-service zugewiesene virtuelle IP im default Namespace gefunden, und diese IP leitet den Datenverkehr an ein Sub weiter, das der Dienstbezeichnung entspricht.


Istio und Envoy ändern diese Logik leicht. Istio konfiguriert Envoy basierend auf den Diensten und Endpunkten im Kubernetes-Cluster und verwendet die intelligenten Routing- und Lastausgleichsfunktionen von Envoy, um den Kubernetes-Dienst zu umgehen. Anstatt jeweils nur eine IP zu übertragen, stellt Envoy eine direkte Verbindung zum IP-Herd her. Zu diesem Zweck ordnet Istio die Kubernetes-Konfiguration der Envoy-Konfiguration zu .


Die Begriffe Kubernetes, Istio und Envoy unterscheiden sich geringfügig, und es ist nicht sofort klar, was sie essen.


Dienstleistungen


Ein Dienst in Kubernetes wird einem Cluster in Envoy zugeordnet. Der Envoy-Cluster enthält eine Liste von Endpunkten , dh die IP (oder Hostnamen) der Instanzen für die Verarbeitung von Anforderungen. Führen Sie istioctl proxy-config cluster < > um die Liste der im Istio Sidecar-Pod konfigurierten Cluster anzuzeigen. Dieser Befehl zeigt den aktuellen Stand der Dinge in Bezug auf den Herd. Hier ist ein Beispiel aus einer unserer Umgebungen:


 $ istioctl proxy-config cluster taxparams-6777cf899c-wwhr7 -n applications SERVICE FQDN PORT SUBSET DIRECTION TYPE BlackHoleCluster - - - STATIC accounts-grpc-gw.applications.svc.cluster.local 80 - outbound EDS accounts-grpc-public.applications.svc.cluster.local 50051 - outbound EDS addressvalidator.applications.svc.cluster.local 50051 - outbound EDS 

Alle gleichen Dienste befinden sich in diesem Namespace:


 $ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) accounts-grpc-gw ClusterIP 10.3.0.91 <none> 80/TCP accounts-grpc-public ClusterIP 10.3.0.202 <none> 50051/TCP addressvalidator ClusterIP 10.3.0.56 <none> 50051/TCP 

Woher weiß Istio, welches Protokoll den Dienst verwendet? Konfiguriert Protokolle für Dienstmanifeste anhand des Namensfelds im Porteintrag.


 $ kubectl get service accounts-grpc-public -o yaml apiVersion: v1 kind: Service metadata: name: accounts-grpc-public spec: ports: - name: grpc port: 50051 protocol: TCP targetPort: 50051 

Wenn es grpc oder das grpc- Präfix gibt, konfiguriert Istio das HTTP2-Protokoll für den Dienst. Wir haben durch bittere Erfahrung gelernt, wie Istio den Portnamen verwendet, wenn Proxy-Konfigurationen beschädigt sind, weil sie keine http- oder grpc-Präfixe angegeben haben ...


Wenn Sie kubectl und die Admin-Port-Weiterleitungsseite in Envoy verwenden, können Sie sehen, dass die Konto-grpc-public-Endpunkte von Pilot als Cluster in Envoy mit dem HTTP2-Protokoll implementiert werden. Dies bestätigt unsere Annahmen:


 $ kubectl -n applications port-forward otherpod-dc56885ff-dqc6t 15000:15000 & $ curl http://localhost:15000/config_dump | yq r - ... - cluster: circuit_breakers: thresholds: - {} connect_timeout: 1s eds_cluster_config: eds_config: ads: {} service_name: outbound|50051||accounts-grpc-public.applications.svc.cluster.local http2_protocol_options: max_concurrent_streams: 1073741824 name: outbound|50051||accounts-grpc-public.applications.svc.cluster.local type: EDS ... 

Port 15000 ist die Envoy-Administrationsseite , die auf jedem Beiwagen verfügbar ist.


Zuhörer


Listener erkennen Kubernetes-Endpunkte, um Datenverkehr an die Herde weiterzuleiten. Der Adressüberprüfungsdienst hat hier einen Endpunkt:


 $ kubectl get ep addressvalidator -o yaml apiVersion: v1 kind: Endpoints metadata: name: addressvalidator subsets: - addresses: - ip: 10.2.26.243 nodeName: ip-10-205-35-230.ec2.internal targetRef: kind: Pod name: addressvalidator-64885ccb76-87l4d namespace: applications ports: - name: grpc port: 50051 protocol: TCP 

Daher verfügt der Adressüberprüfungsherd über einen Listener an Port 50051:


 $ kubectl -n applications port-forward addressvalidator-64885ccb76-87l4d 15000:15000 & $ curl http://localhost:15000/config_dump | yq r - ... dynamic_active_listeners: - version_info: 2019-01-13T18:39:43Z/651 listener: name: 10.2.26.243_50051 address: socket_address: address: 10.2.26.243 port_value: 50051 filter_chains: - filter_chain_match: transport_protocol: raw_buffer ... 

Routen


In Istio wird anstelle des Standardobjekts von Kubernetes Ingress eine abstraktere und effizientere benutzerdefinierte Ressource verwendet - VirtualService . VirtualService ordnet Routen Upstream-Clustern zu, indem sie an das Gateway gebunden werden. So verwenden Sie Kubernetes Ingress mit einem Ingress-Controller.


Wir verwenden nämlich das Istio Ingress-Gateway für den gesamten internen GRPC-Verkehr:


 apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: grpc-gateway spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http2 number: 80 protocol: HTTP2 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: grpc-gateway spec: gateways: - grpc-gateway hosts: - '*' http: - match: - uri: prefix: /namely.address_validator.AddressValidator retries: attempts: 3 perTryTimeout: 2s route: - destination: host: addressvalidator port: number: 50051 

Auf den ersten Blick werden Sie im Beispiel nichts verstehen. Hier ist es nicht sichtbar, aber die Istio-IngressGateway-Bereitstellung zeichnet basierend auf der istio: ingressgateway auf, welche Endpunkte benötigt werden. In diesem Beispiel leitet IngressGateway den Datenverkehr für alle Domänen über Port 80 über HTTP2 weiter. VirtualService implementiert Routen für dieses Gateway, stimmt mit dem Präfix /namely.address_validator.AddressValidator und übergibt den addressvalidator über den Port 50051 addressvalidator einer Wiederholungsregel in zwei Sekunden an den Upstream-Service.


Wenn wir den Pod-Port von Istio-IngressGateway umleiten und die Konfiguration von Envoy sehen, werden wir sehen, was VirtualService tut:


 $ kubectl -n istio-system port-forward istio-ingressgateway-7477597868-rldb5 15000 ... - match: prefix: /namely.address_validator.AddressValidator route: cluster: outbound|50051||addressvalidator.applications.svc.cluster.local timeout: 0s retry_policy: retry_on: 5xx,connect-failure,refused-stream num_retries: 3 per_try_timeout: 2s max_grpc_timeout: 0s decorator: operation: addressvalidator.applications.svc.cluster.local:50051/namely.address_validator.AddressValidator* ... 

Was wir beim Graben in Istio gegoogelt haben


Fehler 503 oder 404 tritt auf


Die Gründe sind unterschiedlich, aber normalerweise sind dies:


  • Beiwagenanwendungen können Pilot nicht kontaktieren (überprüfen Sie, ob Pilot ausgeführt wird).
  • Das Kubernetes-Dienstmanifest hat ein ungültiges Protokoll.
  • Die VirtualService / Envoy-Konfiguration schreibt die Route in den falschen Upstream-Cluster. Beginnen Sie mit dem Edge-Service, bei dem Sie eingehenden Datenverkehr erwarten, und überprüfen Sie die Envoy-Protokolle. Oder verwenden Sie etwas wie Jaeger, um Fehler zu finden.

Was bedeutet NR / UH / UF in Istio-Proxy-Protokollen?


  • NR - Keine Route.
  • UH - Upstream Ungesund (Upstream nicht funktionsfähig).
  • UF - Upstream-Fehler (Upstream-Fehler).

Lesen Sie mehr auf der Envoy-Website .


In Bezug auf Hochverfügbarkeit mit Istio


  • Fügen Sie den Istio-Komponenten NodeAffinity hinzu, um die Herde gleichmäßig auf verschiedene Verfügbarkeitszonen zu verteilen und die Mindestanzahl an Replikaten zu erhöhen.
  • Starten Sie die neue Version von Kubernetes mit der Funktion zur automatischen Skalierung horizontaler Pods. Die wichtigsten Herde werden je nach Belastung skaliert.

Warum endet Cronjob nicht?


Wenn die Hauptauslastung abgeschlossen ist, arbeitet der Beiwagencontainer weiter. Um das Problem zu umgehen, deaktivieren Sie den Beiwagen in Cronjobs, indem Sie sidecar.istio.io/inject: “false” die Anmerkung sidecar.istio.io/inject: “false” hinzufügen.


Wie installiere ich Istio?


Wir verwenden Spinnaker für Bereitstellungen, aber wir nehmen normalerweise die neuesten Helm-Diagramme, zaubern sie, verwenden die helm template -f values.yml und helm template -f values.yml Dateien auf Github fest, um die Änderungen zu sehen, bevor wir sie über kubectl apply -f - . Dies dient dazu, die CRD oder API in verschiedenen Versionen nicht versehentlich zu ändern.


Vielen Dank an Bobby Tables und Michael Hamrah für die Unterstützung beim Schreiben dieses Beitrags.

Source: https://habr.com/ru/post/de441616/


All Articles