As developers, oftentimes we want or need our working environment to be an exact match of the production environment. Using MAMP or your Mac’s built in server simply won’t cut it because there would be too much variation in software versions and/or too much configuration differences between projects. This is especially true when your project is running a complex or specific infrastructure. Lucky for us, there’s Vagrant!
This post serves as a basic overview of Vagrant, a guide to some handy resources and some tips we’ve learned since we started using it. It kinda touches on everything!
Vagrant is written in Ruby and used for creating and configuring virtual development environments. Although it can use other virtual machine software, the most commonly used is VirtualBox. VirtualBox allows you to create a virtual server right on your machine. This allows you to run a Linux server (or whatever else you would like) on your personal Mac or PC. Vagrant is essentially the glue between provisioning software such as Puppet or Chef and VirtualBox.
Vagrant helps you configure your network configurations for VirtualBox as well as run the necessary scripts to provision your virtual machine. The beauty of Vagrant is that once you have your provisioning scripts ready and your Vagrantfile set up, you can spin up a VM with a simple command (vagrant up) and easily dispose of it with (vagrant destroy).
The benefit of this approach, as opposed to manually configuring VirtualBox, is that spinning up and tearing down environments is trivial. When your project is complete you can simply destroy the VM. Six months later, when the project picks back up, just run
vagrant up and you pick up right where you left off.
Vagrant is also a great for onboarding new developers. How many times have you wished a new developer could just hit the ground running and not have to spend hours setting up their own development environment? This can be handled by including your Vagrant provisioning scripts in your project’s code repository.
When a new developer needs to get rolling, they simply checkout the project’s repository (as they normally would), navigate to the proper directory and run "vagrant up". A few minutes later they have the same development environment as everyone else on the team! This also eliminates the old adage, “It worked on my machine”. Now everyone’s development environment should be identical. What works on one developers machine, will work on another developers machine, no matter their primary platform.
Provisioning your Vagrant Machine:
Another nice feature of Vagrant is that you have several options for provisioning your VM.
The most common options are:
- Chef https://www.chef.io/chef/
- Puppet https://puppetlabs.com/
- Ansible http://docs.ansible.com/guide_vagrant.html
- Shell Script (Probably the best starting point if you aren’t familiar with any the above configuration tools.)
Better yet, you can also use multiple provisioning options on the same VM. For example, you can provision your box using Chef and then finish your provisioning with a shell script afterwards! I have found this particularly handy when I am using Chef recipes that I’ve found in the wild that take me 90% of the way but I still need something a little more specific.
Here is an example of how you might use Puppet and a shell script together:
config.vm.provision :shell, :path => "bootstrap/bootstrap.sh" config.vm.provision "puppet" do |puppet| puppet.module_path = "modules" end
Why is this useful? Let’s say you want to provision a CentOS virtual machine using puppet. Your VM needs puppet installed on it before it can do the provisioning. So your provision requires two steps:
- Run a shell script to install puppet (bootstrap/bootstrap.sh).
- Run your Puppet provisioning.
First the the shell script would run and install Puppet:
sudo yum install -y http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs sudo yum install -y puppet-2.7*
Then Vagrant would run the Puppet provisioning:
config.vm.provision "puppet" do |puppet| puppet.module_path = "modules" end
Networking is one the trickiest parts of using a Vagrant setup. Some key concepts to consider are:
Forwarded ports allows you to map ports on your host machine to ports on your guest machine (VM). This is useful direct access to guest ports or services from your host machine. For example, if you wanted to visit a site served from Apache on your VM from your host machine’s browser, you’d want to map host port 8080 to guest port 80 on your VM. This would allow you to hit
http://localhost:8080 on your host and have it automatically forwarded to port 80 on the guest. Here’s how you do it:
config.vm.network "forwarded_port", guest: 80, host: 8080
As your VM gets more complex, you may need to explicitly forward more ports for other services, such as Varnish or MySQL.
Private Network configures your VM with an address from the private address space (something like 192.168.92.68). Private Networks are used when you do not want other machines on the network able to access your virtual machine. The easiest way to set this up is to let the IP address be assigned to you via DHCP. That is as simple as adding ‘config.vm.network "private_network", type: "dhcp"’ to your Vagrant file.
In some instances, however, you may want to define a static ip address for your VM. This can can be done with the following snippet:
config.vm.network "private_network", ip: "192.168.92.68"
In this example, it’s important to make sure the ip address does not conflict with any other addresses on the network. If you are unable to access your virtual server, you may need to check your /etc/hosts file or ping the virtual machine’s intended IP address from the command line to make sure that requests for that IP are routed to your virtual machine.
Sometimes, it’s handy to serve your VM over your public network. This might be useful when you need to access your site or application from other devices or when other stakeholders need to access, test, etc. In this case, you would use the public network option. Vagrant will prompt you for which network interface you would want to use, or you can specify it like this:
config.vm.network "public_network", bridge: 'en1: Wi-Fi (AirPort)'
A Synced Folder is a folder that is accessible to both your host machine and your virtual machine. This is particularly useful for syncing your host machine’s codebase changes to your VM. Without synced folders, you’d have to directly checkout your project’s codebase onto your VM or work directly on your VM. Neither of these are ideal.
With Synced Folders, your workflow doesn’t have to change. Editing files, making commits, etc. all happens on your host machine and your VM will reflect those changes in real time. The files on your host machine are essentially mapped to a directory on your guest machine.
Here’s how to do it:
config.vm.synced_folder "path/to/host/codebase", "path/to/desired/guest/directory", create: true, type:"nfs"
type variable here is very important when it comes to large code bases such as Drupal. If you don’t specify your folder type as "nfs" you may find your site is extremely slow and drush commands take forever. In fact, you will also need to specify this option for Vagrants base mount folder like so:
config.vm.synced_folder ".", "/vagrant", create: true, type: "nfs"
Fortunately there is a plugin for windows users at: https://github.com/GM-Alex/vagrant-winnfsd
There are a lot of Chef and Puppet LAMP environments already available out there in the interwebs.
- Puppet LAMP stack: https://github.com/jrodriguezjr/puppet-lamp-stack
- Chef: https://github.com/r8/vagrant-lamp
- Drupal Specific: https://www.drupal.org/project/vagrant
Quick Start for Drupal:
For those new to Vagrant looking to get a machine up and running quickly for a Drupal project, I recommend checking out The Drupal Vagrant project. This project comes packed with all the bits for running Drupal. Drush, phpMyAdmin, XDebug are all available out of the gate. Even if you end up using your own solution, this will give you a strong place to start.
Further Reading/Helpful Links:
Wrapping (vagrant) Up.
Vagrant is a powerful tool and I’m only beginning to scratch the surface here in terms of covering it thoroughly. We’re now using it on a couple of projects and have found it incredibly useful. Drop us a line in the comments if you have other tips for folks new to Vagrant or other resources worth reading.