Tips for a better Vagrant-based development workflow

I build and destroy a lot of VMs using Vagrant in the course of the day. Between developing Drupal VM, writing Ansible for DevOps, and testing dozens of Ansible Galaxy roles, I probably run vagrant up and vagrant destroy -f at least a dozen times a day.

Building all these VMs would be a pain, and require much more user intervention, if it weren't for a few things I've done on my local workstation to help with the process. I thought I'd share these tips so you can enjoy a much more streamlined Vagrant workflow as well!

Extremely helpful Vagrant plugins

None of my projects require particular Vagrant plugins—but many, like Drupal VM, will benefit from adding at least one venerable plugin, vagrant-hostsupdater. Every time you start or shut down a VM with Vagrant, the relevant hosts entries will be placed in your system's hosts file, without requiring you to do anything manually. Great time-saver, and highly recommended! To install: vagrant plugin install vagrant-hostsupdater

Another plugin that many people have used to provide the fastest filesystem synchronization support is vagrant-gatling-rsync, which uses an rsync-based sync mechanism similar to the one built into Vagrant, but much faster and less resource-intense on your host machine.

Helpful modifications to /etc/sudoers

One major downside to using the vagrant-hostsupdater plugin, or to using NFS mounts (which are much faster than native shares in either VirtualBox or VMWare Fusion), is that you have to enter your sudo password when you build and destroy VMs. You can avoid this gotcha by adding the following lines to your /etc/sudoers configuration (then quit and restart your Terminal session so the new settings are picked up):

# Vagrant configuration.
# Allow Vagrant to manage NFS exports.
Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD = /sbin/nfsd restart
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/ d -ibak /etc/exports
# Allow Vagant to manage hosts file.
Cmnd_Alias VAGRANT_HOSTS_ADD = /bin/sh -c echo "*" >> /etc/hosts
Cmnd_Alias VAGRANT_HOSTS_REMOVE = /usr/bin/sed -i -e /*/ d /etc/hosts
%admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE, VAGRANT_HOSTS_ADD, VAGRANT_HOSTS_REMOVE

Important note: If you're editing sudoers by hand, make sure you edit the file with sudo visudo instead of just editing it in your favorite editor. This ensures the file is valid when you save it, so you don't get locked out from sudo on your system!

This configuration works out of the box on Mac OS X, and only needs slight modifications to make sure it works on Linux distributions (make sure the 'admin' group is changed to whatever group your user account is in).

I've even wrapped up the configuration of /etc/sudoers into my Mac Development Ansible Playbook, so I can automatically ensure all my Macs are configured for an optimal Vagrant experience!

SSH keys inside your VM

If you want to use your SSH credentials inside a Vagrant-powered VM, you can turn on SSH agent forwarding on by adding the following line inside your Vagrantfile:

  config.ssh.forward_agent = true

Drupal VM includes agent forwarding by default, so you can build your VM, log in, and work on Git projects, log into remote servers, use drush, etc., just as you would on your host computer.

Note that I usually don't have fowarding enabled in my own environments, as I treat Vagrant VMs strictly as sandboxed development environments—if I install some software for testing inside the VM as the vagrant user, I don't want it to be able to use my SSH credentials to do anything nefarious! Generally that won't happen, but I like erring on the side of caution.

Summary

What are some of your favorite tips and tricks for Vagrant-based workflows? Any other tricks you know of to solve common pain points (e.g. using the vagrant-vbguest if you have issues with native shares or guest additions)?

Comments

here's some aliases I use for common vagrant commands.

alias v='vagrant'
alias vst='vagrant status'
alias vgst='vagrant global-status'
alias vup='vagrant up'
alias vdes='vagrant destroy'
alias vreset='vagrant destroy -f && vagrant up'
alias vp='vagrant provision'

place in .profile or similar

I noticed when I tried to use Drupal VM I had some issues. The predominant one was that my home dir is encrypted. This meant that the VM refused to use NFS because it can't talk to that partition. Is what you're saying above a workaround for that, or is that a known and undocumented (in the quick start guide) issue? Furthermore I couldn't get the hosts thing to work at all; even entering the IP manually in the browser failed for me, but I don't know what that's about. I did originally find another article that suggested the Vagrant plugin you mentioned above, but when that didn't work too I kinda stopped looking at it. Shame :/

I have my entire home volume encrypted on both my Macs, and haven't had an issue; this is the first time I've heard about NFS issues with a home dir (encrypted or not), but I'd wonder if things would work okay if you shared from a different location on the drive. Also, what OS are you running, and are you using VirtualBox or VMWare Fusion?

If you can't even reach the server by IP address, that sounds like an internal networking issue; the VM uses the 192.168.x range by default, but try switching to 10.0.x.x instead, and see if that works. If you're on Windows, the automatic hostsupdater might not work as well, but hand-editing the hosts file should work. And direct access to the IP address should work.

If not, maybe there are other networking issues with your host configuration—are you using proxies? Using a crazy kind of VPN that takes over hosts/routes?

I think this is what prompted my initial fears (I think I got a similar error but I would have to double check): http://serverfault.com/questions/200759/exportfs-warning-home-user-share...

I eventually used a folder outside of my ~ (I created sudo mkdir /home/dev or something) and dumped the [web root? I can't remember] stuff in there.

I'm running VBox on Ubuntu MATE 14.04. Pretty stable stuff. There's nothing weird about the setup, it's all fresh out of the box, apart from a few installs and the dual boot config (irrelevant).

I'll have to try it again and reproduce I guess.

Seems like while this works on a Mac (I assume) you cannot provision these boxen inside your ~dir, because of the NFS issue I described above. The solution, unfortunately, is to create a dir outside of that (unencrypted) and create the boxen in there.

This is obviously workable-but-not-ideal. If anyone works out a solution to that issue, I'd love to hear from them!

Note: I did finally get https://github.com/thom8/acquia-vagrant-example working and I'm assuming that DrupalVM will also now work given I've assessed and corrected the issues I was having.

I think the vagrant-vbguest plugin is great and seems to fix some random issues that were occurring.

I will definitely check out smerrill/vagrant-gatling-rsync, thanks!

I place this at the beginning of my Vagrantfile to ensure that if I swap machines or I'm sharing my build with a team member we have the correct plugins installed. It's just plain ruby code so it can be done in different ways.

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :
#

# Check for plugins and install if not.
%x(vagrant plugin install vagrant-hostsupdater) unless Vagrant.has_plugin?('vagrant-hostsupdater')
%x(vagrant plugin install vagrant-triggers) unless Vagrant.has_plugin?('vagrant-triggers')
%x(vagrant plugin install vagrant-berkshelf) unless Vagrant.has_plugin?('vagrant-berkshelf')
%x(vagrant plugin install vagrant-vbguest) unless Vagrant.has_plugin?('vagrant-vbguest')
%x(vagrant plugin install vagrant-bindfs) unless Vagrant.has_plugin?('vagrant-bindfs')

Seems to work pretty good for our use cases so far. I have a few more things that I use I may share when I get some time tomorrow, like scaling the memory of your VM to a percentage of memory you have left in your host machine, no sense in punishing people with fast machines :) I also have been using the bindfs vagrant plugin to share my permissions (NFS) for host/guest and it has been working great! I am excited to try out the rsync plugin though to see if it's that much faster. I also work on VPN a lot so I put vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] in my Vagrantfile to share my VPN of my host to my guest.

This is the way I scale, now this is for a VB machine (I really need to a VMware install so I can test it but I like VirtualBox and free is free) so you can't use this exact code for VMware.

Place this first part at the beginning of your Vagrantfile (before your Vagrant.configure statement)

# Get host information from VBoxManage for calculations
hostinfo = `vboxmanage list hostinfo`

Then place this inside your Vagrant.configure

  # Scale factor for memory, basically will use 0.25 25% of avalaible memory.
  scale_factor = 0.35

  # Assign memeory based on a percentage of the host machine's available RAM
  max_memory = hostinfo[/Memory size: (\d+) MByte/, 1].to_i
  guest_mem = (max_memory * scale_factor).to_i
  guest_mem = guest_mem.to_s

Then inside your virtual box configure statement (config.vm.provider :virtualbox do |vb|)

    # RAM.
    vb.customize ["modifyvm", :id, "--memory", guest_mem]

I use a config file to set all of that up but you can adopt it either way, I just like to be able to change the percentages when needed. So depending on the application I'm developing I can swap out the percentages based on what kind of memory the application requires.

Your spam filter is really strict btw, I can't even leave my D.o profile as my homepage.

Your spam filter is really strict btw, I can't even leave my D.o profile as my homepage.

Mollom can be that way :-/ You're not the first one to complain about this. I might try switching back to just using Honeypot, to see if the targeted spam attacks on this site have lessened in the year since I turned on Mollom.

I think it's worth pointing out that when editing /etc/sudoers, you should use sudo visudo to do so. I had never edited that file before, so I just loaded it up in a text editor and inserted the text -- which totally hosed the file and meant I couldn't fix it because I no longer had sudo privileges. Took a little while to figure out how to login as root and restore the file. Anyway, the key is to always and only edit that file with sudo visudo.

Thanks for mentioning that; since I usually use Ansible and set the 'visudo' validation option in my playbooks, I forget about the importance of editing with visudo—will save many people many hours (as you can attest!).