crea un servizio Cloud Run con un sidecar

1. Panoramica

Introduzione

In questo codelab, imparerai come eseguire il deployment di un servizio Cloud Run che utilizza più container. Creerai un'app node.js che verrà utilizzata come container in entrata di Cloud Run e un'app node.js aggiuntiva che verrà utilizzata come file collaterale.

Panoramica tecnica

Quando utilizzi più container all'interno di un'istanza Cloud Run, uno viene utilizzato come container principale per il traffico web in entrata. Uno o più container aggiuntivi sono definiti collaterali.

Esistono due modi per consentire a più container di comunicare tra loro:

  1. I container condividono l'interfaccia di rete localhost, quindi tutti i container possono ascoltare una porta, ad esempio localhost:port.
  2. Puoi anche usare volumi in memoria e montarli sui container per condividere i file.

Casi d'uso

Poiché tutti i container nell'istanza Cloud Run condividono l'interfaccia di rete localhost, puoi utilizzare un file collaterale davanti al container principale per eseguire il proxy delle richieste. Questi proxy possono fornire un ulteriore livello di astrazione per un flusso di traffico più efficiente verso l'applicazione tra client e server intercettando le richieste e inoltrandole all'endpoint appropriato. Ad esempio, puoi utilizzare l'immagine Nginx ufficiale di DockerHub (come mostrato qui).

Dato che più container possono comunicare condividendo file tramite volumi condivisi, puoi aggiungere al tuo servizio varie applicazioni collaterali. Ad esempio, puoi instrumentare il tuo servizio Cloud Run in modo che utilizzi agenti personalizzati come OpenTelemetry per esportare log, metriche e tracce (esempio di OpenTelemetry). Un altro esempio è l'utilizzo di una connessione collaterale a un database PostgreSQL di Cloud Spanner (esempio Postgress di Cloud Spanner).

Esempi in questo codelab

In questo codelab, eseguirai innanzitutto il deployment di un servizio Cloud Run in cui il suo container in entrata comunica con un sidecar tramite una porta localhost. Quindi, aggiornerai il container in entrata e il file collaterale per condividere un file tramite un montaggio del volume.

Cosa imparerai a fare

  • Come creare un container che utilizza un file collaterale
  • Come un container in entrata può comunicare con un file collaterale utilizzando localhost
  • Come un container in entrata e un file collaterale possono entrambi condividere un file tramite un volume montato

2. Configurazione e requisiti

Prerequisiti

Attiva Cloud Shell

  1. Dalla console Cloud, fai clic su Attiva Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se è la prima volta che avvii Cloud Shell, ti verrà mostrata una schermata intermedia che descrive di cosa si tratta. Se ti è stata presentata una schermata intermedia, fai clic su Continua.

d95252b003979716.png

Il provisioning e la connessione a Cloud Shell dovrebbero richiedere solo qualche istante.

7833d5e1c5d18f54.png

Questa macchina virtuale viene caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni di rete e l'autenticazione. Gran parte, se non tutto, del lavoro in questo codelab può essere svolto con un browser.

Una volta stabilita la connessione a Cloud Shell, dovresti vedere che hai eseguito l'autenticazione e che il progetto è impostato sul tuo ID progetto.

  1. Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list

Output comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Esegui questo comando in Cloud Shell per confermare che il comando gcloud è a conoscenza del tuo progetto:
gcloud config list project

Output comando

[core]
project = <PROJECT_ID>

In caso contrario, puoi impostarlo con questo comando:

gcloud config set project <PROJECT_ID>

Output comando

Updated property [core/project].

3. Crea l'app in entrata

Imposta variabili di ambiente

In questo codelab, creerai alcune variabili di ambiente per migliorare la leggibilità dei comandi gcloud utilizzati in questo codelab.

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

SERVICE_NAME=sidecar-codelab
REPO_NAME=sidecar-codelab

Crea un repository ArtifactRegistry per contenere le immagini container

Puoi creare un repository in Artifact Registry per archiviare le immagini container per questo codelab.

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

Quindi, crea un file package.json con i seguenti contenuti:

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

Ora crea un file denominato ingress.js con i seguenti contenuti:

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 per il container in entrata

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

E crea un file ".dockerignore" per il container in entrata.

# Exclude locally installed dependencies
node_modules/

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

# Exclude git history and configuration.
.gitignore

Ora puoi creare l'immagine per il container in entrata eseguendo questo comando:

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

4. Crea l'app collaterale

In questa sezione creerai una seconda app node.js che verrà utilizzata come file collaterale nel servizio Cloud Run.

Vai alla directory del file collaterale.

cd ../sidecar

Crea un file package.json con i seguenti contenuti:

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

Ora crea un file denominato sidecar.js con i seguenti contenuti:

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 per il container collaterale

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

E crea un file ".dockerignore" per il container collaterale.

# Exclude locally installed dependencies
node_modules/

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

# Exclude git history and configuration.
.gitignore

Ora puoi creare l'immagine per il container in entrata eseguendo questo comando:

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

Esegui il deployment del servizio Cloud Run

Eseguirai il deployment del servizio Cloud Run utilizzando un file YAML.

Vai alla directory superiore.

cd ..

Crea un file denominato sidecar-codelab.yaml con i seguenti contenuti:

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"

Poi esegui il deployment del servizio utilizzando il comando seguente. Devi utilizzare gcloud beta perché i montaggi del volume sono in anteprima pubblica.

gcloud beta run services replace sidecar-codelab.yaml

Una volta eseguito il deployment, salva l'URL del servizio in una variabile di ambiente.

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

5. chiama il servizio Cloud Run

Ora puoi chiamare il servizio fornendo il token di identità.

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

I risultati dovrebbero essere simili all'output di esempio seguente:

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

6. Condividere un file tramite un montaggio del volume

In questa sezione aggiornerai i container in modo che condividano un file tramite un montaggio del volume. In questo esempio, il container in entrata scriverà in un file su un volume condiviso. Il file collaterale leggerà il file e restituirà i contenuti al container in entrata.

Innanzitutto, aggiorna il codice del container in entrata. Vai alla directory in entrata.

cd ../ingress

quindi sostituisci i contenuti del file ingress.js con quanto segue:

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

Crea la nuova immagine per il container in entrata eseguendo questo comando:

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

Ora passa alla directory del file collaterale:

cd ../sidecar

Inoltre, aggiorna sidecar.js con i seguenti contenuti:

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

Crea la nuova immagine per il container collaterale eseguendo questo comando:

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

Aggiorna sidecar-codelab.yaml con quanto segue per condividere un volume:

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

Esegui il deployment del file sidecar-codelab.yaml aggiornato

gcloud beta run services replace sidecar-codelab.yaml

Ora puoi chiamare il servizio fornendo il token di identità.

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

I risultati dovrebbero essere simili all'output di esempio seguente:

The sidecar says: the ingress container created this file.

7. Complimenti!

Complimenti per aver completato il codelab.

Consigliamo di consultare la documentazione su Cloud Run, in particolare sul deployment di multicontainer e l'utilizzo di montaggi di volume in memoria.

Argomenti trattati

  • Come creare un container che utilizza un file collaterale
  • Come un container in entrata può comunicare con un file collaterale utilizzando localhost
  • Come un container in entrata e un file collaterale possono entrambi condividere un volume montato

8. Esegui la pulizia

Per evitare addebiti involontari, ad esempio se questa funzione Cloud Functions viene richiamata inavvertitamente più volte rispetto all'allocazione mensile dei callout di Cloud Run nel livello senza costi, puoi eliminare il servizio Cloud Run o eliminare il progetto che hai creato nel passaggio 2.

Per eliminare la funzione Cloud Functions, vai alla console Cloud della funzione Cloud Functions all'indirizzo https://console.cloud.google.com/run/ ed elimina il servizio sidecar-codelab (o $SERVICE_NAME nel caso in cui tu abbia utilizzato un nome diverso).

Se scegli di eliminare l'intero progetto, puoi andare all'indirizzo https://console.cloud.google.com/cloud-resource-manager, selezionare il progetto che hai creato nel passaggio 2 e scegliere Elimina. Se elimini il progetto, dovrai modificarli in Cloud SDK. Puoi visualizzare l'elenco di tutti i progetti disponibili eseguendo gcloud projects list.