Vagrant and Ansible (part 1)

I am used to have a complete LAMP stack on my development machine, so that I can test my sites on a browser directly while writing code.

It’s probably an old-school way to develop, but it has worked well until recently.

Now I am working on two projects. One is a completely new project, but it needs to run on a Ubuntu 12.04 server but could be tested without problems on a more recent Linux config; the other is some legacy PHP4 code that runs fine on Ubuntu 12.04 with PHP 5.3 but it’s a mess to adapt to PHP 5.5.

I thus decided to give Vagrant a try and install an Ubuntu 12.04 image on Virtualbox. I found a Vagrantfile on the Internet and, allons-y!, everything works.

Then I thought: what would happen if I misconfigured the Vagrantfile, or the server config, or, worse, deleted the wrong file? Let’s study some devops tools!

Some months ago I read a book on Puppet and did some tests, but I found it quite complicated, and I heard Chef is similar. The new kid on the block is Ansible, and, from what I read on the Internet, it looked nice. Of course I tested it.

And then, keeping a terminal window open on the old VM’s Vagrant directory, it happened: a vagrant destroy in the wrong directory.

So I had to rush my Ansible study. :)

Installation

Let’s start from scratch. As root:

aptitude install virtualbox-ose vagrant ansible

You can use virtualbox instead of virtualbox-ose if you need the closed-source version, but it should not be necessary.

I hope I didn’t forget anything. :)

Then just create some directory to hold your Vagrant configs. As normal user:

mkdir -p ~/Vagrant/MyFirstBox
cd ~/Vagrant/MyFirstBox

You are allowed to choose a better name for your box!

But let’s stop and rewind a bit, before continuing.

What is Vagrant? And Ansible??

I will leave to the Vagrant website the complete explanation and just give some rough definitions.

Vagrant is a tool that, given a config file, creates a virtual machine, configures it, and allows you to boot it, ssh into it, shut it down and manage (install, configure, remove, etc.) the software installed in it.

It does that using providers and provisioners.

A provider is a virtualization environment. The most famous is Virtualbox, but I heard Vagrant also support VMWare and Docker.io. I’ve never tried them, though.

A provisioner is a tool that allows you to manage a server from a remote location, in some way. The most famous are Puppet and Chef, but also Ansible, or simply shell commands via ssh.

Why Ansible, then?

Puppet and Chef are great tools. They are extremely powerful, but have one flaw: they need software installed on the guest system (correct me if I’m wrong). Ansible doesn’t, and it’s quite easy to configure.

Vagrantfile

Let’s take a look at the Vagrantfile

VAGRANTFILE_API_VERSION = "2"

unless Vagrant.has_plugin?("vagrant-vbguest")
    raise 'vagrant-vbguest is not installed: vagrant plugin install vagrant-vbguest'
end


Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

    config.vm.box = "precise64"
    config.vm.box_url = "http://files.vagrantup.com/precise64.box"

    config.vm.network :private_network, ip: "192.168.33.20"
    config.vm.network :forwarded_port, guest: 80, host: 8001
    config.vm.synced_folder "~/sites", "/var/www/sites"

    config.vm.provision :ansible do |ansible|
        ansible.playbook = "provision/ansible/site.yml"
        ansible.inventory_path = "provision/ansible/development"
    end

    config.vm.provider :virtualbox do |vb|

        # Show Virtualbox GUI (debug)
        # vb.gui = true
        vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
        vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
    end
end

This is a little more complicated than a basic file. Let’s split it down:

VAGRANTFILE_API_VERSION = "2"

This is just a variable definition. Nothing to see here, move on. Chop-chop!

unless Vagrant.has_plugin?("vagrant-vbguest")
    raise 'vagrant-vbguest is not installed: vagrant plugin install vagrant-vbguest'
end

This is a check I added because I had problems with Ubuntu 12.04’s Virtualbox Guest Additions. They were too old. I needed to upgrade them on every new VM. So what?

I found this great plugin that, on vagrant up, checks the version of the Guest Additions package and installs a new one if available.

This check halts the machine before booting it and gives a hint on how to install the plugin.

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

This is the main Vagrant configuration, using the defined variable to declare the Vagrant version supported.

    config.vm.box = "precise64"
    config.vm.box_url = "http://files.vagrantup.com/precise64.box"

These two lines define the system to be installed and where to find the O.S. base image. There are several places where to find boxes, for example Vagrant Cloud.

    config.vm.network :private_network, ip: "192.168.33.20"
    config.vm.network :forwarded_port, guest: 80, host: 8001
    config.vm.synced_folder "~/sites", "/var/www/sites"

This is basic networking setup. It creates a private network and forwards port 80 on the guest to appear as port 8001 on the host (so that we can just write http://localhost:8001 on the browser. More on this later, as we need to consider name-based Virtualhosts).

It is also “exporting” a directory from the host (the sites directory in our home) to the guest (as /var/www/sites/). We will use it later in our Apache Virtualhosts configuration.

This is a quick way to export all our sites, but we could create different VMs for different sites and export only the specific site. Let’s keep it simple for now.

    config.vm.provision :ansible do |ansible|
        ansible.playbook = "provision/ansible/main.yml"
        ansible.inventory_path = "provision/ansible/development"
    end

This is the Ansible configuration. We will need to create Ansible configs later. Paths are relative to the Vagrantfile directory.

    config.vm.provider :virtualbox do |vb|
        # Show Virtualbox GUI (debug)
        # vb.gui = true
        vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
        vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
    end

This is just a list of some Virtualbox configs. By default my Virtualbox was not configured to activate NAT from the guest to the host, so my VM couldn’t connect to the Internet to download the Guest Additions and the packages I configured through Ansible.

Instead of configuring Virtualbox by hand to activate them I preferred to let Vagrant do it, so that I can just reuse the configuration on other computers or on the server (where I don’t have an XServer to launch the GUI config tool).

Uncommenting the vb.gui line allows to see the guest’s screen during the boot to debug “fail to boot” situations.

See you next time with the Ansible configuration!