Per virtual machine, vagrant uses a directory with a Vagrantfile in it. As a convention, I place my vagrant directories as subdirectory inside ~/vm/. The name of the subdirectory (I’ll use “django” as an example in this blog post) is the name I use for the virtual machine. So ~/vm/django/Vagrantfile is the vagrant file for my “django” virtual machine.
I have one other (“barebones”), but I already know I’m also going to make a “php” one for three mysql/php sites that I sometimes do a bit of work on. Those end up in ~/vm/php/ and so.
Everything that’s not in git (/svn/hg/bzr) doesn’t exist, so I’ve versioned my ~/vm/ directory. I ignore (.gitignore) the django/php/barebones directories. The Vagrantfiles in those directories are symlinks to ~/vm/vagrantfile_django and so on. There’s a README.txt to help me set it all up when I move to a new computer.
I also have a fabfile for setting up the (django) box automatically. Some of the things the fabfile does:
I edit my code locally on OSX and I prefer to continue doing that. I also sometimes want to copy downloaded files directly to my source code. Or edit images in an OSX image editor.
So: I want to have some part of my directory structure available both in OSX and inside the virtual machine. I’ve handled that in my Vagrantfile. The file is mostly the vagrant-provided default one. The relevant filesystem line is:
# Share an additional folder to the guest VM. The first argument is # an identifier, the second is the path on the guest to mount the # folder, and the third is the path on the host to the actual folder. config.vm.share_folder "v-data", "/vagrant", ".", :nfs => true
This mounts the ~/vm/django/ folder on OSX to /vagrant/ inside the virtual machine (with NFS), making them available on both. I checkout my source code in /vagrant/some_category/some_project on the virtual machine, which ends up as ~/vm/django/some_category/some_project on OSX.
Note that I use checkoutmanager to create and update my svn/git/hg checkouts, so it was simple for me to split its configuration. I have a separate checkoutmanager config for my django virtual machine and one for OSX.
Vagrant provides a vagrant ssh command that gives you an ssh shell for the virtual machine in whose directory you are. But I don’t want to cd to a directory first. So I set up a hostname and ssh config for my virtual machines. I can do ssh django now to get inside my virtual machine.
126.96.36.199 django 188.8.131.52 barebones 184.108.40.206 php
Host django HostName 220.127.116.11 User vagrant ForwardAgent yes Host barebones HostName 18.104.22.168 User vagrant ForwardAgent yes Host php HostName 22.214.171.124 User vagrant ForwardAgent yes
The User line logs me in as user “vagrant” even though I’m “reinout” in OSX. And “ForwardAgent” lets me re-use my ssh key if I connect to servers from within the virtual machine.
I have emacs (emacs server) running all the time and open files in emacs from the commandline. And I want to do git add from the commandline. So I want to be inside the actual OSX source directory when working, not inside some ssh session inside the virtual machine: I cannot access my OSX emacs from there.
All fine, as I’ve set up my directories the right way (see above).
But... what about running commands? Starting django? Running a buildout? I need to do that inside the virtual machine: that’s why I set it up in the first place.
That’s where a tiny utility I made comes in. I use fabric quite a lot. Fabric allows you to execute commands remotely via ssh. Hey, that’s just what I need. I know my own conventions for filesystem placement, so I can figure out whether my shell is inside a vagrant directory (~/vm/django/somewhere/) and how to map that to a directory (/vagrant/somewhere/) inside the right virtual machine (“django”).
~/vm/django/utils/checkoutmanager $ vc bin/test [django] Executing task 'run_cmd' [django] run: bin/test [django] out: Running tests at level 1 [django] out: Running zope.testing.testrunner.layer.UnitTests tests: [django] out: Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds. [django] out: Running: [django] out: ......................... [django] out: Ran 25 tests with 0 failures and 0 errors in 0.044 seconds. [django] out: Tearing down left over layers: [django] out: Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
It runs the bin/test command inside the correct directory inside the correct virtual machine.
As an extra proof, here’s the pwd (“print working directory”) command output:
~/vm/django/utils/checkoutmanager $ vc pwd [django] Executing task 'run_cmd' [django] run: pwd [django] out: /vagrant/utils/checkoutmanager
Works like a charm!
I’m pretty happy with my setup and with vagrant. It took a few days of finding out the right way to use it, but I’m settled now. The vc command coupled with a good filesystem layout works fine in practice.
And I’m happy that I can now use ubuntu to manage all those pesky OS-level dependencies! And that I can still use all the OSX goodies.
My name is Reinout van Rees and I work a lot with Python (programming language) and Django (website framework). I live in The Netherlands and I'm happily married to Annie van Rees-Kooiman.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):