Настройте службу Cloud Run для доступа как к внутренней службе Cloud Run, так и к публичному Интернету.

1. Введение

Обзор

Для обеспечения безопасности сетевого трафика для своих сервисов и приложений многие организации используют виртуальную частную сеть (VPC) в Google Cloud с периметровым контролем для предотвращения утечки данных. Сеть VPC — это виртуальная версия физической сети, реализованная внутри производственной сети Google. Сеть VPC обеспечивает подключение для ваших виртуальных машин Compute Engine, предлагает собственные внутренние балансировщики нагрузки и прокси-системы для внутренних балансировщиков нагрузки приложений, подключается к локальным сетям с помощью туннелей Cloud VPN и VLAN-подключений для Cloud Interconnect, а также распределяет трафик от внешних балансировщиков нагрузки Google Cloud на бэкэнды.

В отличие от виртуальных машин, сервисы Cloud Run по умолчанию не привязаны к какой-либо конкретной сети VPC. В этом практическом занятии показано, как изменить настройки входящих соединений таким образом, чтобы доступ к сервису Cloud Run (например, к бэкэнд-сервису) имели только соединения, поступающие из VPC. Кроме того, в этом практическом занятии показано, как обеспечить доступ второго сервиса (например, фронтенд-сервиса) как к бэкэнд-сервису Cloud Run через VPC, так и к общедоступному интернету.

В этом примере бэкэнд-сервис Cloud Run возвращает "hello world". Фронтенд-сервис Cloud Run предоставляет поле ввода в пользовательском интерфейсе для получения URL-адреса. Затем фронтенд-сервис отправляет GET-запрос к этому URL-адресу (например, к бэкэнд-сервису), таким образом, это запрос между сервисами (а не запрос между браузером и сервисом). Когда фронтенд-сервис успешно связывается с бэкэндом, в браузере отображается сообщение "hello world". Затем вы увидите, как можно обратиться к https://curlmyip.org, чтобы получить IP-адрес вашего фронтенд-сервиса.

Что вы узнаете

  • Как разрешить доступ к сервису Cloud Run только трафику из VPC.
  • Как настроить исходящий трафик для сервиса Cloud Run (например, фронтенда) для связи с сервисом Cloud Run, имеющим только внутренний трафик (например, бэкендом), сохраняя при этом доступ к общедоступному Интернету для фронтенд-сервиса.

2. Настройка и требования

Предварительные требования

Активировать Cloud Shell

  1. В консоли Cloud нажмите «Активировать Cloud Shell» . d1264ca30785e435.png .

cb81e7c8e34bc8d.png

Если вы запускаете Cloud Shell впервые, вам будет показан промежуточный экран с описанием его возможностей. Если вы увидели промежуточный экран, нажмите «Продолжить» .

d95252b003979716.png

Подготовка и подключение к Cloud Shell займут всего несколько минут.

7833d5e1c5d18f54.png

Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Она предоставляет постоянный домашний каталог объемом 5 ГБ и работает в облаке Google, что значительно повышает производительность сети и аутентификацию. Большая часть, если не вся, ваша работа в этом практическом задании может быть выполнена с помощью браузера.

После подключения к 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 для внешнего интерфейса.

Перейдите в каталог frontend.

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.

Откройте URL-адрес фронтенд-сервиса в своем веб-браузере, например, https://frontend-your-hash-uc.a.run.app/

В текстовом поле введите URL-адрес серверной службы. Обратите внимание, что этот запрос направляется с внешнего экземпляра Cloud Run на серверную службу Cloud Run, а не из вашего браузера.

Вы увидите надпись «hello world».

4. Настройте серверную службу только для внутреннего входящего трафика.

Для интеграции сервиса Cloud Run в вашу частную сеть можно выполнить следующую команду gcloud.

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

Если вы попытаетесь обратиться к бэкэнд-сервису из фронтенд-сервиса, вы получите ошибку 404. Исходящее соединение (или выход) фронтенд-сервиса Cloud Run сначала идет в Интернет, поэтому Google Cloud не знает, откуда поступает запрос.

5. Настройте службу внешнего интерфейса для доступа к VPC.

В этом разделе вы настроите свой фронтенд-сервис Cloud Run для взаимодействия с бэкенд-сервисом через VPC.

Для этого вам потребуется добавить прямой исходящий трафик VPC к вашему сервису Cloud Run, чтобы обеспечить доступ к внутренним IP-адресам в сети VPC. Затем настройте исходящий трафик таким образом, чтобы в VPC направлялись только запросы к частным IP-адресам. Эта конфигурация позволит вашему фронтенду по-прежнему иметь доступ к общедоступному Интернету. Подробнее об этом можно узнать в документации по приему запросов от других сервисов 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)"

Создайте зону Cloud DNS для URL-адресов run.app.

Наконец, создайте зону Cloud DNS для URL-адресов run.app, чтобы Google Cloud мог рассматривать их как внутренние IP-адреса.

На предыдущем шаге вы настроили прямой исходящий трафик из VPC на использование только частных диапазонов IP-адресов. Это означает, что исходящие соединения от вашего фронтенд-сервиса будут направляться в сеть 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://" в запись DNS A.
  • Если после настройки зоны при попытке доступа к бэкэнду возникает ошибка 404, вы можете либо дождаться истечения срока действия кэша в глобальной записи run.app (например, 6 часов), либо создать новую ревизию (тем самым очистив кэш), выполнив следующую команду: gcloud beta run services update $FRONTEND --network=$SUBNET_NAME --subnet=$SUBNET_NAME --vpc-egress=private-ranges-only --region=$REGION

7. Поздравляем!

Поздравляем с завершением практического занятия!

Мы рекомендуем ознакомиться с документацией по использованию частных сетей в Cloud Run .

Что мы рассмотрели

  • Как разрешить доступ к сервису Cloud Run только трафику из VPC.
  • Как настроить исходящий трафик для сервиса Cloud Run (например, фронтенда) для связи с сервисом Cloud Run, имеющим только внутренний трафик (например, бэкендом), сохраняя при этом доступ к общедоступному Интернету для фронтенд-сервиса.

8. Уборка

Чтобы избежать непреднамеренных списаний средств (например, если эта служба Cloud Run будет случайно запущена больше раз, чем предусмотрено вашим ежемесячным лимитом вызовов Cloud Run в бесплатном тарифе ), вы можете либо удалить службу Cloud Run, либо удалить проект, созданный на шаге 2.

Чтобы удалить службы Cloud Run, перейдите в консоль Cloud Run по адресу https://console.cloud.google.com/functions/ и удалите службы $FRONTEND и $BACKEND, созданные вами в этом практическом задании.

Если вы решите удалить весь проект, перейдите по ссылке https://console.cloud.google.com/cloud-resource-manager , выберите проект, созданный на шаге 2, и нажмите «Удалить». После удаления проекта вам потребуется изменить проекты в вашем Cloud SDK. Список всех доступных проектов можно просмотреть, выполнив gcloud projects list .