Pages

May 1, 2014

Vagrant: "Development environments made easy."

I've been using VirtualBox as my go-to hypervisor provider. It's usually how I test out Linux ISOs I've downloaded to see if they run before I load said ISO into a USB device. Another thing I've recently used virtual machines for is to create a development server to, for example, host a LAMP stack, which I prefer not to install into my main OS. I do like to use the same tools when developing stuff across the board. This is where Vagrant shines! You basically create a Vagrant VM to get a LAMP server running but use the tools on your host OS (e.g. text editor, IDE, etc.) to edit the web pages that are served by the VM.

Vagrant is a great tool for spinning up VirtualBox VMs as fast as possible. You create a Vagrantfile, a file which holds the settings on how to setup a VM; things like which base box to base your VM off of, to the networking setup or to the shared folders the VM will have with the host machine. The Vagrantfile is written in Ruby code but it is very easy to grok and you don't need to learn the language to create one.

In this post, I gloss over my usage of Vagrant.

Initialization

As I mentioned, using Vagrant is as easy as creating a Vagrantfile file. The best way to create one is to cd in a directory where you want to put the Vagrant instance and run the command vagrant init; this creates an initial Vagrantfile.

    $ cd ~/development/my_sample_project
    $ vagrant init
    $ ls
    Vagrantfile

Configuration

Base Box

It's now time to edit the Vagrantfile. Use your text editor of preference. The first thing I edit is the base box to build off of. As of Vagrant 1.5, there is a (beta) site called Vagrant Cloud which hosts some vanilla boxes. Most of these boxes are, of course, Linux. In this post, I will work with the Ubuntu 12.04 64-bit box by HashiCorp, creators of Vagrant. So, in my Vagrantfile, I set the config.vm.box option like so (note that vagrant init puts this box as the default):

    ...

    Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
      ...

      # Every Vagrant virtual environment requires a box to build off of.
      config.vm.box = "hashicorp/precise64"

    ...

Most of the time, this is the only configuration I do, and the rest I leave to defaults. So you're now good to go; just issue the command vagrant up inside the folder where the Vagrantfile is and Vagrant starts creating the VM for you.

Port Forwarding

Sometimes, I like to use a different port when doing development. Like with Django, the default port used in development is 8000 (if web server used is the Django built-in runserver). So I need to forward port 8000 of the guest to the host OS. It's just as easy as adding the ff. to the Vagrantfile:

    # Create a forwarded port mapping which allows access
    # to a specific port within the machine from a port on
    # the host machine.
    config.vm.network "forwarded_port", guest: 8000, host: 8000

So when I run my Django project inside the VM, going to localhost:8000 in the host's browser will serve the site in the VM.

Shared Folders

By default, Vagrant comes with a shared folder, /vagrant, in the VM which maps to the host directory where Vagrantfile is located (in this example, it would be mapped to ~/development/my_sample_project). This is a great feature because, let's say I have all my web related files (.html, .css, .js, etc.) in this folder, I can use my preferred editor on my host machine, like gedit, to edit these files and changes will take effect in the VM as well.

If ever there is a need to create more shared folders, then it can be done like so:

    # Share an additional folder to the guest VM. The first argument is
    # the path on the host to the actual folder. The second argument is
    # the path on the guest to mount the folder. And the optional third
    # argument is a set of non-required options.
    config.vm.synced_folder "~/data", "/vagrant_data"

With this, the host folder ~/data will be seen in the VM as folder /vagrant_data.

Provisioning

This is a powerful feature of Vagrant, which I'll get into more in the next section.

Installing Packages Into The Virtual Machine

As mentioned above, the VM is based of off a "base" box. Meaning it's just a vanilla Linux box that comes with the minimum requirements to run a Linux machine. So unnecessary software isn't installed and you will have to install them yourself. There are 2 ways of doing this, which I discuss below.

Manual

Once a VM is up-and-running (via vagrant up), Vagrant has a way of getting into it. Inside the same folder where Vagrantfile is, issue the vagrant ssh command. This will take you into the VM. Once in, and just like any Linux system, you can install to your heart's content (e.g. sudo apt-get update; sudo apt-get install php5; ...). Now this probably makes sense if you are working alone and not deploying to a team. One of Vagrant's strengths is the deployment of uniform development environments for members of the same development team. It would be cumbersome to do individual vagrant ssh on each and every system and installing stuff manually. That's where provisioning comes to the rescue.

(Shell) Provisioning

Provisions, as I understand it, is a way to automatically install packages (among other things). Here's what it says on their documentation page:

Vagrant support configuration management tools like Ansible, Chef and Puppet but I really didn't want to learn a whole new tool just to use Vagrant (most likely because I'm impatient, perhaps). Good thing Vagrant comes with "shell" provisioning or you can use a shell (BASH) script to do provisions. I am not an expert with BASH scripting but I don't need anything fancy (at the moment) for what I need. So the first thing to do is create a shell script file, like provision.sh and put it in the same folder as Vagrantfile. Here's a sample shell script:

    #!/bin/bash

    # Update repos
    sudo apt-get update

    # Install Apache web server
    sudo apt-get install apache2

    # Install PHP 5
    sudo apt-get install php5

And then add the following entry to the Vagrantfile:

    # Enable provisioning using the plain,
    # old shell script
    config.vm.provision "shell", path: "provision.sh"

When vagrant up command is run, it will look for the provision.sh file and then run its contents like a shell script. I don't know if it is necessary to put the sudo command in there because AFAIK provisioning is run as root.

Conclusion

Vagrant is an awesome tool, especially if deploying within teams. All you really need to send the team is the Vagrantfile, and optionally the "provision.sh" file, have team members do a vagrant up on their host system and you are assured of a uniform development environment. Any changes to the environment just needs updating of the necessary files, resend to the team and everything's synchronized.

You can basically do all the VM creation manually thru VirtualBox software and creating all those things but using Vagrant saves you a lot of time. Vagrant also supports other hypervisors, like VMWare so if that's what you prefer, then you are covered.

Anyway, thanks for reading and you can leave some feedback in the comments below.

No comments:

Post a Comment