1. Willkommen
Vielen Dank, dass Sie an diesem Codelab von Google zum Thema „Istio Multi Cloud Burst“ teilnehmen.Für dieses Codelab sind praktische Kenntnisse von Kubernetes, Node und Go für Anfänger erforderlich. Das brauchen Sie
|
|
Lerninhalte
- Kubernetes-Cluster in GKE erstellen
- Istio mit Helm in einem Kubernetes-Cluster installieren
- Istio Multicluster mit Helm installieren
- Webanwendung aus dem Quellcode in Kubernetes bereitstellen
- Traffic-Routing-Regeln für Istio schreiben und anwenden
- Prometheus-Messwerte
- Container-Images in einem Kubernetes-Cluster erstellen und per Push übertragen
2. Einrichtung
Sie können dieses Codelab auf einem der folgenden Geräte durcharbeiten:
- Google Cloud Shell (empfohlen): Shell im Browser mit vorinstallierten Tools
- auf Ihrem Laptop (folgen Sie der Anleitung unten)
Erste Schritte mit der Google Cloud Platform
- Wenn Sie kein GCP-Konto haben, erhalten Sie von Ihrem Kursleiter eine Karte mit einem kostenlosen Nutzerkonto.
- Rufen Sie die Google Cloud Console auf und klicken Sie auf „Projekt auswählen“:

- Notieren Sie sich die ID des Projekts und klicken Sie dann auf das Projekt, um es auszuwählen:

Option 1: Google Cloud Shell verwenden (empfohlen)
Cloud Shell bietet eine Befehlszeile in Ihrem Browser, in der die benötigten Tools installiert sind und die automatisch für Ihr Google Cloud-Konto authentifiziert wird. Wenn Sie diese Übung nicht in Cloud Shell ausführen möchten, fahren Sie mit dem nächsten Abschnitt fort.
Rufen Sie die Cloud Console auf und klicken Sie in der Symbolleiste rechts oben auf „Cloud Shell aktivieren“:

Tools zu Cloud Shell hinzufügen
- Installieren Sie
kubectx****: Laden Sie die Bash-Scripts hier in ein Verzeichnis in $PATH herunter. - Installieren Sie
helm**** gemäß dieser Anleitung.
Alternativ können Sie diese Befehle ausführen, um beide in ~/.bin zu installieren und zu Ihrem $PATH hinzuzufügen:
mkdir -p ~/.bin && \
cd ~/.bin && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubectx && \
chmod +x kubectx && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubens && \
chmod +x kubens && \
curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz && \
tar xzf helm-v2.12.0-linux-amd64.tar.gz && \
rm helm-v2.12.0-linux-amd64.tar.gz && \
mv linux-amd64/helm ./helm && \
rm -r linux-amd64 && \
export PATH=${HOME}/.bin:${PATH}
Hier sind einige Kurztipps, die die Verwendung von Cloud Shell erleichtern können:
1. Shell in einem neuen Fenster abtrennen: |
|
2. Dateieditor verwenden : Klicken Sie oben rechts auf das Stiftsymbol, um einen Dateieditor im Browser zu starten. Das ist nützlich, da wir Code-Snippets in Dateien kopieren werden. |
|
3. Neue Tabs starten:Wenn Sie mehr als einen Terminal-Prompt benötigen. |
|
4. Text vergrößern : Die Standardschriftgröße in Cloud Shell ist möglicherweise zu klein zum Lesen. | Strg + + unter Linux/Windows, ⌘ + + unter macOS |
Option 2: Laptop einrichten (nicht empfohlen)
Wenn Sie lieber Ihre eigene Workstation-Umgebung als Cloud Shell verwenden möchten, richten Sie die folgenden Tools ein:
gcloud:installieren (in Cloud Shell vorinstalliert) Folgen Sie der Anleitung, umgcloudauf Ihrer Plattform zu installieren. Damit erstellen wir einen Kubernetes-Cluster.kubectl:installieren(in Cloud Shell vorinstalliert) Führen Sie den folgenden Befehl aus, um die Installation durchzuführen:
gcloud components install kubectl
Führen Sie den folgenden Befehl aus, um gcloud zu authentifizieren. Sie werden aufgefordert, sich mit Ihrem Google-Konto anzumelden. Wählen Sie dann das zuvor erstellte Projekt (siehe oben) als Standardprojekt aus. Sie können die Konfiguration einer Compute-Zone überspringen:
gcloud init
curl:ist auf den meisten Linux-/macOS-Systemen vorinstalliert. Wahrscheinlich haben Sie es bereits. Suchen Sie andernfalls im Internet nach einer Anleitung zur Installation.- Installieren Sie
kubectx****: Laden Sie die Bash-Skripts hier in ein Verzeichnis in $PATH herunter. - Installieren Sie
helm**** gemäß dieser Anleitung.
3. GCP-Projekt einrichten
Aktivieren Sie die APIs für GKE (Google Kubernetes Engine), GCR (Google Container Registry) und GCB (Google Cloud Build) in Ihrem Projekt:
gcloud services enable \ cloudapis.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ cloudbuild.googleapis.com
Umgebungsvariablen einrichten
Wir werden während der Einrichtung intensiv mit unserem Google Cloud-Projekt arbeiten. Legen wir eine Umgebungsvariable für den schnellen Zugriff fest.
export GCLOUD_PROJECT=$(gcloud config get-value project)
In diesem Workshop erstellen wir einige Code- und Konfigurationsdateien. Erstellen wir also ein Projektverzeichnis und wechseln wir dorthin.
mkdir -p src/istio-burst && \ cd src/istio-burst && \ export proj=$(pwd)
4. „Primären“ Kubernetes-Cluster erstellen
Mit der Google Kubernetes Engine (GKE) können Sie ganz einfach verwaltete Kubernetes-Cluster erstellen.
Mit dem folgenden Befehl wird ein Kubernetes-Cluster erstellt:
- mit dem Namen „primary“
- in der Zone „us-west1-a“
- Die neueste verfügbare Kubernetes-Version
- mit 4 Anfangsknoten
export cluster=primary
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "4" --network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
Das kann etwa 5 Minuten dauern. Sie können die Erstellung des Clusters in der Cloud Console verfolgen.)
Nachdem der Kubernetes-Cluster erstellt wurde, konfiguriert gcloud kubectl mit den Anmeldedaten, die auf den Cluster verweisen.
gcloud container clusters get-credentials $cluster --zone=$zone
Sie sollten kubectl jetzt mit Ihrem neuen Cluster verwenden können.
Führen Sie den folgenden Befehl aus, um die Kubernetes-Knoten Ihres Clusters aufzulisten. Sie sollten den Status „Bereit“ haben:
kubectl get nodes
Kubeconfig-Namen zur besseren Nutzung ändern
Wir wechseln häufig zwischen Kontexten. Daher ist ein kurzer Alias für unsere Cluster praktisch.
Mit diesem Befehl wird der gerade erstellte kubeconfig-Eintrag in primary umbenannt.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
Berechtigungen festlegen:
Für die Bereitstellung von Istio müssen Sie Clusteradministrator sein. Mit diesem Befehl wird die mit Ihrem Google Cloud-Konto verknüpfte E-Mail-Adresse als Clusteradministrator festgelegt.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
5. „Burst“-Cluster erstellen
Mit dem folgenden Befehl wird ein Kubernetes-Cluster erstellt:
- mit dem Namen „burst“,
- in der Zone „us-west1-a“
- Die neueste verfügbare Kubernetes-Version
- Mit 1 Startknoten
- Autoscaling für bis zu 5 Knoten aktiviert
export cluster=burst
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "1" --enable-autoscaling --min-nodes=1 --max-nodes=5 \
--network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
Das kann etwa 5 Minuten dauern. Sie können die Erstellung des Clusters in der Cloud Console verfolgen.)
Nachdem der Kubernetes-Cluster erstellt wurde, konfiguriert gcloud kubectl mit den Anmeldedaten, die auf den Cluster verweisen.
gcloud container clusters get-credentials $cluster --zone=$zone
Sie sollten kubectl jetzt mit Ihrem neuen Cluster verwenden können.
Führen Sie den folgenden Befehl aus, um die Kubernetes-Knoten Ihres Clusters aufzulisten. Sie sollten den Status „Bereit“ haben:
kubectl get nodes
Kubeconfig-Namen zur besseren Nutzung ändern
Mit diesem Befehl wird der gerade erstellte kubeconfig-Eintrag in burst geändert.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
Berechtigungen festlegen:
Für die Bereitstellung von Istio Remote benötigen Sie die Rolle „Cluster Admin“. Mit diesem Befehl wird die mit Ihrem Google Cloud-Konto verknüpfte E-Mail-Adresse als Clusteradministrator festgelegt.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
6. Firewallregeln anwenden
Damit unsere beiden Cluster miteinander kommunizieren können, müssen wir eine Firewallregel erstellen.
Führen Sie die folgenden Befehle aus, um in Google Cloud eine Firewallregel zu erstellen, die die Kommunikation zwischen den Clustern ermöglicht.
function join_by { local IFS="$1"; shift; echo "$*"; }
ALL_CLUSTER_CIDRS=$(gcloud container clusters list \
--filter="(name=burst OR name=primary) AND zone=$zone" \
--format='value(clusterIpv4Cidr)' | sort | uniq)
ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
ALL_CLUSTER_NETTAGS=$(gcloud compute instances list \
--filter="(metadata.cluster-name=burst OR metadata.cluster-name=primary) AND metadata.cluster-location=us-west1-a" \
--format='value(tags.items.[0])' | sort | uniq)
ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
gcloud compute firewall-rules create istio-multicluster-test-pods \
--allow=tcp,udp,icmp,esp,ah,sctp \
--direction=INGRESS \
--priority=900 \
--source-ranges="${ALL_CLUSTER_CIDRS}" \
--target-tags="${ALL_CLUSTER_NETTAGS}" --quiet
Wir haben beide Cluster eingerichtet und können unsere Anwendung und Istio darauf bereitstellen.
7. Einführung in Istio
Was ist Istio?
Istio ist eine Service Mesh-Steuerungsebene, die darauf abzielt, „Dienste zu verbinden, zu sichern, zu steuern und zu beobachten“. Dies geschieht auf verschiedene Weise, hauptsächlich aber durch das Sidecar-ing eines Proxy-Containers ( Envoy) in jeden Ihrer bereitgestellten Kubernetes-Pods. Der Proxy-Container steuert die gesamte Netzwerkkommunikation zwischen Mikrodiensten in Verbindung mit einem universellen Richtlinien- und Telemetrie-Hub ( Mixer).

Diese Richtlinien können unabhängig von Ihren Kubernetes-Bereitstellungen und -Diensten angewendet werden. Das bedeutet, dass der Netzwerkbetreiber die Netzwerkaktivität beobachten, Netzwerkrichtlinien einschränken, umleiten oder neu schreiben kann, ohne die zugehörigen Anwendungen neu bereitzustellen.
Einige der von Istio unterstützten Funktionen zur Trafficverwaltung sind:
- Schutzschalter
- Prozentuale Traffic-Aufteilung
- URL-Umschreibung
- TLS-Terminierung
- Systemdiagnosen
- Load Balancing
In diesem Workshop konzentrieren wir uns auf die prozentuale Aufteilung des Traffics.
Istio-Begriffe, die wir verwenden
VirtualService
Ein VirtualService definiert eine Reihe von Traffic-Routingregeln, die angewendet werden sollen, wenn ein Host adressiert wird.
Gateway
Ein Gateway ist ein Load-Balancer, der am Rand des Mesh-Netzwerks ausgeführt wird und eingehende oder ausgehende HTTP/TCP-Verbindungen empfängt. In Gateways können Ports, SNI-Konfigurationen usw. angegeben werden.
DestinationRule
Eine DestinationRule definiert Richtlinien, die auf Traffic angewendet werden, der für einen Dienst bestimmt ist, nachdem das Routing erfolgt ist. Sie geben die Konfiguration für das Load-Balancing, die Größe des Verbindungspools vom Sidecar und die Einstellungen für die Ausreißererkennung an.
Istio-Multi-Cluster
Als wir unsere beiden Cluster erstellt haben, hatte der primary-Cluster vier Knoten ohne Autoscaling und der burst-Cluster einen Knoten mit Autoscaling auf bis zu fünf Knoten.
Dafür gibt es zwei Gründe.
Zuerst möchten wir ein Szenario simulieren, in dem Daten von einem lokalen System in die Cloud migriert werden. In einer On-Premise-Umgebung haben Sie keinen Zugriff auf Autoscaling-Cluster, da Sie eine feste Infrastruktur haben.
Zweitens ist eine Einrichtung mit vier Knoten (wie oben definiert) die Mindestanforderung für die Ausführung von Istio. Das wirft die Frage auf: Wenn für Istio mindestens 4 Knoten erforderlich sind, wie kann unser burst-Cluster Istio mit nur einem Knoten ausführen? Bei Istio Multicluster wird eine viel kleinere Gruppe von Istio-Diensten installiert. Die Richtlinienregeln werden von der Istio-Installation im primären Cluster abgerufen und Telemetrieinformationen werden dort veröffentlicht.
8. Übersicht über die Anwendungsarchitektur
Komponenten – Übersicht
Wir stellen eine dreistufige Anwendung mit NodeJS und Redis bereit.
Worker
Die Worker-Anwendung ist in NodeJS geschrieben und wartet auf eingehende POST-HTTP-Anfragen. Sie führt eine Hash-Operation für diese Anfragen aus und stellt dem Hash den Wert voran, wenn eine Umgebungsvariable mit dem Namen PREFIX definiert ist. Sobald der Hash berechnet wurde, sendet die Anwendung das Ergebnis über den Channel „calculation“ auf dem angegebenen Redis-Server.
Wir verwenden die Umgebungsvariable PREFIX später, um die Multicluster-Funktionalität zu demonstrieren.
Zur Information: Das sind die Pakete, die von der Anwendung verwendet werden.
body-parser:Ermöglicht das Parsen von HTTP-Anfragen.cors:Ermöglicht die Verwendung von Cross-Origin Resource Sharingdotenv:Umgebungsvariablen einfach parsenexpress:Einfaches Websitehostingioredis:-Clientbibliothek für die Kommunikation mit Redis-Datenbankenmorgan:Bietet ein gut strukturiertes Log
Frontend
Unser Frontend ist ebenfalls eine NodeJS-Anwendung, die eine Webseite mit Express hostet. Es nimmt eine vom Nutzer eingegebene Häufigkeit entgegen und sendet Anfragen mit dieser Rate an unsere worker-Anwendung. Diese Anwendung abonniert auch Nachrichten in einem Redis-Kanal mit dem Namen „calculation“ und zeigt die Ergebnisse auf einer Webseite an.
Die Anwendung verwendet die folgenden Abhängigkeiten.
body-parser:Ermöglicht das Parsen von HTTP-Anfragen.dotenv:Umgebungsvariablen einfach parsenexpress:Einfaches Websitehostingioredis:-Clientbibliothek für die Kommunikation mit Redis-Datenbankenmorgan:Bietet gut strukturierte Logsrequest:: Ermöglicht das Stellen von HTTP-Anfragensocket.io:Ermöglicht die bidirektionale Kommunikation von der Webseite zum Server
Auf dieser Webseite wird Bootstrap für das Styling verwendet. Wenn sie ausgeführt wird, sieht sie so aus:

Architekturdiagramm

Bereitstellungsdiagramm
Wir stellen unsere endgültige Anwendung in den beiden von uns erstellten Clustern bereit. Im primary-Cluster werden alle Komponenten (frontend, worker und Redis) bereitgestellt, im burst-Cluster jedoch nur die worker-Anwendung.
Das folgende Diagramm veranschaulicht die beiden Cluster. Die rot umrandeten Kästen sind Kubernetes-Dienste, die blauen Kubernetes-Deployments. Die gelben Kästen stehen für die Installation von Istio.
Beachten Sie, dass im burst-Cluster weiterhin ein Dienst für Redis bereitgestellt ist, obwohl es kein Deployment für Redis im Cluster gibt. Wir benötigen diesen Dienst im Cluster, damit Kubernetes DNS die Anfrage auflösen kann. Wenn die Anfrage jedoch tatsächlich gestellt wird, leitet der Istio-Proxy die Anfrage an die Redis-Bereitstellung im primary-Cluster weiter.
Die endgültige Anwendung hat ein zusätzliches Deployment, das im primary-Cluster mit dem Namen istiowatcher. ausgeführt wird. Dadurch können wir Traffic dynamisch an burst weiterleiten, wenn unser Traffic einen bestimmten Schwellenwert überschreitet.

9. Bereitstellungsdateien für Anwendungen erstellen
Wir müssen eine Reihe von Kubernetes-Manifesten erstellen, um unsere Anwendung bereitzustellen.
Wechseln Sie in das Stammverzeichnis des Projekts und erstellen Sie einen neuen Ordner mit dem Namen kubernetes.
mkdir ${proj}/kubernetes && cd ${proj}/kubernetes
frontend.yaml schreiben
Dadurch werden sowohl ein Kubernetes-Deployment als auch ein Dienst für den Zugriff auf unser Frontend-Image erstellt.
Fügen Sie Folgendes in frontend.yaml ein.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend-deployment
labels:
app: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: gcr.io/istio-burst-workshop/frontend
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PROCESSOR_URL
value: "http://worker-service"
- name: REDIS_URL
value: "redis-cache-service:6379"
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
Wichtige Hinweise zur Deployment
- Wir haben den Port, auf dem die Anwendung ausgeführt wird, auf
8080festgelegt. - Wir haben die Adresse für den Worker auf „
http://worker-service“ festgelegt und verwenden die integrierte DNS-Funktion von Kubernetes, um den resultierenden Dienst aufzulösen. - Wir haben die Adresse für unsere
REDIS_URLauf „redis-cache-service:6379“ festgelegt und verwenden die integrierte DNS-Funktion von Kubernetes, um die resultierenden IP-Adressen aufzulösen. - Wir haben auch
liveness- undreadiness-Tests für den Container festgelegt, um Kubernetes darüber zu informieren, wann der Container ausgeführt wird.
worker-service.yaml schreiben
Wir schreiben die Kubernetes-Dienstdefinition in eine separate Datei als die Deployment-Definition, da wir diesen Dienst in mehreren Clustern wiederverwenden, aber für jeden Cluster ein anderes Deployment schreiben.
Fügen Sie Folgendes in worker-service.yaml ein:
apiVersion: v1
kind: Service
metadata:
name: worker-service
spec:
type: ClusterIP
selector:
app: worker
ports:
- name: http
port: 80
targetPort: 8081
worker-primary.yaml schreiben
Dies ist die Bereitstellung von worker, die wir in den primären Cluster übertragen.
Fügen Sie Folgendes in worker-primary.yaml ein.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: primary-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
Wir folgen dabei demselben Muster, indem wir liveness- und readiness-Probes bereitstellen und die Umgebungsvariablen PORT und REDIS_URL für unsere Anwendung angeben.
Ein weiterer wichtiger Punkt bei dieser Bereitstellung ist das Fehlen der Umgebungsvariable PREFIX. Das bedeutet, dass unsere Berechnungsergebnisse Roh-Hashes sind (ohne Präfix).
Der letzte wichtige Punkt dieser Bereitstellung ist das Label cluster-type: primary-cluster. Wir werden das später beim Traffic-Routing in Istio-Multicluster verwenden.
redis.yaml schreiben
Die Kommunikation von unserem Worker zurück zum Frontend erfolgt über einen Redis-Kanal. Daher müssen wir eine Redis-Anwendung in unserem Cluster bereitstellen.
Fügen Sie Folgendes in redis.yaml ein:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
template:
metadata:
labels:
app: redis-cache
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
resources:
limits:
memory: 256Mi
cpu: 125m
requests:
cpu: 70m
memory: 200Mi
volumes:
- name: redis-data
emptyDir: {}
Dies ist eine halbwegs standardmäßige Bereitstellung einer Redis-Anwendung. Es wird ein Container basierend auf dem redis:alpine-Image erstellt, die entsprechenden Ports werden freigegeben und sinnvolle Ressourcenlimits werden festgelegt.
redis-service.yaml schreiben
Wir benötigen einen Kubernetes-Dienst, um mit unserer Redis-Anwendung zu kommunizieren.
Fügen Sie Folgendes in redis-service.yaml ein:
apiVersion: v1
kind: Service
metadata:
name: redis-cache-service
spec:
type: ClusterIP
selector:
app: redis-cache
ports:
- port: 6379
targetPort: 6379
Dadurch wird ein Dienst mit dem Namen redis-cache-service bereitgestellt, über den auf unsere Redis-Bereitstellung zugegriffen werden kann.
10. Anwendung bereitstellen
Nachdem unsere Images in GCR übertragen und unsere Kubernetes-Manifeste geschrieben wurden, ist es an der Zeit, unsere Anwendung bereitzustellen und zu sehen, wie sie funktioniert.
Führen Sie die folgenden Befehle aus, um die Anwendung bereitzustellen:
- Prüfen, ob wir uns im richtigen Cluster befinden
kubectx primary
- Redis-Cache bereitstellen
kubectl apply -f redis.yaml
- Redis-Dienst bereitstellen
kubectl apply -f redis-service.yaml
- Frontend bereitstellen
kubectl apply -f frontend.yaml
- Worker bereitstellen
kubectl apply -f worker-primary.yaml
- Worker-Dienst bereitstellen
kubectl apply -f worker-service.yaml
Wir haben unsere Anwendung in GKE bereitgestellt. Glückwunsch!
Test
Warten Sie, bis die Pods online sind.
kubectl get pods -w
Wenn alle Pods den Status „Running“ (Wird ausgeführt) haben, drücken Sie Strg + C.
NAME READY STATUS RESTARTS AGE frontend-deployment-695d95fbf7-76sd8 1/1 Running 0 2m redis-cache-7475999bf5-nxj8x 1/1 Running 0 2m worker-deployment-5b9cf9956d-g975p 1/1 Running 0 2m
Sie werden feststellen, dass wir unser Frontend nicht über einen LoadBalancer bereitgestellt haben. Das liegt daran, dass wir später über Istio auf die Anwendung zugreifen werden. Um zu testen, ob alles funktioniert, verwenden wir kubectl port-forward.. Führen Sie den folgenden Befehl aus, um Port 8080 auf Ihrem lokalen Computer (oder in Cloud Shell) an Port 8080 der frontend-Bereitstellung weiterzuleiten.
kubectl port-forward \
$(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080
Wenn Sie die App lokal ausführen: Öffnen Sie einen Webbrowser und rufen Sie http://localhost:8080 auf.
Wenn Sie Cloud Shell verwenden:Klicken Sie auf die Schaltfläche „Webvorschau“ und wählen Sie „Vorschau auf Port 8080“ aus.

Das Frontend sollte nun angezeigt werden. Wenn Sie eine Zahl in das Feld „Häufigkeit“ eingeben, sollten Hashes angezeigt werden.

Herzlichen Glückwunsch! Alles läuft.
Drücke Ctrl+C, um die Portweiterleitung zu beenden.
11. Bereitgestellte Anwendung bereinigen
Wir wenden Istio auf unseren Cluster an und stellen unsere Anwendung dann noch einmal bereit. Deshalb bereinigen wir zuerst unsere aktuelle Anwendung.
Führen Sie die folgenden Befehle aus, um alle gerade erstellten Deployments und Dienste zu löschen.
redis-cache-servicelöschen
kubectl delete -f redis-service.yaml
redislöschen
kubectl delete -f redis.yaml
frontendlöschen
kubectl delete -f frontend.yaml
workerlöschen
kubectl delete -f worker-primary.yaml
worker-servicelöschen
kubectl delete -f worker-service.yaml
12. Istio auf dem primären Cluster installieren
Istio abrufen
Die Releases von Istio werden auf GitHub gehostet. Mit den folgenden Befehlen wird die Version 1.0.0 von Istio heruntergeladen und entpackt.
- Wechseln Sie zum Stammverzeichnis Ihres Projekts.
cd ${proj}
- Archiv herunterladen
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
- Archiv extrahieren und entfernen
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz
Istio-Vorlage erstellen
Wenn Sie den folgenden Helm-Befehl ausführen, wird die Vorlage für die Installation von Istio in Ihrem Cluster erstellt.
helm template istio-1.0.0/install/kubernetes/helm/istio \ --name istio --namespace istio-system \ --set prometheus.enabled=true \ --set servicegraph.enabled=true > istio-primary.yaml
Dadurch wird im aktuellen Verzeichnis eine Datei mit dem Namen istio-primary.yaml erstellt, die alle Definitionen und Spezifikationen enthält, die zum Bereitstellen und Ausführen von Istio erforderlich sind.
Beachten Sie die beiden --set-Parameter. Diese Add-ons fügen dem Istio-System Unterstützung für Prometheus und ServiceGraph hinzu. Wir werden den Prometheus-Dienst später im Lab verwenden.
Istio bereitstellen
Um Istio bereitzustellen, müssen wir zuerst einen Namespace mit dem Namen istio-system erstellen, in dem die Istio-Bereitstellungen und -Dienste ausgeführt werden können.
kubectl create namespace istio-system
Wenden Sie schließlich die mit Helm erstellte istio-primary.yaml-Datei an.
kubectl apply -f istio-primary.yaml
Standard-Namespace für Labels
Istio funktioniert, indem ein Sidecar-Proxy-Dienst in jede Ihrer Bereitstellungen eingefügt wird. Dies erfolgt auf Opt-in-Basis. Daher müssen wir unserem default-Namespace das Label istio-injection=enabled hinzufügen, damit Istio den Sidecar automatisch einfügen kann.
kubectl label namespace default istio-injection=enabled
Glückwunsch! Wir haben einen Cluster eingerichtet, auf dem Istio ausgeführt wird. Jetzt können wir unsere Anwendung bereitstellen.
13. Anwendung mit Istio-Trafficverwaltung bereitstellen
Konfigurationsdateien für die Istio-Trafficverwaltung erstellen
Istio funktioniert ähnlich wie Kubernetes, da es YAML-Dateien für die Konfiguration verwendet. Dazu müssen wir eine Reihe von Dateien erstellen, die Istio mitteilen, wie unser Traffic bereitgestellt und weitergeleitet werden soll.
Erstellen Sie ein Verzeichnis mit dem Namen istio-manifests und rufen Sie es auf.
mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests
frontend-gateway.yaml schreiben
Mit dieser Datei wird unser Kubernetes-Cluster ähnlich wie ein GKE-LoadBalancer verfügbar gemacht und der gesamte eingehende Traffic wird an unseren Frontend-Dienst weitergeleitet.
Erstellen Sie eine Datei mit dem Namen frontend-gateway.yaml und fügen Sie Folgendes ein.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: frontend-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: frontend-ingress-virtual-service
spec:
hosts:
- "*"
gateways:
- frontend-gateway
http:
- route:
- destination:
host: frontend-service
port:
number: 80
redis-virtualservice.yaml schreiben
Erstellen Sie eine Datei mit dem Namen redis-virtualservice.yaml und fügen Sie Folgendes ein:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: redis-virtual-service
spec:
hosts:
- redis-cache-service
gateways:
- mesh
tcp:
- route:
- destination:
host: redis-cache-service.default.svc.cluster.local
worker-virtualservice.yaml schreiben
Erstellen Sie eine Datei mit dem Namen worker-virtualservice.yaml und fügen Sie Folgendes ein:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
port:
number: 80
Istio-Trafficverwaltungsrichtlinien bereitstellen
Die Bereitstellung der Istio-Richtlinien erfolgt auf dieselbe Weise wie bei anderen Kubernetes-Ressourcen mit kubectl apply.
- Unser Gateway verwenden
kubectl apply -f frontend-gateway.yaml
- Redis-VirtualService anwenden
kubectl apply -f redis-virtualservice.yaml
- Worker-VirtualService anwenden
kubectl apply -f worker-virtualservice.yaml
Anwendung bereitstellen
- Wechseln Sie zurück in das Verzeichnis
kubernetes.
cd ${proj}/kubernetes
- Redis-Cache bereitstellen
kubectl apply -f redis.yaml
- Redis-Dienst bereitstellen
kubectl apply -f redis-service.yaml
- Frontend bereitstellen
kubectl apply -f frontend.yaml
- Worker bereitstellen
kubectl apply -f worker-primary.yaml
- Worker-Dienst bereitstellen
kubectl apply -f worker-service.yaml
Bestätigen
Wir haben unsere Anwendung jetzt auf einem Cluster mit Istio- und Traffic-Management-Richtlinien neu bereitgestellt.
Warten wir, bis alle unsere Arbeitslasten online sind.
Sobald alle online sind, rufen Sie das Ingress-Gateway ab, das wir in frontend-ingressgateway.yaml konfiguriert haben.
$ kubectl -n istio-system get svc istio-ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.36.3.112 35.199.158.10 80:31380/TCP,
Rufen Sie entweder die Adresse <EXTERNAL-IP> auf oder führen Sie „curl“ aus. Das Frontend sollte angezeigt werden.
$ curl 35.199.158.10
<!doctype html>
<html>
<head>
<title>String Hashr</title>
<!-- Bootstrap -->
...
14. Istio auf dem „Burst“-Cluster installieren
Wir haben viel Zeit mit der Einrichtung und Bereitstellung in unserem primary-Cluster verbracht, aber wir haben noch einen weiteren Cluster, in dem wir die Bereitstellung vornehmen können.
In diesem Abschnitt müssen wir Konfigurationsvariablen aus beiden Clustern abrufen. Achten Sie daher genau darauf, auf welchen Cluster wir für jeden Befehl verweisen.
Istio-Remotemanifest erstellen
Ähnlich wie bei der Bereitstellung von Istio für den primary-Cluster verwenden wir Helm, um die Bereitstellung von Istio-Remote für den burst-Cluster zu templatisieren. Bevor wir das tun können, benötigen wir jedoch einige Informationen zu unserem primary-Cluster.
Informationen zum primären Cluster erfassen
Zum Cluster primary wechseln
kubectx primary
Mit den folgenden Befehlen werden die IP-Adressen verschiedener Pods im primären Cluster abgerufen. Diese werden von Istio Remote verwendet, um mit dem primären Cluster zu kommunizieren.
export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
export STATSD_POD_IP=$(kubectl -n istio-system get pod -l istio=statsd-prom-bridge -o jsonpath='{.items[0].status.podIP}')
export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')
Remote-Vorlage erstellen
Jetzt verwenden wir helm, um eine Datei mit dem Namen istio-remote-burst.yaml zu erstellen, die wir dann im burst-Cluster bereitstellen können.
Zum Projektstammverzeichnis wechseln
cd $proj
helm template istio-1.0.0/install/kubernetes/helm/istio-remote --namespace istio-system \
--name istio-remote \
--set global.remotePilotAddress=${PILOT_POD_IP} \
--set global.remotePolicyAddress=${POLICY_POD_IP} \
--set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
--set global.proxy.envoyStatsd.enabled=true \
--set global.proxy.envoyStatsd.host=${STATSD_POD_IP} \
--set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > istio-remote-burst.yaml
Istio Remote auf dem Burst-Cluster installieren
Wenn wir Istio im Cluster burst installieren möchten, müssen wir dieselben Schritte wie bei der Installation im Cluster primary ausführen, aber stattdessen die Datei istio-remote-burst.yaml verwenden.
Kubecontext auf Burst ändern
kubectx burst
Namespace „istio-system“ erstellen
kubectl create ns istio-system
istio-burst.yaml anwenden
kubectl apply -f istio-remote-burst.yaml
Standard-Namespace für Labels
Auch hier müssen wir dem default-Namespace ein Label hinzufügen, damit der Proxy automatisch eingefügt werden kann.
kubectl label namespace default istio-injection=enabled
Glückwunsch! An diesem Punkt haben wir Istio Remote auf dem burst-Cluster eingerichtet. Zu diesem Zeitpunkt können die Cluster jedoch noch nicht miteinander kommunizieren. Wir müssen eine kubeconfig-Datei für den Cluster burst generieren, die wir im Cluster primary bereitstellen können, um die beiden Cluster zu verknüpfen.
kubeconfig für Burst-Cluster erstellen
Zum Burst-Cluster wechseln
kubectx burst
Umgebung einrichten
Wir benötigen einige Informationen zum Cluster, um eine kubeconfig-Datei dafür zu erstellen.
- Name des Clusters abrufen
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
- Name des Clusterservers abrufen
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
- Rufen Sie den Namen des Secrets für die Zertifizierungsstelle des Dienstkontos
istio-multiab.
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
- CA-Daten aus dem vorherigen Secret abrufen
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
- Das im vorherigen Secret gespeicherte Token abrufen
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)
kubeconfig-Datei erstellen
Nachdem alle Umgebungsvariablen festgelegt wurden, müssen wir die kubeconfig-Datei erstellen.
cat <<EOF > burst-kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${CA_DATA}
server: ${SERVER}
name: ${CLUSTER_NAME}
contexts:
- context:
cluster: ${CLUSTER_NAME}
user: ${CLUSTER_NAME}
name: ${CLUSTER_NAME}
current-context: ${CLUSTER_NAME}
kind: Config
preferences: {}
users:
- name: ${CLUSTER_NAME}
user:
token: ${TOKEN}
EOF
Dadurch wird im aktuellen Verzeichnis eine neue Datei mit dem Namen burst-kubeconfig erstellt, die vom primary-Cluster zur Authentifizierung und Verwaltung des burst-Clusters verwendet werden kann.
Zurück zum primären Cluster wechseln
kubectx primary
kubeconfig für „burst“ anwenden, indem Sie ein Secret erstellen und es labeln
kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system
Secret so labeln, dass Istio es für die Multicluster-Authentifizierung verwendet
kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system
Glückwunsch! Beide Cluster sind authentifiziert und kommunizieren über Istio Multicluster miteinander. Stellen wir unsere Anwendung clusterübergreifend bereit.
15. Clusterübergreifende Anwendung bereitstellen
Deployments erstellen
Wechseln Sie in das Verzeichnis kubernetes.
cd ${proj}/kubernetes
Worker-Bereitstellung für den Burst-Cluster erstellen: worker-burst.yaml
Erstellen Sie eine Datei mit dem Namen worker-burst.yaml und fügen Sie Folgendes ein:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: burst-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
Diese Datei ist fast identisch mit der Datei „worker-primary.yaml“, die wir zuvor erstellt haben. Es gibt zwei Hauptunterschiede.
Der erste wichtige Unterschied besteht darin, dass wir die Umgebungsvariable PREFIX mit dem Wert „bursty-“ hinzugefügt haben.
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
Das bedeutet, dass unser Worker im Cluster burst allen gesendeten Hashes das Präfix „bursty-“ voranstellt. So können wir feststellen, ob unsere Anwendung wirklich clusterübergreifend ist.
Der zweite wichtige Unterschied besteht darin, dass wir das Label cluster-type für diese Bereitstellung von primary-cluster in burst-cluster geändert haben.
labels:
app: worker
cluster-type: burst-cluster
Wir verwenden dieses Label später, wenn wir unser VirtualService aktualisieren.
Istio-Dienste ändern
Derzeit nutzen unsere Istio-Dienste nicht beide Bereitstellungen. 100% unseres Traffics werden an den primären Cluster weitergeleitet. Das wollen wir ändern.
Wechseln Sie in das Verzeichnis istio-manifests.
cd ${proj}/istio-manifests
worker-virtualservice.yaml bearbeiten, um DestinationRules einzufügen
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 50
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 50
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
Wir haben unserem VirtualService ein zweites Ziel hinzugefügt. Es wird weiterhin auf denselben Host verwiesen (worker-service.default.svc.cluster.local)), aber 50% des Traffics werden an die Teilmenge primary und die anderen 50% an die Teilmenge burst weitergeleitet.
Wir haben die Teilmenge primary als Bereitstellungen mit dem Label cluster-type: primary-cluster und die Teilmenge burst als Bereitstellungen mit dem Label cluster-type: burst-cluster definiert.
Dadurch wird unser Traffic effektiv zu gleichen Teilen auf die beiden Cluster aufgeteilt.
Im Cluster bereitstellen
redis-service.yaml im Burst-Cluster bereitstellen
Zur burst-kubeconfig wechseln
kubectx burst
Wechseln Sie zum Stammverzeichnis des Projekts.
cd ${proj}
Stellen Sie sie dann bereit.
redis-service.yaml im Burst-Cluster bereitstellen
kubectl apply -f kubernetes/redis-service.yaml
worker-burst.yaml im Burst-Cluster bereitstellen
kubectl apply -f kubernetes/worker-burst.yaml
worker-service.yaml im Burst-Cluster bereitstellen
kubectl apply -f kubernetes/worker-service.yaml
Istio VirtualServices anwenden
Zur primary-kubeconfig wechseln
kubectx primary
Dann bereitstellen
kubectl apply -f istio-manifests/worker-virtualservice.yaml
Funktionsweise prüfen
Wenn Sie prüfen möchten, ob es funktioniert, rufen Sie Ihren Istio-Ingress-Punkt auf. Etwa 50% der Hashes sollten mit „burst-“ beginnen.

Das bedeutet, dass wir erfolgreich clusterübergreifend kommunizieren. Ändern Sie die Gewichtungen der verschiedenen Dienste und wenden Sie die Datei worker-virtualservice.yaml an. Das ist eine gute Möglichkeit, den Traffic zwischen Clustern auszugleichen. Aber was, wenn wir das automatisch erledigen könnten?
16. Prometheus-Messwerte nutzen
Einführung in Prometheus
Prometheus ist ein Open-Source-Toolkit für Systemmonitoring und Benachrichtigungen, das ursprünglich bei SoundCloud entwickelt wurde. Es wird ein mehrdimensionales Datenmodell mit Zeitreihendaten verwaltet, die durch Messwertname und Schlüssel/Wert-Paare identifiziert werden.
Zur Referenz finden Sie hier das Prometheus-Architekturdiagramm:

Wenn Istio mit Prometheus bereitgestellt wird, werden automatisch verschiedene Messwerte an den Prometheus-Server gemeldet. Mithilfe dieser Messwerte können wir unsere Cluster im laufenden Betrieb verwalten.
Prometheus-Messwerte ansehen
Zuerst müssen wir die Prometheus-Bereitstellung freigeben.
Rufen Sie in GKE den Tab „Arbeitslasten“ auf und führen Sie einen Drilldown zur Arbeitslast „prometheus“ durch.

Rufen Sie die Details der Bereitstellung auf und wählen Sie „Aktionen“ –> „Freigeben“ aus.

Wählen Sie aus, dass die Weiterleitung an Port 9090 erfolgen soll, und geben Sie „Load Balancer“ ein.

Wählen Sie „Expose“ aus.
Dadurch wird ein Dienst mit einer öffentlich zugänglichen IP-Adresse erstellt, über die wir unsere Prometheus-Messwerte aufrufen können.
Warten Sie, bis der Endpunkt betriebsbereit ist, und klicken Sie dann neben „Externe Endpunkte“ auf die IP-Adresse
.
Sie sollten jetzt die Prometheus-Benutzeroberfläche sehen.

Prometheus bietet genügend Messwerte, um einen eigenen Workshop zu füllen. Wir beginnen jedoch erst einmal mit der Messung der istio_requests_total-Messwerte.
Wenn Sie diese Abfrage ausführen, werden viele Daten zurückgegeben. Es handelt sich um Messwerte für alle Anfragen, die das Istio-Service-Mesh durchlaufen, und das sind viele. Wir ändern den Ausdruck, um nur die Daten zu filtern, die uns wirklich interessieren:
Anfragen, bei denen der Zieldienst worker-service.default.svc.cluster.local und die Quelle frontend-deployment ist, beschränkt auf die letzten 15 Sekunden
Die Abfrage sieht so aus:
istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]
Dadurch erhalten wir einen viel übersichtlicheren Datensatz, mit dem wir arbeiten können.

Aber es ist immer noch etwas dicht. Wir möchten die Anfragen pro Sekunde und nicht alle Anfragen sehen.
Dazu können wir die integrierte Funktion rate verwenden.
rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

Wir sind auf dem richtigen Weg, aber wir müssen diese Messwerte noch etwas weiter in einer logischen Gruppe zusammenfassen.
Dazu können wir die Keywords sum und by verwenden, um unsere Ergebnisse zu gruppieren und zu summieren.
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)

Super! Wir können die genauen Messwerte, die wir benötigen, aus Prometheus abrufen.
Unsere endgültige Prometheus-Abfrage
Mit allem, was wir gelernt haben, lautet die endgültige Abfrage, die wir an Prometheus stellen müssen:
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)
Jetzt können wir die HTTP API verwenden, um den Messwert abzurufen.
Wir können ihre API mit unserer Abfrage abfragen, indem wir eine HTTP-GET-Anfrage wie folgt stellen. Ersetzen Sie <prometheus-ip-here>
curl http://<prometheus-ip-here>/api/v1/query?query=sum\(rate\(istio_requests_total%7Breporter%3D%22destination%22%2C%0Adestination_service%3D%22worker-service.default.svc.cluster.local%22%2C%0Asource_workload%3D%22frontend-deployment%22%7D%5B15s%5D\)\)%20by%20\(source_workload%2C%0Asource_app%2C%20destination_service\)
Hier ist eine Beispielantwort:
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"destination_service": "worker-service.default.svc.cluster.local",
"source_app": "frontend",
"source_workload": "frontend-deployment"
},
"value": [
1544404907.503,
"18.892886390062788"
]
}
]
}
}
Jetzt können wir den Messwert aus dem JSON extrahieren.
Clean-up
Wir müssen den Dienst löschen, den wir gerade zum Bereitstellen von Prometheus verwendet haben. Klicken Sie in der Google Cloud Console oben auf den Dienst, den wir gerade erstellt haben, und dann auf „Löschen“.

Vorgehensweise:
Nachdem wir herausgefunden haben, wie und mit welcher Rate Traffic durch den Cluster fließt, besteht der nächste Schritt darin, ein kleines Binärprogramm zu schreiben, das regelmäßig Prometheus abfragt. Wenn die Anfragen pro Sekunde an worker einen bestimmten Schwellenwert überschreiten, werden unterschiedliche Zielgewichte auf unseren Worker-Virtual-Service angewendet, um den gesamten Traffic an den Cluster burst zu senden. Sobald die Anfragen pro Sekunde einen unteren Grenzwert unterschreiten, leiten Sie den gesamten Traffic zurück zu primary.
17. Cross-Cluster-Burst erstellen
Einrichtung
Gesamten Traffic für den Worker-Service an den primären Cluster weiterleiten
Wir betrachten es als „Standardstatus“ unserer Anwendung, wenn der gesamte Traffic, der für worker-service bestimmt ist, an den Cluster primary weitergeleitet wird.
Bearbeiten Sie $proj/istio-manifests/worker-virtualservice.yaml so, dass sie wie folgt aussieht:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
Prüfen Sie, ob Sie mit dem Cluster primary verbunden sind.
kubectx primary
istio-manifests/worker-virtualservice.yaml anwenden
kubectl apply -f istio-manifests/worker-virtualservice.yaml
istiowatcher-Daemon schreiben
Wir verwenden Go, um diesen Dienst zu schreiben, da die Sprache schnell und portabel ist. Der allgemeine Ablauf der Anwendung besteht darin, dass sie gestartet wird und jede Sekunde Prometheus abfragt.
Erstellen Sie im Verzeichnis „src“ ein neues Verzeichnis mit dem Namen „istiowatcher“.
mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher
Wir rufen istioctl aus unserem Container auf, um die Istio-Steuerungsebene innerhalb des Clusters zu bearbeiten.
istiowatcher.go schreiben
Erstellen Sie in diesem Verzeichnis eine Datei mit dem Namen istiowatcher.go und fügen Sie Folgendes ein:
package main
import (
"github.com/tidwall/gjson"
"io/ioutil"
"log"
"net/http"
"os/exec"
"time"
)
func main() {
//These are in requests per second
var targetLow float64 = 10
var targetHigh float64 = 15
// This is for the ticker in milliseconds
ticker := time.NewTicker(1000 * time.Millisecond)
isBurst := false
// Our prometheus query
reqQuery := `/api/v1/query?query=sum(rate(istio_requests_total{reporter="destination",destination_service="worker-service.default.svc.cluster.local",source_workload="frontend-deployment"}[15s]))by(source_workload,source_app,destination_service)`
for t := range ticker.C {
log.Printf("Checking Prometheus at %v", t)
// Check prometheus
// Note that b/c we are querying over the past 5 minutes, we are getting a very SLOW ramp of our reqs/second
// If we wanted this to be a little "snappier" we can scale it down to say 30s
resp, err := http.Get("http://prometheus.istio-system.svc.cluster.local:9090" + reqQuery)
if err != nil {
log.Printf("Error: %v", err)
continue
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
val := gjson.Get(string(body), "data.result.0.value.1")
log.Printf("Value: %v", val)
currentReqPerSecond := val.Float()
log.Printf("Reqs per second %f", currentReqPerSecond)
if currentReqPerSecond > targetHigh && !isBurst {
applyIstio("burst.yaml")
log.Println("Entering burst mode")
isBurst = true
} else if currentReqPerSecond < targetLow && isBurst {
applyIstio("natural.yaml")
log.Println("Returning to natural state.")
isBurst = false
}
}
}
func applyIstio(filename string) {
cmd := exec.Command("istioctl", "replace", "-f", filename)
if err := cmd.Run(); err != nil {
log.Printf("Error hit applying istio manifests: %v", err)
}
}
Dockerfile schreiben
Erstellen Sie eine neue Datei mit dem Namen Dockerfile und fügen Sie Folgendes ein.
FROM golang:1.11.2-stretch as base
FROM base as builder
WORKDIR /workdir
RUN curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
RUN tar xzf istio-1.0.0-linux.tar.gz
RUN cp istio-1.0.0/bin/istioctl ./istioctl
FROM base
WORKDIR /go/src/istiowatcher
COPY . .
COPY --from=builder /workdir/istioctl /usr/local/bin/istioctl
RUN go get -d -v ./...
RUN go install -v ./...
CMD ["istiowatcher"]
In diesem mehrstufigen Dockerfile wird in der ersten Phase die Version 1.0.0 von Istio heruntergeladen und extrahiert. In der zweiten Phase wird alles aus unserem Verzeichnis in das Image kopiert. Anschließend wird istioctl aus der Build-Phase in /usr/local/bin kopiert, damit es von unserer Anwendung aufgerufen werden kann. Außerdem werden die Abhängigkeiten abgerufen, der Code wird kompiliert und CMD wird auf „istiowatcher“ gesetzt.
burst.yaml schreiben
Die Datei istiowatcher wird angewendet, wenn die Anfragen pro Sekunde an worker von frontend 15 überschreiten.
Erstellen Sie eine neue Datei mit dem Namen burst.yaml und fügen Sie Folgendes ein.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 0
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 100
natural.yaml schreiben
Das ist der „natürliche“ Zustand, in den wir zurückkehren, wenn die Anfragen pro Sekunde von frontend an worker unter 10 sinken. In diesem Zustand wird 100% des Traffics an den Cluster primary weitergeleitet.
Erstellen Sie eine neue Datei mit dem Namen natural.yaml und fügen Sie Folgendes ein:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
istiowatcher erstellen und per Push übertragen
Führen Sie den folgenden Befehl aus, um das aktuelle Verzeichnis an Google Cloud Build (GCB) zu senden. Das Image wird dann in GCR erstellt und getaggt.
gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher
istio-watcher bereitstellen
Wechseln Sie in das Verzeichnis kubernetes.
cd ${proj}/kubernetes/
Bereitstellungsdatei schreiben: istiowatcher.yaml
Erstellen Sie eine Datei mit dem Namen istiowatcher.yaml und fügen Sie Folgendes ein (ersetzen Sie <your-project-id>).
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: istiowatcher-deployment
labels:
app: istiowatcher
spec:
replicas: 1
selector:
matchLabels:
app: istiowatcher
template:
metadata:
labels:
app: istiowatcher
spec:
serviceAccountName: istio-pilot-service-account
automountServiceAccountToken: true
containers:
- name: istiowatcher
image: gcr.io/<your-project-id>/istiowatcher
imagePullPolicy: Always
Bereitstellen
Prüfen, ob wir im primären Cluster ausgeführt werden
kubectx primary
istiowatcher.yaml im Namespace istio-system bereitstellen
kubectl apply -n istio-system -f istiowatcher.yaml
Wichtig sind die Direktiven serviceAccountName und automountServiceAccountToken im YAML-Code. Dadurch erhalten wir die Anmeldedaten, die zum Ausführen von istioctl im Cluster erforderlich sind.
Wir müssen diese auch im Namespace istio-system bereitstellen, damit wir die Anmeldedaten für istio-pilot-service-account haben. Sie ist nicht im Namespace default vorhanden.
Sehen Sie zu, wie der Traffic automatisch wechselt.
Jetzt kommt der magische Moment. Gehen wir zum Frontend und erhöhen wir die Anfragen pro Sekunde auf 20.
Es dauert einige Sekunden, bis die Hash-Rate ansteigt, aber alle unsere Hashes haben das Präfix „bursty-“.
Das liegt daran, dass wir Prometheus über den Bereich 15s hinweg abtasten, was zu einer leichten Verzögerung der Reaktionszeit führt. Wenn wir ein viel engeres Band haben möchten, können wir unsere Anfrage an Prometheus in 5s. ändern.
18. Nächste Schritte
Clean-up
Wenn Sie ein temporäres Konto verwenden, das für diesen Workshop bereitgestellt wurde, müssen Sie keine Bereinigung durchführen.
Sie können Ihre Kubernetes-Cluster, die Firewallregel und die Bilder in GCR löschen.
gcloud container clusters delete primary --zone=us-west1-a
gcloud container clusters delete burst --zone=us-west1-a
gcloud compute firewall-rules delete istio-multicluster-test-pods
gcloud container images delete gcr.io/$GCLOUD_PROJECT/istiowatcher
Ausblick
- Sehen Sie sich einige Istio-Vorträge an.
- Zertifizierung: Build Your Next App With Kubernetes + Istio
- Keynote: Kubernetes, Istio, Knative: The New Open Cloud Stack – Aparna Sinha, Group Product Manager for Kubernetes, Google
- Anleitung: Istio verwenden – Lee Calcote und Girish Ranganathan, SolarWinds
- Istio – The Packet's-Eye View – Matt Turner, Tetrate
- Ist Istio die modernste Next-Generation-Firewall, die je entwickelt wurde? – John Morello, Twistlock
- Istio-Dokumentation lesen
- Istio-Arbeitsgruppen beitreten
- @IstioMesh auf Twitter folgen




