Making Recipes

Thursday, November 21, 2013, at 06:37PM

By Eric Richardson

Chef Cookbook for
Eric Richardson

Screenshot of a Chef cookbook used to build, showing a recipe that creates the directory structure for the site and installs its configuration into the nginx web server.

I brought this site out of mothballs last month by bemoaning how easy it was to fall behind on the things that we do for a living. I'm proud to say that I took my admonition to heart, and today this site is running on a newly spun-up virtual machine that is 100% built via automation.

I'm using Chef for configuration management, since that's what I use day-to-day at Emcien. My little one-server deployment gave me an excuse to try out their hosted product, as compared to the open-source server we're running.

A handful of off-the-shelf recipes do the initial setup:

  • hostname: Set the server's host name based on the node name and the "" domain.
  • users::sysadmins: Create my user account from information in a data bag.
  • sudo: Grant sudo rights to the proper user groups.
  • ntp: Make sure we're running the NTP daemon to sync the server clock.
  • nodejs: Install NodeJS from packages.
  • redis::server: Install Redis server.
  • percona::server: Install the Percona MySQL server.

After that, a few of my own cookbooks take over.

  • I put together a quick nginx_passenger cookbook to deploy NGINX and Phusion Passenger via the .deb packages that Phusion recently started building.

  • A lifeguard cookbook installs the lifeguard process runner that I wrote for Emcien. A lifeguard_service resource then offers a quick way to install new services that will restart via the Capistrano-friendly touch tmp/restart.txt.

  • The cleverly-named ewr cookbook ties the two together, illustrating how this site gets configured:

include_recipe "nginx_passenger"

# -- Pre-reqs -- #

package "imagemagick"
package "libimage-exiftool-perl"

Run the nginx_passenger::default recipe, then install two packages the site needs to run.

# -- Create a User and Directory -- #

ewr_app "ewr" do
  action      :create
  with_cap    true
  ruby        "1.9.1"

dir = "#{node.ewr.app_path}/ewr"

Use a little app resource to create a user and home directory, install Ruby 1.9.3 (1.9.1 is the ABI version, which packages still use) and set our environment.

# -- Make asset_images directory -- #

directory "/data/ewr/asset_images" do
  action    :create
  owner     "ewr"
  recursive true

Create the directory that we need for storing images.

# -- Install the Site File -- #

nginx_passenger_site "ewr" do
  action      :install
  dir         "#{dir}/current"
  server      ""
  ruby        "/usr/bin/ruby1.9.1"
  rails_env   "production"

Create an NGINX site configuration file pointing to the server we created.

# -- Install Lifeguard and Tasks -- #

lifeguard_service " Resque Pool" do
  action  [:enable,:start]
  command "bundle exec resque-pool"
  user    "ewr"
  dir     "#{dir}/current"
  service "ewr-resque"
  path    "#{dir}/bin"

Install a Lifeguard-managed Resque Pool instance, used for processing images.

The resulting code may not be useful to anyone else, but at least I don't have to be embarrassed when I log on to my own server.