I had an opportunity to use Chef and wanted to know it systematically, so I read Chef Practical Guide. I’ll leave notes for myself.

Overview

  • There are two types of operation modes depending on whether a management server is involved. The first is a server-client model using Chef Server as a management server. In addition to the local terminal and managed nodes, a Chef Server is required. Communication occurs between the local terminal and Chef Server, and between Chef Server and nodes (Chef Client). Strong against increasing number of nodes. The second is a standalone model using Chef Solo. Neither Chef Server nor Chef Client is required. Often used in small-scale environments. Both are implemented in Ruby, so they can be installed by gem like gem install chef knife-solo berkshelf.
  • It has a hierarchical structure of repository (kitchen), cookbook, and recipe. The repository is version-controlled by Git, etc. Place self-created cookbooks in site-cookbooks, external cookbooks in cookbooks, globally scoped data for the entire repository in data_bags, environment information like dev/prod in environments, and node-specific configuration information (node objects) in nodes. Also, describe the list of dependent external cookbooks in Berksfile.

Cookbook Implementation

  • When managing multiple nodes with the same configuration, define a role that groups the nodes. Create <repository>/roles/<role name>.json and write run_list, etc. You can also override Attributes. default_attributes defines things that are not defined, and override_attributes forcibly overwrites.
  • There is a mechanism called Attribute that manages key-values. You can set them yourself or automatically extract them from the system. When automatically extracting, the result of the ohai command is used. Conventionally, use symbols like node[:platform] for keys of values obtained by ohai, and use strings like node["httpd"]["port"] for keys defined in Node objects. Attributes can have default values defined in <cookbook name>/attributes/defaults.rb. Attribute priority order is: Node object > Role > Environment > Recipe Attribute > Cookbook Attribute.
  • The cookbook_file resource transfers files under <cookbook name>/files, and the file resource is used to newly create files.
  • There are resources like ifconfig, mount, gem_package, git, http_request, route, ruby_block. If there are things that cannot be managed even using these resources, use the script resource. However, you need to ensure idempotency yourself by using not_if, only_if, etc. well.
  • After placing configuration files, you can reload services like notifies :reload, "service[httpd]". Alternatively, you can define in the opposite direction by subscribes :reload "template[/etc/httpd.conf]". Both behave the same, queued and executed together.
  • If indentation becomes deep with if statements and readability decreases, it’s good to use conditional actions like only_if.
  • Resources written in recipes are executed at convergence timing after compilation, but other Ruby code is executed at compile time. If you want to write Ruby code executed at convergence timing, use the ruby_block resource.
  • A series of resources and processing can be implemented as a Definition like a macro.

Chef Solo

  • When the cookbook development server and managed nodes are the same, create a cookbook with knife cookbook create <cookbook name> and execute the cookbook with chef-solo -o <cookbook name>. I wonder if this usage is rare.
  • When the development server and managed nodes are different, use knife-solo on the development server. The knife-solo command transfers the local cookbook to the node and executes chef-solo. First, on the development server, prepare the repository with knife solo init .. Next, install chef-solo on the managed node with knife solo prepare <hostname>. Then create a cookbook with knife cookbook create <cookbook name> -o <repository>/site-cookbooks. After that, edit the cookbook and write {'run_list': ["recipe[<cookbook name>:<recipe name>]"]} in <repository>/nodes/<hostname>.json. If you omit <recipe name>, default.rb is referenced. Finally, provision the node with knife solo cook <hostname>. Note that there is also a knife solo bootstrap <hostname> command that combines knife solo prepare <hostname> and knife solo cook <hostname>. Also, use knife solo for things that depend only on chef-solo, and use knife for others.

Other

  • You can integration test cookbooks using Test Kitchen. Launch multiple OSes with Vagrant, etc. Test execution is done by serverspec after applying the cookbook. If you want to test behavior without actually applying tests, use ChefSpec.
  • Search for external cookbooks with knife cookbook site search <cookbook name> and add cookbook '<cookbook>' to Berksfile. Then, with the berks command, they are downloaded and expanded to the cookbooks directory.
  • Opscode, Basecamp, RiotGames, aws, engineyard, pivotal-sprout, etc. publish community cookbooks.
  • Chef Server authenticates by checking validation.pem on both sides when registering a new client. Then, it issues a private key to the client.
  • You can check the last time Chef Client was executed with knife status.
  • Chef’s idempotency and emergency rollback are incompatible. Therefore, application deployment by Chef is not ideal.
  • To prevent forgetting to apply cookbooks, periodically execute Chef Solo or use Server/Client configuration for automatic application.
  • Plugins for knife and ohai commands can be easily implemented by placing Ruby code in specified directories.