my work, life, and ideas

Infrastructure Automation with Chef

By now you’ve at least heard about Chef or perhaps you’ve thought about evaluating it. If you haven’t heard about Chef, no worries, let me explain. Chef is an open source infrastructure automation framework written in Ruby by the guys at OpsCode for developers. In my opinion, OpsCode has hit a grand slam home run on this one and I want to send them a thank you. So the big questions. Why Chef, why another framework, why should you be interested? It boils down to this, developer tooling and infrastructure automation is generally one of the most overlooked areas in software. Let’s be honest, developers never get the appropriate amount of time while working on a project to do this usually because management and stakeholders don’t understand the value it brings to a project. To the business it is totally intangible, or is it? You might have heard complaints about how they hate that it takes so long for a new developer to get setup and hit the ground running. Maybe you’ve gotten complaints about how long, unpredictable, or “manual” deployments have gotten. Perhaps you’ve been wondering how you could rapidly and consistently clone image clusters of servers. Chef makes this dead easy.

The Quick and Dirty

Chef has an organization structure of many cookbooks. Cookbooks are just folders for organization of a particular set of related recipes. Developers write recipes in a Ruby Chef DSL. You can write recipes to do just about anything. Directory creation, library installation, gem installation, file permissions, OS package management can be controlled via the Ruby DSL Chef provides. It gets better. There is probably a recipe or cookbook already written for what you want to do. There are a growing number of Chef cookbooks and recipes shared on Github. Want a Nginx and Passenger recipe? Already written. Want memcached installed? Already written.  You name it, chances are there is a recipe waiting for you. Instantly velocity! Now while this is all fine and dandy for most, recipe support across the various flavors of *nix is growing. Right now there is fantastic cookbook and recipe support if you’re running a Debian, Ubuntu, CentOS, or RedHat Linux. If you’re running another flavor of *nix, it is really easy to do whatever you want. Chef bends and flexes to your needs. Anything you can do with the Ruby language can be used to your advantage while writing a recipe. That reminds me, I’ve got a sweet CentOS recipe for Nginx installation that I have to contribute. Without rambling further you can get the most up to date information on the Chef wiki.

Common Uses

Writing a recipe for developer machine setup is a breeze and you actually can use the Chef gem that comes with the chef-solo command to kick off the recipe.

Are you still using some sucky deployment tool or script written a million years ago? Maybe you’re using Capistrano. Try out the Chef “deploy” resource. The Chef deploy resource by default encapsulates all of the best practices for Rails deployment, it doesn’t get simpler than this. Capistrano was an excellent tool for it’s time, you must try deployment on Chef. It makes rollbacks a snap also. Not using Rails or have some custom deployment requirements? The deploy resource is still awesome. You can pick and choose what you want and configure whatever customizations you need.

Take deployment and rollback even a step further with a tool like Hudson or TeamCity. Configure a job for them to run and wire up the Chef deployment script. The “easy button” deployment and rollback.

Chef combined with some server virtualization management tool you could easily image and setup a whole cluster of servers.

Still not convinced? Community adoption is growing fast and some of the most popular hosting companies in the Ruby sphere of influence are already using Chef. In fact, EngineYard uses Chef for application deployment on their cloud platform.

3 Responses Subscribe to comments


  1. Nathan L Smith

    * I emailed Nick to ask some questions about this article and he asked me to post it here *

    Hi,

    I just read your article
    http://techwhizbang.com/2010/04/cooking-with-chef/ , which was good,
    but I had a question and I thought you might be able to answer.

    In the article you’re talking about how easy it is to deploy with
    Chef. I’ve found this to be somewhat true, but the default deploy
    resource basically makes is so your “master” or whatever is deployed
    to the system whenever you run chef-client. So, if I’m running
    chef-client as a daemon and doing continuous deployment that’s cool,
    but I’m still not getting it for periodic deploys of a certain branch
    or for rolling back.

    I mean, a collegue asked me, “how do I deploy the app”, and I told
    him, “well, you don’t really deploy the app, you bring the node into a
    state of convergence.”, then he said, “What?”

    I’m deploying with the deploy resource and apps data bag, and I’m
    thinking of making a knife plugin where I can do `knife deploy
    production myapp` that sets an attribute for the action of the deploy
    resource or something, so I was wondering how you handle rolling back
    (as I understand it, the way the defaults work I have to edit a
    cookbook if I want to roll back, which is not cool.)

    Also, you said, “Take deployment and rollback even a step further with
    a tool like Hudson or TeamCity. Configure a job for them to run and
    wire up the Chef deployment script. The “easy button” deployment and
    rollback.” Could you explain how you do this?

    * He replied: *

    Hi Nathan,

    For some reason your name sounds familiar. Thanks for the inquiry and the complement. I think Chef is a good choice for deployment if you are already using it for automating your setups. It is probably way too much trouble in terms of setup and understanding for just the deploy resource. Although you could just use chef-solo to sidestep the complicated steps of maintaining and managing the full Chef server stack. I’m assuming you’re intending on using it to its fullest extent. I’ve used the deploy resource a couple different ways. The first way I used it was to create a recipe that does deploying/rollbacks for each target environment. Imagine a cookbook with the following recipes:

    — deploy_some_app_cookbook
    – development.rb
    – qa.rb
    – staging.rb
    – production.rb

    All of these recipes share the same code except for a couple things captured in attributes. The recipes have attributes for the target tag or branch and potentially if you’e deploying or rolling back:
    default[:deploy_apps][:vcs_branch_or_tag] = “Tag v0.0.1″
    default[:deploy_apps][:rollback] = false

    So when you use these recipes you can reference the attributes in the deploy resource. This way you aren’t always deploying master or trunk. Update the recipes and attributes across Chef accordingly as things for your project(s) change.

    Another approach is to use data bags. You can access data bags similarly in your recipes. By the way, the deploy resource is extensible to just about any application, not just Rails apps. I’ve molded it to deploy WAR files, background applications, and all types of services.

    You were concerned about rollback, but Chef does 2 types of deployments – timestamped or commit revisions. When you execute a rollback, Chef places a file on your server that keeps track of the last 10 or so deploys in the exact order they were performed along with all of the artifacts necessary to perform the rollback. So when you do a rollback you don’t have to worry about specifying a revision number, tag, or anything of that sort. Just “rollback” and Chef will automatically change the symlink it uses to point to the previous deploy.

    In terms of using Team City or Jenkins as an “easy button”. Both of the CI servers will take an arbitrary shell script, executable, rake task, maven task, ant task, or whatever else you can dream up. You would normally use the command line to do a deploy with Chef, so my suggestion was to make it one step easier. Create a job that will execute a shell script that wraps the Chef commands used for deployment and rollback.

    I think once you get Chef fully up and running and begin using it this will be easier and also become very clear. Hope this helps.

    Sep 05, 2011 @ 11:53 am


  2. Nathan L Smith

    I guess the thing I’m missing from Chef right now is I guess what I would call “on-demand” execution.

    With Capistrano I do “cap production deploy BRANCH=v20110903″ or whatever and that branch is deployed. With chef I have to set an attribute on a node or edit then upload a data bag, then run the chef-client.

    This is even more important for rolling back, since that’s usually a high-pressure situation, where “cap production deploy:rollback” instantly fixes it. I don’t want to be dicking around with JSON and having to upload stuff while my server is on fire.

    I guess it would be nice to be able to type a command like “knife deploy omfg its on fire roll back roll back!”

    I’m not trying to diss chef here, I use it a lot and I’m going to ditch cap for chef for deployments, but I need to come up with a solution for this (common?) use-case.

    Sep 05, 2011 @ 12:02 pm


  3. techwhizbang

    If you don’t want to mess with the Chef server to update all the nodes with chef-client? Use chef-solo.

    If don’t want to worry about editing JSON files and uploading those JSON files for chef-solo to use? I would consider exporting temporary environment variables during the execution of a remote SSH command and then referencing those in your deploy recipes. Anything you can do with Ruby you can do with Chef. So something like:

     
    deploy "/my/deploy/dir" do
      repo "git@github.com/whoami/project"
      revision "#{ENV['APP_REVISION']}" # Use the temp environment vars..
      user "deploy_ninja"
      enable_submodules true
      migrate true
      migration_command "rake db:migrate"
      environment "RAILS_ENV" => "production"
      shallow_clone true
      action "#{ENV['DEPLOY_OR_ROLLBACK']}"
      restart_command "touch tmp/restart.txt"
      scm_provider Chef::Provider::Git
    end

    If you desire to make it look and feel exactly like Capistrano then write a shell script or a Ruby script that takes the same “signature” and then pass those arguments along accordingly.

    A few parting thoughts. Chef isn’t for everyone, in fact, some might argue that automating your infrastructure is a separate concern from deployment. Deviating too far outside the pragmatic uses of Chef could just mean that it is not a good fit for your team. Don’t try to shoehorn something in because it is trendy or seemingly cool. Maybe Capistrano is exactly what you need…

    Sep 05, 2011 @ 12:56 pm

Reply