Configuration Management with Chef-Solo
上QQ阅读APP看书,第一时间看更新

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 role
  • description: This contains the description of the role
  • run_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.