Install the Vagrant gem
You need vagrant installed for this process to work. Vagrant depends on a version of ruby we’ll set up using the Ruby Version Manager, as shown below. This can take a while, so be patient. A quick note for mac developers: RVM installs Ruby from source. In order to do so, you will need Xcode installed. You can try using another gcc, but for one-stop goodness, install Xcode and move along.
bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
source ~/.bash_profile
rvm install 1.9.2
rvm use 1.9.2 --default
Next install vagrant
gem install vagrant
Create A Home Base
It is likely you’ll be creating several vagrant boxes (individual machines) as you move along, so it makes sense to keep them organized in one place. Let’s create that now.
mkdir ~/boxes
The boxes name given above is just my convention. You may name that folder anything you like. We’ll refer to this as your boxes directory.
Clone The Opscode Cookbooks
Opscode has a set of cookbooks you’ll use when writing chef scripts. You’ll want to pull these down and keep them within reach.
cd ~/boxes
git clone https://github.com/opscode/cookbooks.git
This will create a directory cookbooks in your base directory containing all of Opscode’s great cookbooks. I suggest deleting the .git folder at the base of this dir and checking your cookbooks into your own source control repo. As you add write cookbooks of your own, you may save them there.
Create A Project Directory
A project directory represents one (or more) VMs associated by a VagrantFile. You’ll learn more about the VagrantFile later in this article. For now, just know that the VagrantFile acts as the configuration for your Vagrant project. In the snippet below, we’ll create a project directory called ProjectDirectory. Choose a name that properly describes the box you’re building. For example, WebServer would be a good Project Directory name.
cd ~/boxes/
mkdir ProjectDirectory
cd ProjectDirectory
Clone the Chef Repo
The Chef Repo is the basic structure required by Chef. Your cookbooks and other important files will be kept here. In the example below, we’ll be turning your Project Directory into a Chef Repo. That’s why we add the . at the end of the git clone command.
cd ~/boxes/ProjectDirectory
git clone https://github.com/opscode/chef-repo.git .
If you run a ls -al command, you’ll notice the following directory structure in your Project Directory now:
ls -al
total 32
drwxr-xr-x 13 timsabat staff 442 Dec 13 12:36 .
drwxr-xr-x 7 timsabat staff 238 Dec 13 12:36 ..
drwxr-xr-x 13 timsabat staff 442 Dec 13 12:36 .git
-rw-r--r-- 1 timsabat staff 18 Dec 13 12:36 .gitignore
-rw-r--r-- 1 timsabat staff 3521 Dec 13 12:36 README.md
-rw-r--r-- 1 timsabat staff 2171 Dec 13 12:36 Rakefile
drwxr-xr-x 3 timsabat staff 102 Dec 13 12:36 certificates
-rw-r--r-- 1 timsabat staff 156 Dec 13 12:36 chefignore
drwxr-xr-x 3 timsabat staff 102 Dec 13 12:36 config
drwxr-xr-x 3 timsabat staff 102 Dec 13 12:36 cookbooks
drwxr-xr-x 3 timsabat staff 102 Dec 13 12:36 data_bags
drwxr-xr-x 3 timsabat staff 102 Dec 13 12:36 environments
drwxr-xr-x 3 timsabat staff 102 Dec 13 12:36 roles
Since we’ll be creating our own git repository in this directory, let’s delete the one provided by the previous clone command.
cd ~/boxes/ProjectDirectory
sudo rm -r .git .gitignore
Initialize your Vagrant environment
Vagrant depends on a file called VagrantFile for configuration information. The following command creates that file.
vagrant init
The ls command will prove the vagrant init call did create your VagrantFile.
Now we’ll create a knife.rb file to control how chef’s knife command interacts with your project.
cd ~/boxes/ProjectDirectory
mkdir .chef
touch .chef/knife.rb
What is knife you ask? Opscode describes this way:
[knife] is used by administrators to interact with the Chef Server API and the local Chef repository. It provides the capability to manipulate nodes, cookbooks, roles, databags, environments, etc., and can also be used to provision cloud resources and to bootstrap systems.
The following values should be present in your knife.rb file.
current_dir = File.dirname(__FILE__)
cache_options( :path => "#{ENV['HOME']}/.chef/checksums" )
cookbook_path ["#{current_dir}/../cookbooks", "#{current_dir}/../site-cookbooks"]
The options you’ve set here tell chef where to create new cookbooks, and how/where to cache your erb templates.
Create your vagrant_main cookbook
In order for vagrant to configure your virtual machine, you must tell it which Chef cookbook to run first. For convention’s sake, we’ll call this cookbook vagrant_main. If you were using hosted Chef instead of chef-solo (Vagrant’s default mode), the would represent the ‘run list’. If you don’t know what that means, no big deal, you don’t have to understand hosted chef to run Vagrant.
We’ll run the following knife command create your vagrant_main cookbook.
cd ~/boxes/ProjectDirectory
knife cookbook create vagrant_main
Observe your handiwork :
cd ~/boxes/ProjectDirectory/cookbooks/vagrant_main
ls -al
and you’ll see output which looks like this:
-rw-r--r-- 1 timsabat staff 88 Dec 14 08:56 README.md
drwxr-xr-x 2 timsabat staff 68 Dec 14 08:56 attributes
drwxr-xr-x 2 timsabat staff 68 Dec 14 08:56 definitions
drwxr-xr-x 3 timsabat staff 102 Dec 14 08:56 files
drwxr-xr-x 2 timsabat staff 68 Dec 14 08:56 libraries
-rw-r--r-- 1 timsabat staff 249 Dec 14 08:56 metadata.rb
drwxr-xr-x 2 timsabat staff 68 Dec 14 08:56 providers
drwxr-xr-x 3 timsabat staff 102 Dec 14 08:56 recipes
drwxr-xr-x 2 timsabat staff 68 Dec 14 08:56 resources
drwxr-xr-x 3 timsabat staff 102 Dec 14 08:56 templates
Each directory here has special meaning to Chef. You and read about what each means by checking out the Opscode cookbook documentation.
Finally, we’ll tell the VagrantFile to run Chef against the vagrant_main cookbook we just created. To do so, open the VagrantFile and change the values
# config.vm.provision :chef_solo do |chef|
# chef.cookbooks_path = "cookbooks"
# chef.add_recipe "mysql"
# chef.add_role "web"
#
# # You may also specify custom JSON attributes:
# chef.json = { :mysql_password => "foo" }
# end
to
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
chef.add_recipe "vagrant_main"
end
Conclusion
You’ve set up a Vagrant Development Environment. Now, write a recipe.