This tutorial works with both public and private GitHub repos. Note that the previews themselves will be public, if obscure, URLs.
Objectives
- Create a Cloud Run service.
- Implement source-control based continuous integration on GitHub (also known as GitOps).
- Create and manage access to secrets via Secret Manager.
- Deploy a custom Cloud Builder.
- Create a Cloud Build trigger to invoke builds on GitHub pull requests.
Costs
This tutorial uses the following billable components of Google Cloud:
To generate a cost estimate based on your projected usage,
use the pricing 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.
-
Make sure that billing is enabled for your Cloud project. Learn how to check if billing is enabled on a project.
- Enable the Cloud Run, Cloud Build, and Secret Manager APIs.
-
In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Cloud project. Learn how to check if billing is enabled on a project.
- Enable the Cloud Run, Cloud Build, and Secret Manager APIs.
- Ensure sufficient permissions are available to the account used for this tutorial. In cases where the Owner role cannot be used, the following minimum roles are required to complete this tutorial:
- Cloud Run Admin
- Secret Manager Admin
- Cloud Build Editor
- Sign in or sign up for a GitHub account
Retrieving the code sample
For ease of use in this tutorial, you will create a new GitHub repository with a copy of a Hello World application based on a template. You will then add a new file to this repo with the custom Cloud Build configuration.
- Log into GitHub and navigate to the template repo.
- Create a new repo using this template by clicking "Use this template".
- Name your repo
helloworld-python. - Choose either "Public" or "Private" for the repo.
- Click Create repository from template.
- Name your repo
Create a new Cloud Build configuration file in your repo (full instructions):
- On your repo page, click Add file > Create new file
- Name the new file
cloudbuild.yaml Copy the code below to
cloudbuild.yaml:Keep the default "Commit directly into the
mainbranch" selection.Click Commit new file.
Deploying your service with a build trigger
This tutorial shows shows how to set up a build trigger to start a build automatically each time you update the main branch of your repository. You can also deploy your service manually by invoking Cloud Build each time you want to deploy a change.
For this tutorial, use the cloudbuild.yaml file to deploy a sample service called
myservice.
Grant the Cloud Run Admin and Service Account User roles to the Cloud Build service account (full instructions):
In the Cloud Console, go to the Cloud Build account settings page.
Enable the Cloud Run Admin role.
On the confirmation dialog, click Grant access to all service accounts.
Connect your GitHub account to Cloud Build (full instructions):
In the Cloud Console, go to the Cloud Build triggers page.
Click Connect Repository.
Select GitHub (Cloud Build GitHub App) as the source, and step through the authentication and authorization dialogs.
Select the "GITHUB_USER_NAME/helloworld-python" repository.
Click Connect repository.
In "Create a trigger (optional)", click Create a trigger.
Create a Cloud Build trigger (full instructions):
- In the Cloud Build triggers page, click Create trigger.
- Enter in the following details:
- Name:
prod-deploy - Event: Push to Branch
- Source Repository: "GITHUB_USER_NAME/helloworld-python"
- Source Branch:
^main$ - Build Configuration: Cloud Build configuration file (yaml or json)
- Cloud Build configuration file location:
cloudbuild.yaml
- Name:
- Click Create.
Run the new trigger manually:
- On the new trigger listing, click Run.
- In the popup, confirm the branch name (
main), and click Run Trigger. - Check the progress of the build by going to the Cloud Build history.
- Wait for the build to complete.
Confirm successful deployment.
In the Cloud Console, go to the Cloud Run page.
Confirm that the service has a green check mark showing successful deployment.
Click the Revisions tab and confirm that the service has one revision, serving 100% of traffic, starting with "myservice-00001-".
Click on the service's URL and confirm that the service displays "Hello World!".
Creating tokens and configurations
The prod-deploy trigger created in the previous section deploys the service when a push is made to the main branch. You will now create a second trigger that runs whenever a pull request is created or updated in your repo.
After the new trigger is set up, the preview will be deployed, but there will be no information in the pull request to link to the preview. To set up this functionality, you need to complete the following additional configuration steps:
- Create a GitHub token
- Store this token in Secret Manager
- Create a custom image to use as a step in Cloud Build.
Creating and storing a GitHub Token
- Create a GitHub token to allow writing back to a pull request (full instructions):
- Go to the GitHub Personal Access token settngs page.
- Click Generate new token.
- Enter the following details:
- Note:
preview-deploy - Expiration: 30 days
- Scope:
- For a public repo:
repo:status("Access commit status") - For a private repo:
repo("Full control of private repositories")
- For a public repo:
- Note:
- Click Generate token.
- Copy the value of the generated token.
Store the GitHub token in Secret Manager:
In the Cloud Console, go to the Secret Manager page.
Click Create Secret.
Enter the following details:
- Name:
github_token. - Secret value: paste the token value you copied from GitHub.
- Name:
Click Create Secret.
Allow Cloud Build access to this secret:
In a new browser tab, in the Cloud Console, go to the Cloud Build settings page.
Copy the value for "Service account email".
- The email is
PROJECT_NUM@cloudbuild.gserviceaccount.com
- The email is
Return to Secret Manager, and click on the Permission tab, and click Add
- New Principals:
PROJECT_NUM@cloudbuild.gserviceaccount.com - Role: Secret Manager Secret Accessor
- New Principals:
Click Save.
GitHub recommends setting expiration for personal access tokens, and will send reminder emails when tokens are set to expire. If you continue to use deployment previews, create a new version of the github_token when you regenerate your token. The builder in the next step retrieves the latest version of the token, so the previews will continue to work.
Creating a new image for Cloud Build
The script that writes the "Deployment Preview" notification to the pull request is located within the Python Docs Samples. Instead of adding this script into your source code, you can optionally build this script into a container within your project and run that container as a step in your Cloud Build configuration.
You can complete the following instructions using either
Cloud Shell, or your local
machine if you have installed and configured git and Google Cloud CLI. The
instructions below show both methods.
-
In the Cloud Console, activate Cloud Shell.
At the bottom of the Cloud Console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.
- Configure Google Cloud CLI to use your project, replacing
PROJECT_IDwith your project ID:export PROJECT_ID=PROJECT_ID gcloud config set project $PROJECT_ID
If using Cloud Shell, you may need to authorize Google Cloud CLI to make a Google Cloud API call. Click Authorize to allow this action to proceed. - Create a new container image:
git clone https://github.com/GoogleCloudPlatform/python-docs-samples cd python-docs-samples/ gcloud builds submit --tag gcr.io/$PROJECT_ID/deployment-previews run/deployment-previews
- Confirm that the container has been created:
gcloud container images list
- Remove the cloned repository:
cd .. rm -rf python-docs-samples
Add the new Cloud Build configuration
Your repository already has a cloudbuild.yaml file that is used on your main
branch. You will now create a new configuration for this new trigger.
On your GitHub repo page, click Add file > Create new file
- Name the new file
cloudbuild-preview.yaml - Copy the code below, and paste it into your new file:
- Name the new file
Commit the change to the main branch of your repository.
Creating the secondary trigger
Now that all the groundwork is in place, create the new trigger.
Create a new Cloud Build trigger (full instructions):
In the Cloud Console, go to the Cloud Build triggers page.
Click Create Trigger.
Enter the following details:
- Name:
preview-deploy - Event: Pull Request
- Source Repository: "GITHUB_USER_NAME/helloworld-python"
- Base branch:
^main$ - Comment control: Required except for owners and collaborators
- As the owner of the repo, previews will be automatically built on pull requests you create.
- If you want to allow anyone to preview their changes, read more about the security implications of selecting "Not required".
- Configuration: Cloud Build Configuration file
- Cloud Build configuration file location:
cloudbuild-preview.yaml
- Name:
Click Create.
Checking Success
Since this new trigger is fired when a new pull request is created, you will need to create a new pull request in order to test it.
- Go to your repository, and make a visual change to
app.pyin a new branch.- Go to
app.py, and click the pencil icon ().
- Make a change; for example, change "Hello" to "Greetings".
- Select Create a new branch for this commit and start a pull request, then click Propose change.
- Go to
Create a new pull request with this branch.
If the trigger is configured correctly, a new check is displayed soon after you create the pull request:
The name of the check is the name of the trigger and your project ID. Check on the progress of the build by clicking Details > View more details on Google Cloud Build.
If your trigger fails and you need to resubmit the build, or if you want to make another change to your pull request, you need to commit a change to the same branch. Each new commit on a pull request will trigger a new build.
After the trigger completes, a new status check named "Deployment Preview" is displayed for the pull request. The icon displayed is your avatar because your account owns the token being used:
Click Details to navigate to the preview. The URL shown is the same as your original service URL, but is prefixed with "pr-1---".
Note that if you navigate to the original service URL, the original content is shown:
View the revision list for your service to check the service state in Cloud Run: there are now two revisions serving traffic: the original and the preview:
Continue making changes to the pull request by adding new commits to the branch. Each time you commit, the
preview-deploytrigger fires, creating a new revision of the service and making the revision available at the same URL:
After you are ready to merge your changes, click Merge Pull Request. The original
prod-deploytrigger runs, and the changes from the pull request are reflected in the original URL:
The new revision serves 100% of the traffic at the main URL, but the pull request's preview URL is still attached to the most recent commit for that pull request, so the link will continue to work:
Limitations
There is a limit on the number of revision URLs that can be created. If you
expect your repo will have more than 1000 pull requests, consider a process to
clean up tags as shown in cloudbuild-cleanup.yaml.
Understanding the code
cloudbuild.yaml
This code is based on the sample cloudbuild.yaml provided by Cloud Build, but with a noted update: the fourth step that runs update-traffic.
The configurations in cloudbuild.yaml make changes to the traffic splitting.
The --to-latest parameter offers the same functionality as the
Serve this revision immediately checkbox in the Cloud Run page. It
ensures that this revision of the service serves 100% of traffic immediately.
cloudbuild-preview.yaml
This code is similar to cloudbuild.yaml, but with additional steps:
After building and pushing the service image,
cloudbuild-preview.yamldeploys the service using the--no-trafficflag. This means that even though this is the latest revision, it is not being used to serve traffic.cloudbuild-preview.yamladds a custom tag based on the pull request number. In this case, a string prefixed with "pr-" and ending in the number of the pull request.At this point, the revision URL is working, but the person who submitted the pull request is not able to determine this because Cloud Build logs are not visible from GitHub itself: only a link to the logs are visible. Only authenticated users of the Cloud Build project with sufficient permissions can see the logs.
cloudbuild-preview.yamlruns thecheck_status.pyscript, using built-in substitutions parameters provided by Cloud Build. A number of these parameters are available when working with GitHub repos, such as the pull request number, repo name, and commit SHA.
To re-run this trigger, submit another commit in GitHub. This trigger cannot be re-run from the Cloud Build page in the console.
cloudbuild-cleanup.yaml
This code is an alternative to cloudbuild.yaml, with added cleanup
functionality. The initial steps perform the deployment, and the functionality
is then extended as follows:
Using the Discovery API and GitHub APIs, determine which tags for the service are for closed pull requests. At a minimum, there will be the pull request that was merged, causing this trigger to fire.
Delete the tags identified.
check_status.py
The check_status.py script takes the provided information about the Cloud Run service,
about the GitHub repo and commit, and then performs the following operations:
- Retrieve the service name, tag, and revision URL using the Google API Python client.
- Retrieve the GitHub token from the environment variable, provided by Secret Manager.
- Create a status on the given commit, linking to the retrieved revision URL, using a GitHub Client API for Python.
Clean up
If you created a new project for this tutorial, delete the project. If you used an existing project and wish to keep it without the changes added in this tutorial, delete resources created for the tutorial. Additionally, you will need to delete the GitHub configurations created for the tutorial.
Deleting the project
The easiest way to eliminate billing is to delete the project that you created for the tutorial.
To delete the project:
- In the Cloud Console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
Deleting tutorial resources
Delete the Cloud Run service you deployed in this tutorial:
- Navigate to the Cloud Run console.
- Select the "myservice" listing, and click Delete.
- On the confirmation dialog, click Delete.
Delete other Google Cloud resources created in this tutorial:
- Delete the deployment-preview container image named
gcr.io/PROJECT_ID/deployment-previewfrom Container Registry. - Delete the helloworld container image named
gcr.io/PROJECT_ID/helloworldfrom Container Registry. - Delete the Cloud Build triggers.
- Delete the Secret Manager secret.
- Delete the deployment-preview container image named
Deleting tutorial configurations
To cleanup the configurations in GitHub, you will need to remove the Google Cloud Build application from GitHub:
- Navigate to the GitHub application settings
- On the Google Cloud Build listing, click Configure.
- In the Danger Zone section, click Uninstall.
- In the confirmation dialog, click Okay.
You will also need to delete the GitHub token created:
- Navigate to the GitHub personal access tokens page.
- On the preview-deploy listing, click Delete.
- In the confirmation dialog, click I understand, delete this token.
You will also need to delete the GitHub repo:
- Navigate to your created GitHub repo and click the Settings tab.
- In the Danger Zone section, click Delete this repository.
- In the confirmation dialog, enter the full name of the repository, and click I understand the consequences, delete this repository.
What's next
- Learn more about rollbacks, gradual rollouts, and traffic migration in Cloud Run.
- Learn more about GitHub app triggers in Cloud Build.

