In this article I present the top Vagrant plugins which you should have. Those Vagrant plugins will make working with virtual machines much easier.

Introduction

Vagrant is a very useful tool which abstracts virtual machine providers. It has a lot of features and is open source. If you don’t know it yet, then go directly to the getting started section of the Vagrant project page.

Vagrant is popular but not everyone knows that it’s extensible. Yes, Vagrant can be tuned! And you do this with plugins. And some of them are really awesome!

Discover with me the magic of most wanted Vagrant plugins.

How To Install a Vagrant Plugin

Vagrant plugins can be installed with this command:

vagrant plugin install vagrant-example-plugin

If You want to read more about Vagrant plugins visit this documentation section.

Vagrant Cachier Plugin

vagrant-cachier enables caching for different package managers on many Linux distributions. You will love this plugin if You play a lot with provisioning!

You can find the Vagrant cachier plugin project on Github.

Basic Understanding

When this plugin is enabled and I update one of my Ubuntu VM’s with apt-get update or install any packages with apt-get install [package], any other VM which uses the same base box, will reuse the downloads. This leads to faster provisioning. And the reason for that is because the updates/packages are cached. This brings a little bit of Docker goodnes into the world of Vagrant.

The diagram below helps you understand this simple but effective logic:

Vagrant Cachier Plugin - deb packages overview

Requirements

  • NFS
  • Vagrant 1.4+

Installation

Install the vagrant-cachier plugin with the following command:

vagrant plugin install vagrant-cachier

Usage

Enable it by extending Your Vagrantfile like in the example below:

 1 # -*- mode: ruby -*-
 2 # vi: set ft=ruby :
 3 
 4 # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
 5 VAGRANTFILE_API_VERSION = "2"
 6 
 7 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
 8   # Every Vagrant virtual environment requires a box to build off of.
 9   config.vm.box = "ubuntu/trusty64"
10 
11   # Configure vagrant-cachier plugin
12   if Vagrant.has_plugin?("vagrant-cachier")
13     # Configure cached packages to be shared between instances of the same base box.
14     # More info on http://fgrehm.viewdocs.io/vagrant-cachier/usage
15     config.cache.scope = :box
16 
17     # OPTIONAL: If you are using VirtualBox, you might want to use that to enable
18     # NFS for shared folders. This is also very useful for vagrant-libvirt if you
19     # want bi-directional sync
20     config.cache.synced_folder_opts = {
21       type: :nfs,
22       # The nolock option can be useful for an NFSv3 client that wants to avoid the
23       # NLM sideband protocol. Without this option, apt-get might hang if it tries
24       # to lock files needed for /var/cache/* operations. All of this can be avoided
25       # by using NFSv4 everywhere. Please note that the tcp option is not the default.
26       mount_options: ['rw', 'vers=3', 'tcp', 'nolock']
27     }
28     # For more information please check http://docs.vagrantup.com/v2/synced-folders/basic_usage.html
29   end
30   # @end: Configure vagrant-cachier plugin
31 
32   config.vm.provision "shell", inline: "apt-get update --fix-missing"
33   config.vm.provision "shell", inline: "apt-get install nginx -y"
34 
35   config.vm.define "web1", primary: true do |web1_config|
36     web1_config.vm.network "private_network", ip: "192.168.90.11"
37   end
38 
39   config.vm.define "web2" do |web2_config|
40     web2_config.vm.network "private_network", ip: "192.168.90.12"
41   end
42 end

Note
Next steps will be based on the Vagrantfile presented above.

Now spin up one of Your VM’s which does some provisioning:

vagrant up web1

Then check out the ~/.vagrant.d/cache host directory. You will find there cached downloads like in the example below:

$ tree ~/.vagrant.d/cache
└── ubuntu
    └── trusty64
        ├── apt
        │   ├── fontconfig-config_2.11.0-0ubuntu4.1_all.deb
        │   ├── ...
        │   ├── nginx_1.4.6-1ubuntu3.1_all.deb
        │   ├── nginx-common_1.4.6-1ubuntu3.1_all.deb
        │   ├── nginx-core_1.4.6-1ubuntu3.1_amd64.deb
        │   └── ...
        ├── apt_lists
        │   ├── archive.ubuntu.com_ubuntu_dists_trusty_main_binary-amd64_Packages
        │   └── ...
        └── ...

Now start the second machine. This one will reuse the cache:

vagrant up web2

It should boot faster because it doesn’t need to download the updates and the nginx package.

Isn’t it great?

But that’s not everything. The vagrant-cachier plugin supports also other package managers:

  • apt-cacher
  • apt-lists
  • apt
  • chef
  • composer
  • generic
  • npm
  • pacman
  • rubygems
  • rvm
  • yum
  • zypper

If You are interested in deeper understanding how this plugin works visit this documentation page.

Is it Really Faster?

Yes it is. Here are some statistics:

$ time vagrant up web1
real    1m49.664s
user    0m8.164s
sys 0m4.679s

$ time vagrant up web2
real    1m20.674s
user    0m8.214s
sys 0m4.949s

About 30 seconds faster.

And we installed only one package. The cache has only 103 MB:

du -sh ~/.vagrant.d/cache/ubuntu/trusty64/
103M    /home/czerasz/.vagrant.d/cache/ubuntu/trusty64/

Imagine how much time You can save when building more complex machines.

You can find more benchmarks here.

Vagrant Host Manager Plugin

vagrant-hostmanager makes it possible to “talk” between VM’s by their host names.

You can find the Vagrant host manager plugin project on Github.

Basic Understanding

To make the network communication based on host names possible, the vagrant-hostmanager plugin adjusts the /etc/hosts file on the host and guest machines.

Requirements

  • Vagrant 1.1+

Installation

Install the vagrant-hostmanager plugin with the following command:

vagrant plugin install vagrant-hostmanager

Usage

Enable it by extending Your Vagrantfile like in the example below:

 1 # -*- mode: ruby -*-
 2 # vi: set ft=ruby :
 3 
 4 # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
 5 VAGRANTFILE_API_VERSION = "2"
 6 
 7 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
 8   # Every Vagrant virtual environment requires a box to build off of.
 9   config.vm.box = "ubuntu/trusty64"
10 
11   # Configure vagrant-cachier plugin
12   if Vagrant.has_plugin?("vagrant-hostmanager")
13     config.hostmanager.enabled = true
14     config.hostmanager.manage_host = true
15     config.hostmanager.ignore_private_ip = false
16     config.hostmanager.include_offline = true
17   end
18   # @end: Configure vagrant-cachier plugin
19 
20   config.vm.define "web1", primary: true do |web1_config|
21     web1_config.vm.network "private_network", ip: "192.168.90.11"
22     web1_config.vm.hostname = 'web1'
23 
24     config.vm.provision "shell", inline: "echo 'web1' > /home/vagrant/index.html; chown vagrant:vagrant /home/vagrant/index.html"
25   end
26 
27   config.vm.define "web2" do |web2_config|
28     web2_config.vm.network "private_network", ip: "192.168.90.13"
29     web2_config.vm.hostname = 'web2'
30   end
31 end

Note
Next steps will be based on the Vagrantfile presented above.

Start the VM’s:

vagrant up

Let’s audit our /etc/hosts files.

On the host we can see adjustments done by the vagrant-hostmanager plugin:

$ cat /etc/hosts
...

## vagrant-hostmanager-start id: dbf96559-0f67-4d15-92a5-c41f255cbfc8
192.168.90.11   web1
192.168.90.12   web2
## vagrant-hostmanager-end

On the guest as well:

$ vagrant ssh web1 -c 'cat /etc/hosts'
...

## vagrant-hostmanager-start
192.168.90.11   web1
192.168.90.12   web2
## vagrant-hostmanager-end

Now, let’s run a simple static server with python on web1:

$ vagrant ssh web1
$ python -c 'import BaseHTTPServer as bhs, SimpleHTTPServer as shs; bhs.HTTPServer(("0.0.0.0", 8000), shs.SimpleHTTPRequestHandler).serve_forever()'

It will serve the /home/vagrant/index.html file which we created during the provisioning process.

Open a new terminal. Finally we can request the static server on web1 from web2 by it’s host name:

$ vagrant ssh web2 -c 'curl web1:8000'
  web1

Cool stuff!

Tip
If You change the private network ip of any box remember to execute vagrant halt and vagrant up afterwords. vagrant reload won’t do it.

Call To Action

Do You know any other amazing Vagrant plugins? Let me know and I will add them to this list.

Contact Me

Resources: