Automatyczne skalowanie pul instancji roboczych Cloud Run na podstawie wielkości kolejki Pub/Sub za pomocą CREMA

1. Wprowadzenie

Przegląd

Z tego samouczka dowiesz się, jak wdrożyć pulę procesów roboczych Cloud Run (konsumenta) do przetwarzania wiadomości Pub/Sub i automatycznie skalować instancje konsumenta na podstawie głębokości kolejki za pomocą autoskalowania na podstawie zewnętrznych wskaźników Cloud Run (CREMA).

Czego się nauczysz

W tym ćwiczeniu:

  • utworzyć temat i subskrypcję Pub/Sub oraz wysyłać do niego wiadomości,
  • Wdróż pulę instancji roboczych Cloud Run (odbiorcę), która będzie odbierać wiadomości z Pub/Sub.
  • Wdróż projekt CREMA w GitHubie jako usługę Cloud Run, aby automatycznie skalować pulę procesów roboczych na podstawie liczby wiadomości w subskrypcji Pub/Sub.
  • Przetestuj konfigurację autoskalowania, generując obciążenie przez uruchomienie lokalnie skryptu w języku Python.

2. Konfigurowanie zmiennych środowiskowych

W tym samouczku z programowania używamy wielu zmiennych środowiskowych, dlatego zalecamy uruchomienie

set -u

która wyświetli ostrzeżenie, jeśli spróbujesz użyć zmiennej środowiskowej, która nie została jeszcze ustawiona. Aby cofnąć to ustawienie, uruchom polecenie set +u

Najpierw zmień poniższą zmienną na identyfikator projektu.

export PROJECT_ID=<YOUR_PROJECT_ID>

a następnie ustawić go jako projekt na potrzeby tego modułu.

gcloud config set project $PROJECT_ID

Następnie ustaw zmienne środowiskowe używane w tym ćwiczeniu z programowania.

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

Utwórz katalog dla tych ćwiczeń z programowania.

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

Włącz interfejsy API

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

Na koniec upewnij się, że gcloud używa najnowszej wersji.

gcloud components update

3. Konfiguracja Pub/Sub

Utwórz temat i subskrypcję pull, które będą przetwarzane przez pulę instancji roboczych. Bash

Utwórz temat.

gcloud pubsub topics create $TOPIC_ID

Utwórz subskrypcję.

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

4. Uprawnienia i konta usługi

Zalecamy utworzenie konta usługi dla każdego zasobu Cloud Run. W tym ćwiczeniu utworzysz:

  • Konto usługi konsumenta: tożsamość puli instancji roboczych przetwarzających wiadomości Pub/Sub.
  • CREMA SA: tożsamość usługi automatycznego skalowania CREMA.

Tworzenie kont usługi

Utwórz SA konsumenta puli instancji roboczych:

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

Utwórz usługę CREMA SA puli instancji roboczych:

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

Przyznawanie uprawnień usłudze Consumer SA

Przyznaj uprawnienia do pobierania wiadomości z subskrypcji konsumenckiemu SA puli pracowników.

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

Przyznawanie uprawnień firmie CREMA SA

CREMA potrzebuje uprawnień do odczytywania parametrów, skalowania puli instancji roboczych i monitorowania danych Pub/Sub.

  1. Dostęp do menedżera parametrów (czytanie konfiguracji):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/parametermanager.parameterViewer"
  1. Skalowanie puli instancji roboczych (programista 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. Monitorowanie Pub/Sub:

Przyznaj rolę wyświetlającego monitorowanie.

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

Dodaj do subskrypcji zasady, aby usługa CREMA SA mogła je wyświetlać.

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

Konto usługi CREMA SA musi też mieć rolę Użytkownik konta usługi, która jest wymagana do zmiany liczby instancji:

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. Weryfikowanie uprawnień konta usługi

Zanim przejdziesz dalej, sprawdź, czy konto usługi CREMA ma odpowiednie role na poziomie projektu.

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"

Powinno to spowodować:

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

Sprawdź, czy subskrypcja Pub/Sub ma zasadę, która umożliwia SA usługi CREMA wyświetlanie jej.

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

Powinno to spowodować

roles/pubsub.viewer

i sprawdź, czy konto usługi CREMA ma rolę użytkownika konta usługi.

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"

Powinno to dać następujący wynik:

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

Konto usługi konsumenta puli procesów ma rolę subskrybującego 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)"

Powinno to spowodować

ROLE
roles/pubsub.subscriber

6. Tworzenie i wdrażanie puli instancji roboczych konsumenta

Utwórz katalog na kod konsumencki i wpisz go.

mkdir consumer
cd consumer
  1. Tworzenie pliku 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. Utwórz Dockerfile
FROM python:3.12-slim
RUN pip install google-cloud-pubsub
COPY consumer.py .
CMD ["python", "-u", "consumer.py"]
  1. Wdrażanie puli instancji roboczych konsumentów

W tym module zalecamy wdrożenie puli instancji roboczych z 0 instancji na początek, aby można było obserwować, jak CREMA skaluje pulę instancji roboczych po wykryciu wiadomości Pub/Sub w subskrypcji.

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

  1. Wróć do katalogu głównego projektu.
cd ..
  1. Tworzenie pliku konfiguracyjnego Utwórz plik o nazwie 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. Podstaw zmienne
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. Sprawdź, czy numer crema-config.yaml jest prawidłowy
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. Przesyłanie do Menedżera parametrów

Ustawianie dodatkowych zmiennych środowiskowych dla menedżera parametrów

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

Utwórz zasób parametru

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

Utwórz wersję parametru 1

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

Sprawdź, czy parametr został dodany

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

Powinno pojawić się coś takiego:

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

8. Wdrażanie usługi CREMA

W tej sekcji wdrożysz usługę automatycznego skalowania CREMA. Użyjesz obrazu, który jest dostępny publicznie.

  1. Ustawianie zmiennych środowiskowych wymaganych przez CREMA
CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
  1. Sprawdź ścieżkę nazwy wersji
echo $CREMA_CONFIG_PARAM_VERSION

Powinien wyglądać tak:

projects/<YOUR_PROJECT>/locations/global/parameters/crema-config/versions/1
  1. Ustaw zmienną środowiskową dla obrazu CREMA
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0
  1. i wdrożyć usługę CREMA.

Pamiętaj, że obraz podstawowy jest wymagany.

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. Testowanie obciążenia

  1. Utwórz skrypt, który będzie publikować wiadomości w temacie Pub/Sub.
touch load-pubsub.sh
  1. Dodaj do pliku load-pubsub.sh ten kod:
#!/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. Przeprowadzanie testu obciążenia
chmod +x load-pubsub.sh
./load-pubsub.sh
  1. Poczekaj 3–4 minuty, aż monitor się skaluje. Wyświetl dzienniki CREMA, aby zobaczyć, jak rekomenduje instancje na podstawie nowej konfiguracji 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. Monitorowanie przetwarzania: wyświetl logi Consumer, aby zobaczyć, jak się uruchamia.
gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION

Powinny pojawić się dzienniki podobne do tych:

Done job-100

10. Rozwiązywanie problemów

Najpierw sprawdź, czy problem dotyczy konfiguracji usługi CREMA czy konfiguracji odbiorcy PubSub.

Ustaw autoskalowanie konsumenta PubSub na 1 zamiast 0. Jeśli od razu zacznie przetwarzać wiadomości pubsub, problem dotyczy CREMA. Jeśli nie przetwarza wiadomości pubsub, oznacza to, że występuje problem z konsumentem pubsub.

11. Gratulacje!

Gratulujemy ukończenia ćwiczenia!

Zalecamy zapoznanie się z dokumentacją Cloud Run.

Omówione zagadnienia

  • Jak utworzyć temat i subskrypcję Pub/Sub oraz wysyłać do niego wiadomości.
  • Jak wdrożyć pulę instancji roboczych Cloud Run (odbiorcę), która przetwarza wiadomości z Pub/Sub.
  • Jak wdrożyć projekt CREMA w GitHubie jako usługę Cloud Run, aby automatycznie skalować pulę procesów roboczych na podstawie liczby wiadomości w subskrypcji Pub/Sub.
  • Jak przetestować konfigurację autoskalowania, generując obciążenie przez lokalne uruchomienie skryptu Pythona.

12. Czyszczenie danych

Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby użyte w tym samouczku, możesz usunąć zasoby utworzone w tym ćwiczeniu lub cały projekt.

Usuwanie zasobów użytych w tym ćwiczeniu z programowania

  1. Usuwanie usługi Cloud Run CREMA
gcloud run services delete $CREMA_SERVICE_NAME --region=$REGION --quiet
  1. Usuwanie konsumenta puli instancji roboczych Cloud Run
gcloud beta run worker-pools delete $CONSUMER_WORKER_POOL_NAME --region=$REGION --quiet
  1. Usuwanie subskrypcji i tematu Pub/Sub
gcloud pubsub subscriptions delete $SUBSCRIPTION_ID --quiet
gcloud pubsub topics delete $TOPIC_ID --quiet
  1. Usuwanie konfiguracji Menedżera parametrów

Usuwanie wersji w parametrze

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

Teraz usuń pusty parametr.

gcloud parametermanager parameters delete $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet
  1. Usuwanie kont usługi
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

lub usunąć cały projekt.

Aby usunąć cały projekt, otwórz stronę Zarządzanie zasobami, wybierz projekt utworzony w kroku 2 i kliknij Usuń. Jeśli usuniesz projekt, musisz zmienić projekty w Cloud SDK. Listę wszystkich dostępnych projektów możesz wyświetlić, uruchamiając polecenie gcloud projects list.