Getting started with Vagrant - automated dev servers deploy and provisioning
Jan 24, 2014, 1:16:14 PMWhat 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.
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.
- Download latest Vagrant .deb from official download page
- Install this .deb with Package manager
- Make sure VirtualBox+Extension Pack is also installed (VirtualBox is used for running local virtual machines)
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
- Official Vagrant cloud boxes and config sharing platform
- Official set of Ubuntu Vagrant boxes
- Official Ubuntu set of Vagrant boxes for all recent Ubuntu versions
- User Community Vagrant Boxes
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
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
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 machinevagrant halt
stop machine (yes it is notdown
:))vagrant reload
reload machinevagrant destroy
remove/delete machinevagrant ssh
connect via ssh to machinevagrant 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 eachvagrant 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
Phansible - provides an easy to use interface that helps you generate Ansible Playbooks for PHP based projects.
PuPHPet - a simple GUI to set up virtual machines for
PHPWeb development.Protobox - PuPHPet analog, but uses own installer with YAML configuration format to controls everything that is installed on the virtual machine.
Vagrant plugin for ZSH shell - auto-complete for commands, task names, box names and built-in documentation
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.