Continuous Deployment to Cloud Run Services based on a New Container Image.

This article explains an approach to continuously deploy revisions to Cloud Run service(s) based on a new container image.

Continuous Deployment

Continuous deployment is a strategy for software releases wherein any code commit that passes the automated testing phase is automatically released into the production environment, making changes that are visible to the software's users.

Cloud Run

Cloud Run is a managed compute platform that enables you to run stateless containers, on its serverless environment and abstracts away all infrastructure management, so you can focus on what matters most — building great applications.

If you are new to Cloud Run, feel free to jump into its documentation here.

Continuous deployment on Cloud Run across multiple unknown services based on a container image could be challenging.

Google Cloud Run does not automatically deploy a revision when you push a new image to a tag reference. There are many good reasons it doesn’t.

When a Cloud Run revision is deployed, it computes the sha256 hash of the image reference.

Therefore when you specify a container image with :latest tag, Cloud Run uses its sha256 reference to deploy and scale out that revision of your service. When you update :latest tag to point to the new image, Cloud Run will still use the previous image. It would be a dangerous and slippery slope otherwise. - Ahmet on SO

Continuous Deployment for a Single Cloud Run Service

Google Cloud Build triggers can be used to build and push new container images when code is updated, you can as well add another step to your build configuration for continuous deployment.

Here's an example of a Cloud Build configuration that builds and pushes new images to Google Container Registry (GCR), it also deploys a new revision to the Cloud Run service dashboard.

# cloudbuild.yaml
# Build and Push New Image to Google Container Registry
- name: ""
  args: ["--cache=true", "--cache-ttl=48h", ""]

# Extra step to Deploy New Revision to Cloud Run
- name: ""
  args: ['beta', 'run', 'deploy', 'dashboard', '--image', '', '--region', 'us-central1', '--allow-unauthenticated', '--platform', 'managed']

Continuous Deployment for Multiple Cloud Run Services

If you need to update multiple Cloud Run services, you can simply have extra steps for deploying to Cloud Run services within your Cloud Build configuration, provided you know the service name of each Cloud Run service.

At Mercurie, we use Cloud Run for Multitenancy - this involves automatically creating new services for every new client (or tenant).

To achieve continuous deployment across stores, you could write a Cloud Function that deploys new revisions to your multiple Cloud Run services with the updated container image. This works by subscribing to Cloud Build's notifications through Pub/Sub and then triggering the Cloud Function.

Cloud Function to Update Cloud Run Services

Cloud Functions allows users to write single-use, programmatic functions which listen for cloud events, such as builds. When a cloud event occurs, a trigger responds by executing an action, such as sending a Cloud Pub/Sub message.

Cloud Build publishes messages on a Google Cloud Pub/Sub topic when your build's state changes, such as when your build is created, when your build transitions to a working state, and when your build completes.

The Pub/Sub topic to which Cloud Build publishes these build update messages is called cloud-builds, and it is automatically created for you when you enable the Cloud Build API. Each message contains a JSON representation of your Build resource, and the message's attributes field contain the build's unique ID and the build's status.

Visit Cloud Functions and Create Function

  • Enter your function's name : updateCloudRunServices
  • Set Memory Allocated : 256MB
  • Set Trigger : Cloud Pub/Sub
  • Set Topic : cloud-builds
  • Source code : Select - Inline editor
  • Runtime : Node.js 8
  • Function to execute : updateCloudRunServices

Paste the following code snippet into the Inline editor and create your function.

You now have a Cloud Function that listens to Pub/Sub notifications from Cloud Build when source code gets updated, which also builds a new container image and pushes to GCR using Cloud Build Triggers.

It checks if the updates are to the dashboard source code repo and if the build status is SUCCESS, then it calls the updateDashboardRevisions method which uses a token to make API request to Cloud Run, fetches all services, filters them to get only the services using the container image

Then creates a new build configuration with steps which is submitted to Cloud Build via its API. This successfully updates all Cloud Run services that are based on our container image

Additional Resources

Thanks for reading through! Let me know if I missed any step, if something didn’t work out quite right for you or if this guide was helpful.

Comments (2)

Blaine Garrett's photo

Great article! As a long time App Engine developer, one thing I don't understand about Cloud Run's deployment process is version switching. With App Engine, I could could deploy a release to both QA and Production but not migrate traffic on the later. Once automation tests were run on QA environment and some manual smoke tests, then we would migrate traffic to already deployed version. It was just a few clicks at that point.

So far as I can tell with Cloud Run, there are "revisions" but no concept of traffic splitting, migration, or the default "instance" so that you can quickly switch over to an already deployed (and warmed up) "instance".

Do you have any insight or best practice advice on this?

Timothy Olaleke's photo

Hi Blaine,

Thanks for reading up and making such an awesome comment.

Cloud Run currently only supports serving traffic from the last healthy revision of your service. Therefore, it currently does not support revision based traffic splitting and canary deployments.

You can take a look at this issue: