How to Deploy Ruby on Rails With The Opscode Chef Application Cookbook

Creative Commons License Galileo55

I already wrote about how to get started with the Opscode Chef Platform. In this article I want to show you a very elegant way to deploy a Ruby on Rails stack with Chef. One of the strengths of Chef is the decent set of available cookbooks. @jtimberman does an especially excellent job in writing them. His chef cookbooks really help you to configure your systems neatly. One of his cookbooks is the Application cookbook. It enables data driven application deployment. Currently, it supports Ruby on Rails apps. The preferred stack is currently Matz Ruby with Unicorn, but, in a later post, I’ll show you how to use it cleanly with Ruby Enterprise Edition (REE).
Let’s get started!

Use The Chef Command Line Tool knife to Pull Down Required Cookbooks

First of all we need to get all required cookbooks on our local workstation. I assume your local box is setup to develop chef cookbooks. The preferred way to use existing cookbooks is to “vendor” them:

$ knife cookbook site vendor application -d

The -d parameter tells knife to pull all dependencies. The application cookbook will pull down quite a lot of deprecated dependencies like passenger_enterprise or passenger_apache2. Even if you want to install a unicorn based stack, those cookbooks will be downloaded (but never used). Just ignore them.

You may use the same command to pull a new version of any cookbook (no -d required then).

Configure Your Application Using a Data Bag

One of the great features of opscode chef is the support of data bags. A data bag is a JSON file containing any data structures (like configurations, etc) for your recipes to use. The Application cookbook makes heavy use of a data bag called apps.

First, we need to create a data bag file. Just name the data bag file like your application (in this example I use “my_app”):

$ mkdir data-bags
$ vi data-bags/my_app.json

Copy a sample data bag from application/README and change to your liking.

NOTE: Make sure your deploy key string is in one line with n</code as line breaks within:
"deploy_key": "-----BEGIN DSA PRIVATE KEY-----nMIIBv...EW1auXCaVnb24T...TiaHIn...n-----END DSA PRIVATE KEY-----n",

Now, it’s time to store your data bag on the chef server:

$ knife data bag create apps
$ knife data bag from file apps data-bags/my_app.json

Note the “apps” part before the actual file name. This is the name of the data bag and must be “apps” for the application cookbook to work correctly. You can load multiple application configurations into that same data bag (just use different JSON files).

Define Your Roles

You already put some role names into your data bag. Now, it’s time to create those roles to be able to assign them to nodes.

$ cd ./roles
$ vi my_app.rb
$ vi production.rb
$ vi my_app_database_master.rb

You might want to create a “staging” role as well to differentiate between your staging and your production environment by assigning the respective role to your nodes.

Here are samples for each role:

my_app.rb

	name "my_app"
	run_list "recipe[application]"

	override_attributes :apps => { 
	  :my_app => { 
	    :production => { 
	      :run_migrations => true,
	      :force => false
	    },
	    :staging => {
	      :run_migrations => true,
	      :force => true
	    } 
	  }
	}

Here we define that we want to run rake db:migrate on deployment and want to force git checkout on staging, but we do not want to force git checkout on production.

production.rb

name "production"
default_attributes :app_environment => "production"

For the initial upload of several cookbooks and roles there’s a handy rake task

$ rake install

Install MySQL as Database

Now, let’s add a database to the mix:

$ knife cookbook site vendor database -d

And, add the database::master recipe to the run_list of the “helpster_database_master” role

my_app_database_master.rb

name "helpster_database_master"
run_list "recipe[mysql::server]", "recipe[database::master]"	

Assigning Roles To Nodes

To simplify the example, we install the whole stack on a single node. Just assign the “production”, “my_app_database_master”, and “my_app” roles to your production server node:

$ knife node run_list add www.example.com "role[production]"
$ knife node run_list add www.example.com "role[my_app_database_master]"
$ knife node run_list add www.example.com "role[my_app]"

NOTE: The order in the run_list matters. Make sure you have database_master BEFORE your application role!!!

The application cookbook will install ruby, rails, all packages and gems defined in your data bag and unicorn as a runit service. Sweet!

NOTE: Your application log file is now under:

/etc/sv/my_app/log/main/current

Upload your role and cookbooks (using rake install) and run chef-client on your node!

2 thoughts on “How to Deploy Ruby on Rails With The Opscode Chef Application Cookbook

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.