Inspired by one of the other challengers I started to experiment with Chef. Frederick is using Puppet to provision his Raspberry Pi’s. To get more knowledge on the several tools out there we decided to both try one. So that’s why I started using Chef.
Chef vs Puppet
Both tools are open source projects built for automatically provisioning nodes with software and configuration. They both have a fairly similar setup using a server and clients on all nodes. The biggest difference is in how you manage your configuration. Puppet uses a Ruby-based DSL which is similar to JSON, Chef uses pure Ruby. This makes Chef a bit more powerful out-of-the-box. As Rich Morrow said in his report:
Whereas Chef tries to provide more power to the user, Puppet puts safety rails around them.
Some noteworthy differences:
|Execution||Order enforced||Model driven|
|Approach||Programmer's approach||Sysadmin friendly|
|Used by a.o.||Facebook & Adobe||Twitter & Intel|
To learn more about Puppet I refer you to Frederick’s posts, here more about Chef!
A typical setup consists of three elements: your workstation, a server, and nodes.
The server is the central repository for all code and it also keeps knowledge about every node it manages. From your workstation you write and verify the configuration policy and then upload it to the server. When you run chef-client on a node the latest code is downloaded from the server and the node’s configuration is brought up-to-date.
To start you need a set up workstation and server. You can install a server locally or use a hosted version. Hosted Chef is free up to 5 nodes, so that’s how we’ll start.
- Install the Chef Development Kit
- Sign up for the trial of Hosted Chef
- Create an Organization at https://manage.chef.io/
- Go to the Administration tab, selection your new organization and click Generate Knife Config
- Save knife.rb to ~/.chef
- Copy your private key (created during signup) to ~/.chef as well
- Test the connection between your workstation and the server with knife ssl check
Your first cookbook & recipe
A cookbook is a set of configuration describing a service or node. It consists of recipes, template files and attributes. A recipe describes everything that is required to configure part of a system, for example which software packages to install, how to configure them or execute other recipes.
For this example we’ll create a simple cookbook which creates a file, just like in Fredericks example. Start with generating the cookbook:
chef generate cookbook test-chef
You now have the following directory structure:
│ └── default.rb
│ ├── spec_helper.rb
│ └── unit
│ └── recipes
│ └── default_spec.rb
│ └── serverspec
│ └── default_spec.rb
As you can see there is already a default recipe created. Let’s edit that to contain the following:
file '/tmp/testfile' do
content 'test content'
Now upload it to your server:
knife cookbook upload test-chef
And bootstrap a node:
knife bootstrap ADDRESS --ssh-user USER --ssh-password 'PASSWORD' --sudo --use-sudo-password --node-name node1 --run-list 'recipe[test-chef]'
You’ll see that Chef is installed on the node and in the end the file is created according to the recipe. When you run chef-client from the node it will check if there is a new version and if the file is still there. If something is not according to the recipe – it will fix it.
Of course there are already lots of cookbooks created by others, they are shared in the Supermarket. You can easily add a dependency to one of these cookbooks. There are several ways to override attributes used in the cookbook, or even override complete files to make sure it does exactly what you want.
You should have a basic understanding of Chef now, there is however much more. To let you get more familiar with Chef they have some excellent tutorials. In upcoming blogposts I’ll show my cookbooks as well.
The ugly: Chef on a Raspberry Pi
Now the bad news: Chef doesn’t support the Raspberry Pi out-of-the-box, so you can’t bootstrap it as easily as on other platforms. It also needs a fairly recent version of Ruby, which is not available in the Jessie repository. Luckily you can overcome this by using a custom bootstrap script and using the Stretch (the upcoming version of Debian/Raspbian) repository.
A good starting point is the Raspbian-Bootstrap by Dayne. It’s made for Wheezy, so we’ll have to update it a bit. It took some experimenting, but at some point I found a working solution. We can skip the custom Ruby build (which takes a long time) by using the ruby2.3 package from the Stretch repository and I’ve updated the syntax of the configuration part to the one from the default Chef bootstrap.
This brings us to the following steps:
- Take a Raspberry Pi with a clean Raspbian install (I use raspbian-ua-netinst, as it gives a minimal install)
- Download my version of Raspbian-Bootstrap
knife to bootstrap with a custom template:
1knife bootstrap PI_IP_ADDRESS -t raspbian-jessie-chef.erb --ssh-user root --ssh-password 'raspbian' --node-name 'NODE_NAME' --run-list 'recipe[thuis-base::default]'
This will do the following:
- Add the Raspbian Stretch repository to Apt and update the Apt index
- Remove any existing versions of Ruby
- Install Ruby 2.3 plus build tools from the Stretch repository
- Install gems needed for Chef + Chef itself
- Add basic configuration for Chef
- Start chef-client for the first time running in this case my base cookbook thuis-base
- Start using Chef on your Raspberry!