Getting started with Vagrant - automated dev servers deploy and provisioning

Jan 24, 2014, 1:16:14 PM

vagrant

What is it? Why do I need it?

Have you ever made big server side application with wide technologies and software stack in a team ? Or have you tried to connect quickly to an "old" backend project and bring some help? Or maybe one of your colleagues had ever said to you "hey, that script/soft is not working on my machine..." but you don't understand what is wrong and can't reproduce it. If yes - then you know this pain :

  • you have Windows PC, but want to develop webapp on Linux server
  • usually only some member of a team is a good sysadmin and he is responsible for setup and configuration, during development software stack is changing or require update etc. and every member of a team need to make it by himself on his localhosts
  • you are contributing to different projects and need quickly switch between then - but these projects require different versions of some software like PHP or MySQL and can't co-exist with each other
  • you often work on different laptops etc. and don't want to pollute all of them with server-stack software
  • you need to track versioning of you dev server environment and should be able to checkout not only app code to some moment of time, but server also
  • new member came to your team and you need to setup a full local dev environment in a minutes and for sure without "oh, really I forget this one ..."

We are lucky as now Vagrant exist to solve it. Literally Vagrant is a software that could setup you a local (or cloud) dev Virtual server using a configuration file. So it could be tracked as a project file inside Git repo. It can make server provisioning using Shell script or Ansible, Chef, Puppet.
Anyone, anywhere, anytime could run one terminal command to get their own local dev environment that is exact copy of your own - reliable, reproducible and for sure.

Very important to understand that Vagrant is for Dev machines only. It does not supposed to be used for Production env. deployment. It does not replace cloud orchestration software and great provisioning tools like Ansible/Chef/Puppet (but can utilize them as well, so you could reuse production provisioning scripts on dev machines).

Vagrant has quite good documentation and you should definitely go through it. Here I will juts cover briefly all major points.

Install Vagrant in Ubuntu

It is available for Linux, Windows and Mac. But all examples here assume Ubuntu Linux as Host and Virtual machine.

Quick start : Vagrantfile - The Journey Begins...

just 2 simple terminal commands ~~~ $ vagrant init precise32 http://files.vagrantup.com/precise32.box $ vagrant up ~~~

First command will create a Vagrantfile file in this dir and this config will be predefined ~~~ ... config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" ... ~~~ now running vagrant up will actually start VirualBox instance according to Vagrantfile in current directory. In our case it will download Ubuntu 12.04 box from internet and run it/
Vagrantfile contain all settings for our server.
You can think running a VirtualBox is a big performance overhead for a dev server - but I think it is not. At least it is reliable price for a full isolation of environment. Plus don't forget that we are running server version of Linux without GUI - so 512 Mb Ram and some CPU time will be quite enough for a dev machine.

Box - prepared server image

Actually you can have any Linux distribution (btw. Windows should be able to) installed and deployed by Vagrant. By default it just runs a VirtualBox image. Start your experiment with local VirtualBox and you will quickly get what I am writing about.

In first Vagrant versions Box was simply a tar files of VirtualBox exports, but now as Vagrant supports different providers (like AWS, Rackspace, Digital Ocean etc.) Box could contain OS snapshot with preinstalled soft, metadata.json with provider specification and Vagrantfile with basic config for VM (that will be overriden by yours).

Of course if you make deploy to Cloud provider like Amazon - you can't install OS by your own, for example AWS EC2 has it's own Images that you are deploying while creating an EC2 instance. That's why "non VirtualBox" config has more options where you specify your AWS credentials, ID of instance, region and so on. In this case .box file is just a dummy, that is not being deployed in reality.
If you want to create your own Box for local test refer to these docs, but...

...better use ready made - they will cover almost all needs

Some boxes has already pre-installed software, be careful with it, better use "cleaner" distributions and explicitly provide software setup instructions in Vagrant Provisioning.

To create new Vagrant file with selected box do the following

$ vagrant box add {title} {url}
$ vagrant init {title}
$ vagrant up

When you box add it downloads box to /home/user/.vagrant.d/boxes. These box copies could be reused between different Vagrantfiles. When you launch Box - it makes a copy of downloaded box.
Real boxes with changes according to each project is stored in /home/user/VirtualBox VMs.
That's not a big deal, but good to understand that.

Connecting to Vagrant box

Once you have run vagrant up and it is successfully launched - to get into you box via SSH just do the following (you should be in the same folder where your Vagarantfile is) ~~~ $ vagrant ssh ~~~ if it is "too big magic to trust it" do this ~~~ $ vagrant ssh-config ~~~ ok now you have everything to make ssh connection by any means ~~~{.bash} ijack@home ~/Vagrant » vagrant ssh-config Host precise32 HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile /home/user/.vagrant.d/insecure_private_key IdentitiesOnly yes LogLevel FATAL ~~~

Provisioning

Fine, now you have fresh Box deployed and running, you are ssh connected to it. You are free to install any software you need and go ahead.
> But wait - how can you share your server soft setup and provision to other collaborators then?

You need an automated provisioning for it. Vagrant supports a lot of them :

  • Shell
  • Ansible
  • Chef
  • Puppet

As for Ansible, Chef and Puppet - you need to investigate it separately as they are good and you should definitely use them for "serious" production provisioning.
But now pure "shell" is our "quick" way ! Just add such line to Vagrantfile ~~~ config.vm.provision "shell", path: "./setup.sh" ~~~ and put setup.sh to folder near Vagrantfile, put there any valid OS-specific commands (as in ordinary shell script, it wil be run inside your Box), for example ~~~

! /bin/bash

sudo apt-get update echo mysql-server mysql-server/root_password password root | sudo debconf-set-selections echo mysql-server mysql-server/root_password_again password root | sudo debconf-set-selections sudo apt-get install -y git-core curl wget mc build-essential python-software-properties sudo apt-get install -y apache2 sudo apt-get install -y mysql-server mysql-client sudo apt-get install -y php5 libapache2-mod-php5 php5-cli php5-mysql php5-curl php5-gd php5-mcrypt php5-xdebug ~~~ to ensure your machine is properly provisioned you need to call ~~~ $ vagrant provision ~~~ and you know what? When it will finish you will have a machine with very basic LAMP installed.

For a Shell provisioning in Ubuntu I have found useful repo with a set of apt-get install commands - Vaprobash. It is kept as "modular" and configurable files. Useful for quick and dirty Ubuntu server provisioning.
Also nice example for a Shell provisioning script is in varying-vagrant-vagrants repo

One simple rule - install software manually inside Vagrant box only for your personal exeriments. If you plan to share Vagrantfile with others - provision all you software automatically and always remember to check "fresh" `vagrant up` from time to time. As if you will forget to specify some provisioning rules - another people or even you on other machine will not be able to run it seamlessly.

Folder sharing and synchronization

By default you can find out that in vagrant box you see /vagrant folder and it is the same folder where your Vagrantfile on host machine is located.
This folder is shared between host and Vagrant by means of VirtualBox "shared folders" feature.
You can specify your own set of shared folders like : config.vm.synced_folder "./", "/var/www"

This feature allows you to store project files on host machine and edit them with your IDE locally on host machine - but it will automatically be available on Vagrant machine, so you will run code and test on Vagrant machine.

NFS

If you have low performance of shared folder in VirtualBox machine you can try to use NFS sharing type (instead default one). Install NFS package
sudo apt-get install nfs-kernel-server
and modify Vagrantfile
config.vm.synced_folder "./", "/var/www", type: "nfs"
(but this sharing will not work on Windows host)

rsync

On big shared folder native sharing is really slow and NFS could work also not very fast, then you can try to use rsync sharing. It will not make any "sharing" of directory, byt "sync". So VM disk will work very fast (compared to sharing), but will require 2-3 sec. after changes made - to be synced in VM.
config.vm.synced_folder "./", "/var/www", type: "rsync"
then in Vagrantfile folder you need to run rsync watcher
vagrant rsync-auto

When you delete files in Vagrant machine it is also deleted on host - your real PC. So be carefull when sharing host system root folder and making "rm / -Rf" on Vagrant ;)

Network and port forwarding

This feature actually allows you to make network interactions between host and Vagrant machine.
To access guest machine via this IP from your host machine ~~~ config.vm.network "private_network", ip: "192.168.77.77" ~~~ To access guest machine's port 81 via http://localhost:8081 on host machine ~~~ config.vm.network :forwarded_port, guest: 81, host: 8081 ~~~ You can combine these settings and proxy as many ports as you want.

Change VM settings

You can set non-default Virtual machine settings for VirtualBox in such way ~~~ config.vm.provider :virtualbox do |vb|

    vb.customize ["modifyvm", :id, "--memory", "1024"]

end ~~~ Complete list of all available params could be found on VirtualBox site

Tip : Set a VirtualBox guest CPU count to the number of host cores ~~~ vb.customize ["modifyvm", :id, "--cpus", `grep "^processor" /proc/cpuinfo | wc -l`.chomp ] ~~~

Common Vagrant commands

  • vagrant up start machine
  • vagrant halt stop machine (yes it is not down :))
  • vagrant reload reload machine
  • vagrant destroy remove/delete machine
  • vagrant ssh connect via ssh to machine
  • vagrant provision run provisioning stage on the machine, useful after changes in provisioning configs

Automatic VM resources setup

Give VM 1/4 system memory and access to all cpu cores on the host ~~~{.ruby} config.vm.provider "virtualbox" do |v| host = RbConfig::CONFIG['host_os']

if host =~ /darwin/

cpus = `sysctl -n hw.ncpu`.to_i
mem = `sysctl -n hw.memsize`.to_i / 1024 / 1024 / 4

elsif host =~ /linux/

cpus = `nproc`.to_i
mem = `grep 'MemTotal' /proc/meminfo | sed -e 's/MemTotal://' -e 's/ kB//'`.to_i / 1024 / 4

else

cpus = 2
mem = 1024

end

v.customize ["modifyvm", :id, "--memory", mem] v.customize ["modifyvm", :id, "--cpus", cpus] end ~~~

Useful plugins

Cool things are not finished yet, Vagrant has cookies plugins.

Available Vagrant plugins from GitHub wiki I will collect useful (at my point of view :) ) here :

  • vagrant-vbguest - autoupdate VirtualBox guest additions (according to VB version)
    $ vagrant plugin install vagrant-vbguest
    Doesn't require explicit configuration, will run on each vagrant up and check up version of guest additions.

  • vagrant-hostsupdater - adds an entry to your /etc/hosts file on the host system When you don't like using different ports for different sub-sites on your Vagrant machine and want to have local sub-domains routed automatically
    $ vagrant plugin install vagrant-hostsupdater ~~~ config.vm.network :private_network, ip: "192.168.3.10" config.vm.hostname = "www.testing.de" config.hostsupdater.aliases = ["alias.testing.de", "alias2.somedomain.com"] ~~~

  • sahara - easy manage VM state (commit/rollback while experimenting with software stack)
    vagrant plugin install sahara > vagrant sandbox on
    Do some stuff:
    vagrant ssh
    If satisfied, apply the changes permanently:
    vagrant sandbox commit
    If not satisfied, rollback to the previous commit:
    vagrant sandbox rollback
    Exit sandbox mode:
    vagrant sandbox off

  • vagrant-omnibus - ensures the desired version of Chef Works with almost all Providers, uses the platform-specific Omnibus packages.
    $ vagrant plugin install vagrant-omnibus
    # install latest Chef
    config.omnibus.chef_version = :latest
    # or specific version
    #config.omnibus.chef_version = "11.4.0"
    ...
    
  • vagrant-cachier - share a common package (apt-get, npm, etc.) cache among similiar VM instances. vagrant plugin install vagrant-cachier Usage details here ~~~ if Vagrant.has_plugin?("vagrant-cachier") config.cache.auto_detect = true end ~~~

  • vagrant-host-shell - a vagrant provisioner to run commands on the host when a VM boots. vagrant plugin install vagrant-host-shell ~~~ config.vm.provision :host_shell do |host_shell| host_shell.inline = 'touch /tmp/hostshell-works && echo hello from the host && hostname 1>&2' end ~~~

  • vagrant-ansible-local allow provisioning your VM with ansible playbooks directly from the guest VM vagrant plugin install vagrant-ansible-local ~~~ config.vm.provision :ansibleLocal, :playbook => "ansible/ansible.yml" ~~~

Helpers

More

  • Packer A tool for creating identical machine images for multiple platforms from a single source configuration. For fast infrastructure deployment with multi-provider portability.

  • Veewee Veewee is a tool for easily (and repeatedly) building custom Vagrant base boxes, KVMs, and virtual machine images.

![vagran up](http://blog.bigpanda.io/wp-content/uploads/2014/05/epicKid1.jpg)
comments powered by Disqus
Ievgen
Kuzminov "iJackUA"
Web Team Lead
at MobiDev (Kharkiv, Ukraine)
Code in PHP and Ruby, play with JS/Node.JS, evaluate Elixir, explore databases, use Ubuntu and MacOS, think about IT people and management

Notes