Chef Quick-start

Russell Bateman
28 June 2013
last update:

(If the floating menu to the right overlays
too much of the content of this article,
widen your window or contact me.)

Introduction

Sometimes, people make something complex very complicated and put-offish indeed and perhaps not intentionally. Or, they suffer from a complex that makes them want to wear pointy black hats with moons and stars on them. Whatever the case, I found the Chef learning curve particularly steep and this is me flattening it albeit with a few caveats.

Caution: I'm not an experienced Chef expert. I'm not an expert at all; this is more an attempt at documenting willy-nilly the path of success I found while hacking my way through the forest. Here's a work that is more professional and might be better if longer: Getting Started with Chef

Chef tends to over-burden with the importance of Ruby and Gem. As you go, you'll understand why this happens, but it doesn't need to be at least at first.

My experience with Chef began a month or so before I wrote this. At work, I have a working if still emerging environment. At home, where I have a small VMware ESXi installation of my own to play with, I have a complete Chef 11.x set-up I play with. Beware: this article was written as I teetered between Chef versions 10 and 11. I have tried to note the differences.

Once you get up and going and want to write sophisticated cookbooks and recipes that do very sophisticated things, you'll really need to a) learn to write them using Ruby and JSON, and/or b) steal existing recipes (and there are a lot available). Your head will ache when you read the recipes you steal (b) until you become more or less capable of (a).

'Nuf said, let's get started. Here are the steps to a minimal, stand-alone VM set-up using Chef and a couple of cookbooks and recipes.

In an appendix at the end of this page (and in the floating index to the right here if it's working) is an even more concise list of steps of all that's going to happen here if you'd like a much higher view before getting started or any time during this tutorial.


Quickest steps to setting up and using Chef

  1. Set up a Chef server.

    There exists the ability to use a community set-up where Opscode hosts the server portion, but this isn't what I needed, so I'm not covering it here. There also exists something named Chef Solo—still not what I'm covering here. This is a real, if still no-cost, Chef server running on your hardware.

  2. Set up a Chef client node.

    This is the VM or other real hardware whose set-up is the very reason you want to learn Chef in the first place (grey in the adjoining illustration). Again, this is your hardware whether virtual or real.

  3. Choose and set up a development host for Chef administration.

    This is just a workstation. It could be Windows, Macintosh or Unix/Linux. My examples are on Linux Mint, so you'll need to understand shell commands and how to translate them to Windows if that's what you're running. It's from this host that you'll administer Chef and perform the vast majority of the steps.

  4. Set up a user and client, a role and a cookbook/recipe.

    This happens on the development host and is probably what you came to this page for in the first place.


1. Setting up the Chef server

In the very recent past (May 2013), this has gotten easier. It is two downloads. It's supposed that disparate versions of Chef can be mixed. (I run a 10.x server with 11.x client nodes.)

  1. Ensure the VM, host or computer you're using as a Chef server is running NTP.
  2. Browse to http://www.opscode.com/chef/install.
  3. Under Installing the Chef server, select OS, version and platform architecture.
  4. Choose desired Chef version.
  5. Copy downloaded package to server host to install.
  6. Install the package (how best to do this depends on the platform and is left to you, but my server is running Ubuntu Precise 12.04).
        $ dpkg -i chef-server_10.18.2-1.ubuntu.12.04_amd64.deb
    

    During this installation, you'll be asked (probably via some TUI), for some information:

                  IP address/URL for Chef server: 16.86.192.111
        password for user admin in vhost "/chef": Escoffier
    

    ...including an administrator password. (The password I chose for this guide is the name of a famous French chef.) Make note of your password for later. Note also your server's IP address.

  7. On your Chef server, create /etc/chef-server2 if it does not already exist (it probably does).

1 Note that the Chef server install is always a download.
2 In versions of Chef prior to 11.x, this was named /etc/chef.


2. Setting up a Chef client node

  1. Ensure the VM, host or computer you're targetting as a client node is running NTP.
  2. Browse to http://www.opscode.com/chef/install.
  3. Under Installing the Chef client, select OS, version and platform architecture.
  4.  
    If behind a proxy or firewall, don't use the Quick Install, but Downloads to download the Chef client as a file you'll copy over to your node.
     
  5. Choose desired Chef version.
  6. Copy downloaded package to host (client node) to install.
  7. Install the package (how to do this depends on the platform and is left to you).
        $ dpkg -i chef-server_11.4.4-2.ubuntu.12.04_amd64.deb
    
  8. Once the client node is installed, create /etc/chef, switch to that subdirectory and run the following command (as root):
        $ knife configure client ./
    

    This will create...

        [email protected]:/etc/chef# ll
        total 20
        drwxr-xr-x  2 root root 4096 Jul  1 18:00 ./
        drwxr-xr-x 92 root root 4096 Jul  1 17:44 ../
        -rw-r--r--  1 root root  128 Jul  1 17:44 client.rb
        -rw-r--r--  1 root root    1 Jul  1 17:44 validation.pem
    

    Note: validation.pem will always exist, but contain only a newline on client nodes (including on a development host).

  9. Change chef_server_url inside client.rb to specify the URL of your Chef server, something like
        chef_server_url  'http://16.86.192.111:443'
    

    It was probably created by default as "localhost:443". (Note that, prior to Chef 11.0, the port numbers were 4000 and 4040 for HTTPS.)

  10. Create a file, client.pem, with the contents of a private key you create using the Chef server web interface. To do this,
    1. Bring up the server web interface, click the Clients tab.
    2. Click Create, type in the name of your node (app01 for this tutorial), do not click Admin as there's no need for this client to have those privileges,
    3. Click Create client. You'll get a private key with the warning that it will not show up again.
    4. Carefully copy everything from the first to the last hyphen (-) and paste it into a file, probably on your development (that you haven't set up yet). Something like:
          -----BEGIN RSA PRIVATE KEY-----
          MIIEpAIBAAKCAQEArrttkL6iiv8l9UMLkxth6v7I+Mu5vf+0M/t+HXqqikuq0Nui
          Zd8xMUalAwd0nnaXSYlOC2pa/BMmml98abGh+jlTCJ0VpxyLUjqc24Y9mEmEBpP1
          /Yoj9pZS8V8W8w8tm5sYdjiVhAYKafad/aA2gXXo6ztCYwnxjj8wjsGnV9I+81Sf
          pA0zZ5qzbFlaW95MYeuSwe9zTu4Ve0UK9TwqbraijpxzzAHoMtdFsk+MUd+7DXGm
          nl4GiLWhWyEBY9Rhh5zZOpK+OtyGKe1qShUHb/WqE1Yk0yPKd8SaBDvvjGO62Oiz
          XVh8cIfR1/mbrnTS85UG2BKfb17Ii0lRbGOCSQIDAQABAoIBAAVTBsKrXG6Z2cFA
          esDPy8sKWntiUdWdThNrbWteioXOSnU0zB0IkQosWejeuEn/2RpPicZFRmJ5/uoj
          ULozxHjIeGRBzSAbeY9W4+K4k3Xpf5Fnvs4sAG6KJBrgx+U+KCiesD8h+ERensCd
          2DCbSi3ltuQ8GQjFi8vG1ybydbPyUj5q7SHjgRtRzZ+0eVr3RMoilZu2RskV0RF8
          V2V2EnJBSQyFPsCTgbKHhMUGZbLlojWh0H7Blmnszbk5DGEIv7KEjJDTTko3pMI7
          znX4gDBuDDG+9ccl8g42/9yQ/eB2IMkaupmFrIaTdpwt66fRhEhVmYnyt/cxrH8F
          dflDjgUCgYEA16bQzAre0G5XJzk5tx4XymQJAk3+5SduQxk1NhHdSQjnoKWp2pBu
          ROH1VXNgL8dx+Qxtt1stzT386qxkliAdVCNkdTc0W2NBW366D/+d4LQnzoXjBLKE
          hn03DLkcE7k/LZ1usehT9BEcY53V+cgPa1QgtjXeJu2/nQOC93p6tScCgYEAz2yr
          XhHbUY/mvmLMbuHo5QhZTaBv6iZlhdBBM2Qk0jqkaJ3q3z+lSx1zJFm0r1CzGKC9
          aZzpkWwm4DamKiHbG9fRcQpvjJDaPYdczEhKhRePOEMUEV8WVH62Tqm/yS3GK6Xw
          PKZWL2AP4J7UjxbUqak2SUGkpmkOGJjUdADXEw8CgYEAwSd9JQUnhXEPRuaOt2GQ
          1Yq8NwA9Kmsi656Mdp2RonUDYnR/qnBrE+9/msX4hVMS1os3Sl+0qny3KEq43W5u
          VopM1GBZ2PER/S2I4gOGGVnDvctWB0MOSJem0xKJ/3CREf5Mw7TgXV9mGiOpIEz8
          4pk7o3ikPiH82lnm2FsvxUkCgYANtsSZwpp6iQYbflK/3gXU5rlozXu4wnMh5sP4
          zt00XRYzqIU333BhSAAt3hR5Jt/AeBgt3GcA62KinlpcHMLs01cQnz0C0Szstn9n
          LjxnEkiw0paIE35Zdcs95jE87t7UUfNRPzohhbtnAXlSQJMs6HgjXciyC+4XqDsb
          tFaD9wKBgQCYaKDq5hbF/m5e9VCmCr38iy/okCQRQuVUGpXvFFYP9dx2qJMDL2f+
          a7wD2zWX/V2Lg3YG0VCj+0qiYxWOD+wxHsUKvvqXnSEtS2GsY8fLeB8MtHadEG2Q
          wHxZNXK2TxennULyWrjqH5JYg9l2FmsGdLlDQQmX+d+dT/h+UIKShQ==
          -----END RSA PRIVATE KEY-----
      
    5. Copy this file to the path /etc/chef on this node and rename it to client.pem.

Put this installation on the back burner...

We'll have to leave off setting up our Chef client node just a bit to set up our development host. We could do it using the Chef server web interface,* but it's not how I want to show it. First, we have to set up the developer host we're going to use to administer Chef. After that we'll finish this step.

* With Chef, there are always half a dozen ways to do any one thing.


3. Choose and set up a development host for Chef administration

I leave the choosing to you with the caveat that I use Linux here.

Please install a Chef client on the development host you've chosen just as you did for the VM node you chose to install in step 2, but don't run the knife configure client command yet.

Once the Chef client is installed on your development host, here are the steps to setting it up.

  1. Ensure you've created /etc/chef. Do not run knife configure client ./ on your development host as it will make it vulnerable: if you ever ran chef-client, there's at least a tiny risk Chef might destroy your development host.
  2.  
  3. Create a work area someplace. I'm going to do this in a subdirectory, chef-repos, directly underneath my root:
        ~ $ tree chef-repos
        chef-repos
        |— .chef
        |— cookbooks
        |— nodes
        `— roles
    
        4 directories
    
  4. Create those other subdirectories you see above under chef-repos.
  5.  
    You can add the address of your Chef server to /etc/hosts, but Chef doesn't make much use of this file. You'll often have to use the hard IP address instead, which you'll see in this documentation. It's my impression, however, that Chef does make use of DNS.)
        16.86.192.111 chef-server
    
  6. Create knife.rb. Use the following template, but change the paths, etc. here to match your filesystem and circumstances. Note that you must use your Chef server's IP address (and port 443) here. This is because the knife command you'll be using issues HTTPS to the Chef server.
        log_level                :debug
        log_location             STDOUT
        node_name                'russ'
        client_key               '/home/russ/chef-repos/.chef/russ.pem'
        chef_server_url          'https://16.86.192.111:443/'
        cookbook_path            "/home/russ/chef-repos/cookbooks"
        cookbook_email           "[email protected]"
        cache_type               'BasicFile'
        cache_options( :path => '/home/russ/chef-repos/checksums' )
    
  7. Make sure you can reach the Chef server's web interface. Your browser may not translate from /etc/hosts either:
        http://16.86.192.111:400/
    

    You'll discover that you must use username admin and the password you gave during the Chef server installation.

At this point, you should be able to get some warm fuzzies from typing

    $ knife cookbook list

It won't return anything, but the fact that it doesn't display an error means you've contacted your Chef server and it has replied that you've not created any cookbooks.

What you should know about knife.rb

This file controls a lot of things you're about to use such as:

Note: You can create as many instances of this chef-repos filesystem on your development host as you like and these instances can be named anything you like. If you're a developer operations persons working with more than product team, this might come in handy.


2. (continued) Setting up a Chef node

Remember we said we'd need to tell Chef about the node we want to administer? Here's where we'll do it using knife and a file (or some files) we create. In order to use knife instead of the web interface, we had to get our administration node—our development host—set up first. As I say elsewhere in here, we want as much of our set-up done using files where possible so that we can a) remember this stuff in Git and b) recover from catastrophic system errors that would erase this knowledge in the Chef server web interface.

Nota bene: Even though we're talking about setting up a Chef client node here, this is all done on the development host.

  1. Under the subdirectory, nodes, create a file with the name of a node you installed Chef on. I'm pretending we've got a node named app01.
    app01.json:

    This is a JSON representing of information defining this node. In some systems, this is done using a .yml file, but I haven't reached that grade in Chef school yet. What's really important is the run_list1.

    {
        "normal": { },
        "name": "app01",
        "override": { },
        "default": { },
        "json_class": "Chef::Node",
        "automatic": { },
        "run_list":
        [
            "recipe[tomcat6]",
            "recipe[xyz]",
            "role[application_node]"
        ],
        "chef_type": "node"
    }
    
  2. Use knife to tell the Chef server of this:
        ~/chef-repos $ knife node from file app01.json
        knife node from file app01.json
        Updated Node app01!
    
  3. In the Chef server web interface, under the Nodes tab, see the effect this command just had: there's now a node listed.

1 The run_list tells Chef what recipes to install and in what order. It also tells it what role is going to do this. In our case, these are cookbooks with exactly one recipe each.

For this tutorial, we're only setting up a single node. Any additional nodes are set up identically. There is sophistication you can perform in Chef, using .yml files, etc. to fold a lot of common and redundant stuff into this process. I'm not showing that.


4. Setting up a client, a role and a cookbook/recipe

Unless you don't wish to log into the Chef server web interface as admin, there aren't many reasons to create another user. However, we do want to create a client, just as we did for the client node we want to manage, which is really crucial to finishing our development host set-up.

Administration client (you)

Chef documentation is slightly confusing with its use of the word client. To help disambiguate, I like to keep this term for the up-coming concept and, if I use it with nodes, I make sure I never say only "client" when I mean "client node". Here, we're talking about your Chef client that does real work, i.e.: the administrating development host and not the working node you're going to set up (on which you'll only ever run the command, chef-client).

While you will usually log into the Chef server web interface as admin, you'll use the Chef knife utility as yourself. This is what we're setting up here and Chef knows you as the .pem file which contains your private key when you use knife. Here, I'm russ.pem.

We're only going to create one client. If you've got a colleague that's going to help you administer Chef, he or she will need a separate one (all the while probably consuming the chef-repos contents from common Git repository).

  1. In the Chef server web interface, create a client which you'll use from the development host. I call mine russ. As you do not need to log into the web interface except as admin, don't create a user, at least not by the same name. Click here to see illustration.

  2. Copy the private which you'll lose as soon as you let this page go, to your clipboard. Click here to see illustration.

  3. Paste the private key on your clipboard into a file name russ.pem on the path ~/chef-repos/.chef/russ.pem (or the equivalent if you chose a client named other than russ). You should now see:
        ~/chef-repos $ ll .chef
        total 16
        drwxr-xr-x 2 russ russ 4096 Jun 28 10:23 .
        drwxr-xr-x 9 russ russ 4096 Jun 28 10:09 ..
        -rw-r--r-- 1 russ russ  133 Jun 28 10:23 client.rb
        -rw-r--r-- 1 russ russ 1679 Jun 28 13:34 russ.pem
    

Roles

Roles are an artificial designation in Chef to help organize who does what in the setting up of a Chef client node. For example, ensuring the installation of Tomcat or your database might be considered a role.

You can make a role to be as powerful and run as many recipes as you like, for example, set up an entire application or database server node, or as granualar and pointed, such as only to install Tomcat or MySQL as part of what a node needs. As you chef more and more, it will dawn on you just how granular you should be. If in doubt, be granular. This will make Legos™ you can use to set up different types of nodes.

For our purposes, we're going to create one role, application_node. We could use knife to set up our role, which we'd immediately see in the Chef server web interface, but we want a written record of what we're doing so we don't have to look in the web interface, which might go missing if the Chef server ever died.

You should give thought here to commiting everything to Git or a suitable version-control system that we do here for recoverability.

  1. Under the roles subdirectory, create a new Ruby file, application_node, with these contents:
        name "application_node"
        description "Role for managing web application server nodes"
    
        for_application_servers = %w{
    	    recipe[tomcat6]
    	    recipe[xyz]
        }
    
        run_list for_application_servers
    
  2. Use knife and this file to create this new role:
        ~/chef-repos $ knife role from file application_node.rb
        Updated Role application_node!
    

This installed a new role, application_node, into Chef which you can see in the web interface by clicking the Roles tab. It also told Chef that this role knows of and uses two recipes (out of two cookbooks), which we haven't written yet.

Nodes

We set up a node, app01, with a file, app01.json, in a previous step here. By "node" or "client node", we mean one or more VMs you're administrating using Chef.

Recipes and cookbooks

Cookbooks are another area in which Chef terminology gets flaky if in a different way. You may become confused about the difference between recipes and cookbooks.

Cookbooks are collections of recipes. Your cookbook here, in its subdirectory, is one and it will hold one or more recipes. You could create others. I'm not going to illustrate that so all you'll see is a bunch of cookbooks under the Cookbooks tab of the web interface, but no recipes by name.

Much of Chef documentation uses "recipe" for "cookbook" when a cookbook contains only one recipe. It's confusing. Just beware.

We'll create two cookbooks with one recipe each here.

  1. xyz
  2. tomcat6

Cookbook/recipe xyz

This is a recipe for an imaginary web application, xyz.

  1. Under subdirectory cookbooks, issue the following command:
    ~/chef-repos/cookbooks $ mkdir -p xyz xyz/files/default xyz/recipes templates/default
    
  2. Change your current working directory to xyz and add the following files:
    metadata.rb:
        maintainer       "Despicable Me"
        maintainer_email "[email protected]"
        license          "Apache 2.0"
        description      "Fun web application (xyz) for application node (server) cluster"
        long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
        version          "1.0.0"
    
    README.rdoc:
        = DESCRIPTION:
        Chef recipe for fun XYZ web application.
    
        = REQUIREMENTS:
        Tomcat
    

    Note: When you grow up in Chef, these files, especially the second, will tend to acquire more and better information as you'll see soon when we create the tomcat6 recipe.

  3. Copy any harmless Debian package to the path files/default.

    Admittedly, this is where my Chef quick-start tutorial goes south: I'm not going to go the trouble of creating your web application. Also, this recipe will install a Debian package. I'll try to come back later and add another recipe that copies a WAR file to /var/lib/tomcat6/webapps instead. I use a Debian package since I need to populate the filesystem under /opt with data.

  4. Change to the recipes subdirectory and add the following file including the comment which you can remove, but will be a cheat to give you some information that transcends what I have in mind for this quick-start tutorial.
    default.rb:
        #
        # Cookbook Name::
        # Recipe:: xyz
        #
        # The purpose of this recipe is ONLY to deploy xyz.deb.
        #
        # The way this works is:
        # 1. A new xyz.deb is copied into cookbooks/xyz/files/default.
        # 2. The updated recipe is committed to Git.
        # 3. A Jenkins project notices that there's something new in Git.
        # 4. Jenkins runs a script that knifes the new recipe up to the Chef server.
        # 5. The next time an application node runs chef-client, which is controlled
        #      by a cron job, the new xyz.deb is deployed by this recipe
        #      using dpkg -i.
        #
        # Possible failures:
        # 1. xyz.deb doesn't have a later version than the existing one. This
        #      results in dpkg -i failing to install it.
        # 2. Something else we'll learn by experience and document here.
        #
        # Copyright 2013, Etretat Logiciels, LLC and Russell Bateman
        #
    
        # Copy the Debian package to /tmp. This package is put into the
        # recipe before replacing/updating the recipe on the Chef server.
        cookbook_file "/tmp/xyz.deb" do
    	    source "xyz.deb"
    	    mode   "0644"
    	    owner  "root"
    	    group  "root"
        end
    
        # Install the Debian package...
        dpkg_package "xyz" do
    	    source "/tmp/xyz.deb"
    	    action :install
        end
    
  5. Return to the root of your chef-repos subdirectory and knife this cookbook up using this command:
        ~/chef-repos $ knife cookbook upload xyz
        Uploading xyz            [1.0.0]
        Uploaded 1 cookbook.
    
  6. If you like, examine this cookbook in the Chef server web interface under the tab, Cookbooks. Follow the links down and you should see the text of the actual recipe, default.rb.

Cookbook/recipe tomcat6

There are two reasons I'm illustration the creation of a recipe that installs Tomcat 6 on a Chef node. First, the example of a web application simply requires it. Second, and more important, it illustrates how you can steal your way to Chef glory and win fame among your peers without much effort (sometimes).

The Internet is full of great, useful Chef cookbooks/recipes to do all sorts of things. Pop up your favorite browser and Google for "opscode chef recipe for tomcat". (When I Google for Chef stuff, I often add "opscode" to keep myself from getting distracted by food offerings.)

At or near the top of the list will be Opscode's own Tomcat recipe. I tried that and found it wasn't quite what I wanted. However, removing "opscode" from the search netted me, near but not at the top, this link:
https://github.com/b441berith/chef-cookbook-for-apache-tomcat-cluster

This is someone's somewhat simpler cookbook/recipe, if for Tomcat 7. The copyright notices do not discourage me from consuming this recipe though I preserve them.

Here's what I did to make this just the recipe I needed:

  1. Download the zip file to the cookbooks subdirectory by clicking the Download ZIP at the bottom of the right-hand column. Unzip what comes down. This creates a long subdirectory named chef-cookbook-for-apache-tomcat-cluster-master which I simply rename tomcat6.
  2. Run through the following files making the changes suggested by the copies of my versions in the appendix below.
    • attributes/default.rb
    • metadata.rb
    • README.rdoc
    • recipes/default.rb
  3. Download the tarball for Apache Tomcat 6 from here and copy it down to tomcat6/files/default/apache-tomcat-6.0.37.tar.gz. It's that simple, though there are more sophisticated things to do if you simply want the latest version. When your node is behind a firewall, that complicates things greatly.
  4. Return to the root of your chef-repos subdirectory and knife this cookbook up using this command:
        ~/chef-repos $ knife cookbook upload tomcat6
        Uploading tomcat6        [1.0.0]
        Uploaded 1 cookbook.
    
  5. If you like, examine this cookbook in the Chef server web interface under the tab, Cookbooks. Follow the links down and you should see the text of the actual recipe, default.rb.

Ready to go!

At this point, we've finished our quick-start tutorial except for forcing one node (or as many as we want) to install itself with Tomcat 6 and our web application. We use ssh to get into our node, get root, then use the chef-client command to load our recipes, which is another way of saying "install software and configure" our client node:

    ~/chef-repos $ ssh app01
    Welcome to Ubuntu 12.04.1 LTS (GNU/Linux 3.2.0-48-virtual x86_64)

     * Documentation:  https://help.ubuntu.com/

      System information as of Fri Jun 28 15:43:59 MDT 2013

      System load:    0.0             Processes:           97
      Usage of /home: 6.1% of 937MB   Users logged in:     1
      Memory usage:   5%              IP address for eth0: 16.86.192.114
      Swap usage:     0%

      Graph this data and manage this system at https://landscape.canonical.com/

    Last login: Wed Jun 26 14:31:30 2013 from kalevala.site
    [email protected]:~$ sudo bash
    [email protected]:~# chef-client

Oops! I get an error...

If you fail to create a client in the Chef server web interface, copy its private key and paste it into /etc/chef/client.pem, you'll get an error such as:

    [email protected]:/etc/chef# chef-client
    ...
    Chef encountered an error attempting to create the client "app01"
    ...

If you get the following error...

    Authentication Error:
    ---------------------
    Failed to authenticate to the chef server (http 401).
    The request failed because your clock has drifted by more than 15 minutes.
    Syncing your clock to an NTP Time source should resolve the issue.

...or something like:

    [2013-07-08T18:29:08+00:00] INFO: HTTP Request Returned 401 Unauthorized: Failed to authenticate. Please synchronize the clock on your client

    ================================================================================
    Chef encountered an error attempting to load the node data for "app01"
    ================================================================================

...you'll need to ensure your client node has the same time as the Chef server. Did you set up NTP on your Chef server and client node as instructed? For help with this, see Notes on ntp.

Here are hints on more errors...

Trouble-shooting

Try these steps to trouble-shoot:

  1. Is the Chef client node name identical to the hostname on which it's going to run? (This isn't totally crucial, but differences between the two can lead to trouble sometimes.)
  2. Did you run knife configure client ./?
  3. Is /etc/chef/client.pem the right/latest private key for this client in the Chef server web interface?
  4. In /etc/chef/client.rb, is chef_server_url correctly set (i.e.: points to Chef server)? (Note, each time you run knife configure client, this will be clobbered.)
  5. Is ntp installed?
  6. Is /etc/ntp.conf updated to reflect the time server? (Hint: if you're behind a firewall, this is most likely what's biting you.)
  7. Does /etc/timezone match what's on your Chef server's host? If this is already set up on other nodes and the Chef server, edit this file by hand and copy what's in those configurations (should be identical) to the host you're trouble-shooting.
  8. Have you bounced ntp?
  9. Did you try bouncing the host? Surprisingly more effective than the previous suggestion.
  10. Have you compared the output of date against the same on your Chef server or another, working node? Sometimes, you just need to wait awhile (only a minute or two) and reboot before it aligns with the time server. Reboot a couple of times; the output of date is the dead give-away this is working.

Appendix: Finished filesystem (illustration)

At the end of this tutorial, here's the /home/russ/chef-repos filesystem:

    ~ $ tree chef-repos
    chef-repos
     |— .chef
     |   |— knife.rb
     |   `— russ.pem
     |— cookbooks
     |   |— tomcat6
     |   |   |— attributes
     |   |   |   `— default.rb
     |   |   |— files
     |   |   |   `— default
     |   |   |       `— apache-tomcat-6.0.37.tar.gz
     |   |   |— metadata.rb
     |   |   |— README.rdoc
     |   |   |— recipes
     |   |   |   `— default.rb
     |   |   `— templates
     |   |       `— default
     |   |           |— context.xml.erb
     |   |           `— server.xml.erb
     |   `— xyz
     |       |— files
     |       |   `— default
     |       |— metadata.rb
     |       |— README.rdoc
     |       `— recipes
     |— nodes
     |   `— app01.json
     `— roles
         `— application_node.rb

More...

For more information, you can sort through the mess of the Chef Notes I took before writing this quick-start tutorial.

Of course, at some early point, you should spend time directly in Opscode Chef Home.


Appendix: Files changed in the Tomcat recipe

attributes/default.rb:

The biggest changes are here. If you are familiar with Tomcat, they are easily made. Otherwise, examine these and adapt to your environment. In particular, the ones in green almost certainly need to be different for you.

Of course, this is all overkill. When you install Tomcat, you don't usually need to modify the default server.xml. However, quibbling about this is beyond the scope of this document.

    node.default[:installPath] = "/usr/share/tomcat6/"
    node.default[:tomcatPath] = "/var/lib/tomcat6/"
    node.default[:serverPort] = 8005
    node.default[:connectorPort] = 8080
    node.default[:ajpPort] = 8009
    node.default[:hostIP] = "16.86.192.114"
    node.default[:multicastIP] = "228.0.0.4"
    node.default[:multicastPort] = 45564
    node.default[:nioAddress] = "16.86.192.114"
    node.default[:nioPort] = 4000
    node.default[:tempDir] = "/var/lib/tomcat6/webapps/"
    node.default[:deployDir] = "/var/lib/tomcat6/webapps/"
    node.default[:watchDir] = "/tmp/war-listen/"
metadata.rb:

The values in green are what I changed.

    maintainer       "Despicable Me"
    maintainer_email "[email protected]"
    license          "Apache 2.0"
    description      "Apache Tomcat 6 configuration for cluster"
    long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
    version          "1.0.0"
README.rdoc:

This wouldn't have to be changed, but I changed it a bit to make it more relevant to my use.

    = DESCRIPTION:
    Chef cookbook for Apache Tomcat in clustered environment

    = REQUIREMENTS:
    Ubuntu

    = ATTRIBUTES:
    node.default[:installPath] - path to install tomcat
    node.default[:tomcatPath] - full tomcat path after installation
    node.default[:serverPort] - by default 8005
    node.default[:connectorPort] - by default 8080
    node.default[:ajpPort] - by default 8009
    node.default[:hostIP] - use the host address
    node.default[:multicastIP] - by default "228.0.0.4" (per Apache)
    node.default[:multicastPort] - by default 45564 (per Apache)
    node.default[:nioAddress] - use the host address
    node.default[:nioPort] - by default 4000
    node.default[:tempDir] - temp dir for deploying
    node.default[:deployDir] - dir to deploy WARs
    node.default[:watchDir] - dir to watch WARs

    For more information see opscode tutorials.
recipes/default.rb:

Remember, we want to use this for Tomcat 6, not Tomcat 7. So, lots of stuff has to change. We picked the latest Tomcat 6 build. Also, as I plan to use this on an Ubuntu platform, I had to change from "debian" because, even though Ubuntu is Debian, I got an error out of Ruby land if I didn't change this.

    #
    # Cookbook Name:: apache-tomcat
    # Recipe:: default
    #
    # Copyright 2011
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.

    # TODO extract version to attributes

    # currently tested just with Debian
    if not node['platform'] == "ubuntu" then
      raise RuntimeError, "Unsupported platform: #{node['platform']}"
    end

    # make install folder if it doesn't exist
    execute "mkdir" do
      command "mkdir -p #{node[:installPath]}"
      action :run
    end

    # copy tomcat distrib to install folder
    cookbook_file "#{node[:installPath]}/apache-tomcat-6.0.37.tar.gz" do
      source "apache-tomcat-6.0.37.tar.gz"
      mode "0644"
    end

    # extract tomcat
    execute "tar" do
      command "tar -xvf #{node[:installPath]}/apache-tomcat-6.0.37.tar.gz --directory #{node[:installPath]}/"
      action :run
    end

    # remove archive from install folder
    execute "rm" do
      command "rm -i #{node[:installPath]}/apache-tomcat-6.0.37.tar.gz"
      action :run
    end

    # configure context.xml
    template "#{node[:installPath]}/apache-tomcat-6.0.37/conf/context.xml" do
      source "context.xml.erb"
      mode "0644"
    end

    # configure server.xml
    template "#{node[:installPath]}/apache-tomcat-6.0.37/conf/server.xml" do
      source "server.xml.erb"
      mode "0644"
    end

Appendix: A more concise list of steps and commands

The steps below are concrete, an attempt to condense them in order to make the whole visible, but assumptions about platform (Ubuntu Precise 12.04), Chef version (11.x), etc. have to be made. This appendix has worth mostly to remind and orient. Some steps are too complex to enumerate simply here and, accordingly, links are given to the deeper details.

  1. Download Chef server and client software; copy to server, client and development hosts.
  2. Install Chef server.
        (server) $ sudo dpkg -i chef-server_10.18.2-1.ubuntu.12.04_amd64.deb
    
  3. Install and set up Chef client node.
        (node) $ sudo dpkg -i chef_11.4.4-2.ubuntu.11.04_amd64.deb
        (node) $ sudo mkdir /etc/chef
        (node) $ cd /etc/chef
        (node) $ sudo knife configure client ./
    

    Finish configuring the client node completely as explained here.

  4. Install and set up development host (also a Chef client).
        (host) $ sudo dpkg -i chef_11.4.4-2.ubuntu.11.04_amd64.deb
        (host) $ sudo mkdir /etc/chef
        (host) $ cd /etc/chef
        (host) $ sudo knife configure client ./
    
  5. Create development host filesystem (on host installed and set up above).
        ~ $ cd
        ~ $ mkdir chef-repos
        ~ $ cd chef-repos
        ~/chef-repos $ mkdir .chef cookbooks nodes roles
    
  6. Using Chef server web interface, Clients tab, create a client (russ) and copy its private key to .chef on the development host. See here.
  7. Edit .chef/knife.rb on the development to ensure correct configuration. See here.
  8. Obtain/write recipes, xyz, tomcat6, place under cookbooks, then...
        ~/chef-repos $ knife cookbook upload xyz
        ~/chef-repos $ knife cookbook upload tomcat6
    
  9. Create application node role in file under roles, then...
        ~/chef-repos $ knife role from file application_node.rb
    
  10. Create application node in file under nodes, then...
        ~/chef-repos $ knife node from file app01.json
    
  11. Run chef-client on client node to load up the recipes.
        (node) $ sudo chef-client
    




Introduction
Quickest steps to setting up and using Chef
1. Setting up the Chef server
2. Set up a Chef client node
3. Choose and set up a development host
        What you should know about knife.rb
2. (continued) Setting up a Chef node
4. Setting up...
        Administration client (you)
        Roles
        Nodes
        Recipes and cookbooks
                Cookbook/recipe xyz
                Cookbook/recipe tomcat6
Ready to go!
        Oops! I get an error...
        Trouble-shooting
Appendices
        Finished filesystem (illustration)
        Files changed in the Tomcat recipe


        A more concise list of steps and commands:
                Download Chef software
                Install server
                Install client node and configure
                Install development host
                Create development host filesystem
                Configure development host (client)
                Edit knife.rb
                Obtain recipes
                Create application node role
                Create application node
                Run chef-client to load recipes