Crea un servicio de Cloud Run con un archivo adicional

1. Descripción general

Introducción

En este codelab, aprenderás a implementar un servicio de Cloud Run que usa varios contenedores. Crearás una app de node.js que se usará como el contenedor de entrada de Cloud Run y una app de node.js adicional que se usará como archivo adicional.

Descripción técnica general

Cuando se usan varios contenedores en una instancia de Cloud Run, se usa uno como el principal para la entrada web. Los contenedores adicionales se denominan sidecars.

Existen dos maneras en las que varios contenedores se comunican entre sí:

  1. Los contenedores comparten la interfaz de red localhost, por lo que todos los contenedores pueden escuchar un puerto, p.ej., localhost:port.
  2. También puedes usar volúmenes en la memoria y activarlos en los contenedores para compartir archivos.

Casos de uso

Dado que todos los contenedores dentro de la instancia de Cloud Run comparten la interfaz de red localhost, puedes usar un archivo adicional frente a tu contenedor principal para enviar solicitudes de proxy. Esos proxies pueden proporcionar una capa adicional de abstracción para un flujo más eficiente de tráfico a la aplicación entre el cliente y los servidores mediante la interceptación de solicitudes y su reenvío al endpoint correspondiente. A modo de ejemplo, puede usar la imagen oficial de Nginx de DockerHub (como se muestra aquí).

Dado que varios contenedores se pueden comunicar compartiendo archivos a través de volúmenes compartidos, debes agregar varias aplicaciones de archivo adicional a tu servicio. Por ejemplo, puedes instrumentar tu servicio de Cloud Run para usar agentes personalizados, como OpenTelemetry para exportar registros, métricas y seguimientos (ejemplo de OpenTelemetry). Otro ejemplo es usar una conexión de archivo adicional a una base de datos PostgreSQL de Cloud Spanner (ejemplo de Cloud Spanner Postgress).

Ejemplos de este codelab

En este codelab, primero implementarás un servicio de Cloud Run en el que su contenedor de entrada se comunique con un archivo adicional a través de un puerto localhost. Luego, actualizarás el contenedor de entrada y el archivo adicional para compartir un archivo mediante la activación de volumen.

Qué aprenderás

  • Cómo crear un contenedor que use un archivo adicional
  • Cómo un contenedor de entrada puede comunicarse con un archivo adicional mediante localhost
  • Cómo un contenedor de entrada y un archivo adicional pueden compartir un archivo a través de un volumen activado

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, verás una pantalla intermedia que describe en qué consiste. 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 mejora 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 estás autenticado y que el proyecto está configurado 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. Ejecuta el siguiente comando en Cloud Shell para confirmar que el comando de 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 la app de Ingress

Configura las variables de entorno

En este codelab, crearás algunas variables de entorno para mejorar la legibilidad de los comandos de gcloud que se usan en este codelab.

REGION=<YOUR-REGION>
PROJECT_ID=<YOUR-PROJECT-ID>

SERVICE_NAME=sidecar-codelab
REPO_NAME=sidecar-codelab

Crea un repositorio de ArtifactRegistry para guardar las imágenes de contenedor

Puedes crear un repositorio en Artifact Registry para almacenar las imágenes de contenedor para este codelab.

gcloud artifacts repositories create $REPO_NAME --repository-format=docker \
--location=$REGION --description="sidecar codelab"

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

{
  "name": "sidecar-codelab",
  "version": "1.0.0",
  "private": true,
  "description": "demonstrates how to use sidecars in cloud run",
  "main": "index.js",
  "author": "Google LLC",
  "license": "Apache-2.0",
  "scripts": {
    "start": "node ingress.js"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "express": "^4.18.2"
  }
}

Ahora, crea un archivo llamado ingress.js con el siguiente contenido:

const express = require('express');
const app = express();
const axios = require("axios");

app.get('/', async (req, res) => {

    let response = await axios.get("http://localhost:5000");

    res.send("The sidecar says: " + response.data);
});

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

Crea un Dockerfile para el contenedor de Ingress

FROM node:20.10.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
ENV PORT=8080
CMD [ "npm", "start" ]

Y crea un archivo ``.dockerignore` para el contenedor de Ingress.

# Exclude locally installed dependencies
node_modules/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

Ahora puedes compilar la imagen para tu contenedor de Ingress ejecutando el siguiente comando:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/ingress:latest

4. Crea la app de sidecar

En esta sección, crearás una segunda app de node.js que se usará como archivo adicional en el servicio de Cloud Run.

Navega al directorio de sidecar.

cd ../sidecar

Crea un archivo package.json con el siguiente contenido:

{
  "name": "sidecar-codelab",
  "version": "1.0.0",
  "private": true,
  "description": "demonstrates how to use sidecars in cloud run",
  "main": "index.js",
  "author": "Google LLC",
  "license": "Apache-2.0",
  "scripts": {
    "start": "node sidecar.js"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "express": "^4.18.2"
  }
}

Ahora, crea un archivo llamado sidecar.js con el siguiente contenido:

const express = require('express');
const app = express();

app.get('/', async (req, res) => {
    res.send("Hello ingress container! I'm the sidecar.");
});

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

Crea un Dockerfile para el contenedor del archivo adicional

FROM node:20.10.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
ENV PORT=5000
CMD [ "npm", "start" ]

Y crea un archivo ``.dockerignore` para el contenedor del archivo adicional.

# Exclude locally installed dependencies
node_modules/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

Ahora puedes compilar la imagen para tu contenedor de Ingress ejecutando el siguiente comando:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/sidecar:latest

Implementa el servicio de Cloud Run

Implementarás el servicio de Cloud Run con un archivo yaml.

Navega al directorio superior.

cd ..

Crea un archivo sidecar-codelab.yaml con el siguiente contenido:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
  name: sidecar-codelab
  labels:
    cloud.googleapis.com/location: "<YOUR_REGION>"
spec:
  template:
    spec:
      containers:
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/ingress:latest"
          ports:
            - containerPort: 8080
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/sidecar:latest"
          env:
            - name: PORT
              value: "5000"

Luego, implementa el servicio con el siguiente comando. Debes usar gcloud beta porque las activaciones de volúmenes se encuentran en versión preliminar pública.

gcloud beta run services replace sidecar-codelab.yaml

Una vez implementada, guarda la URL de servicio en una variable de entorno.

SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --platform managed --region $REGION --format 'value(status.url)') 

5. Llama al servicio de Cloud Run

Ahora puedes llamar a tu servicio proporcionando tu token de identidad.

curl -X GET -H "Authorization: Bearer $(gcloud auth print-identity-token)" ${SERVICE_URL}

Tus resultados deberían ser similares al resultado de ejemplo a continuación:

The sidecar says: Hello ingress container! I'm the sidecar.

6. Cómo compartir un archivo mediante la activación de volumen

En esta sección, actualizarás los contenedores para compartir un archivo mediante la activación de volumen. En este ejemplo, el contenedor de Ingress escribirá en un archivo en un volumen compartido. El archivo adicional leerá el archivo y mostrará su contenido de vuelta en el contenedor de Ingress.

Primero, actualizarás el código del contenedor de entrada. Navega al directorio ingress.

cd ../ingress

Luego, reemplaza el contenido del archivo ingress.js por lo siguiente:

const express = require('express');
const app = express();
const fs = require('fs');
const axios = require("axios");

const filename = "test.txt"

let path = "/my-volume-mount";
app.use(path, express.static(path));

try {
    fs.writeFileSync(`${path}/${filename}`, "The ingress container created this file.");
} catch (err) {
    console.error(err);
}

app.get('/', async (req, res) => {

    let response = await axios.get("http://localhost:5000");

    res.send("The sidecar says: " + response.data);
});

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

Ejecuta el siguiente comando para compilar la imagen nueva para tu contenedor de Ingress:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/ingress:latest

Ahora, navega al directorio de sidecar:

cd ../sidecar

Además, actualiza sidecar.js con el siguiente contenido:

const express = require('express');
const app = express();
const fs = require('fs');

const filename = "test.txt"

let path = "/my-volume-mount";
app.use(path, express.static(path));

async function readFile() {
    try {
        return await fs.readFileSync(`${path}/${filename}`, { encoding: 'utf8' });
    } catch (err) {
        console.log(err);
    }
}

app.get('/', async (req, res) => {
    let contents = await readFile();
    res.send(contents);
});

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

Ejecuta el siguiente comando para compilar la imagen nueva para el contenedor de archivo adicional:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/sidecar:latest

Actualiza sidecar-codelab.yaml con lo siguiente para compartir un volumen:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
  name: sidecar-codelab
  labels:
    cloud.googleapis.com/location: "<YOUR_REGION>"
spec:
  template:
    spec:
      containers:
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/ingress:latest"
          ports:
            - containerPort: 8080
          volumeMounts:
            - mountPath: /my-volume-mount
              name: in-memory-1
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/sidecar:latest"
          env:
            - name: PORT
              value: "5000"
          volumeMounts:
            - mountPath: /my-volume-mount
              name: in-memory-1
      volumes:
        - emptyDir:
            medium: Memory
          name: in-memory-1

Implementa el archivo sidecar-codelab.yaml actualizado

gcloud beta run services replace sidecar-codelab.yaml

Ahora puedes llamar a tu servicio proporcionando tu token de identidad.

curl -X GET -H "Authorization: Bearer $(gcloud auth print-identity-token)" ${SERVICE_URL}

Tus resultados deberían ser similares al resultado de ejemplo a continuación:

The sidecar says: the ingress container created this file.

7. ¡Felicitaciones!

¡Felicitaciones por completar el codelab!

Recomendamos revisar la documentación en Cloud Run, específicamente implementar varios contenedores y usar activaciones de volúmenes en memoria.

Temas abordados

  • Cómo crear un contenedor que use un archivo adicional
  • Cómo un contenedor de entrada puede comunicarse con un archivo adicional mediante localhost
  • Cómo un contenedor de entrada y un archivo adicional pueden compartir un volumen activado

8. Limpia

Para evitar cargos accidentales (por ejemplo, si esta Cloud Function se invoca de forma involuntaria más veces que tu asignación de invocación mensual de Cloud Run en el nivel gratuito), puedes borrar el servicio de Cloud Run o borrar el proyecto que creaste en el paso 2.

Para borrar la Cloud Function, ve a la consola de Cloud Function en https://console.cloud.google.com/run/ y borra el servicio sidecar-codelab (o $SERVICE_NAME si usaste otro nombre).

Si decides borrar el proyecto completo, 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 los proyectos en tu SDK de Cloud. Para ver la lista de todos los proyectos disponibles, ejecuta gcloud projects list.