Autoscaler les pools de nœuds de calcul Cloud Run en fonction du volume de la file d'attente Pub/Sub à l'aide de CREMA

1. Introduction

Présentation

Ce tutoriel explique comment déployer un pool de nœuds de calcul Cloud Run (consommateur) pour traiter les messages Pub/Sub et comment effectuer le scaling automatique de vos instances de consommateur en fonction de la profondeur de la file d'attente à l'aide de l'autoscaling des métriques externes Cloud Run (CREMA).

Points abordés

Au cours de cet atelier de programmation, vous apprendrez à :

  • Créez un sujet et un abonnement Pub/Sub, puis envoyez des messages à ce sujet.
  • Déployez un pool de nœuds de calcul Cloud Run (consommateur) qui consomme des messages de Pub/Sub.
  • Déployez le projet CREMA sur GitHub en tant que service Cloud Run pour mettre automatiquement à l'échelle votre pool de nœuds de calcul en fonction du nombre de messages dans l'abonnement Pub/Sub.
  • Testez votre configuration d'autoscaling en générant de la charge à l'aide d'un script Python exécuté en local.

2. Configurer les variables d'environnement

Comme de nombreuses variables d'environnement sont utilisées tout au long de cet atelier de programmation, nous vous recommandons d'exécuter

set -u

qui vous avertit si vous essayez d'utiliser une variable d'environnement qui n'a pas encore été définie. Pour annuler ce paramètre, exécutez set +u

Commencez par remplacer la variable suivante par l'ID de votre projet.

export PROJECT_ID=<YOUR_PROJECT_ID>

et définissez-le comme projet pour cet atelier de programmation.

gcloud config set project $PROJECT_ID

Définissez ensuite les variables d'environnement utilisées par cet atelier de programmation.

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

Créez un répertoire pour cet atelier de programmation.

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

Activer les API

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

Enfin, assurez-vous que votre gcloud utilise la dernière version.

gcloud components update

3. Configurer Pub/Sub

Créez le sujet et l'abonnement pull que votre pool de nœuds de calcul traitera. Bash

Créez le sujet.

gcloud pubsub topics create $TOPIC_ID

Créez l'abonnement.

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

4. IAM et comptes de service

Il est recommandé de créer un compte de service pour chaque ressource Cloud Run. Dans cet atelier de programmation, vous allez créer les éléments suivants :

  • Compte de service consommateur : identité du pool de nœuds de calcul traitant les messages Pub/Sub.
  • CREMA SA : identité du service de scaling automatique CREMA.

Créer des comptes de service

Créez le compte de service consommateur du pool de nœuds de calcul :

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

Créez le compte de service CREMA du pool de nœuds de calcul :

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

Accorder des autorisations à Consumer SA

Accordez à l'adresse SA du consommateur du pool de nœuds de calcul l'autorisation d'extraire les messages de l'abonnement.

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

Accorder des autorisations à CREMA SA

CREMA a besoin d'autorisations pour lire les paramètres, mettre à l'échelle le pool de nœuds de calcul et surveiller les métriques Pub/Sub.

  1. Accéder au Gestionnaire de paramètres (lecteur de configuration) :
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/parametermanager.parameterViewer"
  1. Mettre à l'échelle le pool de nœuds de calcul (développeur Cloud Run) :
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/run.developer"
  1. Surveiller Pub/Sub :

Attribuez le rôle Lecteur Monitoring.

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

Ajouter une règle à l'abonnement pour que le compte de service CREMA puisse le consulter

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

Le CREMA SA a également besoin du rôle "Utilisateur du compte de service", qui est nécessaire pour modifier le nombre d'instances :

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. Vérifier les autorisations du compte de service

Avant de poursuivre l'atelier de programmation, vérifiez que le compte de service CREMA dispose des rôles appropriés au niveau du projet.

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"

Vous devriez obtenir le résultat suivant :

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

Vérifiez que l'abonnement Pub/Sub dispose d'une stratégie qui autorise le compte de service CREMA à l'afficher.

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

Résultat attendu

roles/pubsub.viewer

et vérifiez que CREMA SA dispose du rôle Utilisateur de compte de service.

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"

Vous devriez obtenir le résultat suivant :

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

Le compte de service consommateur du pool de nœuds de calcul dispose du rôle d'abonné 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)"

Résultat attendu

ROLE
roles/pubsub.subscriber

6. Créer et déployer le pool de nœuds de calcul du consommateur

Créez un répertoire pour votre code consommateur et accédez-y.

mkdir consumer
cd consumer
  1. Créez un fichier 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. Créer un objet Dockerfile
FROM python:3.12-slim
RUN pip install google-cloud-pubsub
COPY consumer.py .
CMD ["python", "-u", "consumer.py"]
  1. Déployer le pool de nœuds de calcul du consommateur

Cet atelier de programmation recommande de déployer le pool de nœuds de calcul avec 0 instance pour commencer. Vous pourrez ainsi observer CREMA mettre à l'échelle le pool de nœuds de calcul lorsqu'il détectera les messages Pub/Sub dans l'abonnement.

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. Configurer CREMA

  1. Revenez au répertoire racine de votre projet.
cd ..
  1. Créer le fichier de configuration Créez un fichier nommé 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. Remplacer les variables
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. Vérifiez que votre crema-config.yaml est correct.
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. Importer dans le gestionnaire de paramètres

Définir des variables d'environnement supplémentaires pour le Gestionnaire de paramètres

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

Créer la ressource Parameter

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

Créer une version de paramètre 1

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

Vérifier que le paramètre a bien été ajouté

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

Vous devriez obtenir un résultat semblable au suivant :

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

8. Déployer le service CREMA

Dans cette section, vous allez déployer le service de scaling automatique CREMA. Vous utiliserez l'image accessible au public.

  1. Définir les variables d'environnement nécessaires pour CREMA
CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
  1. Vérifier le chemin d'accès au nom de la version
echo $CREMA_CONFIG_PARAM_VERSION

Elle devrait se présenter comme ceci :

projects/<YOUR_PROJECT>/locations/global/parameters/crema-config/versions/1
  1. Définir la variable d'environnement pour l'image CREMA
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0
  1. et déployer le service CREMA

Notez que l'image de base est obligatoire.

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. Tests de charge

  1. Créez un script qui publiera des messages dans le sujet Pub/Sub.
touch load-pubsub.sh
  1. Ajoutez le code suivant au fichier 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. Exécuter un test de charge
chmod +x load-pubsub.sh
./load-pubsub.sh
  1. Surveillez la mise à l'échelle. Attendez trois à quatre minutes. Affichez les journaux CREMA pour voir les instances recommandées en fonction de la nouvelle configuration 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. Surveillez le traitement. Consultez les journaux du consommateur pour voir s'il est en cours de démarrage.
gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION

Vous devriez voir des journaux tels que

Done job-100

10. Dépannage

Tout d'abord, vous devez déterminer si le problème concerne la configuration du service CREMA ou celle du consommateur Pub/Sub.

Définissez l'autoscaler du consommateur Pub/Sub sur 1 au lieu de 0. Si le traitement des messages Pub/Sub commence immédiatement, il s'agit d'un problème lié à la CREMA. Si elle ne traite pas les messages Pub/Sub, cela signifie qu'il y a un problème avec le consommateur Pub/Sub.

11. Félicitations !

Bravo ! Vous avez terminé cet atelier de programmation.

Nous vous recommandons de consulter la documentation Cloud Run.

Points abordés

  • Comment créer un sujet et un abonnement Pub/Sub, et envoyer des messages à ce sujet.
  • Comment déployer un pool de nœuds de calcul Cloud Run (consommateur) qui consomme des messages de Pub/Sub.
  • Découvrez comment déployer le projet CREMA sur GitHub en tant que service Cloud Run pour mettre automatiquement à l'échelle votre pool de nœuds de calcul en fonction du nombre de messages dans l'abonnement Pub/Sub.
  • Découvrez comment tester votre configuration d'autoscaling en générant une charge à l'aide d'un script Python exécuté en local.

12. Effectuer un nettoyage

Pour éviter que les ressources utilisées dans cet atelier de programmation ne soient facturées sur votre compte Google Cloud, vous pouvez supprimer les ressources que vous avez créées ou supprimer l'intégralité du projet.

Supprimer les ressources utilisées dans cet atelier de programmation

  1. Supprimer le service CREMA Cloud Run
gcloud run services delete $CREMA_SERVICE_NAME --region=$REGION --quiet
  1. Supprimer le consommateur du pool de nœuds de calcul Cloud Run
gcloud beta run worker-pools delete $CONSUMER_WORKER_POOL_NAME --region=$REGION --quiet
  1. Supprimez l'abonnement et le sujet Pub/Sub.
gcloud pubsub subscriptions delete $SUBSCRIPTION_ID --quiet
gcloud pubsub topics delete $TOPIC_ID --quiet
  1. Supprimer la configuration du gestionnaire de paramètres

Supprimer la version dans le paramètre

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

Supprimez maintenant le paramètre vide.

gcloud parametermanager parameters delete $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet
  1. Supprimer les comptes de service
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

supprimer l'intégralité du projet.

Pour supprimer l'intégralité du projet, accédez à Gérer les ressources, sélectionnez le projet que vous avez créé à l'étape 2, puis choisissez "Supprimer". Si vous supprimez le projet, vous devrez changer de projet dans le SDK Cloud. Vous pouvez afficher la liste de tous les projets disponibles en exécutant gcloud projects list.