top of page
  • Writer's pictureBlaz Marinovic

Setting up Cloud Build and Cloud Run through Terraform

Updated: Nov 14, 2023



For a lot of applications, you don't really need all the bells and whistles of a full-blown Kubernetes cluster. You just need a simple container that can run your application. This is where Cloud Run comes in. Cloud Run is a fully managed serverless container platform that allows you to run stateless HTTP containers. It's a great way to run your application without having to worry about the underlying infrastructure.

In this post, we'll be setting up a simple Cloud Run application using Terraform. We'll also be setting up a Cloud Build trigger to automatically deploy our application whenever we push to our repository.

Whereas the code itself will reside in the GitHub repository, we choose Cloud Build as our CI/CD tool because it is tightly integrated with Cloud Run. This means that we can easily deploy our application to Cloud Run without having to worry about authentication or permissions.


Prerequisites


Terraform Service Account roles


This blog post assumes you already have Terraform installed and Terraform Service Account set up. It also assumes you have Google provider configured in your main.tf/providers.tf file.

Make sure your Terraform Service Account has the following roles:

  • roles/storage.admin

  • roles/iam.serviceAccountAdmin

  • roles/iam.securityAdmin

  • roles/iam.serviceAccountKeyAdmin

  • roles/iam.serviceAccountUser

  • roles/secretmanager.admin

  • roles/artifactregistry.admin

  • roles/cloudbuild.connectionAdmin

  • roles/run.admin

  • roles/cloudbuild.builds.editor

Enabling APIs


Make sure the following APIs are enabled:

  • secretmanager.googleapis.com

  • cloudresourcemanager.googleapis.com

  • serviceusage.googleapis.com

  • cloudbuild.googleapis.com

  • artifactregistry.googleapis.com

  • run.googleapis.com

  • iam.googleapis.com


GCP project data


Throughout the project, we'll be using the following data source to fetch data about our GCP project (mostly project number)


Setting up Cloud Build


As part of our development pipeline, we'd like to set up a Cloud Build trigger that will:

  • build our Docker image whenever we push to our master branch

  • push the Docker image to Artifact Registry

  • deploy the Docker image to Cloud Run

Prerequisites (Manual steps)

  1. Install Cloud Build GitHub App and generate GitHub Personal Access Token as explained here

  2. Save the generated token as a secret in Google Secret Manager and name it github_token


Terraform


GCP <-> GitHub connection


1. We fetch previously created secret from Secret Manager and use it as a credential for our GitHub connection


2. We give Cloud Build Service Agent access to the secret. Bear in mind that we are not giving the whole Cloud Build service account access to the secret, but only the Cloud Build Service Agent. This is because we want to limit the scope of the service account as much as possible. This is a special service account used by Cloud Build to interact with other GCP services. It's automatically created in your GCP project when you enable the Cloud Build API. This service agent is what actually performs actions on behalf of Cloud Build, like accessing resources, running builds, pulling/pushing from/to Container Registry, accessing Secret Manager, etc.


3. We create the GitHub connection


4. We create a Cloud Build repository resource (2nd Gen). This is a resource that represents a GitHub repository in Cloud Build. It's used to store the configuration of the repository, like the connection to GitHub.



Artifact Registry

We create a new Artifact Registry repository. This is where we'll be storing our Docker images.


Cloud Build

Since we'll be using Cloud Build to push our Docker images and deploy our application, we need to give it the necessary permissions.


1. Grant the Cloud Build Service Agent permissions to Artifact Registry so it can push Docker images to it


2. Grant the Cloud Build Service Agent permissions to Cloud Run so it can deploy our application


3. Impersonate the Cloud Build service account as the Compute Engine service account, so it can run the Cloud Run service. This is because Compute Engine service account is the default service account for Cloud Run.


4. Define the Cloud Build trigger. We want to trigger the build whenever we push to the master branch. The build configuration is defined in cloudbuild.yaml file in the root of the project.


5. Our cloud_build.yaml file:



Setting up Cloud Run


Similar to Cloud Build, Cloud Run has its Service Agent named serverless-robot-prod. It is automatically created in your GCP project when you enable the Cloud Run API. This service agent is what actually performs actions on behalf of Cloud Run and this is the reason we need to give it the necessary permissions so it can pull the images from Artifact Registry and run the Cloud Run service.


1. Google mentions that this Service Agent has the roles/run.serviceAgent role granted on the project, but if you try to deploy the Cloud Run service without explicitly granting it the roles/run.serviceAgent role, you'll get an error Failed to list OAuth clients, so we give it that role explicitly.


2. We give the Cloud Run Service Agent these permissions so it can pull images from Artifact Registry


3. We define the Cloud Run service. We use a placeholder image for the creation of the service, so that it does not fail if the image is not yet built. Later on, this is overridden by the image built by the cloudbuild.yaml (this is the same thing Google does when you create a Cloud Run service through the UI).



4. (Optional) Allow unauthenticated invocations of the service. This is useful if you want to invoke the service from outside GCP. If you don't need this (e.g. if your service is invoked only by your PubSub), you can skip this step.


Conclusion


And that's it! We've set up a Cloud Build trigger that will build our Docker image and deploy it to Cloud Run whenever we push to our master branch. We've also set up a Cloud Run service that will run our application.

If this seems like a lot of work, it's because it is. Google does all of this behind the scenes when you create a Cloud Run service through the UI. However, if you want to automate your infrastructure, you'll have to do it yourself. Luckily, Terraform makes it easy to do so.

27 views0 comments

Comments


bottom of page