Định cấu hình dịch vụ Cloud Run để truy cập vào cả dịch vụ Cloud Run nội bộ và Internet công cộng

1. Giới thiệu

Tổng quan

Để bảo mật lưu lượng truy cập mạng cho các dịch vụ và ứng dụng của mình, nhiều tổ chức sử dụng mạng đám mây riêng ảo (VCP) trên Google Cloud với các biện pháp kiểm soát ngoại vi nhằm ngăn chặn hành vi đánh cắp dữ liệu. Mạng VPC là phiên bản ảo của mạng vật lý, được triển khai bên trong mạng lưới sản xuất của Google. Mạng VPC cung cấp khả năng kết nối cho các phiên bản máy ảo (VM) Compute Engine của bạn, cung cấp các Trình cân bằng tải mạng truyền qua nội bộ riêng và hệ thống proxy cho các Trình cân bằng tải ứng dụng nội bộ, kết nối với các mạng tại cơ sở bằng cách sử dụng các đường hầm Cloud VPN và tệp đính kèm VLAN cho Cloud Interconnect, đồng thời phân phối lưu lượng truy cập từ các trình cân bằng tải bên ngoài của Google Cloud đến các hệ thống phụ trợ.

Không giống như VM, các dịch vụ Cloud Run không được liên kết với bất kỳ mạng VPC cụ thể nào theo mặc định. Lớp học lập trình này minh hoạ cách thay đổi chế độ cài đặt lưu lượng vào (kết nối đầu vào) để chỉ lưu lượng truy cập đến từ VPC mới có thể truy cập vào dịch vụ Cloud Run (ví dụ: dịch vụ phụ trợ). Ngoài ra, lớp học lập trình này sẽ hướng dẫn bạn cách yêu cầu dịch vụ thứ hai (ví dụ: dịch vụ giao diện người dùng) truy cập vào cả dịch vụ Cloud Run phụ trợ thông qua VPC và tiếp tục có quyền truy cập Internet công cộng.

Trong ví dụ này, dịch vụ Cloud Run phụ trợ sẽ trả về Hello world (Xin chào mọi người). Dịch vụ Cloud Run giao diện người dùng cung cấp một trường nhập dữ liệu trong giao diện người dùng để thu thập URL. Sau đó, dịch vụ giao diện người dùng thực hiện yêu cầu GET tới URL đó (ví dụ: dịch vụ phụ trợ), do đó biến dịch vụ này thành dịch vụ cho yêu cầu dịch vụ (thay vì từ trình duyệt dẫn đến yêu cầu dịch vụ). Khi dịch vụ giao diện người dùng có thể truy cập thành công vào phần phụ trợ, thông báo Hello world (Xin chào thế giới) sẽ hiển thị trong trình duyệt. Sau đó, bạn sẽ tìm hiểu cách thực hiện lệnh gọi đến https://curlmyip.org để truy xuất địa chỉ IP của dịch vụ giao diện người dùng.

Kiến thức bạn sẽ học được

  • Cách chỉ cho phép lưu lượng truy cập từ VPC đến dịch vụ Cloud Run
  • Cách định cấu hình đầu ra trên dịch vụ Cloud Run (ví dụ: giao diện người dùng) để giao tiếp với dịch vụ Cloud Run chỉ vào nội bộ (ví dụ: phần phụ trợ), trong khi vẫn duy trì quyền truy cập Internet công cộng cho dịch vụ giao diện người dùng.

2. Thiết lập và yêu cầu

Điều kiện tiên quyết

Kích hoạt Cloud Shell

  1. Trong Cloud Console, hãy nhấp vào Kích hoạt Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Nếu đây là lần đầu tiên khởi động Cloud Shell, bạn sẽ thấy một màn hình trung gian mô tả về Cloud Shell. Nếu bạn nhìn thấy màn hình trung gian, hãy nhấp vào Tiếp tục.

d95252b003979716.png

Quá trình cấp phép và kết nối với Cloud Shell chỉ mất vài phút.

7833d5e1c5d18f54.pngS

Máy ảo này được tải tất cả các công cụ phát triển cần thiết. Dịch vụ này cung cấp thư mục gốc có dung lượng ổn định 5 GB và chạy trên Google Cloud, giúp nâng cao đáng kể hiệu suất và khả năng xác thực của mạng. Nhiều (nếu không nói là) tất cả công việc của bạn trong lớp học lập trình này đều có thể thực hiện bằng trình duyệt.

Sau khi kết nối với Cloud Shell, bạn sẽ thấy mình đã được xác thực và dự án được đặt thành mã dự án.

  1. Chạy lệnh sau trong Cloud Shell để xác nhận rằng bạn đã được xác thực:
gcloud auth list

Kết quả lệnh

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Chạy lệnh sau trong Cloud Shell để xác nhận rằng lệnh gcloud biết về dự án của bạn:
gcloud config list project

Kết quả lệnh

[core]
project = <PROJECT_ID>

Nếu chưa, bạn có thể thiết lập chế độ này bằng lệnh sau:

gcloud config set project <PROJECT_ID>

Kết quả lệnh

Updated property [core/project].

3. Tạo các dịch vụ Cloud Run

Thiết lập biến môi trường

Bạn có thể thiết lập các biến môi trường sẽ được dùng trong suốt lớp học lập trình này.

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

Tạo dịch vụ Cloud Run phụ trợ

Trước tiên, tạo một thư mục cho mã nguồn và cd vào thư mục đó.

mkdir -p egress-private-codelab/frontend-w-internet egress-private-codelab/backend && cd egress-private-codelab/backend

Sau đó, hãy tạo tệp "package.json" chứa nội dung sau:

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

Tiếp theo, hãy tạo một tệp nguồn index.js có nội dung như bên dưới. Tệp này chứa điểm truy cập cho dịch vụ và chứa logic chính cho ứng dụng.

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}`);
});

Cuối cùng, hãy triển khai dịch vụ Cloud Run bằng lệnh sau đây.

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

Tạo dịch vụ Cloud Run giao diện người dùng

Chuyển đến thư mục giao diện người dùng

cd ../frontend-w-internet

Sau đó, hãy tạo một tệp package.json với nội dung sau:

{
  "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"
  }
}

Tiếp theo, hãy tạo một tệp nguồn index.js có nội dung như bên dưới. Tệp này chứa điểm truy cập cho dịch vụ và chứa logic chính cho ứng dụng.

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}`);
});

Tạo thư mục công khai cho tệpindex.html

mkdir public
touch public/index.html

Và cập nhật index.html để chứa những nội dung sau:

<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>

Cuối cùng, hãy triển khai dịch vụ Cloud Run bằng lệnh sau đây.

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

Gọi cho Dịch vụ phụ trợ

Trong phần này, bạn sẽ xác minh rằng bạn đã triển khai thành công 2 dịch vụ Cloud Run.

Mở URL của dịch vụ giao diện người dùng trong trình duyệt web của bạn, ví dụ: https://frontend-your-hash-uc.a.run.app/

Trong hộp văn bản, hãy nhập URL của dịch vụ phụ trợ. Lưu ý rằng yêu cầu này được định tuyến từ phiên bản giao diện người dùng Cloud Run đến dịch vụ Cloud Run phụ trợ chứ không phải từ trình duyệt của bạn.

Bạn sẽ thấy thông báo "hello world" (Xin chào mọi người)

4. Chỉ đặt Dịch vụ phụ trợ cho lưu lượng vào nội bộ

Bạn có thể chạy lệnh gcloud sau đây để tích hợp dịch vụ Cloud Run vào mạng riêng của mình.

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

Nếu bạn thử gọi dịch vụ phụ trợ từ dịch vụ giao diện người dùng, bạn sẽ gặp lỗi 404. Kết nối đi (hoặc đầu ra) của dịch vụ Cloud Run trên giao diện người dùng đi ra Internet trước, vì vậy Google Cloud không biết nguồn gốc của yêu cầu.

5. Định cấu hình Dịch vụ giao diện người dùng để truy cập vào VPC

Trong phần này, bạn sẽ định cấu hình dịch vụ Cloud Run trên giao diện người dùng để giao tiếp với dịch vụ phụ trợ thông qua VPC.

Để thực hiện, bạn cần thêm đầu ra VPC trực tiếp vào dịch vụ Cloud Run giao diện người dùng để đảm bảo dịch vụ này có thể kết nối với các địa chỉ IP nội bộ trên mạng VPC. Sau đó, bạn sẽ định cấu hình đầu ra sao cho chỉ các yêu cầu gửi tới IP riêng tư mới được định tuyến đến VPC. Cấu hình này sẽ cho phép giao diện người dùng của bạn vẫn kết nối với Internet công cộng. Bạn có thể tìm hiểu thêm trong tài liệu về cách nhận yêu cầu từ các dịch vụ khác trên Cloud Run.

Định cấu hình đầu ra VPC trực tiếp

Trước tiên, hãy chạy lệnh này để sử dụng đầu ra VPC trực tiếp trên dịch vụ giao diện người dùng của bạn:

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

Giờ đây, bạn có thể xác nhận rằng dịch vụ giao diện người dùng của mình có quyền truy cập vào VPC:

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

Bạn sẽ thấy kết quả tương tự như

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

Bật quyền truy cập riêng tư trên Google

Tiếp theo, bạn sẽ bật Quyền truy cập riêng tư của Google trên mạng con bằng cách chạy lệnh sau:

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

Bạn có thể xác minh Quyền truy cập riêng tư của Google đã được bật bằng cách chạy lệnh sau:

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

Tạo vùng Cloud DNS cho các URL run.app

Cuối cùng, hãy tạo một vùng Cloud DNS cho các URL run.app để Google Cloud có thể coi những URL đó là địa chỉ IP nội bộ.

Ở bước trước, khi bạn định cấu hình đầu ra VPC trực tiếp thành chỉ dành cho các dải ô riêng tư. Điều này có nghĩa là các kết nối đi từ dịch vụ giao diện người dùng của bạn sẽ chỉ đi tới mạng VPC nếu đích đến là một IP nội bộ. Tuy nhiên, dịch vụ phụ trợ của bạn sử dụng URL run.app phân giải thành IP công khai.

Trong bước này, bạn sẽ tạo một vùng Cloud DNS cho các URL run.app để phân giải thành dải địa chỉ IP private.googleapis.com được coi là địa chỉ IP nội bộ. Giờ đây, mọi yêu cầu đối với những dải ô này sẽ được định tuyến thông qua mạng VPC.

Bạn có thể thực hiện việc này bằng cách: 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"

Bây giờ, khi cố gắng truy cập vào dịch vụ phụ trợ cho trang web của bạn, bạn sẽ thấy thông báo "hello world" ("xin chào thế giới") bị trả lại.

Và khi cố gắng kết nối Internet bằng https://curlmyip.org/, bạn sẽ thấy địa chỉ IP của mình.

6. Khắc phục sự cố

Dưới đây là một số thông báo lỗi mà bạn có thể gặp phải nếu chế độ cài đặt không được định cấu hình đúng cách.

  • Nếu bạn gặp lỗi getaddrinfo ENOTFOUND backend-your-hash-uc.a.run.app, hãy đảm bảo bạn không thêm "https://" với bản ghi DNS A
  • Nếu gặp lỗi 404 khi cố gắng truy cập vào phần phụ trợ sau khi định cấu hình vùng này, bạn có thể đợi bộ nhớ đệm trên bản ghi run.app chung hết hạn (ví dụ: 6 giờ) hoặc tạo một bản sửa đổi mới (sau đó xoá bộ nhớ đệm) bằng cách chạy lệnh sau: gcloud beta run services update $FRONTEND --network=$SUBNET_NAME --subnet=$SUBNET_NAME --vpc-egress=private-ranges-only --region=$REGION

7. Xin chúc mừng!

Chúc mừng bạn đã hoàn thành lớp học lập trình!

Bạn nên tham khảo tài liệu về Kết nối mạng riêng tư trên Cloud Run.

Nội dung đã đề cập

  • Cách chỉ cho phép lưu lượng truy cập từ VPC đến dịch vụ Cloud Run
  • Cách định cấu hình đầu ra trên dịch vụ Cloud Run (ví dụ: giao diện người dùng) để giao tiếp với dịch vụ Cloud Run chỉ vào nội bộ (ví dụ: phần phụ trợ), trong khi vẫn duy trì quyền truy cập Internet công cộng cho dịch vụ giao diện người dùng.

8. Dọn dẹp

Để tránh các khoản phí vô tình (ví dụ: nếu dịch vụ Cloud Run này vô tình bị gọi nhiều lần hơn mức phân bổ lệnh gọi Cloud Run hằng tháng của bạn ở cấp miễn phí), bạn có thể xoá dịch vụ Cloud Run hoặc xoá dự án bạn đã tạo ở Bước 2.

Để xoá các dịch vụ của Cloud Run, hãy truy cập vào Cloud Run Cloud Console tại https://console.cloud.google.com/functions/ rồi xoá các dịch vụ $FRONTEND và $BACKEND mà bạn đã tạo trong lớp học lập trình này.

Nếu chọn xoá toàn bộ dự án, bạn có thể truy cập vào https://console.cloud.google.com/cloud-resource-manager, chọn dự án mà bạn đã tạo ở Bước 2 rồi chọn Xoá. Nếu xoá dự án, bạn sẽ phải thay đổi các dự án trong Cloud SDK của mình. Bạn có thể xem danh sách tất cả dự án hiện có bằng cách chạy gcloud projects list.