Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Vagrant, Puppet & Chef #FTW - Techorama 2014

Vagrant, Puppet & Chef #FTW - Techorama 2014

Slides for my Vagrant talk at Techorama 2014

Thijs Feryn

May 27, 2014
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. •Environment per project •Dev ~= Test ~= Staging ~= Prod

    •Easy to define & transport •Easy to tear down •Provisionable: infrastructure as code •Versionable •Shared across the team
  2. $  vagrant   Usage:  vagrant  [-­‐v]  [-­‐h]  command  [<args>]  

    !        -­‐v,  -­‐-­‐version    Print  the  version  and  exit.          -­‐h,  -­‐-­‐help          Print  this  help.   ! Available  subcommands:            box            destroy            halt            init            package            plugin            provision            reload            resume            ssh            ssh-­‐config            status            suspend            up
  3. •Select base box •Choose virtualization provider •Configure VM parameters •Configure

    networking •Tweak SSH settings •Mount local folders •Provision machine What does a Vagrantfile do?
  4. $  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. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby  :   ! Vagrant.configure("2")  do  |config|      config.vm.box  =  "base"   end
  5. $  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. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby  :   ! Vagrant.configure("2")  do  |config|      config.vm.box  =  "precise32"      config.vm.box_url  =  "http:// files.vagrantup.com/precise32.box"       end
  6. $vagrant  up   Bringing  machine  'default'  up  with  'virtualbox'  provider...

      [default]  Box  'precise32'  was  not  found.  Fetching  box  from  specified  URL  for   the  provider  'virtualbox'.  Note  that  if  the  URL  does  not  have   a  box  for  this  provider,  you  should  interrupt  Vagrant  now  and  add   the  box  yourself.  Otherwise  Vagrant  will  attempt  to  download  the   full  box  prior  to  discovering  this  error.   Downloading  or  copying  the  box...   Extracting   box...################################################################%   (Rate:  /s,  Estimated  time  remaining:  ))   Successfully  added  box  'precise32'  with  provider  'virtualbox'!   [default]  Importing  base  box  'precise32'...   [default]  Matching  MAC  address  for  NAT  networking...   [default]  Setting  the  name  of  the  VM...   [default]  Clearing  any  previously  set  forwarded  ports...   [default]  Creating  shared  folders  metadata...   [default]  Clearing  any  previously  set  network  interfaces...   [default]  Preparing  network  interfaces  based  on  configuration...   [default]  Forwarding  ports...   [default]  -­‐-­‐  22  =>  2222  (adapter  1)   [default]  Booting  VM...   [default]  Waiting  for  VM  to  boot.  This  can  take  a  few  minutes.   [default]  VM  booted  and  ready  for  use!   [default]  Configuring  and  enabling  network  interfaces...   [default]  Mounting  shared  folders...   [default]  -­‐-­‐  /vagrant
  7. $  vagrant  box   Usage:  vagrant  box  <command>  [<args>]  

    ! Available  subcommands:            add            list            remove            repackage
  8. $  vagrant  box  list   precise32        

         (virtualbox)   ! $  vagrant  box  remove  precise32  virtualbox   Removing  box  'precise32'  with  provider  'virtualbox'...   ! $  vagrant  box  add  precise32  http://files.vagrantup.com/ precise32.box  -­‐-­‐provider  virtualbox   Downloading  or  copying  the  box...   Extracting   box...##################################################### ###########%  (Rate:  /s,  Estimated  time  remaining:  ))   Successfully  added  box  'precise32'  with  provider   'virtualbox'!   ! $  vagrant  box  repackage  precise32  virtualbox   ! $  ls  -­‐lh   -­‐rw-­‐r-­‐-­‐r-­‐-­‐    1  thijs    staff      275M  10  okt  16:06  package.box
  9. $  vagrant  box  list   precise32        

         (virtualbox)   ! $  vagrant  box  remove  precise32  virtualbox   Removing  box  'precise32'  with  provider  'virtualbox'...   ! $  vagrant  box  add  precise32   precise32.box Downloading  or  copying  the  box...   Extracting   box...##################################################### ###########%  (Rate:  /s,  Estimated  time  remaining:  ))   Successfully  added  box  'precise32'  with  provider   'virtualbox'!   ! $  vagrant  box  repackage  precise32  virtualbox   ! $  ls  -­‐lh   -­‐rw-­‐r-­‐-­‐r-­‐-­‐    1  thijs    staff      275M  10  okt  16:06  package.box #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby  :   ! Vagrant.configure("2")  do  |config|      config.vm.box  =  "precise32"      config.vm.box_url  =  "http:// files.vagrantup.com/precise32.box"       end Vagrantfile can do this too
  10. $  tar  xvzf  package.box   x  ./box-­‐disk1.vmdk   x  ./box.ovf

      x  ./metadata.json   x  ./Vagrantfile Content of a box file
  11. $  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...   [default]  Clearing  any  previously  set  forwarded  ports...   [default]  Creating  shared  folders  metadata...   [default]  Clearing  any  previously  set  network  interfaces...   [default]  Preparing  network  interfaces  based  on  configuration...   [default]  Forwarding  ports...   [default]  -­‐-­‐  22  =>  2222  (adapter  1)   [default]  Booting  VM...   [default]  Waiting  for  VM  to  boot.  This  can  take  a  few  minutes.   [default]  VM  booted  and  ready  for  use!   [default]  Configuring  and  enabling  network  interfaces...   [default]  Mounting  shared  folders...   [default]  -­‐-­‐  /vagrant When VM doesn’t exist
  12. ! $  vagrant  up   Bringing  machine  'default'  up  with

     'virtualbox'  provider...   [default]  VirtualBox  VM  is  already  running.   $  vagrant  status   Current  machine  states:   ! default                                    running  (virtualbox) When VM exists & is running
  13. $  vagrant  suspend   [default]  Saving  VM  state  and  suspending

     execution...   $  vagrant  status   Current  machine  states:   ! default                                    saved  (virtualbox)   $  vagrant  up   Bringing  machine  'default'  up  with  'virtualbox'  provider...   [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!   Suspend & resume
  14. $  vagrant  halt   [default]  Attempting  graceful  shutdown  of  VM...

      $  vagrant  status   Current  machine  states:   ! default                                    poweroff  (virtualbox)   $  vagrant  up   Bringing  machine  'default'  up  with  'virtualbox'  provider...   [default]  Setting  the  name  of  the  VM...   [default]  Clearing  any  previously  set  forwarded  ports...   [default]  Creating  shared  folders  metadata...   [default]  Clearing  any  previously  set  network  interfaces...   [default]  Preparing  network  interfaces  based  on  configuration...   [default]  Forwarding  ports...   [default]  -­‐-­‐  22  =>  2222  (adapter  1)   [default]  Booting  VM...   [default]  Waiting  for  VM  to  boot.  This  can  take  a  few  minutes.   [default]  VM  booted  and  ready  for  use!   [default]  Configuring  and  enabling  network  interfaces...   [default]  Mounting  shared  folders...   [default]  -­‐-­‐  /vagrant   Stop & start
  15. $  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  status   Current  machine  states:   ! default                                    not  created  (virtualbox) Destroy
  16. $  vagrant  ssh   Linux  debian-­‐7  3.2.0-­‐4-­‐amd64  #1  SMP  Debian

     3.2.46-­‐1  x86_64   ! The  programs  included  with  the  Debian  GNU/Linux  system  are   free  software;   the  exact  distribution  terms  for  each  program  are  described   in  the   individual  files  in  /usr/share/doc/*/copyright.   ! Debian  GNU/Linux  comes  with  ABSOLUTELY  NO  WARRANTY,  to  the   extent   permitted  by  applicable  law.   Last  login:  Mon  Jul  15  13:13:36  2013  from  10.0.2.2   vagrant@debian-­‐7:~$  sudo  su   root@debian-­‐7:/home/vagrant No login or password required
  17. root@debian-­‐7:/home/vagrant#  cat  .ssh/authorized_keys   ssh-­‐rsa   AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8 YVr+kz4TjGYe7gHzIw +niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6Iedp lqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7P

    tixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL +GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm +R4LOzFUGaHqHDLKLX +FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ==   vagrant  insecure  public  key Public key
  18. $  vagrant  ssh-­‐config   Host  default      HostName  127.0.0.1

         User  vagrant      Port  2222      UserKnownHostsFile  /dev/null      StrictHostKeyChecking  no      PasswordAuthentication  no      IdentityFile  "/Users/thijs/.vagrant.d/insecure_private_key"      IdentitiesOnly  yes      LogLevel  FATAL Username, host, port & private key location
  19. $  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-­‐-­‐-­‐-­‐-­‐ Private key
  20. You probably remember this one #  -­‐*-­‐  mode:  ruby  -­‐*-­‐

      #  vi:  set  ft=ruby  :   ! Vagrant.configure("2")  do  |config|      config.vm.box  =  "precise32"      config.vm.box_url  =  "http:// files.vagrantup.com/precise32.box"       end
  21. Networking config.vm.network  :forwarded_port,  guest:  80,  host:   8080 config.vm.network  :public_network

    config.vm.network  :private_network,  ip:   "192.168.10.10" Bridged network Port forwarding Private IP space
  22. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby

     :   ! Vagrant.configure("2")  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 $  vagrant  up   ...   [default]  Preparing  network  interfaces  based  on   configuration...   [default]  Forwarding  ports...   [default]  -­‐-­‐  22  =>  2222  (adapter  1) Yes, there is port forwarding involved
  23. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby

     :   ! Vagrant.configure("2")  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 $  vagrant  up   ...   [default]  Preparing  network  interfaces  based  on   configuration...   [default]  Forwarding  ports...   [default]  -­‐-­‐  22  =>  2222  (adapter  1)   [default]  -­‐-­‐  80  =>  8080  (adapter  1) There’s port 80
  24. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby

     :   ! Vagrant.configure("2")  do  |config|      config.vm.box  =  "precise32"      config.vm.box_url  =  "http://files.vagrantup.com/ precise32.box"          config.vm.network  :public_network   end
  25. $  vagrant  up   ...   Bringing  machine  'default'  up

     with  'virtualbox'   provider...   [default]  Clearing  any  previously  set  forwarded  ports...   [default]  Creating  shared  folders  metadata...   [default]  Clearing  any  previously  set  network   interfaces...   [default]  Available  bridged  network  interfaces:   1)  en1:  Wi-­‐Fi  (AirPort)   2)  en0:  Ethernet   3)  p2p0   What  interface  should  the  network  bridge  to?  1   [default]  Preparing  network  interfaces  based  on   configuration...   [default]  Forwarding  ports...   [default]  -­‐-­‐  22  =>  2222  (adapter  1) Choose interface
  26. $  vagrant  up   ...   [default]  Mounting  shared  folders...

      [default]  -­‐-­‐  /vagrant config.vm.synced_folder  "web/",  "/var/www" $  vagrant  up   ...   [default]  Mounting  shared  folders...   [default]  -­‐-­‐  /vagrant   [default]  -­‐-­‐  /var/www Extra mount Default mount
  27. 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 VM properties
  28. •Add specific software •Create configuration files •Execute commands •Create users

    •Manage services •Automatically executed on vagrant up Provisioning
  29. shell config.vm.provision  :shell,  :inline  =>  "mount   -­‐t  tmpfs  -­‐o

     size=50m,mode=0777  tmpfs  /vagrant/ app/cache" Mount RAM disk volume
  30. shell $script  =  <<SCRIPT   echo  I  am  provisioning...  

    date  >  /etc/vagrant_provisioned_at   SCRIPT   ! Vagrant.configure("2")  do  |config|      config.vm.provision  "shell",  inline:  $script   end Inject Ruby
  31. shell Vagrant.configure("2")  do  |config|      config.vm.provision  "shell",  path:  "script.sh"

      end Point to script in your current folder Vagrant.configure("2")  do  |config|      config.vm.provision  "shell",  path:  "https:// example.com/provisioner.sh"   end Point to external script
  32. •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 •... Chef & Puppet
  33. Chef vs 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-like”
  34. •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 How to use Chef Solo
  35. 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 Vagrantfile
  36. cookbook   ├──  README.md   ├──  attributes   ├──  definitions

      ├──  files   │      └──  default   ├──  libraries   ├──  metadata.rb   ├──  providers   ├──  recipes   │      └──  default.rb   ├──  resources   └──  templates          └──  default Chef cookbook layout
  37. MySQL attributes 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'   ...
  38. MySQL server recipe ...   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   ...
  39. MySQL template [client]   host          =

     localhost   user          =  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  
  40. 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
  41. 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
  42. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby

     :   ! Vagrant.configure("2")  do  |config|   config.vm.box  =  "precise32"   config.vm.box_url  =  "http://files.vagrantup.com/ precise32.box     config.vm.synced_folder  "web/",  "/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 Your Vagrantfile
  43. $  vagrant  up   ...   [default]  Mounting  shared  folders...

      [default]  -­‐-­‐  /vagrant   [default]  -­‐-­‐  /tmp/vagrant-­‐chef-­‐1/chef-­‐solo-­‐1/cookbooks   [default]  Running  provisioner:  chef_solo...   Generating  chef  JSON  and  uploading...   Running  chef-­‐solo...   ... Vagrant up
  44. [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  ***  Chef  11.4.4  ***   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Setting

     the  run_list  to   ["recipe[project]"]  from  JSON   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Run  List  is  [recipe[project]]   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Run  List  expands  to  [project]   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Starting  Chef  Run  for  debian-­‐7.1.0   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Running  start  handlers   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Start  handlers  complete.   [2013-­‐10-­‐21T10:37:24+00:00]  INFO:  Processing  package[mysql-­‐server]  action   install  (project::default  line  1)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  package[mysql-­‐server]  sending  start  action   to  service[mysql]  (immediate)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Processing  service[mysql]  action  start   (project::default  line  10)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Processing  execute[assign-­‐root-­‐password]   action  run  (project::default  line  5)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  execute[assign-­‐root-­‐password]  ran   successfully   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Processing  service[mysql]  action  enable   (project::default  line  10)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Chef  Run  complete  in  37.208173462  seconds   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Running  report  handlers   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Report  handlers  complete Output
  45. •Download modules (https:// forge.puppetlabs.com) •Configure puppet.module_path, puppet.manifests_path & puppet.manifest_file in

    Vagrantfile •Provisioning flow happens in the main manifest •Configure attributes with puppet.facter How to use Puppet Apply
  46. 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 include  mysql::server class  {  '::mysql::server':      root_password  =>  'foo'   } init.pp Override password Default
  47. Puppet module layout module   ├──  README.md   ├──  files

      ├──  lib   ├──  metadata.json   ├──  spec   ├──  manifests   │      └──  init.pp   │      └──  params.pp   ├──  resources   └──  templates   └──  tests
  48. 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
  49. MySQL params 2 ...   case  $::osfamily  {    

         'RedHat':  {              if  $::operatingsystem  ==  'Fedora'  and   (is_integer($::operatingsystemrelease)  and  $::operatingsystemrelease  >=   19  or  $::operatingsystemrelease  ==  "Rawhide")  {                  $client_package_name  =  'mariadb'                  $server_package_name  =  'mariadb-­‐server'              }  else  {                  $client_package_name  =  'mysql'                  $server_package_name  =  'mysql-­‐server'              }              $basedir                          =  '/usr'              $config_file                  =  '/etc/my.cnf'              $datadir                          =  '/var/lib/mysql'              $log_error                      =  '/var/log/mysqld.log'              $pidfile                          =  '/var/run/mysqld/mysqld.pid'              $root_group                    =  'root'              $server_service_name  =  'mysqld'              $socket                            =  '/var/lib/mysql/mysql.sock'              $ssl_ca                            =  '/etc/mysql/cacert.pem'              $ssl_cert                        =  '/etc/mysql/server-­‐cert.pem'  
  50. 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  {   ...
  51. MySQL template [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']  -­‐%>   ERB style too!
  52. 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
  53. 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"],   } ./tools/puppet/manifests/init.pp
  54. Your Vagrantfile #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:

     set  ft=ruby  :   ! Vagrant.configure("2")  do  |config|   config.vm.box  =  "precise32"   config.vm.box_url  =  "http://files.vagrantup.com/ precise32.box     config.vm.synced_folder  "web/",  "/var/www"   config.vm.provision  :puppet  do  |puppet|        puppet.manifests_path  =  "puppet/manifests"        puppet.module_path  =  "puppet/modules"        puppet.manifest_file    =  "init.pp"        puppet.facter  =  {        "root_password"  =>  "foo",        }        puppet.options  =  ['-­‐-­‐verbose']   end     end
  55. $  vagrant  up   ...   [default]  Mounting  shared  folders...

      [default]  -­‐-­‐  /vagrant   [default]  -­‐-­‐  /tmp/vagrant-­‐puppet/manifests   [default]  -­‐-­‐  /tmp/vagrant-­‐puppet/modules-­‐0   [default]  Running  provisioner:  puppet...   Running  Puppet  with  init.pp...   Notice:  /Stage[main]//Exec[apt-­‐update]/returns:  executed   successfully   Notice:  /Stage[main]//Package[mysql-­‐server]/ensure:  ensure   changed  'purged'  to  'present'   Service[mysql]   Notice:  /Stage[main]//Service[mysql]:  Triggered  'refresh'  from   1  events   Notice:  /Stage[main]//Exec[assign-­‐root-­‐password]/returns:   executed  successfully   Notice:  /Stage[main]//Package[apache2]/ensure:  ensure  changed   'purged'  to  'present'   Notice:  /Stage[main]//Package[php5]/ensure:  ensure  changed   'purged'  to  'present'   Notice:  /Stage[main]//Service[apache2]:  Triggered  'refresh'   from  1  events   Notice:  Finished  catalog  run  in  222.55  seconds
  56. [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  ***  Chef  11.4.4  ***   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Setting

     the  run_list  to   ["recipe[project]"]  from  JSON   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Run  List  is  [recipe[project]]   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Run  List  expands  to  [project]   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Starting  Chef  Run  for  debian-­‐7.1.0   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Running  start  handlers   [2013-­‐10-­‐21T10:37:22+00:00]  INFO:  Start  handlers  complete.   [2013-­‐10-­‐21T10:37:24+00:00]  INFO:  Processing  package[mysql-­‐server]  action   install  (project::default  line  1)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  package[mysql-­‐server]  sending  start  action   to  service[mysql]  (immediate)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Processing  service[mysql]  action  start   (project::default  line  10)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Processing  execute[assign-­‐root-­‐password]   action  run  (project::default  line  5)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  execute[assign-­‐root-­‐password]  ran   successfully   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Processing  service[mysql]  action  enable   (project::default  line  10)   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Chef  Run  complete  in  37.208173462  seconds   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Running  report  handlers   [2013-­‐10-­‐21T10:37:59+00:00]  INFO:  Report  handlers  complete Output
  57. •Provisioning is often slow (especially when installing lots of packages)

    •Quality of public cookbooks/manifests •Support on cookbooks/manifests •Writing it yourself can be difficult •Some cookbooks/manifests only work on certain Linux distros Problems with provisioning
  58. •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 Re-distribute current VM $  vagrant  package
  59. #  -­‐*-­‐  mode:  ruby  -­‐*-­‐   #  vi:  set  ft=ruby

     :   ! Vagrant.configure("2")  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  "web/",  "/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       end
  60. $  vagrant  up   Bringing  machine  'web'  up  with  'virtualbox'

     provider...   Bringing  machine  'db'  up  with  'virtualbox'  provider...   [web]  Importing  base  box  'debian-­‐7.1.0'...   [web]  Matching  MAC  address  for  NAT  networking...   [web]  Setting  the  name  of  the  VM...   [web]  Clearing  any  previously  set  forwarded  ports...   [web]  Creating  shared  folders  metadata...   [web]  Clearing  any  previously  set  network  interfaces...   [web]  Preparing  network  interfaces  based  on  configuration...   [web]  Forwarding  ports...   [web]  -­‐-­‐  22  =>  2222  (adapter  1)   [web]  Booting  VM...   [web]  Waiting  for  VM  to  boot.  This  can  take  a  few  minutes.   [web]  VM  booted  and  ready  for  use!   [web]  Configuring  and  enabling  network  interfaces...   [web]  Mounting  shared  folders...   [web]  -­‐-­‐  /vagrant   [web]  -­‐-­‐  /var/www   [web]  -­‐-­‐  /tmp/vagrant-­‐puppet/manifests   [web]  -­‐-­‐  /tmp/vagrant-­‐puppet/modules-­‐0   [web]  Running  provisioner:  shell...   [web]  Running:  inline  script   [web]  Running  provisioner:  puppet...   Running  Puppet  with  web.pp...  
  61. [db]  Importing  base  box  'debian-­‐7.1.0'...   [db]  Matching  MAC  address

     for  NAT  networking...   [db]  Setting  the  name  of  the  VM...   [db]  Clearing  any  previously  set  forwarded  ports...   [db]  Fixed  port  collision  for  22  =>  2222.  Now  on  port  2200.   [db]  Creating  shared  folders  metadata...   [db]  Clearing  any  previously  set  network  interfaces...   [db]  Preparing  network  interfaces  based  on  configuration...   [db]  Forwarding  ports...   [db]  -­‐-­‐  22  =>  2200  (adapter  1)   [db]  Booting  VM...   [db]  Waiting  for  VM  to  boot.  This  can  take  a  few  minutes.   [db]  VM  booted  and  ready  for  use!   [db]  Configuring  and  enabling  network  interfaces...   [db]  Mounting  shared  folders...   [db]  -­‐-­‐  /vagrant   [db]  -­‐-­‐  /tmp/vagrant-­‐puppet/manifests   [db]  -­‐-­‐  /tmp/vagrant-­‐puppet/modules-­‐0   [db]  Running  provisioner:  shell...   [db]  Running:  inline  script   [db]  Running  provisioner:  puppet...   Running  Puppet  with  db.pp...  
  62. vagrant  up   vagrant  ssh   vagrant  destroy   vagrant

     up  web   vagrant  ssh  web   vagrant  destroy  web   vagrant  up  db   vagrant  ssh  db   vagrant  destroy  db All VM’s Primary VM All VM’s