Scalare automaticamente i pool di worker Cloud Run in base al volume della coda Pub/Sub utilizzando CREMA

1. Introduzione

Panoramica

Questo tutorial mostra come eseguire il deployment di un pool di worker (consumer) Cloud Run per elaborare i messaggi Pub/Sub e scalare automaticamente le istanze consumer in base alla profondità della coda utilizzando la scalabilità automatica delle metriche esterne di Cloud Run (CREMA).

Obiettivi didattici

In questo codelab imparerai a:

  • Crea un argomento e una sottoscrizione Pub/Sub e invia i messaggi a quell'argomento.
  • Esegui il deployment di un pool di worker Cloud Run (consumer) che utilizza i messaggi da Pub/Sub.
  • Esegui il deployment del progetto CREMA su GitHub come servizio Cloud Run per scalare automaticamente il pool di worker in base al numero di messaggi nella sottoscrizione Pub/Sub.
  • Testa la configurazione della scalabilità automatica generando carico eseguendo uno script Python localmente.

2. Configura le variabili di ambiente

Poiché in questo codelab vengono utilizzate molte variabili di ambiente, ti consigliamo di eseguire

set -u

che ti avvisa se provi a utilizzare una variabile di ambiente che non è ancora stata impostata. Per annullare questa impostazione, esegui set +u

Innanzitutto, modifica la seguente variabile con il tuo ID progetto.

export PROJECT_ID=<YOUR_PROJECT_ID>

e poi impostalo come progetto per questo codelab.

gcloud config set project $PROJECT_ID

Successivamente, imposta le variabili di ambiente utilizzate in questo codelab.

export REGION=us-central1
export TOPIC_ID=crema-pubsub-topic
export SUBSCRIPTION_ID=crema-pubsub-sub
export CREMA_SA_NAME=crema-service-account
export CONSUMER_SA_NAME=consumer-service-account
export CONSUMER_WORKER_POOL_NAME=worker-pool-consumer
export CREMA_SERVICE_NAME=my-crema-service

Crea una directory per questo codelab

mkdir crema-pubsub-codelab
cd crema-pubsub-codelab

Abilita API

gcloud services enable \
        artifactregistry.googleapis.com \
        cloudbuild.googleapis.com \
        run.googleapis.com \
        parametermanager.googleapis.com

Infine, assicurati che gcloud utilizzi l'ultima versione.

gcloud components update

3. Configurazione di Pub/Sub

Crea l'argomento e la sottoscrizione pull che verrà elaborata dal pool di worker. Bash

Crea l'argomento.

gcloud pubsub topics create $TOPIC_ID

Crea la sottoscrizione.

gcloud pubsub subscriptions create $SUBSCRIPTION_ID --topic=$TOPIC_ID

4. Account di servizio e IAM

Ti consigliamo di creare un service account per ogni risorsa Cloud Run. In questo codelab creerai:

  • SA consumer: l'identità del pool di worker che elabora i messaggi Pub/Sub.
  • CREMA SA: identità per il servizio di scalabilità automatica CREMA.

Create Service Accounts

Crea l'SA consumer del pool di worker:

gcloud iam service-accounts create $CONSUMER_SA_NAME \
  --display-name="PubSub Consumer Service Account"

Crea il servizio CREMA SA del pool di worker:

gcloud iam service-accounts create $CREMA_SA_NAME \
  --display-name="CREMA Autoscaler Service Account"

Concedere autorizzazioni all'account di servizio consumer

Concedi le autorizzazioni all'account di servizio consumer del pool di worker per estrarre i messaggi dalla sottoscrizione.

gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
  --member="serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/pubsub.subscriber"

Concedere le autorizzazioni a CREMA SA

CREMA ha bisogno delle autorizzazioni per leggere i parametri, scalare il pool di worker e monitorare le metriche Pub/Sub.

  1. Accedi a Parameter Manager (Config Reader):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/parametermanager.parameterViewer"
  1. Scalare il pool di worker (Cloud Run Developer):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/run.developer"
  1. Monitora Pub/Sub:

Concedi il ruolo Visualizzatore Monitoring.

gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/monitoring.viewer"

Aggiungi una policy all'abbonamento per consentire a CREMA service SA di visualizzarla

gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/pubsub.viewer"

Il CREMA SA ha bisogno anche di Utente service account, necessario per modificare i conteggi delle istanze:

gcloud iam service-accounts add-iam-policy-binding \
    $CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
    --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountUser"

5. Verificare le autorizzazioni dell'amministratore del servizio

Prima di procedere con il codelab, verifica che l'account di servizio CREMA disponga dei ruoli corretti a livello di progetto.

gcloud projects get-iam-policy $PROJECT_ID \
  --flatten="bindings[].members" \
  --format="table(bindings.role)" \
  --filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"

Dovrebbe restituire il seguente risultato:

roles/monitoring.viewer
roles/parametermanager.parameterViewer
roles/run.developer

Verifica che la sottoscrizione Pub/Sub abbia un criterio che consenta al service agent del servizio CREMA di visualizzarla.

gcloud pubsub subscriptions get-iam-policy $SUBSCRIPTION_ID \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --format="table(bindings.role)"

Dovrebbe comportare

roles/pubsub.viewer

e verifica che CREMA SA disponga del ruolo Utente account di servizio.

gcloud iam service-accounts get-iam-policy \
  $CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"

Dovrebbe restituire il seguente risultato

bindings:
  members: serviceAccount:crema-service-account@<PROJECT_ID>.iam.gserviceaccount.com
  role: roles/iam.serviceAccountUser

e l'account di servizio consumer del pool di worker ha il ruolo Sottoscrittore Pub/Sub.

gcloud pubsub subscriptions get-iam-policy $SUBSCRIPTION_ID \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --format="table(bindings.role)"

Dovrebbe comportare

ROLE
roles/pubsub.subscriber

6. Crea e implementa il pool di worker consumer

Crea una directory per il codice di consumo e inseriscilo.

mkdir consumer
cd consumer
  1. Creare un file consumer.py
import os
import time
from google.cloud import pubsub_v1
from concurrent.futures import TimeoutError

# Configuration
PROJECT_ID = os.environ.get('PROJECT_ID')
SUBSCRIPTION_ID = os.environ.get('SUBSCRIPTION_ID')

subscription_path = f"projects/{PROJECT_ID}/subscriptions/{SUBSCRIPTION_ID}"

print(f"Worker Pool instance starting. Watching {subscription_path}...")

subscriber = pubsub_v1.SubscriberClient()

def callback(message):
    try:
        data = message.data.decode("utf-8")
        print(f"Processing job: {data}")
        time.sleep(5)  # Simulate work
        print(f"Done {data}")
        message.ack()
    except Exception as e:
        print(f"Error processing message: {e}")
        message.nack()

streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
print(f"Listening for messages on {subscription_path}...")

# Wrap subscriber in a 'with' block to automatically call close() when done.
with subscriber:
    try:
        # When `timeout` is not set, result() will block indefinitely,
        # unless an exception is encountered first.
        streaming_pull_future.result()
    except TimeoutError:
        streaming_pull_future.cancel()  # Trigger the shutdown.
        streaming_pull_future.result()  # Block until the shutdown is complete.
    except Exception as e:
        print(f"Streaming pull failed: {e}")
  1. Crea un Dockerfile
FROM python:3.12-slim
RUN pip install google-cloud-pubsub
COPY consumer.py .
CMD ["python", "-u", "consumer.py"]
  1. Esegui il deployment del pool di worker consumer

Questo codelab consiglia di eseguire il deployment del pool di worker con 0 istanze per iniziare, in modo da poter osservare CREMA scalare il pool di worker quando rileva i messaggi Pub/Sub nella sottoscrizione.

gcloud beta run worker-pools deploy $CONSUMER_WORKER_POOL_NAME \
  --source . \
  --region $REGION \
  --service-account="$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --instances=0 \
  --set-env-vars PROJECT_ID=$PROJECT_ID,SUBSCRIPTION_ID=$SUBSCRIPTION_ID

7. Configura CREMA

  1. Torna alla directory root del progetto.
cd ..
  1. Crea il file di configurazione. Crea un file denominato crema-config.yaml.
apiVersion: crema/v1
kind: CremaConfig
spec:
  pollingInterval: 30
  triggerAuthentications:
    - metadata:
        name: adc-trigger-auth
      spec:
        podIdentity:
          provider: gcp
  scaledObjects:
    - spec:
        scaleTargetRef:
          name: projects/PROJECT_ID_PLACEHOLDER/locations/REGION_PLACEHOLDER/workerpools/CONSUMER_WORKER_POOL_NAME_PLACEHOLDER
        triggers:
          - type: gcp-pubsub
            metadata:
              subscriptionName: "SUBSCRIPTION_ID_PLACEHOLDER"
              # Target number of undelivered messages per worker instance
              value: "10"
              mode: "SubscriptionSize"
            authenticationRef:
              name: adc-trigger-auth
  1. Sostituisci variabili
sed -i "s/PROJECT_ID_PLACEHOLDER/$PROJECT_ID/g" crema-config.yaml
sed -i "s/REGION_PLACEHOLDER/$REGION/g" crema-config.yaml
sed -i "s/CONSUMER_WORKER_POOL_NAME_PLACEHOLDER/$CONSUMER_WORKER_POOL_NAME/g" crema-config.yaml
sed -i "s/SUBSCRIPTION_ID_PLACEHOLDER/$SUBSCRIPTION_ID/g" crema-config.yaml
  1. Verifica che il tuo crema-config.yaml sia corretto
if grep -q "_PLACEHOLDER" crema-config.yaml; then
  echo "❌ ERROR: Validations failed. '_PLACEHOLDER' was found in crema-config.yaml."
  echo "Please check your environment variables and run the 'sed' commands again."
else
  echo "✅ Config check passed: No placeholders found."
fi
  1. Carica in Parameter Manager

Imposta variabili di ambiente aggiuntive per Parameter Manager

export PARAMETER_ID=crema-config
export PARAMETER_REGION=global
export PARAMETER_VERSION=1

Crea la risorsa Parameter

gcloud parametermanager parameters create $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --parameter-format=YAML

Crea versione parametro 1

gcloud parametermanager parameters versions create $PARAMETER_VERSION \
  --parameter=crema-config \
  --project=$PROJECT_ID \
  --location=$PARAMETER_REGION \
  --payload-data-from-file=crema-config.yaml

Verifica che il parametro sia stato aggiunto correttamente

gcloud parametermanager parameters versions list \
  --parameter=$PARAMETER_ID \
  --location=$PARAMETER_REGION

Dovresti vedere qualcosa di simile a

projects/<YOUR_PROJECT_ID>/locations/global/parameters/crema-config/versions/1

8. Esegui il deployment del servizio CREMA

In questa sezione, eseguirai il deployment del servizio di scalabilità automatica CREMA. Utilizzerai l'immagine disponibile pubblicamente.

  1. Imposta le variabili di ambiente necessarie per CREMA
CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
  1. Verifica il percorso del nome della versione
echo $CREMA_CONFIG_PARAM_VERSION

Dovrebbe avere il seguente aspetto:

projects/<YOUR_PROJECT>/locations/global/parameters/crema-config/versions/1
  1. Imposta la variabile di ambiente per l'immagine CREMA
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0
  1. ed esegui il deployment del servizio CREMA

Tieni presente che l'immagine di base è obbligatoria.

gcloud beta run deploy $CREMA_SERVICE_NAME \
  --image=$IMAGE \
  --region=${REGION} \
  --service-account="${CREMA_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --labels=created-by=crema \
  --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
  --set-env-vars="CREMA_CONFIG=${CREMA_CONFIG_PARAM_VERSION},OUTPUT_SCALER_METRICS=True,ENABLE_CLOUD_LOGGING=True"

9. Test di carico

  1. Crea uno script che pubblichi i messaggi nell'argomento Pub/Sub
touch load-pubsub.sh
  1. Aggiungi il seguente codice al file load-pubsub.sh
#!/bin/bash
TOPIC_ID=${TOPIC_ID} 
PROJECT_ID=${PROJECT_ID}
NUM_MESSAGES=100

echo "Publishing $NUM_MESSAGES messages to topic $TOPIC_ID..."

for i in $(seq 1 $NUM_MESSAGES); do
  gcloud pubsub topics publish $TOPIC_ID --message="job-$i" --project=$PROJECT_ID &
  if (( $i % 10 == 0 )); then
    wait
    echo "Published $i messages..."
  fi
done
wait
echo "Done. All messages published."
  1. Esegui test di carico
chmod +x load-pubsub.sh
./load-pubsub.sh
  1. Monitora il ridimensionamento. Attendi 3-4 minuti. Visualizza i log CREMA per vedere le istanze consigliate in base alla nuova configurazione authenticationRef.
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=$CREMA_SERVICE_NAME AND textPayload:SCALER" \
  --limit=20 \
  --format="value(textPayload)" \
  --freshness=5m
  1. Monitora l'elaborazione. Visualizza i log dei consumer per vedere l'avvio.
gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION

Dovresti visualizzare log come

Done job-100

10. Risoluzione dei problemi

Per prima cosa, devi stabilire se il problema riguarda la configurazione del servizio CREMA o quella del consumer Pub/Sub.

Imposta il gestore della scalabilità automatica del consumer Pub/Sub su 1 anziché 0. Se inizia immediatamente a elaborare i messaggi pub/sub, il problema riguarda CREMA. Se non elabora i messaggi pub/sub, si è verificato un problema con il consumer pub/sub.

11. Complimenti!

Congratulazioni per aver completato il codelab.

Ti consigliamo di consultare la documentazione di Cloud Run.

Argomenti trattati

  • Come creare un argomento e una sottoscrizione Pub/Sub e inviare messaggi a quell'argomento.
  • Come eseguire il deployment di un pool di worker (consumer) Cloud Run che utilizza i messaggi da Pub/Sub.
  • Come eseguire il deployment del progetto CREMA su GitHub come servizio Cloud Run per scalare automaticamente il pool di worker in base al numero di messaggi nella sottoscrizione Pub/Sub.
  • Come testare la configurazione della scalabilità automatica generando carico eseguendo uno script Python in locale.

12. Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, puoi eliminare le risorse che hai creato in questo codelab oppure l'intero progetto.

Elimina le risorse utilizzate in questo codelab

  1. Elimina il servizio Cloud Run CREMA
gcloud run services delete $CREMA_SERVICE_NAME --region=$REGION --quiet
  1. Elimina il consumer del pool di worker Cloud Run
gcloud beta run worker-pools delete $CONSUMER_WORKER_POOL_NAME --region=$REGION --quiet
  1. Elimina l'argomento e la sottoscrizione Pub/Sub
gcloud pubsub subscriptions delete $SUBSCRIPTION_ID --quiet
gcloud pubsub topics delete $TOPIC_ID --quiet
  1. Elimina la configurazione di Parameter Manager

Elimina la versione all'interno del parametro

gcloud parametermanager parameters versions delete $PARAMETER_VERSION \
  --parameter=$PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet

Ora elimina il parametro vuoto.

gcloud parametermanager parameters delete $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet
  1. Elimina i service account
gcloud iam service-accounts delete "$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --quiet
gcloud iam service-accounts delete "$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --quiet

Oppure elimina l'intero progetto.

Per eliminare l'intero progetto, vai a Gestisci risorse, seleziona il progetto che hai creato nel passaggio 2 e scegli Elimina. Se elimini il progetto, dovrai cambiare progetto in Cloud SDK. Puoi visualizzare l'elenco di tutti i progetti disponibili eseguendo gcloud projects list.