If you are here, you are interested in topics such as DevOps, Continuous Processes, and Infrastructures, at least I hope so! This article aims to provide a high-level, simple and practical explanation of what it is Vagrant and how you can use it to improve your workflow.
I’m currently a teacher assistant 👨💻@ Técnico Lisboa, and I’m working closely with Dr. Professor Rui Cruz 👨🏫at the It Infrastructure Management and Administration 🖥, a masters level course of the “Master Degree in Information Systems and Computer Engineering” and “Master Degree in Telecommunications and Informatics Engineering” @ Técnico Lisboa.
The contribution from Dr. Professor Rui Cruz to this article is enormous, being him the main responsible main responsible for the “Setting Up” and “The Experiment” sections.
So, what is Vagrant?
In a very simple way, Vagrant is an open source project that is used for building and distributing virtual environments. This means, essentially, that it allows you to manage and share pre-configured virtual machines.
Use case #1: Focusing on your task 🔭
As a developer, have you already spent too much time setting your environment?
Vagrant makes it really easy to manage virtual boxes. An already all-in-one virtual machine with all the software and dependencies installed is a great way to make developers focused on their tasks. One just needs to create an optimal virtual box, once, and then it can be distributed to collaborators. No need for setting up the environment, as it should be already set up!
In short, you just need to run the machine and focus on the task on hands.
Use case #2: Improving the workflow 📈
As a developer, have you already spent too much time fixing bugs that happen on production, but not in the development environment?
Firstly, one should follow good workflow practices, such as the ones referenced by this insightful article, by Peter Murray. Secondly, we can take the next step in our automation process: having the exact same environment, both in development and production (and the intermediary ones). If this is accomplished, the probability of the production app crashing due to an error that was not spot on the development environment is very little, because the environments are the same.
In short, you can develop without being afraid of errors coming from dependencies and installed software.
Use case #3: Distribution ⭐️
Have you spent some time writing extensive documentation on how to do a setup of a project?
Sometimes it can be frustrating, as there may be lots of aspects to take care: environment variables, software, and specific configurations. If you have the need for a pre-configured environment, this tool will help you.
By packing everything you need on a virtual machine and distributing it, you have done work that others don’t need to (uselessly) replicate.
How does it work?
According to Vagrant:
Environments managed by Vagrant can run on local virtualized platforms such as VirtualBox or VMware, in the cloud via AWS or OpenStack, or in containers such as with Docker.
Vagrant provides the framework and configuration format to create and manage complete portable development environments. These development environments can live on your computer or in the cloud, and are portable between Windows, Mac OS X, and Linux.
In a nutshell, Vagrant manages the environments, and uses, for example, VirtualBox to provide (launch) the machines. Scripts that run after the machines are launched can be configured through several provisioners such as the shell, Terraform, Chef and Ansible. Provisioners are meant to leverage provisioning (installing dependencies), automation, configuration management, and orchestration. This meets the DevOps way of thinking and working.
The following scheme helps us visualize how vagrant works and how it works.
- The user creates a Vagrantfile, which is a declarative file (written in Ruby) that describes the type of machine needed, as well as how to configure and provision that machine. The user uses Vagrant to execute the Vagrantfile.
- Vagrant uses VirtualBox as a provider. It can also use other providers.
- The machine is up.
- Vagrant invokes a provisioner to configure the machine.
- The provisioner provisions the machine. It can be a simple shell script or Ansible, for example.
- One can access the deployed machine by ssh.
That’s it. You can manage and launch virtual machines with a few commands. And its complexity is as much as you want.
Enough theory, let’s do it!
Let’s get to work, ladies and gentleman.
For demonstration purposes, I will follow the first Lab Guide of It Infrastructure Management and Administration course, by Professor Rui Cruz. First, we need to install the required tools to run Vagrant. After that, we will launch a Mininet machine. Mininet allows us to create virtual networks, running real kernel and application code.
In this section, we are going to perform the setup for Windows, Linux and mac OS.
The recommended Package Manager for Microsoft Windows is Chocolatey.
To install Chocolatey, open a privileged (i.e. administrative) Windows Command Prompt (cmd.exe) and execute:
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
Now, install the following dependencies through Chocolatey:
C:\> choco install wget
C:\> choco install git -params “ /GitAndUnixToolsOnPath “
C:\> choco install virtualbox
C:\> choco install vagrant
C:\> choco install xming
Make sure that git executable file path is on the PATH environment variable.
In order for xming (an XWindows server) to work, as we are going to need it later, add the environment variable called DISPLAY, with the value localhost:0.0.
The recommended Package Manager for macOS is Homebrew, similar the Linux aptget or yum http://brew.sh.
If you do not have XCode installed then open Terminal and at the shell prompt type the following:
:~$ xcode -select -- install
To install Homebrew, at the shell prompt paste the script (starting at the ruby invocation) and press ENTER:
:~$ /usr/bin/ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
When it’s done, the shell prompt will say that the installation was successful, and ask you to run brew doctor. Do as it suggests:
:~$ brew doctor
This will make Homebrew inspect your system and make sure that everything is set up correctly.
:~$ brew install wget
:~$ brew install git
:~$ brew cask install virtualbox
:~$ brew cask install vagrant
:~$ brew cask install xquartz
To install the other packages open a Terminal and issue the following commands.
:~$ sudo apt -get install git
Please note that for latest distributions of Ubuntu, a careful install of VirtualBox is required as the package architecture has to match the Linux kernel architecture. Additionally, the VirtualBox package in Ubuntu may have some issues when running in RAM-constrained environments.
For that purpose, you need to ensure that you have the adequate sources referenced for your kernel architecture. Start by editing the sources list issuing the following command:
:~$ sudo nano/etc/apt/sources.list
Add the following line to the list (exemplified for 16.04 ’Xenial’ kernel):
deb http://download.virtualbox.org/virtualbox/debian xenial contrib
According to your distribution, replace ’xenial’ by ’vivid’, ’utopic’, ’trusty’, etc. You also need to add and register the Oracle public key (combined command):
:~$ wget -q https://www.virtualbox.org/download/ oracle_vbox_2016.asc -O- | sudo apt-key add -
:~$ wget -q https://www.virtualbox.org/download/ oracle_vbox.asc -O- | sudo apt-key add -
Now you can add Virtualbox:
:~$ sudo apt -get update
:~$ sudo apt -get install virtualbox -5.2
For Vagrant, there is still an issue and we need to get the latest version (not in Ubuntu repository) by downloading the package from the Vagrant website and then issuing the following command (from the downloads folder, adapt to your version):
:~$ wget https://releases.hashicorp.com/vagrant/2.1.5/ vagrant_2.1.5_x86_64.deb
:~$ dpkg -i vagrant_2.1.5_x86_64.deb
Create a folder called mininet and enter it, as we are using the mininet box.
:~$ vagrant box add
This will create a box with the downloaded image from vagrant.org.
Now, let’s create a Vagrantfile containing our box:
:~$ vagrant init ktr/mininet
The above command will fetch an already prepared Mininet system in an Ubuntu OS.
Without the comments, this is the Vagrantfile created:
$script = <<-SCRIPTsudo apt update
sudo apt upgrade -y
Vagrant.configure("2") do |config|
config.vm.box = "ktr/mininet"
config.vm.provision "shell", inline: $script
Vagrant.configure sets the Vagrantfile version, while config.vm.box sets the box to be used (the one we downloaded). The script is going to run after the machine is launched.
Congratulations! You are almost there. Now, we launch the machine:
:~$ vagrant up --provider virtualbox --provision
This phase may take up a few minutes, depending on the speed of the host system, with an output similar to the following:
Bringing machine 'default ' up with 'virtualbox ' provider ...
==> default : Checking if box 'ktr / mininet ' is up to date ...
==> default : Clearing any previously set forwarded ports ...
==> default : Clearing any previously set network interfaces ...
==> default : Preparing network interfaces based on configuration
default : Adapter 1: nat
==> default : Forwarding ports ...
default : 22 => 2222 ( adapter 1)
==> default : Booting VM ...
==> default : Waiting for machine to boot . This may take a few
default : SSH address : 127.0.0.1:2222
default : SSH username : vagrant
default : SSH auth method : private key
==> default : Machine booted and ready !
==> default : Checking for guest additions in VM ...
default : Guest Additions Version : 4.3.10
default : VirtualBox Version : 5.0
==> default : Mounting shared folders ...
Also, you will see the log coming from the provision script.
Next, we will establish a session with the system using the following command:
:~$ vagrant ssh
The session is established and we will get the machine prompt similar to the following:
Welcome to Ubuntu 14.04.4 LTS (GNU / Linux 3.13.0 -87 - generic x86_64 )
Last login : Sun Sep 20 22:50:28 2017 from 10.0.2.2
A very simple test can then be performed to verify that all is working correctly by issuing the command ’sudo mn’ at the mininet shell prompt, to create a simple network topology of two hosts (h1, h2) and a switch (s1):
vagrant@mininet :~$ sudo mn
*** Creating network
*** Adding controller
*** Adding hosts :
*** Adding switches :
*** Adding links :
(h1 , s1) (h2 , s1)
*** Configuring hosts
*** Starting controller
*** Starting 1 switches
*** Starting CLI:
From this point we can issue the command ’pingall’ to verify if we have connectivity between the hosts:
mininet > pingall
*** Ping : testing ping reachability
h1 -> h2
h2 -> h1
*** Results : 0% dropped (2/2 received )
With the command ’net’ we can verify how the nodes are connected, i.e., host1 is connected by its eth0 port to the switch1 on eth1 port, etc.:
mininet > net
h1 h1 - eth0 :s1 - eth1
h2 h2 - eth0 :s1 - eth2
s1 lo: s1 - eth1 :h1 - eth0 s1 - eth2 :h2 - eth0
Issuing the command ’dump’ we can see the IP addresses of the hosts (10.0.0.1 and 10.0.0.2):
mininet > dump
<Host h1: h1 - eth0 :10.0.0.1 pid =1708 >
<Host h2: h2 - eth0 :10.0.0.2 pid =1712 >
<OVSSwitch s1: lo :127.0.0.1 , s1 - eth1 :None ,s1 - eth2 : None pid =1717 >
<Controller c0: 127.0.0.1:6633 pid =1701 >
To end the Mininet emulation we use the command ’exit’.
mininet > exit
We can now exit the session:
vagrant@mininet :~$ exit
Connection to 127.0.0.1 closed .
In order to stop the Virtual Machine and to verify the global state of all active Vagrant environments on the system, we can issue the following commands:
:~$ vagrant halt
==> default : Attempting graceful shutdown of VM ...
:~$ vagrant global-status
Confirm that the status of the VM is powered off.
You know understand what Vagrant is, how to set up a simple Vagrant file, how to launch a machine and how to use it.
Congratulations! 💯 You reached the end! 🦄