1. Witamy
Dziękujemy za udział w ćwiczeniach z wykorzystaniem narzędzia Istio Multi Cloud Burst, które przygotował zespół Google.Ten moduł wymaga praktycznej znajomości Kubernetes, Node i Go na poziomie początkującym. Co będzie potrzebne
|
|
Czego się nauczysz
- Jak utworzyć klaster Kubernetes w GKE
- Instalowanie Istio w klastrze Kubernetes za pomocą Helm
- Instalowanie Istio Multicluster za pomocą Helm
- Wdrażanie aplikacji internetowej z źródła do Kubernetes
- Tworzenie i stosowanie reguł routingu ruchu w Istio
- Wskaźniki Prometheus
- Tworzenie i przesyłanie obrazów kontenerów w klastrze Kubernetes
2. Konfiguracja
Możesz wykonać to ćwiczenie w jednym z tych formatów:
- Google Cloud Shell (zalecane): powłoka w przeglądarce z zainstalowanymi narzędziami.
- laptopa (postępuj zgodnie z instrukcjami poniżej)
Pierwsze kroki z Google Cloud Platform
- Jeśli nie masz konta Google Cloud Platform, poproś instruktora o kartę użytkownika bezpłatnego konta.
- Otwórz konsolę Google Cloud i kliknij „Wybierz projekt”:

- Zanotuj gdzieś „identyfikator” projektu, a potem kliknij projekt, aby go wybrać:

Opcja 1. Użyj Google Cloud Shell (zalecane)
Cloud Shell udostępnia w przeglądarce powłokę wiersza poleceń z zainstalowanymi narzędziami i automatycznie uwierzytelnioną na koncie Google Cloud Platform. (jeśli nie chcesz wykonywać tego ćwiczenia w Cloud Shell, przejdź do następnej sekcji).
Otwórz konsolę Google Cloud i na pasku narzędzi w prawym górnym rogu kliknij „Aktywuj Cloud Shell”:

Dodawanie narzędzi do Cloud Shell
- Zainstaluj
kubectx****: pobierz skrypty basha z tutaj do dowolnej lokalizacji w ścieżce $PATH. - Zainstaluj
helm****: postępuj zgodnie z tymi instrukcjami.
Możesz też użyć tych poleceń, aby zainstalować oba programy w katalogu ~/.bin i dodać je do zmiennej środowiskowej $PATH:
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}
Oto kilka szybkich wskazówek, które ułatwią korzystanie z Cloud Shell:
1. Odłączanie powłoki do nowego okna: |
|
2. Za pomocą edytora plików: kliknij ikonę ołówka w prawym górnym rogu, aby uruchomić edytor plików w przeglądarce. Przyda Ci się to, gdy będziemy kopiować fragmenty kodu do plików. |
|
3. Uruchom nowe karty: jeśli potrzebujesz więcej niż jednego prompta terminala. |
|
4. Powiększ tekst: domyślny rozmiar czcionki w Cloud Shell może być zbyt mały, aby był czytelny. | Ctrl-+ w systemie Linux lub Windows oraz ⌘-+ w systemie macOS. |
Opcja 2. Skonfiguruj laptopa (nie zalecane)
Jeśli wolisz korzystać z własnego środowiska stacji roboczej niż z Cloud Shell, skonfiguruj te narzędzia:
- Zainstaluj
gcloud:(zainstalowany wstępnie w Cloud Shell). Aby zainstalowaćgcloudna swojej platformie, postępuj zgodnie z instrukcjami. Użyjemy go do utworzenia klastra Kubernetes. - Zainstaluj
kubectl:(zainstalowany wstępnie w Cloud Shell). Aby zainstalować:
gcloud components install kubectl
Aby uwierzytelnić się w gcloud, uruchom to polecenie: Pojawi się prośba o zalogowanie się na konto Google. Następnie wybierz utworzony wcześniej projekt (widoczny powyżej) jako projekt domyślny. (możesz pominąć konfigurowanie strefy obliczeniowej):
gcloud init
- Zainstaluj
curl:Wstępnie zainstalowany w większości systemów Linux/macOS. Prawdopodobnie już go masz. W przeciwnym razie wyszukaj w internecie instrukcje instalacji. - Zainstaluj
kubectx****: pobierz skrypty basha z tutaj do katalogu w $PATH. - Zainstaluj
helm****: postępuj zgodnie z tymi instrukcjami.
3. Konfigurowanie projektu GCP
Włącz w projekcie interfejsy GKE (Google Kubernetes Engine), GCR (Google Container Registry) i GCB (Google Cloud Build):
gcloud services enable \ cloudapis.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ cloudbuild.googleapis.com
Konfigurowanie zmiennych środowiskowych
Podczas konfiguracji będziemy intensywnie korzystać z naszego projektu Google Cloud. Aby mieć szybki dostęp do zmiennej środowiskowej,
export GCLOUD_PROJECT=$(gcloud config get-value project)
Podczas tego warsztatu będziemy tworzyć kod i pliki konfiguracji, więc utwórzmy katalog projektu i przejdźmy do niego.
mkdir -p src/istio-burst && \ cd src/istio-burst && \ export proj=$(pwd)
4. Tworzenie „podstawowego” klastra Kubernetes
Za pomocą Google Kubernetes Engine (GKE) możesz łatwo utworzyć zarządzany klaster Kubernetes.
Poniższe polecenie spowoduje utworzenie klastra Kubernetes:
- o nazwie „primary”,
- w strefie us-west1-a,
- najnowsza dostępna wersja Kubernetes,
- z 4 pierwszymi węzłami
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
(może to potrwać około 5 minut). Możesz obserwować tworzenie klastra w konsoli Google Cloud.
Po utworzeniu klastra Kubernetes usługa gcloud konfiguruje kubectl za pomocą danych uwierzytelniających wskazujących na klaster.
gcloud container clusters get-credentials $cluster --zone=$zone
Teraz możesz używać kubectl z nowym klastrem.
Aby wyświetlić listę węzłów Kubernetes klastra (powinny mieć stan „Gotowe”), uruchom to polecenie:
kubectl get nodes
Modyfikowanie nazw plików kubeconfig w celu ułatwienia ich używania
Będziemy często przełączać się między kontekstami, więc krótki alias dla naszych klastrów będzie przydatny.
To polecenie zmieni nazwę utworzonego właśnie wpisu kubeconfig na primary.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
Ustaw uprawnienia:
Aby wdrożyć Istio, musisz być administratorem klastra. To polecenie skonfiguruje adres e-mail powiązany z Twoim kontem Google Cloud jako administratora klastra.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
5. Tworzenie klastra „burst”
Poniższe polecenie spowoduje utworzenie klastra Kubernetes:
- o nazwie „burst”,
- w strefie us-west1-a,
- najnowsza dostępna wersja Kubernetes,
- Z 1 węzłem początkowym
- Autoskalowanie włączone do 5 węzłów
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
(może to potrwać około 5 minut). Możesz obserwować tworzenie klastra w konsoli Google Cloud.
Po utworzeniu klastra Kubernetes usługa gcloud konfiguruje usługę kubectl, podając dane uwierzytelniające wskazujące klaster.
gcloud container clusters get-credentials $cluster --zone=$zone
Teraz możesz używać kubectl z nowym klastrem.
Aby wyświetlić listę węzłów Kubernetes klastra (powinny mieć stan „Gotowe”), uruchom to polecenie:
kubectl get nodes
Modyfikowanie nazw plików kubeconfig w celu ułatwienia ich używania
To polecenie zmodyfikuje właśnie utworzony wpis kubeconfig na burst.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
Ustaw uprawnienia:
Aby wdrożyć Istio Remote, musisz być administratorem klastra. To polecenie spowoduje ustawienie adresu e-mail powiązanego z Twoim kontem Google Cloud jako administratora klastra.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
6. Zastosuj reguły zapory sieciowej
Aby 2 klastery mogły się ze sobą komunikować, musimy utworzyć regułę zapory sieciowej.
Uruchom te polecenia, aby utworzyć na Google Cloud Platform regułę zapory sieciowej, która pozwoli naszym klasterom na komunikację
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
Oba klastry są skonfigurowane i gotowe do wdrożenia aplikacji oraz usługi Istio.
7. Wprowadzenie do Istio
Co to jest Istio?
Istio to platforma sterująca siatką usług, której celem jest „łączenie, zabezpieczanie, kontrolowanie i obserwowanie usług”. Działa on w różne sposoby, ale przede wszystkim poprzez wstawianie kontenera proxy ( Envoy) do każdego z wdrożonych podów Kubernetes. Kontener proxy kontroluje całą komunikację sieciową między mikrousługami w połączeniu z zasadami ogólnymi i hubem telemetrycznym ( Mixer).

Te zasady można stosować niezależnie od wdrożeń i usług Kubernetesa, co oznacza, że operator sieci może obserwować aktywność sieci, ograniczać, przekierowywać lub zmieniać zasady sieci bez ponownego wdrażania powiązanych aplikacji.
Oto niektóre funkcje zarządzania ruchem obsługiwane przez Istio:
- Wyłączniki obwodu
- Podział ruchu na podstawie procentów
- Przepisywanie adresów URL
- zakończenie TLS
- Kontrole stanu
- Równoważenie obciążenia
Na potrzeby tego warsztatu skupimy się na dzieleniu ruchu na podstawie odsetka.
Warunki usługi Istio, z którymi będziemy pracować
VirtualService
VirtualService definiuje zestaw reguł routingu ruchu, które mają zastosowanie, gdy adresowany jest host.
Brama
Brama to system równoważenia obciążenia działający na krawędzi sieci mesh, który odbiera przychodzące lub wychodzące połączenia HTTP/TCP. Bramy mogą określać porty, konfiguracje SNI itp.
DestinationRule
Element DestinationRule definiuje zasady stosowane do ruchu przeznaczonego dla usługi po dokonaniu routingu. Określają one konfigurację równoważenia obciążenia, rozmiar puli połączeń z modułu dodatkowego i ustawienia wykrywania wyników odstających.
Istio Multicluster
Podczas tworzenia naszych 2 klastrów zauważyliśmy, że klaster primary miał 4 węzły bez autoskalowania, a klaster burst miał 1 węzeł z autoskalowaniem do 5 węzłów.
Ta konfiguracja ma 2 przyczyny.
Najpierw chcemy zasymulować przeniesienie środowiska lokalnego do chmury. W środowisku lokalnym nie masz dostępu do klastrów z autoskalowaniem, ponieważ masz stałą infrastrukturę.
Po drugie, konfiguracja z 4 węzłami (zdefiniowana powyżej) to minimalne wymagania do uruchamiania Istio. W związku z tym pojawia się pytanie: jeśli Istio wymaga co najmniej 4 węzłów, jak klaster burst może uruchamiać Istio z 1 węzłem? Odpowiedź brzmi: Istio Multicluster instaluje znacznie mniejszy zestaw usług Istio i komunikuje się z instalacją Istio w klastrze głównym, aby pobrać reguły zasad i opublikować informacje telemetrii.
8. Omówienie architektury aplikacji
Omówienie komponentów
Będziemy wdrażać aplikację 3-poziomową za pomocą NodeJS i Redis.
Worker
Aplikacja robocza została napisana w NodeJS. Nasłuchuje przychodzących żądań HTTP POST, wykonuje na nich operację szyfrowania i, jeśli zdefiniowana jest zmienna środowiskowa o nazwie PREFIX, dołącza do hasha tę wartość. Po obliczeniu wartości szyfru aplikacja wysyła wynik w kanale „calculation” na wskazanym serwerze Redis.
Aby zademonstrować funkcję obsługi wielu klastrów, użyjemy później zmiennej środowiskowej PREFIX.
Informacyjnie: to pakiety używane przez aplikację.
body-parser:Pozwala na analizowanie żądań HTTPcors:Zezwalanie na korzystanie z mechanizmu CORSdotenv:Łatwe parsowanie zmiennych środowiskowychexpress:Łatwy hosting stron internetowychioredis:Biblioteka klienta do komunikacji z bazami danych Redismorgan:Dostarcza uporządkowanego dziennika
Frontend
Nasz front-end to także aplikacja NodeJS, która hostuje stronę internetową za pomocą express. Użytkownik podaje częstotliwość, z jaką ma być wysyłana aplikacja worker. Ta aplikacja subskrybuje też wiadomości na kanale Redis o nazwie „calculation” i wyświetla wyniki na stronie internetowej.
Aplikacja korzysta z tych zależności:
body-parser:Pozwala na analizowanie żądań HTTPdotenv:Łatwe parsowanie zmiennych środowiskowychexpress:Łatwy hosting stron internetowychioredis:Biblioteka klienta do komunikacji z bazami danych Redismorgan:Dostarcza uporządkowanych logówrequest:Zezwalanie na wysyłanie żądań HTTPsocket.io:Umożliwia dwukierunkową komunikację ze strony internetowej na serwer
Ta strona internetowa używa Bootstrap do stylizacji i po uruchomieniu wygląda tak:

Diagram architektury

Diagram wdrożeniowy
Ostateczną wersję aplikacji wdrożymy na 2 klastrach, które utworzyliśmy. W klastrze primary będą zainstalowane wszystkie komponenty (frontend, worker i Redis), ale w klastrze burst będzie zainstalowana tylko aplikacja worker.
Oto diagram przedstawiający 2 klastry. Pola obrysowane na czerwono to usługi Kubernetes, a pola obrysowane na niebiesko to wdrożenia Kubernetes. Żółte pola oznaczają naszą instalację Istio.
Zwróć uwagę, że klaster burst nadal ma wdrożone usługi Redis, mimo że w klastrze nie ma żadnego wdrożenia Redis. Musimy mieć tę usługę w klastrze, aby Kubernetes DNS mógł rozpoznać żądanie, ale gdy żądanie zostanie faktycznie wysłane, Istio Proxy przekieruje je do wdrożenia Redis w klastrze primary.
Ostateczna aplikacja będzie miała dodatkowe wdrożenie działające w klastrze primary o nazwie istiowatcher.. Umożliwi to dynamiczne przekierowywanie ruchu do burst automatycznie, gdy ruch przekroczy określony próg.

9. Tworzenie plików wdrożenia aplikacji
Aby wdrożyć aplikację, musimy utworzyć zestaw plików manifestu Kubernetes.
Przejdź do katalogu głównego projektu i utwórz nowy folder o nazwie kubernetes.
mkdir ${proj}/kubernetes && cd ${proj}/kubernetes
Tworzenie pliku frontend.yaml
Spowoduje to utworzenie zarówno wdrożenia Kubernetes, jak i usługi, aby uzyskać dostęp do obrazu frontendu.
Wstaw te informacje do pliku frontend.yaml.
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
Najważniejsze informacje w Deployment
- Port, na którym ma działać aplikacja, to
8080 - Adres pracownika został ustawiony jako „
http://worker-service”, a Kubernetes użyje wbudowanej funkcji DNS, aby rozpoznać powstałą usługę. - Adresem naszego
REDIS_URLjest „redis-cache-service:6379”, a do rozwiązywania adresów IP będziemy używać wbudowanej w Kubernetes funkcję DNS. - W kontenerze skonfigurowaliśmy też sondy
livenessireadiness, aby poinformować Kubernetes, że kontener jest uruchomiony.
Tworzenie pliku worker-service.yaml
Definicję usługi Kubernetes zapisujemy w osobnym pliku niż definicja wdrożenia, ponieważ będziemy używać tej usługi w różnych klastrach, ale wdrożenie będzie inne dla każdego klastra.
Wstaw te informacje do pliku worker-service.yaml
apiVersion: v1
kind: Service
metadata:
name: worker-service
spec:
type: ClusterIP
selector:
app: worker
ports:
- name: http
port: 80
targetPort: 8081
Tworzenie pliku worker-primary.yaml
Będzie to wdrożenie worker, które prześlemy do klastra głównego.
Wstaw te informacje do pliku worker-primary.yaml.
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"
Zwróć uwagę, że używamy tu tego samego wzorca, podając sondy liveness i readiness oraz podając zmienne środowiskowe PORT i REDIS_URL do użycia przez naszą aplikację.
Kolejną rzeczą, na którą warto zwrócić uwagę w tym wdrożeniu, jest brak zmiennej środowiskowej PREFIX. Oznacza to, że wyniki naszych obliczeń będą zawierać tylko hasze (bez prefiksów).
Ostatnim ważnym punktem tego wdrożenia jest etykieta cluster-type: primary-cluster. Użyjemy tego później, gdy będziemy kierować ruch w wielu klastrach Istio.
Tworzenie pliku redis.yaml
Komunikacja z naszego workera z frontendem odbywa się przez kanał Redis, dlatego musimy wdrożyć aplikację Redis w naszym klastrze.
Wstaw te informacje do pliku redis.yaml
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: {}
To jest wdrożenie półstandardowe aplikacji Redis. Tworzy kontener na podstawie obrazu redis:alpine, udostępnia odpowiednie porty i ustawia sensowne limity zasobów.
Tworzenie pliku redis-service.yaml
Potrzebujemy usługi Kubernetes, aby komunikować się z naszą aplikacją Redis
Wstaw te informacje do pliku redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-cache-service
spec:
type: ClusterIP
selector:
app: redis-cache
ports:
- port: 6379
targetPort: 6379
Usługa o nazwie redis-cache-service ma teraz dostęp do naszego wdrożenia Redis.
10. Wdrażanie aplikacji
Obrazy zostały przesłane do GCR, a pliki manifestu Kubernetes zostały utworzone, więc teraz możesz wdrożyć aplikację i sprawdzić, jak działa.
Aby wdrożyć aplikację, uruchom te polecenia
- Upewnij się, że jesteśmy w prawidłowym gromadzie
kubectx primary
- Wdrażanie pamięci podręcznej Redis
kubectl apply -f redis.yaml
- Wdrażanie usługi Redis
kubectl apply -f redis-service.yaml
- Wdrażanie frontendu
kubectl apply -f frontend.yaml
- Wdrażanie pracownika
kubectl apply -f worker-primary.yaml
- Wdrażanie usługi worker
kubectl apply -f worker-service.yaml
Wdrożyliśmy naszą aplikację w GKE. Gratulacje!
Test
Poczekaj, aż pody będą dostępne online
kubectl get pods -w
Gdy wszystkie pody są w stanie „Uruchomione”, naciśnij Ctrl + 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
Zauważysz, że nie udostępniliśmy interfejsu frontendowego za pomocą LoadBalancera. Dzieje się tak, ponieważ później będziemy uzyskiwać dostęp do aplikacji za pomocą Istio. Aby sprawdzić, czy wszystko działa prawidłowo, użyjemy usługi kubectl port-forward.. Uruchom to polecenie, aby przekierować port 8080 na komputerze lokalnym (lub w Cloud Shell) na port 8080, na którym działa wdrożenie frontend.
kubectl port-forward \
$(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080
Jeśli używasz wersji lokalnej: otwórz przeglądarkę i przejdź do adresu http://localhost:8080.
Jeśli używasz Cloud Shell: kliknij przycisk „Podgląd w przeglądarce” i wybierz „Podgląd na porcie 8080”.

Powinieneś zobaczyć interfejs. Jeśli w polu „Częstotliwość” wpiszesz liczbę, powinny zacząć pojawiać się znaki ukośnikowe.

Gratulacje! Wszystko działa.
Kliknij Ctrl+C, aby zatrzymać przekierowywanie portu.
11. Czyszczenie wdrożonej aplikacji
Zaczniemy stosować Istio w klastrze, a następnie ponownie wdrożymy aplikację, więc najpierw ją wyczyśćmy.
Aby usunąć wszystkie utworzone właśnie wdrożenia i usługi, uruchom te polecenia
- Usuń:
redis-cache-service
kubectl delete -f redis-service.yaml
- Usuń:
redis
kubectl delete -f redis.yaml
- Usuń:
frontend
kubectl delete -f frontend.yaml
- Usuń:
worker
kubectl delete -f worker-primary.yaml
- Usuń:
worker-service
kubectl delete -f worker-service.yaml
12. Instalowanie Istio w klastrze głównym
Pobierz Istio
Wersje Istio są hostowane w GitHub. Poniższe polecenia pobiorą i rozpakują wersję 1.0.0 pakietu istio.
- Przejście do katalogu głównego projektu
cd ${proj}
- Pobieranie archiwum
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
- wyodrębnij i usuń archiwum.
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz
Tworzenie szablonu Istio
Uruchomienie tego polecenia Helm spowoduje utworzenie szablonu do zainstalowania Istio w klastrze.
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
W bieżącym katalogu zostanie utworzony plik o nazwie istio-primary.yaml, który zawiera wszystkie definicje i specyfikacje potrzebne do wdrażania i uruchamiania Istio.
Zwróć uwagę na 2 parametry --set. Dodają one obsługę Prometheus i ServiceGraph do systemu Istio. Użyjemy jej później w tym laboratorium.
Wdrażanie Istio
Aby wdrożyć istio, musisz najpierw utworzyć przestrzeń nazw o nazwie istio-system, w której będą mogły działać wdrożenia i usługi Istio.
kubectl create namespace istio-system
Na koniec zastosuj plik istio-primary.yaml utworzony za pomocą Helm.
kubectl apply -f istio-primary.yaml
Etykieta domyślnej przestrzeni nazw
Istio działa poprzez wstrzyknięcie pomocniczej usługi proxy do każdej z Twoich implementacji. Jest to działanie opcjonalne, dlatego musimy oznaczyć naszą przestrzeń nazw default etykietą istio-injection=enabled, aby Istio mogło automatycznie wstrzyknąć sidecar.
kubectl label namespace default istio-injection=enabled
Gratulacje! Mamy uruchomiony klaster z Istio, który jest gotowy do wdrożenia aplikacji.
13. Wdrażanie aplikacji z zarządzaniem ruchem Istio
Tworzenie plików konfiguracji zarządzania ruchem Istio
Istio działa podobnie do Kubernetes, ponieważ do konfiguracji używa plików yaml. W tym celu musimy utworzyć zestaw plików, które informują Istio, jak udostępniać i przekierowywać ruch.
Utwórz katalog o nazwie istio-manifests i przejdź do niego
mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests
Tworzenie pliku frontend-gateway.yaml
Ten plik udostępnia klaster Kubernetes w sposób podobny do systemu równoważenia obciążenia GKE i kieruje cały ruch przychodzący do naszej usługi front-end.
Utwórz plik o nazwie frontend-gateway.yaml i wstaw ten kod.
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
Tworzenie pliku redis-virtualservice.yaml
Utwórz plik o nazwie redis-virtualservice.yaml i wstaw ten kod
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
Tworzenie pliku worker-virtualservice.yaml
Utwórz plik o nazwie worker-virtualservice.yaml i wstaw ten kod
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
Wdrażanie zasad zarządzania ruchem Istio
Wdrażanie zasad Istio odbywa się w taki sam sposób jak w przypadku innych zasobów Kubernetes, z kubectl apply
- Zastosowanie bramy
kubectl apply -f frontend-gateway.yaml
- Zastosuj naszą usługę Redis VirtualService
kubectl apply -f redis-virtualservice.yaml
- Zastosuj naszą usługę wirtualną Worker
kubectl apply -f worker-virtualservice.yaml
Wdrażanie aplikacji
- Wróć do katalogu
kubernetes
cd ${proj}/kubernetes
- Wdrażanie pamięci podręcznej Redis
kubectl apply -f redis.yaml
- Wdrażanie usługi Redis
kubectl apply -f redis-service.yaml
- Wdrażanie frontendu
kubectl apply -f frontend.yaml
- Wdrażanie pracownika
kubectl apply -f worker-primary.yaml
- Wdrażanie usługi worker
kubectl apply -f worker-service.yaml
Potwierdź
W tej chwili ponownie wdrożyliśmy naszą aplikację w klastrze z Istio i zasadami zarządzania ruchem.
Poczekajmy, aż wszystkie zadania zostaną uruchomione
Gdy wszystkie urządzenia są online, pobierz IngressGateway skonfigurowany w frontend-ingressgateway.yaml
$ 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,
Przejdź do adresu <EXTERNAL-IP> lub użyj polecenia curl, aby wyświetlić frontend.
$ curl 35.199.158.10
<!doctype html>
<html>
<head>
<title>String Hashr</title>
<!-- Bootstrap -->
...
14. Instalowanie Istio w klastrze „burst”
Poświęciliśmy dużo czasu na konfigurowanie i wdrażanie na klastrze primary, ale mamy jeszcze cały inny klaster do wdrożenia.
W tej sekcji musimy pobrać zmienne konfiguracji z obu klastrów, więc zwróć uwagę, do którego klastra odwołuje się każde polecenie.
Tworzenie pliku manifestu Istio Remote
Podobnie jak w przypadku wdrożenia Istio do klastra primary, użyjemy Helma do stworzenia szablonu wdrożenia usługi istio remote do klastra burst. Zanim to zrobimy, musimy uzyskać informacje o naszym klastrze primary
Zbieranie informacji o klastrze podstawowym
Zmień klaster na primary
kubectx primary
Poniższe polecenia umożliwiają pobranie adresów IP różnych podów w klastrze głównym. Są one używane przez Istio Remote do komunikacji z klastrem głównym.
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}')
Tworzenie szablonu zdalnego
Teraz użyjemy helm do utworzenia pliku o nazwie istio-remote-burst.yaml, który następnie możemy wdrożyć do klastra burst.
Zmiana katalogu głównego projektu
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
Instalowanie Istio Remote w klastrze burst
Aby zainstalować Istio w klastrze burst, musimy wykonać te same czynności, co w przypadku instalacji w klastrze primary, ale zamiast pliku istio-remote-burst.yaml musimy użyć pliku istio-remote-burst.yaml.
Zmiana kubecontext na burst
kubectx burst
Tworzenie przestrzeni nazw istio-system
kubectl create ns istio-system
Zastosuj plik istio-burst.yaml
kubectl apply -f istio-remote-burst.yaml
Domyślna przestrzeń nazw etykiety
Ponownie musimy oznaczyć przestrzeń nazw default, aby można było automatycznie wstrzyknąć serwer proxy.
kubectl label namespace default istio-injection=enabled
Gratulacje! W tym momencie skonfigurowaliśmy Istio Remote w klastrze burst. W tej chwili klastry nadal nie mogą się komunikować. Musimy wygenerować plik kubeconfig dla klastra burst, który możemy wdrożyć w klastrze primary, aby je połączyć.
Tworzenie pliku kubeconfig dla klastra „burst”
Przełączanie się na klaster burst
kubectx burst
Konfigurowanie środowiska
Aby utworzyć plik kubeconfig dla klastra, musimy zebrać informacje o tym klastrze.
- Pobieranie nazwy klastra
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
- Pobieranie nazwy serwera klastra
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
- Pobierz nazwę obiektu tajnego urzędu certyfikacji konta usługi
istio-multi
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
- Pobierz dane urzędu certyfikacji zapisane w poprzednim słowie tajnym.
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
- Pobierz token zapisany w poprzednim słowie tajnym.
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)
Tworzenie pliku kubeconfig
Po ustawieniu wszystkich zmiennych środowiskowych musimy utworzyć plik kubeconfig.
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
W bieżącym katalogu zostanie utworzony nowy plik o nazwie burst-kubeconfig, którego klaster primary może używać do uwierzytelniania i zarządzania klastrem burst.
Powrót do klastra podstawowego
kubectx primary
Zastosuj plik kubeconfig do „burstu”, tworząc obiekt tajny i oznaczając go
kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system
Oznacz tajny klucz etykietą, aby Istio wiedziało, że ma go używać do uwierzytelniania w wielu klastrach.
kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system
Gratulacje! Oba klastry są uwierzytelniane i komunikują się ze sobą za pomocą usługi Istio Multicluster. Wdróż aplikację w wielu klastrach
15. Wdrażanie aplikacji w wielu klastrach
Tworzenie wdrożeń
Przejdź do katalogu kubernetes.
cd ${proj}/kubernetes
Utwórz wdrożenie workera dla klastra „burst”: worker-burst.yaml
Utwórz plik o nazwie worker-burst.yaml i wstaw do niego ten kod:
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-"
Zauważ, że jest to prawie identyczne z plikiem worker-primary.yaml, który utworzyliśmy wcześniej. Istnieją 2 kluczowe różnice.
Pierwszą kluczową różnicą jest dodanie zmiennej środowiskowej PREFIX o wartości „bursty-”.
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
Oznacza to, że nasz pracownik w klastrze burst będzie dodawał do wszystkich wysyłanych przez siebie haszy prefiks „bursty-”. Dzięki temu będziemy wiedzieć, że nasza aplikacja działa w wielu klastrach.
Drugą ważną różnicą jest to, że zmieniliśmy etykietę cluster-type w tym wdrożeniu z primary-cluster na burst-cluster.
labels:
app: worker
cluster-type: burst-cluster
Użyjemy tej etykiety później, gdy zaktualizujemy usługę VirtualService.
Modyfikowanie usług Istio
Obecnie nasze usługi Istio nie korzystają z obu naszych wdrożeń. 100% naszego ruchu jest kierowane do klastra „primary” (głównego). Zmieńmy to.
Przejdź do katalogu istio-manifests
cd ${proj}/istio-manifests
Edytowanie pliku worker-virtualservice.yaml w celu uwzględnienia reguł docelowych
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
Dodaliśmy 2 miejsca docelowe do usługi VirtualService. Nadal odwołuje się do tego samego hosta (worker-service.default.svc.cluster.local)), ale 50% ruchu jest kierowane do podzbioru primary, a drugie 50% – do podzbioru burst.
Podzbiór primary to wdrożenia o etykiecie cluster-type: primary-cluster, a podzbiór burst to wdrożenia o etykiecie cluster-type: burst-cluster.
W ten sposób ruch jest dzielony po równo między 2 klastery.
Wdróż na klastrze
Wdróż plik redis-service.yaml do klastra burst
Zmień na plik kubeconfig burst
kubectx burst
Zmień katalog główny projektu
cd ${proj}
Następnie wdróż
Wdróż plik redis-service.yaml w klastrze burst
kubectl apply -f kubernetes/redis-service.yaml
Wdróż plik worker-burst.yaml w klastrze burst
kubectl apply -f kubernetes/worker-burst.yaml
Wdróż plik worker-service.yaml w klastrze burst
kubectl apply -f kubernetes/worker-service.yaml
Stosowanie VirtualServices usługi Istio
Zmień na plik kubeconfig primary
kubectx primary
Następnie Wdróż
kubectl apply -f istio-manifests/worker-virtualservice.yaml
Sprawdzanie działania
Aby sprawdzić, czy działa, otwórz punkt Istio Ingress i zwróć uwagę, że około 50% haszy ma przedrostek „burst-”.

Oznacza to, że rozmawiamy między klastrami. Spróbuj zmienić wagi różnych usług i zastosować plik worker-virtualservice.yaml. To świetny sposób na zrównoważenie ruchu między klastrami, ale co, jeśli możemy zrobić to automatycznie?
16. Korzystanie ze wskaźników Prometheus
Wprowadzenie do Prometheus
Prometheus to pakiet narzędzi do monitorowania i tworzenia alertów systemowych typu open source, który został pierwotnie opracowany w SoundCloud. Utrzymuje on wielowymiarowy model danych z danymi z ciągów czasowych zidentyfikowanymi za pomocą nazwy danych i par klucz-wartość.
Oto schemat architektury Prometheus:

Wdrożony z Prometheusem Istio automatycznie przesyła różne dane do serwera Prometheus. Możemy używać tych danych do dynamicznego zarządzania klastrami.
Poznawanie wskaźników Prometheus
Na początek musimy udostępnić wdrożenie Prometheus.
W GKE otwórz kartę Zadania i przejdź do zadania „prometheus”.

Gdy wyświetlasz szczegóły wdrożenia, kliknij Działania > Udostępnij.

Wybierz przekierowanie na port 9090 i wpisz „System równoważenia obciążenia”.

I wybierz „Odsłonięcie”.
Spowoduje to utworzenie usługi na publicznym adresie IP, którego możemy używać do przeglądania danych Prometheus.
Poczekaj, aż punkt końcowy zacznie działać, a następnie kliknij adres IP obok „Punkty końcowe zewnętrzne”. 
Powinien być teraz widoczny interfejs Prometheus.

Prometheus dostarcza wystarczającej ilości danych, aby stanowił samodzielne narzędzie. Na razie jednak zaczniemy od wskaźnika istio_requests_total.
Wykonywanie tego zapytania zwraca wiele danych. To dane dotyczące wszystkich żądań, które przechodzą przez siatkę usług Istio, a jest ich naprawdę dużo. Zmieńmy wyrażenie, aby zawęzić zakres wyszukiwania do tego, co nas naprawdę interesuje:
żądania, w których usługa docelowa to worker-service.default.svc.cluster.local, a źródło to frontend-deployment, ograniczone do ostatnich 15 sekund;
Zapytanie wygląda tak:
istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]
Dzięki temu mamy do czynienia z łatwiejszym w obsługiwaniu zbiorem danych.

Ale jest trochę gęsty. Chodzi nam o żądania na sekundę, a nie o wszystkie żądania.
Aby to zrobić, możemy użyć wbudowanej funkcji rate.
rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

To nas zbliża do celu, ale te dane musimy jeszcze bardziej zgrupować w logiczną grupę.
Aby to zrobić, możemy użyć słów kluczowych sum i by do zgrupowania i zsumowania wyników.
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! Z serwera Prometheus możemy pobierać dokładne dane, których potrzebujemy.
Nasze ostatnie zapytanie Prometheus
Na podstawie wszystkich informacji, które udało nam się uzyskać, ostatnie zapytanie, jakie musimy przesłać do Prometheus, to
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)
Teraz możemy używać ich interfejsu HTTP API do uzyskiwania danych.
Możemy wysłać do niego zapytanie, przesyłając żądanie HTTP GET w taki sposób.
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\)
Oto przykład odpowiedzi:
{
"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"
]
}
]
}
}
Teraz możemy wyodrębnić wartość danych z pliku JSON.
Czyszczenie
Musimy usunąć usługę, której właśnie użyliśmy do udostępnienia Prometheus. W konsoli Google Cloud Console przejdź do góry utworzonej właśnie usługi i kliknij „Usuń”.

Dalsze kroki:
Po znalezieniu sposobu na wykrycie, jak ruch przemieszcza się przez klaster i z jaką szybkością, następnym krokiem jest napisanie małego pliku binarnego, który okresowo wysyła zapytania do Prometheus. Jeśli liczba żądań na sekundę do worker przekroczy pewien próg, usługa wirtualna pracownika zastosuje różne wagi docelowe w celu wysłania całego ruchu do klastra burst. Gdy liczba żądań na sekundę spadnie poniżej niższego progu, prześlij cały ruch z powrotem do primary.
17. Tworzenie przepustowości w wielu klastrach
Konfiguracja
Ustawianie całego ruchu usługi worker na klastrze głównym
Uważamy, że cały ruch kierowany do worker-service i przekierowywany do klastra primary jest „domyślnym” stanem naszej aplikacji.
Zmień $proj/istio-manifests/worker-virtualservice.yaml tak, aby wyglądał tak:
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
Sprawdź, czy masz połączenie z klastrem primary
kubectx primary
Zastosuj istio-manifests/worker-virtualservice.yaml
kubectl apply -f istio-manifests/worker-virtualservice.yaml
Tworzenie demona istiowatcher
Użyjemy Go do napisania tej usługi ze względu na szybkość i przenośność. Ogólny przebieg działania aplikacji będzie polegał na uruchamianiu i co 2 sekundy wysyłaniu zapytania do Prometheusa.
Utwórz w katalogu src nowy katalog o nazwie istiowatcher.
mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher
Będziemy wywoływać istioctl z poziomu kontenera, aby manipulować płaszczyzną sterowania Istio z poziomu klastra.
Tworzenie pliku istiowatcher.go
Utwórz w tym katalogu plik o nazwie istiowatcher.go i wklej w nim ten kod:
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)
}
}
Tworzenie pliku Dockerfile
Utwórz nowy plik o nazwie Dockerfile i wstaw do niego ten kod.
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"]
Ten wieloetapowy plik Dockerfile pobiera i wyodrębnia wersję 1.0.0 usługi Istio na pierwszym etapie. Drugi etap kopiuje wszystko z naszego katalogu do obrazu, a potem kopiuje istioctl z etapu kompilacji do /usr/local/bin (aby można było go wywołać z naszej aplikacji), pobiera zależności, kompiluje kod i ustawia CMD na „istiowatcher”.
Tworzenie pliku burst.yaml
Ten plik istiowatcher zostanie zastosowany, gdy liczba żądań na sekundę do usługi worker z usługi frontend przekroczy 15.
Utwórz nowy plik o nazwie burst.yaml i wstaw do niego ten kod.
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
Tworzenie pliku natural.yaml
Uważamy, że jest to „naturalny” stan, do którego wracamy, gdy liczba żądań na sekundę w zakresie od frontend do worker spadnie poniżej 10. W tym stanie 100% ruchu jest kierowane do klastra primary.
Utwórz nowy plik o nazwie natural.yaml i wstaw do niego ten kod:
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
Kompilowanie i wypychanie istiowatcher
Uruchom te polecenia, aby wysłać bieżący katalog do Google Cloud Build (GCB), który utworzy obraz i oznaczy go w GCR.
gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher
Wdrażanie istiowatcher
Przejdź do katalogu kubernetes
cd ${proj}/kubernetes/
Utwórz plik wdrożenia: istiowatcher.yaml
Utwórz plik o nazwie istiowatcher.yaml i wstaw następujący kod (zastąp parametr <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
Wdróż
Upewnij się, że działamy w klastrze głównym
kubectx primary
Wdróż istiowatcher.yaml w przestrzeni nazw istio-system
kubectl apply -n istio-system -f istiowatcher.yaml
Zwróć uwagę na dyrektywy serviceAccountName i automountServiceAccountToken w pliku yaml. Dzięki temu mamy dane logowania potrzebne do uruchamiania istioctl w klastrze.
Musimy też wdrożyć to w przestrzeni nazw istio-system, aby mieć pewność, że mamy dane uwierzytelniające dla usługi istio-pilot-service-account. (nie istnieje w przestrzeni nazw default).
Obserwuj automatyczne przełączanie ruchu.
Teraz czas na magiczny moment. Przejdźmy do front-endu i zwiększ liczbę żądań na sekundę do 20.
Zajmie to kilka sekund, ale potem będzie już szybciej. Wszystkie nasze hasze będą miały przedrostek „bursty”.
Wynika to z tego, że próbkujemy dane z Prometheus na podstawie zakresu 15s, co powoduje pewne opóźnienie w czasie odpowiedzi. Jeśli chcemy uzyskać znacznie węższy zakres, możemy zmienić zapytanie w Prometheusie na 5s.
18. Co dalej?
Czyszczenie
Jeśli używasz tymczasowego konta udostępnionego na potrzeby warsztatów, nie musisz niczego usuwać.
Możesz usunąć klastry Kubernetes, regułę zapory sieciowej i obrazy w GCR.
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
Co dalej
- Weź udział w wykładach dotyczących Istio.
- Certyfikat: tworzenie kolejnej aplikacji z Kubernetes i Istio
- Wystąpienie: Kubernetes, Istio, Knative: nowy stos otwartej chmury – Aparna Sinha, menedżer ds. usług zbiorowych w zespole Kubernetes, Google
- Samouczek: korzystanie z Istio – Lee Calcote i Girish Ranganathan, SolarWinds
- Istio – The Packet's-Eye View – Matt Turner, Tetrate
- Czy Istio to najlepsza zapora sieciowa nowej generacji, jaka kiedykolwiek powstała? – John Morello, Twistlock
- Przeczytaj dokumentację Istio.
- Dołącz do grup roboczych Istio.
- Obserwuj konto @IstioMesh na Twitterze.




