Apr 20, 2015 vagrant

I have been using Vagrant and it is the most useful tool for working with VM, such as Virtualbox and Parallels. Before Vagrant, I’d been using virtual disk images, which were cloned and made into snapshots between each changes in configuration. Now, Vagrant makes this process effortless with simple commands.

References

My current Vagrantfile

boxcutter/debian82, ansible, parallel

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "boxcutter/debian82"
  config.vm.network "private_network", ip: "192.168.200.10"
  config.ssh.forward_agent = true
  config.vm.provision "ansible" do |ansible|
	 ansible.playbook = "ansible.yml"
	 ansible.verbose = 'vvvv'
  end

end

Simple Setup

First, download Vagrant.

Create dir and cd if it doesn’t already exist

$ mkdir <MyVagrantDir>; cd <MyVagrantDir>

Create config file Vagrantfile

$ vagrant init

Create a box (it downloads box if it is needed)

$ vagrant box add debian/jessie64   # load Debian box

Edit config file

Vagrant.configure("2") do |config|
    config.vm.box = "debian/jessie64"
end

Start VM

$ vagrant up

Basic usage

SSH into VM

$ vagrant ssh

Reload VM if needed

$ vagrant reload

Manually SSH

$ ssh vagrant@127.0.0.1 -p 2222 -i /.../.vagrant/machines/default/virtualbox/private_key

Status

$ vagrant status
$ vagrant global-status

Box

Quick summary if adding boxes, a little different from above doc. not sure

$ vagrant box add {TITLE} {SOURCE}   # adds box
$ vagrant init
$ vagrant up

Basic operations

$ vagrant box         # help
$ vagrant box list    #lists all boxes

Install box

$ vagrant box add {TITLE} {SOURCE}   # adds box

$ vagrant box add MyBox http://example.com/somedistro.box

Other operations

$ vagrant box remove <NAME>   # remove box 

$ vagrant box update   # update box image

Repackage and put it in current directory to make it redistributable

$ vagrant box repackge <NAME> <PROVIDER> <VERSION>
# not the same as packaging?

Box repository

https://atlas.hashicorp.com/boxes/search

http://www.vagrantbox.es/ ,flat list of boxes, but is a little outdated? It seems do be not updated frequently.

https://chef.github.io/bento/

Box notes

Hashicorp’s Debian Jessie 8.2 Vanilla box (https://atlas.hashicorp.com/debian/boxes/jessie64)

vagrant init debian/jessie64; vagrant up --provider virtualbox

Debian’s official box (https://wiki.debian.org/Teams/Cloud/VagrantBaseBoxes)

Debian doc suggests using this to share files (via rsync)

vagrant rsync-auto

Alternative is to use boxcutter’s Debian

HN Discussion: What’s THE way to setup a OS X dev machine 2015?

Box file location

Box is stored locally (via synced folder).

The current disk content is stored in ~/VirtualBox\ VMs\vagrant*/

To see the names of vagrant running on Virtualbox

$ VBoxManage list vms

https://brianfisher.name/content/alternative-vagrant-synced-folders

Might have to do this if it fails to mount

$ mount -t vboxsf -o uid=`id -u vagrant`,gid=`getent group vagrant | cut -d: -f3` /var/www /var/www
$ mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` /var/www /var/www

Teardown

Save the VM state

$ vagrant suspend #suspend, quick, all states preserved
$ vagrant up      # wake

# alternatively
$ vagrant resume

Shutdown VM gracefully

$ vagrant halt   # completely shut-down, but content of disk remains
$ vagrant up  # boot vm

Shutdown VM by powering off

$ vagrant halt -f  [--force]

Destroy VM permanently

Delete Box

$ vagrant box remove NAME
$ vagrant box remove NAME --provider=".."

Convert Virtualbox to Vagrant box

https://docs.vagrantup.com/v2/virtualbox/boxes.html

Use boxcutter’s boxes.

# find vbox's name
$ VBoxManage list vms
# package into vagrant box
$ vagrant package --base centos5_default_1416400560587_23130 --output virtualbox.box
# name the box
$ vagrant box add box-dimka/centos511-i386 virtualbox.box

Debian recommends this to improve speed

Synced folder

Virtualbox’s bad sync performance

vagrant-project-dir is shared in Vagrant VM’s /vagrant dir.

From https://github.com/mitchellh/vagrant/issues/3062

Here’s my attempt to summarize the issue:

VirtualBox shared folder provides two-way synchronization but it does not fire inotify notifications so we can’t run programs to watch changes and compile them (e.g., Less compiler). The polling approach falls apart quickly because VirtualBox shared folder is slow. Setting up a shared folder via rsync is fast and fires inotify but it is only one-way. My workaround is to set up the source directory as two shared folders, one via rsync and another via virtualbox shared folder. e.g.,

config.vm.synced_folder “.”, “/vagrant”, type: “rsync” config.vm.synced_folder “.”, “/vagrant_sf” I set things up so that any program that watches file changes via inotify reads from /vagrant. Any changes that needs to be persisted goes out to /vagrant_sf (e.g., alembic migration files). This workflow seems to work reasonably well.

Alternatives:

Vagrantfile: Config

# makes precise32 as "base" image
Vagrant.configure("2") do |config|
    config.vm.box = "hashicorp/precise32"
    #.... all settings inside here
    #.....
end

Same as above, but more flexible using var, just in case version changes

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

Networking

In shell, to take effect after changing Vagrantfile

$ vagrant reload  # shutdown and restart VM
# OR
$ vagrant up      # if it wasn't running

Forwarding ports

Vagrantfile

Vagrant.configure("2") do |config|
    config.vm.box = "hashicorp/precise32"
    config.vm.provision :shell, path: "bootstrap.sh"
    config.vm.network :forwarded_port, guest: 80, host: 4567
end

Once forwarded, (on host):

Instead of IP address, use domain name, via change in /etc/hosts

# /etc/hosts
192.168.100.10   dev.otter.pro

Example: forward vagrant’s port 80,443 to host’s 8080,8443

# Vagrantfile
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    ...
    config.vm.network "forwarded_port", guest: 80, host: 8080
    config.vm.network "forwarded_port", guest: 443, host: 8443

# in Shell
$ vagrant reload

NAT (Private network)

Enable internet connection on Debian/ Ubuntu in NAT

config.vm.provider "virtualbox" do |v|
    v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
    v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
end

Private Network (NAT AND Host-only, 2 NIC)

# Create a private network, which allows host-only access to the machine # using a specific IP. config.vm.network “private_network”, ip: “192.168.100.10”

Bridged / 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"

Enable SSH forwarding

Share more folders

config.vm.synced_folder "./app", "/var/www/django-app"

Automated provisioning

Provision process runs when:

  1. $ vagrant up # only on the 1st “vagrant up”!!!
  2. $ vagrant reload --provision # if VM is already running
  3. $ vagrant provision # always provisions on this command

Run a command inline

Vagrant.configure("2") do |config|
config.vm.provision "shell",
    inline: "echo Hello, World"
end

Run inline script Ex (from VagrantFile)

 config.vm.provision "shell", inline: <<-SHELL
   sudo apt-get update
   sudo apt-get install -y apache2
 SHELL

Example

Vagrant.configure("2") do |config|
    config.vm.provision "shell", inline: "echo foo"
    config.vm.provision "shell", inline: "echo baz"
end

named :

config.vm.provision "NAME is Bootstrap", type: "shell" do |s|
  s.inline = "echo hello"
end

Example: run external script

Upload the script to Guest OS and execute it.

Create bootstrap.sh file.

When vagrant is run, it will run the bootstrap.sh once

#!/usr/bin/env bash
apt-get update
apt-get install -y apache2
if ! [ -L /var/www ]; then
    rm -rf /var/www
    ln -fs /vagrant /var/www
fi

Edit Vagrantfile to point to bootstrap.sh

Vagrant.configure("2") do |config|
    config.vm.box = "hashicorp/precise32"
    ...
    config.vm.provision :shell, path: "bootstrap.sh"
end

Ansible

https://docs.vagrantup.com/v2/provisioning/ansible.html

Vagrantfile example

Vagrant.configure("2") do |config|
    config.vm.provision "ansible" do |ansible|
        ansible.playbook = "playbook.yml"
    end
end

# optional ansible example
ansible.extra_vars = {
    ntp_server: "pool.ntp.org",
    nginx: {
        port: 8008,
        workers: 4
    }
}

Recommends using separate provisioning/ to store playbook

$ tree
.
|-- Vagrantfile
|-- provisioning
|   |-- group_vars
|           |-- all
|   |-- playbook.yml

# make sure to put the correct path to playbook.yml
Vagrant.configure("2") do |config|
config.vm.provision "ansible" do |ansible|
    ansible.playbook = "provisioning/playbook.yml"
end
end

Sharing

Providers

Selecting different provider:

option 1. vagrant up command

$ vagrant up --provider=vmware_fusion
$ vagrant up --provider=aws

option 2. set priority in Vagrantfile

Vagrant.configure("2") do |config|
    # ... other config up here

    # Prefer VMware Fusion before VirtualBox
    config.vm.provider "vmware_fusion"
    config.vm.provider "virtualbox"
end

option 3: set env var VAGRANT_DEFAULT_PROVIDER to given provider.

export VAGRANT_DEFAULT_PROVIDER="vmware_fusion"

Virtualbox

Enable linked clone - save HD space (vagrant 1.8+)

config.vm.provider "virtualbox" do |v|
    v.linked_clone = true
end

Set config in single line

config.vm.provider :virtualbox do |vb| vb.customize [“modifyvm”, :id, “–name”, “MyCoolApp”, “–memory”, “512”] end

Parallels (Mac OSX)

http://parallels.github.io/vagrant-parallels/docs/

Install plugin first

$ vagrant plugin install vagrant-parallels

To update plugin if needed

$ vagrant plugin update vagrant-parallels

Parallels will be used as default provider once plugin is installed

$ vagrant init parallels/ubuntu..

$ vagrant init boxcutter/debian82; vagrant up --provider parallels

More Parallels configurations

Use linked clone instead of default regular clone to save disk space and speed up

Change name (shown on desktop GUI)

config.vm.provider "parallels" do |prl|
    prl.name = "my_vm"
end

Issue vagrant halt on Debian stuck for 30 minutes

Virtualbox Notes

Installing guest addon

$ sudo apt-get install linux-headers-generic build-essential dkms
$ sudo mount /dev/cdrom /media/cdrom
$ sudo sh /media/cdrom/VBoxLinuxAdditions.run

Download GuestAddition manually

wget http://download.virtualbox.org/virtualbox/4.3.8/VBoxGuestAdditions_4.3.8.iso
sudo mkdir /media/VBoxGuestAdditions
sudo mount -o loop,ro VBoxGuestAdditions_4.3.8.iso /media/VBoxGuestAdditions
sudo sh /media/VBoxGuestAdditions/VBoxLinuxAdditions.run
rm VBoxGuestAdditions_4.3.8.iso
sudo umount /media/VBoxGuestAdditions
sudo rmdir /media/VBoxGuestAdditions

Package as box, so it doesn’t need to do this again

$ vagrant package --base my-virtual-machine

See vagrant-vbguest plugin instead

Plugins

List of all Plugins

Plugins are provided by 3rd party (mostly).

Install plugin

$ vagrant plugin install <plugin-name>

List all plugins

$ vagrant plugin list

Automatically install Guest Additions on Guest OS

$ vagrant plugin install vagrant-vbguest

Useful plugins

Help

Adding “-h” at end will show help

$ vagrant <command> -h

Successor

otto runs on top of Vagrant

HN Discussion

Front-end

rundeck

jenkins

Others