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

Avatar for Joshua Timberman

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