Cómo configurar un servicio de Cloud Run para acceder a un servicio interno de Cloud Run con la salida de VPC directa

1. Introducción

Descripción general

Para proteger el tráfico de red de sus servicios y aplicaciones, muchas organizaciones usan una red de nube privada virtual (VPC) en Google Cloud con controles perimetrales para evitar el robo de datos. Una red de VPC es una versión virtual de una red física que se implementa dentro de la red de producción de Google. Una red de VPC proporciona conectividad para tus instancias de máquinas virtuales (VM) de Compute Engine, ofrece balanceadores de cargas de red de traspaso internos nativos y sistemas de proxy para balanceadores de cargas de aplicaciones internos, se conecta a redes locales a través de túneles de Cloud VPN y adjuntos de VLAN para Cloud Interconnect, y distribuye el tráfico de los balanceadores de cargas externos de Google Cloud a los backends.

A diferencia de las VMs, los servicios de Cloud Run no están asociados a ninguna red de VPC en particular de forma predeterminada. En este codelab, se muestra cómo cambiar la configuración de entrada (conexiones entrantes) para que solo el tráfico proveniente de una VPC pueda acceder a un servicio de Cloud Run (p.ej., un servicio de backend). Además, en este codelab, se muestra cómo hacer que un segundo servicio (p.ej., un servicio de frontend) acceda al servicio de backend de Cloud Run a través de una VPC.

En este ejemplo, el servicio de Cloud Run de backend devuelve Hello World. El servicio de Cloud Run de frontend proporciona un campo de entrada en la IU para recopilar una URL. Luego, el servicio de frontend realiza una solicitud GET a esa URL (p.ej., el servicio de backend), lo que la convierte en una solicitud de servicio a servicio (en lugar de una solicitud de navegador a servicio). Cuando el servicio de frontend puede acceder correctamente al backend, se muestra el mensaje hello world en el navegador.

Qué aprenderás

  • Cómo permitir solo el tráfico de una VPC a tu servicio de Cloud Run
  • Cómo configurar la salida en un servicio de Cloud Run para comunicarse con un servicio de Cloud Run solo de entrada interna

2. Configuración y requisitos

Requisitos previos

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shelld1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si es la primera vez que inicias Cloud Shell, aparecerá una pantalla intermedia en la que se describirá qué es. Si apareció una pantalla intermedia, haz clic en Continuar.

d95252b003979716.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

7833d5e1c5d18f54.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que te autenticaste y que el proyecto se configuró con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Crea los servicios de Cloud Run

Configura variables de entorno

Puedes establecer variables de entorno que se usarán a lo largo de este codelab.

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

Crea el servicio de Cloud Run de backend

Primero, crea un directorio para el código fuente y, luego, usa el comando cd para acceder a él.

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

Luego, crea un archivo package.json con el siguiente contenido:

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

A continuación, crea un archivo fuente index.js con el siguiente contenido. Este archivo contiene el punto de entrada del servicio y la lógica principal de la app.

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

Por último, implementa el servicio de Cloud Run con el siguiente comando.

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

Crea el servicio de Cloud Run de frontend

Navega al directorio de frontend.

cd ../frontend

Luego, crea un archivo package.json con el siguiente contenido:

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

A continuación, crea un archivo fuente index.js con el siguiente contenido. Este archivo contiene el punto de entrada del servicio y la lógica principal de la app.

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

Crea un directorio público para el archivo index.html

mkdir public
touch public/index.html

Y actualiza el archivo index.html para que contenga lo siguiente:

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

Por último, implementa el servicio de Cloud Run con el siguiente comando.

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

Llama al servicio de backend

Verifica que hayas implementado correctamente dos servicios de Cloud Run.

Abre la URL del servicio de frontend en tu navegador web.

En el cuadro de texto, ingresa la URL del servicio de backend. Ten en cuenta que esta solicitud se enruta desde la instancia de Cloud Run de frontend al servicio de Cloud Run de backend, en lugar de enrutarse desde tu navegador.

Verás "hello world".

4. Configura el servicio de backend solo para la entrada interna

Ejecuta el siguiente comando de gcloud para permitir solo el tráfico desde tu red de VPC para acceder a tu servicio de backend.

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

Para confirmar que tu servicio de backend solo puede recibir tráfico de tu VPC, intenta llamar de nuevo a tu servicio de backend desde tu servicio de frontend.

Esta vez, verás el mensaje "Request failed with status code 404".

Recibiste este error porque la solicitud saliente (es decir, de salida) del servicio de Cloud Run de frontend primero sale a Internet, por lo que Google Cloud no conoce el origen de la solicitud.

En la siguiente sección, configurarás el servicio de frontend para acceder a la VPC, de modo que Google Cloud sepa que la solicitud proviene de la VPC, que se reconoce como una fuente interna.

5. Configura el servicio de frontend para acceder a la VPC

En esta sección, configurarás tu servicio de Cloud Run de frontend para que se comunique con tu servicio de backend a través de una VPC.

Para ello, deberás agregar la salida de VPC directa a tus instancias de Cloud Run de frontend para que tu servicio tenga una IP interna que pueda usar dentro de la VPC. Luego, configurarás la salida de modo que todas las conexiones salientes del servicio de frontend se dirijan a la VPC.

Primero, ejecuta este comando para habilitar la salida de VPC directa:

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

Ahora puedes confirmar que tu servicio de frontend tiene acceso a la VPC:

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

Deberías ver un resultado similar al siguiente:

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

Ahora, vuelve a intentar llamar a tu servicio de backend desde tu servicio de frontend.

Esta vez, verás "hello world".

Nota: Tu servicio de frontend no tendrá acceso a Internet, ya que todo el tráfico de salida se enrutó a la VPC. Por ejemplo, tu servicio de frontend agotará el tiempo de espera si intenta acceder a https://curlmyip.org/.

6. ¡Felicitaciones!

¡Felicitaciones por completar el codelab!

Te recomendamos que revises la documentación de Cloud Run y cómo configurar redes privadas para los servicios de Cloud Run.

Temas abordados

  • Cómo permitir solo el tráfico de una VPC a tu servicio de Cloud Run
  • Cómo configurar la salida en un servicio de Cloud Run para comunicarse con un servicio de Cloud Run solo de entrada interna

7. Limpia

Para evitar cargos involuntarios (por ejemplo, si los servicios de Cloud Run se invocan de forma involuntaria más veces que tu asignación mensual de invocaciones de Cloud Run en el nivel gratuito), puedes borrar Cloud Run o el proyecto que creaste en el paso 2.

Para borrar el servicio de Cloud Run, ve a la consola de Cloud Run en https://console.cloud.google.com/run y borra los servicios $FRONTEND y $BACKEND.

Si decides borrar todo el proyecto, puedes ir a https://console.cloud.google.com/cloud-resource-manager, seleccionar el proyecto que creaste en el paso 2 y elegir Borrar. Si borras el proyecto, deberás cambiar de proyecto en el SDK de Cloud. Para ver la lista de todos los proyectos disponibles, ejecuta gcloud projects list.