กำหนดค่าบริการ Cloud Run เพื่อเข้าถึงทั้งบริการ Cloud Run ภายในและอินเทอร์เน็ตสาธารณะ

1. บทนำ

ภาพรวม

หลายองค์กรใช้เครือข่าย Virtual Private Cloud (VPC) ใน Google Cloud ที่มีการควบคุมขอบเขตเพื่อป้องกันการขโมยข้อมูล เพื่อรักษาความปลอดภัยให้กับการจราจรของข้อมูลในเครือข่ายสำหรับบริการและแอปพลิเคชันของตน เครือข่าย VPC คือเครือข่ายเสมือนที่จำลองมาจากเครือข่ายจริงซึ่งติดตั้งใช้งานภายในเครือข่ายที่ใช้งานจริงของ Google เครือข่าย VPC ช่วยให้การเชื่อมต่อสำหรับอินสแตนซ์เครื่องเสมือน (VM) ของ Compute Engine, มีตัวจัดสรรภาระงานเครือข่ายแบบส่งผ่านภายในดั้งเดิมและระบบพร็อกซีสำหรับตัวจัดสรรภาระงานแอปพลิเคชันภายใน, เชื่อมต่อกับเครือข่ายในองค์กรโดยใช้การแนบอุโมงค์ Cloud VPN และ VLAN สำหรับ Cloud Interconnect และกระจายการรับส่งข้อมูลจากตัวจัดสรรภาระงานภายนอกของ Google Cloud ไปยังแบ็กเอนด์

บริการ Cloud Run จะไม่เชื่อมโยงกับเครือข่าย VPC ใดๆ โดยค่าเริ่มต้น ซึ่งต่างจาก VM Codelab นี้แสดงวิธีเปลี่ยนการตั้งค่าขาเข้า (การเชื่อมต่อขาเข้า) เพื่อให้เฉพาะการรับส่งข้อมูลที่มาจาก VPC เท่านั้นที่เข้าถึงบริการ Cloud Run ได้ (เช่น บริการแบ็กเอนด์) นอกจากนี้ Codelab นี้ยังแสดงวิธีให้บริการที่ 2 (เช่น บริการฟรอนท์เอนด์) เข้าถึงทั้งบริการ Cloud Run แบ็กเอนด์ผ่าน VPC และยังคงเข้าถึงอินเทอร์เน็ตสาธารณะได้

ในตัวอย่างนี้ บริการ Cloud Run แบ็กเอนด์จะแสดงผล "hello world" บริการ Cloud Run ส่วนหน้ามีช่องป้อนข้อมูลใน UI เพื่อรวบรวม URL จากนั้นบริการส่วนหน้าจะส่งคำขอ GET ไปยัง URL นั้น (เช่น บริการแบ็กเอนด์) จึงทำให้คำขอนี้เป็นคำขอจากบริการไปยังบริการ (แทนที่จะเป็นคำขอจากเบราว์เซอร์ไปยังบริการ) เมื่อบริการส่วนหน้าเข้าถึงส่วนหลังได้สำเร็จ ข้อความ "hello world" จะแสดงในเบราว์เซอร์ จากนั้นคุณจะเห็นวิธีโทรไปยัง https://curlmyip.org เพื่อดึงข้อมูลที่อยู่ IP ของบริการฟรอนท์เอนด์

สิ่งที่คุณจะได้เรียนรู้

  • วิธีอนุญาตเฉพาะการรับส่งข้อมูลจาก VPC ไปยังบริการ Cloud Run
  • วิธีกำหนดค่าขาออกในบริการ Cloud Run (เช่น ฟรอนท์เอนด์) เพื่อสื่อสารกับบริการ Cloud Run ที่มีเฉพาะขาเข้าภายใน (เช่น แบ็กเอนด์) ขณะที่ยังคงรักษาสิทธิ์เข้าถึงอินเทอร์เน็ตสาธารณะสำหรับบริการฟรอนท์เอนด์

2. การตั้งค่าและข้อกำหนด

ข้อกำหนดเบื้องต้น

เปิดใช้งาน Cloud Shell

  1. จาก Cloud Console ให้คลิกเปิดใช้งาน Cloud Shell d1264ca30785e435.png

cb81e7c8e34bc8d.png

หากคุณเริ่มใช้ Cloud Shell เป็นครั้งแรก คุณจะเห็นหน้าจอระดับกลางที่อธิบายว่า Cloud Shell คืออะไร หากเห็นหน้าจอระดับกลาง ให้คลิกต่อไป

d95252b003979716.png

การจัดสรรและเชื่อมต่อกับ Cloud Shell จะใช้เวลาไม่นาน

7833d5e1c5d18f54.png

เครื่องเสมือนนี้โหลดเครื่องมือพัฒนาซอฟต์แวร์ทั้งหมดที่จำเป็นไว้แล้ว โดยมีไดเรกทอรีหลักแบบถาวรขนาด 5 GB และทำงานใน 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

ตั้งค่าตัวแปรสภาพแวดล้อม

คุณตั้งค่าตัวแปรสภาพแวดล้อมที่จะใช้ตลอดทั้งโค้ดแล็บนี้ได้

PROJECT_ID=<YOUR_PROJECT_ID>
REGION=<YOUR_REGION, e.g. us-central1>
FRONTEND=frontend-with-internet
BACKEND=backend
SUBNET_NAME=default

สร้างบริการ Cloud Run แบ็กเอนด์

ก่อนอื่นให้สร้างไดเรกทอรีสำหรับซอร์สโค้ดและใช้คำสั่ง cd เพื่อไปยังไดเรกทอรีนั้น

mkdir -p egress-private-codelab/frontend-w-internet egress-private-codelab/backend && cd egress-private-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-w-internet

จากนั้นสร้างไฟล์ 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",
    "htmx.org": "^1.9.10"
  }
}

จากนั้นสร้างไฟล์ต้นฉบับ 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 Request Tester service on the Internet</h1>
      <form hx-trigger="submit" hx-post="/callService" hx-target="#zen">
        <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="zen" 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 2 รายการใช้งานได้สำเร็จ

เปิด URL ของบริการส่วนหน้าในเว็บเบราว์เซอร์ เช่น https://frontend-your-hash-uc.a.run.app/

ป้อน URL สำหรับบริการแบ็กเอนด์ในกล่องข้อความ โปรดทราบว่าคำขอนี้จะกำหนดเส้นทางจากอินสแตนซ์ Cloud Run ฟรอนท์เอนด์ไปยังบริการ Cloud Run แบ็กเอนด์ ไม่ใช่จากเบราว์เซอร์ของคุณ

คุณจะเห็นข้อความ "hello world"

4. ตั้งค่าบริการแบ็กเอนด์สำหรับข้อมูลขาเข้าภายในเท่านั้น

คุณเรียกใช้คำสั่ง gcloud ต่อไปนี้เพื่อรวมบริการ Cloud Run เข้ากับเครือข่ายส่วนตัวได้

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

หากพยายามเรียกใช้บริการแบ็กเอนด์จากบริการฟรอนต์เอนด์ คุณจะได้รับข้อผิดพลาด 404 การเชื่อมต่อขาออก (หรือขาออก) ของบริการ Cloud Run ฟรอนท์เอนด์จะออกไปยังอินเทอร์เน็ตก่อน ดังนั้น Google Cloud จึงไม่ทราบแหล่งที่มาของคำขอ

5. กำหนดค่าบริการส่วนหน้าเพื่อเข้าถึง VPC

ในส่วนนี้ คุณจะได้กำหนดค่าบริการ Cloud Run ส่วนหน้าให้สื่อสารกับบริการแบ็กเอนด์ผ่าน VPC

โดยคุณจะต้องเพิ่มข้อมูลขาออก VPC โดยตรงไปยังบริการ Cloud Run ส่วนหน้าเพื่อให้แน่ใจว่าบริการจะเข้าถึงที่อยู่ IP ภายในในเครือข่าย VPC ได้ จากนั้นคุณจะกำหนดค่าขาออกเพื่อให้ระบบกำหนดเส้นทางเฉพาะคำขอไปยัง IP ส่วนตัวไปยัง VPC การกำหนดค่านี้จะช่วยให้ฟรอนท์เอนด์ยังคงเข้าถึงอินเทอร์เน็ตสาธารณะได้ ดูข้อมูลเพิ่มเติมได้ในเอกสารเกี่ยวกับการรับคำขอจากบริการ Cloud Run อื่นๆ

กำหนดค่าการออก VPC โดยตรง

ก่อนอื่น ให้เรียกใช้คำสั่งนี้เพื่อใช้ข้อมูลขาออก VPC โดยตรงในบริการฟรอนท์เอนด์

gcloud beta run services update $FRONTEND \
--network=$SUBNET_NAME \
--subnet=$SUBNET_NAME  \
--vpc-egress=private-ranges-only \
--region=$REGION

ตอนนี้คุณสามารถยืนยันว่าบริการฟรอนท์เอนด์มีสิทธิ์เข้าถึง VPC ได้แล้ว โดยทำดังนี้

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

คุณควรเห็นเอาต์พุตที่คล้ายกับ

VPC access:
    Network:        default
    Subnet:          default
    Egress:          private-ranges-only

เปิดใช้การเข้าถึง Google แบบส่วนตัว

จากนั้นเปิดใช้การเข้าถึง Google แบบส่วนตัวในซับเน็ตโดยเรียกใช้คำสั่งต่อไปนี้

gcloud compute networks subnets update $SUBNET_NAME \
--region=$REGION \
--enable-private-ip-google-access

คุณตรวจสอบว่าได้เปิดใช้การเข้าถึง Google แบบส่วนตัวแล้วได้โดยเรียกใช้คำสั่งนี้

gcloud compute networks subnets describe $SUBNET_NAME \
--region=$REGION \
--format="get(privateIpGoogleAccess)"

สร้างโซน DNS ของ Cloud สำหรับ URL ของ run.app

สุดท้าย ให้สร้างโซน Cloud DNS สำหรับ URL ของ run.app เพื่อให้ Google Cloud ถือว่า URL เหล่านั้นเป็นที่อยู่ IP ภายใน

ในขั้นตอนก่อนหน้าเมื่อคุณกำหนดค่าข้อมูลขาออก VPC โดยตรงเป็น private-ranges-only ซึ่งหมายความว่าการเชื่อมต่อขาออกจากบริการส่วนหน้าจะไปยังเครือข่าย VPC ก็ต่อเมื่อปลายทางเป็น IP ภายในเท่านั้น อย่างไรก็ตาม บริการแบ็กเอนด์ของคุณใช้ URL ของ run.app ที่จะเปลี่ยนเส้นทางไปยัง IP สาธารณะ

ในขั้นตอนนี้ คุณจะสร้างโซน Cloud DNS สำหรับ URL ของ run.app เพื่อให้แก้ไขช่วงที่อยู่ IP ของ private.googleapis.com ซึ่งระบบจะถือว่าเป็นที่อยู่ IP ภายใน ตอนนี้คำขอใดๆ ที่ส่งไปยังช่วงเหล่านี้จะกำหนดเส้นทางผ่านเครือข่าย VPC ของคุณ

คุณทำได้โดยไปที่ https://cloud.google.com/run/docs/securing/private-networking#from-other-services

# do not include the https:// in your DNS Name
# for example: backend-<hash>-uc.a.run.app
DNS_NAME=<your backend service URL without the https://>

gcloud dns --project=$PROJECT_ID managed-zones create codelab-backend-service \
 --description="" \
 --dns-name="a.run.app." \
 --visibility="private" \
 --networks=$SUBNET_NAME

gcloud dns --project=$PROJECT_ID record-sets create $DNS_NAME. \
--zone="codelab-backend-service" \
 --type="A" \
 --ttl="60" \
--rrdatas="199.36.153.8,199.36.153.9,199.36.153.10,199.36.153.11"

ตอนนี้เมื่อคุณพยายามเข้าถึงบริการแบ็กเอนด์ของเว็บไซต์ คุณจะเห็นข้อความ "hello world" ที่ส่งกลับมา

และเมื่อคุณพยายามเข้าถึงอินเทอร์เน็ตโดยใช้ https://curlmyip.org/ คุณจะเห็นที่อยู่ IP ของคุณ

6. การแก้ปัญหา

ข้อความแสดงข้อผิดพลาดที่คุณอาจพบหากกำหนดค่าการตั้งค่าไม่ถูกต้องมีดังนี้

  • หากได้รับข้อผิดพลาด getaddrinfo ENOTFOUND backend-your-hash-uc.a.run.app โปรดตรวจสอบว่าคุณไม่ได้เพิ่ม "https://" ลงในระเบียน A ของ DNS
  • หากได้รับข้อผิดพลาด 404 เมื่อพยายามเข้าถึงแบ็กเอนด์หลังจากกำหนดค่าโซน คุณสามารถรอให้แคชในระเบียน global.run.app หมดอายุ (เช่น 6 ชั่วโมง) หรือสร้างรีวิชันใหม่ (จึงเป็นการล้างแคช) โดยเรียกใช้คำสั่งต่อไปนี้ gcloud beta run services update $FRONTEND --network=$SUBNET_NAME --subnet=$SUBNET_NAME --vpc-egress=private-ranges-only --region=$REGION

7. ยินดีด้วย

ขอแสดงความยินดีที่ทำ Codelab นี้เสร็จสมบูรณ์

เราขอแนะนำให้อ่านเอกสารเกี่ยวกับเครือข่ายส่วนตัวใน Cloud Run

สิ่งที่เราได้พูดถึง

  • วิธีอนุญาตเฉพาะการรับส่งข้อมูลจาก VPC ไปยังบริการ Cloud Run
  • วิธีกำหนดค่าขาออกในบริการ Cloud Run (เช่น ฟรอนท์เอนด์) เพื่อสื่อสารกับบริการ Cloud Run ที่มีเฉพาะขาเข้าภายใน (เช่น แบ็กเอนด์) ขณะที่ยังคงรักษาสิทธิ์เข้าถึงอินเทอร์เน็ตสาธารณะสำหรับบริการฟรอนท์เอนด์

8. ล้างข้อมูล

หากต้องการหลีกเลี่ยงการเรียกเก็บเงินโดยไม่ตั้งใจ (เช่น หากบริการ Cloud Run นี้ถูกเรียกใช้โดยไม่ตั้งใจมากกว่าการจัดสรรการเรียกใช้ Cloud Run รายเดือนในระดับฟรี) คุณสามารถลบบริการ Cloud Run หรือลบโปรเจ็กต์ที่สร้างในขั้นตอนที่ 2 ได้

หากต้องการลบบริการ Cloud Run ให้ไปที่คอนโซล Cloud Run ที่ https://console.cloud.google.com/functions/ แล้วลบบริการ $FRONTEND และ $BACKEND ที่คุณสร้างใน Codelab นี้

หากเลือกที่จะลบทั้งโปรเจ็กต์ ให้ไปที่ https://console.cloud.google.com/cloud-resource-manager เลือกโปรเจ็กต์ที่สร้างในขั้นตอนที่ 2 แล้วเลือก "ลบ" หากลบโปรเจ็กต์ คุณจะต้องเปลี่ยนโปรเจ็กต์ใน Cloud SDK คุณดูรายการโปรเจ็กต์ทั้งหมดที่พร้อมใช้งานได้โดยเรียกใช้ gcloud projects list