# Vagrant
### It's quite good
## What is it?
From the [Vagrant](http://www.vagrantup.com/) site:
> "Create and configure lightweight, reproducible, and portable development environments."
## What does that mean?
Helps you run an app in a virtual machine and manage it with ease
## Do what with virtual machines now?
* Create and destroy, quickly and safely
* Speedy start, suspend and stop operations
* Automagic forwarding of ports (eg. ssh and http)
* Repeatable provisioning and configuration
## Terminology
### Host and Guest
**Host:** your actual, physical machine
**Guest:** a virtual machine running on your host
## Terminology
### Base box
* A lightweight, pre-prepared OS image
* Usually Linux; could be Windows or something else
* Base boxes are stashed for reuse by Vagrant in `~/.vagrant.d/`
## How does Vagrant work?
* Downloads the base box (if not already present)
* Clones the base box to your project
* Boots the base box
* Runs config and provisioning instructions
### Project files
* They still live on your physical machine
* But the VM can see them, via shared folders...
* ...so you can use your usual editor and tools
### Running the app
* Your Ruby, Python, Node or whatever app runs in the VM
* HTTP ports can be forwarded from guest to host...
* ... so browsers running on the host can see the site
## Get going
* Install stuff
* Create a `Vagrantfile`
* Make a provision script
### Install stuff
1. [VirtualBox](http://www.virtualbox.org/wiki/Downloads)
2. [VirtualBox Extension Pack](http://www.virtualbox.org/wiki/Downloads)
3. [Vagrant](http://www.vagrantup.com/)
NB: [VMware](http://www.vagrantup.com/vmware) also supported (more stable, not free)
### Create a `Vagrantfile`
Just a config file. Have a basic one created for you:
```bash
vagrant init precise64 http://files.vagrantup.com/precise64.box
```
### Or make your own
Should specify:
* base box name
* base box URL
* networking
* provisioning info
## A simple `Vagrantfile`
```ruby
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "precise64"
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
config.vm.network :forwarded_port, host: 4567, guest: 4567
config.vm.provision :shell, :path => "provision.sh"
end
```
## Provisioning
Works with:
* [Chef](http://www.opscode.com/chef/)
* [Puppet](http://puppetlabs.com/)
* Shell scripts
* [SaltStack](http://saltstack.com/) ([soon](https://github.com/mitchellh/vagrant/issues/1416), Python fans)
## Chef and Puppet are hard
Let's use shell scripts
## A simple `provision.sh`
```bash
#!/usr/bin/env bash
# Update system package lists
sudo apt-get update
# Install necessary system packages
sudo apt-get install -y \ # automatic yes to prompts with -y
build-essential \
nodejs \
# Install Bundler (no docs)
gem install --no-rdoc --no-ri \
bundler \
# Bundle all the gems in the gemfile
cd /vagrant/www
bundle install
```
## `vagrant up`
All done.
Now:
```bash
$ vagrant up
```
## `vagrant up`
```bash
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'precise64'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] -- 4567 => 4567 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Configuring and enabling network interfaces...
[default] Mounting shared folders...
[default] -- /vagrant
[default] Running provisioner: shell...
[default] Running: /var/folders/2j/lkj6zqjx3hd6wzwsz2v55bmw0000gn/T/vagrant-shell20130612-1787-14r3iia
# a few minutes + lots of install logging
```
## What now?
Common commands:
* `vagrant up`
* `vagrant ssh`
* `vagrant suspend`
* `vagrant halt`
* `vagrant reload`
* `vagrant destroy`
## `vagrant up`
First use also runs provisioning and starts the VM
After that, it just starts the VM
## `vagrant ssh`
### Get in and muck about
```bash
$ vagrant ssh
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)
* Documentation: https://help.ubuntu.com/
Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:23:18 2012 from 10.0.2.2
vagrant@precise64:/vagrant$ pwd
/vagrant
vagrant@precise64:/vagrant$ exit
logout
Connection to 127.0.0.1 closed.
```
## `vagrant suspend`
### Pause the VM
* Keeping the state
* Freeing up resources
```bash
$ vagrant suspend
[default] Saving VM state and suspending execution...
```
## `vagrant halt`
### Shut down the VM
* Lose state
* Keep installed packages etc.
```bash
$ vagrant halt
[default] Discarding saved state of VM...
```
## `vagrant destroy`
### Destroy the VM
Doesn't affect your project files or the base box.
```bash
$ vagrant destroy
Are you sure you want to destroy the 'default' VM? [y/N] y
[default] Forcing shutdown of VM...
[default] Destroying VM and associated drives...
```
## `vagrant reload`
Like `vagrant up`, but runs the provision script again.
The same as running `vagrant up` for the first time.
## Why bother?
If you can run an app on your actual, physical machine, why bother running them in a Vagrant VM?
### Consistent environment for all
Put the `Vagrantfile` and provision script under version control.
All team members can run the same stack on the same (virtual) OS.
### Consistent environment for all
No more:
* Spending ages trying to get dependencies sorted so work can start
* Weird issues caused by slightly different versions
* "It works fine on my machine" conversations
* Windows-using tech clients getting upset
### Less thought
If you are:
* Using a different machine
* Coming back to a project a few months later
* Helping a new team member get going
### Less thought
```bash
$ git clone https://github.com/user/project-name.git project-name
$ cd project-name
$ cat README.md
$ vagrant up
```
Done (pretty much)
### Code beats documentation
Documentation is good; code is better.
Written instructions on how to get an app running can get out of date quickly.
### Code beats documentation
* Script the provisioning
* Quickly becomes clear when dependencies are broken
* Easy to fix, then distribute
### Fallback
You're not forced into using Vagrant: you can still install the dependencies on your host machine and run the app there, if you like.
## Resources
* [Vagrant docs](http://docs.vagrantup.com/): start here
* [Vagrant book](http://shop.oreilly.com/product/0636920026358.do): just released
* [Vagrant AWS plugin](https://github.com/mitchellh/vagrant-aws): manage EC2 and VPC instances
* [Vagrantbox.es](http://www.vagrantbox.es/): lots of base boxes
* [Rove](http://rove.io/): Chef and Vagrantfile build tool
* [Puphet](https://puphpet.com/): Puppet and Vagrantfile for PHP build tool
* [fabtools](https://github.com/ronnix/fabtools): handy helpers for Fabric (see [Vagrant API](https://fabtools.readthedocs.org/en/latest/api/vagrant.html))
### STFU Paul
Fanks
Presented at [HMTL](http://hmtl6.github.io/2013-06-12-deja-vu/), 12th June 2013
Built with [Reveal.js](http://lab.hakim.se/reveal-js/)