Chef is one of the leading DevOps tools that allows infrastructure to be defined by code. This allows "cookbooks" and "recipes" to be created that then can guarantee that your deployments are automated, repeatable, and invariant. Previously we set up a basic Chef environment; this consists of the Chef Server, the Chef Workstation, and a Chef Node.

To start with this tutorial you should have the basic Chef environment setup, as described here. You will also want to SSH into the Workstation and the Node.

In order to automate your deployments we need to accomplish the following:

  • Update knife.rb with additional configuration for cookbooks.
  • Create a cookbook and recipes, publish them to the Chef Server
  • Associate the cookbook with the Chef Node as part of the node "run list".
  • Execute the Chef client on the selected Chef Node

In order to get a good understanding of the basics we will start with a very simple Chef recipe. Once we have demonstrated the overall process we will move to a more complicated example involving several related and dependent recipes.

Updating knife.rb

In order for the system to work with the local Chef repo on the Workstation we need to tell it: a) where the cookbooks are to be located, and b) what editor we will be using to edit the "run lists". Login to the workstation and edit _~/.chef/knife.rb_. Add the following two lines:

cookbook_path '/root/chef-repo/cookbooks' knife[:editor] = "vi"

Your knife.rb file should look similar to:


The initial Chef cookbook and Node automation run.

Cookbooks are the fundamental unit of configuration and policy enforcement that Chef uses to bring a node to a specific state. Chef uses cookbooks to perform work and make sure things are as they should be on the node. Cookbooks are usually used to handle one specific service, application, or function, for instance, a cookbook can be created to use NTP to set and sync the node's time with a specific server. As we will see cookbooks can be much more complicated and built up from a series of base cookbooks. Think of cookbooks as packages and Chef as the package manager for configuring infrastructure.

The basic workflow is to create cookbooks on the Workstation and then upload them to the Chef server. From there, recipes and policies described within the cookbook can be assigned to nodes as part of the node's "run-list". A run-list is a sequential list of recipes and roles that are run on a node by chef-client in order to bring the node into compliance with the policy you set for it. In a nutshell, this is how the node machine infrastructure is configured via code in an automated fashion.

A word about recipes. A recipe is the main workhorse of the cookbook and are used to declare the state of different resources. A cookbook can contain more than one recipe, or depend on outside recipes. Chef resources describe a part of the system and its desired state. For instance, a resource could say "the package x should be installed". Another resource may say "the x service should be running". A recipe is a list related resources that tell Chef how the system should look when it implements the recipe; while running each resource is checked for compliance to the declared state. If the system matches, it moves on to the next resource, otherwise, it attempts to move the resource into the given state.

Let's get to our first simple cookbook. Since we are installing on an Ubuntu 12.04 server we normally will do a sudo apt-get update command to make sure the application repositories are up to date. We can do this with a simple Chef cookbook that we will call apt. Execute the following knife command (on the Workstation):

$ knife cookbook create apt

This will create a cookbook, called apt in the directory ~/chef-repo/cookbooks. Go to the apt cookbook directory, note all of the supporting directories and files have been setup for the cookbook. Find the recipes directory and cd into it. You should find only 1 file (default.rb), this is the file we will add our instructions to. Edit default.rb and add:

execute "apt-get update" do command "apt-get update" end

Your finished file should look like:


Upload your completed cookbook to the Chef Server:

$ cd
$ knife cookbook upload apt

Now we are ready to update the run list of the Chef Node. First, get the name of the node by executing:

$ knife node list

My node name is 'UC1CCCCCC-4401.local'; yours will vary by what you named the Chef Node server when you created it. Edit the node run list by running the following (substitute your node name):

$ knife node edit UC1CCCCCC-4401.local

We are going to add "recipe[apt]" to the run list, the resulting file should look like:


Finally, we can SSH into the Chef Node and run the chef-client program. This will initiate a "Chef run" which fetches the run-list and executes the cookbooks specified (in our case it should run sudo apt-get update).

On the Chef Node run:

$ sudo chef-client

You should see that the apt cookbook runs and executes apt-get update.


A more complicated example

We have now shown that we can complete the entire Chef workflow; from creating cookbooks and recipes, to uploading them to the server, to executing them in an automated fashion on the target node. Our example was a simple apt-get instruction... However there are experts in the community that have deep knowledge of the apt package manager and have actually codified this into Chef cookbooks. Like all good programmers we are lazy and prefer not to re-invent the wheel, so our next example will show how to get and utilize pre-build cookbooks for common actions.

If you go to the Chef Supermarket and search for "apt" you will find the following cookbook:


First, download and install the remote cookbook:

$ knife cookbook site install apt

And following the workflow above to upload the cookbook and then run the chef-client on the Chef Node. You will note that there are 8 resources being updated this time (opposed to the single one we had previously).


The Finale: Installing Wordpress via a Chef Cookbook on the CenturyLink Cloud

Now that we have demonstrated how to work the end-to-end process let's install a significant application. By now you should have a sense of how easy this will be :). The application will be Wordpress, this is a significant PHP application and has 30 cookbook dependencies.

Download and install Wordpress:

$ knife cookbook site install wordpress

Upload the Wordpress cookbook to the server (the "-a" option says to upload "all" cookbooks):

$ knife cookbook upload -a

Edit the run list for your Chef Node and add a line for Wordpress. Note we will leave the apt cookbook in place:

$ knife node edit UC1CCCCCC-4401.local


And then on the Chef Node run:

$ sudo chef-client

Point your browser at the public IP for the Chef Node and you should see the Wordpress configuration screen:



We now have a repeatable DevOps setup (using Chef) in the CenturyLink Cloud. In order to create the next Wordpress site (or the next 10) you simply need to install a server, deploy the chef-client, and create a run-list for the node that includes the Wordpress cookbook. If the base Wordpress code (or any of the 30 dependencies) changes you will update the Chef Server and simply re-run the chef-client on each Chef Node for seamless and trouble-free deployments.