Today I discovered how to use Vagrant. I’ve seen the term tossed about here and there, and gave a quick glance at it – even installed it – but never actually dug in. There were a few key concepts that weren’t upfront that made me uncomfortable with how it works.

Today, I started a new Ruby project with some teammates and am looking over various options to do my development. At my office, I am on a Windows box, but would strongly prefer to be hacking away in OSX or Ubuntu. I originally set up a VM for a full desktop Ubuntu to run RubyMine in, but the “remote interpreter” feature and “vagrant” stuff kept haunting me. I decided now might be the right time to get caught up.

In short summary, Vagrant setups an OS VM just for your targeted application.

It uses a few nifty tricks to get the job done. Really, it’s no different than creating a new VM, installing an OS with some basic default settings, and then sharing a folder on your host machine to the guest, and mounting it somewhere.

Here’s the details:

Vagrant is a tool for building complete development environments. It abstracts the development environment away from the project itself, and allows developers to share that environment with just a few lines of text in a configuration file. This makes it easy to store in source control, and share with everyone.

No more “Well, it worked on my machine!”

You download the environment image, and get a full virtual environment up and running, already configured to run a project with just a few commands.

Black magic?

Yep. Exactly. Voodoo. Here are the ingredients:

  • A configuration file shared via source control instructs Vagrant what it needs. It includes a reference to a base VM image and some extra configuration on how to set it up.
  • The project folder you initiated from is mounted into the guest VM at /vagrant. This isn’t a symlink or anything – these literally are the same files from your host. You can edit files with tools from the VM, or your host OS. A change to a file from the VM is a change to the file in your Host. Rubymine can even hook into the remote ruby interpreter. Magic.

Using Vagrant

Install

To cast the magic missile, first install the following tools:

If you are using Windows, I highly recommend installing Git for Windows, as it includes the SSH command, which is immensely valuable when using Windows Vagrant with a Linux guest. During install, it will ask if you want to install the Git Tools into Windows CMD. You should probably just say yes, or plan on doing all of your Vagranty stuff from Git-Bash.

Up and running

  1. Go to your project directory (or a parent directory) in a terminal. (Windows users can shift+right click in an explorer window to open a command window here.)

  2. vagrant init ubuntu/trusty64 (or any box, usually in a box repository like Hashicorp Atlas )
    • Some magic happens while it downloads the Ubuntu 14.04 VM image. There is no extra config needed. It performs all of it’s tricks on it’s own.
  3. vagrant up
    • This loads the virtual machine, and sets it up for first time use. The first time it hooks up, it takes a little longer than usual, since it has to copy files and get it started for the first time.
  4. vagrant ssh or use an SSH Client of your choice. By default, the address is mapped to localhost:2222. (Windows users: PuTTY is king.)
    • User: vagrant
    • Password: vagrant
  5. You’ll notice that the folder you ran Vagrant from is mounted in your guest at /vagrant/. You can now edit your files however you want!
    • Since you are actually mounting the project folder in the Guest VM at /vagrant/, you can use tools on either operating system. Run the files in a server in the Vagrant image, but edit them with Notepad++ in Windows. Edit a file in vi because that’s how you roll, but access image assets in Photoshop. It’s all the same files!
  6. You can stop your VM with vagrant halt from the host

  7. If you want to scrap the system and start over (totally fine!) do vagrant destroy
  • This works because the project itself is isolated from the OS environment. Your project is a folder mounted in the filesystem, not anything that actually gets destroyed. This makes it really easy to test your project in different environments.

What just happened?

You downloaded a prepackaged image to develop on. A copy was saved to your system. You can

vagrant init ubuntu/trusty64

from any folder and have a totally isolated version of this VM for any project. A full-fledged Virtualbox VM was created – you can even load Virtualbox to see that it is in fact no different than if you had installed it the manual way. No magic here actually, just really smart shortcuts and defaults tied to some really handy commands. By convention, all usernames and passwords are set to vagrant. At first, this sounds like a terrible idea – but it’s intended to be an easy-access disposable environment for development. You aren’t using this for production!

When you init, a Vagrantfile is created in the directory that offers a variety of options to configure the VM. You’ll find things like port forwarding defaults, memory allotment, and steps to provision the system (for instance, installing Ruby, PHP, Apache, etc). By default, the only configuration enabled is to forward port 2222 to 22 to allow SSH access. Anytime your vagrant image is running, you can ssh into localhost at port 2222.

Some helpful commands

The commands I find myself using the most are:

  • vagrant init Create a new Vagrantfile configuration in the current directory.
  • vagrant up Read the Vagrantfile, download the box (image) if it’s not on your system already, execute the provisioning steps, and bring it up.
  • vagrant ssh SSH into your newly created image.
  • vagrant down Shuts down the Vagrant VM.
  • vagrant destroy Destroys the existing VM image (but leaves the Vagrantfile config file). This allows you to fully reset the system in case you did something cray cray.
  • vagrant box list Lists all of the master boxes you have currently installed on your system
  • vagrant global status Lists all of the Vagrant instances you have created.
  • vagrant global status --prune Lists Vagrant instances, but also removes old entries that no longer exist (e.g. you deleted a directory with explorer without destroying the VM first.)

A note on persistence

Each of the boxes that you create are first copied from a master image, such as a base Ubuntu 14.04 Server installation. This copy is it’s own entity and can be modified in any way you wish, just like any other virtual machine. You can install things and tweak it to your content without having to use the Vagrantfile for provisioning. You can open the VM, install a million different things, and generally treat it just like any other VM image. When you want to power it down, just vagrant down. If you are unhappy with the state of affairs, vagrant destroy will take you back to the base box. If you find that you’ve created a new jumping off point for future projects, it’s very simple to create a new base box from your existing box. I did this to start with Ubuntu 14.04, but build a generic Ruby development box, and then a Ruby + Rails dev box.

I liked following this blog post to make the VM as clean as possible before saving it as a new base box. Of course, if efficiency isn’t a concern, it’s literally as simple as vagrant package --base my-virtual-machine. You can now vagrant init my-virtual-machine in any other project directory.