1. היי!
תודה שהצטרפתם אלינו ל-codelab בנושא Istio Multi Cloud Burst של Google.כדי להשתתף ב-codelab הזה, נדרש ניסיון מעשי ברמת מתחילים ב-Kubernetes, Node ו-Go. מה צריך
|
|
מה תלמדו
- איך יוצרים אשכול Kubernetes ב-GKE
- איך מתקינים את Istio באשכול Kubernetes באמצעות Helm
- איך מתקינים Istio Multicluster באמצעות Helm
- פריסת אפליקציית אינטרנט מקוד מקור ב-Kubernetes
- כתיבה והחלה של כללי ניתוב תנועה ב-Istio
- מדדים של Prometheus
- איך יוצרים תמונות של קונטיינרים ומעבירים אותן לתוך אשכול Kubernetes
2. תהליך ההגדרה
אפשר לנסות את ה-Codelab הזה באחת מהדרכים הבאות:
- Google Cloud Shell (מומלץ): מעטפת (shell) בדפדפן, כולל כלים מותקנים
- במחשב הנייד (פועלים לפי ההוראות שבהמשך)
צעדים ראשונים עם Google Cloud Platform
- אם אין לכם חשבון GCP, תוכלו לקבל כרטיס עם פרטי חשבון משתמש בחינם מהמדריך.
- נכנסים אל מסוף Google Cloud ולוחצים על 'בחירת פרויקט':

- רושמים בצד את המזהה של הפרויקט, ואז לוחצים על הפרויקט כדי לבחור אותו:

אפשרות 1: שימוש ב-Google Cloud Shell (מומלץ)
Cloud Shell מספקת מעטפת של שורת פקודה בתוך הדפדפן, עם הכלים שאתם צריכים מותקנים ומאומתים אוטומטית בחשבון שלכם ב-Google Cloud Platform. (אם אתם לא רוצים להריץ את התרגיל הזה ב-Cloud Shell, אתם יכולים לדלג לקטע הבא).
עוברים אל Cloud Console ולוחצים על 'הפעלת Cloud Shell' בסרגל הכלים שבפינה הימנית העליונה:

הוספת כלים ל-Cloud Shell
- התקנה
kubectx****: מורידים את סקריפטים של bash מכאן למיקום ב- $PATH. - התקנה של
helm****: פועלים לפי ההוראות האלה.
אפשר גם להריץ את הפקודות האלה כדי להתקין את שניהם ב-~/.bin ולהוסיף אותו ל-$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}
כמה טיפים מהירים שיכולים להקל על השימוש ב-Cloud Shell:
1. מנתקים את המעטפת לחלון חדש: |
|
2. באמצעות כלי לעריכת קבצים: לוחצים על סמל העיפרון בפינה השמאלית העליונה כדי להפעיל כלי לעריכת קבצים בדפדפן. הפעולה הזו תהיה שימושית בהמשך, כשנעתיק קטעי קוד לקבצים. |
|
3. לפתוח כרטיסיות חדשות: אם אתם צריכים יותר מהנחיות טרמינל אחת. |
|
4. הגדלת הטקסט: גודל הגופן שמוגדר כברירת מחדל ב-Cloud Shell יכול להיות קטן מדי לקריאה. | Ctrl-+ ב-Linux/Windows או ⌘-+ ב-macOS. |
אפשרות 2: הגדרת המחשב הנייד (לא מומלץ)
אם אתם מעדיפים להשתמש בסביבת תחנת העבודה שלכם במקום ב-Cloud Shell, אתם צריכים להגדיר את הכלים הבאים:
- מתקינים את
gcloud:(האפליקציה מותקנת מראש ב-Cloud Shell). פועלים לפי ההוראות כדי להתקין אתgcloudבפלטפורמה. נשתמש בזה כדי ליצור אשכול Kubernetes. - התקנה של
kubectl:(מותקן מראש ב-Cloud Shell). מריצים את הפקודה הבאה כדי להתקין:
gcloud components install kubectl
מריצים את הפקודה הבאה כדי לבצע אימות של gcloud. תתבקשו להתחבר לחשבון Google. לאחר מכן, בוחרים את הפרויקט שנוצר מראש (כמו שמופיע למעלה) כפרויקט ברירת המחדל. (אפשר לדלג על הגדרת אזור מחשוב):
gcloud init
- התקנה
curl:מותקן מראש ברוב מערכות Linux/macOS. סביר להניח שכבר יש לכם אותו. אחרת, חפשו באינטרנט הוראות להתקנה. - התקנה של
kubectx****: מורידים את סקריפטים של Bash מכאן למיקום ב-$PATH - התקנה של
helm****: פועלים לפי ההוראות האלה.
3. הגדרת פרויקט GCP
מפעילים את ממשקי ה-API של GKE (Google Kubernetes Engine), GCR (Google Container Registry) ו-GCB (Google Cloud Build) בפרויקט:
gcloud services enable \ cloudapis.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ cloudbuild.googleapis.com
הגדרה של משתני סביבה
במהלך ההגדרה נעבוד הרבה עם פרויקט בענן של Google שלנו, לכן כדאי להגדיר משתנה סביבה כדי שנוכל להתייחס אליו במהירות.
export GCLOUD_PROJECT=$(gcloud config get-value project)
במהלך הסדנה הזו ניצור קוד וקבצי הגדרה, אז בואו ניצור ספריית פרויקט ונעבור אליה
mkdir -p src/istio-burst && \ cd src/istio-burst && \ export proj=$(pwd)
4. יצירת אשכול Kubernetes 'ראשי'
אפשר ליצור בקלות אשכול Kubernetes מנוהל באמצעות Google Kubernetes Engine (GKE).
הפקודה הבאה תיצור אשכול Kubernetes:
- בשם 'primary',
- באזור us-west1-a,
- הגרסה האחרונה של Kubernetes שזמינה,
- עם 4 צמתים ראשוניים
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
(התהליך עשוי להימשך כ-5 דקות. אפשר לצפות בתהליך יצירת האשכול במסוף Cloud.)
אחרי שיוצרים את אשכול Kubernetes, gcloud מגדיר את kubectl עם פרטי הכניסה שמפנים לאשכול.
gcloud container clusters get-credentials $cluster --zone=$zone
עכשיו אמורה להיות לך אפשרות להשתמש ב-kubectl עם האשכול החדש.
מריצים את הפקודה הבאה כדי להציג את צמתי Kubernetes של האשכול (הסטטוס שלהם צריך להיות Ready):
kubectl get nodes
שינוי שמות של Kubeconfig לשימוש קל
אנחנו נעבור בין הקשרים לעיתים קרובות, ולכן כדאי שיהיה כינוי קצר לאשכולות שלנו.
הפקודה הזו תשנה את השם של רשומת ה-kubeconfig שיצרתם ל-primary
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
הגדרת הרשאות:
כדי לפרוס את Istio, צריך להיות אדמין של אשכול. הפקודה הזו תגדיר את כתובת האימייל שמשויכת לחשבון Google Cloud שלכם כאדמין של האשכול
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
5. יצירת אשכול 'burst'
הפקודה הבאה תיצור אשכול Kubernetes:
- בשם burst,
- באזור us-west1-a,
- הגרסה האחרונה של Kubernetes שזמינה,
- עם צומת התחלתי אחד
- התאמה אוטומטית לעומס מופעלת עד 5 צמתים
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
(התהליך עשוי להימשך כ-5 דקות. אפשר לצפות בתהליך יצירת האשכול במסוף Cloud.)
אחרי שיוצרים את אשכול Kubernetes, gcloud מגדיר את kubectl עם פרטי הכניסה שמפנים לאשכול.
gcloud container clusters get-credentials $cluster --zone=$zone
עכשיו אמורה להיות לך אפשרות להשתמש ב-kubectl עם האשכול החדש.
מריצים את הפקודה הבאה כדי להציג את צמתי Kubernetes של האשכול (הסטטוס שלהם צריך להיות Ready):
kubectl get nodes
שינוי שמות של Kubeconfig לשימוש קל
הפקודה הזו תשנה את רשומת ה-kubeconfig שיצרתם ל-burst
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
הגדרת הרשאות:
כדי לפרוס את Istio Remote, צריך להיות אדמין של האשכול. הפקודה הזו תגדיר את כתובת האימייל שמשויכת לחשבון Google Cloud שלכם כאדמין של האשכול
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
6. החלת כללים לחומת האש
כדי ששני האשכולות שלנו יוכלו לתקשר ביניהם, נצטרך ליצור כלל בחומת האש.
מריצים את הפקודות הבאות כדי ליצור כלל בחומת האש ב-Google Cloud Platform שיאפשר תקשורת בין האשכולות שלנו
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
הגדרנו את שני האשכולות ואנחנו מוכנים לפרוס עליהם את האפליקציה ואת Istio.
7. מבוא ל-Istio
מה זה Istio?
Istio הוא רמת בקרה של Service mesh שמטרתה 'חיבור, אבטחה, בקרה ומעקב אחרי שירותים'. היא עושה זאת במגוון דרכים, אבל בעיקר על ידי הוספת קונטיינר פרוקסי ( Envoy) לכל אחד מה-Pods של Kubernetes שנפרסו. קונטיינר ה-proxy שולט בכל התקשורת ברשת בין המיקרו-שירותים, בשילוב עם מרכז מדיניות וטלמטריה לשימוש כללי ( Mixer).

אפשר להחיל את המדיניות הזו באופן עצמאי על פריסות ושירותים של Kubernetes, כלומר מפעיל הרשת יכול לצפות בפעילות הרשת, להגביל, להפנות מחדש או לשכתב את מדיניות הרשת בלי לפרוס מחדש את האפליקציות המשויכות.
חלק מהתכונות של ניהול התנועה ש-Istio תומך בהן:
- מפסקים חשמליים
- חלוקת תנועה על סמך אחוזים
- שכתוב כתובות URL
- סיום TLS
- בדיקות תקינות
- איזון עומסים
בסדנה הזו נתמקד בפיצול תנועה על בסיס אחוזים.
מונחים של Istio שבהם נשתמש
VirtualService
VirtualService מגדיר קבוצה של כללים להפניית תנועה שמוחלים כשמפנים בקשה למארח.
Gateway
שער הוא מאזן עומסים שפועל בקצה של רשת ה-mesh ומקבל חיבורי HTTP/TCP נכנסים או יוצאים. שערי VPN יכולים לציין יציאות, הגדרות SNI וכו'.
DestinationRule
DestinationRule מגדיר מדיניות שחלה על תנועה שמיועדת לשירות אחרי הניתוב. הם מציינים את ההגדרה לאיזון עומסים, את הגודל של מאגר החיבורים מ-sidecar ואת ההגדרות של זיהוי חריגים.
Istio Multicluster
יכול להיות ששמתם לב כשיצרנו את שני האשכולות, שאשכול primary היה 4 צמתים ללא התאמה אוטומטית לעומס, ואשכול burst היה צומת אחד עם התאמה אוטומטית לעומס עד 5 צמתים.
יש שתי סיבות להגדרה הזו.
קודם כל, נרצה לדמות תרחיש של העברה משרת מקומי לענן. בסביבה מקומית אין לכם גישה לאשכולות של התאמה אוטומטית לעומס, כי התשתית קבועה.
שנית, הגדרה של 4 צמתים (כפי שמוגדר למעלה) היא דרישת המינימום להרצת Istio. מכאן עולה השאלה: אם Istio דורש מינימום של 4 צמתים, איך יכול אשכול burst שלנו להריץ את Istio עם צומת אחד? התשובה היא ש-Istio Multicluster מתקין קבוצה קטנה בהרבה של שירותי Istio, ומתקשר עם התקנת Istio באשכול הראשי כדי לאחזר את כללי המדיניות ולפרסם מידע טלמטרי.
8. סקירה כללית על ארכיטקטורת אפליקציות
סקירה כללית של הרכיבים
נפרוס אפליקציה תלת-שכבתית באמצעות NodeJS ו-Redis.
Worker
אפליקציית העובד כתובה ב-NodeJS והיא תאזין לבקשות HTTP POST נכנסות, תבצע עליהן פעולת גיבוב, ואם מוגדר משתנה סביבה בשם PREFIX, היא תוסיף את הערך הזה לפני הגיבוב. אחרי שהערך הגיבוב מחושב, האפליקציה שולחת את התוצאה בערוץ calculation בשרת Redis שצוין.
בהמשך נשתמש במשתנה הסביבה PREFIX כדי להדגים את הפונקציונליות של ריבוי אשכולות.
לעיון: אלה החבילות שבהן האפליקציה משתמשת.
-
body-parser:מאפשר לנו לנתח את בקשות ה-HTTP שלנו -
cors:מאפשר שימוש בשיתוף משאבים בין מקורות dotenv:ניתוח קל של משתני סביבהexpress:אירוח אתרים פשוטioredis:ספריית לקוח לתקשורת עם מסדי נתונים של Redismorgan:מספק יומן מובנה ונוח
Frontend
הקצה הקדמי שלנו הוא גם אפליקציית NodeJS שמארחת דף אינטרנט באמצעות express. הכלי מקבל תדירות שהמשתמש מזין ושולח בקשות לאפליקציית worker שלנו בתדירות הזו. האפליקציה הזו גם נרשמת לקבלת הודעות בערוץ Redis בשם calculation ומציגה את התוצאות בדף אינטרנט.
האפליקציה משתמשת ביחסי התלות הבאים.
-
body-parser:מאפשר לנו לנתח את בקשות ה-HTTP שלנו dotenv:ניתוח קל של משתני סביבהexpress:אירוח אתרים פשוטioredis:ספריית לקוח לתקשורת עם מסדי נתונים של Redismorgan:יומנים מובְנים ונוחיםrequest:הרשאה ליצירת בקשות HTTPsocket.io:מאפשר תקשורת דו-כיוונית מדף האינטרנט לשרת
דף האינטרנט הזה משתמש ב-Bootstrap לעיצוב, וכשהוא מופעל הוא נראה כך:

תרשים ארכיטקטורה

Deployment Diagram
נפרוס את האפליקציה הסופית בשני האשכולות שיצרנו. כל הרכיבים (frontend, worker ו-Redis) יפרסו באשכול primary, אבל רק האפליקציה worker תפרוס באשכול burst.
התרשים הבא מתאר את שני האשכולות. התיבות שמסומנות בקו אדום הן שירותי Kubernetes, והתיבות שמסומנות בקו כחול הן פריסות Kubernetes. התיבות הצהובות מסמלות את ההתקנה של Istio.
שימו לב שלקלאסטר burst עדיין יש שירות ל-Redis שפרוס בו, למרות שאין פריסה של Redis בקלאסטר. אנחנו צריכים את השירות הזה באשכול כדי ש-Kubernetes DNS יוכל לפתור את הבקשה, אבל כשהבקשה מוגשת בפועל, Istio Proxy ינתב מחדש את הבקשה לפריסת Redis באשכול primary.
באפליקציה הסופית תפעל פריסה נוספת באשכול primary שנקרא istiowatcher.. הפריסה הזו תאפשר לנו לנתב מחדש את התנועה אל burst באופן דינמי ואוטומטי כשהתנועה תעבור סף מסוים.

9. יצירת קובצי פריסה של אפליקציות
אנחנו צריכים ליצור קבוצה של מניפסטים של Kubernetes כדי לפרוס את האפליקציה שלנו
עוברים לספריית הבסיס של הפרויקט ויוצרים תיקייה חדשה בשם kubernetes
mkdir ${proj}/kubernetes && cd ${proj}/kubernetes
כתיבת הקובץ frontend.yaml
הפעולה הזו תיצור גם Kubernetes Deployment וגם Service כדי לגשת לקובץ האימג' של קצה קדמי.
מכניסים את הקוד הבא ל-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
דברים חשובים שכדאי לשים לב אליהם בDeployment
- ציינו שהיציאה שבה האפליקציה תפעל היא
8080 - הגדרנו את הכתובת של העובד כ-
http://worker-serviceונשתמש בתכונת ה-DNS המובנית של Kubernetes כדי לפתור את השירות שמתקבל - הגדרנו את הכתובת של
REDIS_URLלהיותredis-cache-service:6379ונשתמש בתכונת ה-DNS המובנית של Kubernetes כדי לפענח את כתובות ה-IP שמתקבלות. - הגדרנו גם בדיקות
livenessו-readinessלקונטיינר כדי לעדכן את Kubernetes כשהקונטיינר פועל.
כתיבה של worker-service.yaml
אנחנו כותבים את הגדרת שירות Kubernetes בקובץ נפרד מהגדרת הפריסה, כי נשתמש בשירות הזה מחדש בכמה אשכולות, אבל נכתוב פריסה שונה לכל אשכול.
מזינים את הפרטים הבאים ב-worker-service.yaml
apiVersion: v1
kind: Service
metadata:
name: worker-service
spec:
type: ClusterIP
selector:
app: worker
ports:
- name: http
port: 80
targetPort: 8081
כתיבת הקובץ worker-primary.yaml
זו תהיה הפריסה של worker שנדחוף לאשכול הראשי.
מכניסים את הקוד הבא ל-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"
שימו לב שאנחנו פועלים לפי אותו דפוס של אספקת בדיקות liveness ו-readiness, וגם מציינים את משתני הסביבה PORT ו-REDIS_URL לשימוש באפליקציה שלנו.
עוד דבר שחשוב לשים לב אליו בפריסה הזו הוא שמשתנה הסביבה PREFIX לא מוגדר. המשמעות היא שתוצאות החישוב שלנו יהיו גיבובים גולמיים (ללא קידומת).
נקודת המפתח האחרונה בפריסה הזו היא התווית cluster-type: primary-cluster. נשתמש בזה בהמשך כשנעשה ניתוב תנועה ב-Istio Multicluster
כתיבת redis.yaml
התקשורת מה-worker בחזרה לקצה הקדמי מתבצעת דרך ערוץ Redis, ולכן אנחנו צריכים לפרוס אפליקציית Redis באשכול שלנו.
הוספת הקוד הבא אל 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: {}
זהו פריסה חצי סטנדרטית של אפליקציית Redis. הוא יוצר קונטיינר שמבוסס על תמונת redis:alpine, חושף את הפורטים המתאימים ומגדיר מגבלות משאבים הגיוניות.
כתיבת redis-service.yaml
אנחנו צריכים שירות Kubernetes כדי לתקשר עם אפליקציית Redis
הוספת הקוד הבא אל redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-cache-service
spec:
type: ClusterIP
selector:
app: redis-cache
ports:
- port: 6379
targetPort: 6379
השירות הזה נקרא redis-cache-service ויש לו גישה לפריסת Redis שלנו.
10. פריסת האפליקציה
אחרי שהעברנו את התמונות ל-GCR וכתבנו את המניפסטים של Kubernetes, זה הזמן המתאים לפרוס את האפליקציה ולראות איך היא פועלת.
מריצים את הפקודות הבאות כדי לפרוס את האפליקציה
- מוודאים שאנחנו באשכול הנכון
kubectx primary
- פריסת מטמון Redis
kubectl apply -f redis.yaml
- פריסת שירות Redis
kubectl apply -f redis-service.yaml
- פריסת הקצה הקדמי
kubectl apply -f frontend.yaml
- פריסת העובד
kubectl apply -f worker-primary.yaml
- פריסת שירות העובד
kubectl apply -f worker-service.yaml
פרסנו את האפליקציה שלנו ב-GKE. מזל טוב!
בדיקה
מחכים עד שהפודים יעלו לאונליין
kubectl get pods -w
אחרי שכל הפודים במצב Running, לוחצים על 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
אפשר לראות שלא חשפנו את קצה קדמי שלנו דרך LoadBalancer. הסיבה לכך היא שבהמשך ניגש לאפליקציה דרך Istio. כדי לבדוק שהכול פועל, נשתמש ב-kubectl port-forward.. מריצים את הפקודה הבאה כדי להעביר את היציאה 8080 במחשב המקומי (או ב-Cloud Shell) ליציאה 8080 שבה פועל הפריסה של frontend.
kubectl port-forward \
$(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080
אם מריצים באופן מקומי: פותחים דפדפן אינטרנט ועוברים אל http://localhost:8080
אם אתם מריצים את הפקודה ב-Cloud Shell: לוחצים על הלחצן 'תצוגה מקדימה באינטרנט' ובוחרים באפשרות 'תצוגה מקדימה ביציאה 8080'.

החלק הקדמי של האתר אמור להופיע. אם מזינים מספר בתיבה 'תדירות', אמורים להופיע סימני סולמית

מזל טוב, הכול מוכן!
לוחצים על Ctrl+C כדי להפסיק את העברת המספר.
11. ניקוי אפליקציה שנפרסה
אנחנו הולכים להחיל את Istio על האשכול שלנו ואז לפרוס מחדש את האפליקציה, אז קודם ננקה את האפליקציה הנוכחית.
מריצים את הפקודות הבאות כדי למחוק את כל הפריסות והשירותים שיצרתם
- מחיקת
redis-cache-service
kubectl delete -f redis-service.yaml
- מחיקת
redis
kubectl delete -f redis.yaml
- מחיקת
frontend
kubectl delete -f frontend.yaml
- מחיקת
worker
kubectl delete -f worker-primary.yaml
- מחיקת
worker-service
kubectl delete -f worker-service.yaml
12. התקנת Istio באשכול הראשי
קבלת Istio
הגרסאות של Istio מתארחות ב-GitHub. הפקודות הבאות יורידו את גרסה 1.0.0 של istio ויחלצו אותה.
- מעבר לשורש של הפרויקט
cd ${proj}
- הורדת הארכיון
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
- חילוץ והסרה של הארכיון
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz
יצירת תבנית Istio
הפעלת פקודת Helm הבאה תיצור את התבנית להתקנת Istio באשכול.
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
פעולה זו יוצרת קובץ בשם istio-primary.yaml בתיקייה הנוכחית, שמכיל את כל ההגדרות והמפרטים שנדרשים לפריסה ולהרצה של Istio.
שימו לב לשני הפרמטרים --set. התוספים האלה מוסיפים תמיכה ב-Prometheus וב-ServiceGraph למערכת Istio. נשתמש בשירות Prometheus בהמשך שיעור ה-Lab.
פריסת Istio
כדי לפרוס את Istio, צריך קודם ליצור מרחב שמות בשם istio-system שבו אפשר להריץ את הפריסות והשירותים של Istio.
kubectl create namespace istio-system
ולבסוף, מפעילים את קובץ istio-primary.yaml שיצרנו באמצעות Helm.
kubectl apply -f istio-primary.yaml
מרחב שמות של תוויות ברירת מחדל
Istio פועל על ידי הזרקת שירות פרוקסי של קובץ עזר חיצוני לכל אחד מהפריסות שלכם. הפעולה הזו מתבצעת על בסיס הסכמה, ולכן אנחנו צריכים להוסיף את התווית istio-injection=enabled למרחב השמות default כדי ש-Istio יוכל להוסיף אוטומטית את ה-sidecar בשבילנו.
kubectl label namespace default istio-injection=enabled
מזל טוב! יש לנו אשכול פעיל עם Istio, ואנחנו מוכנים לפרוס את האפליקציה שלנו.
13. פריסת האפליקציה שלנו באמצעות ניהול תנועה ב-Istio
יצירת קובצי הגדרות לניהול תעבורה ב-Istio
Istio פועל באופן דומה ל-Kubernetes, כי הוא משתמש בקובצי yaml להגדרה. לכן, אנחנו צריכים ליצור קבוצה של קבצים שמסבירים ל-Istio איך לחשוף את התנועה שלנו ולנתב אותה.
יוצרים ספרייה בשם istio-manifests ועוברים אליה
mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests
כתיבת הקובץ frontend-gateway.yaml
הקובץ הזה יחשוף את אשכול Kubernetes שלנו באופן דומה ל-GKE LoadBalancer, וינתב את כל התעבורה הנכנסת לשירות הקצה הקדמי שלנו.
יוצרים קובץ בשם frontend-gateway.yaml ומזינים את התוכן הבא.
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
יוצרים קובץ בשם redis-virtualservice.yaml ומזינים בו את התוכן הבא
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
יוצרים קובץ בשם worker-virtualservice.yaml ומזינים בו את התוכן הבא
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
פריסת כללי המדיניות של Istio מתבצעת באותו אופן כמו פריסה של משאבי Kubernetes אחרים, באמצעות kubectl apply
- החלת השער שלנו
kubectl apply -f frontend-gateway.yaml
- החלת Redis VirtualService
kubectl apply -f redis-virtualservice.yaml
- החלת Worker VirtualService
kubectl apply -f worker-virtualservice.yaml
פריסת האפליקציה
- חזרה לספרייה
kubernetesשלנו
cd ${proj}/kubernetes
- פריסת מטמון Redis
kubectl apply -f redis.yaml
- פריסת שירות Redis
kubectl apply -f redis-service.yaml
- פריסת הקצה הקדמי
kubectl apply -f frontend.yaml
- פריסת העובד
kubectl apply -f worker-primary.yaml
- פריסת שירות העובד
kubectl apply -f worker-service.yaml
אימות
בשלב הזה, פרסנו מחדש את האפליקציה שלנו באשכול עם Istio ומדיניות לניהול תנועה.
צריך לחכות עד שכל עומסי העבודה יהיו אונליין
אחרי שכולם מחוברים, מקבלים את IngressGateway שהגדרנו ב-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,
אפשר לעבור לכתובת <EXTERNAL-IP> או להשתמש בפקודה curl כדי לראות את ממשק הקצה.
$ curl 35.199.158.10
<!doctype html>
<html>
<head>
<title>String Hashr</title>
<!-- Bootstrap -->
...
14. התקנת Istio באשכול 'burst'
הקדשנו הרבה זמן להגדרה ולפריסה באשכול primary שלנו, אבל יש לנו עוד אשכול שלם לפרוס בו!
בקטע הזה נצטרך לאחזר משתני הגדרה משני האשכולות, לכן חשוב לשים לב לאשכול שאליו אנחנו מפנים כל פקודה.
יצירת מניפסט Istio Remote
בדומה לפריסת Istio באשכול primary, נשתמש ב-Helm כדי ליצור תבנית לפריסת Istio מרחוק באשכול burst. לפני שנוכל לעשות זאת, אנחנו צריכים לקבל מידע על אשכול primary שלנו
איסוף מידע על האשכול הראשי
שינוי לאשכול primary
kubectx primary
הפקודות הבאות מאחזרות את כתובות ה-IP של פודים שונים באשכול הראשי. הם משמשים את Istio Remote כדי לתקשר עם האשכול הראשי.
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}')
יצירת תבנית מרחוק
עכשיו נשתמש ב-helm כדי ליצור קובץ בשם istio-remote-burst.yaml, שאותו נוכל לפרוס באשכול burst.
שינוי לשורש הפרויקט
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 באשכול Burst
כדי להתקין את Istio באשכול burst, צריך לפעול לפי אותם השלבים כמו בהתקנה באשכול primary, אבל צריך להשתמש בקובץ istio-remote-burst.yaml.
שינוי kubecontext ל-burst
kubectx burst
יצירת מרחב השמות istio-system
kubectl create ns istio-system
החלת istio-burst.yaml
kubectl apply -f istio-remote-burst.yaml
מרחב השמות שמוגדר כברירת מחדל לתווית
שוב, אנחנו צריכים לתייג את מרחב השמות default כדי שה-proxy יוזרק באופן אוטומטי.
kubectl label namespace default istio-injection=enabled
מזל טוב! בשלב הזה הגדרנו את Istio Remote באשכול burst. אבל בשלב הזה, עדיין אין אפשרות לתקשר בין האשכולות. אנחנו צריכים ליצור קובץ kubeconfig עבור אשכול burst שאפשר לפרוס לאשכול primary כדי לקשר ביניהם.
יצירת kubeconfig עבור אשכול 'burst'
מעבר לאשכול עם ניהול תעבורה זמני
kubectx burst
הגדרת הסביבה
כדי ליצור קובץ kubeconfig עבור האשכול, אנחנו צריכים לאסוף מידע מסוים לגבי האשכול.
- אחזור שם האשכול
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
- אחזור שם השרת של האשכול
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
- קבלת השם של הסוד עבור רשות האישורים של חשבון השירות
istio-multi
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
- קבלת נתונים של רשות אישורים שמאוחסנים בסוד הקודם
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
- קבלת האסימון שמאוחסן בסוד הקודם
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)
יצירת קובץ kubeconfig
אחרי שמגדירים את כל משתני הסביבה האלה, צריך ליצור את קובץ ה-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
ייווצר קובץ חדש בשם burst-kubeconfig בספרייה הנוכחית, שאפשר להשתמש בו כדי לאמת את אשכול burst ולנהל אותו באמצעות אשכול primary.
חזרה לקלאסטר הראשי
kubectx primary
החלת kubeconfig ל-burst על ידי יצירת סוד ותיוגו
kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system
מתן תווית לסוד כדי ש-Istio יידע להשתמש בו לאימות בין כמה אשכולות
kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system
מזל טוב! אימתנו את שני האשכולות והם מתקשרים זה עם זה באמצעות Istio Multicluster. פריסת האפליקציה באשכולות
15. פריסת אפליקציה בין אשכולות
יצירת פריסות
עוברים לספרייה kubernetes
cd ${proj}/kubernetes
יצירת פריסת עובדים עבור אשכול 'burst': worker-burst.yaml
יוצרים קובץ בשם worker-burst.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: 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-"
שימו לב שהקובץ הזה כמעט זהה לקובץ worker-primary.yaml שיצרנו קודם. יש שני הבדלים עיקריים.
ההבדל העיקרי הראשון הוא שהוספנו את משתנה הסביבה PREFIX עם הערך bursty-
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
כלומר, העובד באשכול burst יוסיף את הקידומת bursty- לכל הגיבובים שהוא שולח. נוכל להשתמש בזה כדי לדעת שהאפליקציה שלנו היא באמת חוצת-אשכולות.
ההבדל השני הוא ששינינו את התווית cluster-type בפריסה הזו מ-primary-cluster ל-burst-cluster
labels:
app: worker
cluster-type: burst-cluster
נשתמש בתווית הזו בהמשך כשנעדכן את VirtualService.
שינוי שירותי Istio
נכון לעכשיו, שירותי Istio שלנו לא מנצלים את שני הפריסות. 100% מהתנועה שלנו מנותבת לאשכול 'הראשי'. אני רוצה לשנות.
עוברים לספרייה istio-manifests
cd ${proj}/istio-manifests
עריכת הקובץ worker-virtualservice.yaml כדי לכלול בו DestinationRules
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
אפשר לראות שהוספנו יעד שני ל-VirtualService. הוא עדיין מפנה לאותו מארח (worker-service.default.svc.cluster.local)), אבל 50% מהתנועה מנותבים לקבוצת המשנה primary ו-50% מהתנועה מנותבים לקבוצת המשנה burst.
הגדרנו את קבוצת המשנה primary כפריסות עם התווית cluster-type: primary-cluster ואת קבוצת המשנה burst כפריסות עם התווית cluster-type: burst-cluster.
בפועל, התנועה מחולקת באופן שווה בין שני האשכולות.
פריסה באשכול
פריסת redis-service.yaml באשכול burst
שינוי ל-burst kubeconfig
kubectx burst
שינוי לשורש הפרויקט
cd ${proj}
ואז פורסים
פריסת redis-service.yaml באשכול burst
kubectl apply -f kubernetes/redis-service.yaml
פריסת worker-burst.yaml לאשכול burst
kubectl apply -f kubernetes/worker-burst.yaml
פריסת worker-service.yaml לאשכול burst
kubectl apply -f kubernetes/worker-service.yaml
החלת Istio VirtualServices
שינוי ל-primary kubeconfig
kubectx primary
ואז פורסים
kubectl apply -f istio-manifests/worker-virtualservice.yaml
אימות הפעולה
כדי לוודא שהיא פועלת, עוברים לנקודת הכניסה של Istio ורואים שכ-50% מהגיבובים מתחילים ב-burst-.

המשמעות היא שהתקשורת בין האשכולות מתבצעת בהצלחה. נסו לשנות את המשקלים של השירותים השונים ולהחיל את קובץ worker-virtualservice.yaml. זו דרך מצוינת לאזן את התנועה בין האשכולות, אבל מה אם נוכל לעשות זאת באופן אוטומטי?
16. שימוש במדדים של Prometheus
מבוא ל-Prometheus
Prometheus היא ערכת כלים בקוד פתוח למעקב אחרי מערכות ולהתראות, שנבנתה במקור ב-SoundCloud. הוא שומר על מודל נתונים רב-ממדי עם נתוני סדרות זמנים שמזוהים לפי שם המדד וזוגות של מפתח/ערך.
לעיון, הנה תרשים הארכיטקטורה של Prometheus:

כשפורסים את Istio עם Prometheus, המערכת מדווחת אוטומטית על מדדים שונים לשרת Prometheus. אנחנו יכולים להשתמש במדדים האלה כדי לנהל את האשכולות שלנו תוך כדי תנועה.
הסבר על מדדי Prometheus
כדי להתחיל, צריך לחשוף את הפריסה של Prometheus.
עוברים לכרטיסייה Workloads (עומסי עבודה) ב-GKE, ומתעמקים בעומס העבודה prometheus.

אחרי שצופים בפרטי הפריסה, עוברים אל Actions (פעולות) -> Expose (חשיפה).

בוחרים להעביר לפורט 9090 ומקלידים "מאזן עומסים"

בוחרים באפשרות 'חשיפה'.
פעולה זו תיצור שירות בכתובת IP שנגישה לציבור, שנוכל להשתמש בה כדי לבדוק את מדדי Prometheus
מחכים עד שהנקודה תהיה פעילה, ואז לוחצים על כתובת ה-IP לצד 'נקודות קצה חיצוניות' 
עכשיו אמור להופיע ממשק המשתמש של Prometheus.

Prometheus מספק מספיק מדדים כדי להוות סדנה בפני עצמה. אבל בינתיים, נתחיל בבדיקה של המדד istio_requests_total.
הפעלת השאילתה הזו מחזירה הרבה נתונים. אלה מדדים של כל הבקשות שעוברות דרך Service mesh ב-Istio, וזה הרבה! נשנה את הביטוי כדי לסנן את התוצאות ולצמצם אותן למה שבאמת מעניין אותנו:
בקשות שבהן שירות היעד הוא worker-service.default.svc.cluster.local, והמקור הוא frontend-deployment, מוגבלות ל-15 השניות האחרונות
השאילתה תיראה כך:
istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]
ומקבלים מערך נתונים הרבה יותר נוח לעבודה

אבל עדיין קצת צפוף. אנחנו רוצים לדעת את מספר הבקשות לשנייה, ולא את כל הבקשות.
כדי לקבל את זה, אפשר להשתמש בפונקציה המובנית rate
rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

אנחנו מתקרבים, אבל צריך לצמצם עוד קצת את המדדים האלה לקבוצה הגיונית.
כדי לעשות את זה, אפשר להשתמש במילות המפתח sum ו-by כדי לקבץ ולסכם את התוצאות
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)

יופי! אנחנו יכולים לקבל מ-Prometheus את המדדים המדויקים שאנחנו צריכים.
Our final Prometheus Query
אחרי שלמדנו את כל מה שצריך, השאילתה הסופית שצריך להריץ ב-Prometheus היא
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)
עכשיו אפשר להשתמש ב-HTTP API שלהם כדי לקבל את המדד.
אנחנו יכולים לשלוח שאילתה ל-API שלהם באמצעות בקשת GET, כמו בדוגמה הבאה. צריך להחליף את <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\)
זוהי דוגמה לתשובה:
{
"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"
]
}
]
}
}
עכשיו אפשר לחלץ את ערך המדד מ-JSON
ניקוי נתונים
צריך למחוק את השירות שבו השתמשנו כדי לחשוף את Prometheus. במסוף Google Cloud, עוברים לחלק העליון של השירות שיצרנו ולוחצים על Delete (מחיקה).

השלבים הבאים:
אחרי שמצאנו דרך לגלות איך התנועה עוברת דרך האשכול ובאיזו מהירות, השלב הבא הוא לכתוב קובץ בינארי קטן ששולח שאילתות ל-Prometheus באופן תקופתי. אם מספר הבקשות לשנייה ל-worker עולה מעל סף מסוים, המערכת מחילה משקלים שונים של יעדים בשירות הווירטואלי של העובד כדי לשלוח את כל התנועה לאשכול burst. אם מספר הבקשות לשנייה יירד מתחת לסף התחתון, צריך להחזיר את כל התנועה אל primary.
17. יצירת התפרצות תעבורה בין אשכולות
הגדרה
הגדרת כל התנועה לשירות העובד באשכול הראשי
אנחנו נחשיב את כל התנועה שמיועדת ל-worker-service ומנותבת לאשכול primary כסטטוס ברירת המחדל של האפליקציה שלנו
עריכת $proj/istio-manifests/worker-virtualservice.yaml כך שייראה כמו הדוגמה הבאה
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
מוודאים שאתם מחוברים לאשכול primary
kubectx primary
החלת istio-manifests/worker-virtualservice.yaml
kubectl apply -f istio-manifests/worker-virtualservice.yaml
כתיבת דמון istiowatcher
נשתמש ב-Go כדי לכתוב את השירות הזה, בגלל המהירות והניידות שלו. התהליך הכללי של האפליקציה יהיה להתחיל ובכל שנייה לשלוח שאילתה ל-Prometheus,
יוצרים ספרייה חדשה בשם istiowatcher ב-src
mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher
נתקשר אל istioctl מתוך הקונטיינר שלנו כדי לבצע מניפולציה במישור הבקרה של Istio מתוך האשכול.
כתיבת הקובץ istiowatcher.go
יוצרים קובץ בשם istiowatcher.go בתיקייה הזו ומכניסים לתוכו את התוכן הבא
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
יוצרים קובץ חדש בשם Dockerfile ומכניסים לתוכו את התוכן הבא.
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"]
קובץ ה-Dockerfile הרב-שלבי הזה מוריד ומחלץ את גרסה 1.0.0 של Istio בשלב הראשון. בשלב השני, כל מה שיש בספרייה שלנו מועתק לתמונה, ואז istioctl מועתק משלב ה-build אל /usr/local/bin (כדי שאפשר יהיה לקרוא לו מהאפליקציה שלנו), יחסי התלות מתקבלים, הקוד עובר קומפילציה והערך של CMD מוגדר כ-istiowatcher.
כתיבת הקובץ burst.yaml
זהו הקובץ istiowatcher שיחול כשהבקשות לשנייה אל worker מ-frontend יעלו על 15.
יוצרים קובץ חדש בשם burst.yaml ומכניסים לתוכו את התוכן הבא.
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
זה יהיה המצב ה "טבעי" שאליו נחזור כשהערך של בקשות/שנייה מ-frontend אל worker יירד מתחת ל-10. במצב הזה, 100% מהתנועה מנותבת לאשכול primary.
יוצרים קובץ חדש בשם natural.yaml ומכניסים לתוכו את התוכן הבא
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
מריצים את הפקודה הבאה כדי לשלוח את הספרייה הנוכחית אל Google Cloud Build (GCB), שיבנה את התמונה ויסמן אותה ב-GCR.
gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher
פריסת istiowatcher
עוברים לספרייה kubernetes
cd ${proj}/kubernetes/
כתיבת קובץ פריסה: istiowatcher.yaml
יוצרים קובץ בשם istiowatcher.yaml ומזינים את התוכן הבא (צריך להחליף את <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
Deploy
מוודאים שהאפליקציה פועלת באשכול הראשי
kubectx primary
פריסה של istiowatcher.yaml במרחב השמות istio-system
kubectl apply -n istio-system -f istiowatcher.yaml
חשוב לשים לב להוראות serviceAccountName ו-automountServiceAccountToken בקובץ ה-YAML. כך אנחנו מקבלים את פרטי הכניסה שנדרשים להפעלת istioctl מתוך האשכול.
אנחנו צריכים גם לפרוס את זה במרחב השמות istio-system כדי לוודא שיש לנו את פרטי הכניסה ל-istio-pilot-service-account. (הוא לא קיים במרחב השמות default).
רואים את התנועה עוברת אוטומטית!
ועכשיו לרגע הקסום! נעבור לקצה הקדמי שלנו וננסה להגדיל את מספר הבקשות לשנייה ל-20
שימו לב שזה לוקח כמה שניות, אבל אנחנו מגדילים את מספר הגיבובים בהדרגה עד שכל הגיבובים שלנו מקבלים את הקידומת bursty-.
הסיבה לכך היא שאנחנו מבצעים דגימה של Prometheus בטווח של 15s, ולכן יש השהיה קלה בזמן התגובה. אם רוצים להגדיר טווח צר יותר, אפשר לשנות את השאילתה ב-Prometheus ל-5s.
18. מה השלב הבא?
ניקוי נתונים
אם אתם משתמשים בחשבון זמני שקיבלתם לסדנה הזו, אתם לא צריכים לבצע ניקוי.
אפשר למחוק את אשכולות Kubernetes, את כלל חומת האש ואת התמונות ב-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
המשך הדרך
- כדאי להשתתף ב-Istio Talks.
- Get the Cert: Build Your Next App With Kubernetes + Istio
- נאום מרכזי: Kubernetes, Istio, Knative: חבילת הענן החדשה בקוד פתוח – אפארנה סינהה (Aparna Sinha), מנהלת קבוצת מוצרים של Kubernetes, Google
- הדרכה: שימוש ב-Istio – לי קלקוט וגיריש רנגנתן, SolarWinds
- Istio - The Packet's-Eye View - Matt Turner, Tetrate
- Is Istio the Most Next Gen Next Gen Firewall Ever Created? - ג'ון מורלו, Twistlock
- קוראים את התיעוד של Istio
- הצטרפות לקבוצות העבודה של Istio
- עקבו אחרי @IstioMesh ב-Twitter




