Chef (now part of Progress) is a powerful Infrastructure as Code (IaC) and configuration management tool written in Ruby and Erlang. It automates the process of provisioning, configuring, and maintaining servers and hybrid cloud infrastructure.
Chef operates under an agent-server (Chef Infra Server + Chef Infra Client) or standalone local mode architecture.
- Node: A physical server, virtual machine, or container managed by Chef Infra Client.
- Cookbook: The fundamental unit of distribution and configuration containing recipes, attributes, templates, and files.
- Recipe: A file (
.rb) containing declarative Ruby instructions specifying resources to manage. - Resource: A statement of configuration describing the desired state of a system component (
package,service,file,template, etc.). - Run-list: An ordered list of recipes and roles executed by the client on a specific node.
- Ohai: The system profiling tool that automatically detects node attributes (OS, IP, CPU, memory).
🟢 Beginner Commands (Click to Expand)
chef -v
chef-client -vchef generate cookbook my_cookbook
chef generate recipe my_cookbook defaultchef-client --local-mode --runlist 'recipe[my_cookbook]'cookstyle
cookstyle -a # Auto-correct linting errors🟡 Intermediate Commands (Click to Expand)
knife bootstrap 192.168.1.50 -U ubuntu --sudo -N web-node-01 -r 'recipe[my_cookbook]'knife cookbook upload my_cookbook
knife cookbook listknife node show web-node-01
knife node list
knife role list
knife role show webserverknife ssh 'name:web-node-*' 'sudo chef-client' -x ubuntu🔴 Advanced Commands (Click to Expand)
knife search node 'role:webserver AND platform:ubuntu'
knife search node 'ohai_time:[* TO 1600000000]'knife data bag create secrets
knife data bag from file secrets db_creds.json --secret-file /path/to/encrypted_data_bag_secret
knife data bag show secrets db_credschef install Policyfile.rb
chef update Policyfile.rb
chef push production Policyfile.lock.jsonchef exec rspec # Run ChefSpec unit tests
kitchen test # Full integration test cycle
kitchen converge && kitchen verify # Fast development iterationChef Workstation includes the Chef CLI, Knife, Test Kitchen, Cookstyle, InSpec, and embedded Ruby.
# Ubuntu / Debian
curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P chef-workstation
# CentOS / RHEL / Fedora
curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P chef-workstation
# Verify installation
chef -vchef generate cookbook my_cookbook
cd my_cookbookCookbook Directory Structure:
my_cookbook/
├── Policyfile.rb
├── README.md
├── attributes/
│ └── default.rb
├── recipes/
│ └── default.rb
├── templates/
├── files/
├── resources/
└── test/
# recipes/default.rb
# Install package
package 'nginx' do
action :install
end
# Manage file
file '/var/www/html/index.html' do
content '<h1>Deployed by Chef Infra!</h1>'
mode '0644'
owner 'www-data'
group 'www-data'
end
# Manage service
service 'nginx' do
action [:enable, :start]
endNotifications allow resources to communicate changes and trigger actions on other resources (e.g. restart a service when its configuration file updates).
template '/etc/nginx/nginx.conf' do
source 'nginx.conf.erb'
mode '0644'
notifies :restart, 'service[nginx]', :delayed # :delayed (default) or :immediate
end
service 'nginx' do
action [:enable, :start]
endservice 'nginx' do
action :nothing
subscribes :restart, 'template[/etc/nginx/nginx.conf]', :delayed
endAttributes are variables defined across cookbooks, environments, or roles.
# attributes/default.rb
default['web']['port'] = 80
default['web']['docroot'] = '/var/www/html'
override['web']['max_clients'] = 250Attribute Precedence Order (Lowest to Highest):
- Default (
default) - Force Default (
force_default) - Normal (
normal) - Override (
override) - Force Override (
force_override) - Automatic (read-only from Ohai)
Access attributes in recipes:
file "#{node['web']['docroot']}/index.html" do
content "Port configured: #{node['web']['port']}"
endCreate dynamic configuration files based on node attributes:
chef generate template my_cookbook nginx.confTemplate file (templates/nginx.conf.erb):
server {
listen <%= node['web']['port'] %>;
server_name <%= node['fqdn'] %>;
root <%= node['web']['docroot'] %>;
location / {
try_files $uri $uri/ =404;
}
}Recipe usage:
template '/etc/nginx/sites-available/default' do
source 'nginx.conf.erb'
owner 'root'
group 'root'
mode '0644'
notifies :reload, 'service[nginx]'
endData bags store global JSON data accessible by any node in your infrastructure.
// data_bags/users/deploy.json
{
"id": "deploy",
"uid": 2001,
"shell": "/bin/bash",
"comment": "Deployment Service Account"
}Accessing in recipes:
deploy_user = data_bag_item('users', 'deploy')
user deploy_user['id'] do
uid deploy_user['uid']
shell deploy_user['shell']
comment deploy_user['comment']
manage_home true
endCustom resources allow you to build reusable domain-specific abstractions.
File: resources/website.rb:
resource_name :my_website
provides :my_website
unified_mode true
property :site_name, String, name_property: true
property :port, Integer, default: 80
action :create do
directory "/var/www/#{new_resource.site_name}" do
owner 'www-data'
mode '0755'
recursive true
end
file "/var/www/#{new_resource.site_name}/index.html" do
content "<h1>Welcome to #{new_resource.site_name} on port #{new_resource.port}</h1>"
end
end
action :delete do
directory "/var/www/#{new_resource.site_name}" do
action :delete
recursive true
end
endUsage in recipe:
my_website 'internal-portal' do
port 8080
action :create
endPolicyfiles lock cookbook dependencies and run-lists into an immutable, versioned artifact (Policyfile.lock.json).
File: Policyfile.rb:
name 'webserver_policy'
default_source :supermarket
run_list 'my_cookbook::default'
cookbook 'my_cookbook', path: '.'
cookbook 'nginx', '~> 12.0'CLI commands:
# Compile and lock dependencies
chef install Policyfile.rb
# Push policy to Chef Infra Server
chef push production Policyfile.lock.jsonFile: .kitchen.yml:
---
driver:
name: vagrant
provisioner:
name: chef_zero
enforce_idempotency: true
platforms:
- name: ubuntu-22.04
suites:
- name: default
verifier:
inspec_tests:
- test/integration/defaultRun tests:
kitchen converge # Boots VM and runs Chef Client
kitchen verify # Executes InSpec compliance tests
kitchen destroy # Tears down test VMInSpec Test Example (test/integration/default/default_test.rb):
describe package('nginx') do
it { should be_installed }
end
describe service('nginx') do
it { should be_running }
it { should be_enabled }
end
describe port(80) do
it { should be_listening }
end- Always enable
unified_mode true: Ensures execution phase matches compile phase behavior in modern Chef. - Lint with Cookstyle: Run
cookstylebefore committing code to enforce RuboCop and Chef standards. - Prefer Policyfiles over Berkshelf/Roles: Provides deterministic builds and eliminates environment dependency conflicts.
- Use
:delayedNotifications: Prevents repeated service restarts during cookbook runs. - Encrypt Sensitive Data: Always use Encrypted Data Bags or HashiCorp Vault integrations for passwords and keys.
