Vagrant and Chef with knifes
For those of you out there doing team development and collaboration, especially now that github is making it so social and simple, you’ve probably run into some or all the following problems:
- Your development environment doesn’t mirror your production environment (hardly ever).
- Since the Mac / Linux revolution it’s impossible to keep everyone’s development environment consistent
- It takes so much time to get yourself ready to go when starting or switching projects that you want to hire a project planner.
- The services of one project conflict with another project – try running nginx / apache and mysql / percona in the same ports
Besides losing half of your brain power to these nuances and let’s say 3/4 of your good mood as well, you also have to deal with git, lack of technical skills – face it no everyone can configure solr (I raised my hand already :-/) – so all in all you already wasted your productive time.
You know bash logs everything you do and I was setting up a virtual machine with most of the services required to have a good environment, you know how long it took me to get everything setup (setup != configured) 4 hours!
You could say… “I never test my code but when I do I do in production” or “let’s go back to using windows98 with CVS…” that should be cool if I didn’t like vagrant as much as I do.
So let’s close the rant tag ([/rant]) and open the solution tag ([solution])
The powerful vagrant to the rescue
Vagrant is essentially awesome, let’s leave it at that. You can Google it for more…
Getting started is as easy as typing:
vagrant box add lucid32 http://files.vagrantup.com/lucid32.box vagrant init lucid32 vagrant up
But that’s stupid and unhelpful (no really – just that we are going to do this the hard way)… why would you use a 32 bit operating system. Let alone a vanilla box.
So let’s do this instead…
- Download your favorite Linux distribution (please choose 64 bits – we ain’t gonna be watching flash movies)
- Install virtualbox and install your Linux Distro – in my case Ubuntu 12.04 Server 64bits
If you wanted to share this virtual machine in its vanilla state we could package it like this:
vagrant init vagrant package --base virtualmachinename --vagrantfile Vagrantfile
That is overly simplified I suggest you get familiarized with packaging boxes in vagrant.
And you are done! And now with such a nice, fresh virtual machine to play with, we can go ahead and setup all the things we need in our development environment. The main problem is that this vagrantbox isn’t really useful. If someone else joins the project, they’ll have to go through whatever manual setup steps we did to get the dependencies installed on their own vanilla flavored box and remember we don’t want to spend another 4 hours on this or have to explain how to do it. We love automation and we are gonna make this happen one way or another.
Not to worry though we are not going to invoke bash or vala, Vagrant has the perfect solution for this: Provisioning – perfect we have half of the solution already in place – see we are good at this.
Provisioning allows you to automate the setup of your development environment using either Puppet or Chef. Puppet is the older brother and has more plugins… to me puppet is like perl, very powerful but extremely hard to learn. Chef is more like Ruby… well I am not sure what is your choice but I am going with the blue pill.
The Knife and the book
Chef is a provisioning tool, and as you might expect it makes it possible to automatically configure a machine into a specific state (read: it automates setups – holly cow, that’s going to be in the exam!).
In keeping with the culinary metaphors rolling Chef has recipes which represent a specific configuration (e.g.: setting up an Apache server). Recipes are organized into cookbooks, which are really just containers for all those configuration options.
To keep things simple, and within my abilities, I am going to be using Chef Solo.
When you looked at the Vagrant Getting Started documentation for Provisioning you might have noticed the following use of Chef Solo to provision their sample box:
Vagrant::Config.run do |config| config.vm.box = "lucid32" # Enable and configure the chef solo provisioner config.vm.provision :chef_solo do |chef| # We're going to download our cookbooks from the web chef.recipe_url = "http://files.vagrantup.com/getting_started/cookbooks.tar.gz" # Tell chef what recipe to run. In this case, the `vagrant_main` recipe # does all the magic. chef.add_recipe("vagrant_main") end end
This kind of usage is great for a “Hello World” example, cool – let’s bypass the learning curve and do something fun and bold, because I am already feeling you are getting bored.
Ruby is something amazing – because it pretty much has all the great tools in the world. So you know we have cookbooks and who is in charge of taking care of the books!? The Librarian.
Yeah ruby has a great gem already to help us handle cookbooks and all that beautiful code in vagrant land.
gem install librarian librarian-chef init
To set the stage a bit, let’s say we’re starting a Magento project, let’s get dirty:
git clone https://github.com/opscode/cookbooks.git
That repo is deprecated but it serves the purpose of this tutorial – hey I said let’s get dirty.
Let’s get magento:
git clone https://github.com/LokeyCoding/magento-mirror.git latest
I am assuming you have the web server set up and can continue from here… if not we are going to do a follow-up article for nginx and percona.
Essentially we had Librarian or git pull down all those cookbooks and install them into our project. Now we just need to setup Vagrant to provision our environment, in our Vagrantfile make sure you have:
Vagrant::Config.run do |config| config.vm.box = "demo64" config.vm.box_url = "http://community.kingletas.dev/vagrant/demo64.box" config.vm.network :hostonly, "10.1.0.11" config.vm.provision :chef_solo do |chef| chef.cookbooks_path = ["cookbooks"] chef.add_recipe "nginx" chef.add_recipe "mysql" chef.add_recipe "php" end end
Essentially another hello world example because we’re just telling Vagrant to provision using Chef Solo, telling it where to find our cookbooks, and which recipes to use. After that we’ve got those changes in place, we run vagrant up to have Vagrant initialize and provision our virtual machine.
So what have we really accomplished here? Well, we’ve created a simple, automated, and portable way for you to set up all the dependencies for your project without cluttering your system.
Now to share it:
vagrant box add demo64 http://community.kingletas.dev/vagrant/demo64.box vagrant init vagrant up
Again over simplified – refer back to packaging.
However here is how I do my setups:
I choose whatever OS I will use – install everything and make sure is working properly and then package and share it. I love the cookbooks but I love my food to be ready when I am hungry. Of course this is only for my main course, dessert and coffee comes from a recipe.
OK… so what now… go read some more because this is just me trying to combine Ruby, VagrantUp, Chef and Magento into a blog post which by now I have realized was not enough.