Three developers on three laptops running three PHP builds against three MySQL versions produce bugs that only reproduce for one of them, and a production server that resembles none of the three. Vagrant puts a VirtualBox machine behind a file in the repository, so the environment is checked out with the code.
# Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "precise64"
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
config.vm.network :private_network, ip: "192.168.56.20"
config.vm.synced_folder ".", "/var/www/app", :nfs => true
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "1024"]
end
config.vm.provision :shell, path: "provision/bootstrap.sh"
end
The virtual machine is not really the point — provision/bootstrap.sh is. Once the server build is a script under version control, “works on my machine” becomes a diff, and the same script is what gets run on the real host. Two things cost time. The shared folder is slow: VirtualBox’s own sharing over a tree of several thousand files is slow enough that people give up on the idea entirely, and NFS fixes it at the price of a host-only network and a sudo prompt on every vagrant up. And the provisioning script has to be idempotent, because it re-runs — one that appends a line to /etc/hosts will append it again. Make vagrant destroy followed by vagrant up a routine rather than an event, or the box drifts and stops being the shared one.