Rob Morgan

Australian Startup CTO, Berlin Alumni, Creator of Phinx, Startups, Technology, Travel

GCP Serverless CI/CD Pipeline

Recently Google introduced its serverless offering called Cloud Run which abstracts away all infrastructure management, so you can focus on building apps. By combining Cloud Run, Cloud Build and Cloud Source Repositories, we can build a simple, serverless CI/CD pipeline that automatically deploys an app whenever new commits are pushed. Basically you’ll get a Heroku-style interface for much less money and about 20 minutes of work.

Under the hood, we’ll deploy all of the resources using Terraform. You can find the example code used in this post on my GitHub. First, let’s have a look at the steps involved.

Overview

I’ve broken this guide down into the following steps:

  1. Installing the necessary tools
  2. Enabling the appropriate permissions
  3. Running Terraform to deploy the resources
  4. Deploying a custom app
  5. Viewing the app
  6. Cleaning up afterward
  7. Next steps

Install the necessary tools

In order to complete this guide, you’ll need to install the following tools:

  • Terraform: This guide uses Terraform to deploy the resources and manage all the infrastructure as code.
  • Docker: Docker is required for local development and to push Docker images to Google Container Registry.
  • Git: Git is used to clone the example code and trigger new deployments.
  • GCP: You will need a GCP account with billing enabled. There is a free tier that includes $300 of free credit over a 12 month period. You will also need to install the gcloud command-line tool.

Enable the appropriate permissions

This guide requires certain permissions to be configured correctly for the CI/CD pipeline to work. To make life easier I’ve put together a small shell script that can do this for you automatically. This script will automatically enable the following APIs:

  • cloudbuild.googleapis.com
  • containerregistry.googleapis.com
  • cloudresourcemanager.googleapis.com
  • cloudrun.googleapis.com

Then add certain IAM policy bindings so Cloud Build and Cloud Run can work correctly. First ensure you have set the GOOGLE_CLOUD_PROJECT environment variable to your GCP project ID (e.g: project-foo-123456). Then, let’s execute the script:

$ git clone https://github.com/robmorgan/terraform-cloudrun-example.git
$ cd terraform-cloudrun-example
# from the terraform-cloudrun-examples directory
$ ./bin/setup-iam-permissions.sh

Manual Configuration

You can also manually enable the APIs using the following links:

  1. Enable the Cloud Build API
  2. Enable the Cloud Run API
  3. Enable the Container Registry API
  4. Enable the Cloud Resource Manager API

Note: Be sure to select the appropriate GCP project.

Then to add the IAM policy binding, simply run:

$ gcloud iam service-accounts add-iam-policy-binding \
  [PROJECT_NUM][email protected] \
  --member=serviceAccount:[PROJECT_NUM]@cloudbuild.gserviceaccount.com \
  --role=roles/iam.serviceAccountUser \
  --project=[PROJECT_ID]

Note: Be sure to swap [PROJECT_NUM] and [PROJECT_ID] with your GCP Project ID Number and your GCP Project ID.

Grant Cloud Build Permissions

Lastly, we need to ensure Cloud Build has the appropriate permissions to deploy to the Cloud Run service.

  1. Visit the Cloud Build settings page.
  2. In the Service account permissions panel, set the status of the Cloud Run Admin role to Enabled.
Cloud Build Service Account Permissions

If the GCP console opens a modal that says ‘Additional steps may be required’, you can safely click the ‘SKIP’ button.

Cloud Build Service Account Permissions Additional Steps

The following Google Cloud Build page has more information on the required permissions.

Deploy the Resources using Terraform

If you haven’t already, you should clone the following repository containing the example code, then switch to the terraform-cloudrun-example directory:

$ git clone https://github.com/robmorgan/terraform-cloudrun-example.git
$ cd terraform-cloudrun-example

Next, copy the terraform.tfvars.example file to terraform.tfvars. You will need to replace the value of the project variable.

Now we can use Terraform to deploy all of the necessary resources. Simply run the following commands:

  1. terraform init
  2. terraform plan
  3. terraform apply

Terraform will then deploy all of the necessary resources for our pipeline including a Cloud Run service, Git repository and a Cloud Build trigger. This step will take approximately 1-2 minutes to complete. After Terraform has completed, you’ll see a bunch of outputs similar to the following:

Apply complete! Resources: 2 added, 0 changed, 1 destroyed.

Outputs:

registry_url = us.gcr.io/your-project-123456
repository_http_url = https://source.developers.google.com/p/your-project-123456/r/sample-node-app
trigger_id = b4d81a09-20e7-4d2c-9902-577d8c160989
url = https://sample-docker-service-s4fqxvtrpq-uc.a.run.app

You can test the sample application by opening the URL in your browser:

$ open $(terraform output url)

You should see something similar to the following:

Sample Google Cloud Run App

So far we’ve launched a Sample Google App, however, in the next step we’ll deploy a custom app of our own.

Deploying a Custom App

Because Cloud Run uses Docker under the hood, you can use any of your favourite languages including Go, Python, PHP, Java and Node.JS to write your apps! For the purposes of this guide, we’ll use my basic Node app to demonstrate how to deploy custom apps. First, start by cloning it using Git:

$ git clone https://github.com/robmorgan/sample-node-app.git
$ cd sample-node-app

Then run the following commands to add our Cloud Source Repository as a Git remote:

$ git config --global credential.'https://source.developers.google.com'.helper gcloud.sh
$ git remote add google https://source.developers.google.com/p/[PROJECT_ID]/r/[REPO_NAME]

Note: You must substitute [PROJECT_ID] with your GCP Project ID and [REPO_NAME] with your Cloud Source Repositories repo name. You can find these values by running terraform output repository_http_url in the terraform-cloudrun-example directory.

Now it’s time to push the app source code to our Cloud Source Repository:

$ git push google master

Google Cloud Build will trigger a new build and automatically deploy the resulting Docker container on Cloud Run. This is handled automatically as my sample Node app contains a cloudbuild.yaml file in the root of the repository.

Note: As we’ve deployed a custom app by pushing to Cloud Source Repositories, we should update the image reference in the terraform.tfvars file otherwise Terraform will deploy the Google sample app next time it’s invoked.

View the App

Once again we can open the URL in our web browser to see that the custom app has been deployed:

# change to the 'terraform-cloudrun-example' directory
$ open $(terraform output url)

You should see something similar to the following:

Sample Node.js App

Clean Up

Even though Cloud Run is dirt cheap to run your apps, we can easily clean up using the Terraform destroy command:

$ terraform destroy

In about 30 seconds, Terraform will undeploy the app and destroy all of the resources we’ve created.

Next Steps

This guide gave an example of how to deploy a simple CI/CD pipeline using serverless technologies. Under the hood, Cloud Run is built on top of an open standard - Knative which you should read more about. Additionally, you may want to explore adding a relational database using Cloud SQL so you can run stateful apps.