Autoscale worker pools with external metrics

This page describes how to autoscale Cloud Run worker pools using external event-driven metrics. Cloud Run External Metrics Autoscaling (CREMA) enables this functionality by leveraging Kubernetes-based Event Driven Autoscaling (KEDA) to scale workloads based on external event sources.

For supported scalers and compatibility with Cloud Run, see Cloud Run External Metrics Autoscaling (CREMA) in the Google Cloud GitHub documentation.

About the autoscaler service

To autoscale worker pools, deploy the CREMA autoscaler service to Cloud Run. This service performs the following actions:

  1. Polls external event sources, such as Apache Kafka topics or GitHub Runner Scaler.

  2. Calculates the required instance count based on your YAML configuration.

  3. Updates the worker pool's instance count automatically.

Before you begin

  1. Make sure you have set up a new project for Cloud Run, as described in the setup page.

  2. Enable the Artifact Registry, Cloud Build, Cloud Run Admin API, Secret Manager, and Parameter Manager APIs:

    gcloud services enable artifactregistry.googleapis.com \
        cloudbuild.googleapis.com \
        run.googleapis.com \
        secretmanager.googleapis.com \
        parametermanager.googleapis.com
    
  3. Configure an event-driven or request-based workload, such as GitHub Runners or Apache Kafka. To verify that your workload source is supported, see the CREMA compatibility list in the Google Cloud GitHub documentation.

  4. Review the pricing calculator to estimate costs. You incur charges for your Cloud Run scaling service based on how often you trigger scaling.

Required roles

To get the permissions that you need to autoscale your worker pool, ask your administrator to grant you the following IAM roles on your project:

For more information about granting roles, see Manage access to projects, folders, and organizations.

You might also be able to get the required permissions through custom roles or other predefined roles.

Create a custom service account

Create a custom service account with the minimum permissions required to use provisioned resources required for your workload. To set up the service account, do the following:

gcloud iam service-accounts create CREMA_SERVICE_ACCOUNT \
  --display-name="CREMA Service Account"

Replace CREMA_SERVICE_ACCOUNT with a name for your custom service account, for example crema-service-account. This command creates a service account that follows the format, crema-service-account@example-project.iam.gserviceaccount.com.

Create the CREMA configuration file

To define your scaling logic, create a YAML configuration file in your root directory. This file instructs the CREMA service on which external sources to monitor, how to authenticate with the resources, and which worker pools to scale.

YAML example

The following example shows the configuration file to scale a Cloud Run worker pool (example-workerpool) using the GitHub Runner metrics. It uses a Secret Manager secret named github_runner_token to authenticate with GitHub for reading the metrics.

  apiVersion: crema/v1
  kind: CremaConfig
  metadata:
    name: gh-demo
  spec:
    triggerAuthentications:
      - metadata:
          name: github-trigger-auth
        spec:
          gcpSecretManager:
            secrets:
              - parameter: personalAccessToken
                id: github_runner_token
                version: latest
    scaledObjects:
      - spec:
          scaleTargetRef:
            name: projects/example-project/locations/us-central1/workerpools/example-workerpool
          triggers:
            - type: github-runner
              name: example-runner
              metadata:
                owner: repo-owner
                runnerScope: repo
                repos: repo-name
                targetWorkflowQueueLength: 1
              authenticationRef:
                name: github-trigger-auth
          advanced:
            horizontalPodAutoscalerConfig:
              behavior:
                scaleDown:
                  stabilizationWindowSeconds: 10
                  policies:
                    - type: Pods
                      value: 100
                      periodSeconds: 10
                scaleUp:
                  stabilizationWindowSeconds: 10
                  policies:
                    - type: Pods
                      value: 2
                      periodSeconds: 10
        pollingInterval: 10

The YAML configuration uses the following high-level parameters:

  • triggerAuthentications: determines how CREMA authenticates the external service, such as using a token stored in Secret Manager.

  • scaledObjects: defines the mapping between your Cloud Run worker pool and the external metric resource. This parameter includes:

    • scaleTargetRef: the Cloud Run services or worker pools to scale.

    • triggers: the specific external metric used for scaling. If your external metric source requires authentication, set the authenticationRef field to specify one of the TriggerAuthentications objects for credentials.

  • pollingInterval: controls the interval (in seconds) at which CREMA refreshes its metrics. If you omit this parameter, CREMA doesn't poll automatically, and you must trigger a scaling check manually using a POST request to the service.

For more information on defining basic and advanced configuration metrics, see Configuration reference in the Google Cloud GitHub documentation.

For the complete list of configuration definitions for your compatible scalers, see Scalers in the KEDA documentation.

Store your CREMA configuration in Parameter Manager

To store parameter versions for your CREMA autoscaler service, follow these steps:

  1. Create a parameter in the Parameter Manager:

    gcloud parametermanager parameters create PARAMETER_ID --location=global  --parameter-format=YAML
    

    Replace PARAMETER_ID with the name of your parameter.

  2. Upload your local YAML file as a new parameter version:

    gcloud parametermanager parameters versions create PARAMETER_VERSION \
      --location=global \
      --parameter=PARAMETER_ID \
      --payload-data-from-file=LOCAL_YAML_CONFIG_FILE
    

    Replace the following:

    • PARAMETER_VERSION: the ID that you want to assign to the parameter version, for example, 1.
    • LOCAL_YAML_CONFIG_FILE: the path to your YAML configuration file.

For more information, see Create a parameter.

Grant additional permissions to your CREMA service account

To scale the worker pool you specified in your YAML configuration, grant the following permissions on the custom service account:

  1. Grant your CREMA service account permission to read from the Parameter Manager:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:CREMA_SERVICE_ACCOUNT_NAME \
      --role="roles/parametermanager.parameterViewer"
    

    Replace the following:

    • PROJECT_ID: the ID of your Google Cloud project.

    • CREMA_SERVICE_ACCOUNT_NAME: the name of your CREMA service account.

  2. Grant your CREMA service account the roles/run.developer role on the worker pool. This allows the CREMA service to modify the instance count of your worker pool in response to changing metrics:

    WORKER_POOL_NAME=WORKER_POOL_NAME
    WORKER_POOL_REGION=WORKER_POOL_REGION
    gcloud beta run worker-pools add-iam-policy-binding $WORKER_POOL_NAME \
      --region=$WORKER_POOL_REGION \
      --member="serviceAccount:CREMA_SERVICE_ACCOUNT_NAME" \
      --role="roles/run.developer"
    

    Replace the following:

    • WORKER_POOL_NAME: the name of the worker pool.
    • WORKER_POOL_REGION: the region of your worker pool.
  3. Grant your CREMA service account permission to write metrics:

     gcloud projects add-iam-policy-binding PROJECT_ID \
       --member="serviceAccount:CREMA_SERVICE_ACCOUNT_NAME" \
       --role="roles/monitoring.metricWriter"
    
  4. Grant your CREMA service account the service account user role:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:CREMA_SERVICE_ACCOUNT_NAME" \
      --role="roles/iam.serviceAccountUser"
    

Deploy the service to scale your workloads

To deploy the service to scale your worker pool, run the following command with a prebuilt container image:

gcloud beta run deploy SERVICE_NAME\
  --image=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0 \
  --region=SERVICE_REGION \
  --service-account="CREMA_SERVICE_ACCOUNT_NAME" \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-22/runtimes/java21 \
  --labels=created-by=crema \
  --set-env-vars="CREMA_CONFIG=projects/PROJECT_ID/locations/PARAMETER_REGION/parameters/PARAMETER_ID/versions/PARAMETER_VERSION,OUTPUT_SCALER_METRICS=True"

Replace the following:

  • SERVICE_NAME: the name of your autoscaler service.

  • SERVICE_REGION: the region of your service.

  • CREMA_SERVICE_ACCOUNT_NAME: the name of your CREMA service account.

  • PROJECT_ID: the ID of your Google Cloud project.

  • PARAMETER_REGION, PARAMETER_ID, and PARAMETER_VERSION: values you stored in the Parameter Manager.

You can also deploy your CREMA service using a custom container image you build from the source code with Cloud Build.

Test your CREMA service

To verify your autoscaling service is working correctly, check the Logs tab of the Cloud Run service.

You should see the following logs in your service's logs each time metrics are refreshed:

Each log message is labeled with the component that emitted it.

[INFO] [METRIC-PROVIDER] Starting metric collection cycle
[INFO] [METRIC-PROVIDER] Successfully fetched scaled object metrics ...
[INFO] [METRIC-PROVIDER] Sending scale request ...
[INFO] [SCALER] Received ScaleRequest ...
[INFO] [SCALER] Current instances ...
[INFO] [SCALER] Recommended instances ...

What's next