Run and scale self-hosted GitHub runners on Cloud Run worker pools Stay organized with collections Save and categorize content based on your preferences.
Preview — Cloud Run External Metrics Autoscaling (CREMA)
This feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of theService Specific Terms. Pre-GA features are available "as is" and might have limited support. For more information, see thelaunch stage descriptions.
Preview — Cloud Run worker pools
This feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of theService Specific Terms. Pre-GA features are available "as is" and might have limited support. For more information, see thelaunch stage descriptions.
This tutorial shows you how to use self-hosted GitHub runners onworker pools to execute the workflows defined in your GitHub repository, and scaleyour worker pool withCloud Run External Metrics Autoscaling (CREMA).
About self-hosted GitHub runners
In a GitHub Actions workflow, runners are the machines that execute jobs. For example, arunner can clone your repository locally, install testing software, and then runcommands that evaluate your code.
You can useself-hosted runners torun GitHub Actions on Cloud Run worker pool instances. This tutorialshows you how to automatically scale a pool of runners based on the number ofrunning and unscheduled jobs.
Objectives
In this tutorial, you will:
Add self-hosted GitHub runners to support a GitHub repository, andcreate Secret Manager secrets to securely store tokens and secrets.
Deploy a Cloud Run worker pool to Cloud Runand use the worker pool to accept jobs from GitHub actions.
Deploy the autoscaler CREMA service to scale your worker pool.
Test your CREMA service by verifying logs.
Costs
In this document, you use the following billable components of Google Cloud:
To generate a cost estimate based on your projected usage, use thepricing calculator.
Before you begin
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
- Create a project: To create a project, you need the Project Creator role (
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission.Learn how to grant roles.
Verify that billing is enabled for your Google Cloud project.
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
- Create a project: To create a project, you need the Project Creator role (
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission.Learn how to grant roles.
Verify that billing is enabled for your Google Cloud project.
Enable the Cloud Run, Secret Manager,Parameter Manager, Artifact Registry, and Cloud Build APIs.
Roles required to enable APIs
To enable APIs, you need the Service Usage Admin IAM role (
roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enablepermission.Learn how to grant roles.- Install and initialize the gcloud CLI.
- Update components:
gcloudcomponentsupdate
- Set the following configuration variables for CREMA used in this tutorial:
ReplacePROJECT_ID with the ID of your Google Cloud project.PROJECT_ID=PROJECT_IDCREMA_SERVICE_ACCOUNT_NAME=crema-service-account@$PROJECT_ID.iam.gserviceaccount.comCREMA_REPO_NAME=cremaAR_REGION=us-central1
- You incur charges for your Cloud Run scaling service based on how often you trigger scaling. For more information, estimate costs with thepricing calculator.
Required roles
To get the permissions that you need to complete the tutorial, ask your administrator to grant you the following IAM roles on your project:
- Artifact Registry Repository Administrator (
roles/artifactregistry.repoAdmin) - Cloud Build Editor (
roles/cloudbuild.builds.editor) - Cloud Run Admin (
roles/run.admin) - Create Service Accounts (
roles/iam.serviceAccountCreator) - Secret Manager Admin (
roles/secretmanager.admin) - Service Account User (
roles/iam.serviceAccountUser) - Service Usage Consumer (
roles/serviceusage.serviceUsageConsumer) - Storage Admin (
roles/storage.admin) - Parameter Manager Admin (
roles/parametermanager.admin)
For more information about granting roles, seeManage access to projects, folders, and organizations.
You might also be able to get the required permissions throughcustom roles or otherpredefined roles.
Note:IAM basic roles might also contain permissions to complete the tutorial. You shouldn't grant basic roles in a production environment, but you can grant them in a development or test environment.You need permission to edit the settings on a GitHub repository toconfigure the self-hosted runners. The repository can be user-owned, or anorganisation owned repository.
GitHub recommends using self-hosted runners withprivaterepositories only.
Create a custom service account
This tutorial uses a custom service account with theminimum permissions required to use the provisioned resources. To set up the service account, do the following:
gcloudiamservice-accountscreatecrema-service-account\--display-name="CREMA Service Account"Add self-hosted GitHub runners
To add self-hosted GitHub runners, follow the instructions inadding self-hostedrunnersin the GitHub documentation.
Identify the GitHub repository
In this tutorial, theGITHUB_REPO variable represents the repositoryname. This is the part of the name that you find after the domain namefor both personal user repositories and organization repositories. For example:
- If your domain URL is
https://github.com/myuser/myrepo, theGITHUB_REPO ismyuser/myrepo. - If your domain URL is
https://github.com/mycompany/ourrepo, theGITHUB_REPO ismycompany/ourrepo.
Create access token
Create a GitHub access token to dynamically add and remove runners by interactingwith your selected repository. To create an access token onGitHub and save it in the Secret Manager, follow these steps:
- Ensure you are logged into your GitHub account.
- Navigate to GitHub'sSettings > Developer Settings > Personal Access Tokens > Tokens (classic) page.
- ClickGenerate new token, and selectGenerate new token (classic).
- For the token scope, select therepo checkbox.
- ClickGenerate token.
- Copy the generated token.
For more information on access tokens seeAuthentication requirements inGitHub documentation.
Create a secret for your access token using Secret Manager
Take the secret token you created in theprevious step, and store it inSecret Manager. To set access permissions, follow these steps:
Create the secret in Secret Manager:
echo-n"GITHUB_TOKEN"|gcloudsecretscreategithub_runner_token--data-file=-Replace theGITHUB_TOKEN with the value you copied from GitHub.
Grant the
roles/secretmanager.secretAccessorto your custom service account to access your newly created secret:gcloudsecretsadd-iam-policy-bindinggithub_runner_token\--member"serviceAccount:$CREMA_SERVICE_ACCOUNT_NAME"\--role"roles/secretmanager.secretAccessor"
Deploy a worker pool
Create a Cloud Run worker pool to process GitHub actions. Thispool will use an image based on the GitHub-createdactions/runner image. To deploy a worker pool, follow these steps:
Clone the sample repository to your local machine to retrieve the code sample for use:
gitclonehttps://github.com/GoogleCloudPlatform/cloud-run-samplesChange to the directory that contains the Cloud Run samplecode:
cdcloud-run-samples/github-runner/worker-pool-containerDeploy the worker pool:
gcloudbetarunworker-poolsdeployWORKER_POOL_NAME\--regionus-central1\--source.\--scaling1\--set-env-varsGITHUB_REPO=GITHUB_REPO\--set-secretsGITHUB_TOKEN=github_runner_token:latest\--service-account$CREMA_SERVICE_ACCOUNT_NAME\--memory2Gi\--cpu4Replace the following:
- WORKER_POOL_NAME: the name of the worker pool
- WORKER_POOL_LOCATION: the region of the worker pool
- GITHUB_REPO: theGitHub repo name
If this is the first time using Cloud Run source deploys in thisproject, Cloud Run prompts you to create a default Artifact Registry repository.
Understand the code sample
The worker pool is configured with a Dockerfile that is based on the GitHub-createdactions/runner image:
FROMghcr.io/actions/actions-runner:2.329.0# Add scripts with right permissions.USERroot# hadolint ignore=DL3045COPYstart.shstart.shRUNchmod+xstart.sh# Add start entrypoint with right permissions.USERrunnerENTRYPOINT["./start.sh"]This helper script runs when the container is started, registering itself to theconfigured repository as an ephemeral instance, using a token you create.
# Configure the current runner instance with URL, token and name.mkdir/home/docker/actions-runner &&cd/home/docker/actions-runnerecho"GitHub Repo:${GITHUB_REPO_URL} for${RUNNER_PREFIX}-${RUNNER_SUFFIX}"./config.sh--unattended--url${GITHUB_REPO_URL}--pat${GH_TOKEN}--name${RUNNER_NAME}# Function to cleanup and remove runner from Github.cleanup(){echo"Removing runner..."./config.shremove--unattended--pat${GH_TOKEN}}# Trap signals.trap'cleanup; exit 130'INTtrap'cleanup; exit 143'TERM# Run the runner../run.sh &wait$!Use the worker pool to accept jobs from GitHub actions
Your worker pool instance is ready to accept jobs from GitHub actions.
If your repo doesn't already have any GitHub actions, follow the instructions in thequickstart for creating your first workflow.
If your repo has GitHub actions, verify that you completed the setup of yourself-hosted runner by invoking a GitHub action on your repository.
If your GitHub action doesn't use self-hosted runners,change yourGitHub action's job fromruns-on value toself-hosted.
Once you can configured an action to use the self-hosted runners, run the action.
Confirm theaction completes successfully in the GitHub interface.
Deploy the autoscaler CREMA service
You deployed one worker in your original pool, which allows processing ofone action at a time. Depending on your Continuous Integration (CI) usage, youmight need to scale your pool to handle an influx of work to be done.
Once you deploy the worker pool with an active GitHub runner, configure theCREMA autoscaler to provision worker instances based on the job status in the actionsqueue.
This implementation listens for aworkflow_jobevent. When you create a workflow job, it scales up the worker pool, and oncethe job is completed, scales it down again. It won't scale the pool beyond themaximum number of instances you configure, and scales to zero when all runningjobs have completed.
You can adapt CREMA based on your workloads.
Configure the autoscaler
This tutorial uses theParameter Manager tostore the YAML configuration file for CREMA.
Create a parameter in the Parameter Manager to store parameter versionsfor CREMA:
PARAMETER_ID=crema-configPARAMETER_REGION=globalgcloudparametermanagerparameterscreate$PARAMETER_ID--location=$PARAMETER_REGION--parameter-format=YAMLCreate a YAML file,
my-crema-config.yamlin the parent directory to define the autoscaler configuration:apiVersion:crema/v1kind:CremaConfigmetadata:name:gh-demospec:pollingInterval:10triggerAuthentications:-metadata:name:github-trigger-authspec:gcpSecretManager:secrets:-parameter:personalAccessTokenid:github_runner_tokenversion:latestscaledObjects:-spec:scaleTargetRef:name:projects/PROJECT_ID/locations/us-central1/workerpools/WORKER_POOL_NAMEtriggers:-type:github-runnername:GITHUB_RUNNERmetadata:owner:REPOSITORY_OWNERrunnerScope:reporepos:REPOSITORY_NAMEtargetWorkflowQueueLength:1authenticationRef:name:github-trigger-authadvanced:horizontalPodAutoscalerConfig:behavior:scaleDown:stabilizationWindowSeconds:10policies:-type:Podsvalue:100periodSeconds:10scaleUp:stabilizationWindowSeconds:10policies:-type:Podsvalue:2periodSeconds:10Replace the following:
- PROJECT_ID: the Google Cloud project ID
- WORKER_POOL_NAME: the name of the worker pool you deployed
- GITHUB_RUNNER: the name of the GitHub runner you configured
- REPOSITORY_OWNER: the owner of the GitHub repository
- REPOSITORY_NAME: the GitHub repository name
Upload your local YAML file as a new parameter version:
LOCAL_YAML_CONFIG_FILE=my-crema-config.yamlPARAMETER_VERSION=1gcloudparametermanagerparametersversionscreate$PARAMETER_VERSION\--location=$PARAMETER_REGION\--parameter=$PARAMETER_ID\--payload-data-from-file=$LOCAL_YAML_CONFIG_FILE
Grant additional permissions to your custom service account
To scale the worker pool you specified in your YAML configuration, grant the following permissionson the custom service account:
Grant your CREMA service account permission to read from the Parameter Manager:
gcloudprojectsadd-iam-policy-binding$PROJECT_ID\--member="serviceAccount:$CREMA_SERVICE_ACCOUNT_NAME"\--role="roles/parametermanager.parameterViewer"Grant your CREMA service account the
roles/run.developerrole on the worker pool:WORKER_POOL_NAME=WORKER_POOL_NAMEWORKER_POOL_REGION=us-central1gcloudbetarunworker-poolsadd-iam-policy-binding$WORKER_POOL_NAME\--region=$WORKER_POOL_REGION\--member="serviceAccount:$CREMA_SERVICE_ACCOUNT_NAME"\--role="roles/run.developer"ReplaceWORKER_POOL_NAME with the name of the worker pool.
Grant your CREMA service account permission to write metrics:
gcloudprojectsadd-iam-policy-binding$PROJECT_ID\--member="serviceAccount:$CREMA_SERVICE_ACCOUNT_NAME"\--role="roles/monitoring.metricWriter"Grant your CREMA service account the service account user role:
gcloudprojectsadd-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 witha prebuilt container image:
SERVICE_NAME=my-crema-serviceSERVICE_REGION=us-central1CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSIONIMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0gcloudbetarundeploy$SERVICE_NAME\--image=${IMAGE}\--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=${CREMA_CONFIG_PARAM_VERSION},OUTPUT_SCALER_METRICS=True"Create webhook secret value
To create a secret value to access the GitHub webhook, do the following:
Create a Secret Manager secret to manage access to your GitHub webhook.
echo-n"WEBHOOK_SECRET"|gcloudsecretscreategithub_webhook_secret--data-file=-ReplaceWEBHOOK_SECRET with an arbitrary string value.
Grant access to the secret to the autoscaler service account:
gcloudsecretsadd-iam-policy-bindinggithub_webhook_secret\--member"serviceAccount:$CREMA_SERVICE_ACCOUNT_NAME"\--role"roles/secretmanager.secretAccessor"
Create GitHub webhook
To create the GitHub webhook, follow these steps:
- Ensure you are logged into your GitHub account.
- Navigate to your GitHub repository.
- ClickSettings.
- UnderCode and automation, clickWebhooks.
- ClickAdd webhook.
Enter the following:
- InPayload URL, enter the URL of the Cloud Run CREMA service youdeployed,
my-crema-service. - ForContent type, selectapplication/json.
- ForSecret, enter theWEBHOOK_SECRET value you created previously.
- ForSSL verification, selectEnable SSL verification.
- ForWhich events would you like to trigger this webhook?, selectLet me select individual events.
- In the event selection, selectWorkflow jobs. Unselect any other option.
- ClickAdd webhook.
- InPayload URL, enter the URL of the Cloud Run CREMA service youdeployed,
Test your CREMA service
To verify your autoscaling service is working correctly,checktheLogs tab of the Cloud Run service.
You should see the followinglogs 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 ...Clean up
To avoid additional charges to your Google Cloud account, delete all the resourcesyou deployed with this tutorial.
Delete the project
If you created a new project for this tutorial, delete the project.If you used an existing project and need to keep it without the changes you addedin this tutorial,delete resources that you created for the tutorial.
The easiest way to eliminate billing is to delete the project that you created for the tutorial.
To delete the project:
Delete tutorial resources
Delete the Cloud Run service you deployed in this tutorial.Cloud Run services don't incur costs until they receive requests.
To delete your Cloud Run service, run the following command:
gcloudrunservicesdeleteSERVICE-NAME
ReplaceSERVICE-NAME with the name of your service.
You can also delete Cloud Run services from theGoogle Cloud console.
Remove the
gclouddefault region configuration you added during tutorialsetup:gcloudconfigunsetrun/regionRemove the project configuration:
gcloud config unset projectDelete other Google Cloud resources created in this tutorial:
What's next
- Learn more aboutCloud Run worker pools.
- Explore otherCloud Run demos, tutorials, and samples.
- Deploy your CREMA service using acustom container image you build from the source code with Cloud Build.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-12-17 UTC.