Using Chef to provision a Rails and Postgres server
This is a brief overview of how to use chef to automate the provisioning of a server for a Ruby on Rails application. Sample code is provided as a starting point at https://github.com/TalkingQuickly/rails-server-template
2021 Update: a revised version of this tutorial is available here
Our Requirements
- Once setup, provisioning a new server should require just a few simple commands
- It should be platform agnostic, any VPS provider will do
- It should be easy to understand what’s happening, no “magic”
- Once setup the server should take care of itself as much as possible and alert us if anything goes wrong
Our stack
- Ruby 1.9.3+ (this can be selected)
- Postgres
- Redis
- Chef
Chef is a tool which allows us to define the commands to be run on a server using a ruby DSL. Commands are grouped into “recipes” which generally correspond to a piece of software to be installed. One or more recipes can be grouped into a cookbook, so for example a postgres cookbook could contain a recipe for a postgres client and another for a postgres server.
Data which varies from install to install – such as usernames, ports and paths – is defined in JSON files. Recipes and data can be grouped together in “roles,” for example a postgres-server role might combine a postgres recipe with a particular monitoring tool recipe and configuration.
Chef is capable of running on a central server and managing the propagation of recipes to multiple nodes. This is too complicated for the purposes of this single machine setup so we’ll be using the chef-solo gem (http://docs.opscode.com/chef_solo.html) along with the knife gem (http://docs.opscode.com/knife.html) to allow us to use cookbooks on the VPS directly from our workstation.
Finally we’ll be using berkshelf (http://berkshelf.com/) to manage our cookbooks and the dependencies between them, this can be thought of like bundler for chef cookbooks.
Steps
1) Install Tools
git clone [email protected]:TalkingQuickly/rails-server-template.git
The repository includes a Gemfile
so simply run bundle install
to install the required tools.
2) Define the server
First we need to define users, inside data_bags/users copy the file deploy.json.example to deploy.json.
Generate a password for your deploy user with the command:
openssl passwd -1 "plaintextpassword"
And update deploy.json accordingly. Also copy your SSH public key (cat ~/.ssh/id_rsa.pub) into the public keys array.
Finally you need to download all the cookbooks required for the individual server components:
mkdir cookbooks
bundle exec berks install --path ./cookbooks
3) Setup a VPS
This setup is designed to work on any Ubuntu 12.04 VPS, it has been tested on Linode, Rackspace and Digital Ocean. For initial experimentation I’d recommend Digital Ocean or for critical applications where support is key, Linode.
Once your VPS is up and running, copy your SSH key across:
ssh-copy-id root@yourserverip
4) Provision the server
Begin by installing chef on the remote machine:
bundle exec knife solo prepare root@yourserverip
This will generate a file nodes/yourserverip.json. Copy the contents of rails_postgres_redis to this file and change the username and password for monit.
Use the same command as before (openssl passwd -1 “plaintextpassword”) to generate a password for postgresql and add this to the node definition file.
Now run:
bundle exec knife solo cook root@yourserverip
Sit back, relax and enjoy. This process takes quite a while and once it’s completed, you’ve got a server ready for a Rails + Postgres + Redis app.
Next Steps
You can read more about using Capistrano to deploy to VPS configured with this method in this post
Any queries or corrections you can find me on twitter; @talkingquickly
Popular posts about deploying Rails apps
How to quickly provision a VPS for Rails using Chef
Deploying with Capistrano 3
Tailing log files with Capistrano 3
Using Vagrant to test Chef Cookbooks