How we integrated Chef with Jenkins and Nexus for continuous deployment

How we integrated Chef with Jenkins and Nexus for continuous deployment

Chef is a a configuration management tool that uses Ruby, domain-specific language (DSL) for writing system configuration recipes. Chef is used to configure and maintain on-premise servers and can integrate with cloud-based platforms to automatically provision and configure new machines.

Problem Statement

We need to fetch an artifact from an artifact repository and deploy at run time with a chef recipe in a CI CD pipeline using jenkins as the build and orchestration tool.

Scenario

We will use Jenkins as the build and orchestration tool. Whenever a build is successful on staging server, the deployment artifacts are stored in a artifact repository like nexus or artifactory. The artifacts are being stored along with the build number. The artifacts cannot be overridden as at times customer wants to move to a previous build or the technical team might want to refer to previous build to reproduce an issue. Hence after each successful build, a new artifact is stored along with the build number in the artifact repository.
We use chef as the configuration management tool which will fetch the artifacts from the repo and deploy them on the client machine or the chef node. So how do we inform chef that artifacts with a particular build number have to be fetched from the artifact repository. 


Solution

The solution lies in the attributes section of the chef cookbook.  We can generate attributes in a similar way that we created the cookbook itself using chef generate command. Before going to the code details let us first learn a little about attributes. 

What are Attributes

An attribute can be defined in a cookbook (or a recipe) and then used to override the default settings on a node. When a cookbook is loaded during a chef-client run, these attributes are compared to the attributes that are already present on the node. The chef-client will then apply those new settings and values on the node.

How to use attributes

We will first need to create the attributes. Execute following command from chef-repo folder

chef generate attribute <cookbookname> default

This will create default.rb attribute file under <cookbook/attributes folder.

 This is where you need to declare your variable. You can then call this variable from within your chef recipe.

There are two steps involved in our scenario.

Step1: The value of Build number attribute needs to be updated in the default.rb file. 
This should be done for every successful build by jenkins. To update the build number, call a script or run commands on the attributes file on chef workstation from within jenkins job. Then upload the cookbook to the server using knife command. Following are the commands executed from powershell post build commands within jenkins job.

cd ..\chef-repo\cookbooks\<cookbook-name>\attributes
$text = “default[‘<cookbook-name>’][‘versionNo’]= <build number for most recent successful build>”
$text|Set-Content ‘default.rb’
knife cookbook upload <cookbook-name>

Step 2: Whenever chef-client is run on a node, the value of build number will be fetched from the attribute file uploaded along with the cookbook on chef server. The following code from within the recipe file can be used to execute the same.

buildNumber=node[‘<cookbook-name>’][‘versionNo’]
remote_file ‘<artifact path and file name>’ do
source
“< url to download code from repo>
end

In the url string to fetch the artifact, you need to concatenate build number as #{buildNumber} in the url string which is in double quotes.

The above steps are required to be setup during development tine.

During deployment on the node, all one needs to do is call chef-client on the node (assuming the node has been bootstrapped already) which will pickup the latest version from the artifact repository and deploy on the node at the location mentioned in the recipe file.

Let us know if you found this post useful.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *