This is the third post in a 3 part series.
- Introduction: High level set up
- CloudFormation: Setting up CloudFormation
- Chef: Automating using Chef
This post discusses how to use chef-solo to provision instances at a basic level. Once you have automated instance spin up using CloudFormation, you could add in chef to configure the software programs, execute scripts, install code, configurations and start your software. We will be setting up chef-solo, which does not need a chef server to run.
Install Chef
To install chef, we used the script: https://www.chef.io/chef/install.sh which downloads and installs chef. This script in version as optional argument, else installs the latest version. In production, it is recommended you specify the version you would like to be installed.
usage: install.sh [-P project] [-c release_channel] [-v version] [-f filename | -d download_dir]
solo.rb
This file specifies config parameters for chef.
Sample solo.rb –
cookbook_path [
'/var/chef/cookbooks'
]
environment 'example'
environment_path '/var/chef/environments'
file_backup_path '/var/chef/backup'
file_cache_path '/var/chef/cache'
Roles
A chef role can be defined in json (or Ruby DSL). By default, chef looks for roles in /var/chef/roles, you can override that in solo.rb as role_path.
{
"name": "base_node_mongo_nginx",
"description": "This role sets up web server with node and mysql",
"chef_type": "role",
"MONGO":{
"URL":"127.0.0.1",
"PORT":"27017",
"DBNAME":"testdb_staging"
},
"run_list": [
"recipe[init_config]",
"recipe[install_node]", //install nodejs and npm rpm
"recipe[install_mongo]", //install mongo rpm
"recipe[install_nginx]", //install nginx and copy right config
]
}
This is one of our sample roles, this has variables declared in “MONGO” object, these can be set up in the role and referenced in the recipes specified in the run_list.
This allows developers to write one recipe and configure it accordingly for different roles. For instance – staging, production, development can use same recipe and different roles.
A role can also specify another role in run_list. For example:
"run_list": [
"role[base_node_mongo_nginx]",
"recipe[install_app]" //install application, run npm install, and start server
]
This would first execute the role base and then recipe finalize. This can be very useful in certain use cases. For instance, we have one base_node role that installs node js and configures it on centos 6.5, we could use that as a starter role and “inherit” a role from it only doing application specific set up there.
For variables, you can define default values in the base role and override them in the inherited role.
Cookbooks & Recipes
Chef recipes are ruby files that are a component of cookbooks. There are a lot of details to Cookbooks, but to keep things simple we will discuss writing simple recipes with some resources. A much more detailed documentation can be found here:
template vs cookbook_file
Initially, when you are setting up your chef recipe you might end up just using cookbook_file which simply copies the file over to a location, but as you start parameterizing contents of the file with variables you will need to replace cookbook_file with template. For example, you might want 2 nginx configurations on different virtual hosts. A very common use case. Here, instead of having separate file, you can make one config and customize the contents with variables.
role:
{
"name": "staging",
"description": "This role sets up nginx config",
"chef_type": "role",
"ENV":"staging",
"SERVER":{
"DOCUMENT_ROOT":"/var/www/public",
"SERVER_NAME":"vhost.domain.com"
},
"run_list": [
"recipe[install_nginx]"
]
}
recipe – install_nginx:
template "/etc/nginx/conf.d/nginx.#{node['ENV']}.conf" do
source "nginx.template.conf"
mode 0755
variables({
:DOCUMENT_ROOT => node['SERVER']['DOCUMENT_ROOT'],
:SERVER_NAME => node['SERVER']['SERVER_NAME'],
})
notifies :restart, 'service[nginx]', :immediately
end
nginx.template.conf:
server {
listen 80;
listen [::]:80;
server_name <%= @SERVER_NAME %>;
location / {
root <%= @DOCUMENT_ROOT %>;
}
}
This is a template resource that does the following:
- takes nginx.template.conf
- replaces variables DOCUMENT_ROOT, SERVER_NAME and SERVER_PORT
- creates the file to /etc/nginx/conf.d/nginx.staging.conf
- sets the mode to 755
- restarts service nginx immediately after doing all the above.
Folder set up
chef-solo
--cookbooks -> folder that contains all the recip[e folders
--↳---install_nginx -> folder that contains all the files for a recipe
-------↳--recipes -> folder for recipe
----------↳--default.rb -> the recipe with resource blocks
-------↳--templates -> folder that contains all templates
----------↳--nginx.template.conf -> template
-------↳--metadata.rb -> name and description
Executing Chef
Using chef-solo, you can pass in the solo.rb and the role json to execute it.
chef-solo -c /var/chef/solo.rb -j /var/chef/roles/production.json
Official chef documentation:
POWER UP YOUR BUSINESS WITH AWS DEVELOPMENT SERVICES
Author
Parikshit Agnihotry
Works at Logic Square 🏢 | Loves to learn new things 📚 | Always willing to help others 🤝