1. סקירה כללית
בשיעור ה-Lab הזה נדגים תכונות ויכולות שנועדו לייעל את תהליך הפיתוח של מהנדסי תוכנה שנדרשים לפתח אפליקציות NodeJS בסביבה בקונטיינרים. בדרך כלל, פיתוח קונטיינרים דורש מהמשתמש להבין את הפרטים של הקונטיינרים ואת תהליך build של הקונטיינרים. בנוסף, מפתחים בדרך כלל צריכים להפסיק את העבודה, לצאת מסביבת הפיתוח המשולבת (IDE) כדי לבדוק את האפליקציות שלהם ולנפות מהן באגים בסביבות מרוחקות. בעזרת הכלים והטכנולוגיות שמוזכרים במדריך הזה, מפתחים יכולים לעבוד ביעילות עם אפליקציות מבוססות-קונטיינרים בלי לצאת מסביבת הפיתוח המשולבת שלהם.
מה תלמדו
בשיעור ה-Lab הזה תלמדו שיטות לפיתוח באמצעות קונטיינרים ב-GCP, כולל:
- יצירת אפליקציית Nodejs התחלתית
- הגדרת אפליקציית Nodejs לפיתוח קונטיינרים
- תכנות של שירות CRUD Rest פשוט
- פריסה ב-GKE
- ניפוי באגים במצב שגיאה
- שימוש בנקודת עצירה (breakpoint) או ביומנים
- פריסה מהירה של שינויים בחזרה ל-GKE
- אופציונלי: שילוב של CloudSQL להתמדה בקצה העורפי
2. הגדרה ודרישות
הגדרת סביבה בקצב אישי
- נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.



- שם הפרויקט הוא השם המוצג למשתתפים בפרויקט. זו מחרוזת של תווים שלא נמצאת בשימוש ב-Google APIs, ואפשר לעדכן אותה בכל שלב.
- מזהה הפרויקט חייב להיות ייחודי לכל הפרויקטים ב-Google Cloud, והוא קבוע (אי אפשר לשנות אותו אחרי שהוא מוגדר). מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית. בדרך כלל לא צריך לדעת מה היא. ברוב סדנאות ה-Codelab, תצטרכו להפנות למזהה הפרויקט (ובדרך כלל הוא מזוהה כ-
PROJECT_ID), אז אם אתם לא אוהבים אותו, תוכלו ליצור מזהה אקראי אחר, או לנסות ליצור מזהה משלכם ולראות אם הוא זמין. אחרי שהפרויקט נוצר, הוא 'קפוא'. - יש ערך שלישי, מספר פרויקט, שמשמש חלק מממשקי ה-API. מידע נוסף על שלושת הערכים האלה מופיע במאמרי העזרה.
- בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API. העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי לא תהיה עלות בכלל. כדי לכבות את המשאבים ולא לחייב אתכם מעבר למה שמוסבר במדריך הזה, צריך לפעול לפי ההוראות לניקוי שמופיעות בסוף ה-Codelab. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
הפעלת Cloud Shell Editor
ה-Lab הזה תוכנן ונבדק לשימוש עם Google Cloud Shell Editor. כדי לגשת לכלי העריכה,
- נכנסים לפרויקט Google בכתובת https://console.cloud.google.com.
- בפינה השמאלית העליונה, לוחצים על סמל העורך של Cloud Shell.

- ייפתח חלונית חדשה בחלק התחתון של החלון.
- לוחצים על הלחצן 'פתיחת הכלי לעריכה'.

- העורך ייפתח עם סייר בצד שמאל ועורך באזור המרכזי
- חלונית טרמינל אמורה להיות זמינה גם בתחתית המסך
- אם הטרמינל לא פתוח, משתמשים בשילוב המקשים Ctrl + ` כדי לפתוח חלון טרמינל חדש.
הגדרת gcloud
ב-Cloud Shell, מגדירים את מזהה הפרויקט ואת האזור שבו רוצים לפרוס את האפליקציה. שומרים אותם כמשתנים PROJECT_ID ו-REGION.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
הגדרה של אשכול GKE ומסד נתונים
- מורידים את סקריפט ההגדרה והופכים אותו לסקריפט שאפשר להפעיל.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/setup.sh
chmod +x setup.sh
הקצאת התשתית שמשמשת בשיעור ה-Lab הזה
בשיעור ה-Lab הזה תפרסו קוד ב-GKE ותגשו לנתונים שמאוחסנים במסד נתונים של Spanner. סקריפט ההגדרה שמופיע בהמשך מכין את התשתית הזו בשבילכם.
- פותחים את הקובץ
setup.shועורכים את ערכי הסיסמאות שמוגדרים כרגע כ-CHANGEME - מריצים את סקריפט ההגדרה כדי להפעיל אשכול GKE ומסד נתונים של CloudSQL שבהם תשתמשו ב-Lab הזה
./setup.sh
- ב-Cloud Shell, יוצרים ספרייה חדשה בשם
mynodejsapp
mkdir mynodejsapp
- עוברים לספרייה הזו ופותחים אותה כסביבת עבודה. הפעולה הזו תטען מחדש את העורך על ידי יצירת הגדרת סביבת עבודה בתיקייה החדשה שנוצרה.
cd mynodejsapp && cloudshell workspace .
- מתקינים את Node ו-NPM באמצעות NVM.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
# This loads nvm bash_completion
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
nvm install stable
nvm alias default stable
3. יצירת אפליקציה חדשה למתחילים
- אתחול האפליקציה
יוצרים קובץ package.json על ידי הרצת הפקודה הבאה
npm init
Choose the entry point: (index.js) src/index.js and default values for the rest of the parameters. This will create the file with following contents
{
"name": "mynodejsapp",
"version": "1.0.0",
"description": "",
"main": "src/index.js",,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
- הוספת נקודת כניסה
עורכים את הקובץ כדי לכלול את פקודת ההתחלה בסקריפט "start": "node src/index.js",. אחרי השינוי, הסקריפטים צריכים להיראות כמו קטע הקוד הבא:
"scripts": {
"start": "node src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
- הוספת התלות ב-Express
הקוד שאנחנו הולכים להוסיף משתמש גם ב-express, אז נוסיף את התלות הזו לקובץ package.json. לכן, אחרי כל השינויים, הקובץ package.json צריך להיראות כמו בדוגמה שלמטה.
{
"name": "mynodejsapp",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Your Name",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
}
}
- יצירת הקובץ index.js
יוצרים ספריית קובצי המקור בשם src
יוצרים את הקובץ src/index.js עם הקוד הבא
const express = require('express');
const app = express();
const PORT = 8080;
app.get('/', (req, res) => {
var message="Greetings from Node";
res.send({ message: message });
});
app.listen(PORT, () => {
console.log(`Server running at: http://localhost:${PORT}/`);
});
שימו לב שהיציאה מוגדרת לערך 8080
יצירת קובצי מניפסט
Skaffold מספקת כלים משולבים כדי לפשט את פיתוח הקונטיינרים. בשלב הזה תאתחלו את skaffold, שיצור באופן אוטומטי קובצי YAML בסיסיים של Kubernetes. מריצים את הפקודה שלמטה כדי להתחיל בתהליך.
מריצים את הפקודה הבאה במסוף
skaffold init --generate-manifests
כשמוצגת בקשה:
- מזינים 8080 בשדה של היציאה.
- מזינים y כדי לשמור את ההגדרה.
שני קבצים נוספים לסביבת העבודה, skaffold.yaml ו-deployment.yaml
עדכון שם האפליקציה
ערכי ברירת המחדל שכלולים בתצורה לא תואמים כרגע לשם האפליקציה. מעדכנים את הקבצים כך שיפנו לשם האפליקציה ולא לערכי ברירת המחדל.
- שינוי רשומות בהגדרות של Skaffold
- פתיחה של
skaffold.yaml - בוחרים את שם התמונה שמוגדר כרגע כ-
package-json-image - לוחצים לחיצה ימנית ובוחרים באפשרות 'שינוי כל המופעים'.
- מקלידים את השם החדש בתור
mynodejsapp
- שינוי רשומות בהגדרות של Kubernetes
- פתיחת קובץ
deployment.yaml - בוחרים את שם התמונה שמוגדר כרגע כ-
package-json-image - לוחצים לחיצה ימנית ובוחרים באפשרות 'שינוי כל המופעים'.
- מקלידים את השם החדש בתור
mynodejsapp
שימו לב שבקובץ skaffold.yaml, הקטע build משתמש ב-buildpacks כדי להוסיף את האפליקציה למאגר. לקוד הזה אין Dockerfile והמפתח לא צריך ידע ב-Docker כדי להכניס את האפליקציה הזו לקונטיינר.
בנוסף, התצורה הזו של skaffold מפעילה אוטומטית סנכרון מהיר בין העורך לבין הקונטיינר הפועל. לא נדרשת הגדרה נוספת כדי להפעיל סנכרון מהיר.
4. הסבר על תהליך הפיתוח
בקטע הזה נסביר איך להשתמש בתוסף Cloud Code כדי ללמוד על התהליכים הבסיסיים, ואיך לאמת את ההגדרה של אפליקציית המתחילים.
Cloud Code משולב עם skaffold כדי לייעל את תהליך הפיתוח. כשפורסים ל-GKE בשלבים הבאים, Cloud Code ו-Skaffold יוצרים אוטומטית את קובץ האימג' של הקונטיינר, מעבירים אותו בדחיפה ל-Container Registry ואז פורסים את האפליקציה ל-GKE. התהליך הזה מתבצע מאחורי הקלעים, והפרטים לא מוצגים בתהליך הפיתוח. בנוסף, Cloud Code משפר את תהליך הפיתוח באמצעות יכולות ניפוי באגים ו-hotsync מסורתיות לפיתוח מבוסס-קונטיינרים.
פריסה ל-Kubernetes
- בחלונית שבתחתית Cloud Shell Editor, בוחרים באפשרות Cloud Code 

- בחלונית שמופיעה בחלק העליון, בוחרים באפשרות Run on Kubernetes (הפעלה ב-Kubernetes). אם מוצגת בקשה, בוחרים באפשרות Yes כדי להשתמש בהקשר הנוכחי של Kubernetes.

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

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

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

- כדי לראות פרטים נוספים ויומנים שמוזרמים בשידור חי מהקונטיינרים, בוחרים באפשרות Kubernetes: Run/Debug - Detailed (Kubernetes: הפעלה/ניפוי באגים – מפורט) בתפריט הנפתח של הערוץ בצד שמאל.

- כדי לחזור לתצוגה הפשוטה, בוחרים באפשרות Kubernetes: Run/Debug (הפעלה/ניפוי באגים) מהתפריט הנפתח.
- בסיום הבנייה והבדיקות, בכרטיסייה Output (פלט) מופיע הכיתוב
Resource deployment/mynodejsapp status completed successfully, וכתובת URL מופיעה ברשימה: "Forwarded URL from service demo-app: http://localhost:8080" - במסוף Cloud Code, מעבירים את העכבר מעל כתובת ה-URL בפלט (http://localhost:8080), ואז בתיאור הכלים שמופיע בוחרים באפשרות 'פתיחת תצוגה מקדימה באינטרנט'.
התשובה תהיה:
{"message":"Greetings from Node"}
Hot Reload
- נווט אל
src/index.js. עריכת הקוד של הודעת הפתיחה אל'Hello from Node'
אפשר לראות מיד שבחלון Output, בתצוגה Kubernetes: Run/Debug, הכלי watcher מסנכרן את הקבצים המעודכנים עם הקונטיינר ב-Kubernetes
Update initiated File sync started for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a File sync succeeded for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a Update succeeded
- אם עוברים לתצוגה
Kubernetes: Run/Debug - Detailed, אפשר לראות שהיא מזהה שינויים בקובץ ומפעילה מחדש את הצומת.
files modified: [src/index.js] Copying files:map[src/index.js:[/workspace/src/index.js]]togcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a Syncing 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a Watching for changes... [mynodejsapp] [mynodejsapp]> mynodejsapp@1.0.0 start /workspace [mynodejsapp]> node src/index.js [mynodejsapp] [mynodejsapp]Server running at: http://localhost:8080/
- כדי לראות את התוצאות המעודכנות, צריך לרענן את הדפדפן.
ניפוי באגים
- עוברים לתצוגת ניפוי הבאגים ועוצרים את השרשור הנוכחי
. - לוחצים על
Cloud Codeבתפריט התחתון ובוחרים באפשרותDebug on Kubernetesכדי להפעיל את האפליקציה במצבdebug.
- בתצוגה
Kubernetes Run/Debug - Detailedשל חלוןOutput, אפשר לראות ש-Skaffold יפרוס את האפליקציה הזו במצב ניפוי באגים. - ייקח כמה דקות עד שהאפליקציה תיבנה ותיפרס. הפעם תראו שהמנפה מחובר.
Port forwarding pod/mynodejsapp-6bbcf847cd-vqr6v in namespace default, remote port 9229 -> http://127.0.0.1:9229 [mynodejsapp]Debugger attached.
- שורת הסטטוס בתחתית המסך משנה את הצבע שלה מכחול לכתום, כדי לציין שהיא במצב ניפוי באגים.
- בתצוגה
Kubernetes Run/Debug, שימו לב שקונטיינר שאפשר לנפות בו באגים מופעל
**************URLs***************** Forwarded URL from service mynodejsapp-service: http://localhost:8080 Debuggable container started pod/mynodejsapp-deployment-6bc7598798-xl9kj:mynodejsapp (default) Update succeeded ***********************************
שימוש בנקודות עצירה
- פותחים את
src/index.js. - מחפשים את ההצהרה
var message="Greetings from Node"; - מוסיפים נקודת עצירה לשורה הזו בלחיצה על השטח הריק שמימין למספר השורה. יוצג אינדיקטור אדום כדי לציין שהוגדרה נקודת עצירה
- טוענים מחדש את הדפדפן ורואים שהדיבאגר עוצר את התהליך בנקודת העצירה ומאפשר לבדוק את המשתנים ואת מצב האפליקציה שפועלת מרחוק ב-GKE
- לוחצים על הקטע 'משתנים' עד שמוצאים את המשתנה
"message". - מבצעים את השורה בלחיצה על Step over (דילוג על שלב)

- הערך הנוכחי של המשתנה
"message"משתנה ל-"Greetings from Node" - לוחצים לחיצה כפולה על שם המשתנה target (יעד) ובחלון הקופץ שמופיע, משנים את הערך למשהו אחר, כמו
"Hello from Node" - לוחצים על הלחצן Continue (המשך) בחלונית הבקרה של ניפוי הבאגים.
- בודקים את התגובה בדפדפן, שבה מוצג עכשיו הערך המעודכן שהזנתם.
- כדי לעצור את מצב הניפוי באגים, לוחצים על לחצן העצירה
. כדי להסיר את נקודת העצירה, לוחצים עליה שוב.
5. פיתוח שירות REST פשוט של CRUD
בשלב הזה, האפליקציה שלכם מוגדרת באופן מלא לפיתוח מבוסס-קונטיינרים, ועברתם על תהליך העבודה הבסיסי לפיתוח באמצעות Cloud Code. בקטעים הבאים תתרגלו את מה שלמדתם על ידי הוספת נקודות קצה של שירות REST שמתחברות למסד נתונים מנוהל ב-Google Cloud.
הגדרת יחסי תלות
קוד האפליקציה משתמש במסד נתונים כדי לשמור את נתוני שירות ה-REST. מוסיפים את השורות הבאות לקובץ package.json כדי לוודא שיחסי התלות זמינים
- מוסיפים עוד שני יחסי תלות
pgו-sequelizeלקובץpackage.jsonכדי ליצור אפליקציית CRUD ב-Postgres. אחרי פרסום השינויים, קטע התלויות ייראה כך.
"dependencies": {
"express": "^4.16.4",
"pg": "^8.7.3",
"sequelize": "^6.17.0"
}
קידוד שירות REST
- הוספת קוד אפליקציית ה-CRUD לאפליקציה הזו
wget -O app.zip https://github.com/GoogleCloudPlatform/container-developer-workshop/raw/main/labs/nodejs/app.zip
unzip app.zip
הקוד הזה
- תיקיית models עם מודל הישות של
item - תיקייה controllers עם הקוד שמבצע פעולות CRUD
- תיקיית routes שמנתבת תבניות ספציפיות של כתובות URL לשיחות שונות
- תיקיית config עם פרטי הקישוריות למסד הנתונים
- שימו לב שהגדרת מסד הנתונים בקובץ
db.config.jsמתייחסת למשתני הסביבה שצריך לספק כדי להתחבר למסד הנתונים. בנוסף, צריך לנתח את הבקשה הנכנסת כדי לזהות קידוד כתובת URL. - מוסיפים את קטע הקוד הבא ב-
src/index.jsכדי להתחבר לקוד ה-CRUD מקובץ ה-JavaScript הראשי, ממש לפני הקטע האחרון שמתחיל ב-app.listen(PORT, () => {
const bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(
bodyParser.urlencoded({
extended: true,
})
)
const db = require("../app/models");
db.sequelize.sync();
require("../app/routes/item.routes")(app);
- עורכים את הפריסה בקובץ
deployment.yamlכדי להוסיף את משתני הסביבה שכוללים את פרטי הקישוריות למסד הנתונים.
מעדכנים את רשומת המפרט בסוף הקובץ כך שתתאים להגדרה הבאה
spec:
containers:
- name: mynodejsapp
image: mynodejsapp
env:
- name: DB_HOST
value: ${DB_INSTANCE_IP}
- name: DB_PORT
value: "5432"
- name: DB_USER
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: password
- name: DB_NAME
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: database
- מחליפים את הערך DB_HOST בכתובת של מסד הנתונים.
export DB_INSTANCE_IP=$(gcloud sql instances describe mytest-instance \
--format=json | jq \
--raw-output ".ipAddresses[].ipAddress")
envsubst < deployment.yaml > deployment.new && mv deployment.new deployment.yaml
פריסה ואימות של אפליקציה
- בחלונית שבתחתית Cloud Shell Editor, בוחרים באפשרות
Cloud Codeואז בוחרים באפשרותDebug on Kubernetesבחלק העליון של המסך. - כשסיימתם את הבנייה והבדיקות, בכרטיסייה Output (פלט) מופיעה ההודעה:
Resource deployment/mynodejsapp status completed successfully, וכתובת URL מופיעה: "Forwarded URL from service mynodejsapp: http://localhost:8080" - מוסיפים כמה פריטים.
מריצים את הפקודות הבאות בטרמינל של Cloud Shell
URL=localhost:8080
curl -X POST $URL/items -d '{"itemName":"Body Spray", "itemPrice":3.2}' -H "Content-Type: application/json"
curl -X POST $URL/items -d '{"itemName":"Nail Cutter", "itemPrice":2.5}' -H "Content-Type: application/json"
- מריצים את הפקודה $URL/items בדפדפן כדי לבדוק את ה-GET. אפשר גם להריץ את הפקודה curl משורת הפקודה
curl -X GET $URL/items
- בדיקת מחיקה: מנסים למחוק פריט על ידי הפעלה. משנים את הערך של item-id אם צריך.
curl -X DELETE $URL/items/1
This throws an error message
{"message":"Could not delete Item with id=[object Object]"}
זיהוי הבעיה ותיקון שלה
- מפעילים מחדש את האפליקציה במצב ניפוי באגים ומאתרים את הבעיה. ריכזנו בשבילכם כמה טיפים:
- אנחנו יודעים שמשהו לא בסדר בפקודה DELETE כי היא לא מחזירה את התוצאה הרצויה. לכן, צריך להגדיר את נקודת העצירה בשיטה
itemcontroller.js->exports.delete. - מריצים את ההפעלה שלב אחר שלב וצופים במשתנים בכל שלב כדי לראות את הערכים של משתנים מקומיים בחלון הימני.
- כדי לראות ערכים ספציפיים כמו
request.paramsמוסיפים את המשתנה הזה לחלון Watch.
- שימו לב שהערך שמוקצה ל-
idהואundefined. כדי לפתור את הבעיה, צריך לשנות את הקוד.
קטע הקוד המתוקן ייראה כך.
// Delete a Item with the specified id in the request
exports.delete = (req, res) => {
const id = req.params.id;
- אחרי שמפעילים מחדש את האפליקציה, מנסים למחוק שוב כדי לבדוק אם הבעיה נפתרה.
- כדי להפסיק את סשן ניפוי הבאגים, לוחצים על הריבוע האדום בסרגל הכלים לניפוי באגים

6. הסרת המשאבים
מעולה! בשיעור ה-Lab הזה יצרתם אפליקציית Nodejs חדשה מאפס והגדרתם אותה כך שתפעל במצב פריסה פעילה עם קונטיינרים. לאחר מכן פרסתם את האפליקציה וניקיתם בה באגים באשכול GKE מרוחק, לפי אותו תהליך פיתוח שקיים במערכות מסורתיות של אפליקציות.
כדי לנקות אחרי השלמת ה-Lab:
- מחיקת הקבצים שבהם השתמשתם במעבדה
cd ~ && rm -rf mynodejsapp && rm -f setup.sh
- מחיקת הפרויקט כדי להסיר את כל התשתית והמשאבים שקשורים אליו