Multi Region with Google Cloud Run - Part 1
By: Rob Charlwood
Tags: Docker, Google Cloud Platform, Google Cloud Run, Load Balancing, Golang

Docker it to me baby

Now, let’s get our app into a nice Docker image that is easily deployable to Cloud Run via Google’s container registry. Create a Dockerfile in the same directory as your code with the following contents:

This is a multi-stage docker build where we first extend the golang ( golang:1.14.4 ) image in order to compile and build our final binary. The second stage sees us create a slim Alpine linux ( alpine:3.12.0 ) image and copy our final binary in from the first stage into its final production directory.

Particular things of note here:

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o hello .

This line builds our final binary for Linux operating systems running AMD 64 bit architecture. The -w and -s flags omit the symbol and DWARF tables and debug information during compilation. These items are only used in debuggers and since this is a production image, there is no need to include all that extra bloat. It’s also worth noting that this does not remove data required for stack traces, so our panics will still be readable. Awesome.

The Dockerfile also ensures that the final go application is run by a non-root user to tighten security and prevent potential privilege escalation vulnerabilities.

Create a service account

Now we have a final image built, we need to upload it to Google’s container registry. To do that, we’ll need a service account with the correct permissions to perform the upload.

Login to Google Cloud Platform and add a service account for terraform . This service account will be used now to upload our image to the registry but it will also be used in part 2 to provision our infrastructure with terraform.

Create a service account for terraform

Now that you have a service account, go back into the account and generate a JSON key that we can use to authenticate to our project from our local machines or from a CI/CD process (which I highly recommend).

Make sure you download the key and store it somewhere safe. Do not store this key in your Git repository! I suggest that you either add it to a .keys directory and then add .keys to your .gitignore file, or store the key outside the root of your repository. If this key is ever leaked, you’ll need to revoke it immediately and generate a new key. Side note — you should be revoking and rotating your access keys on a regular basis anyway.

Generate and download a JSON key for the terraform service account

Next we need to add our new service account as an IAM user and furnish it with the permissions shown in the image below.

Adding IAM permissions to terraform service account

These permissions will give our terraform service account privilege to access all the required resources on our project.

The only permissions that are required for this part of the tutorial is Storage Admin, however you might want to add them all now to avoid forgetting to do it later.

Compute Instance Admin (beta) Compute Load Balancer Admin Compute Network Admin DNS Administrator Security Admin Create Service Accounts Delete Service Accounts Service Account Key Admin Service Account User Cloud Run Admin Service Usage Admin Storage Admin

Important Note The permissions granted above have not been scrutinised sufficiently to be used in production. It is strongly advised that you lock down all service accounts to only the bare essential permissions required for the use case of that service account. Terraform by its very nature needs quite sensitive permissions. However, I still suggest that you double check and review the permissions specified above should you decide that you’d like to do something more serious with the project.

Setup container registry and upload image

First up, you’ll need to turn on container registry’s API. To do this, login to Google Cloud Platform console and go to APIs and Services and then to Library. Once in the library search for and enable the Google Container Registry API. This will enable the registry for your project and will allow you to create, push and pull images.

Turn on the Google Container Registry API

It’s recommended that you turn on vulnerability scanning in Google Container Registry. It’s built into GCR and will monitor your Debian, Alpine, CentOS, RedHat and Ubuntu based images for vulnerabilities anytime you push to your repository. At the time of writing, vulnerability scanning is 100% free or partially free until January 2021.

Enable vulnerability scanning

Once this is done, we can write a little Makefile to handle the build and upload. Obviously you’ll need to replace the project and image names with your own values. You’ll also need to ensure that you update the script to point to the key file that you downloaded in the previous step. Depending on your region, you might also want to change the container registry to one nearer to your location — eu.gcr is Europe.

You can now build and upload your image to container registry by running the below command

make build

Or if you’d like to build a specific version, you can pass the version argument in to the command:

make build version=0.1.0

Make a note of the version of your final pushed image as you’ll need that in part 2 to provision and run our new cloud run instances.

Let’s wrap it up!

In this part we wrote a simple API service in golang and created a Dockerfile to build and compile the final binary and run it under a slim, secure Alpine image. We then created a service account for provisioning all of our infrastructure and used that account to upload the final image to Google’s container registry ready for running.

Join me again in part 2, where we’ll start provisioning our required infrastructure with terraform. See you there! :)