ik

Ivan Kusalic - home page

Vagrant: Development Environment

In the blog post “Vagrant: Intro”, I’ve given a short introduction to Vagrant and shown an example how it could be used. (If you haven’t read that one, you should check it out.) In this post I’ll show you how I’ve set up my personal, on-demand, Linux development environment.

By the end of this guide, you’ll have Ubuntu VM with Git, Python with Pip, and Ruby with RVM.

The source code is available on github1.

Main ingredients

Setting up personal development environment involves the following elements:

  • Vagrant – spawns and prepares Linux virtual machine
  • Chef – handles most of VM provisioning
  • Personal dotfiles – repository with desired custom settings

So let’s get started.

New project

Let’s initialize a new vagrant project:

1
2
3
4
mkdir devenv  # choose the name you like
cd devenv
git init  # optional, but recommended
vagrant init

If you’re using RVM to manage Ruby, create the .rvmrc:

1
2
echo 'rvm --create use ruby-2.0.0-p247@devenv' > .rvmrc
cd .

I’m also using the vagrant-cachier plugin to speed up the box provisioning. If you didn’t use vagrant-cachier till now, you’ll need to install it:

1
vagrant plugin install vagrant-cachier

Let’s add some basic settings to Vagratfile:

Vagrantfile, take 2
1
2
3
4
5
6
7
8
9
10
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure('2') do |config|
  config.vm.box = 'precise64cloudimagesubuntu'
  config.vm.box_url = 'http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box'

  config.cache.auto_detect = true
  config.cache.scope = :machine
end

I’ve decided to go with Ubuntu Precise, but you can use whatever image you like. The cachier plugin is set to auto-detect needed caching buckets (e.g. Apt, Chef, RVM, etc.) and to use machine scope to prevent potential problems when multiple VM’s are used.

At this point you can start up the virtual box and ssh into it:

1
2
vagrant up
vagrant ssh

If you see the warning about mismatching guest additions, it’s probably safe just to read the warning and then ignore it in the future.

If you are using git, you probably want to create the .gitignore file with the following content:

.gitignore
1
.vagrant/

Provisioning the VM

Now that some basic settings are in place, it’s time to use Chef to provision the VM.

Chef can be used with different setups. Here I’m going to use Librarian-Chef to manage the Chef cookbooks and chef-solo to run the recipes.

So let’s first install Librarian-Chef. Create a file called Gemfile with the following content:

Gemfile
1
2
3
source 'http://rubygems.org'

gem 'librarian-chef'

And run: bundle install. If you do not have Bundler installed, install it by running: gem install bundler.

Like Bundler and Gemfile, Librarian-Chef uses Cheffile, so let’s create it with the desired cookbooks:

Cheffile
1
2
3
4
5
6
7
8
9
# -*- mode: ruby -*-
# vi: set ft=ruby :

site "http://community.opscode.com/api/v1"

cookbook 'apt'
cookbook 'git', git: 'git://github.com/fnichol/chef-git.git'
cookbook 'python'
cookbook 'rvm', git: 'git://github.com/fnichol/chef-rvm.git'

You can see I’ve decided to install Apt, Git, Python (comes with Pip) and RVM for Ruby. So let’s download those cookbooks: librarian-chef install

If you are using Git run: (echo cookbooks/ && echo tmp/) >> .gitignore

Finally, modify the Vagratfile so it has the following content:

Vagrantfile, take 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure('2') do |config|
  config.vm.box = 'precise64cloudimagesubuntu'
  config.vm.box_url = 'http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box'

  config.cache.auto_detect = true
  config.cache.scope = :machine

  config.vm.provision :shell, inline: 'gem install chef --no-rdoc --no-ri'

  config.vm.provision :chef_solo do |chef|
    chef.add_recipe 'apt'
    chef.add_recipe 'git'
    chef.add_recipe 'python'
    chef.add_recipe 'rvm::vagrant'
    chef.add_recipe 'rvm::system'
    chef.add_recipe 'rvm::gem_package'

    chef.json = {
      rvm: {
        default_ruby: 'ruby-2.0.0',
        vagrant: { system_chef_solo: '/opt/vagrant_ruby/bin/chef-solo' }
      }
    }
  end
end

Here I’m specifying Chef recipes that will be used, with custom setting for RVM.

Conclusion

Now once again start the VM and ssh inside:

1
2
vagrant up  # run 'vagrant destroy' and try again if the VM is running
vagrant ssh

Note: you can safely ignore the warning “stdin: is not a tty”, if you get it while starting the VM.

The VM should now have Git, Python with Pip, and Ruby with RVM properly installed. Apt should also be up to date.

You can confirm this by running:

1
2
3
4
5
git --version
python --version
pip --version
ruby --version
rvm --version

To suspend the VM, run vagrant suspend.

If you have questions/suggestions/comments, or just want to chat, send me an email.

That’s all for this post. If you wont to see an example how to use Vagrant to experiment and explore other software, take a look at Using Thoughtworks’ Go (Continuous Delivery) With Vagrant.


  1. By the time you read this, repo could be ahead of this guide