איך להגדיר שירות Cloud Run לגשת לשירות Cloud Run פנימי באמצעות תעבורת נתונים יוצאת (egress) ישירה של VPC

1. מבוא

סקירה כללית

כדי לאבטח את תעבורת הנתונים ברשת עבור השירותים והאפליקציות שלהם, ארגונים רבים משתמשים ברשת ענן וירטואלי פרטי (VPC) ב-Google Cloud עם אמצעי בקרה היקפיים שמונעים זליגת נתונים. רשת VPC היא גרסה וירטואלית של רשת פיזית שמוטמעת בתוך רשת הייצור של Google. רשת VPC מספקת קישוריות למכונות הווירטואליות (VM) של Compute Engine, מציעה מאזני עומסים פנימיים של רשתות חיצוניות ומערכות לשרת proxy עבור מאזני עומסים פנימיים באפליקציות, מתחברת לרשתות מקומיות באמצעות מנהרות Cloud VPN וקבצים מצורפים ל-VLAN בשביל Cloud Interconnect, ומפיצה תעבורת נתונים מאזני עומסים חיצוניים של Google Cloud לקצה העורפי.

בניגוד למכונות וירטואליות, שירותי Cloud Run לא משויכים לרשת VPC מסוימת כברירת מחדל. ה-Codelab הזה מדגים איך לשנות הגדרות של תעבורת נתונים נכנסת (ingress) (חיבורים נכנסים), כך שרק תנועה שמגיעה מ-VPC יכולה לגשת לשירות Cloud Run (למשל לשירות לקצה העורפי). בנוסף, בשיעור הזה תלמדו איך לתת לשירות אחר (למשל שירות קצה קדמי) גישה לשירות Cloud Run לקצה העורפי דרך VPC.

בדוגמה הזו, שירות Cloud Run הקצה העורפי מחזיר את World hello. שירות Cloud Run הקצה לממשק המשתמש מספק שדה להזנת קלט בממשק המשתמש לאיסוף כתובת URL. לאחר מכן שירות הקצה הקדמי שולח בקשת GET לכתובת ה-URL הזו (למשל, השירות לקצה העורפי), ולכן הוא הופך לבקשת שירות לשירות (ולא מאתר לבקשת שירות). כששירות הקצה הקדמי יכול להגיע לקצה העורפי, הודעת שלום העולם מוצגת בדפדפן.

מה תלמדו

  • איך לאפשר תעבורת נתונים רק מ-VPC לשירות Cloud Run
  • איך להגדיר תעבורת נתונים יוצאת (egress) בשירות Cloud Run כדי לתקשר עם שירות Cloud Run פנימי בלבד לתעבורת נתונים נכנסת (ingress)

2. הגדרה ודרישות

דרישות מוקדמות

הפעלת Cloud Shell

  1. במסוף Cloud, לוחצים על Activate Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג לכם מסך ביניים שמתוארת בו. אם הוצג לכם מסך ביניים, לוחצים על המשך.

d95252b003979716.png

ההקצאה וההתחברות ל-Cloud Shell נמשכת כמה דקות.

7833d5e1c5d18f54.png

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

אחרי ההתחברות ל-Cloud Shell, אתם אמורים לראות שהפרויקט מאומת ושהפרויקט מוגדר לפי מזהה הפרויקט שלכם.

  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שהאימות בוצע:
gcloud auth list

פלט הפקודה

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שהפקודה ב-gcloud יודעת על הפרויקט שלכם:
gcloud config list project

פלט הפקודה

[core]
project = <PROJECT_ID>

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

gcloud config set project <PROJECT_ID>

פלט הפקודה

Updated property [core/project].

3. יצירת שירותי Cloud Run

הגדרה של משתני סביבה

אתם יכולים להגדיר משתני סביבה שישמשו ב-Codelab הזה.

REGION=<YOUR_REGION, e.g. us-central1>
FRONTEND=frontend
BACKEND=backend

יצירת שירות Cloud Run לקצה העורפי

קודם כל, יוצרים ספרייה עבור קוד המקור וה-cd בספרייה הזו.

mkdir -p internal-codelab/frontend internal-codelab/backend && cd internal-codelab/backend

לאחר מכן, יוצרים קובץ package.json עם התוכן הבא:

{
    "name": "backend-service",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "node index.js"
    },
    "dependencies": {
        "express": "^4.18.1"
    }
}

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

const express = require('express');

const app = express();

app.use(express.urlencoded({ extended: true }));

app.get('/', function (req, res) {
    res.send("hello world");
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`helloworld: listening on port ${port}`);
});

לבסוף, פורסים את השירות Cloud Run שמפעיל את הפקודה הבאה.

gcloud run deploy $BACKEND --source . --allow-unauthenticated --region $REGION

יצירת שירות Cloud Run בקצה הקדמי

עוברים לספריית הקצה הקדמי.

cd ../frontend

לאחר מכן, יוצרים קובץ package.json עם התוכן הבא:

{
  "name": "frontend",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^1.6.6",
    "express": "^4.18.2"
  }
}

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

const express = require("express");
const app = express();
const port = 8080;
const path = require('path');
const axios = require('axios');

// serve static content (index.html) using
// built-in middleware function in Express 
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));

// this endpoint receives a URL in the post body
// and then makes a get request to that URL
// results are sent back to the caller
app.post('/callService', async (req, res) => {

    const url = req.body.url;
    let message = "";

    try {
        console.log("url: ", url);
        const response = await axios.get(url);
        message = response.data;

    } catch (error) {
        message = error.message;
        console.error(error.message);
    }

    res.send(`
        ${message}
        <p>
        </p>
    `);
});

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});

יצירת ספרייה ציבורית עבור הקובץ index.html

mkdir public
touch public/index.html

ומעדכנים את ה-index.html כך שיכלול את הפרטים הבאים:

<html>
  <script
    src="https://unpkg.com/htmx.org@1.9.10"
    integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
    crossorigin="anonymous"
  ></script>
  <body>
    <div style="margin-top: 100px; margin-left: 100px">
      <h1>I'm the Frontend service on the Internet</h1>
      <form hx-trigger="submit" hx-post="/callService" hx-target="#message">
        <label for="url"> URL:</label>
        <input
          style="width: 308px"
          type="text"
          id="url"
          name="url"
          placeholder="The backend service URL"
          required
        />
        <button hx-indicator="#loading" type="submit">Submit</button>
        <p></p>
        <span class="htmx-indicator" id="loading"> Loading... </span>
        <div id="message" style="white-space: pre-wrap"></div>
        <p></p>
      </form>
    </div>
  </body>
</html>

לבסוף, פורסים את השירות Cloud Run שמפעיל את הפקודה הבאה.

gcloud run deploy $FRONTEND --source . --allow-unauthenticated --region $REGION

התקשרות לשירות לקצה העורפי

מוודאים שפרסתם בהצלחה שני שירותי Cloud Run.

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

בתיבת הטקסט, מזינים את כתובת ה-URL של השירות לקצה העורפי. לתשומת ליבכם: הבקשה הזו מנותבת ממכונה הקצה הקדמי של Cloud Run לשירות Cloud Run לקצה העורפי, במקום להיות מנותבת מהדפדפן.

יופיע הכיתוב 'שלום עולם'.

4. הגדרת השירות לקצה העורפי לתעבורת נתונים נכנסת (ingress) פנימית בלבד

מריצים את פקודת ה-gcloud הבאה כדי לאפשר רק לתעבורת נתונים מתוך רשת ה-VPC לגשת לשירות לקצה העורפי.

gcloud run services update $BACKEND --ingress internal --region $REGION

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

הפעם תופיע ההודעה 'הבקשה נכשלה עם קוד הסטטוס 404'

קיבלתם את השגיאה הזו כי הבקשה היוצאת של שירות Cloud Run (כלומר, תעבורת נתונים יוצאת) נשלחת קודם לאינטרנט, ולכן ל-Google Cloud אין מידע על מקור הבקשה.

בקטע הבא תגדירו לשירות הקצה הקדמי לגשת ל-VPC, כדי שמערכת Google Cloud תדע שהבקשה הגיעה מה-VPC, שמזוהה כמקור פנימי.

5. הגדרת שירות Frontend לגישה ל-VPC

בחלק הזה תגדירו את שירות Cloud Run בקצה הקדמי כדי שיתקשר עם השירות לקצה העורפי דרך VPC.

לשם כך, תצטרכו להוסיף תעבורת נתונים יוצאת (egress) ישירה של VPC למכונות של Cloud Run בקצה הקדמי כדי לספק לשירות כתובת IP פנימית לשימוש בתוך ה-VPC. לאחר מכן צריך להגדיר תעבורת נתונים יוצאת (egress), כך שכל החיבורים היוצאים מהשירות הקדמי יעברו ל-VPC.

ראשית, מריצים את הפקודה הבאה כדי להפעיל תעבורת נתונים יוצאת (egress) ישירה של VPC:

gcloud beta run services update $FRONTEND \
--network=default \
--subnet=default \
--vpc-egress=all-traffic \
--region=$REGION

עכשיו תוכלו לאשר שלשירות הקצה הקדמי יש גישה ל-VPC:

gcloud beta run services describe $FRONTEND \
--region=$REGION

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

VPC access:
    Network:         default
    Subnet:          default
    Egress:          all-traffic

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

הפעם יופיע הכיתוב "שלום עולם".

הערה: לשירות הקצה הקדמי לא תהיה גישה לאינטרנט כי כל תעבורת הנתונים היוצאת נותבה ל-VPC. לדוגמה, אם יתבצע ניסיון לגשת לכתובת https://curlmyip.org/ , הזמן הקצוב לתפוגה של שירות הקצה הקדמי יפוג.

6. מעולה!

מזל טוב, השלמת את Codelab!

מומלץ לעיין בתיעוד של Cloud Run ולקרוא איך להגדיר רשת פרטית לשירותי Cloud Run.

אילו נושאים דיברנו?

  • איך לאפשר תעבורת נתונים רק מ-VPC לשירות Cloud Run
  • איך להגדיר תעבורת נתונים יוצאת (egress) בשירות Cloud Run כדי לתקשר עם שירות Cloud Run פנימי בלבד לתעבורת נתונים נכנסת (ingress)

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

כדי להימנע מחיובים לא מכוונים (לדוגמה, אם שירותי Cloud Run מופעלים בטעות יותר פעמים מהקצאת ההפעלה החודשית של Cloud Run בתוכנית ללא תשלום), אפשר למחוק את Cloud Run או למחוק את הפרויקט שיצרתם בשלב 2.

כדי למחוק את השירות Cloud Run, יש לעבור אל Cloud Run Cloud Console בכתובת https://console.cloud.google.com/run ולמחוק את השירותים $FRONTEND ו-$BACKEND.

אם בוחרים למחוק את הפרויקט כולו, נכנסים לכתובת https://console.cloud.google.com/cloud-resource-manager, בוחרים את הפרויקט שיצרתם בשלב 2 ובוחרים באפשרות 'מחיקה'. אם תמחקו את הפרויקט, יהיה צריך לבצע שינויים בפרויקטים ב-Cloud SDK. כדי להציג את הרשימה של כל הפרויקטים הזמינים, אפשר להריץ את הפקודה gcloud projects list.