שינוי אוטומטי של גודל מאגרי העובדים ב-Cloud Run על סמך נפח התור ב-Pub/Sub באמצעות CREMA

1. מבוא

סקירה כללית

במדריך הזה מוסבר איך לפרוס מאגר עובדים (צרכן) של Cloud Run כדי לעבד הודעות Pub/Sub, ואיך לשנות את גודל המופעים של הצרכן באופן אוטומטי על סמך עומק התור באמצעות שינוי גודל אוטומטי של מדדים חיצוניים של Cloud Run‏ (CREMA).

מה תלמדו

ב-Codelab הזה תלמדו:

  • יוצרים נושא ומינוי ב-Pub/Sub ושולחים הודעות לנושא הזה.
  • פריסת מאגר עובדים (צרכן) של Cloud Run שצורכים הודעות מ-Pub/Sub.
  • פורסים את פרויקט CREMA ב-GitHub כשירות Cloud Run כדי לשנות את גודל מאגר העובדים באופן אוטומטי בהתאם למספר ההודעות במינוי Pub/Sub.
  • כדי לבדוק את ההגדרה של התאמה אוטומטית לעומס, מריצים סקריפט Python באופן מקומי כדי ליצור עומס.

2. הגדרת משתני סביבה

במהלך ה-codelab הזה נעשה שימוש במשתני סביבה רבים, ולכן מומלץ להריץ

set -u

הפקודה תציג אזהרה אם תנסו להשתמש במשתנה סביבה שלא הוגדר עדיין. כדי לבטל את ההגדרה הזו, מריצים את הפקודה set +u

קודם כל, משנים את המשתנה הבא למזהה הפרויקט.

export PROJECT_ID=<YOUR_PROJECT_ID>

ואז מגדירים אותו כפרויקט של ה-codelab הזה.

gcloud config set project $PROJECT_ID

בשלב הבא, מגדירים את משתני הסביבה שמשמשים במעבדת ה-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

יוצרים ספרייה ל-codelab הזה

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

הפעלת ממשקי API

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

לבסוף, מוודאים שמשתמשים בגרסה העדכנית ביותר של gcloud.

gcloud components update

3. הגדרת Pub/Sub

יוצרים את הנושא ואת מינוי המשיכה שהמאגר של העובדים יעבד. Bash

יוצרים את הנושא.

gcloud pubsub topics create $TOPIC_ID

יוצרים את המינוי.

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

4. IAM וחשבונות שירות

מומלץ ליצור חשבון שירות לכל משאב של Cloud Run. ב-codelab הזה תיצרו את הפריטים הבאים:

  • חשבון שירות (SA) של צרכן: הזהות של מאגר העובדים שמבצע עיבוד של הודעות Pub/Sub.
  • ‫CREMA SA: זהות של שירות CREMA לשינוי גודל אוטומטי.

יצירת חשבונות שירות

יוצרים את חשבון ה-SA של הצרכן של מאגר העובדים:

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

יוצרים את חשבון השירות של מאגר העובדים CREMA:

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

איך מעניקים הרשאות ל-Consumer SA

נותנים הרשאות לחשבון השירות של הצרכן במאגר העובדים כדי לשלוף הודעות מהמינוי.

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

מתן הרשאות ל-CREMA SA

ל-CREMA נדרשות הרשאות לקריאת פרמטרים, לשינוי הגודל של מאגר העובדים ולמעקב אחרי מדדי Pub/Sub.

  1. גישה אל 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. שינוי הגודל של מאגר העובדים (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. מעקב אחרי Pub/Sub:

נותנים את התפקיד 'צפייה בניטור'.

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

הוספת מדיניות למינוי לשירות CREMA SA כדי להציג אותה

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

לחשבון השירות של CREMA צריך להיות גם התפקיד Service Account User (משתמש בחשבון שירות), שנדרש כדי לשנות את מספר המכונות:

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. אימות הרשאות SA

לפני שממשיכים עם ה-codelab, צריך לוודא שלחשבון שירות CREMA יש את התפקידים הנכונים ברמת הפרויקט.

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"

התוצאה אמורה להיות:

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

מוודאים שלמינוי Pub/Sub יש מדיניות שמאפשרת ל-SA של שירות CREMA לצפות בו.

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

התוצאה צריכה להיות

roles/pubsub.viewer

ובודקים שלחשבון השירות של CREMA יש את התפקיד Service Account User

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"

התוצאה צריכה להיות

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

ובחשבון ה-SA של צרכן מאגר העובדים יש את התפקיד Pub/Sub subscriber

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

התוצאה צריכה להיות

ROLE
roles/pubsub.subscriber

6. פיתוח ופריסה של מאגר עובדים לצרכנים

יוצרים ספרייה לקוד הצרכן ומזינים אותה.

mkdir consumer
cd consumer
  1. יצירת קובץ 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. צור Dockerfile
FROM python:3.12-slim
RUN pip install google-cloud-pubsub
COPY consumer.py .
CMD ["python", "-u", "consumer.py"]
  1. פריסת מאגר עובדים לצרכנים

ב-codelab הזה מומלץ לפרוס את מאגר העובדים עם 0 מופעים בהתחלה, כדי שתוכלו לראות את CREMA משנה את גודל מאגר העובדים כשהוא מזהה את ההודעות ב-Pub/Sub במינוי.

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. הגדרת CREMA

  1. חוזרים לספריית השורש של הפרויקט.
cd ..
  1. יוצרים את קובץ ההגדרות יוצרים קובץ בשם 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. החלפת משתנים
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. אימות הפרטים של crema-config.yaml
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. העלאה אל Parameter Manager

הגדרת משתני סביבה נוספים ל-Parameter Manager

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

יצירת משאב הפרמטר

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

יצירת פרמטר גרסה 1

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

אימות שהפרמטר נוסף בהצלחה

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

אמור להופיע משהו כמו

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

8. פריסת CREMA Service

בקטע הזה תפרסו את שירות CREMA לשינוי גודל אוטומטי. תשתמשו בתמונה שזמינה לכולם.

  1. הגדרת משתני סביבה שנדרשים ל-CREMA
CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
  1. אימות הנתיב של שם הגרסה
echo $CREMA_CONFIG_PARAM_VERSION

הוא אמור להיראות כך

projects/<YOUR_PROJECT>/locations/global/parameters/crema-config/versions/1
  1. הגדרת משתנה הסביבה לתמונת CREMA
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0
  1. ופריסת שירות CREMA

שימו לב שחובה להוסיף את תמונת הבסיס.

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. בדיקות עומס

  1. יצירת סקריפט שיפרסם הודעות בנושא Pub/Sub
touch load-pubsub.sh
  1. מוסיפים את הקוד הבא לקובץ 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. הרצת בדיקת עומס
chmod +x load-pubsub.sh
./load-pubsub.sh
  1. מעקב אחר שינוי הגודל ממתינים 3-4 דקות. אפשר להציג את היומנים של CREMA כדי לראות את ההמלצות שלו לגבי מופעים על סמך ההגדרה החדשה של 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. מעקב אחר העיבוד: אפשר לראות את ההפעלה ביומנים של הצרכן.
gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION

אמורים להופיע יומנים כמו

Done job-100

10. פתרון בעיות

קודם כל, צריך לקבוע אם הבעיה היא בהגדרת שירות CREMA או בהגדרת צרכן PubSub.

מגדירים את PubSub consumer autoscaler ל-1 במקום ל-0. אם העיבוד של הודעות pubsub מתחיל מיד, הבעיה היא ב-CREMA. אם ההודעות ב-Pub/Sub לא מעובדות, יש בעיה בצרכן של Pub/Sub.

‫11. מזל טוב!

כל הכבוד, סיימתם את ה-Codelab!

מומלץ לעיין במסמכי התיעוד של Cloud Run.

מה נכלל

  • איך יוצרים נושא ומינוי ב-Pub/Sub ושולחים הודעות לנושא הזה.
  • איך פורסים מאגר עובדים (צרכן) של Cloud Run שצורך הודעות מ-Pub/Sub.
  • איך פורסים את פרויקט CREMA ב-GitHub כשירות Cloud Run כדי לשנות את גודל מאגר העובדים באופן אוטומטי בהתאם למספר ההודעות במינוי Pub/Sub.
  • איך בודקים את הגדרת שינוי הגודל האוטומטי על ידי יצירת עומס באמצעות הפעלת סקריפט Python באופן מקומי.

12. הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת ה-Codelab הזה, אפשר למחוק את המשאבים שיצרתם או למחוק את הפרויקט כולו.

מחיקת משאבים שנעשה בהם שימוש ב-codelab הזה

  1. מחיקת שירות CREMA של Cloud Run
gcloud run services delete $CREMA_SERVICE_NAME --region=$REGION --quiet
  1. מחיקת הצרכן של מאגר העובדים ב-Cloud Run
gcloud beta run worker-pools delete $CONSUMER_WORKER_POOL_NAME --region=$REGION --quiet
  1. מחיקת המינוי והנושא ב-Pub/Sub
gcloud pubsub subscriptions delete $SUBSCRIPTION_ID --quiet
gcloud pubsub topics delete $TOPIC_ID --quiet
  1. מחיקת ההגדרה של Parameter Manager

מחיקת הגרסה בתוך הפרמטר

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

עכשיו מוחקים את הפרמטר הריק

gcloud parametermanager parameters delete $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet
  1. מחיקה של חשבונות השירות
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

או למחוק את כל הפרויקט

כדי למחוק את הפרויקט כולו, עוברים אל Manage Resources (ניהול משאבים), בוחרים את הפרויקט שיצרתם בשלב 2 ולוחצים על Delete (מחיקה). אם תמחקו את הפרויקט, תצטרכו לשנות את הפרויקט ב-Cloud SDK. כדי לראות את רשימת כל הפרויקטים הזמינים, מריצים את הפקודה gcloud projects list.