Chef Patterns: Part 1 - Modeling Environment-Specific Differences
Join the DZone community and get the full member experience.
Join For FreeAt work we have the notion of multiple
environments. Dev (used by the developers), Staging (used for showcasing
stories), QA/Testing (used by testers) and Production (caters to end
user). At times, a pre-production environment is also present to simulate
production like scenarios.
Though we fight hard to minimize the
differences between these environments, they do exist and it is
necessary to measure them, which in turn can provide us with some automated
mechanisms to easily spot environment-specific differences. In this
write up I'll be writing some of the techniques I'm using to model them.
There are two generic goals for this techniques:
- Testability of the recipe.
- Ease with which one can spot the environment-specific differences
The techniques:
- Conditionals: Use
raw if else conditions to apply different resources in different
environments. If you are sure that the difference will only be limited
to certain minute details I will start employing raw conditional statements
like this:
if node.chef_environment == 'development' do # # do not configure basic auth # else # # configure basic auth # end
- Attributes: Use attributes to model the differences in environments. In Chef, attributes can be overridden on per environment basis. This
provides an elegant way to implement environment-specific changes. In
the following example, the version of Ruby needs to be different in two
environments.
# the default attribute looks like default[:ruby][:version] = '1.8.7' # # the resource inside ruby recipe might use it like this # ruby_version= 'ruby-'+ node[:ruby][:version] execute "download_ruby" do cwd "/opt" command "wget -c http://someurl/#{ruby_version}.tgz" end # #
name "staging" override_attributes("ruby"=>{"version"=>'1.9.3'})
- Environment-specific Chef recipes/components: Use environment specific recipes and other components on the fly. If
the amount of differences is large enough, involving multiple resources
and significant configuration differences within a single file, you can
use the environment name itself to dynamically load an environment-specific template or environment-specific sub recipe. For example the
deploy recipe invokes database backup as well as load balancer rotation
(the instance should be out of the load balancer during the deployment)
tasks that are only in production and not in any other environments. For this we can
have a dedicated recipe name deploy::production. On the other hand the
main deploy recipe uses something like this
pre_deployment_sub_recipe = "deploy::#{node.chef_environment}_pre_deployment" include_recipe sub_recipe # # Perform deployment # post_deployment_sub_recipe = "deploy::#{node.chef_environment}_post_deployment"
template "/etc/nginx/nginx.conf" do source "nginx." + node.chef_environment + "conf.erb" end
Published at DZone with permission of Ranjib Dey, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Creating Scalable OpenAI GPT Applications in Java
-
Unlocking the Power of AIOps: Enhancing DevOps With Intelligent Automation for Optimized IT Operations
-
CDNs: Speed Up Performance by Reducing Latency
-
Low Code vs. Traditional Development: A Comprehensive Comparison
Comments