Chef Provisioning: Infrastructure As Code

Chef Provisioning is now a Release Candidate, included in the [ChefDK](https://downloads.getchef.com/chef-dk/) version 0.3.4! This powerful new Chef featureset lets you idempotently create and converge machines, images, load balancers and other infrastructure, no matter where they are: cloud, bare metal, virtual machines, or containers. This is the next step in configuration management: Infrastructure as Code.

Chef already does a bang-up job describing and automating the software on individual machines in your clustered application. Chef Provisioning harnesses the simplicity and power of Chef to go one step further: to describe and automate the *whole cluster* with Chef, soup to nuts, hardware to network to software. This is the promise of Infrastructure as Code: when you write your cluster configuration down as code, suddenly your clusters become testable, repeatable, self-healing, idempotent and, most importantly, *easy to understand.*

Some of the features of Chef Provisioning:

* Describe your application cluster with a set of `machine` resources
* Deploy many copies of your application cluster (test, integration, production …)
* Spread your cluster across different clouds and machines for redundancy and availability
* Orchestrate your deployments, making sure (for example) the database primary comes up before any secondaries
* Speed up your deployments by parallelizing machines with `machine_batch`
* Standardize your fleet, and speed up rollouts by creating images without losing the power to patch, using `machine_image`
* Scale your services effortlessly with `load_balancer` and the `machine` resource.

Machines: Dead Simple
———————

This is the recipe to deploy a database machine with mysql on it. Stick this in a file if you want to follow along.

[code language=”ruby”]# mycluster.rb
require ‘chef/provisioning’
machine ‘db’ do
recipe ‘mysql’
end
[/code]

To run this, we’ll need to install Chef and Provisioning, set `CHEF_DRIVER` to our cloud provider, and run the recipe. That’s all there is to it.

Chef Provisioning release candidate is included with the ChefDK! So [install that first](https://downloads.getchef.com/chef-dk/).

#### Pick a Cloud, Any Cloud

To provision machines, you have to decide where you will put them. Pick your favorite supported cloud, virtual machine, container or bare metal driver, and set CHEF_DRIVER environment variable to it:

I picked `aws`, which by default will create machines in your default AWS account in `~/.aws/config`.

[code language=”bash”]export CHEF\_DRIVER=aws # on Unix
set CHEF\_DRIVER=aws # on Windows
[/code]

#### Run That Recipe

Finally, you run the recipe:

`chef-client -z mycluster.rb`

Marvel at the little green text as it brings up the machine! Wonder as it installs Chef from afar! Be amazed as Chef converges and mysql boots up on your new server!

That’s it.

Three Machines Are Better Than One
———————————-

You might be thinking, “man, that’s awesome, but that was one machine and it took me like 3 minutes. What if I want to make a bunch of machines?” Good question! The answer is `machine_batch`, and parallelization. Let’s edit that recipe and add two more web machines:

[code language=”ruby”]# mycluster.rb
require ‘chef/provisioning’
machine_batch do
machine ‘db’ do
recipe ‘mysql’
end
# Create 2 web machines
1.upto(2) do |i|
machine "web#{i}" do
recipe ‘apache2’
end
end
end
[/code]

We did two things here:

– We put our three machines in `machine_batch`. This will cause all the machines to be provisioned *in parallel*. So if one machine takes three minutes, 3 machines will take … three minutes.
– We used a loop to create more than one machine! This is why Provisioning is defined as a part of Chef–the full power of the language, the Chef DSL and all recipes and resources are available to you. If you wanted 10 web machines, you could change the `2` to `10` and run the recipe.

When you run this:

`chef-client -z mycluster.rb`

You will notice that the `db` machine says “up to date” instead of getting created! This is because like all Chef resources, `machine` is idempotent. It knows the db machine is already there and configured the way we want, so it doesn’t do anything.

Take An Image, It’ll Last Longer
——————————–

Another powerful tool in the Provisioning quiver is `machine_image`. This allows you to create an image that is pre-provisioned with some Chef recipes–meaning that you don’t have to install apache2 on every machine, every time. Let’s take a look at that in action:

[code language=”ruby”]# mycluster.rb
machine\_image ‘web\_image’ do
recipe ‘apache2’
end
machine ‘another\_web\_machine’ do
from_image ‘web\_image’
end
[/code]

Run this:

`chef-client -z mycluster.rb`

And you will see an image created by creating a machine, saving the image and then destroying the machine; and then you will see `another_web_machine` get created, *without* having to download and install Apache.

Load Balancers
————–

The network is as big a part of your cluster story as the machines, and Chef provisioning helps with that with the `load_balancer` resource. Let’s modify our first recipe:

[code language=”ruby”]# mycluster.rb

load\_balancer ‘web’ do
machines %w(web1 web2)
end
[/code]

Run the recipe:

`chef-client -z mycluster.rb`

And you get a load balancer with both of your web servers in it!

Drivers
——-

Chef Provisioning has an extensible driver system that works with many clouds, Virtual Machines, containers and even bare metal. Here is a non-exhaustive list:

**Clouds:**

– [aws](https://github.com/opscode/chef-provisioning-aws): Amazon Web Services. Includes support for load balancers, machines and images, as well as resources for managing a growing number of things including SQS and security groups.
– [azure](https://github.com/opscode/chef-provisioning-azure): Microsoft Azure. Includes support for machines and images, with more to come.
– [fog](https://github.com/opscode/chef-provisioning-fog): Support for machines and images on many cloud drivers, including:
– AWS
– CloudStack
– OpenStack
– Joyent
– Rackspace
– DigitalOcean

**Containers:**

– [docker](https://github.com/opscode/chef-provisioning-docker)
– [lxc](https://github.com/opscode/chef-provisioning-lxc)

**Virtual Machines:**

– [vagrant](https://github.com/opscode/chef-provisioning-vagrant): support for Vagrant, which brings in VirtualBox, VMWare Fusion, and others.

**Bare Metal:**

– [hanlon](https://github.com/opscode/chef-provisioning-hanlon)
– [opencrowbar](https://github.com/newgoliath/chef-provisioning-crowbar)
– [vsphere](https://github.com/RallySoftware-cookbooks/chef-metal-vsphere)

Want More?
———-

This just scratches the surface of what Chef Provisioning can do–a couple of primitives and you suddenly open up a whole new world of possibility. You can find a wealth of information at [the chef-provisioning repository](https://github.com/opscode/chef-provisioning) and contains a lot of documentation and examples. That is also the place to file issues. You can join our [Gitter channel](https://gitter.im/opscode/chef-provisioning) if you’d like to chat. Happy provisioning!

Author John Keiser

John is a Principal Mad Scientist at Chef, has contributed code that will be worked around for years to nearly every piece of software Chef ships. Specific credits include chef-zero, chef-provisioning, and the ChefFS tools (knife diff, upload, and download).