Начала DevOps: Opscode Chef
Day 4

Andriy Samilyak
samilyak@gmail.com
skype: samilyaka
Goals
●

Pull deployment with Chef

●

Environments

●

More about Berkshelf+Vagrant way

●

Chef in real live - base_server

●

Exception/Report handlers

●

Debugging with Chef

●

Testing with Chef
Deployment strategies

PULL vs PUSH
Pull deployment with Chef
# http://community.opscode.com/cookbooks/application
application "my_app" do
path "/var/www"
repository "git://github.com/werdan/hpmor.git"
end

copy/paste from http://goo.gl/6sEYT5
Deployment with Chef - Plan
●

Application cookbook
(Berksfile/metadata.rb)

●

Application resource in default.rb

●

git installation

●

docroot correction
Capistrano way
●
●

●

●

Check your /var/www after chef-client run
/var/www/current is a symlink to one of
releases
/var/www/releases contains code
releases
/var/www/shared – anything that is not
kept in repository
Example of solution
webserver/attributes/default.rb:
default['apache']['docroot_dir'] = "/var/www/current"
webserver/recipes/default.rb:
package "git"
application "my_app" do
path "/var/www"
repository "https://github.com/werdan/hpmor.git"
end
Git flow
●

New release is ready for deployement

●

It is in 'develop' branch

●

●

Our current server is going to be now QA
testing
We should maintain the second server
(LIVE) with master branch deployed
Branch deployment with Chef
application "my_app" do
path "/var/www"
repository "git://github.com/werdan/hpmor.git"
revision 'your_branch' # specified with attribute
end
Environments

LIVE server

run_list: role[node]
recipes: recipe[webserver]
git_branch: master

DEV server

run_list: role[node]
recipes: recipe[webserver]
git_branch: develop
Attribute precedence

From: http://docs.opscode.com/essentials_cookbook_attribute_files.html
Environments
●

environments/production.rb
name "production"
default_attributes 'webserver' => {
'revision' => 'master'
}

●

environments/development.rb
name "development"
default_attributes 'webserver' => {
'revision' => 'develop'
}
Default attribute value
●

webserver/attributes/default.rb
default['webserver']['revision'] = 'master'
Environments: knife
knife environment from file production.rb
knife environment from file
development.rb
knife environment list
knife environment show production
Configuring DEV server
●

set environment to 'development'
> knife node edit your_node
> Chef Server GUI

●
●

run chef-client
check result in browser (is it in English
now?)
Branch deployment with Chef
application "my_app" do
path "/var/www"
repository "git://github.com/werdan/hpmor.git"
revision 'your_branch' # specified with attribute
end
Another PCI DSS failure

Go to http://YOUR_NODE_ADDRESS/icons/
Apache configuration patch
<Directory /usr/share/apache2/icons>
Options -Indexes
</Directory>

copy/paste from http://goo.gl/6sEYT5
Environments

LIVE server

run_list: role[node]
recipes: recipe[webserver]
templates: no patch

DEV server

run_list: role[node]
recipes: recipe[webserver]
templates: with patch!
We have to keep LIVE stable!
●

●

●

environments/production.rb
cookbook "webserver", "= 0.1.0"
webserver/metadata.rb
version '0.1.1'
upload cookbook

●

upload production environment

●

knife cookbook show webserver
Better Berksfile strategy
cookbook 'apache2'
cookbook 'htpasswd', git: ….
cookbook 'application'

cookbook 'webserver', path: 'cookbooks/webserver'
●

berks install

●

berks upload
Frozen cookbooks
●

Try now
knife cookbook upload webserver
knife cookbook show webserver 0.1.1
> frozen?: true

●

●

berks update && berks upload → no
changes
knife cookbook upload webserver --force
Vagrant provision
Real demonstration now – hold your breath!
Vagrant provision
chef-repo/Vagrantfile
Vagrant.configure("2") do |config|
config.vm.hostname = "webserver"
config.vm.box = "webserver"
config.vm.box_url =
"http://grahamc.com/vagrant/ubuntu-12.04-omnibus-chef.box"
config.vm.network :public_network
config.berkshelf.berksfile_path = "Berksfile"
config.berkshelf.enabled = true
config.vm.provision :chef_solo do |chef|
chef.run_list = [
]
chef.data_bags_path = "data_bags"
chef.roles_path = "roles"
chef.add_role("node")
chef.environments_path = "environments"
chef.environment = 'production'
end
end
Vagrant provision - chef-solo
●

No API (no databag search , for instance)

●

No cookbook version pin in environment

●

No persistent attributes (normal[..][..])
Cookbook hierarchy
base_server
●

●

●

Create new cookbook with Berks
cd cookbooks
berks cookbook base_server
Add base_server to Berskfile
Include dependences on
apt, ntp, chef-client, cron, openssh

●

Include base_server to role[node] run_list
Recipes to include
base_server/recipes/default.rb

include_recipe "chef-client"
include_recipe "chef-client::delete_validation"
include_recipe "chef-client::config"
include_recipe "ntp"
include_recipe "cron"
include_recipe "apt"
include_recipe "openssh"
●

Bump minor cookbook version of 'base_server'

copy/paste from http://goo.gl/6sEYT5
base_server configuration
default[:openssh][:server][:password_authentication] = 'no'
default[:openssh][:server][:allow_agent_forwarding] = 'yes'
default[:openssh][:server][:allow_tcp_forwarding] = 'no'
default[:openssh][:server][:use_dns] = 'no'

copy/paste from http://goo.gl/6sEYT5
chef_client
On node: ps ajx | grep chef-client
On workstation: knife status

NB! It is a good idea to establish internal procedure
to check knife status on regular basis
chef_restart
include_recipe "cron"
cron "Chef: Node-specific cronjobs: chef-client-restart" do
minute "#{node[:chef_restart_minute] ||= rand(59)}"
hour "#{node[:chef_restart_hour] ||= rand(23)}"
day "*"
month "*"
weekday "*"
command "ps ax | grep -q [c]hef-client &&
sleep $(( $RANDOM % 1800 )) &&
invoke-rc.d chef-client restart >/dev/null 2>&1"
user "root"
end
Exception handlers
●

Report about any exceptions in chef run

●

Many community handlers are available:
–

Airbrake

–

Email

–

Syslog

–

Graphite

–

HipChat
HipChat report example

https://github.com/opsway/chef-hipchat
Chef Server reports
Debugging with Chef
sudo chef-client -ldebug -Fdoc
sudo chef-client --why-run
sudo chef-client -o recipe['apache2::mod_dav']
'puts driven development'
Chef::log.info("Your message")
log("Your message to put it simple")
abort
chef-shell
# chef-shell -z
chef> run_chef
chef> chef_run.skip_back 40
chef> chef_run.step
chef> node['apache']['dir']
Pry - installation
●

Run on node:
/opt/chef/embedded/bin/gem install --no-ri
--no-rdoc pry pry-nav pry-doc

●

Insert into webserver/recipes/default.rb
require 'pry';
binding.pry

copy/paste from http://goo.gl/6sEYT5
pry
# chef-client
pry> ls node
pry> ls node.name
pry> ls node.default
pry> ls node.normal
pry> step
pry> next
pry > continue
Chef-testing
●

Semantic testing → Foodcritics

●

Unit testing → ChefSpec

●

Integration testing →
with ChefZero
– Test Kitchen
–
Foodcritic lint
gem install foodcritic --no-ri --no-rdoc
cd CHEF_REPO
foodcritic cookbooks/webserver

.. see http://acrmp.github.io/foodcritic/
More rules
cd CHEF_REPO
git clone git://github.com/custominkwebops/foodcritic-rules.git foodcritic/customink
git clone git://github.com/etsy/foodcriticrules.git foodcritic/etsy
foodcritic -I foodcritic/* cookbooks/webserver

copy/paste from http://goo.gl/6sEYT5
Functional spec example from
PagerDuty

http://goo.gl/9k5Fj2

Chef training Day4