Skip to content

Chef

Configuration management tool that uses Ruby to define infrastructure as code. Automates infrastructure provisioning and configuration.

Chef Architecture

ComponentDescription
Chef WorkstationWhere you author cookbooks and recipes
Chef ServerCentral hub that stores cookbooks and node data
Chef ClientRuns on nodes, applies configurations from server
Chef SupermarketCommunity cookbook repository

Chef Client Commands

Client Management

COMMANDDESCRIPTION
chef-clientRun chef client and apply cookbooks
chef-client -j attributes.jsonRun with custom attributes
chef-client -WWhy-run mode (dry-run)
chef-client -l debugRun with debug logging
chef-client -F jsonOutput in JSON format
chef-client -zLocal mode (no server)

Configuration

COMMANDDESCRIPTION
chef-client -c client.rbUse specified config file
chef-client -k /path/to/client.pemSpecify client key
chef-client -s https://chef.example.com/organizations/myorgSpecify chef server URL
chef-client -N nodenameSpecify node name

Knife Commands

Knife is Chef's command-line tool for managing the Chef Server.

Client Management

COMMANDDESCRIPTION
knife client listList all registered clients
knife client show CLIENT_NAMEShow client details
knife client create CLIENT_NAMECreate new client
knife client delete CLIENT_NAMEDelete a client
knife client reregister CLIENT_NAMERegenerate client key
knife client bulk delete REGEXDelete clients matching regex

Node Management

COMMANDDESCRIPTION
knife node listList all nodes
knife node show NODE_NAMEShow node details
knife node edit NODE_NAMEEdit node attributes
knife node delete NODE_NAMEDelete a node
knife node from file FILENAMECreate node from file
knife node run_list add NODE_NAME 'recipe[cookbook::recipe]'Add recipe to node
knife node run_list remove NODE_NAME 'recipe[cookbook::recipe]'Remove recipe from node
knife node run_list set NODE_NAME 'recipe[cookbook::recipe]'Set node run list

Role Management

COMMANDDESCRIPTION
knife role listList all roles
knife role show ROLE_NAMEShow role details
knife role create ROLE_NAMECreate new role
knife role edit ROLE_NAMEEdit role
knife role delete ROLE_NAMEDelete a role
knife role from file FILENAMECreate role from file
knife role run_list add ROLE_NAME 'recipe[cookbook::recipe]'Add recipe to role

Cookbook Management

COMMANDDESCRIPTION
knife cookbook listList all cookbooks on server
knife cookbook show COOKBOOK_NAME VERSIONShow cookbook details
knife cookbook upload COOKBOOK_NAMEUpload cookbook to server
knife cookbook upload --allUpload all cookbooks
knife cookbook delete COOKBOOK_NAME VERSIONDelete cookbook from server
knife cookbook download COOKBOOK_NAMEDownload cookbook from server

Knife from Supermarket

COMMANDDESCRIPTION
knife cookbook site search KEYWORDSearch cookbooks in supermarket
knife cookbook site show COOKBOOK_NAMEShow cookbook details
knife cookbook site install COOKBOOK_NAMEInstall cookbook from supermarket
knife cookbook site download COOKBOOK_NAMEDownload cookbook
knife cookbook site share COOKBOOK_NAME CATEGORYShare cookbook to supermarket

Bootstrap (Bootstrapping Nodes)

COMMANDDESCRIPTION
knife bootstrap HOSTNAMEBootstrap a new node
knife bootstrap HOSTNAME -x USERNAME -P PASSWORDBootstrap with username/password
knife bootstrap HOSTNAME -i IDENTITY_FILEBootstrap with SSH key
knife bootstrap HOSTNAME --sudoBootstrap with sudo
knife bootstrap HOSTNAME -r 'recipe[cookbook::recipe]'Bootstrap with run list
knife bootstrap HOSTNAME -N NODE_NAMEBootstrap with custom node name
knife bootstrap HOSTNAME -E ENVIRONMENTBootstrap in environment
COMMANDDESCRIPTION
knife search node 'role:web'Search nodes by role
knife search node 'platform:centos'Search nodes by platform
knife search node 'chef_environment:production'Search nodes by environment
knife search node 'recipes:apache2'Search nodes by recipe
knife search node 'ipaddress:10.0.0.*'Search nodes by IP
knife search node -a hostnameReturn specific attribute

Chef Resources

Chef resources are the building blocks of recipes.

Common Resources

ResourceDescriptionExample
packageInstall/remove packagespackage 'nginx'
serviceManage servicesservice 'nginx'
fileManage filesfile '/etc/config'
directoryManage directoriesdirectory '/var/www'
templateCreate file from templatetemplate '/etc/nginx.conf'
executeRun commandsexecute 'command'
userManage usersuser 'deploy'
groupManage groupsgroup 'deploy'
cronManage cron jobscron 'backup'
gitManage git repositoriesgit '/opt/app'

Package Resource

ruby
package 'nginx' do
  action :install
end

# With version
package 'nginx' do
  version '1.18.0'
  action :install
end

# Remove package
package 'nginx' do
  action :remove
end

Service Resource

ruby
service 'nginx' do
  supports status: true, restart: true, reload: true
  action [:enable, :start]
end

# With conditions
service 'nginx' do
  action [:enable, :start]
  only_if { File.exist?('/etc/nginx/nginx.conf') }
end

File Resource

ruby
file '/etc/config.conf' do
  content 'my config content'
  owner 'root'
  group 'root'
  mode '0644'
  action :create
end

# Delete file
file '/tmp/old_file.txt' do
  action :delete
end

Directory Resource

ruby
directory '/var/www/myapp' do
  owner 'www-data'
  group 'www-data'
  mode '0755'
  recursive true
  action :create
end

Template Resource

ruby
template '/etc/nginx/nginx.conf' do
  source 'nginx.conf.erb'
  owner 'root'
  group 'root'
  mode '0644'
  variables({
    port: 80,
    server_name: node['fqdn']
  })
  action :create
end

Execute Resource

ruby
execute 'run_install_script' do
  command '/tmp/install.sh'
  cwd '/tmp'
  user 'root'
  action :run
  not_if { File.exist?('/opt/app/installed') }
end

User Resource

ruby
user 'deploy' do
  comment 'Deployment user'
  uid '1000'
  gid 'deploy'
  home '/home/deploy'
  shell '/bin/bash'
  action :create
end

Group Resource

ruby
group 'deploy' do
  gid '1000'
  members ['deploy']
  action :create
end

Chef Templates (ERB)

Template Example

erb
# nginx.conf.erb
user <%= @nginx_user %>;
worker_processes <%= @worker_processes %>;

events {
    worker_connections <%= @worker_connections %>;
}

http {
    server {
        listen <%= @port %>;
        server_name <%= @server_name %>;

        location / {
            root <%= @document_root %>;
        }
    }
}

Template Usage

ruby
template '/etc/nginx/nginx.conf' do
  source 'nginx.conf.erb'
  variables(
    nginx_user: 'www-data',
    worker_processes: 4,
    worker_connections: 1024,
    port: 80,
    server_name: node['fqdn'],
    document_root: '/var/www/html'
  )
end

ERB Syntax

SyntaxDescription
<%= variable %>Output variable value
<% code %>Execute Ruby code (no output)
<% if condition %>Conditional block
<% else %>Else block
<% end %>End block
`<% array.each doitem
<% end %>End loop

Chef Attributes

Attribute Types

TypeDescriptionExample
defaultLowest precedencedefault['nginx']['port'] = 80
normalSame as defaultnormal['nginx']['port'] = 80
overrideHigher precedenceoverride['nginx']['port'] = 8080
automaticFrom Ohai (read-only)node['ipaddress']

Attributes File (attributes/default.rb)

ruby
# attributes/default.rb
default['nginx']['port'] = 80
default['nginx']['worker_processes'] = 4
default['nginx']['worker_connections'] = 1024
default['nginx']['document_root'] = '/var/www/html'

# Override in specific environment
override['nginx']['port'] = 8080 if node.chef_environment == 'production'

Using Attributes

ruby
# In recipe
port = node['nginx']['port']
worker_processes = node['nginx']['worker_processes']

# With default value
port = node['nginx']['port'] || 80

# In template
# nginx.conf.erb
listen <%= node['nginx']['port'] %>;

Chef Recipes

Recipe Structure

ruby
# recipes/default.rb

# Install package
package 'nginx' do
  action :install
end

# Create directory
directory '/var/www/html' do
  owner 'www-data'
  group 'www-data'
  mode '0755'
  action :create
end

# Create configuration from template
template '/etc/nginx/sites-available/default' do
  source 'default.erb'
  variables(
    port: node['nginx']['port'],
    server_name: node['fqdn']
  )
  notifies :reload, 'service[nginx]', :immediately
end

# Enable and start service
service 'nginx' do
  action [:enable, :start]
end

Notification

ruby
# Notifies another resource
template '/etc/nginx/nginx.conf' do
  source 'nginx.conf.erb'
  notifies :reload, 'service[nginx]', :immediately
end

# Subscribes to another resource
service 'nginx' do
  action [:enable, :start]
  subscribes :reload, 'template[/etc/nginx/nginx.conf]', :immediately
end

Guards

ruby
# Only run if file exists
execute 'install_package' do
  command 'apt-get install -y nginx'
  not_if { File.exist?('/usr/sbin/nginx') }
end

# Only run if file doesn't exist
file '/tmp/marker' do
  content 'created'
  only_if { Dir.exist?('/var/www/html') }
end

Chef Cookbooks

Cookbook Structure

cookbook_name/
├── attributes/
│   └── default.rb          # Default attributes
├── definitions/
│   └── my_definition.rb    # Resource definitions
├── files/
│   └── default/
│       └── config.conf     # Static files
├── libraries/
│   └── helpers.rb         # Custom Ruby libraries
├── metadata.rb            # Cookbook metadata
├── recipes/
│   └── default.rb         # Default recipe
├── templates/
│   └── default/
│       └── config.erb     # ERB templates
└── README.md              # Cookbook documentation

Create Cookbook

bash
# Using chef generate
chef generate cookbook my_cookbook

# Generate specific item
chef generate recipe my_cookbook my_recipe
chef generate template my_cookbook my_template
chef generate attribute my_cookbook my_attribute

Metadata.rb

ruby
name 'my_cookbook'
maintainer 'Your Name'
maintainer_email 'you@example.com'
license 'Apache-2.0'
description 'Installs and configures my application'
version '1.0.0'

supports 'ubuntu'
supports 'centos'

depends 'nginx', '~> 10.0'
depends 'mysql', '~> 8.0'

Chef Environments

Environment Management

COMMANDDESCRIPTION
knife environment listList all environments
knife environment show ENVIRONMENTShow environment details
knife environment create ENVIRONMENTCreate new environment
knife environment edit ENVIRONMENTEdit environment
knife environment delete ENVIRONMENTDelete environment

Environment File

ruby
# environments/production.rb
name "production"
description "Production environment"
cookbook_versions({
  "nginx" => "= 10.0.0",
  "mysql" => "= 8.0.0"
})
override_attributes({
  "nginx" => {
    "port" => 8080
  }
})

Chef Best Practices

  1. Use Cookbooks for Reusability - Package related recipes
  2. Use Templates for Configuration - Don't hardcode values
  3. Use Attributes for Customization - Keep recipes flexible
  4. Test Locally - Use Test Kitchen or Chef Solo
  5. Version Control Cookbooks - Git for all cookbooks
  6. Use Community Cookbooks - Don't reinvent the wheel
  7. Follow Naming Conventions - cookbook_name::recipe_name
  8. Document Cookbooks - Include README.md files
  9. Use Roles and Environments - Organize configurations
  10. Monitor Chef Runs - Check logs for errors

Chef vs Other Config Management

FeatureChefPuppetAnsible
LanguageRubyPuppet DSLYAML
Agent RequiredYesYesNo
Learning CurveSteepSteepEasy
Push ModeKnife bootstrapMCollectiveYes
Pull ModeYesYesNo
MaturityMatureMatureMature

Useful Tips

Local Testing with Chef Solo

bash
# Run chef solo
chef-solo -c solo.rb -j attributes.json

# solo.rb configuration
file_cache_path "/tmp/chef-solo"
cookbook_path "/tmp/cookbooks"

# attributes.json
{
  "run_list": [
    "recipe[nginx]"
  ]
}

Debugging

bash
# Enable debug logging
chef-client -l debug

# Use why-run mode
chef-client -W

# Check configuration
chef-client --config-file client.rb -c

# Search node data
knife node show NODE_NAME -a attributes

Common Issues

IssueSolution
Permission deniedCheck sudo permissions
Chef::Exceptions::CookbookNotFoundUpload cookbook to server
Template not foundCheck template path
Package not foundUpdate package cache
Syntax errorValidate recipe syntax with chef exec ruby -c recipe.rb

Chef Workstation Installation

bash
# Download from Chef website
curl -L https://omnitruck.chef.io/install.sh | sudo bash

# Install specific version
curl -L https://omnitruck.chef.io/install.sh | sudo bash -s -- -v 18.0

# Verify installation
chef --version
knife --version

Released under MIT License.