Start using Vagrant
Fabrice Bernhard6 min read
I had the chance to spread the good word by talking about adopting DevOps in Symfony projects at the Symfony Live conference. The feedback was very good (for those who attended and have not done so yet, you can give some feedback here: http://joind.in/talk/view/2756) You can also find the slides here: http://www.slideshare.net/mobile/fabrice.bernhard/adopt-devops-philosophy-on-your-symfony-projects and the source code of the slides here: https://github.com/fabriceb/sflive2011-devops)
One of the very good news is that I convinced many people (as observed on twitter) to start using vagrant after the conference. The slides gave a quick introduction, so let me give here a more detailed tutorial on how to start using vagrant.
Introduction to Vagrant
Vagrant is a ruby tool that makes the process of testing your code in a virtual machine VERY easy. You are concerned:
- If you are a developer on a complex project with a specific system configuration on the production server that you want to reproduce in your development environment painlessly. This specific system configuration can be specific versions of some packages, a specific architecture or simply a specific OS.
- If you are a Mac user! Because the chances that the project you develop will be hosted on a Mac are quite small…
It is quite amazing to see how many people develop on Macs to deploy on Linux systems and don’t use virtual environments. This has two obvious downsides:
- you need to install a working development environment on your Mac which can quickly become a pain.
- even with PHP applications, which are usually quite platform-independent, it is never truly the case and it is much better to avoid last-minute system-related surprises.
Install Vagrant
- Mac OS X
- First download VirtualBox 4 http://www.virtualbox.org/wiki/Downloads
- Then install the Vagrant gem
sudo gem install vagrant
- Debian/Ubuntu
# Install Ruby, Ruby Gems and Vagrant sudo apt-get install rubygems sudo apt-get install ruby-dev sudo apt-get install build-essential sudo gem install vagrant
Add the ruby gems path to your path
PATH=$PATH:/var/lib/gems/1.8/bin
Download and install VirtualBox
echo ‘echo “deb http://download.virtualbox.org/virtualbox/debian maverick contrib” >> /etc/apt/sources.list’ | sudo sh wget -q http://download.virtualbox.org/virtualbox/debian/oracle\_vbox.asc -O- | sudo apt-key add - sudo apt-get update sudo apt-get install virtualbox-4.0 sudo apt-get install dkms
You should now be able to type vagrant in your terminal and see the list of tasks that you can do.
$ vagrant Tasks: vagrant box # Commands to manage system boxes vagrant destroy # Destroy the environment, deleting the created virtual machines vagrant halt # Halt the running VMs in the environment vagrant help [TASK] # Describe available tasks or one specific task vagrant init [box_name] [box_url] # Initializes the current folder for Vagrant usage vagrant package # Package a Vagrant environment for distribution vagrant provision # Rerun the provisioning scripts on a running VM vagrant reload # Reload the environment, halting it then restarting it. vagrant resume # Resume a suspended Vagrant environment. vagrant ssh # SSH into the currently running Vagrant environment. vagrant ssh_config # outputs .ssh/config valid syntax for connecting to this environment via ssh vagrant status # Shows the status of the current Vagrant environment. vagrant suspend # Suspend a running Vagrant environment. vagrant up # Creates the Vagrant environment vagrant version # Prints the Vagrant version information
Now fetch the base Ubuntu Ludic 32 box provided by Vagrant. This make take a few minutes depending on your connection, since it consists in downloading around 700MB
$ vagrant box add base http://files.vagrantup.com/lucid32.box
Finally, to avoid permission problems with folder sharing between your host machine and your virtual environment, I highly recommend using NFS instead of VBox, which is the default protocol used by VirtualBox.
- On Mac OS X, you do not need to do anything, NFS is already installed.
- On Debian/Ubuntu, you just need to install the NFS package:
$ sudo apt-get install nfs-common nfs-kernel-server
Test on a first project
I set up a test project so that you can see how it works. Create a new folder called sflive2011vm. We will clone the configuration for our Vagrant Virtual Machine and then clone our actual project inside
$ cd sflive2011vm $ git clone git://github.com/fabriceb/sfLive2011vm.git . $ git clone git://github.com/fabriceb/sfLive2011.git
Now all you have to do to test the project is
$ vagrant up
and after a few minutes, Vagrant will have started a virtual Ubuntu, installed all the packages needed and set up tha machine as described in the Puppet manifest. To verify that everything worked as planned just visit http://127.0.0.1:2011/hello/master
That’s it!
Understand Vagrant
Let us now understand more deeply how Vagrant works:
The base box
The base box is simply a saved hard-disk of a Virtual Machine created with VirtualBox. It can contain anything but it needs at least :
- Ruby
- VirtualBox guest additions
- Puppet
- Chef
to be boot-strapped by Vagrant and then further configured by a Chef recipe or a Puppet manifest
Vagrantfile
This is the configuration file of Vagrant. The most useful options are port forwarding, provisioning solution (Puppet or Chef) and eventually NFS
Vagrant::Config.run do |config| config.vm.box = “base” config.vm.forward_port(“web”, 80, 2011) config.vm.provision :puppet
config.vm.share_folder(“v-root”, “/vagrant”, ”.”, :nfs => true)
end
Provisioning
The configuration of your VM is coded using Chef or Puppet. This ensures that you will reproduce exactly the same configuration in all your development VMs AND your production environment. Here is the Puppet manifest used in the example:
exec { “apt-get-update”: command => “apt-get update”, path => [“/bin”, “/usr/bin”], }
Package { ensure => installed, require => Exec[“apt-get-update”] }
class lighttpd { package { “apache2.2-bin”: ensure => absent, }
package { “lighttpd”: ensure => present, }
service { “lighttpd”: ensure => running, require => Package[“lighttpd”, “apache2.2-bin”], }
notice(“Installing Lighttpd”) }
class lighttpd-phpmysql-fastcgi inherits lighttpd {
package { “php5-cgi”: ensure => present, }
package { “mysql-server”: ensure => present, }
exec { “lighttpd-enable-mod fastcgi”: path => “/usr/bin:/usr/sbin:/bin”, creates => “/etc/lighttpd/conf-enabled/10-fastcgi.conf”, require => Package[“php5-cgi”], }
notice(“Installing PHP5 CGI and MySQL”) }
class symfony-server inherits lighttpd-phpmysql-fastcgi {
package { [“php5-cli”, “php5-sqlite”]: ensure => present, notify => Service[“lighttpd”], }
notice(“Installing PHP5 CLI and SQLite”) }
class symfony-live-server inherits symfony-server {
file { “/etc/lighttpd/conf-available/99-hosts.conf”: source => “/vagrant/files/conf/hosts.conf”, notify => Service[“lighttpd”], require => Package[“lighttpd”], }
exec { “lighttpd-enable-mod hosts”: path => “/usr/bin:/usr/sbin:/bin”, creates => “/etc/lighttpd/conf-enabled/99-hosts.conf”, require => File[“/etc/lighttpd/conf-available/99-hosts.conf”], notify => Service[“lighttpd”], }
notice(“Installing and enabling Hosts file”) }
include symfony-live-server notice(“Symfony2 server is going live!“)
Take home message
- Vagrant is an essential part of the DevOps process: it is the solution to developing, testing and deploying in the same environment. It thus ensures a smoother transition of your project from the dev team to the ops team
- Vagrant is EASY. And it is compatible with both Chef and Puppet
- Vagrant is a must for Mac developers.