Terminologies
We will now discuss some terminologies about Chef. As we have already discussed, Chef has two different types, namely Chef server and Chef-Solo. Chef-Solo provides a simple way to start. The following terminologies mentioned are used for Chef server as well as Chef-Solo.
List of terminologies
A generalized list of Chef terminologies are mentioned in the following section.
Node
Any physical, virtual, or cloud machine where chef-client will run is termed as a node. There are the following four types of nodes that can be managed by chef-client:
- Cloud node: This is a server hosted on any cloud-based service such as Rackspace, Amazon, Virtual Private Cloud, OpenStack, Google Compute Engine, or Windows Azure. Different plugins are available for supporting different cloud types. It can be used to create instances using cloud-based services.
- Physical node: Physical node is a server or a virtual machine that has the capability of sending, receiving, and forwarding data through a network channel. In simple words, a network machine that runs the chef-client.
- Virtual node: A virtual node runs as a software implementation but behaves like a proper machine, for example, VirtualBox, Docker, and so on.
- Network node: This is a device attached to the network and capable of sending, receiving, and forwarding data, and managed by chef-client. Routers, switches, and firewalls are a perfect example of network nodes.
Workstation
A workstation is a machine, where Knife configures and sends instructions to a node. Knife is used to manage nodes, cookbooks and recipes, roles, and environments. A commercial Knife version can be used to search index data on the server.
For a production environment, workstation authentication is managed by RSA or a DSA key pair. Authentication ensures that a workstation is properly registered with the server.
Moreover, Chef-repo is maintained on the workstation and it is distributed in chef-clients from the workstation. Once the distribution is done, chef-client executes the recipes and installs everything on the system.
Cookbooks
Cookbooks are a collection of recipes. Each cookbook defines the policy and scenario to install and configure any particular machine. For instance, installing PostgreSQL needs libpq-dev
and other packages. It contains all the components that need to be installed on the system.
Additional configurations can be set up using cookbooks:
- Attributes to set on nodes
- Definitions of resources
- Dependency control
- File distributions
- Libraries to help Chef-Solo to extend Ruby code, for example, Berkshelf, Librarian-Chef
- Templates
- Custom resources and providers
- Roles
- Metadata of recipes
- Versions
Cookbooks are written in Ruby code. It's good to have knowledge about Ruby, but it's not mandatory. The Ruby code used in cookbooks is very simple and self-explanatory. While using cookbooks, you do not need to maintain the documentation of the server setup.
The sole purpose of a cookbook is to give a reasonable set of resources to a chef-client for the infrastructure automation.
Recipes
Recipes are the fundamental configuration elements in cookbooks. A recipe contains a set of commands that needs to be executed step by step. A recipe can include additional recipes within a recipe.
Each code block contains a set of instructions. For example, take a look at the following code:
# To update
execute "update apt" do
command "apt-get update --fix-missing"
end
# For installing some packages
%w{
curl
screen
make
python2.7-dev
vim
python-setuptools
libmysqlclient-dev
mysql-client
}.each do |pkg|
package pkg do
action :install
end
end
Recipes are written in Ruby code, and it contains the set of resources; each code block is wrapped in a resource. In the previous example, execute
and package
is a resource to handle code inside a block.
There are certain rules for writing recipes:
- It should maintain a proper order. For instance, if you want to use MySQL, you must specify the
libmysqlclient-dev
package first and then install MySQL. - Recipes must be placed in the
cookbook
folder. - It must define everything that needs to be installed in a particular environment.
- Recipes must be declared in
run_list
to execute in any recipe. - Any additional recipe that you specify should be contained in the same
cookbook
folder or you should have some dependency resolved to include the recipe (Berkshelf allows you to include the recipe from github.com).
Resources
A resource is an integral part of any recipe. It defines the actions to be taken in a recipe. It could be a service, a package, a group of a user, and so on. For example, it will instruct chef-client to check whether a particular package needs to be installed or not, or when a service needs to be restarted or not, and which directory or file needs to be created by which user. Each resource is written in a code block and it executes in the same order as mentioned in the recipe. Chef-Solo ensures that each action has to be taken as specified in the recipe. After the successful execution of resources, it returns the success code to chef-client. In case there is an error, it returns with an error code and chef-client exits with an error.
The following is an example of a directory resource:
directory "/var/log/project" do owner "root" group "root" recursive true action :create end
The chef-client will look up the directory resource and call load_current_resource
to create a new directory resource. The client will look up the directory; if it's not created, it will create the directory in the logs
folder, and if the directory already exists, nothing will happen and the resource will be marked as completed.
The following is an example of a Git resource:
git "/home/user/webapps/project" do repository "git@github.com:opscode-cookbooks/chef_handler.git" reference "master" action :sync enable_submodules true user "root" group "root" end
The mentioned Git resource will pull the code from the repository with all sub-modules.
It will switch the branch to master and async will ensure that recent changes have been pulled from the remote repository to the local repository.
The resource is mainly divided into the following four parts:
- Type
- Name
- Attributes
- Actions
The coding convention of the resource is shown in the following code:
resourcetype "name" do attribute "value" action :action end
In the preceding code, resourcetype
is the name of a resource, for example, directory, file, apache_site, and so on.
As we have discussed earlier that each resource has separate actions, the action
command is used to execute these actions.
Each resource has its own type of actions and attributes. The directory
resource has a create
and a delete
action. Each resource has its own default actions and attributes. Similarly, the default action directory resource is create
. And it has group
, inherits
, mode
, owner
, path
, provider
, recursive
, and right
attributes.
Roles
In simple words, the reusable configuration of several nodes, for example, database, Web, and so on, are called as roles. They define certain patterns and processes that need to be installed in different nodes. When a role runs against any recipe, attributes have been overwritten with role attributes.
Each node can have zero or more roles assigned to it and then run_list
of roles will be executed on the node.
An attribute can be defined both in a node and in a role. Role should have at least the following attributes:
name
: This attribute gives the name of the roledescription
: This contains the description of the rolerun_list:
Recipes need to be executed with this role
Roles can be declared in two ways: we can define it in Ruby or in JSON. In case of JSON, there are some additional attributes, such as chef_type
, json_class
that need to be defined. Detailed information about roles is available in the next chapter.
Attributes
In simple terms, attributes are variables that are defined in a cookbook to be used by recipes and templates to create configuration files. When chef-client executes the recipes, it loads all the attributes from cookbooks, recipes, and roles.
Attributes are declared in the attributes
folder under cookbooks. When any recipe is executed, it checks within the context of the current node and applies on that node.
For example, Nginx cookbook attributes are given as follows:
default["nginx"]["dir"] = "/etc/nginx" default["nginx"]["listen_ports"] = [ "80","443" ]
Similarly, Git attributes are given as follows:
default["project"][:project_path] = "/home/chef/webapps/project" default["project"][:repository] = "git@github.com:opscode-cookbooks/chef_handler.git"
We have already discussed about the attributes' precedence in the Roles section. We will discuss attributes in more detail in the upcoming chapters.
Templates
A template is a simple configuration file that has a placeholder for attributes. Templates files are written in Embedded Ruby (.erb
) format. For example, to deploy Nginx, you need the nginx.conf.erb
file.
A sample of a template file is mentioned as follows:
server { listen 80; server_name <%= node["project"]["domain"] %>; access_log <%= node["project"]["logs_dir"] %>/<%= node["project"]["project"_name] %>_access.log; error_log <%= node["project"]["logs_dir"] %>/<%= node["project"]["project"_name] %>_error.log; location / { client_max_body_size 20M; client_body_temp_path /tmp/ expires -1; proxy_pass http://localhost:8000; proxy_set_header X-Real-IP $remote_addr; send_timeout 5m; keepalive_timeout 5m; gzip on; } }
In the preceding example, the following attributes will be replaced and the configuration file will be copied to a specific directory with a real value:
node["project"]["domain"] = "http://mydomain.com" node["project"]["logs_dir"] = "/var/logs/project"
Data bags
A data bag is a global variable defined in JSON and accessible from a server.
The following is an example:
{ "project": { "dbdomain": "dbdomain.com", "dbuser": "database_user", "dbpassword": "database_password" }, "run_list": [ "recipe[git::default]", "recipe[nginx::default]", "recipe[project::default]" ] }
In the preceding example, Dbdomain
, dbuser
, and dbpassword
are the data bags.