Jacob Wood

Deploy Rails Applications on Google Cloud with Cloud Run

Tutorial Overview

You can deploy your Rails application on Google Cloud Platform.

I'll show you how to do it using Google's serverless compute solution called Cloud Run.

This tutorial is less about the Rails application (a basic photo album of cat pictures) and more about the process of deploying it on Google Cloud.

We'll be using this Architecture and running the following Google Cloud services to deploy a containerized Rails Web Application:

Google Cloud Project's Architecture

If you're more interested in learning how to build a Rails application, I'd recommend using this excellent Blog tutorial.

Rails Blog Tutorial


Start Google Cloud Project

If you can, sign-up for the 90 day $300 credits free trial to reduce the risk of incurring Google Cloud Platform charges from running Cloud services.

Free Trial

Login to the Google Cloud Console:

Access Console

Create a Project, which creates an ID to track costs against.

Google Cloud Console - Projects

Head to Billing. Check the sidebar on the left, click budgets and alerts.

Select your new Project and create a simple budget with alerts to prevent excessive spending.

Google Cloud Console - Budgets and Alerts

Both of these steps are optional but can help you to prevent unexpected bills.


Enable APIs & Install Rails App

With those guard rails in place, select your new Project and type in API library.

Google Cloud Console - API Library

Search for and enable the following APIs that we'll be using in our Project:

  1. Cloud Run
  2. Cloud SQL Admin
  3. Cloud Build
  4. Secret Manager
  5. Compute Engine

With our APIs enabled, now click on the terminal icon at the top of the console to enter cloud shell.

Google Cloud Console - Shell

In the console, you'll be writing bash and gcloud commands.

Clone the respository containing our Rails app sample created by Google:

    git clone https://github.com/GoogleCloudPlatform/ruby-docs-samples.git

Navigate to the rails app:

    cd ruby-docs-samples
    cd run
    cd rails

And run:

    bundle install

Google Cloud Console - Install Rails


Setup Cloud SQL for PostgreSQL Database

We're now going to setup our database, Cloud SQL for PostgreSQL because Rails supports relational databases.

First lets create reusable variables to save us time in the shell:

    INSTANCE_NAME=matz
    DATBASE_NAME=dhh
    Region=us-west1
    DB_USERNAME=wooyakob

With those variables, we'll run a gcloud command to create our instance:

    gcloud sql instances create $INSTANCE_NAME \
      --database-version POSTGRES_12 \
      --tier db-g1-small \
      --region $REGION

We'll then create our database in the instance:

    gcloud sql databases create $DATABASE_NAME \
      --instance $INSTANCE_NAME

We then need to setup our username and password for a database user:

Generate a random password and save it to a file called "dbpassword" by running:

    cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n1 > dbpassword

Run gcloud command to create our user and set the password to be the contents of our created file:

    gcloud sql users create $DB_USERNAME \
      --instance=$INSTANCE_NAME --password=$(cat dbpassword)

Google Cloud Console - Cloud SQL


Create Cloud Storage Bucket

Lets create our cloud storage bucket that can store our user uploaded cat pictures:

Set variable:

    BUCKET_NAME=cat-photos-album

Run command:

    gsutil mb -l us-west1 gs://$BUCKET_NAME

Google Cloud Console - Cloud Storage

Set image persmissions to readable so they're publicly accessible:

    gsutil iam ch allUsers:objectViewer gs://$BUCKET_NAME

Access Credentials Securely

We need to ensure our Rails app and Google Cloud services are accessing credentials securely.

For that we'll use Rails credentials and secret manager.

In the console, open up the nano editor:

    EDITOR="nano" bin/rails credentials:edit

Add this to the end of the file:

    gcp:
      db_password: REPLACE_WITH_DB_PASSWORD

Click the plus icon to run another shell. Route back to your Rails app:

    cd ruby-docs-samples
    cd run
    cd rails

Then fetch your created database password:

    cat ~/ruby-docs-samples/run/rails/dbpassword

Move back to your previous shell with the Nano editor opened and add in your Database password.

Google Cloud Console - Nano

Exit and save the edited file.

Create a new secret:

    gcloud secrets create rails_secret --data-file config/master.key

Get value of project number:

    PROJECT_NUMBER=$(gcloud projects describe $DEVSHELL_PROJECT_ID --format='value(projectNumber)')

Grant access to the secret to your Cloud Run service account:

    gcloud secrets add-iam-policy-binding rails_secret \
      --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
      --role roles/secretmanager.secretAccessor

And to your Cloud Build service account:

    gcloud secrets add-iam-policy-binding rails_secret \
      --member serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
      --role roles/secretmanager.secretAccessor

With secure access to our secret information in place, its time to connect our Rails app to Cloud SQL and Storage.


Connect Rails App to Cloud SQL and Storage

Run:

    cat .env

Then:

    cat << EOF > .env
    PRODUCTION_DB_NAME: $DATABASE_NAME
    PRODUCTION_DB_USERNAME: $DB_USERNAME
    CLOUD_SQL_CONNECTION_NAME: $DEVSHELL_PROJECT_ID:$REGION:$INSTANCE_NAME
    GOOGLE_PROJECT_ID: $DEVSHELL_PROJECT_ID
    STORAGE_BUCKET_NAME: $BUCKET_NAME
    EOF

This will supply the information needed from the services we gave secret access to.

Then ensure Cloud Build can access Cloud SQL:

    gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID \
        --member serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
        --role roles/cloudsql.client

Deploy Rails Application to Cloud Run

OK, now its time to deploy our Rails app to Cloud Run.

Get the Ruby image in the Dockerfile to use the same version of Ruby used by Cloud Shell:

    RUBY_VERSION=$(ruby -v | cut -d ' ' -f2 | cut -c1-3)
    sed -i "/FROM/c\FROM ruby:$RUBY_VERSION-buster" Dockerfile

Then use our cloudbuild.yaml file to build the image and run the database migrations:

    APP_NAME=catphotosapp
    gcloud builds submit --config cloudbuild.yaml \
        --substitutions _SERVICE_NAME=$APP_NAME,_INSTANCE_NAME=$INSTANCE_NAME,_REGION=$REGION,_SECRET_NAME=rails_secret --timeout=20m

If it doesn't build in time, increase timeout in the build command above to --timeout=2000s.

Google Cloud Console - Cloud Build

When the build is complete, deploy the Cloud Run service, setting the region, image and connected Cloud SQL instance:

    gcloud run deploy $APP_NAME \
        --platform managed \
        --region $REGION \
        --image gcr.io/$DEVSHELL_PROJECT_ID/$APP_NAME \
        --add-cloudsql-instances $DEVSHELL_PROJECT_ID:$REGION:$INSTANCE_NAME \
        --allow-unauthenticated \
        --max-instances=3

Google Cloud Console - Cloud Build

Voila, following a successful deployment head to the URL provided in cloud shell and check out your photo album!

Google Cloud Console - Cloud Build

Now its time to add some photos of cats:

Google Cloud Console - Cloud Build

And click into your uploaded photos to see more details:

Google Cloud Console - Cloud Build

Congratulations, You Made It!

You'll likely notice that the destroy functionality isn't working but I didn't write the Rails code and this tutorial isn't about the Application but the deployment process.

Please don't forget to delete the project to prevent you from incurring additional charges.

If you're interested in Ruby and Rails applications on Google Cloud Platform, I recommend checking out the following resources:

That's it, any questions on Web Applications, Google Cloud deployment options, Compute solutions or using any of the Google Cloud services used in this tutorial, please email me at jacob@briotech.com.