Chef is a configuration management and infrastructure automation platform that uses a declarative DSL (Ruby-based) to define system state as cookbooks and recipes.
This stack runs Chef Infra Server with a Chef Workstation container for managing nodes and cookbooks.
flowchart LR
User([User]) -->|knife| Workstation[Chef Workstation]
Workstation -->|Upload cookbooks| Server[Chef Infra Server<br/>:443]
Server -->|Policy / Data| PG[(PostgreSQL<br/>embedded)]
Node[Chef Client / Node] -->|chef-client| Server
Node -->|ohai facts| Server
Server -->|Compiled Cookbook| Node
Workstation -->|Bootstrap| Node
Node check-in and converge flow:
sequenceDiagram
participant User
participant Workstation as Chef Workstation
participant Server as Chef Infra Server
participant Node as Chef Client
User->>Workstation: knife cookbook upload setup
Workstation->>Server: Upload cookbook
Server-->>Workstation: OK
User->>Workstation: knife bootstrap node --run-list recipe[setup]
Workstation->>Node: Install chef-client, register
Node->>Server: ohai - upload facts
Server->>Server: Compute node attributes
Node->>Server: Request run list + cookbooks
Server-->>Node: Compiled cookbook (resources)
Node->>Node: Converge - enforce resource state
Node->>Server: Report (success / updated / failed)
Server-->>User: Status
- Cookbook development happens on the workstation container — recipes, templates, and attributes are authored in Ruby DSL.
- Use
knife cookbook uploadto publish cookbooks to the Chef Infra Server. - Nodes run the
chef-clientagent (or are bootstrapped viaknife bootstrap) to register with the server. - During a converge run, the client sends facts (via ohai), requests its run list, downloads the compiled cookbook, and applies every resource declaration to reach the desired state.
- A report is sent back to the server after each run detailing changes, successes, and failures.
| Service | Image | Port | Purpose |
|---|---|---|---|
chef-server |
chef/chef-server:latest |
443 |
Chef Infra Server (API + Web UI) |
chef-workstation |
chef/chef:latest |
— | CLI tools: knife, chef-client, ohai |
Persistent data:
./data/server/config/— Chef Server configuration./data/server/data/— Chef Server runtime data (embedded PostgreSQL, Solr)./data/server/logs/— Chef Server access and error logs./data/workstation/— Workstation home directory (.chef/, SSL certs)./cookbooks/— Local cookbook development directory
Set via .env:
| Variable | Default | Description |
|---|---|---|
CHEF_SERVER_FQDN |
chef-server |
Fully qualified domain name of the Chef Server |
From the repository root:
cd chef
docker compose up -dUseful commands:
docker compose ps
docker compose logs -f chef-server
docker compose exec chef-workstation knife --help
docker compose down
docker compose down -v# Reconfigure the server after first startup
docker compose exec chef-server chef-server-ctl reconfigure
# Create an admin user
docker compose exec chef-server chef-server-ctl user-create admin Admin User admin@example.com 'password123' --filename /etc/chef-server/admin.pem
# Create an organization
docker compose exec chef-server chef-server-ctl org-create myorg 'My Organization' --association_user admin --filename /etc/chef-server/myorg-validator.pem# Copy credentials from the server
docker compose exec chef-workstation mkdir -p /root/.chef
docker compose exec chef-workstation cp /etc/chef-server/admin.pem /root/.chef/
docker compose exec chef-workstation cp /etc/chef-server/myorg-validator.pem /root/.chef/
# Create knife.rb
docker compose exec chef-workstation bash -c 'cat > /root/.chef/knife.rb << EOF
current_dir = File.dirname(__FILE__)
log_level :info
log_location STDOUT
node_name "admin"
client_key "#{current_dir}/admin.pem"
chef_server_url "https://chef-server/organizations/myorg"
cookbook_path ["/cookbooks"]
EOF'docker compose exec chef-workstation knife cookbook upload setupdocker compose exec chef-workstation knife node list
docker compose exec chef-workstation knife cookbook list
docker compose exec chef-workstation knife client listdocker compose exec chef-workstation knife bootstrap <NODE_IP> \
--ssh-user root \
--sudo \
--node-name <NODE_NAME> \
--run-list 'recipe[setup]'The repository includes example files to get started:
cookbooks/setup/recipes/default.rb— recipe that installs packages, manages a service, and writes a motd filecookbooks/setup/recipes/webserver.rb— recipe that installs and configures nginxexamples/default.rb.example— standalone copy of a basic recipe
- First startup takes 2–5 minutes while Chef Server initialises embedded PostgreSQL and Solr. Watch
docker compose logs -f chef-serverfor readiness. - The Chef Server Web UI is available at
https://localhost/(accept the self-signed certificate warning). - Chef Server uses self-signed SSL certificates by default. For production, configure proper certificates in
data/server/config/. - Cookbooks are authored in Ruby DSL — see the Chef Infra Language docs for resource types (
package,service,file,template,execute, etc.). - The workstation container includes
chef-clientandohai— use them for local apply testing. - Manage cookbook dependencies with
Berkshelf(knife cookbookcan also use--berks).