App Engine gotchas For Rubyists

This is part of the GCP Ruby Updates 2019 series.

It has been a while since I wrote about App Engine and Ruby. Honestly, there wasn’t a lot of news to share. It continued to work! But now Google has released App Engine Standard for Ruby. And that gives me a chance to address the common issues people reported during early testing.

Standard Environment vs Flexible Environment

Google Cloud Platform offers two versions of its Platform as a Service (PaaS) offering, Google App Engine. More details on the differences between the two are here. My general recommendation is to use Standard if you can. Standard offers several nice features like reduced deployment time and scale to zero. Most Rubyists looking for a PaaS probably want the elements in App Engine Standard Environment.

There are a couple of cases where App Engine Flexible makes more sense. First, if you already have a docker file App Engine Flex (or Cloud Run when it is GA) is probably a better choice. Also, if your load is very steady, predictable, or has long-running requests, App Engine Flex may be a better choice. Finally, if you need to write to disk beyond /tmp/ then you have to use Flex.

What is an app.yml?

If you read the App Engine documentation, you’ll see that you need an app.yml file. This is the configuration file that tells App Engine what runtime to use. A basic app.yml for a Rails project looks like this:

1
2
3
4
runtime: ruby25

env_variables:
  SECRET_KEY_BASE: [SECRET_KEY]

If you have additional environment variables, you can add them below SECRET_KEY_BASE. You can also change the machine type used with the instance_class configuration. More information on the different instance classes is here.

How Do I Databases and Migrations?

Databases and specifically database migrations are one of the most common issues people have adopting App Engine. Google Cloud offers Cloud SQL as a managed database, and it works well with App Engine. If you want to skip ahead to the tutorial here’s the instructions for MySQL on Cloud SQL ad PostgresSQL on Cloud SQL. That tutorial mentions App Engine Flexible, but it is precisely the same for App Engine Standard. You need to create your databases using either the gcloud command-line tool or on the web at http://console.cloud.google.com.

Once you’ve created the database, you’ll need to update the database configuration for your Rails app. You can get the database connection information from the gcloud command-line utility by running gcloud SQL instances describe rails-cloudsql-instance | grep connectionName. A database.yml for your app will look something like this

1
2
3
4
5
production:
  username: "[YOUR_MYSQL_USERNAME]"
  password: "[YOUR_MYSQL_PASSWORD]"
  database: "[YOUR_DATABASE_NAME]"
  socket:   "/cloudsql/[YOUR_INSTANCE_CONNECTION_NAME]"

To use a cloud database from your local environment, you’ll need to install the Cloud SQL Proxy. But, many people use a local database for development and testing, and that works fine.

To configure your production database, you’ll need to add the App Engine gem to your project. This gem provides a rake appengine:exec command-line utility that you can use to run things like bundle exec rake db:create or bundle exec rake db:create. You will probably need to specify the environment so creating, migrating, and seeding your databases would look like this RAILS_ENV=production bundle exec rake appengine:exec -- bundle exec rake db:create db:migrate db:seeds.

The appengine gem also makes it easy to include Stackdriver Logging and Error Reporting. But, debugging and monitoring Rails applications running on App Engine deserves a more extended, dedicated, blog post.

How do I Store Files?

I’ve verified that storing images with paperclip and Google Cloud Storage works, including resizing images using ImageMagick. I’m using the paperclip- and paperclip-gcs gems in my project with completely standard configuration following the paperclip-gcs instructions here. The only issues I had were configuring the bucket permissions correctly for my use case. Since every use case will vary and the gem documentation is excellent, I’m not going to go into configuring GCS here.