How to deploy your Cloud Run service using GitHub Actions

Create a world-class CI/CD where you can build, test, and deploy your cloud run application right from GitHub.

Felipe Martinez
Google Cloud - Community
7 min readAug 16, 2020

--

Introductions

In this article, we will use GitHub Actions as a CI/CD pipeline in order to deploy automatically our Cloud Run service when you push new code to master.

TLDR;

In this blog post, we created our simple java spring boot application on GitHub and set up the GitHub Actions to deploy it to Cloud Run.

You can see a working repository here.

Requirements

  1. GCP account with the billing activated. If you don’t have one yet you can create a new one using the free tier at $300.
  2. Free GitHub account and a new repository.

Concepts

Cloud Run

Write code your way by deploying any container that listens for requests or events. Build applications in your favorite language, with your favorite dependencies and tools, and deploy them in seconds.

Cloud Run abstracts away all infrastructure management by automatically scaling up and down from zero almost instantaneously — depending on traffic. Cloud Run only charges you for the exact resources you use.

Cloud Run makes app development and deployment simpler and faster. And it’s fully integrated with Cloud Code, Cloud Build, Cloud Monitoring, and Cloud Logging for an enhanced end-to-end developer experience.

GitHub Actions

GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.

** GitHub Action has a free tier of 2,000 minutes per month.

Before start

You will need a GCP project, so if you haven’t created yet you can follow these steps:

  1. Go to the Manage resources page in the Cloud Console.
    GO TO THE MANAGE RESOURCES PAGE
  2. On the Select organization drop-down list at the top of the page, select the organization in which you want to create a project. If you are a free trial user, skip this step, as this list does not appear.
  3. Click Create Project.
  4. In the New Project window that appears, enter a project name and select a billing account as applicable. A project name can contain only letters, numbers, single quotes, hyphens, spaces, or exclamation points, and must be between 4 and 30 characters.
  5. Enter the parent organization or folder in the Location box. That resource will be the hierarchical parent of the new project.
  6. When you’re finished entering new project details, click Create.

You will also need to enable the Cloud Run API and Container Registry API:

  1. Go to the Cloud Console API Library.
  2. From the projects list, select the project you want to use.
  3. In the API Library, select the Cloud Run API
  4. On the API page, click ENABLE.
  5. Select Container Registry API
  6. Click ENABLE

Authentication

Creating a Service Account

The GitHub runner runs on their own data center, so we will need to authenticate the calls to our GCP project. GitHub also gives you the ability to have the actions running within your own environment, but this will be a topic for another post :).

In order to achieve that, we will create a Service Account and add the keys in the GitHub Secrets section.

  1. In the Cloud Console, go to the Service Accounts page.
  2. Click Select a project, choose your project, and click Open.
  3. Click Create Service Account.
  4. Enter a service account name — we will use github-action-deploy.
  5. As a best practice, we should grant the minimum permissions necessary, so this Service Account will need the roles Cloud Run Admin, Service Account User, and Storage Admin.

Save it.

In the next page, click on the service account name and click on Add Key

Click on Create a new key and leave it to the JSON format and click create. You should download a JSON key.

Add the Service Account credentials to GitHub

  1. On the GitHub page in your new repo, go to the Settings -> Secrets. The values added here will work as an environment variable within the GitHub Action.
  2. Click on new secret and add the name GCP_SA_KEY and copy the content of the service account key you just downloaded into the value section.
  3. Click on new secret again and add the name GCP_SA_EMAIL. Copy the service account email we just created into the value section.
  4. We will also add our GCP project ID into the secrets in order to avoid having this exposed within the code. Click on new secret and add the name GCP_PROJECT_ID. Copy the project ID from your GCP Console.
Example of GitHub Secret creation

Demo App

Creating a Java Application

** You can use your own container with any language you desired and if you have one already you can skip this section **

We will be using the java hello world application example from the GCP documentation that you can find here, and you can create your own following these steps.

  1. Create a new java spring boot app based on the spring starter website.
curl https://start.spring.io/starter.zip \
-d dependencies=web \
-d javaVersion=1.8 \
-d bootVersion=2.1.3.RELEASE \
-d name=helloworld \
-d artifactId=helloworld \
-d baseDir=helloworld \
-o helloworld.zip
unzip helloworld.zip
cd helloworld

2. Update your HelloworldApplication.java file adding our HelloWorld endpoint. The file should be similar to

package com.example.helloworld;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class HelloworldApplication {

public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}

@Value("${TARGET:World}")
String target;

@RestController
class HelloworldController {

@GetMapping("/")
String hello() {
return "Hello " + target + "!";
}
}

}

Create your Dockerfile

We are also using the GCP example from here.

# Use the official maven/Java 8 image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3.5-jdk-8-alpine as builder

# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src

# Build a release artifact.
RUN mvn package -DskipTests

# Use AdoptOpenJDK for base image.
# It's important to use OpenJDK 8u191 or above that has container support enabled.
# https://hub.docker.com/r/adoptopenjdk/openjdk8
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim

# Copy the jar to the production image from the builder stage.
COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar

# Run the web service on container startup.
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/helloworld.jar"]

GitHub Action

Create the Actions file

Create a file on the folder .github/workflows/cloud-run-action.yaml inside your repo. Don’t forget to add the correct project ID.

name: publish

on: [push]

jobs:
build:
name: Cloud Run Deployment
runs-on: ubuntu-latest
steps:

- name: Checkout
uses: actions/checkout@master

- name: Setup GCP Service Account
uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
version: 'latest'
service_account_email: ${{ secrets.GCP_SA_EMAIL }}
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true

- name: Configure Docker
run: |
gcloud auth configure-docker

- name: Build
run: |
docker build -t gcr.io/${{ secrets.GCP_PROJECT_ID }}/helloworld:latest .

- name: Push
run: |
docker push gcr.io/${{ secrets.GCP_PROJECT_ID }}/helloworld:latest

- name: Deploy
run: |
gcloud run deploy helloworld \
--region europe-west1 \
--image gcr.io/${{ secrets.GCP_PROJECT_ID }}/helloworld \
--platform managed \
--allow-unauthenticated \
--project ${{ secrets.GCP_PROJECT_ID }}

At the end of the deploy section log, you will see the Cloud Run URL deployed, and it should look like something similar this:

Service [helloworld] revision [helloworld-00002-123] has been deployed and is serving 100 percent of traffic at https://helloworld-abcsdefgh-ew.a.run.app

Clean UP

  1. Delete your Cloud Run instance.
  2. Remove the Service Account IAM permissions.
  3. Delete the Service Account.
  4. Delete the Image from the registry.
  5. Delete your GitHub Repo if you don’t need it anymore.
  6. Delete the project in case you will not use it anymore.

So…

You could see the GitHub Actions integrates smoothly with GCP. You also have an option to use your own runner inside your own environment if you are concern about security and data on someone's server.

Cloud Run is pretty straight forward as well and I do recommend you have a try if serverless is an option for you — and you don’t want to care about servers.

You can also see a fully working version on GitHub account https://github.com/femrtnz/cloud-run-github-action

Please feel free to comment and let me know if you have any questions.

References

https://cloud.google.com/run/docs/quickstarts/build-and-deploy

https://docs.github.com/en/actions/getting-started-with-github-actions

--

--