Provisioning your Vagrant machine

This post was published 4 years ago. It may be exremely outdated.
This is just a very short introduction to Vagrant, if you already know a little bit about Chef and Berkshelf you’ll find it disappointing.

We previously saw how to install and use Vagrant but we didn’t talk about how to install applications to that machine. You can use the traditional way and install everything manually compiling it or through a package manager but if you wonder if there is a better way to do this, you’re lucky: there is.

Vagrant supports multiple provisioners. A provisioner is a utility that allows you to automatically install software and change configuration. Although Vagrant supports a bunch of provisioners this post is focused only on Chef.

If you take a look at your Vagrantfile you’ll see this fragment of code near line 90.

config.vm.provision "chef_solo" do |chef|
chef.cookbooks_path = "../my-recipes/cookbooks"
chef.roles_path = "../my-recipes/roles"
chef.data_bags_path = "../my-recipes/data_bags"
chef.add_recipe "mysql"
chef.add_role "web"
# You may also specify custom JSON attributes:
chef.json = { :mysql_password => "foo" }
end

This is the block telling Chef provisioner  what to install and giving some settings to the installer. You can see three different parts in this chunk of code:

chef.cookbooks_path = "../my-recipes/cookbooks"
chef.roles_path = "../my-recipes/roles"
chef.data_bags_path = "../my-recipes/data_bags"

Tells Chef where cookbooks, roles and data bags are located (don’t worry, we’ll talk about it later).

chef.add_recipe "mysql"
chef.add_role "web"

Tells Chef what do you want to install, in this example MySQL and role web (wait for it…).

chef.json = { :mysql_password => "foo" }

Gives Chef some settings it will use when installing the applications, in this example you ask Chef yo use “foo” as password for MySQL.

Cookbooks, roles and data bags

You’ll probably wondering what are those things. Cookbooks are scripts defining the requirements and steps to install to set up some software. A cookbook can be as simple as adding a file to your .bash_profile or as complex and installing NodeJS by installing gcc, git, cloning NodeJS source’s git repository, compiling and then installing it. But again, don’t worry, most of the times you will use a third-party cookbook. A cookbook may contain more than one installation script (usually referred as recipe).

Roles are a way to set up some common settings for different machines. A simple example:  imagine you are developing a platform where there are nodes serving content to users and nodes performing maintenance tasks, but all of them use Ruby. You would create a role “myplatform-node” which tells Chef to install Ruby, RVM and set up the default Ruby version to the version you want to use. If you decide to upgrade to a new Ruby version you just update your role and reprovision the machines. That is much easier and faster than the alternative: manually adding Ruby, RVM and Ruby’s version setting to Vagrantfile of each one of your nodes (note that there are lots of solutions to this situation).

Data bags are global variables that are can be loaded by a recipe.

Recipes

So we know the basic concepts of Chef and we want to install something in our Vagrant machines, what do we have to do know? Search a cookbook containing the recipe to install the software we want, download it, put it in the cookbooks folder and then provision the machine.

When everything is in its place, you just run:

vagrant up
vagrant provision

And Vagrant will start the machine and install everything. Note that the first time you run vagrant up Vagrant will provision the machine, but after that first start you’ll have to manually ask Vagrant to provision it.

Sounds pretty easy, right? Well, think about it. If you have, let’s say, 2 different computers, you’ll have to copy the cookbooks in the right folder in both machines. That’s not a big issue. But what if we talk about our workplace. Distributing those files to each mate’s computer is not the best idea.

But this is just the initial deployment. What if we want to use an updated version of a recipe? We would have to redistribute again the cookbooks. The chance of not being properly distributed is so high that some people have developed a better way to do this: Berkshelf.

Berkshelf

Berkshelf solves this distribution problem with a very simple approach: in a config file named Berksfile you define the URL of the repository where cookbooks will be searched and a list of cookbooks to search and download (optionally you can indicate the version and even a custom path to where the cookbook is located). Berkshelf will process the config file and download (or update) the cookbooks specified in it. When you provision your Vagrant machine Berkshelf will be hooked so instead of provisioning using the paths specified in Vagrantfile, Berkshelf will handle the location of the cookbooks.

Berkfile looks like this:

source "https://api.berkshelf.com"
cookbook "mysql"
cookbook "nginx", "~> 2.6"

First line tells Berkshelf where should it look for cookbooks. The other lines tell Berkshelf which cookbooks should download and which version.

And so, by just distributing the Vagrantfile and Bersfile, anybody will be able to provision the machine with the desired version of desired applications.

Setting up Berkshelf

Assuming you’ve installed Vagrant, you’ll have to install Berkshelf and Vagrant Berkshelf plugin. Then you’ll have to add this line to your Vagrantfile to enable Berkshelf:

config.berkshelf.enabled = true

 

Introduction to Vagrant

This post was published 5 years ago. It may be exremely outdated.

Vagrant is a set of tools aimed to create and configure lightweight and portable development environments. The approach is actually pretty simple: Vagrant offers you a way to create config files which are executed later to set up a virtual machine. The interesting point here is that this machine can be (re)created with just one command and can be configured by changing a couple of Ruby lines in the config file.

What’s the point of this? You can have a development environment identical to the one you usually use in any machine with Vagrant installed. If for any reason you break the development environment (installing unstable packages, misconfiguring anything, etc) you can return to the start by running just one command. But it is not limited to development environment: you can deploy your application in a virtual machine with the same software than the production environment.

Setting up Vagrant and VirtualBox

To use Vagrant you’ll need an external software to actually execute the virtual machines. Vagrant works very well with VirtualBox. Although it also works with VMWare and Parallels (via plugins) we’ll use VirtualBox as it is free and good enough. So first download and install VirtualBox and then download and install Vagrant. Installation process is pretty simple in both cases.

Once Vagrant and VirtualBox are installed we can create our first virtual machine by simply running:

vagrant init

In the folder where we want to store the configuration file (called Vagrantfile).

Setting up Vagrantfile

Before being able to run our virtual machine we have to define some parameters, specifically the name of the box and its URL but before that, what’s a box? A box is basically a base image: an image of a virtual machine that has installed an operating system (and many times the required tools to integrate it with a provider – VirtualBox, VMWare and Parallels are usually referred as providers as they are the applications that actually run the virtual machine: Vagrant just takes care of setting them up). Having a box makes having a virtual machine ready faster as you don’t have to install the operating system.

Boxes have a name and a URL but these parameters only affect the local settings of Vagrant: you can choose the name you want for your boxes, as the URL – name mapping is stored only in your computer.

Open Vagrantfile and look for this line:

config.vm.box = "base"

There you specify that this virtual machine will use the box “base” as starting point. As Vagrant doesn’t now which box it is you have to specify the box URL so that Vagrant can download it. If you create later a new virtual machine and set up the box name to “base” then Vagrant won’t download the box as it would  have downloaded it before.

config.vm.box_url = "http://domain.com/path/to/above.box"

This line will specify the URL of the box. You can find a list of free boxes in vagrantbox.es. You can also create your own boxes, but that’s beyond this article.

You can also tell Vagrant that you want a certain URL associated with a certain box name by running the command vagrant box add <name> <url>:

vagrant box add precise32 http://files.vagrantup.com/precise32.box

Take into account that Vagrantfile is just a Ruby file, so you can modify, read other files, take decisions on the fly and much more. In this file you can set up other settings which are interesting but not essential to run the virtual machine, like port forwarding, folders synced with the host, software to be installed and so on.

Accessing the virtual machine

Once you have chosen a box name and URL you can run it with the command: vagrant up.

vagrant up

This command will start the virtual machine, set up port forwarding, etc. You won’t see any new screen as the virtual machine is run in background. You’ll need SSH to access it, but don’t worry, Vagrant will take care of authentication:

vagrant ssh

Once you are done with the virtual machine you can stop it with:

vagrant halt

If for any reason you want to return to the initial state, removing any change you have done to the virtual machine, you can do it by deleting the virtual machine and recreating it, as easily as:

vagrant destroy
vagrant up

vagrant destroy won’t delete the config file (it’s just a couple of KB) but will remove the image of the machine. So you  actually don’t lose your configuration when running vagrant destroy.

If you want to completely remove the virtual machine, after running vagrant destroy just delete the folder with the config file.