Chef Provisioning
Chef All The Things
John Keiser
Principal Engineer
Resident Mad Scientist
jkeiser@chef.io
@jkeiser2
Ye Olde Ops Playbook
Chef!
package 'apache2' do
version '2.0'
end
template '/etc/httpd.conf'
service 'apache2'
Chef!
-
Repeatable
-
Self-Documenting
- Flexible
-
Self-Healing
- Versionable
- Readable
- Testable
YE NEWE OPS PLAYBOOK
Clusters IN OUR DREAMS
real Clusters
the Cluster Litany
- Version?
- Test?
- Re-create?
- Manage Machines?
- Add Capacity?
I JUST WANT TO CONVERGE
My First Cluster
machine 'db' do
recipe 'mysql'
end
machine 'web1' do
recipe 'apache'
end
My First Cluster
> CHEF_DRIVER=vagrant:~/vms
> chef-client -z cluster.rb
Recipe: talk1::cluster
* machine[db] action create
- run vagrant up db
- write file /etc/chef/client.rb on db
Starting Chef Client, version 11.8.2
Recipe: mysql::default
* file[/etc/mysql.txt] action create - create new file /etc/mysql.txt
Chef Client finished, 1 resources updated
- run 'chef-client' on db
* machine[web1] action create
- run vagrant up web1
- write file /etc/chef/client.rb on web1
- run 'chef-client' on web1
Chef Client finished, 2 resources updated
What.
-
machine resource
- Drivers
WHAT.
-
machine resource
- Drivers
- Cloud
- VMs
- Containers
- Metal (Razor, etc.)
It's Chef
chef-client
It's Recipes
private_key 'crypt'
chef_data_bag_item 'x/y' do
secret_path 'crypt'
end
machine 'mydb' do
file '/etc/crypt', 'crypt'
end
It's Unified
metal login [node] metal execute [node] metal delete [node] metal converge [node]
Adding a New Machine
machine 'db' do
recipe 'mysql'
end
machine 'web' do
recipe 'apache'
end
machine 'web2' do
recipe 'apache'
end
Idempotence!
> chef-client -z -o cluster.rb
Recipe: talk1::cluster
* machine[db] action create (up to date)
* machine[web1] action create (up to date)
* machine[web2] action create
- run vagrant up web2
- write file /etc/chef/client.rb on web2
Starting Chef Client, version 11.8.2
Recipe: apache::default
* file[/etc/apache.txt] action create - create new file /etc/apache.txt
Chef Client finished, 1 resources updated
- run 'chef-client' on web2
Chef Client finished, 1 resource updated
Recycle, Reuse, Renew
Let's Do EC2
CHEF_DRIVER=fog:AWS:default
Yay
> chef-client -z cluster.rb
Continuous Integration
Continuous Integration
- Check in Metal recipe
- chef-client on Jenkins node
-
...
Provisioning nodes
-
Upload cluster cookbook
-
Wait 5 minutes
-
...
Growing the cluster
machine 'db' dorecipe 'mysql'
end
machine 'web' do
recipe 'apache'
end
machine 'web2' do
recipe 'apache'
end
Upscaling
Upscaling
-
Upscaling is just adding new nodes
- Chef recipes are code
-
Use a variable for your for loop
- Drive it from your own monitor data
1.upto(num_webservers) do
machine "webserver#{i}" do
recipe 'apache'
tag 'webserver'
end
end
Downscaling
Delete what you don't need.
search('tags:webserver') do |node|
node.name =~ /^webserver(\d+)$/
if $1.to_i > num_webservers
machine node.name do
action :delete
end
end
end
Parallelism
with_machine_batch 'my_batch'
1.upto(50) do |i|
machine "webserver#{i}" do
recipe 'apache'
end
end
Provisioners
There are lots already
chef-metal-fog
chef-metal-vagrant
chef-metal-ssh
chef-metal-lxc
chef-metal-docker
chef-metal-vsphere
Between them, we support
EC2 - DigitalOcean - Openstack - SoftLayer - VSphere
VirtualBox - VMWare Fusion
Bare Metal (SSH, no PXE yet)
LXC - Docker
Making a Driver
-
Extend the Driver interface
-
Implement 4 methods
- ...
driver.allocate_machine(...)
Reserves / purchases a machine
Optionally starting spinup
Short execution time
driver.ready_machine(...)
Starts up machine
Waits for machine to be ready
Returns Machine object
The machine object
- Execute commands
- Manipulate files
-
Converge machine
It's already there
UnixMachine
WindowsMachine
Transports
-
Used by Unix/WindowsMachine
-
Handle execution and file manipulation
Already there:
SSHTransport
WinRMTransport
LXCTransport
DockerTransport
Convergence Strategies
Handle installation of chef and converge
"idempotent bootstrap"
Already there:
InstallCached
InstallSh
InstallMsi
NoConverge
class MyProvisioner < Provisioner
def allocate_machine(ah, machine, options)
id = machine.location['id']
if id
server = lookup_server(id)
else
server = create_server(options) machine.location = {
'id' => server.id
}
end
end
end
Parallelism
allocate_machines
ready_machines
Other methods
connect_to_machine
delete_machine
stop_machine
MACHINE Options
Shape of the machine
Freeform Hash
Driver decides what goes in it
Not stored anywhere
Example Vagrant options:
machine_options :vagrant_options => { 'vm.box' => 'precise64' },
:vagrant_config => 'config.vm.synced_folder "~/code", "/mnt/code"'
Example EC2 options:
machine_options :bootstrap_options => {
:image_id => 'ami-2f726546',
:flavor_id => 'c1.xlarge'
}
Different Machines Are Different
machine 'webserver' do
driver 'fog:GoogleCloud:MyAccount'
recipe 'webserver'
end
with_driver 'fog:AWS:default', :region => 'us-west-1' do
machine 'monitor' do
recipe 'monitor'
end
machine 'another_webserver' do
machine_options :region => 'us-east-1'
recipe 'webserver'
end
end
1.0 Soon.
After 1.0:
- More Drivers
- Lightweight Provisioning
- More Cluster Resources
- Key Management
How you can help
- Write drivers
- Use it
- Send feedback
-
File and fix bugs
https://github.com/opscode/chef-metal
Chef Provisioning
By John Keiser
Chef Provisioning
- 2,306