Have you ever setup a Rails production environment from scratch, by hand? If you had, I share your pain every time when a new project started.
The process is often repetitive. To me, it seems to be a waste to do it manually every time. It also consumes time and attention. It would be great if I could spend them on tasks that bring more values to clients.
To minimize such waste, I have written two Chef cookbooks to automate the process:
- rackbox - to provision rack-based web server (Nginx as front server, Unicorn and Passenger as upstream app servers,
rbenvas ruby version manager). - databox - to provision database server (supports MySQL and PostgreSQL).
Getting started
In this post, I will show you a step-by-step guide on how to use the
cookbooks together with
knife-solo to provision a
remote server in 4 steps:
- setup Chef Solo environment
- modify config file
- provision remote server
- tweak Capistrano
deploy.rb
A working example in also available at teohm/kitchen-example.
1. Setup Chef Solo environment
- Install Chef Solo tools on local machine.
- Download Chef cookbooks to local machine.
- Install
chef-soloon remote server.
Install Chef Solo tools
Let’s create a new directory,
1 2 | |
and a Gemfile.
1 2 3 4 | |
I recommend knife-solo >= 0.3 as it includes a few major fixes and
improvements.
Now, install the ruby gems.
1
| |
Finally, setup a kitchen directory structure with knife-solo.
1
| |
Download Chef cookbooks
I use Berkshelf to manage cookbooks. So we need a Berksfile,
1 2 3 4 5 | |
(I added a hack here to force berkshelf to use runit 1.1.2 required
by rackbox. Still looking for a better solution.)
We can now download cookbooks with berks install.
1
| |
Install chef-solo on remote server
1
| |
In this example, testbox is a host I setup in my ~/.ssh/config:
1 2 3 4 | |
2. Customize config file
- Download config example
- Customize config file
Download config example
1
| |
Modify config file (JSON)
The config file starts with a run_list. You specify a list of cookbook
recipes here. Chef will run them in the same order in this list.
It is followed by cookbook attributes. You can modify these attributes. A full reference of attributes are described in each cookbook’s README (see appbox, databox, rackbox).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
3. Provision remote server
1
| |
It uploads the kitchen directory and runs chef-solo on the remote
server. Chef-solo will then takeover and execute the run list to setup
everything.
What do we get at this point?
Basically, it’s done!
We have a full-stack, rack-based server with:
- 3 user accounts (deploy, devops, apps)
rbenvas ruby version managernginxas front-serverunicorn,passenger-standaloneas upstream app servers, managed byrunitpostgresql,mysqlinstalled and databases created- all apps will be stored in
/home/apps/
4. Tweak Capistrano deploy.rb
Now, it’s ready to deploy a Rack-based app to the remote server!
I have two example Rails apps available on Github:
- teohm/sample-app1 runs on unicorn,
- teohm/sample-app2 runs on passenger-standalone.
There are a few minor tweaks required in Capistrano deploy.rb, as listed below.
I will explain the tweaks in details next time. Meanwhile, check out the complete working examples at: app1/config/deploy.rb and app2/config/deploy.rb
Login as deploy user
1
| |
Deploy to /home/apps
1
| |
Load rbenv in Capistrano
1
| |
Run bundler with --binstubs
1 2 3 | |
Restart app with runit sv
1 2 3 4 5 6 7 8 9 10 11 | |
Feedback
If you are interested on using the cookbooks, or have an idea/feedback/question about this topic, feel free to drop me (@teohm) a message. Pull requests and issue reports are definitely welcomed!


