העברת אפליקציית x86 ב-GKE לארכיטקטורה מרובת ליבות עם Arm

במדריך הזה נסביר איך להעביר אפליקציה שנוצרה לצמתים באמצעות מעבד x86 (Intel או AMD) באשכול Google Kubernetes Engine‏ (GKE) לאפליקציה מרובת-ארכיטקטורות (multi-arch) שפועלת בצמתי x86 או Arm. קהל היעד של המדריך הזה הוא מנהלי פלטפורמות, מפעילים של אפליקציות ומפתחי אפליקציות שרוצים להריץ את עומסי העבודה הקיימים שלהם שתואמים ל-x86 ב-Arm.

באמצעות אשכולות GKE, אתם יכולים להריץ עומסי עבודה בצמתים של Arm באמצעות סדרות המכונות C4A,‏ N4A או Tau T2A. במדריך הזה נעשה שימוש בצמתים מסוג C4A, שבדומה לצמתים מסוג N4A ו-T2A, יכולים לפעול באשכול GKE שלכם בדיוק כמו כל צומת אחר באמצעות מעבדי x86 (Intel או AMD). צמתים מסוג C4A מספקים ביצועים גבוהים באופן עקבי לעומסי העבודה שלכם על בסיס Arm.

מידע נוסף זמין במאמר בנושא עומסי עבודה של Arm ב-GKE.

ההנחה היא שאתם מכירים את Kubernetes ואת Docker. במדריך הזה נעשה שימוש ב-Google Kubernetes Engine וב-Artifact Registry.

מטרות

במדריך הזה תבצעו את המשימות הבאות:

  • אחסון תמונות של קונטיינרים באמצעות Docker ב-Artifact Registry.
  • פריסת עומס עבודה (workload) שתואם ל-x86 באשכול GKE.
  • בונים מחדש עומס עבודה שתואם ל-x86 כדי להריץ אותו ב-Arm.
  • הוספת מאגר צמתים של Arm לאשכול קיים.
  • פריסת עומס עבודה שתואם ל-Arm להרצה בצומת Arm.
  • יצירת תמונה מרובת ארכיטקטורות להרצת עומס עבודה בכמה ארכיטקטורות.
  • הפעלת עומסי עבודה בכמה ארכיטקטורות באשכול GKE אחד.

עלויות

במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:

כדי להעריך את ההוצאות בהתאם לתחזית השימוש שלכם, אתם יכולים להיעזר במחשבון העלויות.

משתמשים חדשים של Google Cloud ? יכול להיות שאתם זכאים לתקופת ניסיון בחינם.

כשמסיימים את המשימות שמתוארות במסמך הזה אפשר למחוק את המשאבים שיצרתם כדי להימנע מחיובים נוספים. מידע נוסף זמין בקטע הסרת המשאבים.

לפני שמתחילים

כדי להפעיל את Kubernetes Engine API, מבצעים את השלבים הבאים:
  1. נכנסים לחשבון Google Cloud . אם אתם משתמשים חדשים ב- Google Cloud, צרו חשבון כדי שתוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Artifact Registry and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Artifact Registry and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

כדי להימנע מחיובים נוספים אחרי שסיימתם את המדריך, תוכלו למחוק את המשאבים שיצרתם. פרטים נוספים מופיעים במאמר בנושא הסרת המשאבים.

הפעלת Cloud Shell

במדריך הזה תשתמשו ב-Cloud Shell, שהיא סביבת מעטפת לניהול משאבים שמתארחים ב-Google Cloud.

ב-Cloud Shell מותקנים מראש Google Cloud CLI וכלי שורת הפקודה kubectl. ה-CLI של gcloud הוא ממשק שורת הפקודה העיקרי ל- Google Cloud, ו-kubectl הוא ממשק שורת הפקודה העיקרי להרצת פקודות מול אשכולות Kubernetes.

מפעילים את Cloud Shell:

  1. נכנסים למסוף Google Cloud .

    Google Cloud console

  2. לוחצים על Activate Cloud Shell בפינה הימנית העליונה של המסוף.

סשן של Cloud Shell יופיע בתוך המסוף. משתמשים בשורת הפקודה הזו כדי להריץ פקודות gcloud ו-kubectl.

הכנת הסביבה

בקטע הזה מוסבר איך להכין את הסביבה כדי לפעול לפי ההוראות במדריך.

הגדרת ברירת המחדל של ה-CLI של gcloud

מגדירים משתני סביבה למזהה הפרויקט, למיקום של Compute Engine עבור האשכול ולשם האשכול החדש.

export PROJECT_ID=PROJECT_ID
export CONTROL_PLANE_LOCATION=us-central1-a
export CLUSTER_NAME=my-cluster

מחליפים את PROJECT_ID במזהה הפרויקט שבחרתם למדריך הזה בקטע לפני שמתחילים.

במדריך הזה, תיצרו משאבים ב-us-central1-a. כדי לראות רשימה מלאה של המקומות שבהם סדרת המכונות C4A זמינה, אפשר לעיין במאמר בנושא אזורים ותחומים זמינים.

שכפול מאגר Git

  1. משכפלים את המאגר:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  2. מעבירים את ספריית העבודה הנוכחית למאגר ששוכפל בשלב הקודם:

    cd kubernetes-engine-samples/workloads/migrate-x86-app-to-multi-arch/
    

    המאגר הזה מכיל את הקבצים שדרושים לכם כדי להשלים את ההדרכה הזו. בהדרכה הזו נעשה שימוש בפריסות של Kubernetes. פריסה היא אובייקט Kubernetes API שמאפשר להפעיל כמה רפליקות של Pods שמפוזרות בין הצמתים באשכול.

יצירת אשכול GKE ופריסת אפליקציית x86

בחלק הראשון של המדריך הזה, יוצרים אשכול עם צמתי x86 ופורסים אפליקציית x86. אפליקציית הדוגמה היא שירות שמגיב לבקשות HTTP. היא בנויה בשפת התכנות Golang.

ההגדרה הזו מייצגת את מה שעשוי להיות בסביבת אשכול טיפוסית, באמצעות אפליקציות שתואמות ל-x86 וצמתים של x86.

יצירת אשכול GKE

קודם כל, יוצרים GKE באמצעות צמתים עם מעבדי x86. בעזרת ההגדרה הזו, יוצרים סביבת אשכול טיפוסית להפעלת אפליקציות x86.

יוצרים את האשכול:

gcloud container clusters create $CLUSTER_NAME \
    --release-channel=rapid \
    --location=$CONTROL_PLANE_LOCATION \
    --machine-type=e2-standard-2 \
    --num-nodes=1 \
    --async

השבתנו את ההתאמה האוטומטית לעומס של האשכול הזה כדי להדגים פונקציונליות ספציפית בשלבים מאוחרים יותר.

יצירת האשכול עשויה להימשך כמה דקות. הדגל --async מאפשר להפעיל את הפעולה הזו ברקע בזמן שאתם מבצעים את השלבים הבאים.

אפשר ליצור אשכולות עם צמתי Arm בלבד, אבל במדריך הזה קודם ניצור אשכול עם צמתי x86 בלבד כדי ללמוד על התהליך של התאמת אפליקציות x86 בלבד ל-Arm.

יצירת מאגר Docker ב-Artifact Registry

  1. יוצרים מאגר ב-Artifact Registry לאחסון קובצי אימג' של Docker:

    gcloud artifacts repositories create docker-repo \
          --repository-format=docker \
          --location=us-central1 \
          --description="Docker repository"
    
  2. מגדירים את כלי שורת הפקודה של Docker לאימות למאגר הזה ב-Artifact Registry:

    gcloud auth configure-docker us-central1-docker.pkg.dev
    

יצירת תמונת x86 והעברה שלה בדחיפה ל-Artifact Registry

  1. מבצעים build של גרסה של האפליקציה שתואמת ל-x86:

    docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/x86-hello:v0.0.1 . 
    
  2. מעבירים את האימג' ל-Artifact Registry:

    docker push us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/x86-hello:v0.0.1
    

פריסת אפליקציית x86

  1. מריצים את הסקריפט הבא כדי לוודא שהאשכול מוכן:

    echo
    echo -ne "Waiting for GKE cluster to finish provisioning"
    gke_status=""
    while [ -z $gke_status ]; do
       sleep 2
       echo -ne '.'   
       gke_status=$(gcloud container clusters list --format="value(STATUS)" --filter="NAME=$CLUSTER_NAME AND STATUS=RUNNING")
    done
    echo
    echo "GKE Cluster '$CLUSTER_NAME' is $gke_status" 
    echo
    

    כשהאשכול מוכן, הפלט אמור להיראות כך:

    GKE Cluster 'my-cluster' is RUNNING
    
  2. מאחזרים את פרטי הכניסה של האשכול כדי ש-kubectl יוכל להתחבר ל-Kubernetes API של האשכול:

    gcloud container clusters get-credentials $CLUSTER_NAME --location $CONTROL_PLANE_LOCATION --project $PROJECT_ID
    
  3. מעדכנים את התמונה באמצעות kustomize ומפעילים את אפליקציית x86:

    $(cd k8s/overlays/x86 && kustomize edit set image hello=us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/x86-hello:v0.0.1) 
    kubectl apply -k k8s/overlays/x86
    
  4. פריסת שירות כדי לחשוף את האפליקציה לאינטרנט:

    kubectl apply -f k8s/hello-service.yaml
    
  5. בודקים שהקצאת כתובת ה-IP החיצונית לשירות, hello-service, הסתיימה:

    echo
    echo -ne "Waiting for External IP to be provisioned"
    external_ip=""
    while [ -z $external_ip ]; do
       sleep 2
       echo -ne '.'
       external_ip=$(kubectl get svc hello-service --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")
    done
    echo
    echo "External IP: $external_ip"
    echo
    

    אחרי הקצאת כתובת ה-IP החיצונית, הפלט אמור להיראות כך:

    External IP: 203.0.113.0
    
  6. שולחים בקשת HTTP כדי לבדוק שהפריסה פועלת כמצופה:

    curl -w '\n' http://$external_ip
    

    הפלט אמור להיראות כך:

    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-mwfkd, CPU PLATFORM:linux/amd64
    

    הפלט מראה שהפריסה הזו שתואמת ל-x86 פועלת בצומת במאגר הצמתים שמוגדר כברירת מחדל בארכיטקטורה amd64. לצמתים במאגר הצמתים שמוגדר כברירת מחדל באשכול יש מעבדי x86 (Intel או AMD).

הוספת צמתי Arm לאשכול

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

נקודת ביקורת

עד עכשיו השגת את המטרות הבאות:

  • ליצור אשכול GKE באמצעות צמתים מסוג x86.
  • לאחסן קובץ אימג' של קונטיינר שתואם ל-x86 באמצעות Docker ב-Artifact Registry.
  • לפרוס עומס עבודה שתואם ל-x86 באשכול GKE.

הגדרתם סביבת אשכול עם צמתים מסוג x86 ועומס עבודה שתואם ל-x86. ההגדרה הזו דומה לסביבות האשכולות הקיימות שלכם אם אתם לא משתמשים כרגע בצמתי Arm ובעומסי עבודה שתואמים ל-Arm.

הוספת מאגר צמתים של Arm לאשכול

כדי להוסיף מאגר צמתים של Arm לאשכול קיים:

gcloud container node-pools create arm-pool \
    --cluster $CLUSTER_NAME \
    --location $CONTROL_PLANE_LOCATION \
    --machine-type=c4a-standard-2 \
    --num-nodes=1

סוג המכונה c4a-standard-2 הוא מכונת Arm VM מסדרת המכונות C4A.

תהליך יצירת מאגר צמתים עם צמתי Arm זהה לתהליך יצירת מאגר צמתים עם צמתי x86. אחרי שיוצרים את מאגר הצמתים הזה, פועלים באותו אשכול גם צמתי x86 וגם צמתי Arm.

מידע נוסף על הוספת מאגרי צמתים של Arm לאשכולות קיימים זמין במאמר הוספת מאגר צמתים של Arm לאשכול GKE.

הגדלת הקיבולת של האפליקציה הקיימת שפועלת בצמתים מבוססי x86

צמתים מסוגי ארכיטקטורה שונים יכולים לפעול יחד בצורה חלקה באשכול אחד. כברירת מחדל, GKE לא מקצה עומסי עבודה קיימים שפועלים בצמתי x86 לצמתי Arm באשכול, כי דחייה (taint) ממוקמת באופן אוטומטי בצמתי Arm. עם זאת, אם רוצים ש-GKE יקצה עומסי עבודה שתואמים ל-x86 ושאין להם טולרנטיות מתאימה לצמתי Arm, אפשר להגדיר את מאגרי הצמתים כך ש-GKE לא יוסיף את הדחייה. מידע נוסף זמין במאמר בנושא הגדרת דחיית ברירת המחדל של ארכיטקטורת Arm.

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

  1. מעדכנים את עומס העבודה ומגדילים את קנה המידה שלו ל-6 רפליקות:

    $(cd k8s/overlays/x86_increase_replicas && kustomize edit set image hello=us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/x86-hello:v0.0.1)
    kubectl apply -k k8s/overlays/x86_increase_replicas/
    
  2. מחכים 30 שניות ואז מריצים את הפקודה הבאה כדי לבדוק את סטטוס הפריסה:

    kubectl get pods -l="app=hello" --field-selector="status.phase=Pending"
    

    הפלט אמור להיראות כך:

    NAME                                    READY   STATUS    RESTARTS   AGE
    x86-hello-deployment-6b7b456dd5-6tkxd   0/1     Pending   0          40s
    x86-hello-deployment-6b7b456dd5-k95b7   0/1     Pending   0          40s
    x86-hello-deployment-6b7b456dd5-kc876   0/1     Pending   0          40s
    

    בפלט הזה מוצגים פודים עם סטטוס Pending (בהמתנה) כי לא נשאר מקום בצמתים מבוססי-x86. מאחר שהמידרוג האוטומטי של האשכול מושבת, והצמתים של Arm מוכתמים כברירת מחדל, עומסי העבודה לא ייפרסו באף אחד מהצמתים הזמינים של Arm. ההגדרה הזו מונעת מ-GKE לתזמן עומסי עבודה של x86 בצמתי Arm. כדי לבצע פריסה לצומתי Arm, צריך לציין שהפריסה תואמת לצומתי Arm. אפשר גם להגדיר את GKE להסרת ה-taint שמוגדר כברירת מחדל.

  3. בודקים את ה-Pods שנמצאים במצב Running:

    kubectl get pods -l="app=hello" --field-selector="status.phase=Running" -o wide
    

    הפלט אמור להיראות כך:

    NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE                                        NOMINATED NODE   READINESS GATES
    x86-hello-deployment-6b7b456dd5-cjclz   1/1     Running   0          62s   10.100.0.17   gke-my-cluster-default-pool-32019863-b41t   <none>           <none>
    x86-hello-deployment-6b7b456dd5-mwfkd   1/1     Running   0          34m   10.100.0.11   gke-my-cluster-default-pool-32019863-b41t   <none>           <none>
    x86-hello-deployment-6b7b456dd5-n56rg   1/1     Running   0          62s   10.100.0.16   gke-my-cluster-default-pool-32019863-b41t   <none>           <none>
    

    בפלט הזה, העמודה NODE מציינת שכל ה-Pods מהפריסה פועלים רק במאגר ברירת המחדל, כלומר ה-Pods שתואמים ל-x86 מתוזמנים רק לצמתים של x86. ה-Pod המקורי שכבר תזמן לפני יצירת מאגר הצמתים של Arm עדיין פועל באותו צומת.

  4. מריצים את הפקודה הבאה כדי לגשת לשירות ולראות את הפלט:

    for i in $(seq 1 6); do curl -w '\n' http://$external_ip; done
    

    הפלט אמור להיראות כך:

    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-cjclz, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-cjclz, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-n56rg, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-n56rg, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-cjclz, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-cjclz, CPU PLATFORM:linux/amd64
    

    מהפלט הזה אפשר לראות שכל ה-Pods שמשרתים בקשות פועלים בצמתי x86. חלק מה-Pods לא יכולים להגיב כי הם עדיין במצב Pending, כי אין מקום בצמתי x86 הקיימים והם לא יתוזמנו לצמתי Arm.

צריך לבנות מחדש את האפליקציה כדי להפעיל אותה ב-Arm

בקטע הקודם, הוספתם מאגר צמתים של Arm לאשכול הקיים. עם זאת, כשביצעתם הגדלה של אפליקציית x86 הקיימת, לא בוצע תזמון של אף אחד מעומסי העבודה לצמתי Arm. בקטע הזה, תבנו מחדש את האפליקציה כך שהיא תהיה תואמת ל-Arm, כדי שהיא תוכל לפעול בצמתי Arm באשכול.

בדוגמה הזו, צריך לבצע את השלבים האלה באמצעות docker build. הגישה הזו כוללת שני שלבים:

  • שלב ראשון: בניית הקוד ל-Arm.
  • שלב שני: מעתיקים את קובץ ההפעלה למאגר קטן.

אחרי שמבצעים את השלבים האלה, מקבלים תמונה שתואמת ל-Arm בנוסף לתמונה שתואמת ל-x86.

השלב השני של העתקת קובץ ההפעלה לקונטיינר אחר מתבסס על אחת השיטות המומלצות ליצירת קונטיינר, והיא ליצור את קובץ האימג' הקטן ביותר שאפשר.

במדריך הזה נעשה שימוש באפליקציה לדוגמה שנבנתה באמצעות שפת התכנות Golang. באמצעות Golang, אפשר לבצע קומפילציה צולבת של אפליקציה למערכות הפעלה שונות ולפלטפורמות CPU שונות על ידי ציון משתני סביבה, GOOS ו-GOARCH, בהתאמה.

  1. מריצים את הפקודה cat Dockerfile_arm כדי לראות את קובץ ה-Dockerfile שנכתב עבור Arm:

    #
    # Build: 1st stage
    #
    FROM golang:1.18-alpine as builder 
    WORKDIR /app
    COPY go.mod .
    COPY hello.go .
    RUN GOARCH=arm64 go build -o /hello && \
       apk add --update --no-cache file && \
       file /hello
    

    קטע הקוד שמוצג כאן מציג רק את השלב הראשון. שני השלבים נכללים בקובץ.

    בקובץ הזה, ההגדרה GOARCH=arm64 מורה לקומפיילר של Go לבצע build של האפליקציה עבור סט פקודות Arm. אין צורך להגדיר את GOOS כי תמונת הבסיס בשלב הראשון היא תמונת Linux Alpine.

  2. יוצרים את הקוד עבור Arm ומעבירים אותו בדחיפה ל-Artifact Registry:

    docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/arm-hello:v0.0.1 -f Dockerfile_arm .
    docker push us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/arm-hello:v0.0.1
    

פריסת גרסת Arm של האפליקציה

עכשיו, אחרי שהאפליקציה בנויה להרצה בצמתי Arm, אפשר לפרוס אותה בצמתי Arm באשכול.

  1. בודקים את add_arm_support.yaml על ידי הרצת הפקודה cat k8s/overlays/arm/add_arm_support.yaml:

    הפלט אמור להיראות כך:

       nodeSelector:
          kubernetes.io/arch: arm64
    

    התג nodeSelector מציין שעומס העבודה צריך לפעול רק בצמתי Arm. כשמשתמשים ב-nodeSelector, ‏ GKE מוסיף טולרנטיות שתואמת ל-דחייה (taint) שמוגדר כברירת מחדל בצמתי Arm, וכך מאפשר ל-GKE להקצות את עומס העבודה בצמתים האלה. מידע נוסף על הגדרת השדה הזה זמין במאמר הכנת עומס עבודה של Arm לפריסה.

  2. פורסים עותק אחד של גרסת האפליקציה שתואמת ל-Arm:

    $(cd k8s/overlays/arm && kustomize edit set image hello=us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/arm-hello:v0.0.1)
    kubectl apply -k k8s/overlays/arm
    
  3. ממתינים 5 שניות, ואז בודקים אם הפריסה של Arm עונה לבקשות curl:

    for i in $(seq 1 6); do curl -w '\n' http://$external_ip; done
    

    הפלט אמור להיראות כך:

    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-n56rg, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-n56rg, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-mwfkd, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-mwfkd, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-arm-pool-e172cff7-shwc, POD:arm-hello-deployment-69b4b6bdcc-n5l28, CPU PLATFORM:linux/arm64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:x86-hello-deployment-6b7b456dd5-n56rg, CPU PLATFORM:linux/amd64
    

    הפלט הזה צריך לכלול תגובות גם מהאפליקציות שתואמות ל-x86 וגם מהאפליקציות שתואמות ל-Arm, בתגובה לבקשה curl.

איך יוצרים תמונה מרובת ארכיטקטורות כדי להריץ עומס עבודה בארכיטקטורות שונות

אפשר להשתמש באסטרטגיה שמתוארת בקטע הקודם ולפרוס עומסי עבודה נפרדים עבור x86 ו-Arm, אבל זה ידרוש מכם לתחזק ולשמור על שני תהליכי build ושני קובצי אימג' של קונטיינרים.

הכי טוב לבנות ולהריץ את האפליקציה בצורה חלקה גם בפלטפורמות x86 וגם בפלטפורמות Arm. אנחנו ממליצים על הגישה הזו. כדי להריץ את האפליקציה עם מניפסט אחד בכמה פלטפורמות ארכיטקטורה, צריך להשתמש בתמונות מרובות ארכיטקטורות (multi-arch). מידע נוסף על תמונות מרובות ארכיטקטורות זמין במאמר יצירת תמונות מרובות ארכיטקטורות לעומסי עבודה של Arm.

כדי להשתמש בתמונות מרובות ארכיטקטורות, צריך לוודא שהאפליקציה עומדת בדרישות המוקדמות הבאות:

  • לאפליקציה שלך אין תלות בפלטפורמת ארכיטקטורה ספציפית.
  • כל התלויות חייבות להיות מיועדות למבנים מרובים או לפלטפורמות היעד לפחות.

אפליקציית הדוגמה שבה נעשה שימוש במדריך הזה עומדת בשני התנאים המוקדמים האלה. עם זאת, מומלץ לבדוק את האפליקציות שלכם כשיוצרים את התמונות שלהן עם תמיכה בכמה ארכיטקטורות, לפני שפורסים אותן בסביבת ייצור.

יצירה ודחיפה של תמונות מרובות ארכיטקטורות

אתם יכולים ליצור קובצי אימג' מרובי-ארכיטקטורה באמצעות Docker Buildx אם עומדים בדרישות המוקדמות הבאות:

  • תמונת הבסיס תומכת במספר ארכיטקטורות. כדי לבדוק את זה, מריצים את הפקודה docker manifest inspect בתמונת הבסיס ובודקים את רשימת פלטפורמות הארכיטקטורה. בסוף הקטע הזה יש דוגמה לאופן הבדיקה של תמונה.
  • האפליקציה לא דורשת שלבי בנייה מיוחדים לכל פלטפורמת ארכיטקטורה. אם נדרשו שלבים מיוחדים, יכול להיות ש-Buildx לא יספיק. תצטרכו ליצור Dockerfile נפרד לכל פלטפורמה וליצור את המניפסט באופן ידני באמצעות docker manifest create.

קובץ האימג' הבסיסי של האפליקציה לדוגמה הוא Alpine, שתומך בכמה ארכיטקטורות. אין גם שלבים ספציפיים לפלטפורמת ארכיטקטורה, כך שאפשר ליצור את התמונה מרובת הארכיטקטורות באמצעות Buildx.

  1. בודקים את קובץ Docker על ידי הפעלת הפקודה cat Dockerfile:

    # This is a multi-stage Dockerfile. 
    # 1st stage builds the app in the target platform
    # 2nd stage create a lean image coping the binary from the 1st stage
    
    #
    # Build: 1st stage
    #
    FROM golang:1.18-alpine as builder 
    ARG BUILDPLATFORM    
    ARG TARGETPLATFORM
    RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM"  
    WORKDIR /app
    COPY go.mod .
    COPY hello.go .
    RUN go build -o /hello && \
       apk add --update --no-cache file && \
       file /hello   
    
    #
    # Release: 2nd stage
    #
    FROM alpine
    WORKDIR /
    COPY --from=builder /hello /hello
    CMD [ "/hello" ]
    

    קובץ ה-Dockerfile הזה מגדיר שני שלבים: שלב הבנייה ושלב השחרור. אתם משתמשים באותו Dockerfile ששימש לבניית אפליקציית x86.

  2. מריצים את הפקודה הבאה כדי ליצור ולהשתמש ב-docker buildx חדש:

    docker buildx create --name multiarch --use --bootstrap
    

    אחרי שיצרתם את כלי הבנייה החדש הזה, אתם יכולים לבנות ולדחוף תמונה שתואמת גם ל-linux/amd64 וגם ל-linux/arm64 באמצעות הדגל --platform. לכל פלטפורמה שמסופקת עם הדגל, Buildx יוצר תמונה בפלטפורמת היעד. כש-Buildx יוצר את קובץ האימג' linux/arm64, הוא מוריד קובצי אימג' בסיסיים arm64. בשלב הראשון, המערכת בונה את הקובץ הבינארי בתמונה arm64 golang:1.18-alpine עבור arm64. בשלב השני, מתבצעת הורדה של תמונת arm64 Alpine Linux והקובץ הבינארי מועתק לשכבה של התמונה הזו.

  3. בנייה והעלאה של התמונה:

    docker buildx build -t us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/multiarch-hello:v0.0.1 -f Dockerfile --platform linux/amd64,linux/arm64 --push .
    

    הפלט אמור להיראות כך:

    => [linux/arm64 builder x/x] ..
    => [linux/amd64 builder x/x] ..
    

    בפלט הזה אפשר לראות שנוצרו שתי תמונות, אחת עבור linux/arm64 ואחת עבור linux/amd64.

  4. בודקים את קובץ המניפסט של תמונת המולטי-ארכיטקטורה החדשה:

    docker manifest inspect us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/multiarch-hello:v0.0.1
    

    הפלט אמור להיראות כך:

    {
       "schemaVersion": 2,
       "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
       "manifests": [
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 739,
             "digest": "sha256:dfcf8febd94d61809bca8313850a5af9113ad7d4741edec1362099c9b7d423fc",
             "platform": {
                "architecture": "amd64",
                "os": "linux"
             }
          },
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 739,
             "digest": "sha256:90b637d85a93c3dc03fc7a97d1fd640013c3f98c7c362d1156560bbd01f6a419",
             "platform": {
                "architecture": "arm64",
                "os": "linux"
             }
          }
       ]
    

    בפלט הזה, הקטע manifests כולל שני קובצי מניפסט, אחד עם ארכיטקטורת הפלטפורמה amd64 והשני עם ארכיטקטורת הפלטפורמה arm64.

    כשפורסים את קובץ האימג' של הקונטיינר הזה באשכול, GKE מוריד באופן אוטומטי רק את קובץ האימג' שתואם לארכיטקטורה של הצומת.

פריסת הגרסה מרובת הארכיטקטורות של האפליקציה

  1. לפני שמפעילים את תמונת המולטי-ארכיטקטורה, צריך למחוק את עומסי העבודה המקוריים:

    kubectl delete deploy x86-hello-deployment arm-hello-deployment
    
  2. בודקים את add_multiarch_support.yaml kustomize overlay על ידי הרצת הפקודה cat k8s/overlays/multiarch/add_multiarch_support.yaml:

    הפלט כולל את קבוצת הטולרנטיות הבאה:

       tolerations:
          - key: kubernetes.io/arch
             operator: Equal
             value: arm64
             effect: NoSchedule
    

    הטולרנטיות הזו מאפשרת להריץ את עומס העבודה בצמתי Arm באשכול, כי הטולרנטיות תואמת לדחייה שמוגדרת כברירת מחדל בכל צמתי Arm. עכשיו עומס העבודה הזה יכול לפעול בכל צומת באשכול, ולכן נדרשת רק הסבילות. אם מגדירים רק את ה-toleration, ‏ GKE יכול לתזמן את עומס העבודה גם לצמתי x86 וגם לצמתי Arm. אם רוצים לציין איפה GKE יכול לתזמן עומסי עבודה, אפשר להשתמש בבוררי צמתים ובכללי שיוך צמתים. מידע נוסף על הגדרת השדות האלה זמין במאמר הכנת עומס עבודה של Arm לפריסה.

  3. פורסים את קובץ האימג' של הקונטיינר עם כמה ארכיטקטורות עם 6 רפליקות:

    $(cd k8s/overlays/multiarch && kustomize edit set image hello=us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/multiarch-hello:v0.0.1)
    kubectl apply -k k8s/overlays/multiarch
    
  4. ממתינים 10 שניות ואז מוודאים שכל העותקים של האפליקציה פועלים:

    kubectl get pods -l="app=hello" -o wide
    

    הפלט אמור להיראות כך:

    NAME                                         READY   STATUS    RESTARTS   AGE   IP            NODE                                        NOMINATED NODE   READINESS GATES
    multiarch-hello-deployment-65bfd784d-5xrrr   1/1     Running   0          95s   10.100.1.5    gke-my-cluster-arm-pool-e172cff7-shwc       <none>           <none>
    multiarch-hello-deployment-65bfd784d-7h94b   1/1     Running   0          95s   10.100.1.4    gke-my-cluster-arm-pool-e172cff7-shwc       <none>           <none>
    multiarch-hello-deployment-65bfd784d-7qbkz   1/1     Running   0          95s   10.100.1.7    gke-my-cluster-arm-pool-e172cff7-shwc       <none>           <none>
    multiarch-hello-deployment-65bfd784d-7wqb6   1/1     Running   0          95s   10.100.1.6    gke-my-cluster-arm-pool-e172cff7-shwc       <none>           <none>
    multiarch-hello-deployment-65bfd784d-h2g2k   1/1     Running   0          95s   10.100.0.19   gke-my-cluster-default-pool-32019863-b41t   <none>           <none>
    multiarch-hello-deployment-65bfd784d-lc9dc   1/1     Running   0          95s   10.100.0.18   gke-my-cluster-default-pool-32019863-b41t   <none>           <none>
    

    הפלט הזה כולל עמודה NODE שמציינת שה-Pods פועלים בשני הצמתים במאגר הצמתים של Arm ובצמתים אחרים במאגר הצמתים שמוגדר כברירת מחדל (x86).

  5. מריצים את הפקודה הבאה כדי לגשת לשירות ולראות את הפלט:

    for i in $(seq 1 6); do curl -w '\n' http://$external_ip; done
    

    הפלט אמור להיראות כך:

    Hello from NODE:gke-my-cluster-arm-pool-e172cff7-shwc, POD:multiarch-hello-deployment-65bfd784d-7qbkz, CPU PLATFORM:linux/arm64
    Hello from NODE:gke-my-cluster-default-pool-32019863-b41t, POD:multiarch-hello-deployment-65bfd784d-lc9dc, CPU PLATFORM:linux/amd64
    Hello from NODE:gke-my-cluster-arm-pool-e172cff7-shwc, POD:multiarch-hello-deployment-65bfd784d-5xrrr, CPU PLATFORM:linux/arm64
    Hello from NODE:gke-my-cluster-arm-pool-e172cff7-shwc, POD:multiarch-hello-deployment-65bfd784d-7wqb6, CPU PLATFORM:linux/arm64
    Hello from NODE:gke-my-cluster-arm-pool-e172cff7-shwc, POD:multiarch-hello-deployment-65bfd784d-7h94b, CPU PLATFORM:linux/arm64
    Hello from NODE:gke-my-cluster-arm-pool-e172cff7-shwc, POD:multiarch-hello-deployment-65bfd784d-7wqb6, CPU PLATFORM:linux/arm64
    

    אפשר לראות שקבוצות ה-Pod שפועלות בפלטפורמות ארכיטקטורה עונות על הבקשות.

יצרתם ופרסתם תמונה מרובת ארכיטקטורות כדי להריץ עומס עבודה בצורה חלקה בכמה ארכיטקטורות.

הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, אפשר למחוק את הפרויקט שמכיל את המשאבים, או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד.

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

מחיקת הפרויקט

הדרך הקלה ביותר לבטל את החיוב היא למחוק את הפרויקט שיצרתם בשביל המדריך הזה.

כדי למחוק את הפרויקט:

  1. במסוף Google Cloud , נכנסים לדף Manage resources.

    כניסה לדף Manage resources

  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

מחיקת השירות, האשכול והמאגר

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

  1. מריצים את הפקודה kubectl delete כדי למחוק את השירות של האפליקציה:

    kubectl delete service hello-service
    

    הפקודה הזו מוחקת את מאזן העומסים של Compute Engine שיצרתם כשחשפתם את הפריסה.

  2. כדי למחוק את האשכול, מריצים את הפקודה gcloud container clusters delete:

    gcloud container clusters delete $CLUSTER_NAME --location $CONTROL_PLANE_LOCATION
    
  3. מחיקת המאגר:

    gcloud artifacts repositories delete docker-repo —location=us-central1 --async
    

המאמרים הבאים