Cloud Service Mesh הוא כלי רב עוצמה לניהול ולמעקב אחרי אפליקציות מבוזרות. כדי להפיק את המקסימום מ-Cloud Service Mesh, כדאי להבין את ההפשטות שעליהן הוא מבוסס, כולל קונטיינרים ו-Kubernetes. במדריך הזה מוסבר איך להכין אפליקציה ל-Cloud Service Mesh, מקוד המקור ועד לקונטיינר שפועל ב-GKE, עד לשלב שלפני ההתקנה של Cloud Service Mesh.
אם אתם כבר מכירים את המושגים של Kubernetes ו-service mesh, אתם יכולים לדלג על המדריך הזה ולעבור ישירות אל מדריך ההתקנה של Cloud Service Mesh.
מטרות
- אפליקציית "hello world" פשוטה עם כמה שירותים.
- מריצים את האפליקציה מקוד המקור
- העברת האפליקציה לקונטיינר.
- יוצרים אשכול Kubernetes.
- פורסים את הקונטיינרים באשכול.
לפני שמתחילים
כדי להפעיל את Cloud Service Mesh API:- נכנסים לדף Kubernetes Engine במסוף Google Cloud .
- יוצרים או בוחרים פרויקט.
- מחכים עד שה-API והשירותים הקשורים יופעלו. הפעולה עשויה להימשך כמה דקות.
במדריך הזה משתמשים ב-Cloud Shell, שמקצה מכונה וירטואלית (VM) של g1-small Compute Engine שמריצה מערכת הפעלה של Linux שמבוססת על Debian.
הכנת Cloud Shell
היתרונות של שימוש ב-Cloud Shell הם:
- סביבות הפיתוח של Python 2 ו-Python 3 (כולל
virtualenv) מוגדרות. - כלי שורת הפקודה
gcloud,docker,gitו-kubectlשמשמשים במדריך הזה כבר מותקנים. אתם יכולים לבחור כלי לעריכת טקסט:
עורך הקוד, שאליו ניגשים בלחיצה על בחלק העליון של חלון Cloud Shell.
Emacs, Vim או Nano, שאפשר לגשת אליהם משורת הפקודה ב-Cloud Shell.
מפעילים את Cloud Shell במסוף Google Cloud .
בחלק התחתון של Google Cloud המסוף יתחיל סשן של Cloud Shell ותופיע הודעה של שורת הפקודה. Cloud Shell היא סביבת מעטפת שבה ה-CLI של Google Cloud מותקן ומוגדרים ערכים לפרויקט הקיים. הסשן יופעל תוך כמה שניות.
הורדת הקוד לדוגמה
מורידים את קוד המקור של
helloserver:git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samplesעוברים לספרייה של הקוד לדוגמה:
cd anthos-service-mesh-samples/docs/helloserver
הכרת האפליקציה עם כמה שירותים
אפליקציית הדוגמה כתובה ב-Python, ויש לה שני רכיבים שמתקשרים באמצעות REST:
-
server: שרת פשוט עם נקודת קצה אחתGET, /, שמדפיסה את המחרוזת hello world במסוף. -
loadgen: סקריפט ששולח תעבורה אלserver, עם מספר בקשות לשנייה (RPS) שניתן להגדרה.
מריצים את האפליקציה מקוד המקור
כדי להכיר את האפליקציה לדוגמה, מריצים אותה ב-Cloud Shell.
מהספרייה
sample-apps/helloserver, מריצים את הפקודהserver:python3 server/server.pyבזמן ההפעלה, ב-
serverמוצגים הנתונים הבאים:INFO:root:Starting server...
פותחים חלון טרמינל נוסף כדי לשלוח בקשות אל
server. לוחצים על כדי לפתוח סשן נוסף.שליחת בקשה אל
server:curl http://localhost:8080התשובה של
server:Hello World!
מהספרייה שבה הורדתם את הקוד לדוגמה, עוברים לספרייה שמכילה את
loadgen:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/loadgen
יוצרים את משתני הסביבה הבאים:
export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5התחלה של
virtualenv:virtualenv --python python3 envמפעילים את הסביבה הווירטואלית:
source env/bin/activateמתקינים את הדרישות של
loadgen:pip3 install -r requirements.txtמריצים את
loadgen:python3 loadgen.pyבזמן ההפעלה,
loadgenמוציא פלט של הודעה שדומה לזו:Starting loadgen: 2019-05-20 10:44:12.448415 5 request(s) complete to http://localhost:8080
בחלון הטרמינל השני,
serverכותב הודעות למסוף, בדומה להודעות הבאות:127.0.0.1 - - [21/Jun/2019 14:22:01] "GET / HTTP/1.1" 200 - INFO:root:GET request, Path: / Headers: Host: localhost:8080 User-Agent: python-requests/2.22.0 Accept-Encoding: gzip, deflate Accept: */*
מבחינת הרשת, כל האפליקציה פועלת עכשיו באותו מארח. לכן אפשר להשתמש ב-
localhostכדי לשלוח בקשות אלserver.כדי לעצור את
loadgenואתserver, מזיניםCtrl-cבכל חלון של מסוף.בחלון הטרמינל של
loadgen, משביתים את הסביבה הווירטואלית:deactivate
העברת האפליקציה לקונטיינר
כדי להריץ את האפליקציה ב-GKE, צריך לארוז את האפליקציה לדוגמה – גם את server וגם את loadgen – בקונטיינרים. קונטיינר הוא דרך לארוז אפליקציה כך שהיא מבודדת מהסביבה הבסיסית.
כדי להוסיף את האפליקציה למאגר, צריך Dockerfile. Dockerfile הוא קובץ טקסט שמגדיר את הפקודות שנדרשות כדי להרכיב את קוד המקור של האפליקציה ואת יחסי התלות שלה בקובץ אימג' של Docker. אחרי שיוצרים את קובץ האימג', מעלים אותו למרשם קונטיינרים כמו Docker Hub או Container Registry.
הדוגמה כוללת Dockerfile גם ל-server וגם ל-loadgen עם כל הפקודות שנדרשות כדי ליצור את קובצי האימג'. הנה Dockerfile של server:
- הפקודה
FROM python:3-slim as baseמורה ל-Docker להשתמש בקובץ האימג' העדכני של Python 3 כקובץ האימג' הבסיסי. - הפקודה
COPY . .מעתיקה את קובצי המקור בספריית העבודה הנוכחית (במקרה הזה, רקserver.py) למערכת הקבצים של הקונטיינר. - ה-
ENTRYPOINTמגדיר את הפקודה שמשמשת להפעלת הקונטיינר. במקרה הזה, הפקודה כמעט זהה לפקודה שבה השתמשתם כדי להריץ אתserver.pyמקוד המקור. - הפקודה
EXPOSEמציינת שהשירותserverמאזין ליציאה8080. הפקודה הזו לא חושפת יציאות, אלא משמשת כתיעוד לכך שצריך לפתוח את היציאה8080כשמריצים את הקונטיינר.
הכנה להעברת האפליקציה לקונטיינר
מגדירים את משתני הסביבה הבאים. מחליפים את
PROJECT_IDבמזהה הפרויקט ב-Google Cloud .export PROJECT_ID="PROJECT_ID"
export GCR_REPO="asm-ready"
משתמשים בערכים של
PROJECT_IDו-GCR_REPOכדי לתייג את קובץ האימג' של Docker כשיוצרים אותו, ואז מעבירים אותו בדחיפה ל-Container Registry הפרטי.מגדירים את פרויקט ברירת המחדל ב- Google Cloud ל-Google Cloud CLI.
gcloud config set project $PROJECT_ID
מגדירים את אזור ברירת המחדל ל-Google Cloud CLI.
gcloud config set compute/zone us-central1-bמוודאים ששירות Container Registry מופעל בפרויקטGoogle Cloud .
gcloud services enable containerregistry.googleapis.com
הכנסת server לקונטיינר
עוברים לספרייה שבה נמצאת הדוגמה של
server:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
יוצרים את קובץ האימג' באמצעות
Dockerfileומשתני הסביבה שהגדרתם קודם:docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 .הדגל
-tמייצג את התג של Docker. זה השם של קובץ האימג' שמשמש לפריסת הקונטיינר.מעבירים את קובץ האימג' בדחיפה ל-Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1
הכנסת loadgen לקונטיינר
עוברים לספרייה שבה נמצאת הדוגמה של
loadgen:cd ../loadgenיצירת התמונה:
docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 .מעבירים את קובץ האימג' בדחיפה ל-Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1
הכנת רשימה של התמונות
כדי לוודא שהתמונות נשלחו, מציגים רשימה של התמונות במאגר:
gcloud container images list --repository gcr.io/$PROJECT_ID/asm-ready
הפקודה מחזירה את שמות קובצי האימג' ששלחתם:
NAME gcr.io/PROJECT_ID/asm-ready/helloserver gcr.io/PROJECT_ID/asm-ready/loadgen
יצירת אשכול GKE
אפשר להריץ את הקונטיינרים האלה במכונה הווירטואלית של Cloud Shell באמצעות הפקודה docker run. אבל בסביבת הייצור, צריך לתזמר קונטיינרים בצורה אחידה יותר. לדוגמה, אתם צריכים מערכת שמוודאת שהקונטיינרים פועלים תמיד, ודרך להרחיב אנכית בהתאם לעומס (scale up) ולהפעיל מכונות נוספות של קונטיינר כדי לטפל בעלייה בתנועה.
אתם יכולים להשתמש ב-GKE כדי להריץ אפליקציות בקונטיינרים. GKE היא פלטפורמה לניהול קונטיינרים, שמחברת מכונות וירטואליות לאשכול. כל מכונה וירטואלית נקראת צומת. אשכולות GKE מופעלים באמצעות המערכת לניהול אשכולות בקוד פתוח של Kubernetes. Kubernetes מספק את המנגנונים שדרכם אתם יוצרים אינטראקציה עם האשכול.
כדי ליצור אשכול GKE:
יוצרים את האשכול:
gcloud container clusters create asm-ready \ --cluster-version latest \ --machine-type=n1-standard-4 \ --num-nodes 4
הפקודה
gcloudיוצרת אשכול בפרויקט ובאזור שהגדרתם קודם לכן,Google Cloud . כדי להפעיל את Cloud Service Mesh, מומלץ להשתמש לפחות ב-4 צמתים ובסוג המכונה n1-standard-4.הפקודה ליצירת האשכול נמשכת כמה דקות. כשהאשכול מוכן, פלט הפקודה מפיק הודעה שדומה לזו:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asm-ready us-central1-b 1.13.5-gke.10 203.0.113.1 n1-standard-2 1.13.5-gke.10 4 RUNNING
כדי להשתמש בכלי שורת הפקודה
kubectlלניהול האשכול, צריך לספק לו את פרטי הכניסה:gcloud container clusters get-credentials asm-readyעכשיו אפשר להשתמש ב-
kubectlכדי לתקשר עם Kubernetes. לדוגמה, אפשר להריץ את הפקודה הבאה כדי לקבל את הסטטוס של הצמתים:kubectl get nodesהפקודה מחזירה רשימה של הצמתים, בדומה לדוגמה הבאה:
NAME STATUS ROLES AGE VERSION gke-asm-ready-default-pool-dbeb23dc-1vg0 Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-36z5 Ready <none> 100s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-fj7s Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-wbjw Ready <none> 99s v1.13.6-gke.13
הסבר על מושגי מפתח ב-Kubernetes
בתרשים הבא מוצגת האפליקציה שפועלת ב-GKE:
לפני שמבצעים פריסה של הקונטיינרים ב-GKE, כדאי לעיין בכמה מושגים מרכזיים ב-Kubernetes. בסוף המדריך הזה מופיעים קישורים שדרכם אפשר לקבל מידע נוסף על כל מושג.
צמתים ואשכולות: ב-GKE, צומת הוא מכונה וירטואלית. בפלטפורמות אחרות של Kubernetes, צומת יכול להיות מכונה פיזית או וירטואלית. אשכול הוא קבוצה של צמתים שאפשר להתייחס אליהם יחד כמכונה אחת, שעליה פורסים אפליקציה בקונטיינר.
Pods: ב-Kubernetes, קונטיינרים פועלים בתוך Pod. Pod הוא היחידה האטומית ב-Kubernetes. Pod מכיל מאגר אחד או יותר. אתם פורסים את הקונטיינרים של
serverו-loadgen, כל אחד ב-Pod משלו. כש-Pod מריץ כמה קונטיינרים (לדוגמה, שרת אפליקציות ושרת proxy), הקונטיינרים מנוהלים כישות אחת ומשתפים את המשאבים של ה-Pod.פריסות: פריסה היא אובייקט של Kubernetes שמייצג קבוצה של Pods זהים. פריסה מריצה כמה רפליקות של Pods שמופצים בין הצמתים של אשכול. פריסת אפליקציה מחליפה באופן אוטומטי כל Pod שנכשל או מפסיק להגיב.
Kubernetes Service: הרצת קוד האפליקציה ב-GKE משנה את הרישות בין
loadgenלביןserver. כשהפעלתם את השירותים במכונה וירטואלית של Cloud Shell, יכולתם לשלוח בקשות אלserverבאמצעות הכתובתlocalhost:8080. אחרי הפריסה ב-GKE, הפודים מתוזמנים להפעלה בצמתים הזמינים. כברירת מחדל, אי אפשר לקבוע באיזה צומת ה-Pod פועל, ולכן ל-Pods אין כתובות IP יציבות.כדי לקבל כתובת IP ל-
server, צריך להגדיר הפשטה של רשת מעל ה-Pods, שנקראת שירות Kubernetes. שירות Kubernetes מספק נקודת קצה יציבה ברשת לקבוצה של Pods. יש כמה סוגים של שירותים. serverמשתמש ב-LoadBalancer, שחושף כתובת IP חיצונית כדי שתוכלו להגיע אלserverמחוץ לאשכול.ל-Kubernetes יש גם מערכת DNS מובנית, שמקצה שמות DNS (לדוגמה,
helloserver.default.cluster.local) לשירותים. כך אפשר ל-Pods בתוך האשכול להגיע ל-Pods אחרים באשכול עם כתובת יציבה. אי אפשר להשתמש בשם ה-DNS הזה מחוץ לאשכול, למשל מ-Cloud Shell.
מניפסטים של Kubernetes
כשהרצתם את האפליקציה מקוד המקור, השתמשתם בפקודה אימפרטיבית: python3 server.py
ציווי הוא צורת פועל שמשמשת למתן הוראה: "תעשה את זה".
לעומת זאת, Kubernetes פועל לפי מודל הצהרתי. כלומר, במקום להורות ל-Kubernetes בדיוק מה לעשות, אתם מספקים ל-Kubernetes את המצב הרצוי. לדוגמה, Kubernetes מפעיל ומפסיק את ה-Pods לפי הצורך, כך שהמצב בפועל של המערכת תואם למצב הרצוי.
מציינים את המצב הרצוי בקבוצה של מניפסטים או קבצי YAML. קובץ YAML מכיל את המפרט של אובייקט Kubernetes אחד או יותר.
הדוגמה מכילה קובץ YAML ל-server ול-loadgen. כל קובץ YAML מציין את המצב הרצוי של אובייקט הפריסה והשירות של Kubernetes.
שרת
-
kindמציין את סוג האובייקט. -
metadata.nameמציין את שם הפריסה. - השדה הראשון של
specמכיל תיאור של המצב הרצוי. -
spec.replicasמציין את מספר ה-Pods הרצוי. - הקטע
spec.templateמגדיר תבנית Pod. במפרט של ה-Pods נכלל השדהimage, שהוא השם של קובץ האימג' שצריך לשלוף מ-Container Registry.
השירות מוגדר כך:
-
LoadBalancer: לקוחות שולחים בקשות לכתובת ה-IP של מאזן עומסים ברשת, שיש לו כתובת IP יציבה שאפשר להגיע אליה מחוץ לאשכול. -
targetPort: חשוב לזכור שהפקודהEXPOSE 8080ב-Dockerfileלא חושפת אף יציאה. אתם חושפים את יציאה8080כדי שתוכלו להגיע למאגרserverמחוץ לאשכול. במקרה הזה,hellosvc.default.cluster.local:80(shortname:hellosvc) ממופה ליציאה8080של כתובת ה-IP של ה-Podhelloserver. -
port: מספר היציאה ששירותים אחרים באשכול משתמשים בו כששולחים בקשות.
מחולל עומסים
האובייקט Deployment ב-loadgen.yaml דומה ל-server.yaml. הבדל אחד בולט הוא שאובייקט הפריסה מכיל קטע שנקרא env. בקטע הזה מוגדרים משתני הסביבה שנדרשים ל-loadgen, שהגדרתם קודם כשהפעלתם את האפליקציה מהמקור.
מכיוון שה-loadgen לא מקבל בקשות נכנסות, השדה type מוגדר ל-ClusterIP. הסוג הזה מספק כתובת IP יציבה ששירותים באשכול יכולים להשתמש בה, אבל כתובת ה-IP לא חשופה ללקוחות חיצוניים.
פריסת הקונטיינרים ב-GKE
עוברים לספרייה שבה נמצאת הדוגמה של
server:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
פותחים את
server.yamlבכלי לעריכת טקסט.מחליפים את השם בשדה
imageבשם של קובץ האימג' של Docker.image: gcr.io/PROJECT_ID/asm-ready/helloserver:v0.0.1
מחליפים את
PROJECT_IDבמזהה הפרויקט ב- Google Cloud .שומרים וסוגרים את
server.yaml.פורסים את קובץ ה-YAML ב-Kubernetes:
kubectl apply -f server.yamlאם הפקודה מסתיימת ללא שגיאות, התגובה תהיה:
deployment.apps/helloserver created service/hellosvc created
עוברים לספרייה שבה נמצא הקובץ
loadgen.cd ../loadgenפותחים את
loadgen.yamlבכלי לעריכת טקסט.מחליפים את השם בשדה
imageבשם של קובץ האימג' של Docker.image: gcr.io/PROJECT_ID/asm-ready/loadgen:v0.0.1
מחליפים את
PROJECT_IDבמזהה הפרויקט ב- Google Cloud .שומרים וסוגרים את
loadgen.yaml, וסוגרים את הכלי לעריכת טקסט.פורסים את קובץ ה-YAML ל-Kubernetes:
kubectl apply -f loadgen.yamlאם הפקודה מצליחה, היא מחזירה את התגובה הבאה:
deployment.apps/loadgenerator created service/loadgensvc created
בודקים את הסטטוס של ה-Pods:
kubectl get podsהתגובה של הפקודה תכלול את הסטטוס, כמו בדוגמה הבאה:
NAME READY STATUS RESTARTS AGE helloserver-69b9576d96-mwtcj 1/1 Running 0 58s loadgenerator-774dbc46fb-gpbrz 1/1 Running 0 57s
מורידים את יומני האפליקציה מה-Pod של
loadgen. מחליפים אתPOD_IDבמזהה מהפלט הקודם.kubectl logs loadgenerator-POD_ID
משיגים את כתובות ה-IP החיצוניות של
hellosvc:kubectl get serviceהתגובה של הפקודה אמורה להיראות כך:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hellosvc LoadBalancer 10.81.15.158 192.0.2.1 80:31127/TCP 33m kubernetes ClusterIP 10.81.0.1 <none> 443/TCP 93m loadgensvc ClusterIP 10.81.15.155 <none> 80/TCP 4m52s
שליחת בקשה אל
hellosvc. מחליפים אתEXTERNAL_IPבכתובת ה-IP החיצונית שלhellosvc.curl http://EXTERNAL_IP
מוכן ל-Cloud Service Mesh
האפליקציה פרוסה עכשיו ב-GKE. loadgen יכול להשתמש ב-Kubernetes DNS (hellosvc:80) כדי לשלוח בקשות אל server, ואתם יכולים לשלוח בקשות אל server באמצעות כתובת IP חיצונית. למרות ש-Kubernetes מספקת לכם תכונות רבות, חסר מידע מסוים על השירותים:
- איך השירותים פועלים יחד? מה הקשר בין השירותים? איך התנועה זורמת בין השירותים? אתם יודעים ש
loadgenשולח בקשות אלserver, אבל נניח שאתם לא מכירים את האפליקציה. אי אפשר לענות על השאלות האלה על סמך רשימת ה-Pods שפועלים ב-GKE. - מדדים: כמה זמן לוקח ל-
serverלהגיב לבקשות נכנסות? כמה בקשות לשנייה (RPS) נכנסות אלserver? האם יש תשובות שגיאה? - מידע על אבטחה: האם התנועה בין
loadgenלביןserverהיאHTTPרגילה או mTLS?
בעזרת Cloud Service Mesh אפשר לקבל תשובות לשאלות האלה. Cloud Service Mesh הוא גרסה של Google Cloudשמנוהלת על ידי פרויקט הקוד הפתוח Istio. Cloud Service Mesh פועל על ידי הצבת פרוקסי של Envoy sidecar בכל Pod. שרת ה-proxy של Envoy מיירט את כל התנועה הנכנסת והיוצאת לקונטיינרים של האפליקציה. כלומר, server ו-loadgen מקבלים כל אחד קובץ עזר חיצוני של Envoy, וכל התנועה מ-loadgen אל server מתווכת על ידי קובצי העזר החיצוניים של Envoy. החיבורים בין שרתי ה-proxy האלה של Envoy יוצרים את Service mesh. ארכיטקטורת ה-service mesh הזו מספקת שכבת בקרה מעל Kubernetes.
מכיוון ששרתי ה-proxy של Envoy פועלים בקונטיינרים משלהם, אתם יכולים להתקין את Cloud Service Mesh באשכול GKE בלי לבצע שינויים משמעותיים בקוד האפליקציה. עם זאת, יש כמה דרכים עיקריות שבהן הכנתם את האפליקציה להטמעה באמצעות Cloud Service Mesh:
- שירותים לכל הקונטיינרים: לשני הפריסות,
serverו-loadgen, מצורף שירות Kubernetes. אפילו ל-loadgen, שלא מקבל בקשות נכנסות, יש שירות. - צריך לתת שמות ליציאות בשירותים: למרות ש-GKE מאפשר להגדיר יציאות שירות ללא שם, ב-Cloud Service Mesh צריך לספק שם ליציאה שתואם לפרוטוקול של היציאה. בקובץ ה-YAML, היציאה של
serverנקראתhttpכיserverמשתמש בפרוטוקול התקשורתHTTP. אםserviceמשתמש ב-gRPC, צריך לתת ליציאה את השםgrpc. - הפריסות מסומנות בתוויות: כך אפשר להשתמש בתכונות של Cloud Service Mesh לניהול תעבורת הנתונים, כמו פיצול תעבורת הנתונים בין גרסאות של אותו שירות.
התקנת Cloud Service Mesh
במדריך להתקנת Cloud Service Mesh פועלים לפי ההוראות להתקנת Cloud Service Mesh באשכול.
הסרת המשאבים
כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, אפשר למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד.
כדי לנקות, מוחקים את אשכול GKE. מחיקת האשכול מוחקת את כל המשאבים שמרכיבים את אשכול הקונטיינרים, כמו מכונות Compute, דיסקים ומשאבי רשת.
gcloud container clusters delete asm-ready
המאמרים הבאים
מידע נוסף על הטכנולוגיות שמשמשות במדריך הזה:
מידע נוסף על הכלים:
מידע נוסף על מושגי Kubernetes: