Chef Logo

Cooking With Chef

Dan Shultz • OverDrive, Inc


Who Am I

  • 8 Years Writing Web Applications
  • Teacher
  • Write Lots of JavaScript
  • ...and Ruby
  • ...and Python
  • ...occassionaly .NET
  • Server Jugler/Cloud Rider

Do You Server?

Things work in dev but not production?

Abusive by infrastructure team?

Infrastructure upgrades go like this?

Think the cloud will make things better?

to the cloud
Houston, we've got a problem
  • Developers Need to Create Environments
  • Configuration as Documentation
  • Infrastructure as Code
  • Reproducible and Predictible
  • Fast and Responsive


South Park Chef

System and Cloud Infrastructure Automation Framework

...that makes it easy to deploy servers and applications to any physical, virtual or cloud location, no matter the size of the infrastructure.

Why Chef


Recipe runs of the same configuration always produce the same resolution across systems and chef runs where nothing has changed, take no actions

Reasonable Run Ordering

Chef order is declarative and recipes are run in the order they are declared. Within a recipe, resources are applied in the order they are declared. There is no dependency management system. If you add a new cookbook/recipe at the end of your run list, the run order doesn't change

Easy Configuration/Sane Defaults

Generic Cookbooks work with little or no configuration. Attributes are easily changed and assigned


  • Resource
  • Recipe DSLs
  • Light Weight Resource Providers

Getting to Know Chef

Chef Architecture

Chef Server

  • Keeps track of your nodes
  • Serves cookbooks
  • Allows you to search across your nodes
  • Manages node data
Chef Architecture

Chef Client

  • Runs on your nodes
  • Communicates to Chef Server
  • Compiles and Executes Cookbooks
Chef Architecture

Chef Solo

  • Like chef client but...
  • Does not use chef server
  • Does not provide environments
  • It's up to you to get your cookbooks and data to the server


                % tree cookbooks/mycookbook
    ├── attributes
    ├── definitions
    ├── files
    │   └── default
    ├── libraries
    ├── metadata.rb
    ├── providers
    ├── recipes
    │   └── default.rb
    ├── resources
    └── templates
        └── default


Scripts to install/configure servers and define services

            	package node['nginx']['package_name']

template "nginx.conf" do
  path "#{node['nginx']['dir']}/nginx.conf"
  source "nginx.conf.erb"
  owner "root"
  group "root"
  mode 00644
  notifies :reload, 'service[nginx]'

service 'nginx' do
  supports :status => true, :restart => true, :reload => true
  action :enable



Configuration for recipes

              default['nginx']['version'] = "1.2.6"
default['nginx']['package_name'] = "nginx"
default['nginx']['dir'] = "/etc/nginx"
default['nginx']['log_dir'] = "/var/log/nginx"
default['nginx']['binary'] = "/usr/sbin/nginx"

The Tools

  • VirtualBox
  • Vagrant
  • Capistrano
  • Community Cookbooks
  • Berkshelf
  • Chef-Solo

Chef Server Need Not Apply

  • Keep Things Simple
  • One Less Dependency
  • Decentralized Server Management

Vagrant for Development

Development environments made easy.

Vagrant for Development

  • Create Local VMs
  • Test Deployments
  • Configured Similar to Production


  1. Visit Vagrant Website and download vagrant
  2. Install
  3. run `vagrant init`
  4. Update created Vagrantfile
  5. run `vagrant up`

Bootstrap With Capistrano


          	$ cap chef deploy:setup

Build on Community Cookbooks

Opscode Community

Cookbooks Are Basic

  • Data/Attribute Driven
  • Basic Case
  • Work out of the box

Create Wapper Cookbooks

  • Don't Fork and Modify Community Cookbooks for Concrete Usage
  • Cookbooks can be versioned, Roles Can't
  • Create App Specific Cookbooks

Rails App Wrapper Cookbook

              % tree rails_app/
├── attributes
├── definitions
├── libraries
├── metadata.rb
├── providers
├── recipes
│   ├── app.rb
│   ├── database.rb
│   ├── default.rb
│   └── web.rb
├── resources
└── templates
    └── default
            └── pg_hba.conf.erb

Example Recipe


# use a custom hba_config
hba_conf = resources("template[#{node['postgresql']['dir']}/pg_hba.conf]")

postgresql_connection_info = {
  :host => "localhost",
  :port => node['postgresql']['config']['port'],
  :username => 'postgres',
  :password => node['postgresql']['password']['postgres']

Berkshelf to Create Cookbook Scaffolding

            	$ berks cookbook rails_app

Berkshelf to Resolve Cookbook Dependencies


              site :opscode
cookbook('nginx', '~> 1.7.0')
cookbook('postgresql', '~> 3.0.2')
cookbook('rails_app', :path => './chef/cookbooks/rails_app')

Configure with Chef-Solo

Using Capistrano

              set(:chef_attributes) { File.join('/etc/chef', "attributes.json") }

find_servers.each { |server|
  json = JSON.pretty_generate(server.options[:chef_attributes])
  put(json, chef_attributes, :hosts =>
sudo("chef-solo -j #{chef_attributes}")


Configure with Chef-Solo

Using Capistrano

              $ cap chef deploy
Chef Logo

Thank you

Dan Shultz • OverDrive, Inc