

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!
How do you start the app with chef?
LikeLike