Skip to content

Instantly share code, notes, and snippets.

@smford22
Last active August 29, 2015 14:14
Show Gist options
  • Save smford22/879b9bff9ee351651687 to your computer and use it in GitHub Desktop.
Save smford22/879b9bff9ee351651687 to your computer and use it in GitHub Desktop.
DeveloperWeek SF 2015 - Build an Awesome Application with Chef

Use Chef to Deploy an Awesome Application

Local Development Setup

This section is for configuring your local workstation with the tools you need to write Chef code. You will need to install the following:

  1. ChefDK (Developers Kit) - Contains the most common tools you need to write Chef code.
  2. Vagrant -
  3. VirtualBox

###Install the ChefDK

  1. Go to http://downloads.chef.io/chef-dk
  2. Click on your OS platform and download the installer
  3. Run the installer
  4. Once installed run chef --version to validate the install
$ chef --version
Chef Development Kit Version: 0.4.0

###Install Vagrant

  1. Go to https://www.vagrantup.com/downloads.html
  2. Download the installer for your OS platform
  3. Run the installer
$ vagrant --version
Vagrant 1.7.2

###Install VirtualBox

  1. Go to https://www.virtualbox.org/wiki/Downloads
  2. Download the installer for your OS platform
  3. Run the installer
$ VBoxManage --version
4.3.20r96996

Create a cookbook

  • Open a Terminal window (Mac), Shell (Linux), or Command Prompt/PowerShell (Windows) and run: chef generate cookbook awesome_app

  • Change directory into your cookbook: cd awewsome_app

Bring up a local test VM with TestKitchen

  • Open a command prompt and make sure you are in your awesome_app cookbook folder

For more information on Chef cookbooks

  • At the prompt type kitchen list and hit return
$ kitchen list
Instance             Driver   Provisioner  Transport  Last Action
default-ubuntu-1204  Vagrant  ChefZero     ssh        <Not Created>
default-centos-65    Vagrant  ChefZero     ssh        <Not Created>

Test Kitchen is configured via a .kitchen.yml file in the cookbook you generate with the chef generate cookbook command. The following example is used to spin up an instance locally that is accessible via a private network address at 192.168.30.33:

---
driver:
  name: vagrant

provisioner:
  name: chef_zero

platforms:
  - name: ubuntu-12.04
  - name: centos-6.5
    driver:
      network:
      - ["private_network", {ip: "192.168.33.7" }]

suites:
  - name: default
    run_list:
      - recipe[apache::default]
    attributes:

The output shows there are two possible test suites currently configured (Ubuntu 12.04 and CentOS 6.5). ####Create a local test VM and install Chef on it: The following command will install Chef on your local VM...

$ kitchen converge default-centos-65
-----> Starting Kitchen (v1.3.2.dev)
-----> Creating <default-centos-65>...
       Bringing machine 'default' up with 'virtualbox' provider...
       ==> default: Importing base box 'opscode-centos-6.5'...
==> default: Matching MAC address for NAT networking...
       ==> default: Setting the name of the VM: default-centos-65_default_1423331677844_33060
       ==> default: Clearing any previously set network interfaces...
       ==> default: Preparing network interfaces based on configuration...
           default: Adapter 1: nat
       ==> default: Forwarding ports...
           default: 22 => 2222 (adapter 1)
       ==> default: Booting VM...
       ==> default: Waiting for machine to boot. This may take a few minutes...    default: SSH address: 127.0.0.1:2222
           default: SSH username: vagrant
           default: SSH auth method: private key
           default: Warning: Connection timeout. Retrying...
           default:
           default: Vagrant insecure key detected. Vagrant will automatically replace
           default: this with a newly generated keypair for better security.
           default:
           default: Inserting generated public key within guest...
           default: Removing insecure key from the guest if its present...
           default: Key inserted! Disconnecting and reconnecting using new SSH key...
       ==> default: Machine booted and ready!
       ==> default: Checking for guest additions in VM...
       ==> default: Setting hostname...
       ==> default: Machine not provisioning because `--no-provision` is specified.
       Vagrant instance <default-centos-65> created.
       Finished creating <default-centos-65> (0m42.28s).
-----> Converging <default-centos-65>...
       Preparing files for transfer
       Preparing dna.json
       Resolving cookbook dependencies with Berkshelf 3.2.1...
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
-----> Installing Chef Omnibus (install only if missing)
       downloading https://www.chef.io/chef/install.sh
         to file /tmp/install.sh
       trying wget...
       Downloading Chef  for el...

####Login to the vm:

$ kitchen login default-centos-65
Last login: Fri Mar  7 16:57:20 2014 from 10.0.2.2
[vagrant@default-centos-65 ~]$ sudo su -
[root@default-centos-65 ~]# cat /etc/redhat-release
CentOS release 6.5 (Final)
[root@default-centos-65 ~]# chef-client --version
Chef: 12.0.3

Congratulations, you know have a local development host that you can test your Chef code on!!!

For more information on configuring Test Kitchen go to http://kitchen.ci

Basic Tenets of Chef

The following section describes the basics of writing Chef code. For the DeveloperWeek Hackathon we will not go into Chef Server, but rather just get you going writing simple recipes. If you want to use Chef server, BY ALL MEANS PLEASE DO SO!

Resources

Resources are the the most basic building blocks of Chef. Resources represent a piece of your system and the state you want it to be in.

Packages
package "mysql-server" do
  action :install
end
Services
service "iptables" do
  action [ :start, :enable ]
end
Files
file "/etc/motd" do
  content "Property of Chef Software"
end

Remote File

remote_file "/tmp/testfile" do
  source "http://www.example.com/tempfiles/testfile"
  mode '0644'
  checksum "3a7dac00b1" # A SHA256 (or portion thereof) of the file.
end

Execute

The execute resource allows you to execute commands on your node. The following example also uses the not_if guard which will not execute the command if a test returns true Conversely there is the only_if guard which will execute the command only if the test returns true

%w{rover fido bubbers}.each do |pet_name|
  execute "feed_pet_#{pet_name}" do
    command "echo 'Feeding: #{pet_name}'; touch '/tmp/#{pet_name}'"
    not_if { ::File.exists?("/tmp/#{pet_name}")}
  end
end

Cron

cron "restart webserver" do
  hour '2'
  minute '0'
  command 'service httpd restart'
end

Users

user "nginx" do
  comment "Nginx user <nginx@example.com>"
  uid 500
  gid 500
  supports :manage_home => true
end

Microsoft DSC

dsc_script 'emacs' do
  code <<-EOH
  Environment 'texteditor'
  {
    Name = 'EDITOR'
    Value = 'c:\\emacs\\bin\\emacs.exe'
  }
  EOH
end

For more information on Chef Resources go to http://docs.chef.io/chef/resources.html

The Basic Tenets of Chef

Login to your local Test Kitchen VM

$ kitchen login default-centos-65
Last login: Sat Feb  7 21:30:02 2015 from 10.0.2.2
[vagrant@default-centos-65 ~]$

Use chef-apply to configure an instance

chef-apply is an executable program that allows you to work with resources. It is included as part of the ChefDK. While it is a great way to explore resources, it is NOT how you’ll eventually use Chef in production. For the purposes of the DeveloperWeek hackathon it might just be all you need!

[vagrant@default-centos-65 ~]$ chef-apply --help
Usage: chef-apply [RECIPE_FILE] [-e RECIPE_TEXT] [-s]
        --[no-]color                 Use colored output, defaults to enabled
    -e, --execute RECIPE_TEXT        Execute resources supplied in a string
    -l, --log_level LEVEL            Set the log level (debug, info, warn, error, fatal)
    -s, --stdin                      Execute resources read from STDIN
    -v, --version                    Show chef version
    -W, --why-run                    Enable whyrun mode
    -h, --help                       Show this message

Install a package

[vagrant@default-centos-65 ~]$ sudo chef-apply -e "package 'git'"

Resource Test and Repair

Resources follow a test and repair model

Resource currently in the desired state? (test)

  • Yes – Do nothing
  • No – Bring the resource into the desired state (repair)

Run chef-apply again and see what happens

[vagrant@default-centos-65 ~]$ sudo chef-apply -e "package 'vim'"
Recipe: (chef-apply cookbook)::(chef-apply recipe)
  * yum_package[vim] action install
    - install version 7.2.411-1.8.el6 of package vim-enhanced

Time for Hello World!

Open in a text editor ~/hello.rb

file "hello.txt" do
  action :create
  content "Hello, world!"
  mode "0644"
  owner "chef"
  group "chef"
end

Use chef-apply to apply the policy

[vagrant@default-centos-65 ~]$ sudo chef-apply hello.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
  * file[hello.txt] action create
    - create new file hello.txt
    - update content in file hello.txt from none to 315f5b
    --- hello.txt	2015-02-07 21:45:43.878012741 +0000
    +++ ./.hello.txt20150207-3588-96noix	2015-02-07 21:45:43.876012742 +0000
    @@ -1 +1,2 @@
    +Hello, world!
    - change mode from '' to '0644'
    - change owner from '' to 'vagrant'
    - change group from '' to 'vagrant'
    - restore selinux security context

[vagrant@default-centos-65 ~]$ cat hello.txt
Hello, world!

All Chef Resources:

  • Have a name (file)
  • Have a type (hello.txt)
  • Have an action (:create)

Chef Recipes

Recipes are an ORDERED list of resources. In Chef, ORDER MATTERS. Your resources will be executed in the same order every time!

Here is a sample recipe:

package "haproxy" do
  action :install
end

template "/etc/haproxy/haproxy.cfg" do
  source "haproxy.cfg.erb"
  owner "root"
  group "root"
  mode "0644"
  notifies :restart, "service[haproxy]"
end

service "haproxy" do
  supports :restart => :true
  action [:enable, :start]
end

Chef Cookbooks

Cookbooks are a collection of recipes and their supporting files. Supporting files

As shown above, you can create a chef cookbook using the chef generate cookbook <cookbook_name> command

Test Driven Infrastructure with ServerSpec

ServerSpec allows you to write tests to verify your servers. It is not dependent on Chef. It already supports many resource types package, service, user, etc. It works well with Test Kitchen!!! http://serverspec.org/

Inside of your cookbook, create a folder for your tests

$ mkdir -p test/integration/default/serverspec
Test Kitchen will look in the test/integration directory for test-related files

Write a ServerSpec test

In an editor open <cookbook_name>/test/integration/default/serverspec/default_spec.rb

describe 'apache' do
  it "is installed" do
    expect(package 'httpd').to be_installed
  end

  it "is running" do
    expect(service 'httpd').to be_running
  end

  it "is listening on port 80" do
    expect(port 80).to be_listening
  end

  it "displays a custom home page" do
    expect(command("curl localhost").stdout).to match /hello/
  end
end

Run your test

$ kitchen test default-centos-65
...
apache
        is installed
        is running
        is listening on port 80
        displays a custom home page

      Finished in 0.3968 seconds
      4 examples, 0 failures
      Finished verifying <default-centos-64> (0m4.25s).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment