My Workflow with Chef
Something i wish somebody had published before i went and discovered myself. I have started with the Single Repository for everything at first, quickly realizing that maintaining such a repository would be a pain. I then went and split all the Community cookbooks and my own cookbooks into two directories in the repository, so i could update the Community Versions with knife cookbook install
.
As soon as you have multiple projects sharing some cookbooks, this way also becomes hard to manage. After a lot of reading and exploring, i ended up with the following.
One Repository per cookbook #
This is a way, that afaict is something that evolved from using Vagrant and Berkshelf in recent months. It makes sense if you start with these tools, to manage every Cookbook in it’s separate Repository. That way you can easily Change and Test things, without having to worry about the entire Repository.
For Personal cookbooks i have the habbit of prefixing them with something, so tools like berkshelf and knife won’t suddenly pull Versions from their Repositories because the name is identical.
Use a ‘Meta’ cookbook for roles and configuration #
Beating a dead horse here, but still. Something i wish the Chef Server would do better sometimes. Because of the Lack of versioning in all Configurations on the Chef Server (Environments, Roles etc) i mostly end up pulling all Configuration into meta cookbooks that just pull togother all required cookbooks and apply configuration through attributes.
You would for example create a cookbook ‘Webserver’ that includes Apache, and apply the configuration in ‘attributes/apache.rb’.
With this, you will be able to actually test configuration changes before pushing them live. Also adding new Nodes is then just a matter of setting one Role in the node Config to recipe[webserver]
.
Berkshelf for Version Management #
Berkshelf is a nice tool, albeit somewhat buggy at times. It helps with Version Management for a cookbook. Make sure you don’t use both chef_api :config
and site :opscode
in one Berksfile, choose your “master” source, and configure single special Cookbooks to pull from a different source. Using both sources, lets Berkshelf choose where to get the cookbook from, which i have found to be very funky.
Also don’t use Version constraints in the metadata.rb. Berkshelf 2 can’t use them, and the Chef server tends to lock up trying to resolve them in my experience. Use the Berksfile for constraints, and then berks apply
them to a Environment on the Chef Server that is used by your destination Nodes.
And don’t add the Berksfile.lock to the Repo, After writing it once, Berkshelf 2 can’t read it anymore. You’ll end up constantly deleting it… Occasionally deleting ~/.berkshelf/cookbooks
also seems a good idea, to prevent Berkshelf from using it as cache.
I hope Berkshelf 3 is released soon, and fixes all the oddities and bugs that currently exist. Haven’t been brave enough to use the Beta yet.
Vagrant for Testing and Development #
Use Vagrant. Use one of the Provisionerless Boxes from opscode/bento, and add the Omnibus and Berkshelf plugins to Vagrant. That way you have a ‘clean’ base box, with a Chef version of your choice.
The Vagrant Box never talks to the Chef Server, so if you need data bags, use chef-solo-search
.
Foodcritic / knife cookbook test / Unit Test #
As bare minimum, use foodcritic and knife cookbook test
to verify your code. I use chef-minitest for Unitesting. You really want to use these facilities, you’ll thank yourself the first time you need to change something after you’ve not touched a cookbook in a few weeks.
Tie everyting into Jenkins #
At Work i have a Jenkins running that watches the cookbook Repositories, and runs foodcritic and knife cookbook test on them, and finally vagrant destroy -f && vagrant up
. So before i berkshelf upload
i can verify my changes on Jenkins on a clean installation.
The Steps #
This is what the workflow entails at the end:
- Bump
metadata.rb
version - Work on cookbook
- Write Unit Tests
vagrant provision
to test changes locally, rinse, repeatgit commit
to central Repository, wait for Jenkins to finish the entire runberks upload
to Upload Cookbookberks apply
to send Cookbook into the wild