How to Deploy a Multi-Server Rails App using ElasticBox

In this tutorial, I am going to show you how to deploy a Ruby on Rails app which has a database and background processing hosted across three servers in the cloud using the Free Version of ElasticBox.

Why Use ElasticBox

Recently, I joined ElasticBox as a Solutions Architect because I love the promise that ElasticBox gives a Developer, an IT Ops or DevOps engineer. ElasticBox gives you the ability to define an application once and then retain workload mobility and scalability through ElasticBox’s modular, application definition concept, a “Box“.

Once you have defined your application in ElasticBox, each component is versionable which means that you can iterate  on components individually, rather that the entire application architecture. You can do all this while keeping your application provider agnostic so you can gauge which provider represents the best cost / performance ratio for your interests. We can make all this possible by using ElasticBox for server provisioning and server configuration.

Define Your Rails App

If you’ve made the decision to manage the hosting and deployment of a Rails app, a driving factor might be that you want to make your app more scalable – while simultaneously getting higher performance from cheaper hardware – by hosting the various components of your application on their own servers.

  • A work server which runs
    • a rails webserver
    • an arbitrary resque workers which reads jobs off a Redis server for background image processing
  • A database server running PostgreSQL to store relational data
  • A keyvalue store server running Redis storing instructions for the Resque workers

The code for this example is publicly stored in this Github Repo.

On a high level, we are going to provision and configure the PostgreSQL and Redis servers. And then provision and configure the Rails application server, clone the code, install dependency packages, update our config files to point to the outside servers, install our database on the database server, start the web server, and then start our workers.

Let’s get started! (Note: this tutorial assumes you already have an ElasticBox account. If you do not, you can get a free one here)

First, create a new box of service type “Linux Compute” in your ElasticBox account. I chose to upload the Rails logo to make it clear to me that this is a Rails app, but you don’t have to. You also have the option of setting descriptions and tags . The description shows up under the box’s name on the boxes page, so this is just meant to help you identify what your box does. Tags are primarily used for filtering, so you might wish to use descriptive tags, (like I did) to help you find your box. (You can learn more about boxes in the ElasticBox help documentation.)

After hitting “Save,” you’ll have the option of setting it to use the following variables:

  • A binding variable named postgres that accepts a PostgreSQL Database Service box
  • A binding variable named redis that accepts a Redis box
  • A box variable named packages that accepts a Package Installer box
  • A box variable named rails that accepts a Rails box

The binding variables are pointers to instances of boxes of the types you set them to be. We use them so we could dynamically refer to aspects of the servers they are on (like hostname, variables set on the boxes – usernames and passwords, in this case) in an abstract manner. The box variables are scripts that get installed as part of this box. In this demo, we are using a packages box, which is a utility box to install packages on your machine instance when you spin it up.

In the packages box, change the contents of ubuntu_install_packages.txt to contain the following:

imagemagick
libmagickcore-dev
libmagickwand-dev
#postgresql-devel
libpq-dev
ruby1.9.1-dev

Then, set the rails variables as follows:

  • CLONE_URL => https://github.com/ysiadf/elastic_box_demo
  • http => 3000
  • RAILS_APP => Whatever you want (I called it demo in my example)

You can leave the other variables set at their default values.

Now we get to edit script files.

In the post configure script, edit the file so it looks like this:

#!/bin/bash
#kill rails server
fuser -k 3000/tcp
#stop any resque workers
pkill -f resque
elasticbox config -i {{ rails.RAILS_APP }}/current/config/database.yml.template -o {{ rails.RAILS_APP }}/current/config/database.yml
elasticbox config -i {{ rails.RAILS_APP }}/current/config/resque.yml.template -o {{ rails.RAILS_APP }}/current/config/resque.yml
rake -f {{ rails.RAILS_APP }}/current/Rakefile db:setup RAILS_ENV=production

Notice those double-squiggly-brackets {{}} above. Those are how we reference variables in elastic box. (Learn more about ElasticBox variables.)

Also, notice those lines with the “elasticbox config” commands. The -i argument takes a path to an input file on the machine once it’s deployed, and the -o argument takes a path to an output file. We use this command to process files and replace their ElasticBox variables with their underlying values. So in this case, we use ElasticBox to dynamically set our config files with the hostname, ports, usernames, and passwords of our files across in a manner that we know will work across ANY cloud, without having to query to get the host names ourselves.

Here are the contents of the two template files we created in our Rails app to enable this. These are already checked in and included in the git repository you are cloning in the app, so you do not need to make any changes in this tutorial. Note that if you wanted to make your code completely independent from ElasticBox, you could also either: output these files using our bash scripts or save the contents of these files as file variables in our app, and the application will deploy just fine. I happened to decide to save the template files in my Rails app itself. It’s a matter of personal style.

And finally, include the following as your post_start script:

!/bin/bash
rake -f {{ rails.RAILS_APP }}/current/Rakefile resque:work QUEUE=* RAILS_ENV=production &

And that’s it for setting up the box.

Now to provision servers  and deploy the box you just created.

First, create an instance of a PostgreSQL box. (You can read about creating instances of a PostgreSQL box here.)

Then, create an instance of a Redis box. You can set the username and password variables to whatever you’d like and ElasticBox will pick them up when you start the Rails Demo app.

Now you can click on “New Instance” again to create a new instance of the Rails Demo box you just saved, set your deployment profile to spin up an Ubuntu box, select the PostgreSQL and Redis instances you just spun up, and watch the logs roll by.

To visit the web server you can click on endpoints to get the address of your Rails server.

Since we are using resque for monitoring, you can put “/resque” at the end of that to monitor your Resque workers. So in this case, that would be http://50.18.75.78:3000/resque

Annnnd, that’s it! Congratulations, you just used ElasticBox to set up a three-tiered Ruby on Rails box that uses CarrierWave to upload images, PostgreSQL, Redis as data stores, and Resque to process background jobs. The power of ElasticBox, is that now that you’ve set up this box, you can deploy to any cloud provider that spins up ubuntu servers. If you have any questions about this tutorial, please don’t hesitate to email me at ysiad@elasticbox.com.

Hacker News

Categories: Cool Features & Tutorials
Tags: , , ,
  • Santanu Chakraborty

    is package installer is missing in the current elasticbox?

  • Mrina N

    Hi Santanu, you guessed right. The package installer box in this walkthrough is not part of the Quick Starts catalog. One of our team members will share it with your dev edition account. I’ll notify you when it is shared. Thank you for trying the tutorial!

  • systemr

    Mind sharing the document with me please? The pictures are poor and cant seem to see them on any resolution