Skip to content

Chef

On this page

Chef's model for configuration management: the resource/recipe/cookbook hierarchy, the pull-based agent run, and how to keep nodes in a declared state.

Basics

Chef (Progress Chef) is a configuration-management tool that describes a machine's desired state as code (Ruby DSL) and converges nodes to that state. It is classically pull-based and agent-based: each managed node runs chef-client, which fetches policy from a Chef Infra Server (or runs locally) and applies it.

Core building blocks (smallest → largest)

Concept What it is
Resource A declared piece of state: a package, service, file, template, user.
Recipe An ordered collection of resources (a .rb file).
Cookbook A package of recipes + templates, files, attributes, custom resources.
Attributes Variables/data that parameterize recipes (defaults, overrides).
Run-list The ordered set of recipes/roles applied to a node.
Role / Environment Group nodes by function / lifecycle (dev, prod).
Data bags Global JSON data (e.g. users, secrets via encrypted data bags).
Policyfiles Modern way to pin cookbook versions for a node group (preferred over roles/environments).

How a chef-client run works

  1. Build the node object and gather system facts via Ohai.
  2. Sync cookbooks from the Chef Infra Server (or use local mode / chef-solo).
  3. Compile recipes into a resource collection.
  4. Converge — execute each resource to reach desired state (idempotently).
  5. Report/handlers run.

Declarative + idempotent

You declare what should be true (package 'nginx' do action :install end), not the steps. Chef makes changes only if the current state differs, so runs are safe to repeat.

Tooling

  • Chef Workstation — author/test cookbooks; ships chef, knife, Test Kitchen, InSpec, Cookstyle.
  • Chef Infra Client — the agent on nodes.
  • Chef Infra Server — central store for cookbooks, node data, policy.
  • Test Kitchen — spins up VMs/containers to test cookbooks.
  • InSpec — compliance/security testing as code.

Cheatsheet

A minimal recipe

# cookbooks/web/recipes/default.rb
package 'nginx' do
  action :install
end

template '/etc/nginx/nginx.conf' do
  source 'nginx.conf.erb'
  owner 'root'
  group 'root'
  mode '0644'
  notifies :reload, 'service[nginx]', :delayed
end

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

Common resources

file '/tmp/x' do content 'hello' end
directory '/opt/app' do recursive true end
user 'deploy' do shell '/bin/bash' end
execute 'reload-sysctl' do command 'sysctl -p' end
git '/srv/app' do repository 'https://...' revision 'main' end
cron 'cleanup' do minute '0' hour '2' command '/usr/local/bin/cleanup' end

CLI / workflow

chef generate cookbook web        # scaffold a cookbook
chef generate recipe web extra

# knife (talks to Chef Infra Server)
knife cookbook upload web
knife node list ; knife node show NODE
knife bootstrap HOST -N name -r 'recipe[web]'   # install client + run
knife ssl check

# local / standalone
chef-client --local-mode --runlist 'recipe[web]'
chef-client                       # normal run against server

# test & lint
kitchen test                      # Test Kitchen full cycle
cookstyle .                       # Ruby/style linting
inspec exec compliance-profile

Thumb Rules

Rules of thumb

  • Declare state, don't script steps. Reach for a resource before execute/bash.
  • Every run must be idempotent. If a second run changes things, the recipe is wrong.
  • Use notifies/subscribes for restarts so services reload only when config changes.
  • Pin cookbook versions (Policyfiles) so prod doesn't drift when you publish updates.
  • Secrets go in encrypted data bags or a vault, never plaintext in cookbooks.
  • Test in Test Kitchen before uploading. Treat cookbooks like application code (lint, test, review).
  • Attributes have precedence levels — keep overrides minimal and predictable.

Use Cases

  • Fleet configuration — install/patch packages, manage users, deploy config across many servers.
  • Golden-state enforcement — periodic chef-client runs correct drift automatically.
  • Compliance as code — pair with InSpec for continuous security/compliance checks.
  • Application deployment — provision the OS layer and app dependencies consistently.
  • Hybrid/large enterprises — Chef is common where a pull-based, self-healing model is preferred.

Common Issues

Recipe not idempotent / changes every run

A execute/bash block runs unconditionally. Add a not_if/only_if guard or use a proper declarative resource that knows its current state.

“Cookbook not found” or version conflicts

Dependency constraints in metadata.rb / Policyfile can't be satisfied. Run berks/chef install to resolve, and pin versions. Re-upload with knife cookbook upload.

Service doesn't restart after config change

Missing notifies :restart, 'service[x]' on the template/file resource, or the service resource name doesn't match. Confirm the notification target name.

SSL / client registration errors on bootstrap

Clock skew, wrong server URL, or missing validation key. knife ssl check, verify time sync (chrony), and the node's client.rb.

Attribute precedence surprises

A value isn't what you expect because a higher-precedence level overrides it. Inspect with node.debug_value('key') and reduce override sprawl.

Best Practices

  • Adopt Policyfiles for deterministic, version-pinned node policy.
  • Keep cookbooks small and single-purpose; compose via dependencies.
  • Lint with Cookstyle, test with Test Kitchen, verify with InSpec in CI.
  • Manage secrets with encrypted data bags or an external vault.
  • Use roles/environments or policy groups to separate dev/stage/prod.
  • Version-control everything and review changes like app code.
  • Schedule regular chef-client runs so drift is corrected continuously.
  • Document attributes and their defaults clearly.

Official Sources