פריסה רציפה (CD) ב-Google Kubernetes Engine (GKE) באמצעות Cloud Build

1. סקירה כללית

בשיעור ה-Lab הזה תלמדו להגדיר צינור עיבוד נתונים לפיתוח רציף (continuous delivery) ל-GKE באמצעות Cloud Build. בשיעור ה-Lab הזה נדגיש איך להפעיל משימות ב-Cloud Build לאירועי git שונים, וגם דפוס פשוט לגרסאות אוטומטיות של גרסה ראשונית (canary) ב-GKE.

כך תבצעו את השלבים הבאים:

  • יצירת אפליקציית GKE
  • אוטומציה של פריסות להסתעפויות Git
  • אוטומציה של פריסות בהסתעפות הראשית ב-Git
  • אוטומציה של פריסות של תגי git

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

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

  1. בוחרים פרויקט קיים או יוצרים פרויקט חדש ב-Google Cloud.

לדף בוחר הפרויקט

  1. מפעילים את החיוב בפרויקט.

הפעלת החיוב

3. הכנת הסביבה

  1. יוצרים משתני סביבה לשימוש במדריך הזה:
    export PROJECT_ID=$(gcloud config get-value project)
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
    export ZONE=us-central1-b
    export CLUSTER=gke-progression-cluster
    export APP_NAME=myapp
    
  2. מפעילים את ממשקי ה-API הבאים:
    • Resource Manager
    • GKE
    • Cloud Source Repositories
    • Cloud Build
    • Container Registry
    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        container.googleapis.com \
        sourcerepo.googleapis.com \
        cloudbuild.googleapis.com \
        containerregistry.googleapis.com \
        --async
    
  3. משכפלים את המקור לדוגמה ועוברים לספריית שיעור ה-Lab:
    git clone https://github.com/GoogleCloudPlatform/software-delivery-workshop.git gke-progression
    
    cd gke-progression/labs/gke-progression
    rm -rf ../../.git
    
  4. מחליפים את הערכים הזמניים לשמירת מקום (placeholder) במאגר לדוגמה ב-PROJECT_ID:בשלב הזה יוצרים מופעים של קובצי התצורה השונים שייחודיים לסביבה הנוכחית.כדי לראות דוגמה של התבניות שעודכנו, מריצים את הפקודה הבאה.
    cat k8s/deployments/dev/frontend-dev.yaml.tmpl
    
    מריצים את הפקודה הבאה כדי להחליף את המשתנים.
    for template in $(find . -name '*.tmpl'); do envsubst '${PROJECT_ID} ${ZONE} ${CLUSTER} ${APP_NAME}' < ${template} > ${template%.*}; done
    
    כדי לראות דוגמה של הקובץ אחרי ההחלפה, מריצים את הפקודה הבאה.
    cat k8s/deployments/dev/frontend-dev.yaml
    
  5. אם לא השתמשתם ב-Git ב-Cloud Shell בעבר, צריך להגדיר את הערכים user.name ו-user.email שבהם רוצים להשתמש:
    git config --global user.email "YOUR_EMAIL_ADDRESS"
    git config --global user.name "YOUR_USERNAME"
    
  6. שומרים את הקוד מהמאגר לדוגמה ב-Cloud Source Repositories:
    gcloud source repos create gke-progression
    git init
    git config credential.helper gcloud.sh
    git remote add gcp https://source.developers.google.com/p/$PROJECT_ID/r/gke-progression
    git branch -m main
    git add . && git commit -m "initial commit"
    git push gcp main
    
  7. יוצרים אשכול GKE.
    gcloud container clusters create ${CLUSTER} \
        --project=${PROJECT_ID} \
        --zone=${ZONE}
    
  8. נותנים ל-Cloud Build הרשאות ל-cluster.Cloud Build יבצע פריסה של האפליקציה באשכול GKE שלכם, ויהיו צורך בהרשאות כדי לעשות זאת.
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
        --role=roles/container.developer
    

הסביבה שלך מוכנה

4. יצירת אפליקציית GKE

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

  1. פיתוח האפליקציה באמצעות Cloud Build:
    gcloud builds submit --tag gcr.io/$PROJECT_ID/$APP_NAME:1.0.0 src/
    
  2. פריסה ידנית בסביבות Canary ובסביבות ייצור:יצירת פריסות ושירותים של סביבת הייצור ושל גרסה ראשונית (canary) באמצעות הפקודות kubectl apply.
    kubectl create ns production
    kubectl apply -f k8s/deployments/prod -n production
    kubectl apply -f k8s/deployments/canary -n production
    kubectl apply -f k8s/services -n production
    
    השירות שנפרס כאן ינתב את התנועה גם לפריסה הקנונית וגם לפריסת הייצור.
  3. בודקים את מספר ה-Pods הפעילים ומוודאים שיש ארבעה Pods שרצים בחזית, כולל שלושה לתעבורת נתונים בסביבת הייצור ויחידה אחת לגרסאות של גרסה ראשונית (canary). המשמעות היא ששינויים בגרסה הקנונית ישפיעו רק על 1 מתוך 4 (25%) מהמשתמשים.
    kubectl get pods -n production -l app=$APP_NAME -l role=frontend
    
  4. מאחזרים את כתובת ה-IP החיצונית של השירותים בסביבת הייצור.
    kubectl get service $APP_NAME -n production
    
    אחרי שמאזן העומסים מחזיר את כתובת ה-IP, ממשיכים לשלב הבא
  5. אחסון כתובת ה-IP החיצונית לשימוש מאוחר יותר.
    export PRODUCTION_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=production services $APP_NAME)
    
  6. מעיינים באפליקציה בודקים את פלט הגרסה של השירות. צריך להיות כתוב: Hello World v1.0
    curl http://$PRODUCTION_IP
    

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

5. אוטומציה של פריסות להסתעפויות Git

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

  1. מגדירים את הטריגר:הרכיב העיקרי של הטריגר הזה הוא השימוש בפרמטר branchName כדי לבצע התאמה ל-main ובפרמטר invertRegex שמוגדר כ-True ומשנה את הדפוס branchName כך שיתאים לכל דבר שאינו main. לידיעתך, השורות הבאות מופיעות ב-build/branch-trigger.json.
      "branchName": "main",
      "invertRegex": true
    
    בנוסף, השורות האחרונות בקובץ Cloud Build שבו נעשה שימוש בטריגר הזה יוצרות מרחב שמות שנקרא על שם ההסתעפות שהפעילה את המשימה, ואז האפליקציה והשירות פורסים במרחב השמות החדש. לידיעתך, השורות הבאות מופיעות ב-build/branch-cloudbuild.yaml
      kubectl get ns ${BRANCH_NAME} || kubectl create ns ${BRANCH_NAME}
      kubectl apply --namespace ${BRANCH_NAME} --recursive -f k8s/deployments/dev
      kubectl apply --namespace ${BRANCH_NAME} --recursive -f k8s/services
    
    עכשיו, אחרי שאתם מבינים את המנגנונים שבהם אתם משתמשים, אתם יכולים ליצור את הטריגר באמצעות הפקודה gcloud שלמטה.
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/branch-trigger.json
    
  2. כדי לבדוק את הטריגר, נכנסים לדף Cloud Build Triggers במסוף.כניסה לדף Triggers
  3. יצירת הסתעפות חדשה:
    git checkout -b new-feature-1
    
  4. משנים את הקוד כך שיציין את גרסה 1.1. עריכת src/app.py ומשנים את התשובה מ-1.0 ל-1.1
    @app.route('/')
    def hello_world():
        return 'Hello World v1.1'
    
  5. שומרים את השינוי ודוחפים למאגר המרוחק:
    git add . && git commit -m "updated" && git push gcp new-feature-1
    
  6. כדי לבדוק את ה-build בתהליך, נכנסים אל דף ההיסטוריה של Cloud Build במסוף.כניסה ל-Buildsאחרי שה-build מסתיים, ממשיכים לשלב הבא
  7. מאחזרים את כתובת ה-IP החיצונית של שירות ההסתעפות החדש שנפרס.
    kubectl get service $APP_NAME -n new-feature-1
    
    אחרי שמאזן העומסים מחזיר את כתובת ה-IP, ממשיכים לשלב הבא
  8. אחסון כתובת ה-IP החיצונית לשימוש מאוחר יותר.
    export BRANCH_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=new-feature-1 services $APP_NAME)
    
  9. מעיינים ב- applicationCheck את פלט הגרסה של השירות. צריך להיות כתוב: Hello World v1.0
    curl http://$BRANCH_IP
    

6. אוטומציה של פריסות להסתעפות הראשית ב-Git

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

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

  1. מגדירים את הטריגר להסתעפות הראשית:
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/main-trigger.json
    
  2. כדי לבדוק את הטריגר החדש, נכנסים לדף Cloud Build Triggers (טריגרים) במסוף.כניסה לדף Triggers (טריגרים)
  3. ממזגים את ההסתעפות לשורה הראשית ודוחפים למאגר המרוחק:
    git checkout main
    git merge new-feature-1
    git push gcp main
    
  4. כדי לבדוק את ה-build בתהליך, נכנסים אל דף ההיסטוריה של Cloud Build במסוף.כניסה ל-Buildsאחרי שה-build מסתיים, ממשיכים לשלב הבא
  5. בודקים את התגובות המרובות מה-serverRun באמצעות הפקודה הבאה, ושימו לב שבכ-25% מהתגובות מוצגת התגובה החדשה של Hello World v1.1
    while true; do curl -w "\n" http://$PRODUCTION_IP; sleep 1;  done
    
    כשהכול מוכן, אפשר להמשיך ללחוץ על Ctrl+c כדי לצאת מהלולאה.

7. אוטומציה של פריסות לתגי git

אחרי אימות הפריסה של גרסה ראשונית (canary) עם קבוצת משנה קטנה של תנועה, משחררים את הפריסה לשאר התנועה בזמן אמת.

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

  1. מגדירים את טריגר התג:
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/tag-trigger.json
    
  2. כדי לבדוק את הטריגר החדש, נכנסים לדף Cloud Build Triggers (טריגרים) במסוף.כניסה לדף Triggers (טריגרים)
  3. יוצרים תג חדש בדחיפה למאגר המרוחק:
    git tag 1.1
    git push gcp 1.1
    
  4. כדי לבדוק את ה-build בתהליך, נכנסים לדף ההיסטוריה של Cloud Build במסוף.כניסה ל-Builds
  5. בודקים את התגובות המרובות מה-serverRun להרצת הפקודה הבאה, והערה: ב-100% מהתשובות מוצגת התגובה החדשה של Hello World v1.1הפעולה עשויה להימשך כמה רגעים בזמן שהקבוצות החדשות נפרסות ונבדקות תקינות ב-GKE
    while true; do curl -w "\n" http://$PRODUCTION_IP; sleep 1;  done
    
    כדי להמשיך, אפשר ללחוץ על Ctrl+c כדי לצאת מהלולאה.כל הכבוד! יצרתם טריגרים ל-CI/CD ב-Cloud Build להסתעפויות ולתגים, כדי לפרוס את האפליקציות שלכם ב-GKE.

8. הסרת המשאבים

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

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