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

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

בשיעור ה-Lab הזה תלמדו להגדיר צינור עיבוד נתונים לפיתוח רציף (CD) ב-GKE באמצעות Cloud Build. בשיעור ה-Lab הזה נסביר איך להפעיל משימות של Cloud Build לאירועי git שונים, וגם נציג דפוס פשוט של הפצות קנרי אוטומטיות ב-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 הרשאות לאשכול.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) וייצור:יוצרים את ה-Deployment (פריסה) והשירותים של הייצור ושל גרסה ראשונית (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
    
    השירות שנפרס כאן ינתב תנועה גם לפריסות של גרסה ראשונית (canary) וגם לפריסות של prod.
  3. בודקים את מספר הפודים הפועלים. מוודאים שיש ארבעה Pods שפועלים בקצה הקדמי, כולל שלושה לתנועת Production ואחד לגרסאות איטרטיביות לקהל מצומצם (canary release). כלומר, שינויים בגרסה איטרטיבית לקהל מצומצם (canary release) ישפיעו רק על משתמש אחד מתוך 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 כשמתבצעת פעולת commit בכל ענף חוץ מ-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. משנים את הקוד כדי לציין v1.1Edit 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. כדי לבדוק את הסטטוס של הבנייה, עוברים אל הדף Cloud Build History במסוף.עוברים אל Builds אחרי שהבנייה מסתיימת, ממשיכים לשלב הבא.
  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. בודקים את הפלט של הגרסה של השירות. התוכן צריך להיות Hello World v1.0
    curl http://$BRANCH_IP
    

6. אוטומציה של פריסות עבור הענף הראשי של git

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

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

  1. מגדירים את הטריגר לענף הראשי:
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/main-trigger.json
    
  2. כדי לבדוק את הטריגר החדש, עוברים אל הדף Cloud Build Triggers במסוף.מעבר אל Triggers
  3. ממזגים את הענף עם השורה הראשית ומבצעים push למאגר המרוחק:
    git checkout main
    git merge new-feature-1
    git push gcp main
    
  4. כדי לבדוק את ה-build בתהליך, עוברים אל הדף Cloud Build History במסוף.עוברים אל Builds אחרי שה-build מסתיים, ממשיכים לשלב הבא.
  5. בודקים כמה תשובות מהשרת. מריצים את הפקודה הבאה ורואים שכ-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 History במסוף.מעבר אל Builds
  5. בדיקת כמה תגובות מהשרת מריצים את הפקודה הבאה ורואים ש-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, עוברים אל הדף 'ניהול משאבים'.
  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.