Virtualisation is ubiqious in production
The shape of data centers has changed
As Ruby developers, we have it pretty good:
But...
Vagrant lowers development environment setup time, increases development/production parity, and makes the “works on my machine” excuse a relic of the past.
$ vagrant init precise32 http://files.vagrantup.com/precise32.box
$ vagrant up
$ vagrant ssh
Welcome to your Vagrant-built virtual machine.
vagrant@precise32:/vagrant$
$ vagrant suspend
[default] Saving VM state and suspending execution...
$ vagrant resume
[default] Resuming suspended VM...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
$ 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 up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'precise32'...
Which boxes are installed?
$ vagrant box list
precise32 (virtualbox)
Let's install another
$ vagrant box add precise64 http://files.vagrantup.com/precise64.box
Downloading or copying the box...
Successfully added box 'precise64' with provider 'virtualbox'!
$ vagrant box list
precise32 (virtualbox)
precise64 (virtualbox)
Now we can use either box in our Vagrantfiles
A Vagrantfile is created via the init command
$ vagrant init precise64
$ vi Vagrantfile
Generated file, minus comments
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
end
Now we can start to provision our development machines
Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
config.vm.network :forwarded_port, host: 8080, guest: 80
config.vm.provision :shell, :path => "bootstrap.sh"
end
bootstrap
#!/usr/bin/env bash
apt-get update
apt-get install -y apache2
rm -rf /var/www
ln -fs /vagrant /var/www
index.html
Hello from the VM
$ vagrant up
Visit http://localhost:8080
Why should you use Chef?
$ gem install librarian-chef
$ librarian-chef init
create Cheffile
The Cheffile
#!/usr/bin/env ruby
#^syntax detection
site 'http://community.opscode.com/api/v1'
cookbook 'apt'
cookbook 'build-essential'
cookbook 'rvm',
:git => 'https://github.com/fnichol/chef-rvm'
$ librarian-chef install
Installing apt (2.1.1)
Installing build-essential (1.4.2)
Installing chef_gem (0.1.0)
Installing rvm (0.9.1)
Sinatra Hello World
# Gemfile
source "https://rubygems.org"
gem "sinatra"
# app.rb
require 'sinatra'
get '/' do
"Hello World!"
end
# config.ru
require './app'
run Sinatra::Application
The Vagrantfile
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
config.vm.network :private_network, ip: "192.168.128.5"
config.vm.provision :chef_solo do |chef|
# This path will be expanded relative to the project directory
chef.cookbooks_path = "cookbooks"
chef.add_recipe 'apt'
chef.add_recipe 'build-essential'
chef.add_recipe 'rvm::vagrant'
chef.add_recipe 'rvm::system'
chef.json = {
rvm: {
rubies: ['2.0.0'],
default_ruby: '2.0.0',
global_gems: [
{ name: 'bundler'},
{ name: 'rake'}
],
vagrant: {
system_chef_solo: '/opt/vagrant_ruby/bin/chef-solo'
}
}
}
end
config.vm.provision :shell,
:inline => "cd /vagrant && bundle install"
end
$ vagrant up
$ vagrant ssh
vagrant@precise64:/vagrant$ cd /vagrant
vagrant@precise64:/vagrant$ rackup
Visit http://192.168.128.5:9292/
# Cheffile
+ cookbook 'mysql'
# Vagrantfile
config.vm.provision :chef_solo do |chef|
+ chef.add_recipe 'mysql::server'
...
chef.json = {
+ mysql: {
+ version: '5.5.29',
+ server_root_password: 'password',
+ server_repl_password: 'password',
+ server_debian_password: 'password',
+ allow_remote_root: true,
+ remove_test_database: true
+ }
We don't need to rebuild
$ vagrant provision
We can focus one provisioning block
$ vagrant provision --provision-with chef_solo
Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
config.vm.provision :shell, :path => "bootstrap.sh"
config.vm.define :app do |web|
config.vm.network :private_network, ip: "192.168.128.5"
# provisioning steps for app
end
config.vm.define :db do |db|
config.vm.network :private_network, ip: "192.168.128.10"
# provisoning steps for db
end
end
$ vagrant up
or
$ vagrant up app
$ vagrant up db
vagrant package --output ruby-mysql-demo.box
vagrant box add ruby-mysql-demo ./ruby-mysql-demo.box
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ruby-mysql-demo"
config.vm.box_url = 'http://www.example.com/ruby-mysql-demo.box'
end
# Vagrantfile.pkg
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.host_name = "ruby-dev-box"
config.vm.forward_port 3306, 3307 # mysql
end
vagrant package --output ruby-mysql-demo.box \
--vagrantfile Vagrantfile.pkg
config.vm.provider :virtualbox do |vb|
vb.gui = true
end
Slides and examples are available online https://github.com/brrygrdn/an-intro-to-vagrant