DEV Community

loading...
Cover image for Quickstart: Continuous deployment to Google Cloud Run using Github Actions

Quickstart: Continuous deployment to Google Cloud Run using Github Actions

pcraig3 profile image Paul Craig ・8 min read

Preamble

If you’re a hobbyist developer and you want to host your fun app for next-to-free, you should definitely use Google Cloud Run. Once you set it up, Cloud Run is a dream to work with, but getting started can mean a lot of trial and error.

In this post, I will go step-by-step through setting up GitHub Actions to automatically deploy your cool app to Cloud Run.

Let’s get started.

Prerequisites

1. Install gcloud and do a local deployment

My initial idea was to write a “how to get started with Cloud Run” post, but it turns out the official Quickstart is excellent.

If you’re just starting out, follow Google’s Quickstart. It covers:

By the end of the tutorial, you will have installed the gcloud command-line interface (CLI) and used it to deploy your first container to Cloud Run. This article picks up after the Quickstart material: it’s intended for anyone looking to add a bit more automation to their deployments.

2. Create a GitHub repository

You will also need a GitHub repository — you know, for the GitHub Actions to work. If you’re more of a “see the code” learner, I created an example repo — pcraig3/hello-cr — as part of writing the article. Feel free to clone or fork it.

Service accounts

When you run gcloud commands locally, you’re probably using your root account (ie, tied to your email address) because that’s the default account you create when you sign up to GCP. For local development, that’s fine: your root account is a superuser with lots of permissions, so you can do whatever you need to.

However, you should really avoid using your root account on other platforms. If your account password is ever stolen, an evildoer can take over your entire G-Cloud setup and use it to host crappy websites, run up a huge tab, or steal your data.

Instead, you should create a "service account": a separate account with limited permissions intended for specialized tasks. If your service account is compromised, the aforementioned evildoer can take down your Cloud Run app, but they won’t be able to mess up too much else.

Creating a service account using the Console

I’m most familiar with creating service accounts by logging in and clicking around, so that’s what I’m going to do here. If you’re smarter than me, you might prefer the command line, but all the same stuff will apply.

  • Log in to Google’s backend console
  • Using the drop-down selector in the header, pick the project where your Cloud Run app lives. (Mine is called hello-cr, it’ll be in a few screenshots)

Project: hello-cr

  • Open the left-hand navigation menu and select "IAM & Admin" > "Service Accounts"

Service accounts

  • Click "+ Create service account": it will be in the contextual header near the top of the screen
  • The first section is titled "Service account details". Enter a "Service account name" (it will also be used for the id). Adding a description is optional. Click "Create" when you are finished.

Service account details

  • Next, assign permissions to your new service account. This part was pretty tricky to figure out, but after a lot of trial and error, I found this combination works.
  • Add the following permissions:
    • Cloud Run Admin
    • Cloud Run Service Agent
    • Cloud Build Service Agent
    • Viewer
  • Click "Continue"

Alt Text

  • The final section ("Grant users access to this service account") is not relevant to this tutorial, so you can skip it.

Hooray! Now that you’ve created your service account, let’s make sure that everything works as expected by trying a local deployment as your new service account.

Authenticating on the command line as a service account

Show all of your service accounts with

  • gcloud iam service-accounts list

The account you just created should be listed there.

In order to run commands as the service account, we will need to download a service account key. The service account key is a JSON file containing credentials for the account, so be careful with it (eg, don’t commit it to your repository 😬).

Get the service account key with

  • gcloud iam service-accounts keys create ./NAME-OF-KEY-FILE.json --iam-account EMAIL-ADDRESS

Replace EMAIL-ADDRESS with the email for your service account. Also, you probably want to rename the .json file to something less shouty. If you store it in your app directory, make sure to add it to your .gitignore file.

Now that you have the key file, you can authenticate yourself as this service account.

Authenticate yourself with

  • gcloud auth activate-service-account --key-file=NAME-OF-KEY-FILE.json

This way, you can run commands as the service account.

You can see which account you are logged into with

  • gcloud auth list

You can change back to your original account at any time with

  • gcloud config set account YOUR-EMAIL-ADDRESS

Deploying your app with your service account

You should be able to build and deploy your app using your service account. To do so, follow the steps outlined in the Cloud Run Quickstart.

Build your container image using Cloud Build, by running the following command from the directory containing the Dockerfile:

gcloud builds submit --tag gcr.io/PROJECT-ID/helloworld

where PROJECT-ID is your GCP project ID.

Once built, let’s deploy.

Deploy using the following command:

gcloud run deploy --image gcr.io/PROJECT-ID/helloworld --platform managed

Replace PROJECT-ID with your GCP project ID. You can view your project ID by running the command gcloud config get-value project.

Nice! If the deploy succeeded, you know this service account has the permissions it needs to automate future deployments.

Setting up a "deploy" GitHub Action

Phew, now we’re on the home stretch.

Github Actions automate various parts of your development workflow: you can run tests, do linting, or trigger notifications based on certain conditions. You can also set up rules to deploy your app when your main branch is updated, which is what we want to do.

GitHub maintains a Marketplace of third-party Actions that we can use to plug into third-party services. Luckily for us, the folks at GCP have built a GitHub Action we can use to log in and run CLI commands: https://github.com/marketplace/actions/setup-gcloud-environment

GitHub Actions’ syntax is .yml-based, so let’s see what our deploy workflow will look like.

In the root directory of your app, create a file at .github/workflows/deploy.yml.

# .github/workflows/deploy.yml
name: Deploy to Cloud Run
on:
  push:
    branches:
      - main
env:
  PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
  RUN_REGION: us-east1
  SA_KEY_JSON: ${{ secrets.GCP_SA_KEY_JSON }}
jobs:
  deploy:
    name: Deploy to Cloud Run
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      # Setup gcloud CLI
      - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
        with:
          version: "290.0.1"
          service_account_key: ${{ secrets.GCP_SA_KEY_JSON }}
          project_id: ${{ secrets.GCP_PROJECT_ID }}

      # Build and push image to Google Container Registry
      - name: Build
        run: gcloud builds submit --tag gcr.io/$PROJECT_ID/$PROJECT_ID:$GITHUB_SHA

      - name: Deploy
        run: gcloud run deploy $PROJECT_ID --image gcr.io/$PROJECT_ID/$PROJECT_ID:$GITHUB_SHA --platform managed --region $RUN_REGION

Enter fullscreen mode Exit fullscreen mode

The Build and Deploy commands are pretty similar to those we just ran above, although there are a couple of differences. Let’s take a closer look at the build command.

gcloud builds submit --tag gcr.io/$PROJECT_ID/$PROJECT_ID:$GITHUB_SHA
Enter fullscreen mode Exit fullscreen mode
  • The dollar-sign syntax (eg, $PROJECT_ID) represents an environment variable. All of our env vars are set at the top of the file, except $GITHUB_SHA, which is a default environment variable referencing the current commit hash
  • gcr.io/$PROJECT_ID/$PROJECT_ID: My project name is also the same as my app name (hello-cr). If your "project" name is different from your app name, you will need to add a new variable.
  • :$GITHUB_SHA: Adding a colon and a string is a way of tagging containers so we can distinguish between versions. In this case, the git SHA is appended, so that we can identify the current version of the app by referencing our commit history.

Setting up app secrets

If Actions are enabled for your repo, pushing your new deploy.yml file will attempt a deployment but it will fail because we need to add the secrets for our service account. The secrets we need to add are referred to in the env: section near the top of the file.

env:
  PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
  RUN_REGION: us-east1
  SA_KEY_JSON: ${{ secrets.GCP_SA_KEY_JSON }}
Enter fullscreen mode Exit fullscreen mode

The RUN_REGION is hard-coded, but we have to create the other two secrets. Github’s documentation for creating secrets is actually really good: you can add them under "Settings" > "Secrets" > "New secret".

  1. GCP_PROJECT_ID: The project ID is just a string
  2. GCP_SA_KEY_JSON: For the service account key, copy the entire JSON file into the textarea. It seems a bit weird but it works just fine.

Secrets are encrypted as soon as they are created, and there’s no way to reveal the original values once saved, so if you are adding sensitive values in the future, make sure to add them as secrets rather than accidentally committing them to your repo.

Once you’ve created your secrets and committed your deploy.yml file, your next push to the main branch will trigger an automated deployment. It usually takes a few minutes to deploy a new version of your application (depending mostly on how long it takes to build your container).

pcraig3/hello-cr on GitHub

While writing this post, I created an example repository using Google’s Node.JS sample application and added my workflow file to it. It’s super simple, and might help you out if you need an tangible example of these concepts. Feel free to clone, fork, or raise an issue if you have any questions.

GitHub logo pcraig3 / hello-cr

demo autodeployments to Cloud Run

hello-cr

Overview

This repository is a reference implementation for using Github Actions to continuously deploy a Node.JS application.

The deployment configuration is described in .github/workflows/deploy.yml. Whenever the main branch is updated, it will:

  • log in to GCP as a service account
  • build and push a container, tagging it with the git SHA
  • deploy the container

The app itself is based on the sample application used in Google's "Build and Deploy" Quickstart for Cloud Run.

The repo is MIT-licensed, so you are free to use or modify it however you like.

All done!

You did it! Get yerself light lager and a pizza. 🍕

Discussion (1)

pic
Editor guide
Collapse
hanscl profile image
Hans Luther

Great tutorial, thanks Paul. One quick note: I had to add "--allow-unauthenticated" to the gcloud run deploy command to make the service available to the public. Otherwise, it worked perfectly. Thanks again!