I suggest that you think of your cookbooks in two different types: Application cookbooks and Library cookbooks.
An Application cookbook is what you develop for your company. Generally it contains a resource block which does the job of deploying a piece of software for your company. This cookbook should just do the job of deploying and configuring that software and it’s components. It’s metadata file probably has a long list of cookbooks it depends on and these dependencies should have their versions locked. We lock the versions here so when we pass our application cookbook to another developer to work on we know he gets the right dependencies. We developed (and use) Berkshelf to achieve this portableness. You can see a perfect example of this in the Chef 11 server cookbook https://github.com/opscode-cookbooks/chef-server. Notice the Berksfile and Vagrantfile at the root of the cookbook.
A Library cookbook is something that you include into your Application cookbook. It’s generally something you need to have but it isn’t something that the customers of your organization are really asking for. For example: If you’re Facebook then people want to share pictures of their stupid cats and cups of Starbucks that they are about to drink. They don’t care if your web application is running on NGINX or Apache, they just want to interact with your application. These Library cookbooks can often be obtained from the Opscode community site and should be re-usable from project to project. They should be highly customizable through the setting of various attributes which will change the way the cookbook functions. This will allow you to put something like this into a recipe in your Application cookbook:
Cookbook Name:: my_face
node.set[:nginx][:install_method] = "source"
This recipe above may actually be all there is to it. You would have successfully installed NGINX from source and that’s all you care about for setting up a web_proxy for your application “my_face”. Since we want to make sure the way we install NGINX from source with the NGINX cookbook doesn’t change, we’ll go into our metadata.rb and lock the version.
Now on your environment file you don’t want to lock NGINX down because we’ve already locked it in the “my_face” cookbook. Instead you want to lock the version of the “my_face” cookbook. If you recall a bit ago in this insanely TLDR email I mentioned that NGINX should be invisible to your users so this should make sense to why we wouldn’t lock NGINX here. In the end you should have an environment file which locks down the versions of all of your application cookbooks and completely ignores the version of your library cookbooks.
One minor note: A role does nothing but set a run_list and some attributes. A recipe can do these things, too. The biggest difference is that we have put a mental label on what a Role is and it’s really easy to explain that to people. The naming conventions in Chef are cute, but they really hurt us when we try to teach these concepts to people or when we try to begin to think outside the box. In my experience it has been difficult to explain to people why Roles are not necessary because they can’t seem to reify a Recipe the same they have a Role.
I hope this clears things up for you!
On Monday, January 21, 2013 at 1:41 PM, Peter Donald wrote:
On Tue, Jan 22, 2013 at 8:26 AM, Kayla Townsend <firstname.lastname@example.org (mailto:email@example.com)> wrote:
So do you guys manually maintain your versions in a role cookbook metadata file for each role? Or do you still use your environment files because you don’t have a reason to have more than one version of a service in production at the same time? Did you just do a massive switchover to role cookbooks? Or have you slowly transitioned, having some basic roles as well as role cookbooks for a time?
We use role cookbooks but mostly keep the versions of the cookbooks in the environment. We have contemplated moving some version information into the role cookbook itself but as yet we have not found a scenario that justifies the extra cost of this variation.