@coldfumonkeh
Matt Gifford
WINNING with
VAGRANT, PUPPET
and CHEF
Create and configure
lightweight, reproducible, and
portable development
environments.
QUESTION
Environment per project
Dev ~= Test ~= Staging ~= Production
Easy to define & transport
Easy to tear down
Provisionable
Versionable
Shared across the team
➜ ~
Usage: vagrant [options] <command> [<args>]
-v, --version Print the version and exit.
-h, --help Print this help.
vagrant
Common commands:
box manages boxes: installation, removal, etc.
connect connect to a remotely shared Vagrant environment
destroy stops and deletes all traces of the vagrant machine
global-status outputs status Vagrant environments for this user
halt stops the vagrant machine
help shows the help for a subcommand
init initializes a new Vagrant environment by creating a Vagrantfile
login log in to Vagrant Cloud
package packages a running vagrant environment into a box
plugin manages plugins: install, uninstall, update, etc.
provision provisions the vagrant machine
rdp connects to machine via RDP
reload restarts vagrant machine, loads new Vagrantfile configuration
resume resume a suspended vagrant machine
share share your Vagrant environment with anyone in the world
ssh connects to machine via SSH
ssh-config outputs OpenSSH valid configuration to connect to the machine
status outputs status of the vagrant machine
suspend suspends the machine
up starts and provisions the vagrant environment
version prints current and latest Vagrant version
For help on any individual command run `vagrant COMMAND -h`
Additional subcommands are available, but are either more
advanced or not commonly used.
To see all subcommands, run the command
`vagrant list-commands`.
Generating a
Vagrantfile
Select base box
Choose virtualization provider
Configure VM parameters
Configure networking
Tweak SSH settings
Mount local folders
Provision machine
➜ ~
Usage: vagrant init [options] [name [url]]
Options:
-f, --force Overwrite existing Vagrantfile
-m, --minimal Create minimal Vagrantfile (no help comments)
--output FILE Output path for the box. '-' for stdout
-h, --help Print this help
vagrant init -h
➜ ~ vagrant init
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
15
Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "base"
end
➜ ~ vagrant init precise32 http://files.vagrantup.com/precise32.box
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
17
Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
end
Boxes
http://vagrantbox.es
https://atlas.hashicorp.com/boxes/search
https://github.com/jedi4ever/veewee
https://packer.io
Box Management
➜ ~
Usage: vagrant box <subcommand> [<args>]
Available subcommands:
add
list
outdated
remove
repackage
update
vagrant box
➜ ~
==> box: Adding box 'precise32' (v0) for provider: virtualbox
box: Downloading: http://files.vagrantup.com/precise32.box
box: Progress: 38% (Rate: 615k/s, Estimated time remaining: 0:04:25)
==> box: Successfully added box 'precise32' (v0) for 'virtualbox'!
vagrant box add --provider virtualbox precise32 http://
files.vagrantup.com/precise32.box
➜ ~ vagrant box list
atomia/windows-2012R2 (virtualbox, 0.2.0)
precise32 (virtualbox, 0)
➜ ~ vagrant box list
atomia/windows-2012R2 (virtualbox, 0.2.0)
box-disk1.vmdk
box.ovf
metadata.json
Vagrantfile
28
Up and Running
(and destroying)
➜ ~ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1430903546481_36514
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
default: The guest additions on this VM do not match the installed version of
default: VirtualBox! In most cases this is fine, but in rare cases it can
default: prevent things such as shared folders from working properly. If you see
default: shared folder errors, please make sure the guest additions within the
default: virtual machine match the version of VirtualBox you have installed on
default: your host and reload your VM.
default:
default: Guest Additions Version: 4.2.0
default: VirtualBox Version: 4.3
==> default: Mounting shared folders...
default: /vagrant => /Users/monkehworks/my_project
➜ ~
Bringing machine 'default' up with 'virtualbox' provider...
==> default: VirtualBox VM is already running.
vagrant up
➜ ~ vagrant status
Current machine states:
default running (virtualbox)
The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.
➜ ~
==> default: Saving VM state and suspending execution...
vagrant suspend
➜ ~ vagrant status
Current machine states:
default saved (virtualbox)
To resume this VM, simply run `vagrant up`.
➜ ~ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Resuming suspended VM...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection refused. Retrying...
==> default: Machine booted and ready!
➜ ~
==> default: Attempting graceful shutdown of VM...
vagrant halt
➜ ~ vagrant status
Current machine states:
default power (virtualbox)
The VM is powered off. To restart the VM, simply run `vagrant up`.
➜ ~ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
default: The guest additions on this VM do not match the installed version of
default: VirtualBox! In most cases this is fine, but in rare cases it can
default: prevent things such as shared folders from working properly. If you see
default: shared folder errors, please make sure the guest additions within the
default: virtual machine match the version of VirtualBox you have installed on
default: your host and reload your VM.
default:
default: Guest Additions Version: 4.2.0
default: VirtualBox Version: 4.3
==> default: Mounting shared folders...
default: /vagrant => /Users/monkehworks/my_project
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.
➜ ~
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...
vagrant destroy
➜ ~ vagrant status
Current machine states:
default not created (virtualbox)
default: Are you sure you want to destroy the 'default' VM? [y/N] y
The environment has not yet been created. Run `vagrant up` to
create the environment. If a machine is not created, only the
default provider will be shown. So if a provider is not listed,
then the machine is not created for that environment.
36
Connections
➜ ~ vagrant ssh
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
* Documentation: https://help.ubuntu.com/
New release '14.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
Welcome to your Vagrant-built virtual machine.
Last login: Wed May 6 13:56:45 2015 from 10.0.2.2
vagrant@precise32:~$ sudo su
root@precise32:/home/vagrant#
root@precise32:/home/vagrant# cat .ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr
+kz4TjGYe7gHzIw
+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYe
t2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4p
zC6kivAIhyfHilFR61RGL
+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm
+R4LOzFUGaHqHDLKLX
+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant
insecure public key
root@precise32:/home/vagrant# cat .ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr
+kz4TjGYe7gHzIw
+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYe
t2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4p
zC6kivAIhyfHilFR61RGL
+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm
+R4LOzFUGaHqHDLKLX
+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant
insecure public key
➜ ~ vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /Users/monkehworks/.vagrant.d/insecure_private_key
IdentitiesOnly yes
LogLevel FATAL
➜ ~ vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /Users/monkehworks/.vagrant.d/insecure_private_key
IdentitiesOnly yes
LogLevel FATAL
➜ ~ cat ~/.vagrant.d/insecure_private_key
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
-----END RSA PRIVATE KEY-----
Portability
By sharing your Vagrantfile you
are essentially sharing your
development environment.
46
Infrastructure as
Code
47
Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
end
Networking
49
config.vm.network :public_network
Bridged Network
50
config.vm.network :forwarded_port, guest: 80, host: 8080
Port Forwarding
51
config.vm.network :private_network, ip: "192.168.10.10"
Private IP Space
52
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :private_network, ip: "192.168.10.10"
end
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431011744813_57334
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: hostonly
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
➜ ~ vagrant up
53
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :private_network, ip: "192.168.10.10"
end
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431011744813_57334
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: hostonly
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
➜ ~ vagrant up
54
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :forwarded_port, guest: 80, host: 8080
end
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431011744813_57334
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 80 => 8080 (adapter 1)
default: 22 => 2222 (adapter 1)
➜ ~ vagrant up
55
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431011744813_57334
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 80 => 8080 (adapter 1)
default: 22 => 2222 (adapter 1)
➜ ~ vagrant up
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :forwarded_port, guest: 80, host: 8080
end
56
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :public_network
end
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431012579630_44486
==> default: Clearing any previously set network interfaces...
==> default: Available bridged network interfaces:
1) en1: Wi-Fi (AirPort)
2) en0: Ethernet
3) p2p0
default: What interface should the network bridge to?
➜ ~ vagrant up
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: bridged
==> default: Forwarding ports...
1
57
➜ ~ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431012579630_44486
==> default: Clearing any previously set network interfaces...
==> default: Available bridged network interfaces:
1) en1: Wi-Fi (AirPort)
2) en0: Ethernet
3) p2p0
default: What interface should the network bridge to?
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: bridged
==> default: Forwarding ports...
1
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :public_network
end
58
➜ ~ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1431012579630_44486
==> default: Clearing any previously set network interfaces...
==> default: Available bridged network interfaces:
1) en1: Wi-Fi (AirPort)
2) en0: Ethernet
3) p2p0
default: What interface should the network bridge to?
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: bridged
==> default: Forwarding ports...
1
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network "public_network", :bridge => 'en1: Wi-‐Fi (AirPort)'
end
Synced Folders
==> default: Mounting shared folders...
default: /vagrant => /Users/monkehworks/my_project
Mount Management
config.vm.synced_folder "htdocs/", "/var/www"
==> default: Mounting shared folders…
default: /var/www => /Users/monkehworks/my_project/htdocs
default: /vagrant => /Users/monkehworks/my_project
VM Properties
config.vm.hostname = "mymachine"
config.vm.provider :virtualbox do |v|
v.customize ["modifyvm", :id, '-‐chipset', 'ich9']
v.customize ["modifyvm", :id, "-‐natdnshostresolver1", "on"]
v.customize ["modifyvm", :id, "-‐ioapic", "on"]
v.customize ["modifyvm", :id, "-‐memory", 2048]
v.customize ["modifyvm", :id, "-‐cpus", "4"]
#v.gui = true
end
Provisioning
Add specific software
Create configuration files
Execute commands
Create users
Manage services
Automatically executed on vagrant up
Aim to have an exact
(or as close as possible)
copy of your production
environment
Shell
Ansible
Chef Solo
Chef Client
Puppet Apply
Puppet Agent
Shell Provisioning
config.vm.provision :shell, :inline =>
"mount ‐t tmpfs ‐o size=50m,mode=0777 tmpfs /vagrant/ app/cache"
# -*- mode: ruby -*-
# vi: set ft=ruby :
$script = <<SCRIPT
echo I am provisioning...
date > /etc/vagrant_provisioned_at
SCRIPT
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.provision :shell, :inline $script
end
config.vm.provision "shell", path: "script.sh"
config.vm.provision "shell", path: "https://example.com/provisioner.sh"
External Scripts
Written in Ruby
Open source with enterprise revenue model
Similar features
Both have a standalone and server-side edition
Supported by a large community
Modularized components
Use packages for software installs
Use templating for custom files
Filesystem methods
and more…
Chef & Puppet
Chef Puppet
Modules Cookbooks Modules
Actions Recipes Manifests
Language Ruby extended with DSL DSL
Running order Sequential “Random”
Approach Define actions Define state
Programming style Procedural “OO-esque”
An Intro to Chef
Download cookbooks
- https://github.com/opscode-cookbooks
Configure chef.cookbooks_path in Vagrantfile
Add recipes using chef.add_recipe in Vagrantfile
Configure attributes with chef.json
Group custom actions in custom cookbook
Using Chef Solo
Vagrantfile
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = "./tools/chef/cookbooks"
chef.add_recipe "mysql::server"
chef.json = {
"mysql" => {
"server_root_password" => "foo",
"server_repl_password" => "foo",
"server_debian_password" => "foo"
}
}
end
cookbook
├── README.md
├── attributes
├── definitions
├── files
│ └── default
├── libraries
├── metadata.rb
├── providers
├── recipes
│ └── default.rb
├── resources
└── templates
└── default
default['mysql']['port'] = 3306
default['mysql']['nice'] = 0
case node['platform_family']
when 'debian'
default['mysql']['server']['packages'] = %w[mysql-server]
default['mysql']['service_name'] = 'mysql'
default['mysql']['basedir'] = '/usr'
default['mysql']['data_dir'] = '/var/lib/mysql'
default['mysql']['root_group'] = 'root'
default['mysql']['mysqladmin_bin'] = '/usr/bin/mysqladmin'
default['mysql']['mysql_bin'] = '/usr/bin/mysql'
default['mysql']['conf_dir'] = '/etc/mysql'
default['mysql']['confd_dir'] = '/etc/mysql/conf.d'
default['mysql']['socket'] = '/var/run/mysqld/mysqld.sock'
default['mysql']['pid_file'] = '/var/run/mysqld/mysqld.pid'
default['mysql']['old_passwords'] = 0
default['mysql']['grants_path'] = '/etc/mysql/grants.sql'
MySQL Attributes
...
group 'mysql' do
action :create
end
user 'mysql' do
comment 'MySQL Server'
gid 'mysql'
system true
home node['mysql']['data_dir']
shell '/sbin/nologin'
end
node['mysql']['server']['packages'].each do |name|
package name do
action :install
notifies :start, 'service[mysql]', :immediately
end
end
...
MySQL Server Recipe
[client]
host user = localhost
= debian-sys-maint
password = <%= node['mysql']['server_debian_password'] %>
socket = <%= node['mysql']['socket'] %>
[mysql_upgrade]
host = localhost
user = debian‐sys-maint
password = <%= node['mysql']['server_debian_password'] %>
socket = <%= node['mysql']['socket'] %>
basedir = /usr
MySQL Template
Cron
Directory
Execute
File
Git
Group
Link
Log
Package
Service
Template
User
and more...
Typical Chef resources
Cooking for yourself
execute 'update apt' do command "apt‐get update"
action :run
end
package 'mysql-server' do
action :install
notifies :start, 'service[mysql]', :immediately
end
package 'apache2' do
action :install
notifies :start, 'service[apache2]', :delayed
end
package 'php5' do
action :install
notifies :reload, 'service[apache2]', :delayed
end
./tools/chef/cookbooks/project/recipes/default.rb
execute 'assign‐root‐password' do
command "/usr/bin/mysqladmin -u root password ‘#{node['project']
['server_root_password']}'"
action :run
only_if "/usr/bin/mysql -u root -e 'show databases;'"
end
service 'mysql' do
service_name 'mysql'
supports :status => true, :restart => true, :reload => true
action :enable
end
service 'apache2' do
service_name 'apache2'
supports :status => true, :restart => true, :reload => true
action :enable
end
./tools/chef/cookbooks/project/recipes/default.rb
Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = “http://files.vagrantup.com/precise32.box"
config.vm.synced_folder "htdocs/", "/var/www"
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = "./tools/chef/cookbooks"
chef.add_recipe "project"
chef.json = {
"project" => {
"server_root_password" => "foo"
}
}
end
end
➜ ~ vagrant up
...
==> default: Mounting shared folders…
default: /var/www => /Users/monkehworks/my_project/htdocs
default: /vagrant => /Users/monkehworks/my_project
==> default: /tmp/vagrant-chef-1/chef-solo-1/cookbooks
==> default: Running provisioner: chef_solo…
Generating chef JSON and uploading…
Running chef-solo…
...
An Intro to Puppet
Download modules
- https://forge.puppetlabs.com
Configure in Vagrantfile:
- puppet.module_path
- puppet.manifests_path
- puppet.manifest_file
Provisioning flow happens in the main manifest
Configure attributes with puppet.facter
Using Puppet Apply
Vagrantfile
config.vm.provision :puppet do |puppet|
puppet.manifests_path = "./tools/puppet/manifests"
puppet.module_path = "./tools/puppet/modules"
puppet.manifest_file = "init.pp"
puppet.options = ['--verbose']
end
init.pp
include mysql::server
class {
'::mysql::server' :root_password => 'foo'
}
module
├── README.md
├── files
├── lib
├──
metadata.json
├── spec
├── manifests
│ └── init.pp
│ └──
params.pp
├── resources
└── templates
└── tests
MySQL Params
class mysql::params {
$manage_config_file = true
$old_root_password = ''
$purge_conf_dir = false
$restart = false
$root_password = 'UNSET'
$server_package_ensure = 'present'
$server_service_manage = true
$server_service_enabled = true
# mysql::bindings
$bindings_enable = false
$java_package_ensure = 'present'
$java_package_provider = undef
$perl_package_ensure = 'present'
$perl_package_provider = undef
$php_package_ensure = 'present'
$php_package_provider = undef
$python_package_ensure = 'present'
$python_package_provider = undef
$ruby_package_ensure = 'present'
$ruby_package_provider = undef
MySQL server manifest
class mysql::server (
$config_file = $mysql::params::config_file
$manage_config_file = $mysql::params::manage_config_file
$old_root_password = $mysql::params::old_root_password,
$override_options = {},
$package_ensure = $mysql::params::server_package_ensure,
$package_name = $mysql::params::server_package_name,
$purge_conf_dir = $mysql::params::purge_conf_dir,
$remove_default_accounts = false,
$restart = $mysql::params::restart,
$root_group = $mysql::params::root_group,
$root_password = $mysql::params::root_password,
$service_enabled = $mysql::params::server_service_enabled,
$service_manage = $mysql::params::server_service_manage,
$service_name = $mysql::params::server_service_name,
$service_provider = $mysql::params::server_service_provider,
# Deprecated parameters
$enabled = undef,
$manage_service = undef
) inherits mysql::params {
...
[client]
user=root
host=localhost
<% unless scope.lookupvar('mysql::server::root_password') == 'UNSET' ‐%>
password='<%= scope.lookupvar('mysql::server::root_password') %>'
<% end ‐%>
socket=<%= @options['client']['socket'] ‐%>
MySQL Template
Computer
Cron
Exec
File
Filebucket
Group
Host
Interface
Package
Service
Sshkey
User
and more…
Typical Puppet resources
Pulling your own
strings
exec { "apt‐update":
command => "/usr/bin/apt-get update",
}
package { 'mysql‐server':
ensure => present,
require => Exec['apt‐update'],
notify => Service['mysql'],
}
package { 'apache2':
ensure => present,
require => Exec['apt‐update'],
notify => Package['php5'],
}
package { 'php5':
ensure => present,
require => Exec['apt‐update'],
notify => Service['apache2'],
}
./tools/puppet/manifests/init.pp
./tools/puppet/manifests/init.pp
exec {'assign‐root‐password':
command => "/usr/bin/mysqladmin ‐u root password $root_password",
require => Package["mysql‐server"],
onlyif => "/usr/bin/mysql ‐u root ‐e 'show databases;'"
}
service { "mysql":
name => "mysql",
ensure => running,
enable => true,
hasrestart => true,
require => Package["mysql‐server"],
}
service { "apache2":
name => "apache2",
ensure => running,
enable => true,
hasrestart => true,
require => Package["apache2"],
}
Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise32"
config.vm.box_url = “http://files.vagrantup.com/precise32.box"
config.vm.synced_folder "htdocs/", "/var/www"
config.vm.provision :puppet do |puppet|
puppet.manifests_path = "./tools/puppet/manifests"
puppet.module_path = "./tools/puppet/modules"
puppet.manifest_file = “init.pp"
puppet.facter = {
“root_password” => “foo”,
}
puppet.options = ['--verbose']
end
end
(when machine is running)
➜ ~ vagrant provision
Problems with
Provisioning
Provisioning is often slow
Quality of public cookbooks/manifests
Support on cookbooks/manifests
Writing it yourself can be difficult
Distribution restrictions
➜ ~ vagrant package
Possible solution for slow provisioning
Is not the same as vagrant box repackage
Use exported box as new base box
No provisioning required on startup
Possibility of doing “light” provisioning instead
Multi-Machine Setup
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.provision "shell", inline: "/usr/bin/apt‐get update"
config.vm.box = "debian‐7.1.0"
config.vm.define "web", primary: true do |web|
web.vm.hostname = "web"
web.vm.network :private_network, ip: "192.168.33.10"
web.vm.synced_folder "htdocs/", "/var/www"
web.vm.provision :puppet do |puppet|
puppet.manifests_path = "./tools/puppet/manifests"
puppet.module_path = "./tools/puppet/modules"
puppet.manifest_file = "web.pp"
puppet.options = ['-‐verbose']
end
end
config.vm.define "db" do |db|
db.vm.hostname = "db"
db.vm.network :private_network, ip: "192.168.33.11"
db.vm.provision :puppet do |puppet|
puppet.manifests_path = "./tools/puppet/manifests"
puppet.module_path = "./tools/puppet/modules"
puppet.manifest_file = "db.pp"
puppet.options = ['-‐verbose']
puppet.facter = {
"root_password" => "foo",
}
end
end
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.provision "shell", inline: "/usr/bin/apt‐get update"
config.vm.box = "debian‐7.1.0"
config.vm.define "web", primary: true do |web|
web.vm.hostname = "web"
web.vm.network :private_network, ip: "192.168.33.10"
web.vm.synced_folder "htdocs/", "/var/www"
web.vm.provision :puppet do |puppet|
puppet.manifests_path = "./tools/puppet/manifests"
puppet.module_path = "./tools/puppet/modules"
puppet.manifest_file = "web.pp"
puppet.options = ['-‐verbose']
end
end
config.vm.define "db" do |db|
db.vm.hostname = "db"
db.vm.network :private_network, ip: "192.168.33.11"
db.vm.provision :puppet do |puppet|
puppet.manifests_path = "./tools/puppet/manifests"
puppet.module_path = "./tools/puppet/modules"
puppet.manifest_file = "db.pp"
puppet.options = ['-‐verbose']
puppet.facter = {
"root_password" => "foo",
}
end
end
➜ ~ vagrant up
➜ ~ vagrant destroy
➜ ~ vagrant ssh
➜ ~ vagrant up web
➜ ~ vagrant ssh web
➜ ~ vagrant destroy web
➜ ~ vagrant up db
➜ ~ vagrant ssh db
➜ ~ vagrant destroy db
ColdFusion and
Vagrant
https://github.com/lewg/cfenv-chef
https://github.com/davejlong/vagrant-boxes
https://github.com/mikesprague/vagrant-lemtl
https://github.com/bdcravens/railo-vagrant
https://github.com/gratzc/it-works-on-my-machine-chef-vagrant
#WINNING

ITB2015 - Winning with Vagrant, Puppet and Chef

  • 1.
  • 4.
    Create and configure lightweight,reproducible, and portable development environments.
  • 7.
  • 9.
    Environment per project Dev~= Test ~= Staging ~= Production Easy to define & transport Easy to tear down Provisionable Versionable Shared across the team
  • 10.
    ➜ ~ Usage: vagrant[options] <command> [<args>] -v, --version Print the version and exit. -h, --help Print this help. vagrant Common commands: box manages boxes: installation, removal, etc. connect connect to a remotely shared Vagrant environment destroy stops and deletes all traces of the vagrant machine global-status outputs status Vagrant environments for this user halt stops the vagrant machine help shows the help for a subcommand init initializes a new Vagrant environment by creating a Vagrantfile login log in to Vagrant Cloud package packages a running vagrant environment into a box plugin manages plugins: install, uninstall, update, etc. provision provisions the vagrant machine rdp connects to machine via RDP reload restarts vagrant machine, loads new Vagrantfile configuration resume resume a suspended vagrant machine share share your Vagrant environment with anyone in the world ssh connects to machine via SSH ssh-config outputs OpenSSH valid configuration to connect to the machine status outputs status of the vagrant machine suspend suspends the machine up starts and provisions the vagrant environment version prints current and latest Vagrant version
  • 11.
    For help onany individual command run `vagrant COMMAND -h` Additional subcommands are available, but are either more advanced or not commonly used. To see all subcommands, run the command `vagrant list-commands`.
  • 12.
  • 13.
    Select base box Choosevirtualization provider Configure VM parameters Configure networking Tweak SSH settings Mount local folders Provision machine
  • 14.
    ➜ ~ Usage: vagrantinit [options] [name [url]] Options: -f, --force Overwrite existing Vagrantfile -m, --minimal Create minimal Vagrantfile (no help comments) --output FILE Output path for the box. '-' for stdout -h, --help Print this help vagrant init -h ➜ ~ vagrant init A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
  • 15.
    15 Vagrantfile # -*- mode:ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "base" end
  • 16.
    ➜ ~ vagrantinit precise32 http://files.vagrantup.com/precise32.box A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
  • 17.
    17 Vagrantfile # -*- mode:ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" end
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 24.
  • 25.
    ➜ ~ Usage: vagrantbox <subcommand> [<args>] Available subcommands: add list outdated remove repackage update vagrant box
  • 26.
    ➜ ~ ==> box:Adding box 'precise32' (v0) for provider: virtualbox box: Downloading: http://files.vagrantup.com/precise32.box box: Progress: 38% (Rate: 615k/s, Estimated time remaining: 0:04:25) ==> box: Successfully added box 'precise32' (v0) for 'virtualbox'! vagrant box add --provider virtualbox precise32 http:// files.vagrantup.com/precise32.box ➜ ~ vagrant box list atomia/windows-2012R2 (virtualbox, 0.2.0) precise32 (virtualbox, 0) ➜ ~ vagrant box list atomia/windows-2012R2 (virtualbox, 0.2.0)
  • 27.
  • 28.
  • 29.
    ➜ ~ vagrantup Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1430903546481_36514 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection timeout. Retrying... ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... default: The guest additions on this VM do not match the installed version of default: VirtualBox! In most cases this is fine, but in rare cases it can default: prevent things such as shared folders from working properly. If you see default: shared folder errors, please make sure the guest additions within the default: virtual machine match the version of VirtualBox you have installed on default: your host and reload your VM. default: default: Guest Additions Version: 4.2.0 default: VirtualBox Version: 4.3 ==> default: Mounting shared folders... default: /vagrant => /Users/monkehworks/my_project
  • 30.
    ➜ ~ Bringing machine'default' up with 'virtualbox' provider... ==> default: VirtualBox VM is already running. vagrant up ➜ ~ vagrant status Current machine states: default running (virtualbox) The VM is running. To stop this VM, you can run `vagrant halt` to shut it down forcefully, or you can run `vagrant suspend` to simply suspend the virtual machine. In either case, to restart it again, simply run `vagrant up`.
  • 31.
    ➜ ~ ==> default:Saving VM state and suspending execution... vagrant suspend ➜ ~ vagrant status Current machine states: default saved (virtualbox) To resume this VM, simply run `vagrant up`.
  • 32.
    ➜ ~ vagrantup Bringing machine 'default' up with 'virtualbox' provider... ==> default: Resuming suspended VM... ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection refused. Retrying... ==> default: Machine booted and ready!
  • 33.
    ➜ ~ ==> default:Attempting graceful shutdown of VM... vagrant halt ➜ ~ vagrant status Current machine states: default power (virtualbox) The VM is powered off. To restart the VM, simply run `vagrant up`.
  • 34.
    ➜ ~ vagrantup Bringing machine 'default' up with 'virtualbox' provider... ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection timeout. Retrying... ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... default: The guest additions on this VM do not match the installed version of default: VirtualBox! In most cases this is fine, but in rare cases it can default: prevent things such as shared folders from working properly. If you see default: shared folder errors, please make sure the guest additions within the default: virtual machine match the version of VirtualBox you have installed on default: your host and reload your VM. default: default: Guest Additions Version: 4.2.0 default: VirtualBox Version: 4.3 ==> default: Mounting shared folders... default: /vagrant => /Users/monkehworks/my_project ==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision` ==> default: to force provisioning. Provisioners marked to run always will still run.
  • 35.
    ➜ ~ ==> default:Forcing shutdown of VM... ==> default: Destroying VM and associated drives... vagrant destroy ➜ ~ vagrant status Current machine states: default not created (virtualbox) default: Are you sure you want to destroy the 'default' VM? [y/N] y The environment has not yet been created. Run `vagrant up` to create the environment. If a machine is not created, only the default provider will be shown. So if a provider is not listed, then the machine is not created for that environment.
  • 36.
  • 37.
    ➜ ~ vagrantssh Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686) * Documentation: https://help.ubuntu.com/ New release '14.04.2 LTS' available. Run 'do-release-upgrade' to upgrade to it. Welcome to your Vagrant-built virtual machine. Last login: Wed May 6 13:56:45 2015 from 10.0.2.2 vagrant@precise32:~$ sudo su root@precise32:/home/vagrant#
  • 38.
    root@precise32:/home/vagrant# cat .ssh/authorized_keys ssh-rsaAAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr +kz4TjGYe7gHzIw +niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYe t2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4p zC6kivAIhyfHilFR61RGL +GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm +R4LOzFUGaHqHDLKLX +FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key
  • 39.
    root@precise32:/home/vagrant# cat .ssh/authorized_keys ssh-rsaAAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr +kz4TjGYe7gHzIw +niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYe t2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4p zC6kivAIhyfHilFR61RGL +GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm +R4LOzFUGaHqHDLKLX +FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key
  • 40.
    ➜ ~ vagrantssh-config Host default HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile /Users/monkehworks/.vagrant.d/insecure_private_key IdentitiesOnly yes LogLevel FATAL
  • 41.
    ➜ ~ vagrantssh-config Host default HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile /Users/monkehworks/.vagrant.d/insecure_private_key IdentitiesOnly yes LogLevel FATAL
  • 42.
    ➜ ~ cat~/.vagrant.d/insecure_private_key -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2 hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1 Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf 4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX 3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj 3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+ dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz 6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH +vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s= -----END RSA PRIVATE KEY-----
  • 43.
  • 45.
    By sharing yourVagrantfile you are essentially sharing your development environment.
  • 46.
  • 47.
    47 Vagrantfile # -*- mode:ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" end
  • 48.
  • 49.
  • 50.
    50 config.vm.network :forwarded_port, guest:80, host: 8080 Port Forwarding
  • 51.
    51 config.vm.network :private_network, ip:"192.168.10.10" Private IP Space
  • 52.
    52 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box= "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :private_network, ip: "192.168.10.10" end Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431011744813_57334 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: hostonly ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ➜ ~ vagrant up
  • 53.
    53 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box= "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :private_network, ip: "192.168.10.10" end Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431011744813_57334 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: hostonly ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ➜ ~ vagrant up
  • 54.
    54 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box= "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :forwarded_port, guest: 80, host: 8080 end Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431011744813_57334 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 80 => 8080 (adapter 1) default: 22 => 2222 (adapter 1) ➜ ~ vagrant up
  • 55.
    55 Bringing machine 'default'up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431011744813_57334 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 80 => 8080 (adapter 1) default: 22 => 2222 (adapter 1) ➜ ~ vagrant up Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :forwarded_port, guest: 80, host: 8080 end
  • 56.
    56 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box= "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :public_network end Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431012579630_44486 ==> default: Clearing any previously set network interfaces... ==> default: Available bridged network interfaces: 1) en1: Wi-Fi (AirPort) 2) en0: Ethernet 3) p2p0 default: What interface should the network bridge to? ➜ ~ vagrant up ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: bridged ==> default: Forwarding ports... 1
  • 57.
    57 ➜ ~ vagrantup Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431012579630_44486 ==> default: Clearing any previously set network interfaces... ==> default: Available bridged network interfaces: 1) en1: Wi-Fi (AirPort) 2) en0: Ethernet 3) p2p0 default: What interface should the network bridge to? ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: bridged ==> default: Forwarding ports... 1 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :public_network end
  • 58.
    58 ➜ ~ vagrantup Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'precise32'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: test_default_1431012579630_44486 ==> default: Clearing any previously set network interfaces... ==> default: Available bridged network interfaces: 1) en1: Wi-Fi (AirPort) 2) en0: Ethernet 3) p2p0 default: What interface should the network bridge to? ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: bridged ==> default: Forwarding ports... 1 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network "public_network", :bridge => 'en1: Wi-‐Fi (AirPort)' end
  • 59.
  • 60.
    ==> default: Mountingshared folders... default: /vagrant => /Users/monkehworks/my_project Mount Management config.vm.synced_folder "htdocs/", "/var/www" ==> default: Mounting shared folders… default: /var/www => /Users/monkehworks/my_project/htdocs default: /vagrant => /Users/monkehworks/my_project
  • 61.
  • 62.
    config.vm.hostname = "mymachine" config.vm.provider:virtualbox do |v| v.customize ["modifyvm", :id, '-‐chipset', 'ich9'] v.customize ["modifyvm", :id, "-‐natdnshostresolver1", "on"] v.customize ["modifyvm", :id, "-‐ioapic", "on"] v.customize ["modifyvm", :id, "-‐memory", 2048] v.customize ["modifyvm", :id, "-‐cpus", "4"] #v.gui = true end
  • 63.
  • 64.
    Add specific software Createconfiguration files Execute commands Create users Manage services Automatically executed on vagrant up
  • 65.
    Aim to havean exact (or as close as possible) copy of your production environment
  • 66.
  • 67.
  • 68.
    config.vm.provision :shell, :inline=> "mount ‐t tmpfs ‐o size=50m,mode=0777 tmpfs /vagrant/ app/cache"
  • 69.
    # -*- mode:ruby -*- # vi: set ft=ruby : $script = <<SCRIPT echo I am provisioning... date > /etc/vagrant_provisioned_at SCRIPT VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.provision :shell, :inline $script end
  • 70.
    config.vm.provision "shell", path:"script.sh" config.vm.provision "shell", path: "https://example.com/provisioner.sh" External Scripts
  • 74.
    Written in Ruby Opensource with enterprise revenue model Similar features Both have a standalone and server-side edition Supported by a large community Modularized components Use packages for software installs Use templating for custom files Filesystem methods and more… Chef & Puppet
  • 75.
    Chef Puppet Modules CookbooksModules Actions Recipes Manifests Language Ruby extended with DSL DSL Running order Sequential “Random” Approach Define actions Define state Programming style Procedural “OO-esque”
  • 76.
  • 77.
    Download cookbooks - https://github.com/opscode-cookbooks Configurechef.cookbooks_path in Vagrantfile Add recipes using chef.add_recipe in Vagrantfile Configure attributes with chef.json Group custom actions in custom cookbook Using Chef Solo
  • 78.
    Vagrantfile config.vm.provision :chef_solo do|chef| chef.cookbooks_path = "./tools/chef/cookbooks" chef.add_recipe "mysql::server" chef.json = { "mysql" => { "server_root_password" => "foo", "server_repl_password" => "foo", "server_debian_password" => "foo" } } end
  • 79.
    cookbook ├── README.md ├── attributes ├──definitions ├── files │ └── default ├── libraries ├── metadata.rb ├── providers ├── recipes │ └── default.rb ├── resources └── templates └── default
  • 80.
    default['mysql']['port'] = 3306 default['mysql']['nice']= 0 case node['platform_family'] when 'debian' default['mysql']['server']['packages'] = %w[mysql-server] default['mysql']['service_name'] = 'mysql' default['mysql']['basedir'] = '/usr' default['mysql']['data_dir'] = '/var/lib/mysql' default['mysql']['root_group'] = 'root' default['mysql']['mysqladmin_bin'] = '/usr/bin/mysqladmin' default['mysql']['mysql_bin'] = '/usr/bin/mysql' default['mysql']['conf_dir'] = '/etc/mysql' default['mysql']['confd_dir'] = '/etc/mysql/conf.d' default['mysql']['socket'] = '/var/run/mysqld/mysqld.sock' default['mysql']['pid_file'] = '/var/run/mysqld/mysqld.pid' default['mysql']['old_passwords'] = 0 default['mysql']['grants_path'] = '/etc/mysql/grants.sql' MySQL Attributes
  • 81.
    ... group 'mysql' do action:create end user 'mysql' do comment 'MySQL Server' gid 'mysql' system true home node['mysql']['data_dir'] shell '/sbin/nologin' end node['mysql']['server']['packages'].each do |name| package name do action :install notifies :start, 'service[mysql]', :immediately end end ... MySQL Server Recipe
  • 82.
    [client] host user =localhost = debian-sys-maint password = <%= node['mysql']['server_debian_password'] %> socket = <%= node['mysql']['socket'] %> [mysql_upgrade] host = localhost user = debian‐sys-maint password = <%= node['mysql']['server_debian_password'] %> socket = <%= node['mysql']['socket'] %> basedir = /usr MySQL Template
  • 83.
  • 84.
  • 85.
    execute 'update apt'do command "apt‐get update" action :run end package 'mysql-server' do action :install notifies :start, 'service[mysql]', :immediately end package 'apache2' do action :install notifies :start, 'service[apache2]', :delayed end package 'php5' do action :install notifies :reload, 'service[apache2]', :delayed end ./tools/chef/cookbooks/project/recipes/default.rb
  • 86.
    execute 'assign‐root‐password' do command"/usr/bin/mysqladmin -u root password ‘#{node['project'] ['server_root_password']}'" action :run only_if "/usr/bin/mysql -u root -e 'show databases;'" end service 'mysql' do service_name 'mysql' supports :status => true, :restart => true, :reload => true action :enable end service 'apache2' do service_name 'apache2' supports :status => true, :restart => true, :reload => true action :enable end ./tools/chef/cookbooks/project/recipes/default.rb
  • 87.
    Vagrantfile VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION)do |config| config.vm.box = "precise32" config.vm.box_url = “http://files.vagrantup.com/precise32.box" config.vm.synced_folder "htdocs/", "/var/www" config.vm.provision :chef_solo do |chef| chef.cookbooks_path = "./tools/chef/cookbooks" chef.add_recipe "project" chef.json = { "project" => { "server_root_password" => "foo" } } end end
  • 88.
    ➜ ~ vagrantup ... ==> default: Mounting shared folders… default: /var/www => /Users/monkehworks/my_project/htdocs default: /vagrant => /Users/monkehworks/my_project ==> default: /tmp/vagrant-chef-1/chef-solo-1/cookbooks ==> default: Running provisioner: chef_solo… Generating chef JSON and uploading… Running chef-solo… ...
  • 90.
  • 91.
    Download modules - https://forge.puppetlabs.com Configurein Vagrantfile: - puppet.module_path - puppet.manifests_path - puppet.manifest_file Provisioning flow happens in the main manifest Configure attributes with puppet.facter Using Puppet Apply
  • 92.
    Vagrantfile config.vm.provision :puppet do|puppet| puppet.manifests_path = "./tools/puppet/manifests" puppet.module_path = "./tools/puppet/modules" puppet.manifest_file = "init.pp" puppet.options = ['--verbose'] end init.pp include mysql::server class { '::mysql::server' :root_password => 'foo' }
  • 93.
    module ├── README.md ├── files ├──lib ├── metadata.json ├── spec ├── manifests │ └── init.pp │ └── params.pp ├── resources └── templates └── tests
  • 94.
    MySQL Params class mysql::params{ $manage_config_file = true $old_root_password = '' $purge_conf_dir = false $restart = false $root_password = 'UNSET' $server_package_ensure = 'present' $server_service_manage = true $server_service_enabled = true # mysql::bindings $bindings_enable = false $java_package_ensure = 'present' $java_package_provider = undef $perl_package_ensure = 'present' $perl_package_provider = undef $php_package_ensure = 'present' $php_package_provider = undef $python_package_ensure = 'present' $python_package_provider = undef $ruby_package_ensure = 'present' $ruby_package_provider = undef
  • 95.
    MySQL server manifest classmysql::server ( $config_file = $mysql::params::config_file $manage_config_file = $mysql::params::manage_config_file $old_root_password = $mysql::params::old_root_password, $override_options = {}, $package_ensure = $mysql::params::server_package_ensure, $package_name = $mysql::params::server_package_name, $purge_conf_dir = $mysql::params::purge_conf_dir, $remove_default_accounts = false, $restart = $mysql::params::restart, $root_group = $mysql::params::root_group, $root_password = $mysql::params::root_password, $service_enabled = $mysql::params::server_service_enabled, $service_manage = $mysql::params::server_service_manage, $service_name = $mysql::params::server_service_name, $service_provider = $mysql::params::server_service_provider, # Deprecated parameters $enabled = undef, $manage_service = undef ) inherits mysql::params { ...
  • 96.
    [client] user=root host=localhost <% unless scope.lookupvar('mysql::server::root_password')== 'UNSET' ‐%> password='<%= scope.lookupvar('mysql::server::root_password') %>' <% end ‐%> socket=<%= @options['client']['socket'] ‐%> MySQL Template
  • 97.
  • 98.
  • 99.
    exec { "apt‐update": command=> "/usr/bin/apt-get update", } package { 'mysql‐server': ensure => present, require => Exec['apt‐update'], notify => Service['mysql'], } package { 'apache2': ensure => present, require => Exec['apt‐update'], notify => Package['php5'], } package { 'php5': ensure => present, require => Exec['apt‐update'], notify => Service['apache2'], } ./tools/puppet/manifests/init.pp
  • 100.
    ./tools/puppet/manifests/init.pp exec {'assign‐root‐password': command =>"/usr/bin/mysqladmin ‐u root password $root_password", require => Package["mysql‐server"], onlyif => "/usr/bin/mysql ‐u root ‐e 'show databases;'" } service { "mysql": name => "mysql", ensure => running, enable => true, hasrestart => true, require => Package["mysql‐server"], } service { "apache2": name => "apache2", ensure => running, enable => true, hasrestart => true, require => Package["apache2"], }
  • 101.
    Vagrantfile VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION)do |config| config.vm.box = "precise32" config.vm.box_url = “http://files.vagrantup.com/precise32.box" config.vm.synced_folder "htdocs/", "/var/www" config.vm.provision :puppet do |puppet| puppet.manifests_path = "./tools/puppet/manifests" puppet.module_path = "./tools/puppet/modules" puppet.manifest_file = “init.pp" puppet.facter = { “root_password” => “foo”, } puppet.options = ['--verbose'] end end
  • 104.
    (when machine isrunning) ➜ ~ vagrant provision
  • 105.
  • 106.
    Provisioning is oftenslow Quality of public cookbooks/manifests Support on cookbooks/manifests Writing it yourself can be difficult Distribution restrictions
  • 107.
  • 108.
    Possible solution forslow provisioning Is not the same as vagrant box repackage Use exported box as new base box No provisioning required on startup Possibility of doing “light” provisioning instead
  • 110.
  • 111.
    VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION)do |config| config.vm.provision "shell", inline: "/usr/bin/apt‐get update" config.vm.box = "debian‐7.1.0" config.vm.define "web", primary: true do |web| web.vm.hostname = "web" web.vm.network :private_network, ip: "192.168.33.10" web.vm.synced_folder "htdocs/", "/var/www" web.vm.provision :puppet do |puppet| puppet.manifests_path = "./tools/puppet/manifests" puppet.module_path = "./tools/puppet/modules" puppet.manifest_file = "web.pp" puppet.options = ['-‐verbose'] end end config.vm.define "db" do |db| db.vm.hostname = "db" db.vm.network :private_network, ip: "192.168.33.11" db.vm.provision :puppet do |puppet| puppet.manifests_path = "./tools/puppet/manifests" puppet.module_path = "./tools/puppet/modules" puppet.manifest_file = "db.pp" puppet.options = ['-‐verbose'] puppet.facter = { "root_password" => "foo", } end end
  • 112.
    VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION)do |config| config.vm.provision "shell", inline: "/usr/bin/apt‐get update" config.vm.box = "debian‐7.1.0" config.vm.define "web", primary: true do |web| web.vm.hostname = "web" web.vm.network :private_network, ip: "192.168.33.10" web.vm.synced_folder "htdocs/", "/var/www" web.vm.provision :puppet do |puppet| puppet.manifests_path = "./tools/puppet/manifests" puppet.module_path = "./tools/puppet/modules" puppet.manifest_file = "web.pp" puppet.options = ['-‐verbose'] end end config.vm.define "db" do |db| db.vm.hostname = "db" db.vm.network :private_network, ip: "192.168.33.11" db.vm.provision :puppet do |puppet| puppet.manifests_path = "./tools/puppet/manifests" puppet.module_path = "./tools/puppet/modules" puppet.manifest_file = "db.pp" puppet.options = ['-‐verbose'] puppet.facter = { "root_password" => "foo", } end end
  • 115.
    ➜ ~ vagrantup ➜ ~ vagrant destroy ➜ ~ vagrant ssh ➜ ~ vagrant up web ➜ ~ vagrant ssh web ➜ ~ vagrant destroy web ➜ ~ vagrant up db ➜ ~ vagrant ssh db ➜ ~ vagrant destroy db
  • 116.
  • 117.
  • 119.