EDITING BOARD
RO
EN
×
▼ BROWSE ISSUES ▼
Issue 20

Getting started with Vagrant

Carmen Frăţilă
Software engineer
@3Pillar Global



OTHERS

How many times have you heard "But it works on my machine" or "But it works on my local"? How long does it take to setup an environment? How many times have you encountered differences between the production and development environments? Imagine an ideal world where all developers work on the same pre-build platform and the development and production platform share the same specs. This world exists and it"s called virtualization. Vagrant is a virtualization tool, which has an answer for all these questions, making this ideal world reality. It can be used to create and configure lightweight, reproducible and portable development environments.

Vagrant is written in Ruby by Mitchell Hashimoto (https://github.com/mitchellh). The project started in 2010 as a side-project, in Mitchell Hashimoto"s free hours. In the next two years Vagrant grew and started to be trusted and used by a range of individuals to teams from large companies. In 2012 Mitchell formed his own company called HashiCorp, in order to develop and to provide professional training and support for Vagrant. Currently Vagrant is an open source project, being the result of hundreds of individuals" contribution (https://github.com/mitchellh/vagrant).

To achieve its magic, Vagrant stands on the shoulders of his giants, by acting as a layer on top of VirtualBox, VMware, AWS, or other provider. Also the industry-standard provisioning tools such as Shell scripts, Chef or Puppet can be used to automatically setup a new environment. Vagrant is usable in projects written in other programming languages such as PHP, Python, Java, C# or JavaScript and can be installed on Linux, Mac OS X, or Windows systems.

Vagrant offers transient boxes that are portable and can move around, with no permanent residence just like a vagrant. If you"re a developer you can use Vagrant to isolate dependencies and their configuration with a single disposable consistent environment. Once Vagrantfile is created you just need to run vagrant up command and everything is up and running on your machine. As an operations engineer, Vagrant gives you a disposable environment and consistent workflow for developing and testing infrastructure management scripts. You can quickly test things like shell scripts, Chef cookbooks, Puppet modules, and more, using local virtualization such as VirtualBox or VMware. Then, with the same configuration, you can test these scripts on remote clouds such as AWS or RackSpace with the same workflow. As a designer, by using Vagrant, you can simply setup your environment base on the Vagrantfile, which is already configured, without worrying about how to get the app running again.

By using Vagrant you can achieve the following:

  • environment per project - you can have different configuration files for each project
  • same configuration file for developing, pre-staging, staging and production environments
  • easy to define and transport the configuration file (Vagrantfile)
  • easy to tear down, provisional: infrastructure as a code
  • version able configuration files - you can commit all your cookbooks and the Vagrantfile
  • shared across the team - by using the same configuration file (Vagrantfile)

Before diving into the first vagrant project, you need to install VirtualBox or any other supported provider. For this example I used VirtualBox. The next step is to install Vagrant. For this step you have to download and install the appropriate package or installer from Vagrant"s download page (http://www.vagrantup.com/downloads). The installer will automatically add vagrant to the system path, so it will be available in terminals as shown below.

$ vagrant
Usage: vagrant [-v] [-h] command []
    -v, --version                    Print the version and exit.
    -h, --help                       Print this help.
Available subcommands:
     box          manages boxes: installation, removal, etc.
     destroy      stops and deletes all traces of the vagrant machine
     halt         stops the vagrant machine
     help         shows the help for a subcommand
     init         initializes a new Vagrant environment by creating a                    Vagrantfile
     package      packages a running vagrant environment into a box
     plugin       manages plugin s: install, uninstall, update, etc.
     provision    provisions the vagrant machine
     reload       restarts vagrant machine, loads new Vagrantfile              configuration
     resume       resume a suspended vagrant machine
     ssh          connects to machine via SSH
     ssh-config   outputs OpenSSH valid configuration to connect to 
		   the machine
     status       outputs status of the vagrant machine
     suspend      suspends the machine
     up           starts and provisions the vagrant environment

The next step is to initialize vagrant on your project by running vagrant init command line:

$ vagrant init

A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please 
Read the comments in the Vagrantfile as well as documentation on`vagrantup.com` for more information on using Vagrant.

After running this command, a new file called Vagrantfile is generated into your project folder. Vagrantfile is written in Ruby, but knowledge of the Ruby programming language is not necessary to make modifications, since it is mostly simple variable assignment. The Vagrantfile has the following roles:

  • Select base box
  • Choose virtualization provider
  • Configure VM parameters
  • Configure Networking
  • Tweak SSH settings
  • Mount local folders
  • Provision machine

Select base box

The automatically generated Vagrantfile, contains the following lines:

# Every Vagrant virtual environment requires a box to build off of.
  config.vm.box = "precise32"
  # The url from where the "config.vm.box" box will be fetched if it
  # doesn"t already exist on the user"s system.
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"

config.vm.box line describes the machine"s type required for the project. The box is actually a skeleton from which Vagrant machines are constructed. Boxes are portable files which can be used by anyone on any platform that runs Vagrant. Boxes are related to the providers, so when choosing a base box you have to be aware of the supported provider. In order to choose a base box, you can access http://www.vagrantbox.es/ web site, where you can find a list of available boxes. Vagrant offers also the possibility of creating custom boxes. A nice tool which can be used to create custom boxes can be found here: https://github.com/jedi4ever/veewee.

There are two ways to add a base box. One option is to define the base box in the Vagrantfile config.vm.box, and when you run vagrant up command, the box will be added. The second option is to execute the command bellow:

$ vagrant box add  

parameter can be anything you want to, just make sure it is the same value defined in the directive config.vm.box, form Vagrantfile.

is the location of the box. This can be a path to your local file system or an HTTP URL to the box remotely.

$ vagrant box add precise32 http://files.vagrantup.com/precise32.box

Available commands for boxes are described below:

$ vagrant box -h
Usage: vagrant box  []
Available subcommands:
    add
    list
    remove
    repackage
For help on any individual command run `vagrant box COMMAND -h`

Choose virtualization provider

There are two ways to specify the provider, similar to those described for the base box.

The first option is to specify the provider from the command line as a parameter. If you choose this solution you have to make sure that the argument from command line matches Vagrantfile"s directive config.vm.provider.

$ vagrant up --provider=virtualbox

There are two ways to specify the provider, similar to those described for the base box. The first option is to specify the provider from the command line as a parameter. If you choose this solution you have to make sure that the argument from command line matches Vagrantfile"s directive config.vm.provider.

Configure VM parameters

Vagrantfile offers the possibility to configure the providers by adding the vb.customize directive. For example if you want to increase the memory, you can do as shown below.


# Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  config.vm.provider :virtualbox do |vb|
  # # Don"t boot with headless mode
     #  vb.gui = true
     #
  # # Use VBoxManage to customize the VM. For example to change memory:
	vb.customize ["modifyvm", :id, "--memory", "2048"]
    end
  • config.vm.network :public_network
# Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  config.vm.network :public_network
  • config.vm.network :private_network, ip: "192.168.33.10"
 access to the machine
  # using a specific IP.
  config.vm.network :private_network, ip: "192.168.33.10"

Tweak SSH settingsH

Vagrantfile offers also the possibility to configure the config.ssh namespace, in order to specify username, host, port, guest_port, private_key_path, forward_agent, forward_x11 and shell.

Vagrant.configure("2") do |config|
  config.ssh.private_key_path = "~/.ssh/id_rsa"
  config.ssh.forward_agent = true
end

Mount local folders

While many people edit files from virtual machines just using plain terminal-based editors over SSH, Vagrant offers the possibility to automatically sync files on both guest and host machines, by using synced folders. By default Vagrant offers the possibility to share your project folders to the /vagrant directory on the guest machine. So the /vagrant directory that can be seen on the guest machine, is actually the same directory that you have on your host machine. So you won"t have to use anymore the Upload and Download option from your IDE in order to sync files on the host and the guest machines. If you want to change the synced directory on the guest machine, you can add the directive config.vm.synced_folder "../data", "/vagrant_data" in the Vagrantfile.

Vagrant.configure("2") do |config|
    config.vm.synced_folder "../data", "/vagrant_data"
  end 

Provision Machine

Provisioning isn"t a matter that developers should care about, as usually sysadmins handle it. The idea is to record somehow the software and the configurations made on the server, in order to be able to replicate it on other servers. In the old days sysadmins kept a wiki of the executed commands, but this was a terrible idea. Another option was to create .box or .iso backups, so new servers can be configured based on those files. But maintaining these backups up to date requires a lot of work and as the time goes by, it"s quite hard to keep synced all the machines. Provisioning in our days, offers the possibility to add specific software, to create configuration files, to execute commands, manage services or create users, by using modern provisioning systems. Vagrant can integrate the following provisioning systems: Shell, Ansible, Chef Solo, Chef Client, Puppet, Salt Stack. The two most popular provisioning systems are Chef and Puppet, being supported by large communities. Both are written in Ruby, having similar features like modularized components, packages for software installs or templates for custom files. As a notice, both systems are open source projects with enterprise revenue model.

Provisioning with Shell

Provisioning with Shell in Vagrant is quite easy. There are three ways to do it. You can write inline command, or you can specify the path to the shell script. The path can be either from an internal or external folder.

Table 1. Chef vs. Puppet

Inline command

config.vm.provision :shell, :inline => "curl -L https://get.rvm.io | bash -s stable"

Internal path

config.vm.provision :shell, :path => "install-rvm.sh", :args => "stable"

External path

config.vm.provision :shell, :path=>"https://example.com/install-rvm.sh", :args => "stable"

Provisioning with Pupppet

Puppet modules can be downloaded from https://github.com/puppetlabs. In order to configure Vagrant with Puppet, you have to setup the Puppet directives as follows:

Fig. 1 Puppet Module"s Structure

config.vm.provision :puppet do |puppet|
    puppet.manifests_path = "./tools/puppet/manifests/"
    puppet.module_path = "./tools/puppet/modules"
    puppet.manifest_file = "init.pp"
    puppet.options = ["--verbose"]
End

init.pp

include mysql::server
class { "::mysql::server":
  root_password    => "strongpassword"
}
class mysql::server (
   $config_file = $mysql::params::config_file,
   $manage_config_file = $mysql::params::manage_config_file,
   $package_ensure = mysql::params::server_package_ensure,
)

Mysql params.pp:

class mysql::params {
   $manage_config_file = true
   $old_root_password = ""
   $root_password = "strongpassword"
}

Mysql Template:

Mysql Template
[client]
password=<%= scope.lookupvar("mysql::root_password") %>

Provisioning with Chef Solo

Chef Solo cookbooks can be downloaded from here: https://github.com/opscode-cookbooks.

Fig 2. Cookbook files structure

For Chef Solo Vagrantfile has to be edited as shown below, in order to configure the path to the cookbooks.

config.vm.provision :chef_solo do |chef|
        chef.cookbooks_path = "cookbooks"
        chef.add_recipe "vagrant_main"
  #     chef.roles_path = "../my-recipes/roles"

  #     chef.data_bags_path = "../my-   recipes/data_bags"
  
  #     chef.add_role "web"
  #
  #   # You may also specify custom JSON attributes:
  #   chef.json = { :mysql_password => "foo" }
  end

vagrant_main/recipes/default.rb

include_recipe "apache2"
include_recipe "apache2::mod_rewrite"

package "mysql-server" do
    package_name value_for_platform("default" => "mysql-server")
    action :install 
end

vagrant_main/templates/default.rb

NameVirtualHost *:80

    ServerAdmin webmaster@localhost
    ServerName cfratila.tsm.com
    ServerAlias www.cfratila.tsm.com 

    DocumentRoot /var/www

    
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
    

    ErrorLog <%= node[:apache][:log_dir] %>/tsm-error.log
    CustomLog <%= node[:apache][:log_dir] %>/tsm-access.log combined
    LogLevel warn

If you"re still irresolute and you don"t know which provisioner to choose, you could have a look at Table 1 for a helping hand.

Once you are done with the Vagrantfile configuration, you are ready to create the virtual machine. For this step you should open your command line interface and navigate to the project"s folder, where the Vagrantfile should be placed also, in order to sync the folders. Then just type vagrant up and your guest machine will be created. First time, when you"ll run vagrant up, it will take a while, because Vagrant will download the configured box. In our case, I didn"t add the virtual box with vagrant box add command, so the box will be added at vagrant up command line, as shown below.

D:projects	sm> vagrant up
Bringing machine "default" up with "virtualbox" provider...
[default] Box "precise32" was not found. Fetching box from specified URL for  the provider "virtualbox". Note that if the URL does not have a box for this provider, you should interrupt Vagramt now and add the box yourself. Otherwise Vagrant will attempt to download the full box prior to discovering this error.
Downloading box from URL: http://files.vagrantup.com/precise32.box
Progres: 1% 

After the guest machine was created, you can simply type vagrant ssh in order to access it. For Windows systems you can install PuTTY SSH client if you want to, by adding the authentication information as shown below:

D:projects	sm> vagrant ssh
"ssh" executable not found in any directories in the %PATH% variable. Is an SSH client instaled? Try installing Cygwin, MinGW or Git, all of which contain SSH client. Or use the PuTTY SSH client with the following authentication information shown below:

Host: 127.0.0.1
Port: 2222
Username: vagrant
Private key: C:/Users/Carmen/.vagrant.d/insecure_private_key

If you have modified only the provisioning scripts and want to quickly test, you can just run vagrant provision or vagrant --provision-with x,y,z, where x,y,z represents the provisioner :shell or :chef_solo.

If you want to save the state of the machine rather than doing a full boot every time, you can run vagrant suspend. With vagrant resume command you can resume a Vagrant machine that was suspended.

If you want to shut down the machine you should use vagrant halt command. By using this command you can save space, but it will take longer time to restart the machine because of booting. With vagrant up, you"ll have your machine running again. If you want to run halt and up, because you just did a modification to the Vagrantfile, for example, you can quickly run vagrant reload.

If you want to stop the machine and to remove all the allocated resources, you can do it by typing vagrant destroy.

Vagrant vs. Docker

Docker is an open source project to pack, ship and run any application as a lightweight container. The main idea is to create components per application. The component is actually a snapshot of the application. After making changes in the component, you can commit the new state of the snapshot, so rolling back to a previous state is quite easy. This project is awesome because it doesn"t involve virtual machines as Vagrant does, which means that startup time and resources usage is better. Also you can forget about cookbooks if you don"t want to use Chef anymore. The interactive command line tutorial (http://www.docker.io/gettingstarted/) is also very intuitive and in less than 20 minutes you can have an overview image of what Docker is.

By comparing the workflow we can enunciate the following points:

1. Docker is better on the provisioning side.

2. Rolling back is easier with Docker because of the snapshot system

3. Docker raised a new deployment model

4. Docker is supported only on Ubuntu linux machines

5. Docker is not recommend on production since it is still in the development phase

6. Vagrant is better because it keeps source code and deployment information in the same place

7. Vagrant is better because it is stable and can be used in production

8. Vagrant is better because it can be integrated with Linux, Windows and Mac OS X systems

VIDEO: ISSUE 109 LAUNCH EVENT

Sponsors

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects

VIDEO: ISSUE 109 LAUNCH EVENT