Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Chef Provisioning a Chef Server Cluster

Chef Provisioning a Chef Server Cluster

Slides from my ChefConf 2015 talk

Joshua Timberman

April 02, 2015
Tweet

More Decks by Joshua Timberman

Other Decks in Technology

Transcript

  1. Before we begin, provisioning a Chef Server: • Run chef-client...

    • Which talks to a different Chef Server... • Which downloads a recipe that... • Creates machines that run chef-client... • That install Chef Server packages... • Which then run chef-server-ctl reconfigure... • Which runs chef-solo to configure the Chef Server
  2. Where are we going*? *And why are we in this

    handbasket? https://www.flickr.com/photos/steevithak/6936667291
  3. Bootstrap a Chef Server with Chef Solo sudo  chef-­‐solo  \

             -­‐c  /etc/chef/solo.rb  \          -­‐j  ~/chef.json  \          -­‐r  http://s3.amazonaws.com/chef-­‐solo/bootstrap-­‐latest.tar.gz  
  4. As it turns out... This is a pretty good idea!

    https://www.flickr.com/photos/nao904/6084536885
  5. chef-server-ctl reconfigure frontend-­‐chef-­‐server%  sudo  chef-­‐server-­‐ctl  reconfigure   Starting  Chef  Client,

     version  11.18.0   Compiling  Cookbooks...   Recipe:  private-­‐chef::default   ....   Recipe:  private-­‐chef::default      *  file[/etc/opscode/chef-­‐server-­‐running.json]  action  create  (up   to  date)   Running  handlers:   Running  handlers  complete   Chef  Client  finished,  7/228  resources  updated  in  7.282379304   seconds   opscode  Reconfigured!
  6. omnibus-ctl reconfigure... def  reconfigure(exit_on_success=true)      status  =  run_command(  

           "chef-­‐solo  -­‐c  #{base_path}/embedded/cookbooks/solo.rb  -­‐j            #{base_path}/embedded/cookbooks/dna.json"      )      if  status.success?          log  "#{display_name}  Reconfigured!"          exit!  0  if  exit_on_success      else          exit!  1      end   end
  7. Hosted Chef... is different (and that's the problem) • Built

    using Chef cookbooks • (yay! ...but) • Many forked community cookbooks • (before berkshelf/librarian) • One cookbook per component/service • (postgresql, erchef, authz, rabbitmq, solr, etc) • Growth over time • (over 10k commits) • Not the same as what customers use • (chef-server-ctl reconfigure vs "knife ssh and chef-client")
  8. Hosted Chef's Chef Server Cluster Hosted Chef Is a Chef

    Server Cluster VPC Our Use Case: Hosted Chef and its Chef Server running in AWS EC2
  9. Chef Server 12 "There is One Chef Server, and it

    is Open Source" - Adam Jacob https://www.chef.io/blog/2014/09/08/there-is-one-chef-server-and-it-is-open-source/
  10. You've probably heard this by now... • Multi-tenancy - required

    feature for Hosted Chef • Chef Push Jobs is opened now • Remove tension between Open Source Chef and Enterprise Chef codebase • Remove tension between Hosted Enterprise Chef and Enterprise Chef code, too
  11. Current state: Installing Chef Server 12 Or, "this is how

    you do it manually per the documentation at docs.chef.io" http://docs.chef.io/server/install_server.html
  12. Installing Chef Server 12 sudo  dpkg  -­‐i  chef-­‐server-­‐core*.deb   sudo

     vi  /etc/opscode/chef-­‐server.rb   sudo  chef-­‐server-­‐ctl  reconfigure  
  13. Or there's a cookbook for that... curl  -­‐L  https://www.chef.io/chef/install.sh  |

     sudo  bash   sudo  mkdir  -­‐p  /var/chef/cache  /var/chef/cookbooks   wget  -­‐qO-­‐  https://supermarket.chef.io/cookbooks/chef-­‐server/ download  |  sudo  tar  xvzC  /var/chef/cookbooks   wget  -­‐qO-­‐  https://supermarket.chef.io/cookbooks/chef-­‐server-­‐ ingredient/download  |  sudo  tar  xvzC  /var/chef/cookbooks   wget  -­‐qO-­‐  https://supermarket.chef.io/cookbooks/packagecloud/ download  |  sudo  tar  xvzC  /var/chef/cookbooks   sudo  chef-­‐solo  -­‐o  'recipe[chef-­‐server::default]'  
  14. But if you want a cluster... ##  On  the  first

     node  ("bootstrap  backend")   sudo  dpkg  -­‐i  chef-­‐server-­‐core*.deb   sudo  vi  /etc/opscode/chef-­‐server.rb   ##  manage  some  server  blocks  for  the  cluster  per  docs   sudo  chef-­‐server-­‐ctl  reconfigure   sudo  rsync  -­‐avz  /etc/opscode  [email protected]:/etc   ##  On  the  second  node  ("frontend")   sudo  dpkg  -­‐i  chef-­‐server-­‐core*.deb   sudo  chef-­‐server-­‐ctl  reconfigure  
  15. Wait. What was that? ##  On  the  first  node  ("bootstrap

     backend")   sudo  dpkg  -­‐i  chef-­‐server-­‐core*.deb   sudo  vi  /etc/opscode/chef-­‐server.rb   ##  manage  some  server  blocks  according  to  docs.chef.io...   sudo  chef-­‐server-­‐ctl  reconfigure   sudo  rsync  -­‐avz  /etc/opscode  [email protected]:/etc   ##  On  the  second  node  ("frontend")   sudo  dpkg  -­‐i  chef-­‐server-­‐core*.deb   sudo  chef-­‐server-­‐ctl  reconfigure  
  16. What is Chef Provisioning? • Previously known as "Chef Metal"

    • Manage machines as Chef resources • Various provisioners available • several come with ChefDK, e.g., aws, azure • Available as rubygems • Makes it easy to reason about standing up a cluster
  17. Chef Provisioning has `machine` resources machine  'database'  do    

     recipe  'example-­‐postgresql::server'   end   machine  'cache'  do      recipe  'example-­‐memcached'   end   machine  'www1'  do      recipe  'example-­‐nginx'   end   machine  'www2'  do      recipe  'example-­‐nginx   end
  18. Chef Provisioning extends Chef's Recipe DSL #  AWS  EC2...  

    with_driver('aws::us-­‐west-­‐2')   with_machine_options(      :bootstrap_options  =>  {          :key_name  =>  'hc-­‐metal-­‐provisioner',          :image_id  =>  'ami-­‐b99ed989',          :instance_type  =>  'm3.medium'      }   )   #  Microsoft  Azure...   with_driver('azure')   with_machine_options(      :image_id  =>  'Ubuntu-­‐14_04_1-­‐LTS-­‐amd64-­‐server-­‐20140927-­‐en-­‐us-­‐30GB',      :bootstrap_options  =>  {          :vm_size  =>  'Standard_D1',          :other_options  =>  'Slides  are  only  so  big...'      }   )
  19. Chef Provisioning a Chef Server Cluster machine  'backend'  do  

       recipe  'chef-­‐server-­‐cluster::bootstrap-­‐backend'   end   machine  'frontend'  do      recipe  'chef-­‐server-­‐cluster::frontend'   end   machine  'analytics'  do      recipe  'chef-­‐server-­‐cluster::analytics'   end
  20. Chef Server (Hosted Chef) Provisioner (laptop) AWS EC2 backend analytics

    frontend chef-client chef/knife chef-provisioning-aws SSH SSH SSH
  21. Chef Provisioning Requires a... Provisioner • What is a provisioner?

    • What does it provision? • What does it need on the Chef Server?
  22. SSH Access - Provisioner options {      :ssh_username  =>

     "ubuntu",      :bootstrap_options  =>  {          :key_name  =>  "hc-­‐metal-­‐provisioner"      }   }
  23. SSH Keys - Data Bag Item {      "id":

     "hc-­‐metal-­‐provisioner",      "private_ssh_key":  "-­‐-­‐-­‐-­‐-­‐BEGIN  RSA  PRIVATE   KEY-­‐-­‐-­‐-­‐-­‐\nSNIP-­‐-­‐-­‐-­‐-­‐END  RSA  PRIVATE  KEY-­‐-­‐-­‐-­‐-­‐ \n"   }  
  24. setup-ssh-keys recipe ssh_keys  =  data_bag_item('secrets',  'hc-­‐metal-­‐provisioner')   key_dir    =

     File.join(Dir.home,  '.ssh')   directory  key_dir  do      recursive  true   end   file  File.join(key_dir,  key_name)  do      content  ssh_keys['private_ssh_key']      sensitive  true   end  
  25. Checkpoint! • ./.chef/config.rb for knife and chef-client • Uploaded cookbooks

    (using Policyfiles*) • Uploaded data bags • AWS authentication credentials in ~/.aws/config • SSH private key in ~/.ssh/keyname * Due to time constraints, Policyfile discussion is not appearing in this talk
  26. Provisioner node run list %  knife  node  show  chefconf-­‐provisioner  

    Node  Name:      chefconf-­‐provisioner   Environment:  _default   FQDN:   IP:                    10.13.37.102   Run  List:        recipe[chef-­‐server-­‐cluster::cluster-­‐provision]   Roles:   Recipes:          chef-­‐server-­‐cluster::cluster-­‐provision,  chef-­‐server-­‐ cluster::setup-­‐provisioner,  chef-­‐server-­‐cluster::setup-­‐ssh-­‐keys   Platform:        mac_os_x  10.10.2   Tags:
  27. chef-server-cluster cookbook attributes default['chef-server-cluster']['topology'] = 'tier' default['chef-server-cluster']['role'] = 'frontend' default['chef-server-cluster']['bootstrap']['enable']

    = false default['chef-server-cluster']['chef-provisioner-key-name'] = ‘keyname’ default['chef-server-cluster']['driver'] = { 'gems' => [ { 'name' => 'chef-provisioning-aws', 'require' => 'chef/provisioning/aws_driver' } ], 'with-parameter' => 'aws::us-west-2' } default['chef-server-cluster']['driver']['machine_options'] = { 'ssh_username' => 'ubuntu', 'use_private_ip_for_ssh' => false, 'bootstrap_options' => { 'key_name' => ‘keyname’, 'image_id' => 'ami-b99ed989', 'instance_type' => 'm3.medium' } }
  28. chef-server-cluster::setup-provisioner node['chef-­‐server-­‐cluster']['driver']['gems'].each  do  |g|      chef_gem  g['name']    

     require  g['require']  if  g.has_key?('require')   end   provisioner_machine_opts  =  node['chef-­‐server-­‐cluster']['driver']['machine_options'].to_hash   ChefHelpers.symbolize_keys_deep!(provisioner_machine_opts)   with_driver(node['chef-­‐server-­‐cluster']['driver']['with-­‐parameter'])   with_machine_options(provisioner_machine_opts)  
  29. What that actually looks like... chef_gem  'chef-­‐provisioning-­‐aws'   require  'chef/provisioning/aws'

      with_driver('aws::us-­‐west-­‐2')   with_machine_options({      :ssh_username                      =>  'ubuntu',      :use_private_ip_for_ssh  =>  false,      :bootstrap_options            =>  {          :key_name            =>  'hc-­‐metal-­‐provisioner',          :image_id            =>  'ami-­‐b99ed989',          :instance_type  =>'m3.medium'      }   })  
  30. So in theory... {      "id":  "azure-­‐provisioner",    

     "default_attributes":  {          "chef-­‐server-­‐cluster":  {              "driver":  {                  "gems":  [{                      "name":  "chef-­‐provisioning-­‐azure",                      "require":  "chef/provisioning/azure_driver"                  }],                  "with-­‐parameter":  "azure",                  "machine_options":  {                      "bootstrap_options":  {                          "cloud_service_name":  "chef-­‐provisioner",                          "storage_aaccount_name":  "chef-­‐provisioner",                          "vm_size":  "Standard_D1",                          "location":  "West  US",                          "tcp_endpoints":  "80:80"                      },                      "image_id":  "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-­‐14_04_1-­‐LTS-­‐amd64-­‐server-­‐20140927-­‐en-­‐us-­‐30GB",                      "password":  "SshKeysArentSupportedYet"                  }              }          }      }   }  
  31. chef-server-cluster::cluster-provision include_recipe  'chef-­‐server-­‐cluster::setup-­‐provisioner'   include_recipe  'chef-­‐server-­‐cluster::setup-­‐ssh-­‐keys'   directory  '/tmp/stash'  do

         recursive  true   end   machine  'bootstrap-­‐backend'  do      recipe  'chef-­‐server-­‐cluster::bootstrap'      action  :converge      converge  true   end   #  machine  files  in  here...   machine  'frontend'  do      recipe  'chef-­‐server-­‐cluster::frontend'      action  :converge      converge  true      #  files  property...   end   machine  'analytics'  do      recipe  'chef-­‐server-­‐cluster::analytics'      action  :converge      converge  true   end
  32. machine resource <machine[bootstrap-­‐backend]      @name:  "bootstrap-­‐backend"      @allowed_actions:

      [:nothing,  :allocate,  :ready,  :setup,  :converge,  :converge_only,  :d estroy,  :stop]      @action:  [:converge]      @chef_server:  {          :chef_server_url=>"https://api.opscode.com/organizations/ jtimberman-­‐chefconf",          :options=>{              :client_name=>"jtimberman",              :signing_key_filename=>"/Users/jtimberman/.chef/ jtimberman.pem"          }      }
  33. machine resource continued    @driver:  "aws::us-­‐west-­‐2"      @machine_options:  {

             "ssh_username"=>"ubuntu",          "use_private_ip_for_ssh"=>false,          "bootstrap_options"=>{              "key_name"=>"hc-­‐metal-­‐provisioner",              "image_id"=>"ami-­‐b99ed989",              "instance_type"=>"m3.medium"          }      }      @run_list_modifiers:  [#<Chef::RunList::RunListItem:0x007f8cbe394d90   @version=nil,  @type=:recipe,  @name="chef-­‐server-­‐cluster::bootstrap">]      @ohai_hints:  {"ec2"=>"{}"}      @converge:  true   >
  34. Data bags chef_server/topology.json   {      "id":  "topology",  

       "topology":  "tier",      "disabled_svcs":  [],      "enabled_svcs":  [],      "vips":  [],      "dark_launch":  {          "actions":  true      },      "api_fqdn":  "chef.jtimberman.name",      "analytics_fqdn":  "analytics.jtimberman.name",      "notification_email":  "[email protected]"   }  
  35. Configuring the Cluster - bootstrap recipe chef_server_config  =  data_bag_item('chef_server',  'topology').to_hash

      chef_server_config.delete('id')   chef_servers  =  search('node',  'chef-­‐server-­‐cluster_role:backend').map  do  |server|      {          :fqdn  =>  server['fqdn'],          :ipaddress  =>  server['ipaddress'],          :bootstrap  =>  server['chef-­‐server-­‐cluster']['bootstrap']['enable'],          :role  =>  server['chef-­‐server-­‐cluster']['role']      }   end   if  chef_servers.empty?      chef_servers  =  [                                      {                                          :fqdn  =>  node['fqdn'],                                          :ipaddress  =>  node['ipaddress'],                                          :bootstrap  =>  true,                                          :role  =>  'backend'                                      }                                    ]   end   chef_server_config['vips']  =  {  'rabbitmq'  =>  node['ipaddress']  }   chef_server_config['rabbitmq']  =  {  'node_ip_address'  =>  '0.0.0.0'  }  
  36. Merge the configuration #  Merge  the  attributes  with  the  data

     bag  values,  and  the  search   #  results  for  other  servers.   node.default['chef-­‐server-­‐cluster'].merge!(chef_server_config)
  37. Configuration template template '/etc/opscode/chef-server.rb' do source 'chef-server.rb.erb' variables(:chef_server_config => node['chef-server-cluster'],

    :chef_servers => chef_servers) notifies :reconfigure, 'chef_server_ingredient[chef-server-core]' end
  38. Render configuration: /etc/opscode/chef-server.rb topology  '<%=  @chef_server_config['topology']  %>'   api_fqdn  '<%=

     @chef_server_config['api_fqdn']  %>'   #  Analytics  configuration   dark_launch['actions']  =  <%=  @chef_server_config['dark_launch']['actions']  %>   <%  if  @chef_server_config.has_key?('vips')  -­‐%>   <%      @chef_server_config['vips'].each  do  |vip_name,  vip_add|  -­‐%>   <%=        vip_name  %>['vip']  =  '<%=  vip_add  %>'   <%      end  -­‐%>   <%  end  -­‐%>   <%  if  @chef_server_config.has_key?('rabbitmq')  &&   @chef_server_config['rabbitmq'].has_key?('node_ip_address')  -­‐%>   rabbitmq['node_ip_address']  =  '<%=  @chef_server_config['rabbitmq']['node_ip_address']  %>'   <%  end  -­‐%>   oc_id['applications']  =  {      'analytics'  =>  {          'redirect_uri'  =>  'https://<%=  @chef_server_config['analytics_fqdn']  %>'      }   }  
  39. /etc/opscode/chef-server.rb #  Server  blocks   <%  @chef_servers.each  do  |server|  -­‐%>

      server  '<%=  server[:fqdn]  %>',      :ipaddress  =>  '<%=  server[:ipaddress]  %>',      <%  if  server[:bootstrap]  -­‐%>      :bootstrap  =>  true,      <%  end  -­‐%>      :role  =>  '<%=  server[:role]  %>'   <%      if  server[:role]  ==  'backend'  -­‐%>   backend_vip  '<%=  server[:fqdn]  %>',      :ipaddress  =>  '<%=  server[:ipaddress]  %>'   <%      end  -­‐%>   <%  end  -­‐%>   `server` blocks describe frontend and backend nodes
  40. Rendered: backend topology  'tier'   api_fqdn  'chef.jtimberman.name'   dark_launch['actions']  =

     true   rabbitmq['vip']  =  '172.31.12.241'   rabbitmq['node_ip_address']  =  '0.0.0.0'   oc_id['applications']  =  {      'analytics'  =>  {          'redirect_uri'  =>  'https://analytics.jtimberman.name'      }   }   server  'ip-­‐172-­‐31-­‐12-­‐241.us-­‐west-­‐2.compute.internal',      :ipaddress  =>  '172.31.12.241',      :bootstrap  =>  true,      :role  =>  'backend'   backend_vip  'ip-­‐172-­‐31-­‐12-­‐241.us-­‐west-­‐2.compute.internal',      :ipaddress  =>  '172.31.12.241'  
  41. Rendered: frontend topology  'tier'   api_fqdn  'chef.jtimberman.name'   dark_launch['actions']  =

     true   oc_id['applications']  =  {      'analytics'  =>  {          'redirect_uri'  =>  'https://analytics.jtimberman.name'      }   }   server  'ip-­‐172-­‐31-­‐12-­‐241.us-­‐west-­‐2.compute.internal',      :ipaddress  =>  '172.31.12.241',      :bootstrap  =>  true,      :role  =>  'backend'   backend_vip  'ip-­‐172-­‐31-­‐12-­‐241.us-­‐west-­‐2.compute.internal',      :ipaddress  =>  '172.31.12.241'   server  'ip-­‐172-­‐31-­‐11-­‐8.us-­‐west-­‐2.compute.internal',      :ipaddress  =>  '172.31.11.8',      :role  =>  'frontend'  
  42. /etc/opscode-analytics/actions-source.json {      "private_chef":  {        

     "api_fqdn":  "chef.jtimberman.name",          "oc_id_application":  {              "name":  "analytics",              "uid":   "56d493b4ef2290cb29d9e73d34bd89688667b9f0d4583ac273e6e9de79ba3cb7",              "secret":  "Generated-­‐long-­‐secret",              "redirect_uri":  "https://analytics.jtimberman.name"          },          "rabbitmq_host":  "172.31.10.165",          "rabbitmq_port":  "5672",          "rabbitmq_vhost":  "/analytics",          "rabbitmq_exchange":  "actions",          "rabbitmq_user":  "actions",          "rabbitmq_password":  "generated-­‐long-­‐secret"      } the bootstrap backend node
  43. Configuration template template '/etc/opscode/chef-server.rb' do source 'chef-server.rb.erb' variables(:chef_server_config => node['chef-server-cluster'],

    :chef_servers => chef_servers) notifies :reconfigure, 'chef_server_ingredient[chef-server-core]' end What is chef_server_ingredient??
  44. chef-server-ingredient cookbook • What is an ingredient? • Clever, what's

    an addon? • What does the cookbook do? • How does the resource work? • Primitive resource for installing/managing Chef Server add-ons
  45. chef_server_ingredient resources... chef_server_ingredient  'chef-­‐server-­‐core'  do      notifies  :reconfigure,  'chef_server_ingredient[chef-­‐server-­‐core]'

      end   chef_server_ingredient  'opscode-­‐reporting'  do      notifies  :reconfigure,  'chef_server_ingredient[opscode-­‐reporting]'   end   chef_server_ingredient  'opscode-­‐manage'  do      notifies  :reconfigure,  'chef_server_ingredient[opscode-­‐manage]'   end   chef_server_ingredient  'opscode-­‐analytics'  do      notifies  :reconfigure,  'chef_server_ingredient[opscode-­‐analytics]'   end
  46. chef_server_ingredient action  :install  do      packagecloud_repo  'chef/stable'  do  

           type  value_for_platform_family(:debian  =>  'deb',  :rhel  =>  'rpm')      end      package  new_resource.package_name  do          options  new_resource.options          version  new_resource.version      end   end   action  :reconfigure  do      ctl_cmd  =  ctl_command      execute  "#{new_resource.package_name}-­‐reconfigure"  do          command  "#{ctl_cmd}  reconfigure"      end   end
  47. Omnibus package pattern is consistent: • Install the package •

    Write the configuration* • Run the reconfigure command • Configuration can happen first - and does with the Chef Provisioning recipes * or rsync it from a node, RIGHT?
  48. Hello, machine_file! %w{  actions-­‐source.json  webui_priv.pem  }.each  do  |analytics_file|    machine_file

     "/etc/opscode-­‐analytics/#{analytics_file}"  do          local_path  "/tmp/stash/#{analytics_file}"          machine  'bootstrap-­‐backend'          action  :download      end   end   %w{  pivotal.pem  webui_pub.pem  }.each  do  |opscode_file|    machine_file  "/etc/opscode/#{opscode_file}"  do          local_path  "/tmp/stash/#{opscode_file}"          machine  'bootstrap-­‐backend'          action  :download      end   end
  49. And the 'files' property of machine resource machine  'frontend'  do

         recipe  'chef-­‐server-­‐cluster::frontend'      action  :converge      converge  true      files('/etc/opscode/webui_priv.pem'  =>  '/tmp/stash/webui_priv.pem',                  '/etc/opscode/webui_pub.pem'  =>  '/tmp/stash/webui_pub.pem',                  '/etc/opscode/pivotal.pem'  =>  '/tmp/stash/pivotal.pem')   end   machine  'analytics'  do      recipe  'chef-­‐server-­‐cluster::analytics'      action  :converge      converge  true      files('/etc/opscode-­‐analytics/actions-­‐source.json'  =>  '/tmp/stash/actions-­‐source.json',                  '/etc/opscode-­‐analytics/webui_priv.pem'  =>  '/tmp/stash/webui_priv.pem')   end
  50. Sure, we could rsync in the recipe... • But then

    we have to setup SSH keys between the nodes • And all files in /etc/opscode, including ones put there by someone that shouldn't be there...
  51. chef-client on the provisioner %  CHEF_NODE=chefconf-­‐provisioner  chef-­‐client  -­‐c  .chef/config.rb  

    Starting  Chef  Client,  version  12.0.3   [2015-­‐02-­‐18T14:28:12-­‐07:00]  WARN:  Using  experimental  Policyfile   feature   resolving  cookbooks  for  run  list:  ["chef-­‐server-­‐cluster::cluster-­‐ [email protected]  (e1e803c)"]   Synchronizing  Cookbooks:      -­‐  chef-­‐server-­‐ingredient      -­‐  chef-­‐server-­‐cluster      -­‐  apt      -­‐  packagecloud      -­‐  chef-­‐vault   Compiling  Cookbooks...   ...  SNIP  converging  3  machines  ...   Chef  Client  finished,  11/16  resources  updated  in  1248.519725  seconds
  52. machine resources converging *  machine[bootstrap-­‐backend]  action  converge      -­‐

     Create  bootstrap-­‐backend  with  AMI  ami-­‐b99ed989  in  us-­‐west-­‐2      -­‐  create  node  bootstrap-­‐backend  at  https://api.opscode.com/organizations/jtimberman-­‐chefconf      -­‐      update  run_list  from  []  to  ["recipe[chef-­‐server-­‐cluster::bootstrap]"]      -­‐  waiting  for  bootstrap-­‐backend  (i-­‐553a519c  on  aws::us-­‐west-­‐2)  to  be  connectable      -­‐  bootstrap-­‐backend  is  now  connectable      -­‐  generate  private  key  (2048  bits)      -­‐  create  directory  /etc/chef  on  bootstrap-­‐backend      -­‐  write  file  /etc/chef/client.pem  on  bootstrap-­‐backend      -­‐  create  client  bootstrap-­‐backend  at  clients      -­‐      add  public_key  =  "-­‐-­‐-­‐-­‐-­‐BEGIN  PUBLIC  KEY-­‐-­‐-­‐-­‐-­‐\n...SNIP...-­‐-­‐-­‐-­‐-­‐END  PUBLIC  KEY-­‐-­‐-­‐-­‐-­‐\n"      -­‐  Add  bootstrap-­‐backend  to  client  read  ACLs      -­‐  Add  bootstrap-­‐backend  to  client  update  ACLs      -­‐  create  directory  /etc/chef/ohai/hints  on  bootstrap-­‐backend      -­‐  write  file  /etc/chef/ohai/hints/ec2.json  on  bootstrap-­‐backend      -­‐  write  file  /etc/chef/client.rb  on  bootstrap-­‐backend      -­‐  write  file  /tmp/chef-­‐install.sh  on  bootstrap-­‐backend      -­‐  run  'bash  -­‐c  '  bash  /tmp/chef-­‐install.sh''  on  bootstrap-­‐backend      [bootstrap-­‐backend]  Starting  Chef  Client,  version  12.1.1                                              Chef  Client  finished,  25/32  resources  updated  in  453.570204517  seconds      -­‐  run  'chef-­‐client  -­‐l  auto'  on  bootstrap-­‐backend  
  53. Create and connect to EC2 instance *  machine[bootstrap-­‐backend]  action  converge

         -­‐  Create  bootstrap-­‐backend  with  AMI  ami-­‐b99ed989  in  us-­‐west-­‐2      -­‐  create  node  bootstrap-­‐backend  at  https://api.opscode.com/ organizations/jtimberman-­‐chefconf      -­‐      update  run_list  from  []  to  ["recipe[chef-­‐server-­‐ cluster::bootstrap]"]      -­‐  waiting  for  bootstrap-­‐backend  (i-­‐553a519c  on  aws::us-­‐west-­‐2)   to  be  connectable      -­‐  bootstrap-­‐backend  is  now  connectable
  54. Create the API client and give permission *  machine[bootstrap-­‐backend]  action

     converge    -­‐  generate  private  key  (2048  bits)      -­‐  create  directory  /etc/chef  on  bootstrap-­‐backend      -­‐  write  file  /etc/chef/client.pem  on  bootstrap-­‐backend      -­‐  create  client  bootstrap-­‐backend  at  clients      -­‐      add  public_key  =  "RSA  Public  key  content"      -­‐  Add  bootstrap-­‐backend  to  client  read  ACLs      -­‐  Add  bootstrap-­‐backend  to  client  update  ACLs
  55. Bootstrap like you may have seen... *  machine[bootstrap-­‐backend]  action  converge

         -­‐  create  directory  /etc/chef/ohai/hints  on  bootstrap-­‐backend      -­‐  write  file  /etc/chef/ohai/hints/ec2.json  on  bootstrap-­‐backend      -­‐  write  file  /etc/chef/client.rb  on  bootstrap-­‐backend      -­‐  write  file  /tmp/chef-­‐install.sh  on  bootstrap-­‐backend      -­‐  run  'bash  -­‐c  '  bash  /tmp/chef-­‐install.sh''  on  bootstrap-­‐ backend      [bootstrap-­‐backend]  Starting  Chef  Client,  version  12.1.1      Chef  Client  finished,  25/32  resources  updated  in  453.57  seconds      -­‐  run  'chef-­‐client  -­‐l  auto'  on  bootstrap-­‐backend  
  56. machine files    *  machine_file[/etc/opscode-­‐analytics/actions-­‐source.json]  action  download      

       -­‐  download  file  /etc/opscode-­‐analytics/actions-­‐source.json  on  bootstrap-­‐backend  to  /tmp/stash/actions-­‐source.json      *  machine_file[/etc/opscode-­‐analytics/webui_priv.pem]  action  download          -­‐  download  file  /etc/opscode-­‐analytics/webui_priv.pem  on  bootstrap-­‐backend  to  /tmp/stash/webui_priv.pem      *  machine_file[/etc/opscode/pivotal.pem]  action  download          -­‐  download  file  /etc/opscode/pivotal.pem  on  bootstrap-­‐backend  to  /tmp/stash/pivotal.pem      *  machine_file[/etc/opscode/webui_pub.pem]  action  download          -­‐  download  file  /etc/opscode/webui_pub.pem  on  bootstrap-­‐backend  to  /tmp/stash/webui_pub.pem   ...SNIP          -­‐  upload  file  /tmp/stash/webui_priv.pem  to  /etc/opscode/webui_priv.pem  on  frontend          -­‐  upload  file  /tmp/stash/webui_pub.pem  to  /etc/opscode/webui_pub.pem  on  frontend          -­‐  upload  file  /tmp/stash/pivotal.pem  to  /etc/opscode/pivotal.pem  on  frontend
  57. Wrap-up and takeaways • Chef Server 12 is totally what

    you want to use • Using Chef to build Chef is awesome • Chef Provisioning makes deploying to EC2 easy • chef-server-cluster is a full working example • chef-server-ingredient is a lower level primitive • (and used by chef-server cookbook, too!) • Build your own with chef-server-ingredient