Continuous integration with the Google Cloud Run orb
Developer Advocate, CircleCI
This post will demonstrate how to use the Google Cloud Run platform in a CI/CD pipeline. The pipeline will test the application’s code, build a Docker image, and deploy the image as a Google Cloud Run service on the Google Cloud Platform.
Technologies used
This post assumes a basic understanding of the following;
Add a project to CircleCI
The project used in this demo can be found in this repo. If you would like to follow along, fork the repo. Then, signup for a free CircleCI account if you don’t already have one. Connect the project to CircleCI by following the instructions for setting up your build on CircleCI.
Google Cloud setup
Let’s create the necessary credentials needed to interact with the Google Cloud Run platform. These credentials will give our CI/CD pipeline the access needed to execute commands on the Google Cloud Platform (GCP).
Create a GCP project
Create a new project in the GCP console. Give your project a memorable name. We want to make it readily identifiable so that it is easy to tear down later. After creating it, be sure to copy the project id
as it is different from the project name
.
Getting your project’s credentials
Next, set up a service account key which you will use to create and manage resources in your GCP project. Follow the steps here to create service account keys. Select JSON
as the key type, and click Create. Save this .json
file locally.
Important security note: Protect your Google Cloud credentials from being published and exposed in a public GitHub repository. You must be very cautious with the data in this file because, if exposed, anyone with this information can log into your account, create resources, and run up charges. Add the credential’s .json
filename to the project’s .gitignore
file as a layer of protection against accidentally publishing this sensitive data.
CirceCI pipeline setup
Next, we need to update our pipeline configuration file in order to use the Google Cloud Run platform in our CI/CD pipeline.
Encoding the Google service account file
The service account file must be encoded into a base64
value in order to store this data as an environment variable on CircleCI. Run the following command in a terminal to encode the values and get the results:
base64 cicd_demo_gcp_creds.json
The results of this command will look similar to this:
ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiY2ljZC13b3Jrc2hvcHMiLAogICJwcml2YXRlX2tleV9pZCI6ICJiYTFmZDAwOThkNTE1ZTE0NzE3ZjE4NTVlOTY1NmViMTUwNDM4YTQ4IiwKICAicHJpdmF0ZV9rZXkiOiAiLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tXG5NSUlFdlFJQkFEQU5CZ2txaGtpRzl3MEJBUUVGQUFTQ0JLY3dnZ1NqQWdFQUFvSUJBUURjT1JuRXFla3F4WUlTXG5UcHFlYkxUbWdWT3VzQkY5NTE1YkhmYWNCVlcyZ2lYWjNQeFFBMFlhK2RrYjdOTFRXV1ZoRDZzcFFwWDBxY2l6XG5GdjFZekRJbXkxMCtHYnlUNWFNV2RjTWw3ZlI2TmhZay9FeXEwNlc3U0FhV0ZnSlJkZjU4U0xWcC8yS1pBbjZ6XG5BTVdHZjM5RWxSNlhDaENmZUNNWXorQmlZd29ya3Nob3BzLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg==
Copy the result into your clipboard. You’ll be using it in the next section.
Create project variables
In order for this CI/CD pipeline to execute commands on GCP, we have to create project-level environment variables on CircleCI. These environment variables will be used later in the config.yml
file.
Create the following project-level environment variables using the CircleCI dashboard:
- GOOGLE_PROJECT_ID: The Project ID for your Google Cloud project. This value can be retrieved from the project card in the Google Cloud Dashboard.
- GCP_PROJECT_KEY: The base64 encoded result from the previous section.
- GOOGLE_COMPUTE_ZONE: The value of the region to target your deployment.
Google Cloud Run (fully managed) vs Google Cloud Run on GKE with Anthos
Google Cloud Run allows you to run services on a fully managed environment or on a Google Kubernetes Engine (GKE) cluster with Anthos. In this post, I’ll address running Google Cloud Run fully managed as well as running Google Cloud Run on a GKE cluster with Anthos. In both cases, I’ll demonstrate how to integrate Google Cloud Run deployments into your CI/CD pipelines using the Google Cloud Run orb.
Creating a CI/CD pipeline with the Google Cloud Run (fully managed) service
Now that you have all of the elements required to use the Google Cloud Run platform in a CircleCI pipeline, update your project’s config.yml
file with the following configuration syntax.
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@0.6.1
cloudrun: circleci/gcp-cloud-run@1.0.0
jobs:
build_test:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
- run:
name: Run Tests
command: |
pytest
build_push_image_cloud_run_mangaged:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
- cloudrun/deploy:
platform: "managed"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
service-name: "orb-gcp-cloud-run"
region: $GOOGLE_COMPUTE_ZONE
unauthenticated: true
workflows:
build_test_deploy:
jobs:
- build_test
- build_push_image_cloud_run_mangaged:
requires:
- build_test
Cloud Run (fully managed) config breakdown
Let’s breakdown the pipeline syntax that implements the Google Cloud Run orb and deploys the application using the Google Cloud Run (fully managed) service.
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@0.6.1
cloudrun: circleci/gcp-cloud-run@1.0.0
The snippet above declares 2.1
as the version
of CircleCI’s platform to use. The orbs:
key specifies the orbs to include in this pipeline. In this example, I’ll be using the circleci/gcp-gcr@0.6.1
and circleci/gcp-cloud-run@1.0.0
orbs. I included the gcp-gcr
orb to demonstrate implementing multiple orbs into your pipeline.
jobs:
build_test:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
- run:
name: Run Tests
command: |
pytest
build_push_image_cloud_run_mangaged:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
The snippet above shows the jobs:
key which is a list of jobs that represents a grouping of actions to execute within the pipeline. This snippet specifies two jobs: build_test:
and build_push_image_cloud_run_mangaged:
. The build_test
job installs application dependencies. It then executes the project’s unit tests to ensure the app passes before moving onto the next job in the pipeline. The next job listed, build_push_image_cloud_run_mangaged:
, creates environment variables, and builds a Docker image that will be deployed to the Google Cloud Run service.
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
The snippet above uses the gcp-gcr/gcr-auth:
orb to authenticate to Google Container Registry (GCR) using the environment variables set in the previous section.
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
In the snippet above, the push-image
command is used to push the newly created image up to GCR for use within GCP.
- cloudrun/deploy:
platform: "managed"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
service-name: "orb-gcp-cloud-run"
region: $GOOGLE_COMPUTE_ZONE
unauthenticated: true
The code snippet above uses the deploy
function from the cloudrun
orb to create and deploy the Google Cloud Run service that will serve up the newly packaged Docker image. The platform
parameter is set to managed
which deploys the service to the fully managed environment on GCP.
The next section will demonstrate how to deploy the Docker image to Google Cloud Run for Anthos.
Creating a CI/CD pipeline with the Google Cloud Run service on GKE for Anthos
The previous section demonstrated how to deploy the application to the fully managed Google Cloud Run environment. In this section, I’ll demonstrate how to deploy an application to Google Cloud Run on GKE for Anthos. In the following pipeline example the build_test:
job is identical to the previous fully managed Google Cloud Run example, but notice the new job named build_push_image_cloud_run_gke:
which deploys an application to a Google Cloud Run service running on a GKE cluster via the Google Cloud Run orb.
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@0.6.1
cloudrun: circleci/gcp-cloud-run@1.0.0
jobs:
build_test:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
- run:
name: Run Tests
command: |
pytest
build_push_image_cloud_run_gke:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
- cloudrun/create_gke_cluster:
cluster-name: $CIRCLE_PROJECT_REPONAME
machine-type: "g1-small"
zone: $GOOGLE_COMPUTE_ZONE
enable-stackdriver-kubernetes: true
scopes: "cloud-platform"
- cloudrun/deploy:
platform: "gke"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
cluster: $CIRCLE_PROJECT_REPONAME
service-name: $CIRCLE_PROJECT_REPONAME
cluster-location: $GOOGLE_COMPUTE_ZONE
workflows:
build_test_deploy:
jobs:
- build_test
- build_push_image_cloud_run_gke:
requires:
- build_test
Cloud Run GKE Config Breakdown
The first job of the pipeline example shown above was covered in the fully managed section, so I’ll skip to the new job build_push_image_cloud_run_gke:
.
build_push_image_cloud_run_gke:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
The snippet above builds the Docker image based on the application and uploads the image to GCR. These actions are also identical to the Docker operations demonstrated in the fully managed section of this post.
- cloudrun/create_gke_cluster:
cluster-name: $CIRCLE_PROJECT_REPONAME
machine-type: "g1-small"
zone: "us-east1"
enable-stackdriver-kubernetes: true
scopes: "cloud-platform"
- cloudrun/deploy:
platform: "gke"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
cluster: $CIRCLE_PROJECT_REPONAME
service-name: $CIRCLE_PROJECT_REPONAME
cluster-location: $GOOGLE_COMPUTE_ZONE
workflows:
build_test_deploy:
jobs:
- build_test
- build_push_image_cloud_run_gke:
requires:
- build_test
In the snippet above, the pipeline deploys the Google Cloud Run app to a GKE cluster using the cloudrun
orb. The cloudrun/create_gke_cluster:
command created a new GKE cluster where the Google Cloud Run app will be deployed. Next, the cloudrun/deploy:
command deploys the application to the newly created GKE cluster. The application is being deployed to a Kubernetes cluster and can take a few minutes, so be patient during this process. It will take a bit longer than the other operations.
Wrapping up
This post shows how to automate the building, testing, and deploying of applications to the Google Cloud Run platform within CI/CD pipelines using the Google Cloud Run orb. Using orbs within CircleCI pipelines offers a clean, concise, and well-tested solution for deploying applications to the Google Cloud Run platform.
Thanks for reading!