Deploy to Cloud Run with GitHub Actions
Andrew Chasin
Cloud Infrastructure Engineer
Rawan Badawi
Reliability Engineer
Google Cloud customers rely on a mixture of Google Cloud services and third party software. In this blog, we discuss how to deploy Google Cloud Run from GitHub Actions using code from example workflows built by Google. We focus on deploying Cloud Run with a declarative service YAML to multiple environments.
Guidance on how to build images and deploy Google Cloud Run with buildpacks, from source, and from Docker can be found in this Google example workflows repository.The example in this blog will show a more detailed view of how to use one of these workflows while also being set up to deploy to multiple projects. This blog is intended for users who are not using Cloud Deploy, if you are using Cloud Deploy it is recommended that you see the following blog on how to use GitHub Actions with Cloud Deploy.
Typical workflow
A typical GitHub Actions workflow uses the following steps to deploy to Cloud Run.
Continuous Integration
- Artifact build stage: use language-specific tooling such as maven, gradle, sbt, npm to build an application artifact
- Packaging & Containerization stage: collect all of the necessary components and dependencies for the application artifact, containerize and push that image to an existing Artifact Registry (Docker, Buildpacks)
Continuous Deployment
- Release approval: Request and obtain approval to release new container artifact to the existing target environment. Use reusable deployment workflows, along with GitHub environments to manage the release process. Third party tools can be used for release management as well. Google Cloud Deploy handles releases seamlessly, although we have found that some customers want to use different tools for such deployments.
- Deploy stage: Deploy the new code from the release to the target environment
- Rollout stages: progress through a series of Cloud Run target environments with gradual rollouts or canary deployments
Prerequisites
- Workload Identity Federation must be set up with the pool and connected to the service account saved as a GitHub secret. A workload identity federation pool and connected service account are needed to authenticate to Google Cloud. Please see this blog for more information on setting this up.
- The service account has required roles to be able to push an image, impersonate the Cloud Run service account and deploy Cloud Run. The following roles are required.
- roles/artifactregistry.writer
- roles/iam.serviceAccountUser
- roles/run.admin
- roles/iam.workloadIdentityUser
GitHub Actions workflows
Caller workflow for environment based deployments
The workflow below is designed to be a caller workflow that reuses a base workflow; allowing different variables per environment. This can be used to deploy to separate environments even if the environments are split between Google Cloud projects.
This workflow builds a container image, pushes it to Artifact Registry, and deploys it to Cloud Run. This workflow is triggered on a push to the repository then deploys to the develop, stage, and main environments located in separate Google Cloud projects. Other triggers can be used, such as on a schedule or on a manual trigger. You can also define your variables using environments.
Here is a more detailed breakdown of the workflow:
- On push to develop, stage, or main, the workflow is triggered
- Builds the container image using a Dockerfile
- Pushes the container image to Artifact Registry
- Deploys the container image to Cloud Run in the corresponding Google Cloud project
Optional steps:
- Conduct code scanning and unit testing of code on pull requests
- Define variables using environments
- Trigger on a schedule or manually
The caller workflow can help with deployments to multiple environments. Here, the user can define different attributes per environment which will use the same base workflow to deploy. The caller workflow calls the workflow that is referenced within the uses block.
Reusable workflow
The reusable workflow defines inputs for the caller workflow. This allows the user to pass variables to the reusable workflow. The workflow_call attribute allows this workflow to be called from another workflow.
This workflow is also calling environment based secrets and variables. In this example, the following variables are defined.
Continuous Integration
Artifact build and packaging stages
The following workflow will show how to authenticate to Google Cloud and push an image to Artifact Registry before the artifact build & packing stages.
The first step of the workflow is to use the checkout and auth actions. These steps checkout the repository and authenticate to Google Cloud. Workload Identity Federation is used to utilize Open Authorization (OAuth) for adhering to zero trust.
Authenticate to Docker using the OAuth token that was generated in the previous step.
In the case of Docker builds, the Dockerfile will build the artifact then package that artifact into an image. A sample Dockerfile for packaging a Java application into a container image can be found in the Google Cloud Platform’s Java code samples.
The following workflow step will build the container image and tag it with the GitHub reference commit hash. This is to keep track of the latest image while also keeping commit history and images aligned. It is important to note the context attribute in this step tells the action where to look for the source code relative to the current working directory. Please see this repository for more information on the docker build push action.
Continuous Deployment
Release approval stage
In any application deployment, it is common to have controls on who can deploy to production and when. There are many different tools to handle change management. We will show how to do so with GitHub environments. Below we have defined three environments for our Cloud Run deployment.
There are many branch protection rules, available to enforce deployment standards on each environment. It is helpful to integrate branch protection rules to manage releases and prevent accidental deployments to your production environment. Below, we have defined a rule to require approvals before deployment.
Deploy stage
The next stage after approval is the stage to deploy to Cloud Run. This step will export the environment variables so they are defined locally within the workflow. The envsubst command will tokenize and replace the values in your service template YAML file. You can see a sample service template YAML in the Google example workflows repository. For a full list of attributes for the service YAML, please see the Google Cloud Run YAML Reference.
The next step uses Google’s Cloud Run GitHub Action to perform the Cloud Run deployment. Tokenizing the file name ensures the developer can split the traffic in production environments while it is not needed in lower environments.
Gradual rollout stage
Gradual rollouts can be utilized to partially deploy your new release to the target environment. To do this, you can split the traffic within your service YAML file. Traffic can also be changed in the console, please see the documentation on rollbacks, gradual rollouts and traffic migration in Google Cloud for more information on managing traffic.
You have now deployed a Cloud Run instance using GitHub Actions! You can find the Cloud Run GitHub Action with documentation here, and other GitHub Actions examples here. Don’t wait, test this deployment today!