In this codelab, you will learn how to deploy Refinery CMS to Google App Engine flexible environment. You will also learn how to use Google Cloud Shell and Google Cloud SDK.

Google App Engine Flexible environment applications are easy to create, easy to maintain, and easy to scale as your traffic and data storage changes. With App Engine, there are no servers to maintain. You simply upload your application and it's ready to go.

App Engine applications automatically scale based on incoming traffic. Load balancing, microservices, authorization, SQL and NoSQL databases, traffic splitting, logging, search, versioning, roll out and roll backs, and security scanning are all supported natively and are highly customizable.

What you'll learn

What you'll need

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would you rate your experience with Ruby?

Novice Intermediate Proficient

How would you rate your experience with using Google Cloud Platform services?

Novice Intermediate Proficient

Self-paced environment setup

If you don't already have a Google Account (Gmail or Google Apps), you must create one. Sign-in to Google Cloud Platform console (console.cloud.google.com) and create a new project:

Remember the project ID, a unique name across all Google Cloud projects (the name above has already been taken and will not work for you, sorry!). It will be referred to later in this codelab as PROJECT_ID.

Next, you'll need to enable billing in the Cloud Console in order to use Google Cloud resources.

Running through this codelab shouldn't cost you more than a few dollars, but it could be more if you decide to use more resources or if you leave them running (see "cleanup" section at the end of this document).

New users of Google Cloud Platform are eligible for a $300 free trial.

Start Cloud Shell

While Google Cloud can be operated remotely from your laptop, in this codelab you will be using Google Cloud Shell, a command line environment running in the Cloud.

Activate Google Cloud Shell

From the GCP Console click the Cloud Shell icon on the top right toolbar:

Then click "Start Cloud Shell":

It should only take a few moments to provision and connect to the environment:

This virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory, and runs on the Google Cloud, greatly enhancing network performance and authentication. Much, if not all, of your work in this lab can be done with simply a browser or your Google Chromebook.

Once connected to the cloud shell, you should see that you are already authenticated and that the project is already set to your PROJECT_ID.

Run the following command in the cloud shell to confirm that you are authenticated:

gcloud auth list

Command output

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Command output

[core]
project = <PROJECT_ID>

If it is not, you can set it with this command:

gcloud config set project <PROJECT_ID>

Command output

Updated property [core/project].

In this codelab, you will be using Runtime Configuration Service to store secret information later on in this tutorial, Cloud SQL for PostgreSQL as your managed PostgreSQL database service, and Cloud Container Builder used for database migrations and reading secret information at runtime in this codelab.

gcloud services enable runtimeconfig.googleapis.com
gcloud services enable sqladmin.googleapis.com
gcloud services enable cloudbuild.googleapis.com

In the Google Cloud Shell, you can install Rails version 5.1.6 and execjs gems which are used by Refinery CMS by using the following commands:

gem install rails -v 5.1.6
gem install execjs

Generate a new Refinery CMS project:

rails _5.1.6_ new refinery_cms_gae \
    --template=http://refinerycms.com/t/4.0.0

Move into the directory created by Rails for the application:

cd refinery_cms_gae

You can view the generated files for a new Rails applications by using:

ls

You should see something similar to:

Finally, set the environment variable GOOGLE_CLOUD_PROJECT to your project id.

export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)

Now that we have a Rails app, let's test it using the Web Preview functionality provided by the Cloud Shell environment. By default the Web Preview uses port 8080.

Start the Rails app server listening on port 8080:

bundle exec rails server --port 8080

Once the application starts, click on the Web Preview icon in the Cloud Shell toolbar and choose Preview on port 8080.

A tab in your browser opens and connects to the server you just started. You can read more about the Web Preview here. You should see the following image!

You can now stop the Rails server by using (Ctrl + c) in the Cloud Shell.

You will use Google Cloud Storage to host files and images for RefineryCMS.

Before configuring RefineryCMS, create a new bucket for named [YOUR-PROJECT-ID]-refinery-cms by using the following gsutil command:

gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-refinery-cms

This will make a globally unique bucket named [YOUR-PROJECT-ID]-refinery-cms.

RefineryCMS uses Dragonfly to interact with cloud data stores. To configure Dragonfly to use Google Cloud Storage we will set the custom backend configuration exposed by RefineryCMS to use a lightweight open source Dragonfly gem to use Google Cloud Storage.

bundle add dragonfly-google_data_store

Next update the file config/initializers/refinery/core.rb to the following:

# encoding: utf-8
require "dragonfly/google_data_store"
Refinery::Core.configure do |config|
  # Use a custom Dragonfly storage backend instead of the default
  # file system for storing resources and images
  config.dragonfly_custom_backend_class = "Dragonfly::GoogleDataStore"
  config.dragonfly_custom_backend_opts = {
   project: ENV["GOOGLE_CLOUD_PROJECT"],
   bucket:  "#{ENV['GOOGLE_CLOUD_PROJECT']}-refinery-cms"
  } 
  config.s3_backend = config.s3_access_key_id.present? ||  config.s3_secret_access_key.present?
end

RefineryCMS is now ready to use Google Cloud Storage to store files and images.

Cloud SQL for PostgreSQL is a fully managed database service that makes it easy to set up, maintain, manage, and administer your relational PostgreSQL databases in the cloud. That means you can use Cloud SQL in a Rails app like any other relational database.

In this section, you will set up a Cloud SQL for PostgreSQL instance for this codelab.

First, create a Second Generation instance. In this codelab the name for the instance is refinery-cloudsql-instance.

gcloud beta sql instances create refinery-cloudsql-instance \
    --database-version POSTGRES_9_6 \
    --cpu=1 --memory=3840MiB --region=us-central1

You should see the following:

NAME                       REGION      TIER      STATUS
refinery-cloudsql-instance us-central1 db-custom RUNNABLE

Next, create a new database in the new instance. In this codelab the name for the production database is refinery_database_production.

gcloud sql databases create refinery_database_production \
    --instance=refinery-cloudsql-instance

You should see the following:

Creating Cloud SQL database...done.                                                                                                                                                                              
Created database [cat_list_production].
instance: refinery-cloudsql-instance
name: refinery_database_production
Project: YOUR_PROJECT_ID

Finally, set a root user password for the instance.

gcloud sql users set-password postgres no-host \
    --instance=refinery-cloudsql-instance \
    --password=some-password

Now that you have a new CloudSQL for PostgreSQL database, you will configure the Refinery CMS database configuration to use this new database in production.

Let's update the Refinery CMS app to use Cloud SQL in production.

Add the gems pg, appengine, and dotenv-rails to the Gemfile file using the following Bundler commands:

bundle add pg
bundle add appengine 
bundle add dotenv-rails

bundle add will add the gem and run bundle install to update the Gemfile.lock.

Next, get the Instance Connection Name using the following command

gcloud sql instances describe refinery-cloudsql-instance | grep connectionName

The Instance Connection Name will be the name of a UNIX_SOCKET the app will use to connect to the CloudSQL instance refinery-cloudsql-instance.

Open config/database.yml and update the production environment settings to the following:

production:
  encoding: unicode
  adapter: postgresql
  pool: 5
  timeout: 5000
  username: "postgres"
  password: <%= ENV['DATABASE_PASSWORD'] %>
  database: "refinery_database_production"
  host:   "/cloudsql/[YOUR_INSTANCE_CONNECTION_NAME]"

Replace [YOUR_INSTANCE_CONNECTION_NAME] with your Cloud SQL Instance Connection Name.

Close and save the file. Next we will prepare the app for deployment to App Engine.

App Engine Flexible environment uses a file called app.yaml to describe an application's deployment configuration. If this file is not present, the gcloud tool will try to guess the deployment configuration. However, it is a good idea to provide this file because Rails requires a secret key in production.

A secret key is used to protect user session data. You can generate a secret key by using:

bundle exec bin/rails secret

Copy the secret key that's generated to your clipboard because you will use it in the next step.

To store the secret key, you will use the Runtime Configuration Service.

Create a new configuration named flex-env-config by using the following command:

gcloud beta runtime-config configs create flex-env-config

Next, add a variable for the SECRET_KEY_BASE environment variable:

gcloud beta runtime-config configs variables set \
  --config-name=flex-env-config --is-text \
  SECRET_KEY_BASE "[SECRET_KEY]"

Replace [SECRET_KEY] with the value generated from running bundle exec rails secret. When the app is deployed, the environment variable SECRET_KEY_BASE in production will be set to the secret key. The environment variable SECRET_KEY_BASE is used in config/secrets.yml.

Next, add variable for the DATABASE_PASSWORD environment variable:

gcloud beta runtime-config configs variables set \
  --config-name=flex-env-config --is-text \
  DATABASE_PASSWORD some-password

App Engine requires permission to load configurations from Runtime Configuration Service at build time.

Retrieve the project number by listing available projects by using the following command:

gcloud projects list --filter "name:$GOOGLE_CLOUD_PROJECT"

Copy your projects PROJECT NUMBER for the project you will use to deploy your app.

Use the PROJECT_NUMBER in the following command to add the a new member to your project IAM policy for the role roles/editor to run database migrations:

gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member=serviceAccount:[PROJECT_NUMBER]@cloudbuild.gserviceaccount.com \
--role=roles/editor

Create a new file called app.yaml using vim, nano, or emacs and add the following into the file:

# How to start your application
entrypoint: bundle exec rackup --port $PORT
# Use App Engine flexible environment
env: flex
# Use the supported Ruby runtime 
runtime: ruby

# App Engine flexible environment will load the configuration
# values from the Runtime Configuration Service defined by 
# flex-env-config and create a .env file used by your
# application to determine environment values.
runtime_config:
  dotenv_config: flex-env-config

# App Engine flexible environment will start a Cloud SQL Proxy
# to connect your database instance using the Instance Connection
# Name.
beta_settings:
  cloud_sql_instances: [YOUR_INSTANCE_CONNECTION_NAME]

Next you will deploy your app to App Engine which will be used for database migrations and finally as the default serving app.

First, you need to create an App Engine instance by using:

gcloud app create --region us-central

After this is enabled, you can deploy your app to App Engine by using:

gcloud app deploy

You will see the following error notice if you attempt to access your deployed application at this point, because database migrations haven't been executed. Continue onto the next step to learn how to run database migrations.

Rails database migrations are used to update the schema of your database without using SQL syntax directly. Next you will perform a database migration for your production database refinery_database_production.

The Appengine gem provides the Rake task appengine:exec to run a command against the most recent deployed version of your app in the production App Engine environment.

To run a database migration in production, invoke the following command:

bundle exec rake appengine:exec -- bundle exec rake db:migrate

This command migrates the production Cloud SQL for PostgreSQL database refinery_database_production. You should see a similar output to the following for a successful migration:

bundle exec rake db:migrate
== 20180328001950 CreateRefinerycmsResourcesSchema: migrating =================
-- adapter_name()
   -> 0.0000s
-- adapter_name()
   -> 0.0000s
-- create_table(:refinery_resources, {:id=>:integer})
   -> 0.0097s
== 20180328001950 CreateRefinerycmsResourcesSchema: migrated (0.0099s) ========

== 20180328001951 AddTranslatedTitleToRefineryResources: migrating ============
== 20180328001951 AddTranslatedTitleToRefineryResources: migrated (0.0344s) ===

== 20180328001952 CreateRefinerycmsPagesSchema: migrating =====================
-- adapter_name()
   -> 0.0000s
...Truncated due to length...

Next, you will need to seed the database using the following command:

bundle exec rake appengine:exec -- bundle exec rake db:seed

Finally, verify the database migration by browsing to:

[YOUR-PROJECT-ID].appspot.com

You can also use gcloud app browse. You will see the following for a successful deployment using Cloud SQL for PostgreSQL:

Add an image to the home page

Next, you will test image uploads by adding an image to the home page of your new RefineryCMS project.

First, you will need to create a new super-user by browsing to:

[YOUR-PROJECT-ID].appspot.com/refinery

You will see the following new user form:

After creating the new user you will be logged-in. Next, browse to:

[YOUR-PROJECT-ID].appspot.com

You will now see the following new options for the home page:

Click Edit this page to start editing this page. You will see the following editor:

Click the Add Image button to add a new image to this page. In case you don't have an image available you can use this cat image. Finally, click the Save button to update the homepage with your new image.

Now, browse to:

[YOUR-PROJECT-ID].appspot.com

You should now see your image on the home page. In case you used the cat image you may see the following depending on placement:

You learned how to deploy RefineryCMS to App Engine!

Clean up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this quickstart:

Learn More

License

This work is licensed under a Creative Commons Attribution 2.0 Generic License.