Home

Awesome

Ruby on Rails on Cloud Run!

This repo was originally made as a workshop for a conference in Perth in 2020, Latency Conf.

What's in this repository

How to use

1. Create a Google Cloud Project

2. Copy the example code from this repository

You have two options for this section, you can either use your own machine, or if you prefer, you can use the cloud-shell which is provided by GCP in-browser. If you want to use your own machine, you'll need the Google Cloud CLI and Docker installed.

Latency Attendees: Please use cloud shell as bandwidth may be limited in the workshop space.

If you prefer to use cloud shell, click the terminal icon at the top right of any Google Cloud console webpage. It looks like this: >_ surrounded by a white square.

Successfully built 16587984de73
Successfully tagged my_app:latest

3. Push and deploy the example server

Once you've build the image, it's time to store it in GCR (Google Container Repository).

jgunnink@cloudshell:~/latency-container-workshop$ gcloud projects list
PROJECT_ID          NAME               PROJECT_NUMBER
containerworkshop   ContainerWorkshop  123456789101
jgunnink@cloudshell:~/latency-container-workshop$ PROJECT_ID=containerworkshop
jgunnink@cloudshell:~/latency-container-workshop$ echo $PROJECT_ID
containerworkshop

4. Deploy to Cloud Run

In the console, we'll deploy the application for the first time before we move on to automated deployments.

After a short time, the service will be deployed and serving traffic at the url provided. The first time the container starts, it will be a little slower than subsequent starts.

Your URL will look something like: https://container-workshop-f4hgxdldqa-ts.a.run.app which you can visit and see your deployed container running serverlessly in production.


It's now time for the morning tea break

If you're here well before the 10:30 break, you're free to continue with the workshop, think about your entry to the competition, or help a nearby person who looks like they need it!


Now that we're back from morning tea, the fun resumes! Automating deployments and testing traffic splitting. With git!

5. Connect Cloudbuild

In Github, navigate to https://github.com/marketplace and type "google" into the search box. In the results, look for "Google Cloud Build" and add it to your account. You'll be taken to the console to authorise the application for use with your Google account.

Then back in Github, go to configure your installation. If you're lost, you can continue from here: https://github.com/settings/installations. Next to Google Cloud Build, click the configure button and under the "Repository Access" section either add "All repositories" or select repos and choose the fork you've made of the "latency-container-workshop" and add the repo by clicking save.

You'll be taken to google cloud to confirm the link. You'll select the project, then the repo to link to that project.

Finally you can configure the trigger settings. Here you would set when you wanted cloudbuild to fire. Click next to save the default for now, you can change it later.

6. Permissions for Cloudbuild

In order for cloudbuild to deploy and manage our cloudrun containers, we need to give it permission to do so. Let's get some more project information into our environment variables.

jgunnink@cloudshell:~/latency-container-workshop$ gcloud projects list
PROJECT_ID          NAME               PROJECT_NUMBER
containerworkshop   ContainerWorkshop  123456789101

Let's note again the PROJECT_ID and PROJECT_NUMBER, and store them for reuse later.

# Config
PROJECT_ID=containerworkshop
PROJECT_NUMBER=your-gcp-project-number

# Grant the Cloud Run Admin role to the Cloud Build service account
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \
  --role roles/run.admin

# Grant the IAM Service Account User role to the Cloud Build service account on the Cloud Run runtime service account
gcloud iam service-accounts add-iam-policy-binding \
  $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
  --member="serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \
  --role="roles/iam.serviceAccountUser"

It's worth noting that we've given Admin permissions to cloudbuild to manage our cloud run service. In practice, it's better to provide specific permissions that you intend cloudbuild to use.

7. The cloudbuild.yml file

In the root of this repository you'll see a cloudbuild.yml file. In it, there are some instructions which tell our cloudbuild instance how to build our application. Right now, it's configured to deploy a new version and then send all traffic (i.e. 100%) to the new version once the health checks are passing.

Let's change the command to deploy new versions of the container, but not send any traffic to them just yet.

In the cloudbuild.yml file look for the deployment step, and the argument to --no-traffic as seen here:

# Deploy to cloud run
- name: "gcr.io/cloud-builders/gcloud"
  args: [
      "run",
      "deploy",
      "$PROJECT_ID",
      "--image",
      "gcr.io/$PROJECT_ID/my_app:latest",
      "--no-traffic", # Add this line
      "--region",
      "australia-southeast1",
      "--platform",
      "managed",
    ]

To read more about how this works, check out the documentation here: https://cloud.google.com/sdk/gcloud/reference/run/deploy#--no-traffic

Setting this flag assigns any traffic assigned to the LATEST revision to the specific revision bound to LATEST before the deployment. The effect is that the revision being deployed will not receive traffic.

After a deployment with this flag the LATEST revision will not receive traffic on future deployments. To restore sending traffic to the LATEST revision by default, run the gcloud run services update-traffic command with --to-latest.

Now when we make a change to our code, cloudbuild will build the image, deploy it, but cloudrun won't send any traffic to it.

Let's change that.

# Switch 50% of all traffic over to the latest version.
- name: "gcr.io/cloud-builders/gcloud"
  args: [
      "run",
      "services",
      "update-traffic",
      "$PROJECT_ID",
      "--to-latest", # Delete this line
      "--to-revisions=LATEST=50", # Add this line
      "--region",
      "australia-southeast1",
      "--platform",
      "managed",
    ]

8. Make a small change

In the folders in the repo, navigate to the file at:

app > views > welcome > index.html.erb

Make a small change here, for example, change the text version 1 to version 2.

Let's save all files make a commit and push our changes to our repo.

In the cloudbuild console you'll see cloudbuild running! It will build and deploy your app with no traffic initially, then make a change to route 50% of the traffic over.

In the cloud run console you should see two versions of your application running. Test it by accessing the URL of your application and validating that version 1 and 2 show up! (Keep hitting refresh if you don't see it straight away.)

In the cloud run console you'll be able to manually adjust the percentage of traffic between versions, feel free to play around with it, if you like.

End

Congratulations, you've made it to the end of the workshop. If you've finished early, below you'll find some more tasks which you can try to extend what you've learned.

Bonus tasks

These tasks are designed to make you think about your learnings and extend them into creating a more robust service. One that can be used in workplaces and create good DevOps practices. They also show some of the power of the cloud and how you can control deployments using code, commits and controls.

  1. Completely automate the entire application we've created today using the services we've connected on GCP using infrastructure as code templates. Using Terraform or similar.

    Helpful links:

  2. Add some automation (by any means necessary) to promote a workload from 50% traffic to 100% traffic after the application is reporting zero errors after a given amount of time.

  3. Using the tools we've covered, setup some automated testing. Where will it be added in the flow of code to production? (note, to complete this exercise a script which exits with a code zero to prove the concept is fine)

  4. Configure your pipeline to only deploy when git tags are created in the master branch.

    Helpful Links:

  5. Observe the memory and CPU utilisation with the metrics provided.

    • Have we right-sized this application? How can you tell?
    • What happens to the performance of the application if we increase or decrease CPU or Memory?

    Understanding the metrics of our application can help ensure we have the capacity to serve customers quickly and also ensure we don't create services which cost extra unnecessarily. See what monitoring and observability you can setup for the application using native cloud tools to pro-actively monitor your application. Hint: take a look at Stackdriver

  6. Completed all the above in the workshop? Come find me for employment opportunities.